Postfix3.3.1
single_server.c
[詳解]
1 /*++
2 /* NAME
3 /* single_server 3
4 /* SUMMARY
5 /* skeleton single-threaded mail subsystem
6 /* SYNOPSIS
7 /* #include <mail_server.h>
8 /*
9 /* NORETURN single_server_main(argc, argv, service, key, value, ...)
10 /* int argc;
11 /* char **argv;
12 /* void (*service)(VSTREAM *stream, char *service_name, char **argv);
13 /* int key;
14 /* DESCRIPTION
15 /* This module implements a skeleton for single-threaded
16 /* mail subsystems: mail subsystem programs that service one
17 /* client at a time. The resulting program expects to be run
18 /* from the \fBmaster\fR process.
19 /*
20 /* single_server_main() is the skeleton entry point. It should be
21 /* called from the application main program. The skeleton does the
22 /* generic command-line options processing, initialization of
23 /* configurable parameters, and connection management.
24 /* The skeleton never returns.
25 /*
26 /* Arguments:
27 /* .IP "void (*service)(VSTREAM *fp, char *service_name, char **argv)"
28 /* A pointer to a function that is called by the skeleton each time
29 /* a client connects to the program's service port. The function is
30 /* run after the program has irrevocably dropped its privileges.
31 /* The stream initial state is non-blocking mode.
32 /* Optional connection attributes are provided as a hash that
33 /* is attached as stream context.
34 /* The service name argument corresponds to the service name in the
35 /* master.cf file.
36 /* The argv argument specifies command-line arguments left over
37 /* after options processing.
38 /* .PP
39 /* Optional arguments are specified as a null-terminated list
40 /* with macros that have zero or more arguments:
41 /* .IP "CA_MAIL_SERVER_INT_TABLE(CONFIG_INT_TABLE *)"
42 /* A table with configurable parameters, to be loaded from the
43 /* global Postfix configuration file. Tables are loaded in the
44 /* order as specified, and multiple instances of the same type
45 /* are allowed.
46 /* .IP "CA_MAIL_SERVER_LONG_TABLE(CONFIG_LONG_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_STR_TABLE(CONFIG_STR_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_BOOL_TABLE(CONFIG_BOOL_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_TIME_TABLE(CONFIG_TIME_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_RAW_TABLE(CONFIG_RAW_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. Raw parameters are not subjected to $name
71 /* evaluation.
72 /* .IP "CA_MAIL_SERVER_NINT_TABLE(CONFIG_NINT_TABLE *)"
73 /* A table with configurable parameters, to be loaded from the
74 /* global Postfix configuration file. Tables are loaded in the
75 /* order as specified, and multiple instances of the same type
76 /* are allowed.
77 /* .IP "CA_MAIL_SERVER_NBOOL_TABLE(CONFIG_NBOOL_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_PRE_INIT(void *(char *service_name, char **argv))"
83 /* A pointer to a function that is called once
84 /* by the skeleton after it has read the global configuration file
85 /* and after it has processed command-line arguments, but before
86 /* the skeleton has optionally relinquished the process privileges.
87 /* .sp
88 /* Only the last instance of this parameter type is remembered.
89 /* .IP "CA_MAIL_SERVER_POST_INIT(void *(char *service_name, char **argv))"
90 /* A pointer to a function that is called once
91 /* by the skeleton after it has optionally relinquished the process
92 /* privileges, but before servicing client connection requests.
93 /* .sp
94 /* Only the last instance of this parameter type is remembered.
95 /* .IP "CA_MAIL_SERVER_LOOP(int *(char *service_name, char **argv))"
96 /* A pointer to function that is executed from
97 /* within the event loop, whenever an I/O or timer event has happened,
98 /* or whenever nothing has happened for a specified amount of time.
99 /* The result value of the function specifies how long to wait until
100 /* the next event. Specify -1 to wait for "as long as it takes".
101 /* .sp
102 /* Only the last instance of this parameter type is remembered.
103 /* .IP "CA_MAIL_SERVER_EXIT(void *(void))"
104 /* A pointer to function that is executed immediately before normal
105 /* process termination.
106 /* .sp
107 /* Only the last instance of this parameter type is remembered.
108 /* .IP "CA_MAIL_SERVER_PRE_ACCEPT(void *(char *service_name, char **argv))"
109 /* Function to be executed prior to accepting a new connection.
110 /* .sp
111 /* Only the last instance of this parameter type is remembered.
112 /* .IP "CA_MAIL_SERVER_IN_FLOW_DELAY(none)"
113 /* Pause $in_flow_delay seconds when no "mail flow control token"
114 /* is available. A token is consumed for each connection request.
115 /* .IP CA_MAIL_SERVER_SOLITARY
116 /* This service must be configured with process limit of 1.
117 /* .IP CA_MAIL_SERVER_UNLIMITED
118 /* This service must be configured with process limit of 0.
119 /* .IP CA_MAIL_SERVER_PRIVILEGED
120 /* This service must be configured as privileged.
121 /* .IP "CA_MAIL_SERVER_BOUNCE_INIT(const char *, const char **)"
122 /* Initialize the DSN filter for the bounce/defer service
123 /* clients with the specified map source and map names.
124 /* .PP
125 /* The var_use_limit variable limits the number of clients that
126 /* a server can service before it commits suicide.
127 /* This value is taken from the global \fBmain.cf\fR configuration
128 /* file. Setting \fBvar_idle_limit\fR to zero disables the client limit.
129 /*
130 /* The var_idle_limit variable limits the time that a service
131 /* receives no client connection requests before it commits suicide.
132 /* This value is taken from the global \fBmain.cf\fR configuration
133 /* file. Setting \fBvar_use_limit\fR to zero disables the idle limit.
134 /* DIAGNOSTICS
135 /* Problems and transactions are logged to \fBsyslogd\fR(8).
136 /* BUGS
137 /* SEE ALSO
138 /* master(8), master process
139 /* syslogd(8) system logging
140 /* LICENSE
141 /* .ad
142 /* .fi
143 /* The Secure Mailer license must be distributed with this software.
144 /* AUTHOR(S)
145 /* Wietse Venema
146 /* IBM T.J. Watson Research
147 /* P.O. Box 704
148 /* Yorktown Heights, NY 10598, USA
149 /*
150 /* Wietse Venema
151 /* Google, Inc.
152 /* 111 8th Avenue
153 /* New York, NY 10011, USA
154 /*--*/
155 
156 /* System library. */
157 
158 #include <sys_defs.h>
159 #include <sys/socket.h>
160 #include <unistd.h>
161 #include <signal.h>
162 #include <syslog.h>
163 #include <stdlib.h>
164 #include <limits.h>
165 #include <string.h>
166 #include <errno.h>
167 #include <fcntl.h>
168 #include <stdarg.h>
169 #ifdef STRCASECMP_IN_STRINGS_H
170 #include <strings.h>
171 #endif
172 #include <time.h>
173 
174 /* Utility library. */
175 
176 #include <msg.h>
177 #include <msg_syslog.h>
178 #include <msg_vstream.h>
179 #include <chroot_uid.h>
180 #include <vstring.h>
181 #include <vstream.h>
182 #include <msg_vstream.h>
183 #include <mymalloc.h>
184 #include <events.h>
185 #include <iostuff.h>
186 #include <stringops.h>
187 #include <sane_accept.h>
188 #include <myflock.h>
189 #include <safe_open.h>
190 #include <listen.h>
191 #include <watchdog.h>
192 #include <split_at.h>
193 
194 /* Global library. */
195 
196 #include <mail_params.h>
197 #include <mail_task.h>
198 #include <debug_process.h>
199 #include <mail_conf.h>
200 #include <mail_dict.h>
201 #include <timed_ipc.h>
202 #include <resolve_local.h>
203 #include <mail_flow.h>
204 #include <mail_version.h>
205 #include <bounce.h>
206 
207 /* Process manager. */
208 
209 #include "master_proto.h"
210 
211 /* Application-specific */
212 
213 #include "mail_server.h"
214 
215  /*
216  * Global state.
217  */
218 static int use_count;
219 
220 static void (*single_server_service) (VSTREAM *, char *, char **);
221 static char *single_server_name;
222 static char **single_server_argv;
223 static void (*single_server_accept) (int, void *);
224 static void (*single_server_onexit) (char *, char **);
225 static void (*single_server_pre_accept) (char *, char **);
226 static VSTREAM *single_server_lock;
227 static int single_server_in_flow_delay;
228 static unsigned single_server_generation;
229 
230 /* single_server_exit - normal termination */
231 
232 static NORETURN single_server_exit(void)
233 {
234  if (single_server_onexit)
235  single_server_onexit(single_server_name, single_server_argv);
236  exit(0);
237 }
238 
239 /* single_server_abort - terminate after abnormal master exit */
240 
241 static void single_server_abort(int unused_event, void *unused_context)
242 {
243  if (msg_verbose)
244  msg_info("master disconnect -- exiting");
245  single_server_exit();
246 }
247 
248 /* single_server_timeout - idle time exceeded */
249 
250 static void single_server_timeout(int unused_event, void *unused_context)
251 {
252  if (msg_verbose)
253  msg_info("idle timeout -- exiting");
254  single_server_exit();
255 }
256 
257 /* single_server_wakeup - wake up application */
258 
259 static void single_server_wakeup(int fd, HTABLE *attr)
260 {
261  VSTREAM *stream;
262  char *tmp;
263 
264  /*
265  * If the accept() succeeds, be sure to disable non-blocking I/O, because
266  * the application is supposed to be single-threaded. Notice the master
267  * of our (un)availability to service connection requests. Commit suicide
268  * when the master process disconnected from us. Don't drop the already
269  * accepted client request after "postfix reload"; that would be rude.
270  */
271  if (msg_verbose)
272  msg_info("connection established");
273  non_blocking(fd, BLOCKING);
275  stream = vstream_fdopen(fd, O_RDWR);
276  tmp = concatenate(single_server_name, " socket", (char *) 0);
277  vstream_control(stream,
278  CA_VSTREAM_CTL_PATH(tmp),
279  CA_VSTREAM_CTL_CONTEXT((void *) attr),
281  myfree(tmp);
282  timed_ipc_setup(stream);
283  if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0)
284  /* void */ ;
285  if (single_server_in_flow_delay && mail_flow_get(1) < 0)
286  doze(var_in_flow_delay * 1000000);
287  single_server_service(stream, single_server_name, single_server_argv);
288  (void) vstream_fclose(stream);
289  if (master_notify(var_pid, single_server_generation, MASTER_STAT_AVAIL) < 0)
290  single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
291  if (msg_verbose)
292  msg_info("connection closed");
293  /* Avoid integer wrap-around in a persistent process. */
294  if (use_count < INT_MAX)
295  use_count++;
296  if (var_idle_limit > 0)
297  event_request_timer(single_server_timeout, (void *) 0, var_idle_limit);
298  if (attr)
299  htable_free(attr, myfree);
300 }
301 
302 /* single_server_accept_local - accept client connection request */
303 
304 static void single_server_accept_local(int unused_event, void *context)
305 {
306  int listen_fd = CAST_ANY_PTR_TO_INT(context);
307  int time_left = -1;
308  int fd;
309 
310  /*
311  * Be prepared for accept() to fail because some other process already
312  * got the connection. We use select() + accept(), instead of simply
313  * blocking in accept(), because we must be able to detect that the
314  * master process has gone away unexpectedly.
315  */
316  if (var_idle_limit > 0)
317  time_left = event_cancel_timer(single_server_timeout, (void *) 0);
318 
319  if (single_server_pre_accept)
320  single_server_pre_accept(single_server_name, single_server_argv);
321  fd = LOCAL_ACCEPT(listen_fd);
322  if (single_server_lock != 0
323  && myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
324  MYFLOCK_OP_NONE) < 0)
325  msg_fatal("select unlock: %m");
326  if (fd < 0) {
327  if (errno != EAGAIN)
328  msg_error("accept connection: %m");
329  if (time_left >= 0)
330  event_request_timer(single_server_timeout, (void *) 0, time_left);
331  return;
332  }
333  single_server_wakeup(fd, (HTABLE *) 0);
334 }
335 
336 #ifdef MASTER_XPORT_NAME_PASS
337 
338 /* single_server_accept_pass - accept descriptor */
339 
340 static void single_server_accept_pass(int unused_event, void *context)
341 {
342  int listen_fd = CAST_ANY_PTR_TO_INT(context);
343  int time_left = -1;
344  int fd;
345  HTABLE *attr = 0;
346 
347  /*
348  * Be prepared for accept() to fail because some other process already
349  * got the connection. We use select() + accept(), instead of simply
350  * blocking in accept(), because we must be able to detect that the
351  * master process has gone away unexpectedly.
352  */
353  if (var_idle_limit > 0)
354  time_left = event_cancel_timer(single_server_timeout, (void *) 0);
355 
356  if (single_server_pre_accept)
357  single_server_pre_accept(single_server_name, single_server_argv);
358  fd = pass_accept_attr(listen_fd, &attr);
359  if (single_server_lock != 0
360  && myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
361  MYFLOCK_OP_NONE) < 0)
362  msg_fatal("select unlock: %m");
363  if (fd < 0) {
364  if (errno != EAGAIN)
365  msg_error("accept connection: %m");
366  if (time_left >= 0)
367  event_request_timer(single_server_timeout, (void *) 0, time_left);
368  return;
369  }
370  single_server_wakeup(fd, attr);
371 }
372 
373 #endif
374 
375 /* single_server_accept_inet - accept client connection request */
376 
377 static void single_server_accept_inet(int unused_event, void *context)
378 {
379  int listen_fd = CAST_ANY_PTR_TO_INT(context);
380  int time_left = -1;
381  int fd;
382 
383  /*
384  * Be prepared for accept() to fail because some other process already
385  * got the connection. We use select() + accept(), instead of simply
386  * blocking in accept(), because we must be able to detect that the
387  * master process has gone away unexpectedly.
388  */
389  if (var_idle_limit > 0)
390  time_left = event_cancel_timer(single_server_timeout, (void *) 0);
391 
392  if (single_server_pre_accept)
393  single_server_pre_accept(single_server_name, single_server_argv);
394  fd = inet_accept(listen_fd);
395  if (single_server_lock != 0
396  && myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
397  MYFLOCK_OP_NONE) < 0)
398  msg_fatal("select unlock: %m");
399  if (fd < 0) {
400  if (errno != EAGAIN)
401  msg_error("accept connection: %m");
402  if (time_left >= 0)
403  event_request_timer(single_server_timeout, (void *) 0, time_left);
404  return;
405  }
406  single_server_wakeup(fd, (HTABLE *) 0);
407 }
408 
409 /* single_server_main - the real main program */
410 
411 NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
412 {
413  const char *myname = "single_server_main";
414  VSTREAM *stream = 0;
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  int delay;
421  int c;
422  int socket_count = 1;
423  int fd;
424  va_list ap;
425  MAIL_SERVER_INIT_FN pre_init = 0;
426  MAIL_SERVER_INIT_FN post_init = 0;
427  MAIL_SERVER_LOOP_FN loop = 0;
428  int key;
429  char *transport = 0;
430  char *lock_path;
431  VSTRING *why;
432  int alone = 0;
433  int zerolimit = 0;
434  WATCHDOG *watchdog;
435  char *oname_val;
436  char *oname;
437  char *oval;
438  const char *err;
439  char *generation;
440  int msg_vstream_needed = 0;
441  int redo_syslog_init = 0;
442  const char *dsn_filter_title;
443  const char **dsn_filter_maps;
444 
445  /*
446  * Process environment options as early as we can.
447  */
448  if (getenv(CONF_ENV_VERB))
449  msg_verbose = 1;
450  if (getenv(CONF_ENV_DEBUG))
451  debug_me = 1;
452 
453  /*
454  * Don't die when a process goes away unexpectedly.
455  */
456  signal(SIGPIPE, SIG_IGN);
457 
458  /*
459  * Don't die for frivolous reasons.
460  */
461 #ifdef SIGXFSZ
462  signal(SIGXFSZ, SIG_IGN);
463 #endif
464 
465  /*
466  * May need this every now and then.
467  */
468  var_procname = mystrdup(basename(argv[0]));
470 
471  /*
472  * Initialize logging and exit handler. Do the syslog first, so that its
473  * initialization completes before we enter the optional chroot jail.
474  */
476  if (msg_verbose)
477  msg_info("daemon started");
478 
479  /*
480  * Check the Postfix library version as soon as we enable logging.
481  */
483 
484  /*
485  * Initialize from the configuration file. Allow command-line options to
486  * override compiled-in defaults or configured parameter values.
487  */
488  mail_conf_suck();
489 
490  /*
491  * After database open error, continue execution with reduced
492  * functionality.
493  */
495 
496  /*
497  * Pick up policy settings from master process. Shut up error messages to
498  * stderr, because no-one is going to see them.
499  */
500  opterr = 0;
501  while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
502  switch (c) {
503  case 'c':
504  root_dir = "setme";
505  break;
506  case 'd':
507  daemon_mode = 0;
508  break;
509  case 'D':
510  debug_me = 1;
511  break;
512  case 'i':
514  break;
515  case 'l':
516  alone = 1;
517  break;
518  case 'm':
519  mail_conf_update(VAR_MAX_USE, optarg);
520  break;
521  case 'n':
522  service_name = optarg;
523  break;
524  case 'o':
525  oname_val = mystrdup(optarg);
526  if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
527  msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
528  mail_conf_update(oname, oval);
529  if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
530  redo_syslog_init = 1;
531  myfree(oname_val);
532  break;
533  case 's':
534  if ((socket_count = atoi(optarg)) <= 0)
535  msg_fatal("invalid socket_count: %s", optarg);
536  break;
537  case 'S':
538  stream = VSTREAM_IN;
539  break;
540  case 'u':
541  user_name = "setme";
542  break;
543  case 't':
544  transport = optarg;
545  break;
546  case 'v':
547  msg_verbose++;
548  break;
549  case 'V':
550  if (++msg_vstream_needed == 1)
552  break;
553  case 'z':
554  zerolimit = 1;
555  break;
556  default:
557  msg_fatal("invalid option: %c", optopt);
558  break;
559  }
560  }
561  set_mail_conf_str(VAR_SERVNAME, service_name);
562 
563  /*
564  * Initialize generic parameters.
565  */
567  if (redo_syslog_init)
569 
570  /*
571  * Register higher-level dictionaries and initialize the support for
572  * dynamically-loaded dictionarles.
573  */
574  mail_dict_init();
575 
576  /*
577  * If not connected to stdin, stdin must not be a terminal.
578  */
579  if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
581  msg_fatal("do not run this command by hand");
582  }
583 
584  /*
585  * Application-specific initialization.
586  */
587  va_start(ap, service);
588  while ((key = va_arg(ap, int)) != 0) {
589  switch (key) {
592  break;
595  break;
598  break;
601  break;
604  break;
607  break;
610  break;
613  break;
615  pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
616  break;
618  post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
619  break;
620  case MAIL_SERVER_LOOP:
621  loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
622  break;
623  case MAIL_SERVER_EXIT:
624  single_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
625  break;
627  single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
628  break;
630  single_server_in_flow_delay = 1;
631  break;
633  if (stream == 0 && !alone)
634  msg_fatal("service %s requires a process limit of 1",
635  service_name);
636  break;
638  if (stream == 0 && !zerolimit)
639  msg_fatal("service %s requires a process limit of 0",
640  service_name);
641  break;
643  if (user_name)
644  msg_fatal("service %s requires privileged operation",
645  service_name);
646  break;
648  dsn_filter_title = va_arg(ap, const char *);
649  dsn_filter_maps = va_arg(ap, const char **);
650  bounce_client_init(dsn_filter_title, *dsn_filter_maps);
651  break;
652  default:
653  msg_panic("%s: unknown argument type: %d", myname, key);
654  }
655  }
656  va_end(ap);
657 
658  if (root_dir)
659  root_dir = var_queue_dir;
660  if (user_name)
661  user_name = var_mail_owner;
662 
663  /*
664  * Can options be required?
665  */
666  if (stream == 0) {
667  if (transport == 0)
668  msg_fatal("no transport type specified");
669  if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
670  single_server_accept = single_server_accept_inet;
671  else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
672  single_server_accept = single_server_accept_local;
673 #ifdef MASTER_XPORT_NAME_PASS
674  else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
675  single_server_accept = single_server_accept_pass;
676 #endif
677  else
678  msg_fatal("unsupported transport type: %s", transport);
679  }
680 
681  /*
682  * Retrieve process generation from environment.
683  */
684  if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
685  if (!alldig(generation))
686  msg_fatal("bad generation: %s", generation);
687  OCTAL_TO_UNSIGNED(single_server_generation, generation);
688  if (msg_verbose)
689  msg_info("process generation: %s (%o)",
690  generation, single_server_generation);
691  }
692 
693  /*
694  * Optionally start the debugger on ourself.
695  */
696  if (debug_me)
697  debug_process();
698 
699  /*
700  * Traditionally, BSD select() can't handle multiple processes selecting
701  * on the same socket, and wakes up every process in select(). See TCP/IP
702  * Illustrated volume 2 page 532. We avoid select() collisions with an
703  * external lock file.
704  */
705  if (stream == 0 && !alone) {
706  lock_path = concatenate(DEF_PID_DIR, "/", transport,
707  ".", service_name, (void *) 0);
708  why = vstring_alloc(1);
709  if ((single_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
710  (struct stat *) 0, -1, -1, why)) == 0)
711  msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
712  close_on_exec(vstream_fileno(single_server_lock), CLOSE_ON_EXEC);
713  myfree(lock_path);
714  vstring_free(why);
715  }
716 
717  /*
718  * Set up call-back info.
719  */
720  single_server_service = service;
721  single_server_name = service_name;
722  single_server_argv = argv + optind;
723 
724  /*
725  * Run pre-jail initialization.
726  */
727  if (chdir(var_queue_dir) < 0)
728  msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
729  if (pre_init)
730  pre_init(single_server_name, single_server_argv);
731 
732  /*
733  * Optionally, restrict the damage that this process can do.
734  */
736  tzset();
737  chroot_uid(root_dir, user_name);
738 
739  /*
740  * Run post-jail initialization.
741  */
742  if (post_init)
743  post_init(single_server_name, single_server_argv);
744 
745  /*
746  * Are we running as a one-shot server with the client connection on
747  * standard input? If so, make sure the output is written to stdout so as
748  * to satisfy common expectation.
749  */
750  if (stream != 0) {
751  vstream_control(stream,
753  CA_VSTREAM_CTL_WRITE_FD(STDOUT_FILENO),
755  service(stream, single_server_name, single_server_argv);
756  vstream_fflush(stream);
757  single_server_exit();
758  }
759 
760  /*
761  * Running as a semi-resident server. Service connection requests.
762  * Terminate when we have serviced a sufficient number of clients, when
763  * no-one has been talking to us for a configurable amount of time, or
764  * when the master process terminated abnormally.
765  */
766  if (var_idle_limit > 0)
767  event_request_timer(single_server_timeout, (void *) 0, var_idle_limit);
768  for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
769  event_enable_read(fd, single_server_accept, CAST_INT_TO_VOID_PTR(fd));
771  }
772  event_enable_read(MASTER_STATUS_FD, single_server_abort, (void *) 0);
776  watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (void *) 0);
777 
778  /*
779  * The event loop, at last.
780  */
781  while (var_use_limit == 0 || use_count < var_use_limit) {
782  if (single_server_lock != 0) {
783  watchdog_stop(watchdog);
784  if (myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
786  msg_fatal("select lock: %m");
787  }
788  watchdog_start(watchdog);
789  delay = loop ? loop(single_server_name, single_server_argv) : -1;
790  event_loop(delay);
791  }
792  single_server_exit();
793 }
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 htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
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 CA_VSTREAM_CTL_DOUBLE
Definition: vstream.h:159
#define MASTER_LISTEN_FD
Definition: master_proto.h:57
#define CA_VSTREAM_CTL_CONTEXT(v)
Definition: vstream.h:165
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
int alldig(const char *string)
Definition: alldig.c:38
#define MASTER_STAT_AVAIL
Definition: master_proto.h:34
Definition: htable.h:25
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
int inet_accept(int fd)
Definition: inet_listen.c:169
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
#define CA_VSTREAM_CTL_WRITE_FD(v)
Definition: vstream.h:161
#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
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
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 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 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_INET
Definition: master_proto.h:17
void get_mail_conf_str_table(const CONFIG_STR_TABLE *)
void timed_ipc_setup(VSTREAM *stream)
Definition: timed_ipc.c:47
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
void(* SINGLE_SERVER_FN)(VSTREAM *, char *, char **)
Definition: mail_server.h:99
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
int non_blocking(int, int)
Definition: non_blocking.c:55
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 *)
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
int var_daemon_timeout
Definition: mail_params.c:284
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
#define CA_VSTREAM_CTL_PATH(v)
Definition: vstream.h:158
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 vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
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
#define BLOCKING
Definition: iostuff.h:48
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
int pass_accept_attr(int, HTABLE **)
Definition: pass_accept.c:78
#define MAIL_SERVER_SOLITARY
Definition: mail_server.h:38
#define VSTREAM_ERR
Definition: vstream.h:68
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
void msg_info(const char *fmt,...)
Definition: msg.c:199