event_server.c revision 1.4
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 */ 262static int client_count; 263static int use_count; 264static int socket_count = 1; 265 266static void (*event_server_service) (VSTREAM *, char *, char **); 267static char *event_server_name; 268static char **event_server_argv; 269static void (*event_server_accept) (int, void *); 270static void (*event_server_onexit) (char *, char **); 271static void (*event_server_pre_accept) (char *, char **); 272static VSTREAM *event_server_lock; 273static int event_server_in_flow_delay; 274static unsigned event_server_generation; 275static void (*event_server_pre_disconn) (VSTREAM *, char *, char **); 276static void (*event_server_slow_exit) (char *, char **); 277static int event_server_watchdog = 1000; 278 279/* event_server_exit - normal termination */ 280 281static 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 290static 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 304static 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 318static 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 327int 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 357void 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 374static 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 400static 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 444static 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 481static 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 519static 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 554NORETURN 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