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