1 /* $NetBSD: bounce.c,v 1.1.1.1 2009/06/23 10:08:42 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* bounce 8 6 /* SUMMARY 7 /* Postfix delivery status reports 8 /* SYNOPSIS 9 /* \fBbounce\fR [generic Postfix daemon options] 10 /* DESCRIPTION 11 /* The \fBbounce\fR(8) daemon maintains per-message log files with 12 /* delivery status information. Each log file is named after the 13 /* queue file that it corresponds to, and is kept in a queue subdirectory 14 /* named after the service name in the \fBmaster.cf\fR file (either 15 /* \fBbounce\fR, \fBdefer\fR or \fBtrace\fR). 16 /* This program expects to be run from the \fBmaster\fR(8) process 17 /* manager. 18 /* 19 /* The \fBbounce\fR(8) daemon processes two types of service requests: 20 /* .IP \(bu 21 /* Append a recipient (non-)delivery status record to a per-message 22 /* log file. 23 /* .IP \(bu 24 /* Enqueue a delivery status notification message, with a copy 25 /* of a per-message log file and of the corresponding message. 26 /* When the delivery status notification message is 27 /* enqueued successfully, the per-message log file is deleted. 28 /* .PP 29 /* The software does a best notification effort. A non-delivery 30 /* notification is sent even when the log file or the original 31 /* message cannot be read. 32 /* 33 /* Optionally, a bounce (defer, trace) client can request that the 34 /* per-message log file be deleted when the requested operation fails. 35 /* This is used by clients that cannot retry transactions by 36 /* themselves, and that depend on retry logic in their own client. 37 /* STANDARDS 38 /* RFC 822 (ARPA Internet Text Messages) 39 /* RFC 2045 (Format of Internet Message Bodies) 40 /* RFC 2822 (ARPA Internet Text Messages) 41 /* RFC 3462 (Delivery Status Notifications) 42 /* RFC 3464 (Delivery Status Notifications) 43 /* RFC 3834 (Auto-Submitted: message header) 44 /* DIAGNOSTICS 45 /* Problems and transactions are logged to \fBsyslogd\fR(8). 46 /* CONFIGURATION PARAMETERS 47 /* .ad 48 /* .fi 49 /* Changes to \fBmain.cf\fR are picked up automatically, as \fBbounce\fR(8) 50 /* processes run for only a limited amount of time. Use the command 51 /* "\fBpostfix reload\fR" to speed up a change. 52 /* 53 /* The text below provides only a parameter summary. See 54 /* \fBpostconf\fR(5) for more details including examples. 55 /* .IP "\fB2bounce_notice_recipient (postmaster)\fR" 56 /* The recipient of undeliverable mail that cannot be returned to 57 /* the sender. 58 /* .IP "\fBbackwards_bounce_logfile_compatibility (yes)\fR" 59 /* Produce additional \fBbounce\fR(8) logfile records that can be read by 60 /* Postfix versions before 2.0. 61 /* .IP "\fBbounce_notice_recipient (postmaster)\fR" 62 /* The recipient of postmaster notifications with the message headers 63 /* of mail that Postfix did not deliver and of SMTP conversation 64 /* transcripts of mail that Postfix did not receive. 65 /* .IP "\fBbounce_size_limit (50000)\fR" 66 /* The maximal amount of original message text that is sent in a 67 /* non-delivery notification. 68 /* .IP "\fBbounce_template_file (empty)\fR" 69 /* Pathname of a configuration file with bounce message templates. 70 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" 71 /* The default location of the Postfix main.cf and master.cf 72 /* configuration files. 73 /* .IP "\fBdaemon_timeout (18000s)\fR" 74 /* How much time a Postfix daemon process may take to handle a 75 /* request before it is terminated by a built-in watchdog timer. 76 /* .IP "\fBdelay_notice_recipient (postmaster)\fR" 77 /* The recipient of postmaster notifications with the message headers 78 /* of mail that cannot be delivered within $delay_warning_time time 79 /* units. 80 /* .IP "\fBdeliver_lock_attempts (20)\fR" 81 /* The maximal number of attempts to acquire an exclusive lock on a 82 /* mailbox file or \fBbounce\fR(8) logfile. 83 /* .IP "\fBdeliver_lock_delay (1s)\fR" 84 /* The time between attempts to acquire an exclusive lock on a mailbox 85 /* file or \fBbounce\fR(8) logfile. 86 /* .IP "\fBipc_timeout (3600s)\fR" 87 /* The time limit for sending or receiving information over an internal 88 /* communication channel. 89 /* .IP "\fBinternal_mail_filter_classes (empty)\fR" 90 /* What categories of Postfix-generated mail are subject to 91 /* before-queue content inspection by non_smtpd_milters, header_checks 92 /* and body_checks. 93 /* .IP "\fBmail_name (Postfix)\fR" 94 /* The mail system name that is displayed in Received: headers, in 95 /* the SMTP greeting banner, and in bounced mail. 96 /* .IP "\fBmax_idle (100s)\fR" 97 /* The maximum amount of time that an idle Postfix daemon process waits 98 /* for an incoming connection before terminating voluntarily. 99 /* .IP "\fBmax_use (100)\fR" 100 /* The maximal number of incoming connections that a Postfix daemon 101 /* process will service before terminating voluntarily. 102 /* .IP "\fBnotify_classes (resource, software)\fR" 103 /* The list of error classes that are reported to the postmaster. 104 /* .IP "\fBprocess_id (read-only)\fR" 105 /* The process ID of a Postfix command or daemon process. 106 /* .IP "\fBprocess_name (read-only)\fR" 107 /* The process name of a Postfix command or daemon process. 108 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" 109 /* The location of the Postfix top-level queue directory. 110 /* .IP "\fBsyslog_facility (mail)\fR" 111 /* The syslog facility of Postfix logging. 112 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" 113 /* The mail system name that is prepended to the process name in syslog 114 /* records, so that "smtpd" becomes, for example, "postfix/smtpd". 115 /* FILES 116 /* /var/spool/postfix/bounce/* non-delivery records 117 /* /var/spool/postfix/defer/* non-delivery records 118 /* /var/spool/postfix/trace/* delivery status records 119 /* SEE ALSO 120 /* bounce(5), bounce message template format 121 /* qmgr(8), queue manager 122 /* postconf(5), configuration parameters 123 /* master(5), generic daemon options 124 /* master(8), process manager 125 /* syslogd(8), system logging 126 /* LICENSE 127 /* .ad 128 /* .fi 129 /* The Secure Mailer license must be distributed with this software. 130 /* AUTHOR(S) 131 /* Wietse Venema 132 /* IBM T.J. Watson Research 133 /* P.O. Box 704 134 /* Yorktown Heights, NY 10598, USA 135 /*--*/ 136 137 /* System library. */ 138 139 #include <sys_defs.h> 140 #include <string.h> 141 #include <stdlib.h> 142 143 #ifdef STRCASECMP_IN_STRINGS_H 144 #include <strings.h> 145 #endif 146 147 /* Utility library. */ 148 149 #include <msg.h> 150 #include <vstring.h> 151 #include <vstream.h> 152 #include <stringops.h> 153 #include <load_file.h> 154 155 /* Global library. */ 156 157 #include <mail_proto.h> 158 #include <mail_queue.h> 159 #include <mail_params.h> 160 #include <mail_version.h> 161 #include <mail_conf.h> 162 #include <bounce.h> 163 #include <mail_addr.h> 164 #include <rcpt_buf.h> 165 #include <dsb_scan.h> 166 167 /* Single-threaded server skeleton. */ 168 169 #include <mail_server.h> 170 171 /* Application-specific. */ 172 173 #include <bounce_service.h> 174 175 /* 176 * Tunables. 177 */ 178 int var_bounce_limit; 179 int var_max_queue_time; 180 int var_delay_warn_time; 181 char *var_notify_classes; 182 char *var_bounce_rcpt; 183 char *var_2bounce_rcpt; 184 char *var_delay_rcpt; 185 char *var_bounce_tmpl; 186 187 /* 188 * We're single threaded, so we can avoid some memory allocation overhead. 189 */ 190 static VSTRING *queue_id; 191 static VSTRING *queue_name; 192 static RCPT_BUF *rcpt_buf; 193 static VSTRING *encoding; 194 static VSTRING *sender; 195 static VSTRING *dsn_envid; 196 static VSTRING *verp_delims; 197 static DSN_BUF *dsn_buf; 198 199 /* 200 * Templates. 201 */ 202 BOUNCE_TEMPLATES *bounce_templates; 203 204 #define STR vstring_str 205 206 #define VS_NEUTER(s) printable(vstring_str(s), '?') 207 208 /* bounce_append_proto - bounce_append server protocol */ 209 210 static int bounce_append_proto(char *service_name, VSTREAM *client) 211 { 212 const char *myname = "bounce_append_proto"; 213 int flags; 214 215 /* 216 * Read and validate the client request. 217 */ 218 if (mail_command_server(client, 219 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, 220 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 221 ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, 222 ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf, 223 ATTR_TYPE_END) != 4) { 224 msg_warn("malformed request"); 225 return (-1); 226 } 227 228 /* 229 * Sanitize input. 230 */ 231 if (mail_queue_id_ok(STR(queue_id)) == 0) { 232 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 233 return (-1); 234 } 235 VS_NEUTER(rcpt_buf->address); 236 VS_NEUTER(rcpt_buf->orig_addr); 237 VS_NEUTER(rcpt_buf->dsn_orcpt); 238 VS_NEUTER(dsn_buf->status); 239 VS_NEUTER(dsn_buf->action); 240 VS_NEUTER(dsn_buf->reason); 241 VS_NEUTER(dsn_buf->dtype); 242 VS_NEUTER(dsn_buf->dtext); 243 VS_NEUTER(dsn_buf->mtype); 244 VS_NEUTER(dsn_buf->mname); 245 (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); 246 (void) DSN_FROM_DSN_BUF(dsn_buf); 247 248 /* 249 * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and 250 * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and 251 * RECIPIENT_FROM_RCPT_BUF(). 252 */ 253 if (msg_verbose) 254 msg_info("%s: flags=0x%x service=%s id=%s org_to=%s to=%s off=%ld dsn_org=%s, notif=0x%x stat=%s act=%s why=%s", 255 myname, flags, service_name, STR(queue_id), 256 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address), 257 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt), 258 rcpt_buf->dsn_notify, STR(dsn_buf->status), 259 STR(dsn_buf->action), STR(dsn_buf->reason)); 260 261 /* 262 * On request by the client, set up a trap to delete the log file in case 263 * of errors. 264 */ 265 if (flags & BOUNCE_FLAG_CLEAN) 266 bounce_cleanup_register(service_name, STR(queue_id)); 267 268 /* 269 * Execute the request. 270 */ 271 return (bounce_append_service(flags, service_name, STR(queue_id), 272 &rcpt_buf->rcpt, &dsn_buf->dsn)); 273 } 274 275 /* bounce_notify_proto - bounce_notify server protocol */ 276 277 static int bounce_notify_proto(char *service_name, VSTREAM *client, 278 int (*service) (int, char *, char *, char *, 279 char *, char *, char *, int, 280 BOUNCE_TEMPLATES *)) 281 { 282 const char *myname = "bounce_notify_proto"; 283 int flags; 284 int dsn_ret; 285 286 /* 287 * Read and validate the client request. 288 */ 289 if (mail_command_server(client, 290 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, 291 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, 292 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 293 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 294 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 295 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 296 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret, 297 ATTR_TYPE_END) != 7) { 298 msg_warn("malformed request"); 299 return (-1); 300 } 301 302 /* 303 * Sanitize input. 304 */ 305 if (mail_queue_name_ok(STR(queue_name)) == 0) { 306 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 307 return (-1); 308 } 309 if (mail_queue_id_ok(STR(queue_id)) == 0) { 310 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 311 return (-1); 312 } 313 printable(STR(dsn_envid), '?'); 314 if (msg_verbose) 315 msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s envid=%s ret=0x%x", 316 myname, flags, service_name, STR(queue_name), STR(queue_id), 317 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret); 318 319 /* 320 * On request by the client, set up a trap to delete the log file in case 321 * of errors. 322 */ 323 if (flags & BOUNCE_FLAG_CLEAN) 324 bounce_cleanup_register(service_name, STR(queue_id)); 325 326 /* 327 * Execute the request. 328 */ 329 return (service(flags, service_name, STR(queue_name), 330 STR(queue_id), STR(encoding), 331 STR(sender), STR(dsn_envid), dsn_ret, 332 bounce_templates)); 333 } 334 335 /* bounce_verp_proto - bounce_notify server protocol, VERP style */ 336 337 static int bounce_verp_proto(char *service_name, VSTREAM *client) 338 { 339 const char *myname = "bounce_verp_proto"; 340 int flags; 341 int dsn_ret; 342 343 /* 344 * Read and validate the client request. 345 */ 346 if (mail_command_server(client, 347 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, 348 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, 349 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 350 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 351 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 352 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 353 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret, 354 ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims, 355 ATTR_TYPE_END) != 8) { 356 msg_warn("malformed request"); 357 return (-1); 358 } 359 360 /* 361 * Sanitize input. 362 */ 363 if (mail_queue_name_ok(STR(queue_name)) == 0) { 364 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 365 return (-1); 366 } 367 if (mail_queue_id_ok(STR(queue_id)) == 0) { 368 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 369 return (-1); 370 } 371 printable(STR(dsn_envid), '?'); 372 if (strlen(STR(verp_delims)) != 2) { 373 msg_warn("malformed verp delimiter string: %s", 374 printable(STR(verp_delims), '?')); 375 return (-1); 376 } 377 if (msg_verbose) 378 msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s envid=%s ret=0x%x delim=%s", 379 myname, flags, service_name, STR(queue_name), 380 STR(queue_id), STR(encoding), STR(sender), 381 STR(dsn_envid), dsn_ret, STR(verp_delims)); 382 383 /* 384 * On request by the client, set up a trap to delete the log file in case 385 * of errors. 386 */ 387 if (flags & BOUNCE_FLAG_CLEAN) 388 bounce_cleanup_register(service_name, STR(queue_id)); 389 390 /* 391 * Execute the request. Fall back to traditional notification if a bounce 392 * was returned as undeliverable, because we don't want to VERPify those. 393 */ 394 if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) { 395 msg_warn("request to send VERP-style notification of bounced mail"); 396 return (bounce_notify_service(flags, service_name, STR(queue_name), 397 STR(queue_id), STR(encoding), 398 STR(sender), STR(dsn_envid), dsn_ret, 399 bounce_templates)); 400 } else 401 return (bounce_notify_verp(flags, service_name, STR(queue_name), 402 STR(queue_id), STR(encoding), 403 STR(sender), STR(dsn_envid), dsn_ret, 404 STR(verp_delims), bounce_templates)); 405 } 406 407 /* bounce_one_proto - bounce_one server protocol */ 408 409 static int bounce_one_proto(char *service_name, VSTREAM *client) 410 { 411 const char *myname = "bounce_one_proto"; 412 int flags; 413 int dsn_ret; 414 415 /* 416 * Read and validate the client request. 417 */ 418 if (mail_command_server(client, 419 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, 420 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, 421 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, 422 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 423 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 424 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 425 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret, 426 ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, 427 ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf, 428 ATTR_TYPE_END) != 9) { 429 msg_warn("malformed request"); 430 return (-1); 431 } 432 433 /* 434 * Sanitize input. 435 */ 436 if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) { 437 msg_warn("wrong service name \"%s\" for one-recipient bouncing", 438 service_name); 439 return (-1); 440 } 441 if (mail_queue_name_ok(STR(queue_name)) == 0) { 442 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 443 return (-1); 444 } 445 if (mail_queue_id_ok(STR(queue_id)) == 0) { 446 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 447 return (-1); 448 } 449 printable(STR(dsn_envid), '?'); 450 VS_NEUTER(rcpt_buf->address); 451 VS_NEUTER(rcpt_buf->orig_addr); 452 VS_NEUTER(rcpt_buf->dsn_orcpt); 453 VS_NEUTER(dsn_buf->status); 454 VS_NEUTER(dsn_buf->action); 455 VS_NEUTER(dsn_buf->reason); 456 VS_NEUTER(dsn_buf->dtype); 457 VS_NEUTER(dsn_buf->dtext); 458 VS_NEUTER(dsn_buf->mtype); 459 VS_NEUTER(dsn_buf->mname); 460 (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); 461 (void) DSN_FROM_DSN_BUF(dsn_buf); 462 463 /* 464 * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and 465 * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and 466 * RECIPIENT_FROM_RCPT_BUF(). 467 */ 468 if (msg_verbose) 469 msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s envid=%s dsn_ret=0x%x orig_to=%s to=%s off=%ld dsn_orig=%s notif=0x%x stat=%s act=%s why=%s", 470 myname, flags, STR(queue_name), STR(queue_id), 471 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret, 472 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address), 473 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt), 474 rcpt_buf->dsn_notify, STR(dsn_buf->status), 475 STR(dsn_buf->action), STR(dsn_buf->reason)); 476 477 /* 478 * Execute the request. 479 */ 480 return (bounce_one_service(flags, STR(queue_name), STR(queue_id), 481 STR(encoding), STR(sender), STR(dsn_envid), 482 dsn_ret, rcpt_buf, dsn_buf, bounce_templates)); 483 } 484 485 /* bounce_service - parse bounce command type and delegate */ 486 487 static void bounce_service(VSTREAM *client, char *service_name, char **argv) 488 { 489 int command; 490 int status; 491 492 /* 493 * Sanity check. This service takes no command-line arguments. The 494 * service name should be usable as a subdirectory name. 495 */ 496 if (argv[0]) 497 msg_fatal("unexpected command-line argument: %s", argv[0]); 498 if (mail_queue_name_ok(service_name) == 0) 499 msg_fatal("malformed service name: %s", service_name); 500 501 /* 502 * Read and validate the first parameter of the client request. Let the 503 * request-specific protocol routines take care of the remainder. 504 */ 505 if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, 506 ATTR_TYPE_INT, MAIL_ATTR_NREQ, &command, 0) != 1) { 507 msg_warn("malformed request"); 508 status = -1; 509 } else if (command == BOUNCE_CMD_VERP) { 510 status = bounce_verp_proto(service_name, client); 511 } else if (command == BOUNCE_CMD_FLUSH) { 512 status = bounce_notify_proto(service_name, client, 513 bounce_notify_service); 514 } else if (command == BOUNCE_CMD_WARN) { 515 status = bounce_notify_proto(service_name, client, 516 bounce_warn_service); 517 } else if (command == BOUNCE_CMD_TRACE) { 518 status = bounce_notify_proto(service_name, client, 519 bounce_trace_service); 520 } else if (command == BOUNCE_CMD_APPEND) { 521 status = bounce_append_proto(service_name, client); 522 } else if (command == BOUNCE_CMD_ONE) { 523 status = bounce_one_proto(service_name, client); 524 } else { 525 msg_warn("unknown command: %d", command); 526 status = -1; 527 } 528 529 /* 530 * When the request has completed, send the completion status to the 531 * client. 532 */ 533 attr_print(client, ATTR_FLAG_NONE, 534 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 535 ATTR_TYPE_END); 536 vstream_fflush(client); 537 538 /* 539 * When a cleanup trap was set, delete the log file in case of error. 540 * This includes errors while sending the completion status to the 541 * client. 542 */ 543 if (bounce_cleanup_path) { 544 if (status || vstream_ferror(client)) 545 bounce_cleanup_log(); 546 bounce_cleanup_unregister(); 547 } 548 } 549 550 static void load_helper(VSTREAM *stream, void *context) 551 { 552 BOUNCE_TEMPLATES *templates = (BOUNCE_TEMPLATES *) context; 553 554 bounce_templates_load(stream, templates); 555 } 556 557 /* pre_jail_init - pre-jail initialization */ 558 559 static void pre_jail_init(char *unused_name, char **unused_argv) 560 { 561 562 /* 563 * Bundle up a bunch of bounce template information. 564 */ 565 bounce_templates = bounce_templates_create(); 566 567 /* 568 * Load the alternate message files (if specified) before entering the 569 * chroot jail. 570 */ 571 if (*var_bounce_tmpl) 572 load_file(var_bounce_tmpl, load_helper, (char *) bounce_templates); 573 } 574 575 /* post_jail_init - initialize after entering chroot jail */ 576 577 static void post_jail_init(char *service_name, char **unused_argv) 578 { 579 580 /* 581 * Special case: dump bounce templates. This is not part of the master(5) 582 * public interface. This internal interface is used by the postconf 583 * command. It was implemented before bounce templates were isolated into 584 * modules that could have been called directly. 585 */ 586 if (strcmp(service_name, "dump_templates") == 0) { 587 bounce_templates_dump(VSTREAM_OUT, bounce_templates); 588 vstream_fflush(VSTREAM_OUT); 589 exit(0); 590 } 591 if (strcmp(service_name, "expand_templates") == 0) { 592 bounce_templates_expand(VSTREAM_OUT, bounce_templates); 593 vstream_fflush(VSTREAM_OUT); 594 exit(0); 595 } 596 597 /* 598 * Initialize. We're single threaded so we can reuse some memory upon 599 * successive requests. 600 */ 601 queue_id = vstring_alloc(10); 602 queue_name = vstring_alloc(10); 603 rcpt_buf = rcpb_create(); 604 encoding = vstring_alloc(10); 605 sender = vstring_alloc(10); 606 dsn_envid = vstring_alloc(10); 607 verp_delims = vstring_alloc(10); 608 dsn_buf = dsb_create(); 609 } 610 611 MAIL_VERSION_STAMP_DECLARE; 612 613 /* main - the main program */ 614 615 int main(int argc, char **argv) 616 { 617 static const CONFIG_INT_TABLE int_table[] = { 618 VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0, 619 0, 620 }; 621 static const CONFIG_TIME_TABLE time_table[] = { 622 VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000, 623 VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0, 624 0, 625 }; 626 static const CONFIG_STR_TABLE str_table[] = { 627 VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, 628 VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0, 629 VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0, 630 VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0, 631 VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0, 632 0, 633 }; 634 635 /* 636 * Fingerprint executables and core dumps. 637 */ 638 MAIL_VERSION_STAMP_ALLOCATE; 639 640 /* 641 * Pass control to the single-threaded service skeleton. 642 */ 643 single_server_main(argc, argv, bounce_service, 644 MAIL_SERVER_INT_TABLE, int_table, 645 MAIL_SERVER_STR_TABLE, str_table, 646 MAIL_SERVER_TIME_TABLE, time_table, 647 MAIL_SERVER_PRE_INIT, pre_jail_init, 648 MAIL_SERVER_POST_INIT, post_jail_init, 649 MAIL_SERVER_UNLIMITED, 650 0); 651 } 652