1 /* $NetBSD: event_server.c,v 1.4 2022/10/08 16:12:46 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
279 /* event_server_exit - normal termination */
280
event_server_exit(void)281 static NORETURN event_server_exit(void)
282 {
283 if (event_server_onexit)
284 event_server_onexit(event_server_name, event_server_argv);
285 exit(0);
286 }
287
288 /* event_server_retire - retire when idle */
289
event_server_retire(int unused_event,void * unused_context)290 static void event_server_retire(int unused_event, void *unused_context)
291 {
292 if (msg_verbose)
293 msg_info("time to retire -- %s", event_server_slow_exit ?
294 "draining" : "exiting");
295 event_disable_readwrite(MASTER_STATUS_FD);
296 if (event_server_slow_exit)
297 event_server_slow_exit(event_server_name, event_server_argv);
298 else
299 event_server_exit();
300 }
301
302 /* event_server_abort - terminate after abnormal master exit */
303
event_server_abort(int unused_event,void * unused_context)304 static void event_server_abort(int unused_event, void *unused_context)
305 {
306 if (msg_verbose)
307 msg_info("master disconnect -- %s", event_server_slow_exit ?
308 "draining" : "exiting");
309 event_disable_readwrite(MASTER_STATUS_FD);
310 if (event_server_slow_exit)
311 event_server_slow_exit(event_server_name, event_server_argv);
312 else
313 event_server_exit();
314 }
315
316 /* event_server_timeout - idle time exceeded */
317
event_server_timeout(int unused_event,void * unused_context)318 static void event_server_timeout(int unused_event, void *unused_context)
319 {
320 if (msg_verbose)
321 msg_info("idle timeout -- exiting");
322 event_server_exit();
323 }
324
325 /* event_server_drain - stop accepting new clients */
326
event_server_drain(void)327 int event_server_drain(void)
328 {
329 const char *myname = "event_server_drain";
330 int fd;
331
332 switch (fork()) {
333 /* Try again later. */
334 case -1:
335 return (-1);
336 /* Finish existing clients in the background, then terminate. */
337 case 0:
338 (void) msg_cleanup((MSG_CLEANUP_FN) 0);
339 event_fork();
340 for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
341 event_disable_readwrite(fd);
342 (void) close(fd);
343 /* Play safe - don't reuse this file number. */
344 if (DUP2(STDIN_FILENO, fd) < 0)
345 msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
346 }
347 var_use_limit = 1;
348 return (0);
349 /* Let the master start a new process. */
350 default:
351 exit(0);
352 }
353 }
354
355 /* event_server_disconnect - terminate client session */
356
event_server_disconnect(VSTREAM * stream)357 void event_server_disconnect(VSTREAM *stream)
358 {
359 if (msg_verbose)
360 msg_info("connection closed fd %d", vstream_fileno(stream));
361 if (event_server_pre_disconn)
362 event_server_pre_disconn(stream, event_server_name, event_server_argv);
363 (void) vstream_fclose(stream);
364 client_count--;
365 /* Avoid integer wrap-around in a persistent process. */
366 if (use_count < INT_MAX)
367 use_count++;
368 if (client_count == 0 && var_idle_limit > 0)
369 event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
370 }
371
372 /* event_server_execute - in case (char *) != (struct *) */
373
event_server_execute(int unused_event,void * context)374 static void event_server_execute(int unused_event, void *context)
375 {
376 VSTREAM *stream = (VSTREAM *) context;
377 HTABLE *attr = (HTABLE *) vstream_context(stream);
378
379 if (event_server_lock != 0
380 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
381 MYFLOCK_OP_NONE) < 0)
382 msg_fatal("select unlock: %m");
383
384 /*
385 * Do bother the application when the client disconnected. Don't drop the
386 * already accepted client request after "postfix reload"; that would be
387 * rude.
388 */
389 if (master_notify(var_pid, event_server_generation, MASTER_STAT_TAKEN) < 0)
390 /* void */ ;
391 event_server_service(stream, event_server_name, event_server_argv);
392 if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
393 event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
394 if (attr)
395 htable_free(attr, myfree);
396 }
397
398 /* event_server_wakeup - wake up application */
399
event_server_wakeup(int fd,HTABLE * attr)400 static void event_server_wakeup(int fd, HTABLE *attr)
401 {
402 VSTREAM *stream;
403 char *tmp;
404
405 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
406 #ifndef THRESHOLD_FD_WORKAROUND
407 #define THRESHOLD_FD_WORKAROUND 128
408 #endif
409 int new_fd;
410
411 /*
412 * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
413 * case of a multi-server with a thousand clients.
414 */
415 if (fd < THRESHOLD_FD_WORKAROUND) {
416 if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
417 msg_fatal("fcntl F_DUPFD: %m");
418 (void) close(fd);
419 fd = new_fd;
420 }
421 #endif
422 if (msg_verbose)
423 msg_info("connection established fd %d", fd);
424 non_blocking(fd, BLOCKING);
425 close_on_exec(fd, CLOSE_ON_EXEC);
426 client_count++;
427 stream = vstream_fdopen(fd, O_RDWR);
428 tmp = concatenate(event_server_name, " socket", (char *) 0);
429 vstream_control(stream,
430 CA_VSTREAM_CTL_PATH(tmp),
431 CA_VSTREAM_CTL_CONTEXT((void *) attr),
432 CA_VSTREAM_CTL_END);
433 myfree(tmp);
434 timed_ipc_setup(stream);
435 if (event_server_in_flow_delay && mail_flow_get(1) < 0)
436 event_request_timer(event_server_execute, (void *) stream,
437 var_in_flow_delay);
438 else
439 event_server_execute(0, (void *) stream);
440 }
441
442 /* event_server_accept_local - accept client connection request */
443
event_server_accept_local(int unused_event,void * context)444 static void event_server_accept_local(int unused_event, void *context)
445 {
446 int listen_fd = CAST_ANY_PTR_TO_INT(context);
447 int time_left = -1;
448 int fd;
449
450 /*
451 * Be prepared for accept() to fail because some other process already
452 * got the connection (the number of processes competing for clients is
453 * kept small, so this is not a "thundering herd" problem). If the
454 * accept() succeeds, be sure to disable non-blocking I/O, in order to
455 * minimize confusion.
456 */
457 if (client_count == 0 && var_idle_limit > 0)
458 time_left = event_cancel_timer(event_server_timeout, (void *) 0);
459
460 if (event_server_pre_accept)
461 event_server_pre_accept(event_server_name, event_server_argv);
462 fd = LOCAL_ACCEPT(listen_fd);
463 if (event_server_lock != 0
464 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
465 MYFLOCK_OP_NONE) < 0)
466 msg_fatal("select unlock: %m");
467 if (fd < 0) {
468 if (errno != EAGAIN)
469 msg_error("accept connection: %m");
470 if (time_left >= 0)
471 event_request_timer(event_server_timeout, (void *) 0, time_left);
472 return;
473 }
474 event_server_wakeup(fd, (HTABLE *) 0);
475 }
476
477 #ifdef MASTER_XPORT_NAME_PASS
478
479 /* event_server_accept_pass - accept descriptor */
480
event_server_accept_pass(int unused_event,void * context)481 static void event_server_accept_pass(int unused_event, void *context)
482 {
483 int listen_fd = CAST_ANY_PTR_TO_INT(context);
484 int time_left = -1;
485 int fd;
486 HTABLE *attr = 0;
487
488 /*
489 * Be prepared for accept() to fail because some other process already
490 * got the connection (the number of processes competing for clients is
491 * kept small, so this is not a "thundering herd" problem). If the
492 * accept() succeeds, be sure to disable non-blocking I/O, in order to
493 * minimize confusion.
494 */
495 if (client_count == 0 && var_idle_limit > 0)
496 time_left = event_cancel_timer(event_server_timeout, (void *) 0);
497
498 if (event_server_pre_accept)
499 event_server_pre_accept(event_server_name, event_server_argv);
500 fd = pass_accept_attr(listen_fd, &attr);
501 if (event_server_lock != 0
502 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
503 MYFLOCK_OP_NONE) < 0)
504 msg_fatal("select unlock: %m");
505 if (fd < 0) {
506 if (errno != EAGAIN)
507 msg_error("accept connection: %m");
508 if (time_left >= 0)
509 event_request_timer(event_server_timeout, (void *) 0, time_left);
510 return;
511 }
512 event_server_wakeup(fd, attr);
513 }
514
515 #endif
516
517 /* event_server_accept_inet - accept client connection request */
518
event_server_accept_inet(int unused_event,void * context)519 static void event_server_accept_inet(int unused_event, void *context)
520 {
521 int listen_fd = CAST_ANY_PTR_TO_INT(context);
522 int time_left = -1;
523 int fd;
524
525 /*
526 * Be prepared for accept() to fail because some other process already
527 * got the connection (the number of processes competing for clients is
528 * kept small, so this is not a "thundering herd" problem). If the
529 * accept() succeeds, be sure to disable non-blocking I/O, in order to
530 * minimize confusion.
531 */
532 if (client_count == 0 && var_idle_limit > 0)
533 time_left = event_cancel_timer(event_server_timeout, (void *) 0);
534
535 if (event_server_pre_accept)
536 event_server_pre_accept(event_server_name, event_server_argv);
537 fd = inet_accept(listen_fd);
538 if (event_server_lock != 0
539 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
540 MYFLOCK_OP_NONE) < 0)
541 msg_fatal("select unlock: %m");
542 if (fd < 0) {
543 if (errno != EAGAIN)
544 msg_error("accept connection: %m");
545 if (time_left >= 0)
546 event_request_timer(event_server_timeout, (void *) 0, time_left);
547 return;
548 }
549 event_server_wakeup(fd, (HTABLE *) 0);
550 }
551
552 /* event_server_main - the real main program */
553
event_server_main(int argc,char ** argv,MULTI_SERVER_FN service,...)554 NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
555 {
556 const char *myname = "event_server_main";
557 VSTREAM *stream = 0;
558 char *root_dir = 0;
559 char *user_name = 0;
560 int debug_me = 0;
561 int daemon_mode = 1;
562 char *service_name = basename(argv[0]);
563 int delay;
564 int c;
565 int fd;
566 va_list ap;
567 MAIL_SERVER_INIT_FN pre_init = 0;
568 MAIL_SERVER_INIT_FN post_init = 0;
569 MAIL_SERVER_LOOP_FN loop = 0;
570 int key;
571 char *transport = 0;
572
573 #if 0
574 char *lock_path;
575 VSTRING *why;
576
577 #endif
578 int alone = 0;
579 int zerolimit = 0;
580 WATCHDOG *watchdog;
581 char *oname_val;
582 char *oname;
583 char *oval;
584 const char *err;
585 char *generation;
586 int msg_vstream_needed = 0;
587 const char *dsn_filter_title;
588 const char **dsn_filter_maps;
589 int retire_me_from_flags = 0;
590 int retire_me = 0;
591
592 /*
593 * Process environment options as early as we can.
594 */
595 if (getenv(CONF_ENV_VERB))
596 msg_verbose = 1;
597 if (getenv(CONF_ENV_DEBUG))
598 debug_me = 1;
599
600 /*
601 * Don't die when a process goes away unexpectedly.
602 */
603 signal(SIGPIPE, SIG_IGN);
604
605 /*
606 * Don't die for frivolous reasons.
607 */
608 #ifdef SIGXFSZ
609 signal(SIGXFSZ, SIG_IGN);
610 #endif
611
612 /*
613 * May need this every now and then.
614 */
615 var_procname = mystrdup(basename(argv[0]));
616 set_mail_conf_str(VAR_PROCNAME, var_procname);
617
618 /*
619 * Initialize logging and exit handler. Do the syslog first, so that its
620 * initialization completes before we enter the optional chroot jail.
621 */
622 maillog_client_init(mail_task(var_procname), MAILLOG_CLIENT_FLAG_NONE);
623 if (msg_verbose)
624 msg_info("daemon started");
625
626 /*
627 * Check the Postfix library version as soon as we enable logging.
628 */
629 MAIL_VERSION_CHECK;
630
631 /*
632 * Initialize from the configuration file. Allow command-line options to
633 * override compiled-in defaults or configured parameter values.
634 */
635 mail_conf_suck();
636
637 /*
638 * After database open error, continue execution with reduced
639 * functionality.
640 */
641 dict_allow_surrogate = 1;
642
643 /*
644 * Pick up policy settings from master process. Shut up error messages to
645 * stderr, because no-one is going to see them.
646 */
647 opterr = 0;
648 while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:r:s:St:uvVz")) > 0) {
649 switch (c) {
650 case 'c':
651 root_dir = "setme";
652 break;
653 case 'd':
654 daemon_mode = 0;
655 break;
656 case 'D':
657 debug_me = 1;
658 break;
659 case 'i':
660 mail_conf_update(VAR_MAX_IDLE, optarg);
661 break;
662 case 'l':
663 alone = 1;
664 break;
665 case 'm':
666 mail_conf_update(VAR_MAX_USE, optarg);
667 break;
668 case 'n':
669 service_name = optarg;
670 break;
671 case 'o':
672 oname_val = mystrdup(optarg);
673 if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
674 msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
675 mail_conf_update(oname, oval);
676 myfree(oname_val);
677 break;
678 case 'r':
679 if ((retire_me_from_flags = atoi(optarg)) <= 0)
680 msg_fatal("invalid retirement time: %s", optarg);
681 break;
682 case 's':
683 if ((socket_count = atoi(optarg)) <= 0)
684 msg_fatal("invalid socket_count: %s", optarg);
685 break;
686 case 'S':
687 stream = VSTREAM_IN;
688 break;
689 case 'u':
690 user_name = "setme";
691 break;
692 case 't':
693 transport = optarg;
694 break;
695 case 'v':
696 msg_verbose++;
697 break;
698 case 'V':
699 if (++msg_vstream_needed == 1)
700 msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
701 break;
702 case 'z':
703 zerolimit = 1;
704 break;
705 default:
706 msg_fatal("invalid option: %c", optopt);
707 break;
708 }
709 }
710 set_mail_conf_str(VAR_SERVNAME, service_name);
711
712 /*
713 * Initialize generic parameters and re-initialize logging in case of a
714 * non-default program name or logging destination.
715 */
716 mail_params_init();
717 maillog_client_init(mail_task(var_procname), MAILLOG_CLIENT_FLAG_NONE);
718
719 /*
720 * Register higher-level dictionaries and initialize the support for
721 * dynamically-loaded dictionaries.
722 */
723 mail_dict_init();
724
725 /*
726 * If not connected to stdin, stdin must not be a terminal.
727 */
728 if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
729 msg_vstream_init(var_procname, VSTREAM_ERR);
730 msg_fatal("do not run this command by hand");
731 }
732
733 /*
734 * Application-specific initialization.
735 */
736 va_start(ap, service);
737 while ((key = va_arg(ap, int)) != 0) {
738 switch (key) {
739 case MAIL_SERVER_INT_TABLE:
740 get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
741 break;
742 case MAIL_SERVER_LONG_TABLE:
743 get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
744 break;
745 case MAIL_SERVER_STR_TABLE:
746 get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
747 break;
748 case MAIL_SERVER_BOOL_TABLE:
749 get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
750 break;
751 case MAIL_SERVER_TIME_TABLE:
752 get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
753 break;
754 case MAIL_SERVER_RAW_TABLE:
755 get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
756 break;
757 case MAIL_SERVER_NINT_TABLE:
758 get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
759 break;
760 case MAIL_SERVER_NBOOL_TABLE:
761 get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
762 break;
763 case MAIL_SERVER_PRE_INIT:
764 pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
765 break;
766 case MAIL_SERVER_POST_INIT:
767 post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
768 break;
769 case MAIL_SERVER_LOOP:
770 loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
771 break;
772 case MAIL_SERVER_EXIT:
773 event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
774 break;
775 case MAIL_SERVER_PRE_ACCEPT:
776 event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
777 break;
778 case MAIL_SERVER_PRE_DISCONN:
779 event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
780 break;
781 case MAIL_SERVER_IN_FLOW_DELAY:
782 event_server_in_flow_delay = 1;
783 break;
784 case MAIL_SERVER_SOLITARY:
785 if (stream == 0 && !alone)
786 msg_fatal("service %s requires a process limit of 1",
787 service_name);
788 break;
789 case MAIL_SERVER_UNLIMITED:
790 if (stream == 0 && !zerolimit)
791 msg_fatal("service %s requires a process limit of 0",
792 service_name);
793 break;
794 case MAIL_SERVER_PRIVILEGED:
795 if (user_name)
796 msg_fatal("service %s requires privileged operation",
797 service_name);
798 break;
799 case MAIL_SERVER_WATCHDOG:
800 event_server_watchdog = *va_arg(ap, int *);
801 break;
802 case MAIL_SERVER_SLOW_EXIT:
803 event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
804 break;
805 case MAIL_SERVER_BOUNCE_INIT:
806 dsn_filter_title = va_arg(ap, const char *);
807 dsn_filter_maps = va_arg(ap, const char **);
808 bounce_client_init(dsn_filter_title, *dsn_filter_maps);
809 break;
810 case MAIL_SERVER_RETIRE_ME:
811 if (retire_me_from_flags > 0)
812 retire_me = retire_me_from_flags;
813 else if (var_idle_limit == 0 || var_use_limit == 0
814 || var_idle_limit > 18000 / var_use_limit)
815 retire_me = 18000;
816 else
817 retire_me = var_idle_limit * var_use_limit;
818 break;
819 default:
820 msg_panic("%s: unknown argument type: %d", myname, key);
821 }
822 }
823 va_end(ap);
824
825 if (root_dir)
826 root_dir = var_queue_dir;
827 if (user_name)
828 user_name = var_mail_owner;
829
830 /*
831 * Can options be required?
832 */
833 if (stream == 0) {
834 if (transport == 0)
835 msg_fatal("no transport type specified");
836 if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
837 event_server_accept = event_server_accept_inet;
838 else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
839 event_server_accept = event_server_accept_local;
840 #ifdef MASTER_XPORT_NAME_PASS
841 else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
842 event_server_accept = event_server_accept_pass;
843 #endif
844 else
845 msg_fatal("unsupported transport type: %s", transport);
846 }
847
848 /*
849 * Retrieve process generation from environment.
850 */
851 if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
852 if (!alldig(generation))
853 msg_fatal("bad generation: %s", generation);
854 OCTAL_TO_UNSIGNED(event_server_generation, generation);
855 if (msg_verbose)
856 msg_info("process generation: %s (%o)",
857 generation, event_server_generation);
858 }
859
860 /*
861 * Optionally start the debugger on ourself.
862 */
863 if (debug_me)
864 debug_process();
865
866 /*
867 * Traditionally, BSD select() can't handle multiple processes selecting
868 * on the same socket, and wakes up every process in select(). See TCP/IP
869 * Illustrated volume 2 page 532. We avoid select() collisions with an
870 * external lock file.
871 */
872
873 /*
874 * XXX Can't compete for exclusive access to the listen socket because we
875 * also have to monitor existing client connections for service requests.
876 */
877 #if 0
878 if (stream == 0 && !alone) {
879 lock_path = concatenate(DEF_PID_DIR, "/", transport,
880 ".", service_name, (char *) 0);
881 why = vstring_alloc(1);
882 if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
883 (struct stat *) 0, -1, -1, why)) == 0)
884 msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
885 close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
886 myfree(lock_path);
887 vstring_free(why);
888 }
889 #endif
890
891 /*
892 * Set up call-back info.
893 */
894 event_server_service = service;
895 event_server_name = service_name;
896 event_server_argv = argv + optind;
897
898 /*
899 * Run pre-jail initialization.
900 */
901 if (chdir(var_queue_dir) < 0)
902 msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
903 if (pre_init)
904 pre_init(event_server_name, event_server_argv);
905
906 /*
907 * Optionally, restrict the damage that this process can do.
908 */
909 resolve_local_init();
910 tzset();
911 chroot_uid(root_dir, user_name);
912
913 /*
914 * Run post-jail initialization.
915 */
916 if (post_init)
917 post_init(event_server_name, event_server_argv);
918
919 /*
920 * Are we running as a one-shot server with the client connection on
921 * standard input? If so, make sure the output is written to stdout so as
922 * to satisfy common expectation.
923 */
924 if (stream != 0) {
925 vstream_control(stream,
926 CA_VSTREAM_CTL_DOUBLE,
927 CA_VSTREAM_CTL_WRITE_FD(STDOUT_FILENO),
928 CA_VSTREAM_CTL_END);
929 service(stream, event_server_name, event_server_argv);
930 vstream_fflush(stream);
931 event_server_exit();
932 }
933
934 /*
935 * Running as a semi-resident server. Service connection requests.
936 * Terminate when we have serviced a sufficient number of clients, when
937 * no-one has been talking to us for a configurable amount of time, or
938 * when the master process terminated abnormally.
939 */
940 if (var_idle_limit > 0)
941 event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
942 if (retire_me)
943 event_request_timer(event_server_retire, (void *) 0, retire_me);
944 for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
945 event_enable_read(fd, event_server_accept, CAST_INT_TO_VOID_PTR(fd));
946 close_on_exec(fd, CLOSE_ON_EXEC);
947 }
948 event_enable_read(MASTER_STATUS_FD, event_server_abort, (void *) 0);
949 close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
950 close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
951 close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
952 watchdog = watchdog_create(event_server_watchdog,
953 (WATCHDOG_FN) 0, (void *) 0);
954
955 /*
956 * The event loop, at last.
957 */
958 while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
959 if (event_server_lock != 0) {
960 watchdog_stop(watchdog);
961 if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
962 MYFLOCK_OP_EXCLUSIVE) < 0)
963 msg_fatal("select lock: %m");
964 }
965 watchdog_start(watchdog);
966 delay = loop ? loop(event_server_name, event_server_argv) : -1;
967 event_loop(delay);
968 }
969 event_server_exit();
970 }
971