5
/* skeleton triggered mail subsystem
7
/* #include <mail_server.h>
9
/* NORETURN trigger_server_main(argc, argv, service, key, value, ...)
12
/* void (*service)(char *buf, int len, char *service_name, char **argv);
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.
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.
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
40
/* The argv argument specifies command-line arguments left over
41
/* after options processing.
42
/* The \fBserver\fR argument provides the following information:
44
/* Optional arguments are specified as a null-terminated (key, value)
45
/* list. Keys and expected values are:
46
/* .IP "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
51
/* .IP "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
56
/* .IP "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
61
/* .IP "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
66
/* .IP "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
72
/* .IP "MAIL_SERVER_PRE_INIT (void *(char *service_name, char **argv))"
73
/* A pointer to a function that is called once
74
/* by the skeleton after it has read the global configuration file
75
/* and after it has processed command-line arguments, but before
76
/* the skeleton has optionally relinquished the process privileges.
78
/* Only the last instance of this parameter type is remembered.
79
/* .IP "MAIL_SERVER_POST_INIT (void *(char *service_name, char **argv))"
80
/* A pointer to a function that is called once
81
/* by the skeleton after it has optionally relinquished the process
82
/* privileges, but before servicing client connection requests.
84
/* Only the last instance of this parameter type is remembered.
85
/* .IP "MAIL_SERVER_LOOP (int *(char *service_name, char **argv))"
86
/* A pointer to function that is executed from
87
/* within the event loop, whenever an I/O or timer event has happened,
88
/* or whenever nothing has happened for a specified amount of time.
89
/* The result value of the function specifies how long to wait until
90
/* the next event. Specify -1 to wait for "as long as it takes".
92
/* Only the last instance of this parameter type is remembered.
93
/* .IP "MAIL_SERVER_EXIT (void *(char *service_name, char **argv))"
94
/* A pointer to function that is executed immediately before normal
95
/* process termination.
97
/* Only the last instance of this parameter type is remembered.
98
/* .IP "MAIL_SERVER_PRE_ACCEPT (void *(char *service_name, char **argv))"
99
/* Function to be executed prior to accepting a new request.
101
/* Only the last instance of this parameter type is remembered.
102
/* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)"
103
/* Pause $in_flow_delay seconds when no "mail flow control token"
104
/* is available. A token is consumed for each connection request.
105
/* .IP MAIL_SERVER_SOLITARY
106
/* This service must be configured with process limit of 1.
107
/* .IP MAIL_SERVER_UNLIMITED
108
/* This service must be configured with process limit of 0.
110
/* The var_use_limit variable limits the number of clients that
111
/* a server can service before it commits suicide.
112
/* This value is taken from the global \fBmain.cf\fR configuration
113
/* file. Setting \fBvar_use_limit\fR to zero disables the client limit.
115
/* The var_idle_limit variable limits the time that a service
116
/* receives no client connection requests before it commits suicide.
117
/* This value is taken from the global \fBmain.cf\fR configuration
118
/* file. Setting \fBvar_use_limit\fR to zero disables the idle limit.
120
/* Problems and transactions are logged to \fBsyslogd\fR(8).
122
/* Works with FIFO-based services only.
124
/* master(8), master process
125
/* syslogd(8) system logging
129
/* The Secure Mailer license must be distributed with this software.
132
/* IBM T.J. Watson Research
134
/* Yorktown Heights, NY 10598, USA
137
/* System library. */
139
#include <sys_defs.h>
140
#include <sys/socket.h>
149
#ifdef STRCASECMP_IN_STRINGS_H
153
/* Utility library. */
156
#include <msg_syslog.h>
157
#include <chroot_uid.h>
160
#include <msg_vstream.h>
161
#include <mymalloc.h>
164
#include <stringops.h>
165
#include <sane_accept.h>
167
#include <safe_open.h>
169
#include <watchdog.h>
170
#include <split_at.h>
172
/* Global library. */
174
#include <mail_params.h>
175
#include <mail_task.h>
176
#include <debug_process.h>
177
#include <mail_conf.h>
178
#include <mail_dict.h>
179
#include <resolve_local.h>
180
#include <mail_flow.h>
182
/* Process manager. */
184
#include "master_proto.h"
186
/* Application-specific */
188
#include "mail_server.h"
193
static int use_count;
195
static TRIGGER_SERVER_FN trigger_server_service;
196
static char *trigger_server_name;
197
static char **trigger_server_argv;
198
static void (*trigger_server_accept) (int, char *);
199
static void (*trigger_server_onexit) (char *, char **);
200
static void (*trigger_server_pre_accept) (char *, char **);
201
static VSTREAM *trigger_server_lock;
202
static int trigger_server_in_flow_delay;
204
/* trigger_server_exit - normal termination */
206
static NORETURN trigger_server_exit(void)
208
if (trigger_server_onexit)
209
trigger_server_onexit(trigger_server_name, trigger_server_argv);
213
/* trigger_server_abort - terminate after abnormal master exit */
215
static void trigger_server_abort(int unused_event, char *unused_context)
218
msg_info("master disconnect -- exiting");
219
trigger_server_exit();
222
/* trigger_server_timeout - idle time exceeded */
224
static void trigger_server_timeout(int unused_event, char *unused_context)
227
msg_info("idle timeout -- exiting");
228
trigger_server_exit();
231
/* trigger_server_wakeup - wake up application */
233
static void trigger_server_wakeup(int fd)
235
char buf[TRIGGER_BUF_SIZE];
239
* Commit suicide when the master process disconnected from us.
241
if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
242
trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
243
if (trigger_server_in_flow_delay && mail_flow_get(1) < 0)
244
doze(var_in_flow_delay * 1000000);
245
if ((len = read(fd, buf, sizeof(buf))) >= 0)
246
trigger_server_service(buf, len, trigger_server_name,
247
trigger_server_argv);
248
if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
249
trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
250
if (var_idle_limit > 0)
251
event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
255
/* trigger_server_accept_fifo - accept fifo client request */
257
static void trigger_server_accept_fifo(int unused_event, char *context)
259
char *myname = "trigger_server_accept_fifo";
260
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
262
if (trigger_server_lock != 0
263
&& myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
264
MYFLOCK_OP_NONE) < 0)
265
msg_fatal("select unlock: %m");
268
msg_info("%s: trigger arrived", myname);
271
* Read whatever the other side wrote into the FIFO. The FIFO read end is
272
* non-blocking so we won't get stuck when multiple processes wake up.
274
if (trigger_server_pre_accept)
275
trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
276
trigger_server_wakeup(listen_fd);
279
/* trigger_server_accept_local - accept socket client request */
281
static void trigger_server_accept_local(int unused_event, char *context)
283
char *myname = "trigger_server_accept_local";
284
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
289
msg_info("%s: trigger arrived", myname);
292
* Read a message from a socket. Be prepared for accept() to fail because
293
* some other process already got the connection. The socket is
294
* non-blocking so we won't get stuck when multiple processes wake up.
295
* Don't get stuck when the client connects but sends no data. Restart
296
* the idle timer if this was a false alarm.
298
if (var_idle_limit > 0)
299
time_left = event_cancel_timer(trigger_server_timeout, (char *) 0);
301
if (trigger_server_pre_accept)
302
trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
303
fd = LOCAL_ACCEPT(listen_fd);
304
if (trigger_server_lock != 0
305
&& myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
306
MYFLOCK_OP_NONE) < 0)
307
msg_fatal("select unlock: %m");
310
msg_fatal("accept connection: %m");
312
event_request_timer(trigger_server_timeout, (char *) 0, time_left);
315
close_on_exec(fd, CLOSE_ON_EXEC);
316
if (read_wait(fd, 10) == 0)
317
trigger_server_wakeup(fd);
318
else if (time_left >= 0)
319
event_request_timer(trigger_server_timeout, (char *) 0, time_left);
323
/* trigger_server_main - the real main program */
325
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
327
char *myname = "trigger_server_main";
331
char *service_name = basename(argv[0]);
335
int socket_count = 1;
338
MAIL_SERVER_INIT_FN pre_init = 0;
339
MAIL_SERVER_INIT_FN post_init = 0;
340
MAIL_SERVER_LOOP_FN loop = 0;
342
char buf[TRIGGER_BUF_SIZE];
353
* Process environment options as early as we can.
355
if (getenv(CONF_ENV_VERB))
357
if (getenv(CONF_ENV_DEBUG))
361
* Don't die when a process goes away unexpectedly.
363
signal(SIGPIPE, SIG_IGN);
366
* Don't die for frivolous reasons.
369
signal(SIGXFSZ, SIG_IGN);
373
* May need this every now and then.
375
var_procname = mystrdup(basename(argv[0]));
376
set_mail_conf_str(VAR_PROCNAME, var_procname);
379
* Initialize logging and exit handler. Do the syslog first, so that its
380
* initialization completes before we enter the optional chroot jail.
382
msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
384
msg_info("daemon started");
387
* Initialize from the configuration file. Allow command-line options to
388
* override compiled-in defaults or configured parameter values.
393
* Register dictionaries that use higher-level interfaces and protocols.
398
* Pick up policy settings from master process. Shut up error messages to
399
* stderr, because no-one is going to see them.
402
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uvz")) > 0) {
411
mail_conf_update(VAR_MAX_IDLE, optarg);
417
mail_conf_update(VAR_MAX_USE, optarg);
420
service_name = optarg;
423
if ((oval = split_at(optarg, '=')) == 0)
425
mail_conf_update(optarg, oval);
428
if ((socket_count = atoi(optarg)) <= 0)
429
msg_fatal("invalid socket_count: %s", optarg);
447
msg_fatal("invalid option: %c", c);
453
* Initialize generic parameters.
458
* Application-specific initialization.
460
va_start(ap, service);
461
while ((key = va_arg(ap, int)) != 0) {
463
case MAIL_SERVER_INT_TABLE:
464
get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
466
case MAIL_SERVER_STR_TABLE:
467
get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
469
case MAIL_SERVER_BOOL_TABLE:
470
get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
472
case MAIL_SERVER_TIME_TABLE:
473
get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
475
case MAIL_SERVER_RAW_TABLE:
476
get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
478
case MAIL_SERVER_PRE_INIT:
479
pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
481
case MAIL_SERVER_POST_INIT:
482
post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
484
case MAIL_SERVER_LOOP:
485
loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
487
case MAIL_SERVER_EXIT:
488
trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
490
case MAIL_SERVER_PRE_ACCEPT:
491
trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
493
case MAIL_SERVER_IN_FLOW_DELAY:
494
trigger_server_in_flow_delay = 1;
496
case MAIL_SERVER_SOLITARY:
498
msg_fatal("service %s requires a process limit of 1",
501
case MAIL_SERVER_UNLIMITED:
503
msg_fatal("service %s requires a process limit of 0",
507
msg_panic("%s: unknown argument type: %d", myname, key);
513
root_dir = var_queue_dir;
515
user_name = var_mail_owner;
518
* If not connected to stdin, stdin must not be a terminal.
520
if (stream == 0 && isatty(STDIN_FILENO)) {
521
msg_vstream_init(var_procname, VSTREAM_ERR);
522
msg_fatal("do not run this command by hand");
526
* Can options be required?
528
* XXX Initially this code was implemented with UNIX-domain sockets, but
529
* Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
530
* client disconnects before the server has accepted the connection.
531
* Symptom: the server accept() fails with EPIPE or EPROTO, but the
532
* socket stays readable, so that the program goes into a wasteful loop.
534
* The initial fix was to use FIFOs, but those turn out to have their own
535
* problems, witness the workarounds in the fifo_listen() routine.
536
* Therefore we support both FIFOs and UNIX-domain sockets, so that the
537
* user can choose whatever works best.
539
* Well, I give up. Solaris UNIX-domain sockets still don't work properly,
540
* so it will have to limp along with a streams-specific alternative.
544
msg_fatal("no transport type specified");
545
if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
546
trigger_server_accept = trigger_server_accept_local;
547
else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
548
trigger_server_accept = trigger_server_accept_fifo;
550
msg_fatal("unsupported transport type: %s", transport);
554
* Optionally start the debugger on ourself.
560
* Traditionally, BSD select() can't handle multiple processes selecting
561
* on the same socket, and wakes up every process in select(). See TCP/IP
562
* Illustrated volume 2 page 532. We avoid select() collisions with an
563
* external lock file.
565
if (stream == 0 && !alone) {
566
lock_path = concatenate(DEF_PID_DIR, "/", transport,
567
".", service_name, (char *) 0);
568
why = vstring_alloc(1);
569
if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
570
(struct stat *) 0, -1, -1, why)) == 0)
571
msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
572
close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
578
* Set up call-back info.
580
trigger_server_service = service;
581
trigger_server_name = service_name;
582
trigger_server_argv = argv + optind;
585
* Run pre-jail initialization.
587
if (chdir(var_queue_dir) < 0)
588
msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
590
pre_init(trigger_server_name, trigger_server_argv);
593
* Optionally, restrict the damage that this process can do.
595
resolve_local_init();
596
chroot_uid(root_dir, user_name);
599
* Run post-jail initialization.
602
post_init(trigger_server_name, trigger_server_argv);
605
* Are we running as a one-shot server with the client connection on
609
if ((len = read(vstream_fileno(stream), buf, sizeof(buf))) <= 0)
610
msg_fatal("read: %m");
611
service(buf, len, trigger_server_name, trigger_server_argv);
612
vstream_fflush(stream);
613
trigger_server_exit();
617
* Running as a semi-resident server. Service connection requests.
618
* Terminate when we have serviced a sufficient number of clients, when
619
* no-one has been talking to us for a configurable amount of time, or
620
* when the master process terminated abnormally.
622
if (var_idle_limit > 0)
623
event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
624
for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
625
event_enable_read(fd, trigger_server_accept, CAST_INT_TO_CHAR_PTR(fd));
626
close_on_exec(fd, CLOSE_ON_EXEC);
628
event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
629
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
630
close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
631
close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
632
watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);
635
* The event loop, at last.
637
while (var_use_limit == 0 || use_count < var_use_limit) {
638
if (trigger_server_lock != 0) {
639
watchdog_stop(watchdog);
640
if (myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
641
MYFLOCK_OP_EXCLUSIVE) < 0)
642
msg_fatal("select lock: %m");
644
watchdog_start(watchdog);
645
delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
648
trigger_server_exit();