Home | History | Annotate | Line # | Download | only in master
      1 /*	$NetBSD: event_server.c,v 1.5 2026/05/09 18:49:17 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	event_server 3
      6 /* SUMMARY
      7 /*	skeleton multi-threaded mail subsystem
      8 /* SYNOPSIS
      9 /*	#include <mail_server.h>
     10 /*
     11 /*	NORETURN event_server_main(argc, argv, service, key, value, ...)
     12 /*	int	argc;
     13 /*	char	**argv;
     14 /*	void	(*service)(VSTREAM *stream, char *service_name, char **argv);
     15 /*	int	key;
     16 /*
     17 /*	void	event_server_disconnect(fd)
     18 /*	VSTREAM	*stream;
     19 /*
     20 /*	void	event_server_drain()
     21 /* DESCRIPTION
     22 /*	This module implements a skeleton for event-driven
     23 /*	mail subsystems: mail subsystem programs that service multiple
     24 /*	clients at the same time. The resulting program expects to be run
     25 /*	from the \fBmaster\fR process.
     26 /*
     27 /*	event_server_main() is the skeleton entry point. It should be
     28 /*	called from the application main program.  The skeleton does all
     29 /*	the generic command-line processing, initialization of
     30 /*	configurable parameters, and connection management.
     31 /*	Unlike multi_server, this skeleton does not attempt to manage
     32 /*	all the events on a client connection.
     33 /*	The skeleton never returns.
     34 /*
     35 /*	Arguments:
     36 /* .IP "void (*service)(VSTREAM *stream, char *service_name, char **argv)"
     37 /*	A pointer to a function that is called by the skeleton each
     38 /*	time a client connects to the program's service port. The
     39 /*	function is run after the program has optionally dropped
     40 /*	its privileges. The application is responsible for managing
     41 /*	subsequent I/O events on the stream, and is responsible for
     42 /*	calling event_server_disconnect() when the stream is closed.
     43 /*	The stream initial state is non-blocking mode.
     44 /*	Optional connection attributes are provided as a hash that
     45 /*	is attached as stream context. NOTE: the attributes are
     46 /*	destroyed after this function is called. The service
     47 /*	name argument corresponds to the service name in the master.cf
     48 /*	file.  The argv argument specifies command-line arguments
     49 /*	left over after options processing.
     50 /* .PP
     51 /*	Optional arguments are specified as a null-terminated list
     52 /*	with macros that have zero or more arguments:
     53 /* .IP "CA_MAIL_SERVER_REQ_INT_TABLE(CONFIG_INT_TABLE *)"
     54 /*	A table with configurable parameters, to be loaded from the
     55 /*	global Postfix configuration file. Tables are loaded in the
     56 /*	order as specified, and multiple instances of the same type
     57 /*	are allowed.
     58 /* .IP "CA_MAIL_SERVER_REQ_LONG_TABLE(CONFIG_LONG_TABLE *)"
     59 /*	A table with configurable parameters, to be loaded from the
     60 /*	global Postfix configuration file. Tables are loaded in the
     61 /*	order as specified, and multiple instances of the same type
     62 /*	are allowed.
     63 /* .IP "CA_MAIL_SERVER_REQ_STR_TABLE(CONFIG_STR_TABLE *)"
     64 /*	A table with configurable parameters, to be loaded from the
     65 /*	global Postfix configuration file. Tables are loaded in the
     66 /*	order as specified, and multiple instances of the same type
     67 /*	are allowed.
     68 /* .IP "CA_MAIL_SERVER_REQ_BOOL_TABLE(CONFIG_BOOL_TABLE *)"
     69 /*	A table with configurable parameters, to be loaded from the
     70 /*	global Postfix configuration file. Tables are loaded in the
     71 /*	order as specified, and multiple instances of the same type
     72 /*	are allowed.
     73 /* .IP "CA_MAIL_SERVER_REQ_TIME_TABLE(CONFIG_TIME_TABLE *)"
     74 /*	A table with configurable parameters, to be loaded from the
     75 /*	global Postfix configuration file. Tables are loaded in the
     76 /*	order as specified, and multiple instances of the same type
     77 /*	are allowed.
     78 /* .IP "CA_MAIL_SERVER_REQ_RAW_TABLE(CONFIG_RAW_TABLE *)"
     79 /*	A table with configurable parameters, to be loaded from the
     80 /*	global Postfix configuration file. Tables are loaded in the
     81 /*	order as specified, and multiple instances of the same type
     82 /*	are allowed. Raw parameters are not subjected to $name
     83 /*	evaluation.
     84 /* .IP "CA_MAIL_SERVER_REQ_NINT_TABLE(CONFIG_NINT_TABLE *)"
     85 /*	A table with configurable parameters, to be loaded from the
     86 /*	global Postfix configuration file. Tables are loaded in the
     87 /*	order as specified, and multiple instances of the same type
     88 /*	are allowed.
     89 /* .IP "CA_MAIL_SERVER_REQ_NBOOL_TABLE(CONFIG_NBOOL_TABLE *)"
     90 /*	A table with configurable parameters, to be loaded from the
     91 /*	global Postfix configuration file. Tables are loaded in the
     92 /*	order as specified, and multiple instances of the same type
     93 /*	are allowed.
     94 /* .IP "CA_MAIL_SERVER_REQ_PRE_INIT(void *(char *service_name, char **argv))"
     95 /*	A pointer to a function that is called once
     96 /*	by the skeleton after it has read the global configuration file
     97 /*	and after it has processed command-line arguments, but before
     98 /*	the skeleton has optionally relinquished the process privileges.
     99 /* .sp
    100 /*	Only the last instance of this parameter type is remembered.
    101 /* .IP "CA_MAIL_SERVER_REQ_POST_INIT(void *(char *service_name, char **argv))"
    102 /*	A pointer to a function that is called once
    103 /*	by the skeleton after it has optionally relinquished the process
    104 /*	privileges, but before servicing client connection requests.
    105 /* .sp
    106 /*	Only the last instance of this parameter type is remembered.
    107 /* .IP "CA_MAIL_SERVER_REQ_LOOP(int *(char *service_name, char **argv))"
    108 /*	A pointer to function that is executed from
    109 /*	within the event loop, whenever an I/O or timer event has happened,
    110 /*	or whenever nothing has happened for a specified amount of time.
    111 /*	The result value of the function specifies how long to wait until
    112 /*	the next event. Specify -1 to wait for "as long as it takes".
    113 /* .sp
    114 /*	Only the last instance of this parameter type is remembered.
    115 /* .IP "CA_MAIL_SERVER_EXIT(void *(char *service_name, char **argv))"
    116 /*	A pointer to function that is executed immediately before normal
    117 /*	process termination.
    118 /* .IP "CA_MAIL_SERVER_PRE_ACCEPT(void *(char *service_name, char **argv))"
    119 /*	Function to be executed prior to accepting a new connection.
    120 /* .sp
    121 /*	Only the last instance of this parameter type is remembered.
    122 /* .IP "CA_MAIL_SERVER_PRE_DISCONN(VSTREAM *, char *service_name, char **argv)"
    123 /*	A pointer to a function that is called
    124 /*	by the event_server_disconnect() function (see below).
    125 /* .sp
    126 /*	Only the last instance of this parameter type is remembered.
    127 /* .IP CA_MAIL_SERVER_IN_FLOW_DELAY
    128 /*	Pause $in_flow_delay seconds when no "mail flow control token"
    129 /*	is available. A token is consumed for each connection request.
    130 /* .IP CA_MAIL_SERVER_SOLITARY
    131 /*	This service must be configured with process limit of 1.
    132 /* .IP CA_MAIL_SERVER_UNLIMITED
    133 /*	This service must be configured with process limit of 0.
    134 /* .IP CA_MAIL_SERVER_PRIVILEGED
    135 /*	This service must be configured as privileged.
    136 /* .IP "CA_MAIL_SERVER_SLOW_EXIT(void *(char *service_name, char **argv))"
    137 /*	A pointer to a function that is called after "postfix reload"
    138 /*	or "master exit".  The application can call event_server_drain()
    139 /*	(see below) to finish ongoing activities in the background.
    140 /* .IP "CA_MAIL_SERVER_WATCHDOG(int *)"
    141 /*	Override the default 1000s watchdog timeout. The value is
    142 /*	used after command-line and main.cf file processing.
    143 /* .IP "CA_MAIL_SERVER_BOUNCE_INIT(const char *, const char **)"
    144 /*	Initialize the DSN filter for the bounce/defer service
    145 /*	clients with the specified map source and map names.
    146 /* .IP "CA_MAIL_SERVER_RETIRE_ME"
    147 /*	Prevent a process from being reused indefinitely. After
    148 /*	(var_max_use * var_max_idle) seconds or some sane constant,
    149 /*	stop accepting new connections and terminate voluntarily
    150 /*	when the process becomes idle.
    151 /* .PP
    152 /*	event_server_disconnect() should be called by the application
    153 /*	to close a client connection.
    154 /*
    155 /*	event_server_drain() should be called when the application
    156 /*	no longer wishes to accept new client connections. Existing
    157 /*	clients are handled in a background process, and the process
    158 /*	terminates when the last client is disconnected. A non-zero
    159 /*	result means this call should be tried again later.
    160 /*
    161 /*	The var_use_limit variable limits the number of clients
    162 /*	that a server can service before it commits suicide. This
    163 /*	value is taken from the global \fBmain.cf\fR configuration
    164 /*	file. Setting \fBvar_use_limit\fR to zero disables the
    165 /*	client limit.
    166 /*
    167 /*	The var_idle_limit variable limits the time that a service
    168 /*	receives no client connection requests before it commits
    169 /*	suicide.  This value is taken from the global \fBmain.cf\fR
    170 /*	configuration file. Setting \fBvar_idle_limit\fR to zero
    171 /*	disables the idle limit.
    172 /* DIAGNOSTICS
    173 /*	Problems and transactions are logged to \fBsyslogd\fR(8)
    174 /*	or \fBpostlogd\fR(8).
    175 /* SEE ALSO
    176 /*	master(8), master process
    177 /*	postlogd(8), Postfix logging
    178 /*	syslogd(8), system logging
    179 /* LICENSE
    180 /* .ad
    181 /* .fi
    182 /*	The Secure Mailer license must be distributed with this software.
    183 /* AUTHOR(S)
    184 /*	Wietse Venema
    185 /*	IBM T.J. Watson Research
    186 /*	P.O. Box 704
    187 /*	Yorktown Heights, NY 10598, USA
    188 /*
    189 /*	Wietse Venema
    190 /*	Google, Inc.
    191 /*	111 8th Avenue
    192 /*	New York, NY 10011, USA
    193 /*--*/
    194 
    195 /* System library. */
    196 
    197 #include <sys_defs.h>
    198 #include <sys/socket.h>
    199 #include <sys/time.h>			/* select() */
    200 #include <unistd.h>
    201 #include <signal.h>
    202 #include <stdlib.h>
    203 #include <limits.h>
    204 #include <string.h>
    205 #include <errno.h>
    206 #include <fcntl.h>
    207 #include <stdarg.h>
    208 #ifdef STRCASECMP_IN_STRINGS_H
    209 #include <strings.h>
    210 #endif
    211 #include <time.h>
    212 
    213 #ifdef USE_SYS_SELECT_H
    214 #include <sys/select.h>			/* select() */
    215 #endif
    216 
    217 /* Utility library. */
    218 
    219 #include <msg.h>
    220 #include <msg_vstream.h>
    221 #include <chroot_uid.h>
    222 #include <listen.h>
    223 #include <events.h>
    224 #include <vstring.h>
    225 #include <vstream.h>
    226 #include <msg_vstream.h>
    227 #include <mymalloc.h>
    228 #include <iostuff.h>
    229 #include <stringops.h>
    230 #include <sane_accept.h>
    231 #include <myflock.h>
    232 #include <safe_open.h>
    233 #include <listen.h>
    234 #include <watchdog.h>
    235 #include <split_at.h>
    236 
    237 /* Global library. */
    238 
    239 #include <mail_task.h>
    240 #include <debug_process.h>
    241 #include <mail_params.h>
    242 #include <mail_conf.h>
    243 #include <mail_dict.h>
    244 #include <timed_ipc.h>
    245 #include <resolve_local.h>
    246 #include <mail_flow.h>
    247 #include <mail_version.h>
    248 #include <bounce.h>
    249 #include <maillog_client.h>
    250 
    251 /* Process manager. */
    252 
    253 #include "master_proto.h"
    254 
    255 /* Application-specific */
    256 
    257 #include "mail_server.h"
    258 
    259  /*
    260   * Global state.
    261   */
    262 static int client_count;
    263 static int use_count;
    264 static int socket_count = 1;
    265 
    266 static void (*event_server_service) (VSTREAM *, char *, char **);
    267 static char *event_server_name;
    268 static char **event_server_argv;
    269 static void (*event_server_accept) (int, void *);
    270 static void (*event_server_onexit) (char *, char **);
    271 static void (*event_server_pre_accept) (char *, char **);
    272 static VSTREAM *event_server_lock;
    273 static int event_server_in_flow_delay;
    274 static unsigned event_server_generation;
    275 static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
    276 static void (*event_server_slow_exit) (char *, char **);
    277 static int event_server_watchdog = 1000;
    278 static int event_server_drain_was_called = 0;
    279 
    280 /* event_server_exit - normal termination */
    281 
    282 static NORETURN event_server_exit(void)
    283 {
    284     if (event_server_onexit)
    285 	event_server_onexit(event_server_name, event_server_argv);
    286     exit(0);
    287 }
    288 
    289 /* event_server_retire - retire when idle */
    290 
    291 static void event_server_retire(int unused_event, void *unused_context)
    292 {
    293     if (msg_verbose)
    294 	msg_info("time to retire -- %s", event_server_slow_exit ?
    295 		 "draining" : "exiting");
    296     event_disable_readwrite(MASTER_STATUS_FD);
    297     if (event_server_slow_exit)
    298 	event_server_slow_exit(event_server_name, event_server_argv);
    299     else
    300 	event_server_exit();
    301 }
    302 
    303 /* event_server_abort - terminate after abnormal master exit */
    304 
    305 static void event_server_abort(int unused_event, void *unused_context)
    306 {
    307     if (msg_verbose)
    308 	msg_info("master disconnect -- %s", event_server_slow_exit ?
    309 		 "draining" : "exiting");
    310     event_disable_readwrite(MASTER_STATUS_FD);
    311     if (event_server_slow_exit)
    312 	event_server_slow_exit(event_server_name, event_server_argv);
    313     else
    314 	event_server_exit();
    315 }
    316 
    317 /* event_server_timeout - idle time exceeded */
    318 
    319 static void event_server_timeout(int unused_event, void *unused_context)
    320 {
    321     if (msg_verbose)
    322 	msg_info("idle timeout -- exiting");
    323     event_server_exit();
    324 }
    325 
    326 /* event_server_drain - stop accepting new clients */
    327 
    328 int     event_server_drain(void)
    329 {
    330     const char *myname = "event_server_drain";
    331     int     fd;
    332 
    333     if (event_server_drain_was_called)
    334 	return (0);
    335 
    336     switch (fork()) {
    337 	/* Try again later. */
    338     case -1:
    339 	return (-1);
    340 	/* Finish existing clients in the background, then terminate. */
    341     case 0:
    342 	(void) msg_cleanup((MSG_CLEANUP_FN) 0);
    343 	event_fork();
    344 	for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
    345 	    event_disable_readwrite(fd);
    346 	    (void) close(fd);
    347 	    /* Play safe - don't reuse this file number. */
    348 	    if (DUP2(STDIN_FILENO, fd) < 0)
    349 		msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
    350 	}
    351 	var_use_limit = 1;
    352 	event_server_drain_was_called = 1;
    353 	return (0);
    354 	/* Let the master start a new process. */
    355     default:
    356 	exit(0);
    357     }
    358 }
    359 
    360 /* event_server_disconnect - terminate client session */
    361 
    362 void    event_server_disconnect(VSTREAM *stream)
    363 {
    364     if (msg_verbose)
    365 	msg_info("connection closed fd %d", vstream_fileno(stream));
    366     if (event_server_pre_disconn)
    367 	event_server_pre_disconn(stream, event_server_name, event_server_argv);
    368     (void) vstream_fclose(stream);
    369     client_count--;
    370     /* Avoid integer wrap-around in a persistent process.  */
    371     if (use_count < INT_MAX)
    372 	use_count++;
    373     if (client_count == 0 && var_idle_limit > 0)
    374 	event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
    375 }
    376 
    377 /* event_server_execute - in case (char *) != (struct *) */
    378 
    379 static void event_server_execute(int unused_event, void *context)
    380 {
    381     VSTREAM *stream = (VSTREAM *) context;
    382     HTABLE *attr = (HTABLE *) vstream_context(stream);
    383 
    384     if (event_server_lock != 0
    385 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
    386 		   MYFLOCK_OP_NONE) < 0)
    387 	msg_fatal("select unlock: %m");
    388 
    389     /*
    390      * Do bother the application when the client disconnected. Don't drop the
    391      * already accepted client request after "postfix reload"; that would be
    392      * rude.
    393      */
    394     if (master_notify(var_pid, event_server_generation, MASTER_STAT_TAKEN) < 0)
    395 	 /* void */ ;
    396     event_server_service(stream, event_server_name, event_server_argv);
    397     if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
    398 	event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    399     if (attr)
    400 	htable_free(attr, myfree);
    401 }
    402 
    403 /* event_server_wakeup - wake up application */
    404 
    405 static void event_server_wakeup(int fd, HTABLE *attr)
    406 {
    407     VSTREAM *stream;
    408     char   *tmp;
    409 
    410 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
    411 #ifndef THRESHOLD_FD_WORKAROUND
    412 #define THRESHOLD_FD_WORKAROUND 128
    413 #endif
    414     int     new_fd;
    415 
    416     /*
    417      * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
    418      * case of a multi-server with a thousand clients.
    419      */
    420     if (fd < THRESHOLD_FD_WORKAROUND) {
    421 	if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
    422 	    msg_fatal("fcntl F_DUPFD: %m");
    423 	(void) close(fd);
    424 	fd = new_fd;
    425     }
    426 #endif
    427     if (msg_verbose)
    428 	msg_info("connection established fd %d", fd);
    429     non_blocking(fd, BLOCKING);
    430     close_on_exec(fd, CLOSE_ON_EXEC);
    431     client_count++;
    432     stream = vstream_fdopen(fd, O_RDWR);
    433     tmp = concatenate(event_server_name, " socket", (char *) 0);
    434     vstream_control(stream,
    435 		    CA_VSTREAM_CTL_PATH(tmp),
    436 		    CA_VSTREAM_CTL_CONTEXT((void *) attr),
    437 		    CA_VSTREAM_CTL_END);
    438     myfree(tmp);
    439     timed_ipc_setup(stream);
    440     if (event_server_in_flow_delay && mail_flow_get(1) < 0)
    441 	event_request_timer(event_server_execute, (void *) stream,
    442 			    var_in_flow_delay);
    443     else
    444 	event_server_execute(0, (void *) stream);
    445 }
    446 
    447 /* event_server_accept_local - accept client connection request */
    448 
    449 static void event_server_accept_local(int unused_event, void *context)
    450 {
    451     int     listen_fd = CAST_ANY_PTR_TO_INT(context);
    452     int     time_left = -1;
    453     int     fd;
    454 
    455     if (event_server_drain_was_called)
    456 	return;
    457 
    458     /*
    459      * Be prepared for accept() to fail because some other process already
    460      * got the connection (the number of processes competing for clients is
    461      * kept small, so this is not a "thundering herd" problem). If the
    462      * accept() succeeds, be sure to disable non-blocking I/O, in order to
    463      * minimize confusion.
    464      */
    465     if (client_count == 0 && var_idle_limit > 0)
    466 	time_left = event_cancel_timer(event_server_timeout, (void *) 0);
    467 
    468     if (event_server_pre_accept)
    469 	event_server_pre_accept(event_server_name, event_server_argv);
    470     if (event_server_drain_was_called)
    471 	return;
    472     fd = LOCAL_ACCEPT(listen_fd);
    473     if (event_server_lock != 0
    474 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
    475 		   MYFLOCK_OP_NONE) < 0)
    476 	msg_fatal("select unlock: %m");
    477     if (fd < 0) {
    478 	if (errno != EAGAIN)
    479 	    msg_error("accept connection: %m");
    480 	if (time_left >= 0)
    481 	    event_request_timer(event_server_timeout, (void *) 0, time_left);
    482 	return;
    483     }
    484     event_server_wakeup(fd, (HTABLE *) 0);
    485 }
    486 
    487 #ifdef MASTER_XPORT_NAME_PASS
    488 
    489 /* event_server_accept_pass - accept descriptor */
    490 
    491 static void event_server_accept_pass(int unused_event, void *context)
    492 {
    493     int     listen_fd = CAST_ANY_PTR_TO_INT(context);
    494     int     time_left = -1;
    495     int     fd;
    496     HTABLE *attr = 0;
    497 
    498     if (event_server_drain_was_called)
    499 	return;
    500 
    501     /*
    502      * Be prepared for accept() to fail because some other process already
    503      * got the connection (the number of processes competing for clients is
    504      * kept small, so this is not a "thundering herd" problem). If the
    505      * accept() succeeds, be sure to disable non-blocking I/O, in order to
    506      * minimize confusion.
    507      */
    508     if (client_count == 0 && var_idle_limit > 0)
    509 	time_left = event_cancel_timer(event_server_timeout, (void *) 0);
    510 
    511     if (event_server_pre_accept)
    512 	event_server_pre_accept(event_server_name, event_server_argv);
    513     if (event_server_drain_was_called)
    514 	return;
    515     fd = pass_accept_attr(listen_fd, &attr);
    516     if (event_server_lock != 0
    517 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
    518 		   MYFLOCK_OP_NONE) < 0)
    519 	msg_fatal("select unlock: %m");
    520     if (fd < 0) {
    521 	if (errno != EAGAIN)
    522 	    msg_error("accept connection: %m");
    523 	if (time_left >= 0)
    524 	    event_request_timer(event_server_timeout, (void *) 0, time_left);
    525 	return;
    526     }
    527     event_server_wakeup(fd, attr);
    528 }
    529 
    530 #endif
    531 
    532 /* event_server_accept_inet - accept client connection request */
    533 
    534 static void event_server_accept_inet(int unused_event, void *context)
    535 {
    536     int     listen_fd = CAST_ANY_PTR_TO_INT(context);
    537     int     time_left = -1;
    538     int     fd;
    539 
    540     if (event_server_drain_was_called)
    541 	return;
    542 
    543     /*
    544      * Be prepared for accept() to fail because some other process already
    545      * got the connection (the number of processes competing for clients is
    546      * kept small, so this is not a "thundering herd" problem). If the
    547      * accept() succeeds, be sure to disable non-blocking I/O, in order to
    548      * minimize confusion.
    549      */
    550     if (client_count == 0 && var_idle_limit > 0)
    551 	time_left = event_cancel_timer(event_server_timeout, (void *) 0);
    552 
    553     if (event_server_pre_accept)
    554 	event_server_pre_accept(event_server_name, event_server_argv);
    555     if (event_server_drain_was_called)
    556 	return;
    557     fd = inet_accept(listen_fd);
    558     if (event_server_lock != 0
    559 	&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
    560 		   MYFLOCK_OP_NONE) < 0)
    561 	msg_fatal("select unlock: %m");
    562     if (fd < 0) {
    563 	if (errno != EAGAIN)
    564 	    msg_error("accept connection: %m");
    565 	if (time_left >= 0)
    566 	    event_request_timer(event_server_timeout, (void *) 0, time_left);
    567 	return;
    568     }
    569     event_server_wakeup(fd, (HTABLE *) 0);
    570 }
    571 
    572 /* event_server_main - the real main program */
    573 
    574 NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
    575 {
    576     const char *myname = "event_server_main";
    577     VSTREAM *stream = 0;
    578     char   *root_dir = 0;
    579     char   *user_name = 0;
    580     int     debug_me = 0;
    581     int     daemon_mode = 1;
    582     char   *service_name = basename(argv[0]);
    583     int     delay;
    584     int     c;
    585     int     fd;
    586     va_list ap;
    587     MAIL_SERVER_INIT_FN pre_init = 0;
    588     MAIL_SERVER_INIT_FN post_init = 0;
    589     MAIL_SERVER_LOOP_FN loop = 0;
    590     int     key;
    591     char   *transport = 0;
    592 
    593 #if 0
    594     char   *lock_path;
    595     VSTRING *why;
    596 
    597 #endif
    598     int     alone = 0;
    599     int     zerolimit = 0;
    600     WATCHDOG *watchdog;
    601     char   *oname_val;
    602     char   *oname;
    603     char   *oval;
    604     const char *err;
    605     char   *generation;
    606     int     msg_vstream_needed = 0;
    607     const char *dsn_filter_title;
    608     const char **dsn_filter_maps;
    609     int     retire_me_from_flags = 0;
    610     int     retire_me = 0;
    611 
    612     /*
    613      * Process environment options as early as we can.
    614      */
    615     if (getenv(CONF_ENV_VERB))
    616 	msg_verbose = 1;
    617     if (getenv(CONF_ENV_DEBUG))
    618 	debug_me = 1;
    619 
    620     /*
    621      * Don't die when a process goes away unexpectedly.
    622      */
    623     signal(SIGPIPE, SIG_IGN);
    624 
    625     /*
    626      * Don't die for frivolous reasons.
    627      */
    628 #ifdef SIGXFSZ
    629     signal(SIGXFSZ, SIG_IGN);
    630 #endif
    631 
    632     /*
    633      * May need this every now and then.
    634      */
    635     var_procname = mystrdup(basename(argv[0]));
    636     set_mail_conf_str(VAR_PROCNAME, var_procname);
    637 
    638     /*
    639      * Initialize logging and exit handler. Do the syslog first, so that its
    640      * initialization completes before we enter the optional chroot jail.
    641      */
    642     maillog_client_init(mail_task(var_procname), MAILLOG_CLIENT_FLAG_NONE);
    643     if (msg_verbose)
    644 	msg_info("daemon started");
    645 
    646     /*
    647      * Check the Postfix library version as soon as we enable logging.
    648      */
    649     MAIL_VERSION_CHECK;
    650 
    651     /*
    652      * Initialize from the configuration file. Allow command-line options to
    653      * override compiled-in defaults or configured parameter values.
    654      */
    655     mail_conf_suck();
    656 
    657     /*
    658      * After database open error, continue execution with reduced
    659      * functionality.
    660      */
    661     dict_allow_surrogate = 1;
    662 
    663     /*
    664      * Pick up policy settings from master process. Shut up error messages to
    665      * stderr, because no-one is going to see them.
    666      */
    667     opterr = 0;
    668     while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:r:s:St:uvVz")) > 0) {
    669 	switch (c) {
    670 	case 'c':
    671 	    root_dir = "setme";
    672 	    break;
    673 	case 'd':
    674 	    daemon_mode = 0;
    675 	    break;
    676 	case 'D':
    677 	    debug_me = 1;
    678 	    break;
    679 	case 'i':
    680 	    mail_conf_update(VAR_MAX_IDLE, optarg);
    681 	    break;
    682 	case 'l':
    683 	    alone = 1;
    684 	    break;
    685 	case 'm':
    686 	    mail_conf_update(VAR_MAX_USE, optarg);
    687 	    break;
    688 	case 'n':
    689 	    service_name = optarg;
    690 	    break;
    691 	case 'o':
    692 	    oname_val = mystrdup(optarg);
    693 	    if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
    694 		msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
    695 	    mail_conf_update(oname, oval);
    696 	    myfree(oname_val);
    697 	    break;
    698 	case 'r':
    699 	    if ((retire_me_from_flags = atoi(optarg)) <= 0)
    700 		msg_fatal("invalid retirement time: %s", optarg);
    701 	    break;
    702 	case 's':
    703 	    if ((socket_count = atoi(optarg)) <= 0)
    704 		msg_fatal("invalid socket_count: %s", optarg);
    705 	    break;
    706 	case 'S':
    707 	    stream = VSTREAM_IN;
    708 	    break;
    709 	case 'u':
    710 	    user_name = "setme";
    711 	    break;
    712 	case 't':
    713 	    transport = optarg;
    714 	    break;
    715 	case 'v':
    716 	    msg_verbose++;
    717 	    break;
    718 	case 'V':
    719 	    if (++msg_vstream_needed == 1)
    720 		msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
    721 	    break;
    722 	case 'z':
    723 	    zerolimit = 1;
    724 	    break;
    725 	default:
    726 	    msg_fatal("invalid option: %c", optopt);
    727 	    break;
    728 	}
    729     }
    730     set_mail_conf_str(VAR_SERVNAME, service_name);
    731 
    732     /*
    733      * Initialize generic parameters and re-initialize logging in case of a
    734      * non-default program name or logging destination.
    735      */
    736     mail_params_init();
    737     maillog_client_init(mail_task(var_procname), MAILLOG_CLIENT_FLAG_NONE);
    738 
    739     /*
    740      * Register higher-level dictionaries and initialize the support for
    741      * dynamically-loaded dictionaries.
    742      */
    743     mail_dict_init();
    744 
    745     /*
    746      * If not connected to stdin, stdin must not be a terminal.
    747      */
    748     if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    749 	msg_vstream_init(var_procname, VSTREAM_ERR);
    750 	msg_fatal("do not run this command by hand");
    751     }
    752 
    753     /*
    754      * Application-specific initialization.
    755      */
    756     va_start(ap, service);
    757     while ((key = va_arg(ap, int)) != 0) {
    758 	switch (key) {
    759 	case MAIL_SERVER_INT_TABLE:
    760 	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
    761 	    break;
    762 	case MAIL_SERVER_LONG_TABLE:
    763 	    get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
    764 	    break;
    765 	case MAIL_SERVER_STR_TABLE:
    766 	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
    767 	    break;
    768 	case MAIL_SERVER_BOOL_TABLE:
    769 	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
    770 	    break;
    771 	case MAIL_SERVER_TIME_TABLE:
    772 	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
    773 	    break;
    774 	case MAIL_SERVER_RAW_TABLE:
    775 	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
    776 	    break;
    777 	case MAIL_SERVER_NINT_TABLE:
    778 	    get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
    779 	    break;
    780 	case MAIL_SERVER_NBOOL_TABLE:
    781 	    get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
    782 	    break;
    783 	case MAIL_SERVER_PRE_INIT:
    784 	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
    785 	    break;
    786 	case MAIL_SERVER_POST_INIT:
    787 	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
    788 	    break;
    789 	case MAIL_SERVER_LOOP:
    790 	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
    791 	    break;
    792 	case MAIL_SERVER_EXIT:
    793 	    event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
    794 	    break;
    795 	case MAIL_SERVER_PRE_ACCEPT:
    796 	    event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
    797 	    break;
    798 	case MAIL_SERVER_PRE_DISCONN:
    799 	    event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
    800 	    break;
    801 	case MAIL_SERVER_IN_FLOW_DELAY:
    802 	    event_server_in_flow_delay = 1;
    803 	    break;
    804 	case MAIL_SERVER_SOLITARY:
    805 	    if (stream == 0 && !alone)
    806 		msg_fatal("service %s requires a process limit of 1",
    807 			  service_name);
    808 	    break;
    809 	case MAIL_SERVER_UNLIMITED:
    810 	    if (stream == 0 && !zerolimit)
    811 		msg_fatal("service %s requires a process limit of 0",
    812 			  service_name);
    813 	    break;
    814 	case MAIL_SERVER_PRIVILEGED:
    815 	    if (user_name)
    816 		msg_fatal("service %s requires privileged operation",
    817 			  service_name);
    818 	    break;
    819 	case MAIL_SERVER_WATCHDOG:
    820 	    event_server_watchdog = *va_arg(ap, int *);
    821 	    break;
    822 	case MAIL_SERVER_SLOW_EXIT:
    823 	    event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
    824 	    break;
    825 	case MAIL_SERVER_BOUNCE_INIT:
    826 	    dsn_filter_title = va_arg(ap, const char *);
    827 	    dsn_filter_maps = va_arg(ap, const char **);
    828 	    bounce_client_init(dsn_filter_title, *dsn_filter_maps);
    829 	    break;
    830 	case MAIL_SERVER_RETIRE_ME:
    831 	    if (retire_me_from_flags > 0)
    832 		retire_me = retire_me_from_flags;
    833 	    else if (var_idle_limit == 0 || var_use_limit == 0
    834 		     || var_idle_limit > 18000 / var_use_limit)
    835 		retire_me = 18000;
    836 	    else
    837 		retire_me = var_idle_limit * var_use_limit;
    838 	    break;
    839 	default:
    840 	    msg_panic("%s: unknown argument type: %d", myname, key);
    841 	}
    842     }
    843     va_end(ap);
    844 
    845     if (root_dir)
    846 	root_dir = var_queue_dir;
    847     if (user_name)
    848 	user_name = var_mail_owner;
    849 
    850     /*
    851      * Can options be required?
    852      */
    853     if (stream == 0) {
    854 	if (transport == 0)
    855 	    msg_fatal("no transport type specified");
    856 	if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
    857 	    event_server_accept = event_server_accept_inet;
    858 	else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
    859 	    event_server_accept = event_server_accept_local;
    860 #ifdef MASTER_XPORT_NAME_PASS
    861 	else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
    862 	    event_server_accept = event_server_accept_pass;
    863 #endif
    864 	else
    865 	    msg_fatal("unsupported transport type: %s", transport);
    866     }
    867 
    868     /*
    869      * Retrieve process generation from environment.
    870      */
    871     if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
    872 	if (!alldig(generation))
    873 	    msg_fatal("bad generation: %s", generation);
    874 	OCTAL_TO_UNSIGNED(event_server_generation, generation);
    875 	if (msg_verbose)
    876 	    msg_info("process generation: %s (%o)",
    877 		     generation, event_server_generation);
    878     }
    879 
    880     /*
    881      * Optionally start the debugger on ourself.
    882      */
    883     if (debug_me)
    884 	debug_process();
    885 
    886     /*
    887      * Traditionally, BSD select() can't handle multiple processes selecting
    888      * on the same socket, and wakes up every process in select(). See TCP/IP
    889      * Illustrated volume 2 page 532. We avoid select() collisions with an
    890      * external lock file.
    891      */
    892 
    893     /*
    894      * XXX Can't compete for exclusive access to the listen socket because we
    895      * also have to monitor existing client connections for service requests.
    896      */
    897 #if 0
    898     if (stream == 0 && !alone) {
    899 	lock_path = concatenate(DEF_PID_DIR, "/", transport,
    900 				".", service_name, (char *) 0);
    901 	why = vstring_alloc(1);
    902 	if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
    903 				      (struct stat *) 0, -1, -1, why)) == 0)
    904 	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
    905 	close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
    906 	myfree(lock_path);
    907 	vstring_free(why);
    908     }
    909 #endif
    910 
    911     /*
    912      * Set up call-back info.
    913      */
    914     event_server_service = service;
    915     event_server_name = service_name;
    916     event_server_argv = argv + optind;
    917 
    918     /*
    919      * Run pre-jail initialization.
    920      */
    921     if (chdir(var_queue_dir) < 0)
    922 	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    923     if (pre_init)
    924 	pre_init(event_server_name, event_server_argv);
    925 
    926     /*
    927      * Optionally, restrict the damage that this process can do.
    928      */
    929     resolve_local_init();
    930     tzset();
    931     chroot_uid(root_dir, user_name);
    932 
    933     /*
    934      * Run post-jail initialization.
    935      */
    936     if (post_init)
    937 	post_init(event_server_name, event_server_argv);
    938 
    939     /*
    940      * Are we running as a one-shot server with the client connection on
    941      * standard input? If so, make sure the output is written to stdout so as
    942      * to satisfy common expectation.
    943      */
    944     if (stream != 0) {
    945 	vstream_control(stream,
    946 			CA_VSTREAM_CTL_DOUBLE,
    947 			CA_VSTREAM_CTL_WRITE_FD(STDOUT_FILENO),
    948 			CA_VSTREAM_CTL_END);
    949 	service(stream, event_server_name, event_server_argv);
    950 	vstream_fflush(stream);
    951 	event_server_exit();
    952     }
    953 
    954     /*
    955      * Running as a semi-resident server. Service connection requests.
    956      * Terminate when we have serviced a sufficient number of clients, when
    957      * no-one has been talking to us for a configurable amount of time, or
    958      * when the master process terminated abnormally.
    959      */
    960     if (var_idle_limit > 0)
    961 	event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
    962     if (retire_me)
    963 	event_request_timer(event_server_retire, (void *) 0, retire_me);
    964     for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
    965 	event_enable_read(fd, event_server_accept, CAST_INT_TO_VOID_PTR(fd));
    966 	close_on_exec(fd, CLOSE_ON_EXEC);
    967     }
    968     event_enable_read(MASTER_STATUS_FD, event_server_abort, (void *) 0);
    969     close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    970     close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    971     close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    972     watchdog = watchdog_create(event_server_watchdog,
    973 			       (WATCHDOG_FN) 0, (void *) 0);
    974 
    975     /*
    976      * The event loop, at last.
    977      */
    978     while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
    979 	if (event_server_lock != 0) {
    980 	    watchdog_stop(watchdog);
    981 	    if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
    982 			MYFLOCK_OP_EXCLUSIVE) < 0)
    983 		msg_fatal("select lock: %m");
    984 	}
    985 	watchdog_start(watchdog);
    986 	delay = loop ? loop(event_server_name, event_server_argv) : -1;
    987 	event_loop(delay);
    988     }
    989     event_server_exit();
    990 }
    991