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