Postfix3.3.1
trigger_server.c
[詳解]
1 /*++
2 /* NAME
3 /* trigger_server 3
4 /* SUMMARY
5 /* skeleton triggered mail subsystem
6 /* SYNOPSIS
7 /* #include <mail_server.h>
8 /*
9 /* NORETURN trigger_server_main(argc, argv, service, key, value, ...)
10 /* int argc;
11 /* char **argv;
12 /* void (*service)(char *buf, int len, char *service_name, char **argv);
13 /* int key;
14 /* DESCRIPTION
15 /* This module implements a skeleton for triggered
16 /* mail subsystems: mail subsystem programs that wake up on
17 /* client request and perform some activity without further
18 /* client interaction. This module supports local IPC via FIFOs
19 /* and via UNIX-domain sockets. The resulting program expects to be
20 /* run from the \fBmaster\fR process.
21 /*
22 /* trigger_server_main() is the skeleton entry point. It should be
23 /* called from the application main program. The skeleton does the
24 /* generic command-line options processing, initialization of
25 /* configurable parameters, and connection management.
26 /* The skeleton never returns.
27 /*
28 /* Arguments:
29 /* .IP "void (*service)(char *buf, int len, char *service_name, char **argv)"
30 /* A pointer to a function that is called by the skeleton each time
31 /* a client connects to the program's service port. The function is
32 /* run after the program has irrevocably dropped its privileges.
33 /* The buffer argument specifies the data read from the trigger port;
34 /* this data corresponds to one or more trigger requests.
35 /* The len argument specifies how much client data is available.
36 /* The maximal size of the buffer is specified via the
37 /* TRIGGER_BUF_SIZE manifest constant.
38 /* The service name argument corresponds to the service name in the
39 /* master.cf file.
40 /* The argv argument specifies command-line arguments left over
41 /* after options processing.
42 /* The \fBserver\fR argument provides the following information:
43 /* .PP
44 /* Optional arguments are specified as a null-terminated list
45 /* with macros that have zero or more arguments:
46 /* .IP "CA_MAIL_SERVER_INT_TABLE(CONFIG_INT_TABLE *)"
47 /* A table with configurable parameters, to be loaded from the
48 /* global Postfix configuration file. Tables are loaded in the
49 /* order as specified, and multiple instances of the same type
50 /* are allowed.
51 /* .IP "CA_MAIL_SERVER_LONG_TABLE(CONFIG_LONG_TABLE *)"
52 /* A table with configurable parameters, to be loaded from the
53 /* global Postfix configuration file. Tables are loaded in the
54 /* order as specified, and multiple instances of the same type
55 /* are allowed.
56 /* .IP "CA_MAIL_SERVER_STR_TABLE(CONFIG_STR_TABLE *)"
57 /* A table with configurable parameters, to be loaded from the
58 /* global Postfix configuration file. Tables are loaded in the
59 /* order as specified, and multiple instances of the same type
60 /* are allowed.
61 /* .IP "CA_MAIL_SERVER_BOOL_TABLE(CONFIG_BOOL_TABLE *)"
62 /* A table with configurable parameters, to be loaded from the
63 /* global Postfix configuration file. Tables are loaded in the
64 /* order as specified, and multiple instances of the same type
65 /* are allowed.
66 /* .IP "CA_MAIL_SERVER_TIME_TABLE(CONFIG_TIME_TABLE *)"
67 /* A table with configurable parameters, to be loaded from the
68 /* global Postfix configuration file. Tables are loaded in the
69 /* order as specified, and multiple instances of the same type
70 /* are allowed.
71 /* .IP "CA_MAIL_SERVER_RAW_TABLE(CONFIG_RAW_TABLE *)"
72 /* A table with configurable parameters, to be loaded from the
73 /* global Postfix configuration file. Tables are loaded in the
74 /* order as specified, and multiple instances of the same type
75 /* are allowed. Raw parameters are not subjected to $name
76 /* evaluation.
77 /* .IP "CA_MAIL_SERVER_NINT_TABLE(CONFIG_NINT_TABLE *)"
78 /* A table with configurable parameters, to be loaded from the
79 /* global Postfix configuration file. Tables are loaded in the
80 /* order as specified, and multiple instances of the same type
81 /* are allowed.
82 /* .IP "CA_MAIL_SERVER_NBOOL_TABLE(CONFIG_NBOOL_TABLE *)"
83 /* A table with configurable parameters, to be loaded from the
84 /* global Postfix configuration file. Tables are loaded in the
85 /* order as specified, and multiple instances of the same type
86 /* are allowed.
87 /* .IP "CA_MAIL_SERVER_PRE_INIT(void *(char *service_name, char **argv))"
88 /* A pointer to a function that is called once
89 /* by the skeleton after it has read the global configuration file
90 /* and after it has processed command-line arguments, but before
91 /* the skeleton has optionally relinquished the process privileges.
92 /* .sp
93 /* Only the last instance of this parameter type is remembered.
94 /* .IP "CA_MAIL_SERVER_POST_INIT(void *(char *service_name, char **argv))"
95 /* A pointer to a function that is called once
96 /* by the skeleton after it has optionally relinquished the process
97 /* privileges, but before servicing client connection requests.
98 /* .sp
99 /* Only the last instance of this parameter type is remembered.
100 /* .IP "CA_MAIL_SERVER_LOOP(int *(char *service_name, char **argv))"
101 /* A pointer to function that is executed from
102 /* within the event loop, whenever an I/O or timer event has happened,
103 /* or whenever nothing has happened for a specified amount of time.
104 /* The result value of the function specifies how long to wait until
105 /* the next event. Specify -1 to wait for "as long as it takes".
106 /* .sp
107 /* Only the last instance of this parameter type is remembered.
108 /* .IP "CA_MAIL_SERVER_EXIT(void *(char *service_name, char **argv))"
109 /* A pointer to function that is executed immediately before normal
110 /* process termination.
111 /* .sp
112 /* Only the last instance of this parameter type is remembered.
113 /* .IP "CA_MAIL_SERVER_PRE_ACCEPT(void *(char *service_name, char **argv))"
114 /* Function to be executed prior to accepting a new request.
115 /* .sp
116 /* Only the last instance of this parameter type is remembered.
117 /* .IP "CA_MAIL_SERVER_IN_FLOW_DELAY(none)"
118 /* Pause $in_flow_delay seconds when no "mail flow control token"
119 /* is available. A token is consumed for each connection request.
120 /* .IP CA_MAIL_SERVER_SOLITARY
121 /* This service must be configured with process limit of 1.
122 /* .IP CA_MAIL_SERVER_UNLIMITED
123 /* This service must be configured with process limit of 0.
124 /* .IP CA_MAIL_SERVER_PRIVILEGED
125 /* This service must be configured as privileged.
126 /* .IP "CA_MAIL_SERVER_WATCHDOG(int *)"
127 /* Override the default 1000s watchdog timeout. The value is
128 /* used after command-line and main.cf file processing.
129 /* .IP "CA_MAIL_SERVER_BOUNCE_INIT(const char *, const char **)"
130 /* Initialize the DSN filter for the bounce/defer service
131 /* clients with the specified map source and map names.
132 /* .PP
133 /* The var_use_limit variable limits the number of clients that
134 /* a server can service before it commits suicide.
135 /* This value is taken from the global \fBmain.cf\fR configuration
136 /* file. Setting \fBvar_use_limit\fR to zero disables the client limit.
137 /*
138 /* The var_idle_limit variable limits the time that a service
139 /* receives no client connection requests before it commits suicide.
140 /* This value is taken from the global \fBmain.cf\fR configuration
141 /* file. Setting \fBvar_use_limit\fR to zero disables the idle limit.
142 /* DIAGNOSTICS
143 /* Problems and transactions are logged to \fBsyslogd\fR(8).
144 /* BUGS
145 /* Works with FIFO-based services only.
146 /* SEE ALSO
147 /* master(8), master process
148 /* syslogd(8) system logging
149 /* LICENSE
150 /* .ad
151 /* .fi
152 /* The Secure Mailer license must be distributed with this software.
153 /* AUTHOR(S)
154 /* Wietse Venema
155 /* IBM T.J. Watson Research
156 /* P.O. Box 704
157 /* Yorktown Heights, NY 10598, USA
158 /*
159 /* Wietse Venema
160 /* Google, Inc.
161 /* 111 8th Avenue
162 /* New York, NY 10011, USA
163 /*--*/
164 
165 /* System library. */
166 
167 #include <sys_defs.h>
168 #include <sys/socket.h>
169 #include <unistd.h>
170 #include <signal.h>
171 #include <syslog.h>
172 #include <stdlib.h>
173 #include <limits.h>
174 #include <string.h>
175 #include <errno.h>
176 #include <fcntl.h>
177 #include <stdarg.h>
178 #ifdef STRCASECMP_IN_STRINGS_H
179 #include <strings.h>
180 #endif
181 #include <time.h>
182 
183 /* Utility library. */
184 
185 #include <msg.h>
186 #include <msg_syslog.h>
187 #include <msg_vstream.h>
188 #include <chroot_uid.h>
189 #include <vstring.h>
190 #include <vstream.h>
191 #include <msg_vstream.h>
192 #include <mymalloc.h>
193 #include <events.h>
194 #include <iostuff.h>
195 #include <stringops.h>
196 #include <sane_accept.h>
197 #include <myflock.h>
198 #include <safe_open.h>
199 #include <listen.h>
200 #include <watchdog.h>
201 #include <split_at.h>
202 
203 /* Global library. */
204 
205 #include <mail_params.h>
206 #include <mail_task.h>
207 #include <debug_process.h>
208 #include <mail_conf.h>
209 #include <mail_dict.h>
210 #include <resolve_local.h>
211 #include <mail_flow.h>
212 #include <mail_version.h>
213 #include <bounce.h>
214 
215 /* Process manager. */
216 
217 #include "master_proto.h"
218 
219 /* Application-specific */
220 
221 #include "mail_server.h"
222 
223  /*
224  * Global state.
225  */
226 static int use_count;
227 
228 static TRIGGER_SERVER_FN trigger_server_service;
229 static char *trigger_server_name;
230 static char **trigger_server_argv;
231 static void (*trigger_server_accept) (int, void *);
232 static void (*trigger_server_onexit) (char *, char **);
233 static void (*trigger_server_pre_accept) (char *, char **);
234 static VSTREAM *trigger_server_lock;
235 static int trigger_server_in_flow_delay;
236 static unsigned trigger_server_generation;
237 static int trigger_server_watchdog = 1000;
238 
239 /* trigger_server_exit - normal termination */
240 
241 static NORETURN trigger_server_exit(void)
242 {
243  if (trigger_server_onexit)
244  trigger_server_onexit(trigger_server_name, trigger_server_argv);
245  exit(0);
246 }
247 
248 /* trigger_server_abort - terminate after abnormal master exit */
249 
250 static void trigger_server_abort(int unused_event, void *unused_context)
251 {
252  if (msg_verbose)
253  msg_info("master disconnect -- exiting");
254  trigger_server_exit();
255 }
256 
257 /* trigger_server_timeout - idle time exceeded */
258 
259 static void trigger_server_timeout(int unused_event, void *unused_context)
260 {
261  if (msg_verbose)
262  msg_info("idle timeout -- exiting");
263  trigger_server_exit();
264 }
265 
266 /* trigger_server_wakeup - wake up application */
267 
268 static void trigger_server_wakeup(int fd)
269 {
270  char buf[TRIGGER_BUF_SIZE];
271  ssize_t len;
272 
273  /*
274  * Commit suicide when the master process disconnected from us. Don't
275  * drop the already accepted client request after "postfix reload"; that
276  * would be rude.
277  */
278  if (master_notify(var_pid, trigger_server_generation, MASTER_STAT_TAKEN) < 0)
279  /* void */ ;
280  if (trigger_server_in_flow_delay && mail_flow_get(1) < 0)
281  doze(var_in_flow_delay * 1000000);
282  if ((len = read(fd, buf, sizeof(buf))) >= 0)
283  trigger_server_service(buf, len, trigger_server_name,
284  trigger_server_argv);
285  if (master_notify(var_pid, trigger_server_generation, MASTER_STAT_AVAIL) < 0)
286  trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
287  if (var_idle_limit > 0)
288  event_request_timer(trigger_server_timeout, (void *) 0, var_idle_limit);
289  /* Avoid integer wrap-around in a persistent process. */
290  if (use_count < INT_MAX)
291  use_count++;
292 }
293 
294 /* trigger_server_accept_fifo - accept fifo client request */
295 
296 static void trigger_server_accept_fifo(int unused_event, void *context)
297 {
298  const char *myname = "trigger_server_accept_fifo";
299  int listen_fd = CAST_ANY_PTR_TO_INT(context);
300 
301  if (trigger_server_lock != 0
302  && myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
303  MYFLOCK_OP_NONE) < 0)
304  msg_fatal("select unlock: %m");
305 
306  if (msg_verbose)
307  msg_info("%s: trigger arrived", myname);
308 
309  /*
310  * Read whatever the other side wrote into the FIFO. The FIFO read end is
311  * non-blocking so we won't get stuck when multiple processes wake up.
312  */
313  if (trigger_server_pre_accept)
314  trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
315  trigger_server_wakeup(listen_fd);
316 }
317 
318 /* trigger_server_accept_local - accept socket client request */
319 
320 static void trigger_server_accept_local(int unused_event, void *context)
321 {
322  const char *myname = "trigger_server_accept_local";
323  int listen_fd = CAST_ANY_PTR_TO_INT(context);
324  int time_left = 0;
325  int fd;
326 
327  if (msg_verbose)
328  msg_info("%s: trigger arrived", myname);
329 
330  /*
331  * Read a message from a socket. Be prepared for accept() to fail because
332  * some other process already got the connection. The socket is
333  * non-blocking so we won't get stuck when multiple processes wake up.
334  * Don't get stuck when the client connects but sends no data. Restart
335  * the idle timer if this was a false alarm.
336  */
337  if (var_idle_limit > 0)
338  time_left = event_cancel_timer(trigger_server_timeout, (void *) 0);
339 
340  if (trigger_server_pre_accept)
341  trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
342  fd = LOCAL_ACCEPT(listen_fd);
343  if (trigger_server_lock != 0
344  && myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
345  MYFLOCK_OP_NONE) < 0)
346  msg_fatal("select unlock: %m");
347  if (fd < 0) {
348  if (errno != EAGAIN)
349  msg_error("accept connection: %m");
350  if (time_left >= 0)
351  event_request_timer(trigger_server_timeout, (void *) 0, time_left);
352  return;
353  }
355  if (read_wait(fd, 10) == 0)
356  trigger_server_wakeup(fd);
357  else if (time_left >= 0)
358  event_request_timer(trigger_server_timeout, (void *) 0, time_left);
359  close(fd);
360 }
361 
362 #ifdef MASTER_XPORT_NAME_PASS
363 
364 /* trigger_server_accept_pass - accept descriptor */
365 
366 static void trigger_server_accept_pass(int unused_event, void *context)
367 {
368  const char *myname = "trigger_server_accept_pass";
369  int listen_fd = CAST_ANY_PTR_TO_INT(context);
370  int time_left = 0;
371  int fd;
372 
373  if (msg_verbose)
374  msg_info("%s: trigger arrived", myname);
375 
376  /*
377  * Read a message from a socket. Be prepared for accept() to fail because
378  * some other process already got the connection. The socket is
379  * non-blocking so we won't get stuck when multiple processes wake up.
380  * Don't get stuck when the client connects but sends no data. Restart
381  * the idle timer if this was a false alarm.
382  */
383  if (var_idle_limit > 0)
384  time_left = event_cancel_timer(trigger_server_timeout, (void *) 0);
385 
386  if (trigger_server_pre_accept)
387  trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
388  fd = pass_accept(listen_fd);
389  if (trigger_server_lock != 0
390  && myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
391  MYFLOCK_OP_NONE) < 0)
392  msg_fatal("select unlock: %m");
393  if (fd < 0) {
394  if (errno != EAGAIN)
395  msg_error("accept connection: %m");
396  if (time_left >= 0)
397  event_request_timer(trigger_server_timeout, (void *) 0, time_left);
398  return;
399  }
401  if (read_wait(fd, 10) == 0)
402  trigger_server_wakeup(fd);
403  else if (time_left >= 0)
404  event_request_timer(trigger_server_timeout, (void *) 0, time_left);
405  close(fd);
406 }
407 
408 #endif
409 
410 /* trigger_server_main - the real main program */
411 
412 NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
413 {
414  const char *myname = "trigger_server_main";
415  char *root_dir = 0;
416  char *user_name = 0;
417  int debug_me = 0;
418  int daemon_mode = 1;
419  char *service_name = basename(argv[0]);
420  VSTREAM *stream = 0;
421  int delay;
422  int c;
423  int socket_count = 1;
424  int fd;
425  va_list ap;
426  MAIL_SERVER_INIT_FN pre_init = 0;
427  MAIL_SERVER_INIT_FN post_init = 0;
428  MAIL_SERVER_LOOP_FN loop = 0;
429  int key;
430  char buf[TRIGGER_BUF_SIZE];
431  ssize_t len;
432  char *transport = 0;
433  char *lock_path;
434  VSTRING *why;
435  int alone = 0;
436  int zerolimit = 0;
437  WATCHDOG *watchdog;
438  char *oname_val;
439  char *oname;
440  char *oval;
441  const char *err;
442  char *generation;
443  int msg_vstream_needed = 0;
444  int redo_syslog_init = 0;
445  const char *dsn_filter_title;
446  const char **dsn_filter_maps;
447 
448  /*
449  * Process environment options as early as we can.
450  */
451  if (getenv(CONF_ENV_VERB))
452  msg_verbose = 1;
453  if (getenv(CONF_ENV_DEBUG))
454  debug_me = 1;
455 
456  /*
457  * Don't die when a process goes away unexpectedly.
458  */
459  signal(SIGPIPE, SIG_IGN);
460 
461  /*
462  * Don't die for frivolous reasons.
463  */
464 #ifdef SIGXFSZ
465  signal(SIGXFSZ, SIG_IGN);
466 #endif
467 
468  /*
469  * May need this every now and then.
470  */
471  var_procname = mystrdup(basename(argv[0]));
473 
474  /*
475  * Initialize logging and exit handler. Do the syslog first, so that its
476  * initialization completes before we enter the optional chroot jail.
477  */
479  if (msg_verbose)
480  msg_info("daemon started");
481 
482  /*
483  * Check the Postfix library version as soon as we enable logging.
484  */
486 
487  /*
488  * Initialize from the configuration file. Allow command-line options to
489  * override compiled-in defaults or configured parameter values.
490  */
491  mail_conf_suck();
492 
493  /*
494  * After database open error, continue execution with reduced
495  * functionality.
496  */
498 
499  /*
500  * Pick up policy settings from master process. Shut up error messages to
501  * stderr, because no-one is going to see them.
502  */
503  opterr = 0;
504  while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
505  switch (c) {
506  case 'c':
507  root_dir = "setme";
508  break;
509  case 'd':
510  daemon_mode = 0;
511  break;
512  case 'D':
513  debug_me = 1;
514  break;
515  case 'i':
517  break;
518  case 'l':
519  alone = 1;
520  break;
521  case 'm':
522  mail_conf_update(VAR_MAX_USE, optarg);
523  break;
524  case 'n':
525  service_name = optarg;
526  break;
527  case 'o':
528  oname_val = mystrdup(optarg);
529  if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
530  msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
531  mail_conf_update(oname, oval);
532  if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
533  redo_syslog_init = 1;
534  myfree(oname_val);
535  break;
536  case 's':
537  if ((socket_count = atoi(optarg)) <= 0)
538  msg_fatal("invalid socket_count: %s", optarg);
539  break;
540  case 'S':
541  stream = VSTREAM_IN;
542  break;
543  case 't':
544  transport = optarg;
545  break;
546  case 'u':
547  user_name = "setme";
548  break;
549  case 'v':
550  msg_verbose++;
551  break;
552  case 'V':
553  if (++msg_vstream_needed == 1)
555  break;
556  case 'z':
557  zerolimit = 1;
558  break;
559  default:
560  msg_fatal("invalid option: %c", optopt);
561  break;
562  }
563  }
564  set_mail_conf_str(VAR_SERVNAME, service_name);
565 
566  /*
567  * Initialize generic parameters.
568  */
570  if (redo_syslog_init)
572 
573  /*
574  * Register higher-level dictionaries and initialize the support for
575  * dynamically-loaded dictionarles.
576  */
577  mail_dict_init();
578 
579  /*
580  * If not connected to stdin, stdin must not be a terminal.
581  */
582  if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
584  msg_fatal("do not run this command by hand");
585  }
586 
587  /*
588  * Application-specific initialization.
589  */
590  va_start(ap, service);
591  while ((key = va_arg(ap, int)) != 0) {
592  switch (key) {
595  break;
598  break;
601  break;
604  break;
607  break;
610  break;
613  break;
616  break;
618  pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
619  break;
621  post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
622  break;
623  case MAIL_SERVER_LOOP:
624  loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
625  break;
626  case MAIL_SERVER_EXIT:
627  trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
628  break;
630  trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
631  break;
633  trigger_server_in_flow_delay = 1;
634  break;
636  if (stream == 0 && !alone)
637  msg_fatal("service %s requires a process limit of 1",
638  service_name);
639  break;
641  if (stream == 0 && !zerolimit)
642  msg_fatal("service %s requires a process limit of 0",
643  service_name);
644  break;
646  if (user_name)
647  msg_fatal("service %s requires privileged operation",
648  service_name);
649  break;
651  trigger_server_watchdog = *va_arg(ap, int *);
652  break;
654  dsn_filter_title = va_arg(ap, const char *);
655  dsn_filter_maps = va_arg(ap, const char **);
656  bounce_client_init(dsn_filter_title, *dsn_filter_maps);
657  break;
658  default:
659  msg_panic("%s: unknown argument type: %d", myname, key);
660  }
661  }
662  va_end(ap);
663 
664  if (root_dir)
665  root_dir = var_queue_dir;
666  if (user_name)
667  user_name = var_mail_owner;
668 
669  /*
670  * Can options be required?
671  *
672  * XXX Initially this code was implemented with UNIX-domain sockets, but
673  * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
674  * client disconnects before the server has accepted the connection.
675  * Symptom: the server accept() fails with EPIPE or EPROTO, but the
676  * socket stays readable, so that the program goes into a wasteful loop.
677  *
678  * The initial fix was to use FIFOs, but those turn out to have their own
679  * problems, witness the workarounds in the fifo_listen() routine.
680  * Therefore we support both FIFOs and UNIX-domain sockets, so that the
681  * user can choose whatever works best.
682  *
683  * Well, I give up. Solaris UNIX-domain sockets still don't work properly,
684  * so it will have to limp along with a streams-specific alternative.
685  */
686  if (stream == 0) {
687  if (transport == 0)
688  msg_fatal("no transport type specified");
689  if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
690  trigger_server_accept = trigger_server_accept_local;
691  else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
692  trigger_server_accept = trigger_server_accept_fifo;
693 #ifdef MASTER_XPORT_NAME_PASS
694  else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
695  trigger_server_accept = trigger_server_accept_pass;
696 #endif
697  else
698  msg_fatal("unsupported transport type: %s", transport);
699  }
700 
701  /*
702  * Retrieve process generation from environment.
703  */
704  if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
705  if (!alldig(generation))
706  msg_fatal("bad generation: %s", generation);
707  OCTAL_TO_UNSIGNED(trigger_server_generation, generation);
708  if (msg_verbose)
709  msg_info("process generation: %s (%o)",
710  generation, trigger_server_generation);
711  }
712 
713  /*
714  * Optionally start the debugger on ourself.
715  */
716  if (debug_me)
717  debug_process();
718 
719  /*
720  * Traditionally, BSD select() can't handle multiple processes selecting
721  * on the same socket, and wakes up every process in select(). See TCP/IP
722  * Illustrated volume 2 page 532. We avoid select() collisions with an
723  * external lock file.
724  */
725  if (stream == 0 && !alone) {
726  lock_path = concatenate(DEF_PID_DIR, "/", transport,
727  ".", service_name, (char *) 0);
728  why = vstring_alloc(1);
729  if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
730  (struct stat *) 0, -1, -1, why)) == 0)
731  msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
732  close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
733  myfree(lock_path);
734  vstring_free(why);
735  }
736 
737  /*
738  * Set up call-back info.
739  */
740  trigger_server_service = service;
741  trigger_server_name = service_name;
742  trigger_server_argv = argv + optind;
743 
744  /*
745  * Run pre-jail initialization.
746  */
747  if (chdir(var_queue_dir) < 0)
748  msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
749  if (pre_init)
750  pre_init(trigger_server_name, trigger_server_argv);
751 
752  /*
753  * Optionally, restrict the damage that this process can do.
754  */
756  tzset();
757  chroot_uid(root_dir, user_name);
758 
759  /*
760  * Run post-jail initialization.
761  */
762  if (post_init)
763  post_init(trigger_server_name, trigger_server_argv);
764 
765  /*
766  * Are we running as a one-shot server with the client connection on
767  * standard input?
768  */
769  if (stream != 0) {
770  if ((len = read(vstream_fileno(stream), buf, sizeof(buf))) <= 0)
771  msg_fatal("read: %m");
772  service(buf, len, trigger_server_name, trigger_server_argv);
773  vstream_fflush(stream);
774  trigger_server_exit();
775  }
776 
777  /*
778  * Running as a semi-resident server. Service connection requests.
779  * Terminate when we have serviced a sufficient number of clients, when
780  * no-one has been talking to us for a configurable amount of time, or
781  * when the master process terminated abnormally.
782  */
783  if (var_idle_limit > 0)
784  event_request_timer(trigger_server_timeout, (void *) 0, var_idle_limit);
785  for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
786  event_enable_read(fd, trigger_server_accept, CAST_INT_TO_VOID_PTR(fd));
788  }
789  event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (void *) 0);
793  watchdog = watchdog_create(trigger_server_watchdog,
794  (WATCHDOG_FN) 0, (void *) 0);
795 
796  /*
797  * The event loop, at last.
798  */
799  while (var_use_limit == 0 || use_count < var_use_limit) {
800  if (trigger_server_lock != 0) {
801  watchdog_stop(watchdog);
802  if (myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
804  msg_fatal("select lock: %m");
805  }
806  watchdog_start(watchdog);
807  delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
808  event_loop(delay);
809  }
810  trigger_server_exit();
811 }
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
void msg_error(const char *fmt,...)
Definition: msg.c:231
void mail_params_init()
Definition: mail_params.c:658
#define MAIL_SERVER_UNLIMITED
Definition: mail_server.h:39
void myfree(void *ptr)
Definition: mymalloc.c:207
const char * mail_task(const char *argv0)
Definition: mail_task.c:49
char * var_procname
Definition: mail_params.c:252
#define MAIL_SERVER_STR_TABLE
Definition: mail_server.h:25
#define LOCAL_ACCEPT
Definition: sys_defs.h:1423
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define VAR_SERVNAME
Definition: mail_params.h:2438
int master_notify(int pid, unsigned generation, int status)
Definition: master_proto.c:65
void set_mail_conf_str(const char *, const char *)
#define CAST_ANY_PTR_TO_INT(cptr)
Definition: sys_defs.h:1298
int var_pid
Definition: mail_params.c:254
#define NORETURN
Definition: sys_defs.h:1583
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
void chroot_uid(const char *root_dir, const char *user_name)
Definition: chroot_uid.c:43
#define MAIL_SERVER_INT_TABLE
Definition: mail_server.h:24
#define stat(p, s)
Definition: warn_stat.h:18
#define MASTER_FLOW_WRITE
Definition: master_proto.h:44
#define VAR_MAX_IDLE
Definition: mail_params.h:919
#define MYFLOCK_OP_EXCLUSIVE
Definition: myflock.h:30
#define OCTAL_TO_UNSIGNED(res, str)
Definition: sys_defs.h:1450
#define VAR_PROCNAME
Definition: mail_params.h:2435
#define LOG_FACILITY
Definition: mail_params.h:357
#define MAIL_SERVER_TIME_TABLE
Definition: mail_server.h:27
#define MASTER_STATUS_FD
Definition: master_proto.h:56
void get_mail_conf_nint_table(const CONFIG_NINT_TABLE *)
void(* MAIL_SERVER_EXIT_FN)(char *, char **)
Definition: mail_server.h:50
#define MASTER_LISTEN_FD
Definition: master_proto.h:57
void get_mail_conf_nbool_table(const CONFIG_NBOOL_TABLE *)
#define MASTER_XPORT_NAME_PASS
Definition: master_proto.h:18
int var_idle_limit
Definition: mail_params.c:250
#define MASTER_FLOW_READ
Definition: master_proto.h:43
#define EVENT_NULL_CONTEXT
Definition: events.h:51
#define VSTREAM_IN
Definition: vstream.h:66
void(* TRIGGER_SERVER_FN)(char *, ssize_t, char *, char **)
Definition: mail_server.h:121
int alldig(const char *string)
Definition: alldig.c:38
#define MASTER_STAT_AVAIL
Definition: master_proto.h:34
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define CONF_ENV_VERB
Definition: mail_conf.h:23
void watchdog_start(WATCHDOG *wp)
Definition: watchdog.c:251
#define MAIL_SERVER_WATCHDOG
Definition: mail_server.h:42
void(* WATCHDOG_FN)(WATCHDOG *, char *)
Definition: watchdog.h:18
#define MAIL_SERVER_LOOP
Definition: mail_server.h:35
void mail_conf_suck(void)
Definition: mail_conf.c:186
#define MAIL_SERVER_BOOL_TABLE
Definition: mail_server.h:26
#define MAIL_SERVER_PRIVILEGED
Definition: mail_server.h:41
#define MAIL_SERVER_POST_INIT
Definition: mail_server.h:34
#define MAIL_SERVER_BOUNCE_INIT
Definition: mail_server.h:46
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
#define CONF_ENV_DEBUG
Definition: mail_conf.h:24
void get_mail_conf_time_table(const CONFIG_TIME_TABLE *)
#define MAIL_SERVER_PRE_ACCEPT
Definition: mail_server.h:37
#define MASTER_STAT_TAKEN
Definition: master_proto.h:33
void(* MAIL_SERVER_INIT_FN)(char *, char **)
Definition: mail_server.h:48
int dict_allow_surrogate
void get_mail_conf_raw_table(const CONFIG_RAW_TABLE *)
#define CAST_INT_TO_VOID_PTR(ival)
Definition: sys_defs.h:1299
ssize_t mail_flow_get(ssize_t len)
Definition: mail_flow.c:70
#define EVENT_NULL_TYPE
Definition: events.h:50
void event_loop(int delay)
Definition: events.c:998
WATCHDOG * watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
Definition: watchdog.c:189
#define read_wait(fd, timeout)
Definition: iostuff.h:39
#define MAIL_SERVER_IN_FLOW_DELAY
Definition: mail_server.h:44
void resolve_local_init(void)
Definition: resolve_local.c:67
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int myflock(int fd, int lock_style, int operation)
Definition: myflock.c:87
void mail_dict_init(void)
Definition: mail_dict.c:81
int var_use_limit
Definition: mail_params.c:248
#define VAR_MAX_USE
Definition: mail_params.h:911
#define TRIGGER_BUF_SIZE
Definition: mail_server.h:124
#define MAIL_SERVER_EXIT
Definition: mail_server.h:36
void debug_process(void)
Definition: debug_process.c:50
void doze(unsigned delay)
Definition: doze.c:44
#define MASTER_XPORT_NAME_FIFO
Definition: master_proto.h:16
void get_mail_conf_str_table(const CONFIG_STR_TABLE *)
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define MYFLOCK_OP_NONE
Definition: myflock.h:28
void get_mail_conf_bool_table(const CONFIG_BOOL_TABLE *)
#define MASTER_XPORT_NAME_UNIX
Definition: master_proto.h:15
#define MAIL_VERSION_CHECK
Definition: mail_version.h:90
#define MAIL_SERVER_LONG_TABLE
Definition: mail_server.h:31
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void watchdog_stop(WATCHDOG *wp)
Definition: watchdog.c:265
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
void bounce_client_init(const char *title, const char *maps)
Definition: bounce.c:532
void msg_syslog_init(const char *name, int logopt, int facility)
Definition: msg_syslog.c:173
void(* MAIL_SERVER_ACCEPT_FN)(char *, char **)
Definition: mail_server.h:51
#define VAR_SYSLOG_NAME
Definition: mail_params.h:2560
#define DEF_PID_DIR
Definition: mail_params.h:303
#define MAIL_SERVER_NINT_TABLE
Definition: mail_server.h:29
int var_in_flow_delay
Definition: mail_params.c:291
int int
Definition: smtpd_proxy.h:21
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:41
VSTREAM * safe_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t user, gid_t group, VSTRING *why)
Definition: safe_open.c:243
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define MAIL_SERVER_PRE_INIT
Definition: mail_server.h:33
char * var_mail_owner
Definition: mail_params.c:233
void get_mail_conf_int_table(const CONFIG_INT_TABLE *)
int pass_accept(int)
Definition: pass_accept.c:54
char * var_queue_dir
Definition: mail_params.c:246
#define vstream_fileno(vp)
Definition: vstream.h:115
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
int(* MAIL_SERVER_LOOP_FN)(char *, char **)
Definition: mail_server.h:49
void get_mail_conf_long_table(const CONFIG_LONG_TABLE *)
#define MASTER_GEN_NAME
Definition: master_proto.h:31
void mail_conf_update(const char *key, const char *value)
Definition: mail_conf.c:275
#define MAIL_SERVER_NBOOL_TABLE
Definition: mail_server.h:30
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
#define basename
Definition: stringops.h:36
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
#define MAIL_SERVER_RAW_TABLE
Definition: mail_server.h:28
#define MAIL_SERVER_SOLITARY
Definition: mail_server.h:38
#define VSTREAM_ERR
Definition: vstream.h:68
void msg_info(const char *fmt,...)
Definition: msg.c:199