1 /* $NetBSD: bounce.c,v 1.6 2026/05/09 18:49:14 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 /* .PP 140 /* Available in Postfix 3.10 and later: 141 /* .IP "\fBtls_required_enable (yes)\fR" 142 /* Enable support for the "TLS-Required: no" message header, defined 143 /* in RFC 8689. 144 /* .PP 145 /* Available in Postfix 3.11 and later: 146 /* .IP "\fBrequiretls_redact_dsn (yes)\fR" 147 /* When sending a delivery status notification for an original 148 /* message received with the REQUIRETLS option, do not send the original 149 /* message body (as if that message was received with "RET=HDRS") and 150 /* do not enforce REQUIRETLS (as if that message was received without 151 /* REQUIRETLS). 152 /* FILES 153 /* /var/spool/postfix/bounce/* non-delivery records 154 /* /var/spool/postfix/defer/* non-delivery records 155 /* /var/spool/postfix/trace/* delivery status records 156 /* SEE ALSO 157 /* bounce(5), bounce message template format 158 /* qmgr(8), queue manager 159 /* postconf(5), configuration parameters 160 /* master(5), generic daemon options 161 /* master(8), process manager 162 /* postlogd(8), Postfix logging 163 /* syslogd(8), system logging 164 /* LICENSE 165 /* .ad 166 /* .fi 167 /* The Secure Mailer license must be distributed with this software. 168 /* AUTHOR(S) 169 /* Wietse Venema 170 /* IBM T.J. Watson Research 171 /* P.O. Box 704 172 /* Yorktown Heights, NY 10598, USA 173 /* 174 /* Wietse Venema 175 /* Google, Inc. 176 /* 111 8th Avenue 177 /* New York, NY 10011, USA 178 /* 179 /* Wietse Venema 180 /* porcupine.org 181 /*--*/ 182 183 /* System library. */ 184 185 #include <sys_defs.h> 186 #include <string.h> 187 #include <stdlib.h> 188 189 /* Utility library. */ 190 191 #include <msg.h> 192 #include <vstring.h> 193 #include <vstream.h> 194 #include <stringops.h> 195 #include <load_file.h> 196 197 /* Global library. */ 198 199 #include <mail_proto.h> 200 #include <mail_queue.h> 201 #include <mail_params.h> 202 #include <mail_version.h> 203 #include <mail_conf.h> 204 #include <bounce.h> 205 #include <mail_addr.h> 206 #include <rcpt_buf.h> 207 #include <dsb_scan.h> 208 #include <hfrom_format.h> 209 #include <sendopts.h> 210 #include <dsn_mask.h> 211 212 /* Single-threaded server skeleton. */ 213 214 #include <mail_server.h> 215 216 /* Application-specific. */ 217 218 #include <bounce_service.h> 219 220 /* 221 * Tunables. 222 */ 223 int var_bounce_limit; 224 int var_max_queue_time; 225 int var_delay_warn_time; 226 char *var_notify_classes; 227 char *var_bounce_rcpt; 228 char *var_2bounce_rcpt; 229 char *var_delay_rcpt; 230 char *var_bounce_tmpl; 231 bool var_threaded_bounce; 232 char *var_hfrom_format; /* header_from_format */ 233 bool var_reqtls_redact_dsn; 234 235 /* 236 * We're single threaded, so we can avoid some memory allocation overhead. 237 */ 238 static VSTRING *queue_id; 239 static VSTRING *queue_name; 240 static RCPT_BUF *rcpt_buf; 241 static VSTRING *encoding; 242 static VSTRING *sender; 243 static VSTRING *dsn_envid; 244 static VSTRING *verp_delims; 245 static DSN_BUF *dsn_buf; 246 247 /* 248 * Templates. 249 */ 250 BOUNCE_TEMPLATES *bounce_templates; 251 252 /* 253 * From: header format. 254 */ 255 int bounce_hfrom_format; 256 257 #define STR vstring_str 258 259 #define VS_NEUTER(s) printable(vstring_str(s), '?') 260 261 /* bounce_append_proto - bounce_append server protocol */ 262 263 static int bounce_append_proto(char *service_name, VSTREAM *client) 264 { 265 const char *myname = "bounce_append_proto"; 266 int flags; 267 268 /* 269 * Read and validate the client request. 270 */ 271 if (mail_command_server(client, 272 RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags), 273 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 274 RECV_ATTR_FUNC(rcpb_scan, (void *) rcpt_buf), 275 RECV_ATTR_FUNC(dsb_scan, (void *) dsn_buf), 276 ATTR_TYPE_END) != 4) { 277 msg_warn("malformed request"); 278 return (-1); 279 } 280 281 /* 282 * Sanitize input. 283 */ 284 if (mail_queue_id_ok(STR(queue_id)) == 0) { 285 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 286 return (-1); 287 } 288 VS_NEUTER(rcpt_buf->address); 289 VS_NEUTER(rcpt_buf->orig_addr); 290 VS_NEUTER(rcpt_buf->dsn_orcpt); 291 VS_NEUTER(dsn_buf->status); 292 VS_NEUTER(dsn_buf->action); 293 VS_NEUTER(dsn_buf->reason); 294 VS_NEUTER(dsn_buf->dtype); 295 VS_NEUTER(dsn_buf->dtext); 296 VS_NEUTER(dsn_buf->mtype); 297 VS_NEUTER(dsn_buf->mname); 298 (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); 299 (void) DSN_FROM_DSN_BUF(dsn_buf); 300 301 /* 302 * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and 303 * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and 304 * RECIPIENT_FROM_RCPT_BUF(). 305 */ 306 if (msg_verbose) 307 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", 308 myname, flags, service_name, STR(queue_id), 309 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address), 310 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt), 311 rcpt_buf->dsn_notify, STR(dsn_buf->status), 312 STR(dsn_buf->action), STR(dsn_buf->reason)); 313 314 /* 315 * On request by the client, set up a trap to delete the log file in case 316 * of errors. 317 */ 318 if (flags & BOUNCE_FLAG_CLEAN) 319 bounce_cleanup_register(service_name, STR(queue_id)); 320 321 /* 322 * Execute the request. 323 */ 324 return (bounce_append_service(flags, service_name, STR(queue_id), 325 &rcpt_buf->rcpt, &dsn_buf->dsn)); 326 } 327 328 /* edit_notification_properties - bounce message filter */ 329 330 static void edit_notification_properties(int *sendopts, int *dsn_ret) 331 { 332 333 /* 334 * If REQUIRETLS is requested, do not propagate "TLS-Required: no". See 335 * also down-stream code in bounce_header(). 336 */ 337 if (*sendopts & SOPT_REQUIRETLS_ESMTP) 338 *sendopts &= ~SOPT_REQUIRETLS_HEADER; 339 340 /* 341 * Redact delivery status notification for REQUIRETLS message. 342 */ 343 if (var_reqtls_redact_dsn && (*sendopts & SOPT_REQUIRETLS_ESMTP)) { 344 *sendopts &= ~SOPT_REQUIRETLS_ESMTP; 345 *dsn_ret = DSN_RET_HDRS; 346 } 347 } 348 349 /* bounce_notify_proto - bounce_notify server protocol */ 350 351 static int bounce_notify_proto(char *service_name, VSTREAM *client, 352 int (*service) (int, char *, char *, char *, 353 char *, int, char *, char *, int, 354 BOUNCE_TEMPLATES *)) 355 { 356 const char *myname = "bounce_notify_proto"; 357 int flags; 358 int sendopts; 359 int dsn_ret; 360 361 /* 362 * Read and validate the client request. 363 */ 364 if (mail_command_server(client, 365 RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags), 366 RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name), 367 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 368 RECV_ATTR_STR(MAIL_ATTR_ENCODING, encoding), 369 RECV_ATTR_INT(MAIL_ATTR_SENDOPTS, &sendopts), 370 RECV_ATTR_STR(MAIL_ATTR_SENDER, sender), 371 RECV_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid), 372 RECV_ATTR_INT(MAIL_ATTR_DSN_RET, &dsn_ret), 373 ATTR_TYPE_END) != 8) { 374 msg_warn("malformed request"); 375 return (-1); 376 } 377 378 /* 379 * Sanitize input. 380 */ 381 if (mail_queue_name_ok(STR(queue_name)) == 0) { 382 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 383 return (-1); 384 } 385 if (mail_queue_id_ok(STR(queue_id)) == 0) { 386 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 387 return (-1); 388 } 389 VS_NEUTER(encoding); 390 VS_NEUTER(sender); 391 VS_NEUTER(dsn_envid); 392 if (msg_verbose) 393 msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sendopts=%d sender=%s envid=%s ret=0x%x", 394 myname, flags, service_name, STR(queue_name), STR(queue_id), 395 STR(encoding), sendopts, STR(sender), STR(dsn_envid), 396 dsn_ret); 397 398 /* 399 * On request by the client, set up a trap to delete the log file in case 400 * of errors. 401 */ 402 if (flags & BOUNCE_FLAG_CLEAN) 403 bounce_cleanup_register(service_name, STR(queue_id)); 404 405 /* 406 * Handle REQUIRETLS etc. matters. 407 */ 408 if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL)) 409 edit_notification_properties(&sendopts, &dsn_ret); 410 411 /* 412 * Execute the request. 413 */ 414 return (service(flags, service_name, STR(queue_name), 415 STR(queue_id), STR(encoding), sendopts, 416 STR(sender), STR(dsn_envid), dsn_ret, 417 bounce_templates)); 418 } 419 420 /* bounce_verp_proto - bounce_notify server protocol, VERP style */ 421 422 static int bounce_verp_proto(char *service_name, VSTREAM *client) 423 { 424 const char *myname = "bounce_verp_proto"; 425 int flags; 426 int sendopts; 427 int dsn_ret; 428 429 /* 430 * Read and validate the client request. 431 */ 432 if (mail_command_server(client, 433 RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags), 434 RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name), 435 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 436 RECV_ATTR_STR(MAIL_ATTR_ENCODING, encoding), 437 RECV_ATTR_INT(MAIL_ATTR_SENDOPTS, &sendopts), 438 RECV_ATTR_STR(MAIL_ATTR_SENDER, sender), 439 RECV_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid), 440 RECV_ATTR_INT(MAIL_ATTR_DSN_RET, &dsn_ret), 441 RECV_ATTR_STR(MAIL_ATTR_VERPDL, verp_delims), 442 ATTR_TYPE_END) != 9) { 443 msg_warn("malformed request"); 444 return (-1); 445 } 446 447 /* 448 * Sanitize input. 449 */ 450 if (mail_queue_name_ok(STR(queue_name)) == 0) { 451 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 452 return (-1); 453 } 454 if (mail_queue_id_ok(STR(queue_id)) == 0) { 455 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 456 return (-1); 457 } 458 VS_NEUTER(encoding); 459 VS_NEUTER(sender); 460 VS_NEUTER(dsn_envid); 461 VS_NEUTER(verp_delims); 462 if (strlen(STR(verp_delims)) != 2) { 463 msg_warn("malformed verp delimiter string: %s", STR(verp_delims)); 464 return (-1); 465 } 466 if (msg_verbose) 467 msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sendopts=%d sender=%s envid=%s ret=0x%x delim=%s", 468 myname, flags, service_name, STR(queue_name), 469 STR(queue_id), STR(encoding), sendopts, STR(sender), 470 STR(dsn_envid), dsn_ret, STR(verp_delims)); 471 472 /* 473 * On request by the client, set up a trap to delete the log file in case 474 * of errors. 475 */ 476 if (flags & BOUNCE_FLAG_CLEAN) 477 bounce_cleanup_register(service_name, STR(queue_id)); 478 479 /* 480 * Handle REQUIRETLS etc. matters. 481 */ 482 if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL)) 483 edit_notification_properties(&sendopts, &dsn_ret); 484 485 /* 486 * Execute the request. Fall back to traditional notification if a bounce 487 * was returned as undeliverable, because we don't want to VERPify those. 488 */ 489 if (!*STR(sender) || !strcasecmp_utf8(STR(sender), 490 mail_addr_double_bounce())) { 491 msg_warn("request to send VERP-style notification of bounced mail"); 492 return (bounce_notify_service(flags, service_name, STR(queue_name), 493 STR(queue_id), STR(encoding), sendopts, 494 STR(sender), STR(dsn_envid), dsn_ret, 495 bounce_templates)); 496 } else 497 return (bounce_notify_verp(flags, service_name, STR(queue_name), 498 STR(queue_id), STR(encoding), sendopts, 499 STR(sender), STR(dsn_envid), dsn_ret, 500 STR(verp_delims), bounce_templates)); 501 } 502 503 /* bounce_one_proto - bounce_one server protocol */ 504 505 static int bounce_one_proto(char *service_name, VSTREAM *client) 506 { 507 const char *myname = "bounce_one_proto"; 508 int flags; 509 int sendopts; 510 int dsn_ret; 511 512 /* 513 * Read and validate the client request. 514 */ 515 if (mail_command_server(client, 516 RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags), 517 RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name), 518 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 519 RECV_ATTR_STR(MAIL_ATTR_ENCODING, encoding), 520 RECV_ATTR_INT(MAIL_ATTR_SENDOPTS, &sendopts), 521 RECV_ATTR_STR(MAIL_ATTR_SENDER, sender), 522 RECV_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid), 523 RECV_ATTR_INT(MAIL_ATTR_DSN_RET, &dsn_ret), 524 RECV_ATTR_FUNC(rcpb_scan, (void *) rcpt_buf), 525 RECV_ATTR_FUNC(dsb_scan, (void *) dsn_buf), 526 ATTR_TYPE_END) != 10) { 527 msg_warn("malformed request"); 528 return (-1); 529 } 530 531 /* 532 * Sanitize input. 533 */ 534 if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) { 535 msg_warn("wrong service name \"%s\" for one-recipient bouncing", 536 service_name); 537 return (-1); 538 } 539 if (mail_queue_name_ok(STR(queue_name)) == 0) { 540 msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); 541 return (-1); 542 } 543 if (mail_queue_id_ok(STR(queue_id)) == 0) { 544 msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); 545 return (-1); 546 } 547 VS_NEUTER(encoding); 548 VS_NEUTER(sender); 549 VS_NEUTER(dsn_envid); 550 VS_NEUTER(rcpt_buf->address); 551 VS_NEUTER(rcpt_buf->orig_addr); 552 VS_NEUTER(rcpt_buf->dsn_orcpt); 553 VS_NEUTER(dsn_buf->status); 554 VS_NEUTER(dsn_buf->action); 555 VS_NEUTER(dsn_buf->reason); 556 VS_NEUTER(dsn_buf->dtype); 557 VS_NEUTER(dsn_buf->dtext); 558 VS_NEUTER(dsn_buf->mtype); 559 VS_NEUTER(dsn_buf->mname); 560 (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); 561 (void) DSN_FROM_DSN_BUF(dsn_buf); 562 563 /* 564 * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and 565 * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and 566 * RECIPIENT_FROM_RCPT_BUF(). 567 */ 568 if (msg_verbose) 569 msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sendopts=%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", 570 myname, flags, STR(queue_name), STR(queue_id), 571 STR(encoding), sendopts, STR(sender), STR(dsn_envid), 572 dsn_ret, STR(rcpt_buf->orig_addr), STR(rcpt_buf->address), 573 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt), 574 rcpt_buf->dsn_notify, STR(dsn_buf->status), 575 STR(dsn_buf->action), STR(dsn_buf->reason)); 576 577 /* 578 * Handle REQUIRETLS etc. matters. 579 */ 580 if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL)) 581 edit_notification_properties(&sendopts, &dsn_ret); 582 583 /* 584 * Execute the request. 585 */ 586 return (bounce_one_service(flags, STR(queue_name), STR(queue_id), 587 STR(encoding), sendopts, STR(sender), 588 STR(dsn_envid), dsn_ret, rcpt_buf, 589 dsn_buf, bounce_templates)); 590 } 591 592 /* bounce_service - parse bounce command type and delegate */ 593 594 static void bounce_service(VSTREAM *client, char *service_name, char **argv) 595 { 596 int command; 597 int status; 598 599 /* 600 * Sanity check. This service takes no command-line arguments. The 601 * service name should be usable as a subdirectory name. 602 */ 603 if (argv[0]) 604 msg_fatal("unexpected command-line argument: %s", argv[0]); 605 if (mail_queue_name_ok(service_name) == 0) 606 msg_fatal("malformed service name: %s", service_name); 607 608 /* 609 * Announce the protocol. 610 */ 611 attr_print(client, ATTR_FLAG_NONE, 612 SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_BOUNCE), 613 ATTR_TYPE_END); 614 (void) vstream_fflush(client); 615 616 /* 617 * Read and validate the first parameter of the client request. Let the 618 * request-specific protocol routines take care of the remainder. 619 */ 620 if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, 621 RECV_ATTR_INT(MAIL_ATTR_NREQ, &command), 0) != 1) { 622 msg_warn("malformed request"); 623 status = -1; 624 } else if (command == BOUNCE_CMD_VERP) { 625 status = bounce_verp_proto(service_name, client); 626 } else if (command == BOUNCE_CMD_FLUSH) { 627 status = bounce_notify_proto(service_name, client, 628 bounce_notify_service); 629 } else if (command == BOUNCE_CMD_WARN) { 630 status = bounce_notify_proto(service_name, client, 631 bounce_warn_service); 632 } else if (command == BOUNCE_CMD_TRACE) { 633 status = bounce_notify_proto(service_name, client, 634 bounce_trace_service); 635 } else if (command == BOUNCE_CMD_APPEND) { 636 status = bounce_append_proto(service_name, client); 637 } else if (command == BOUNCE_CMD_ONE) { 638 status = bounce_one_proto(service_name, client); 639 } else { 640 msg_warn("unknown command: %d", command); 641 status = -1; 642 } 643 644 /* 645 * When the request has completed, send the completion status to the 646 * client. 647 */ 648 attr_print(client, ATTR_FLAG_NONE, 649 SEND_ATTR_INT(MAIL_ATTR_STATUS, status), 650 ATTR_TYPE_END); 651 vstream_fflush(client); 652 653 /* 654 * When a cleanup trap was set, delete the log file in case of error. 655 * This includes errors while sending the completion status to the 656 * client. 657 */ 658 if (bounce_cleanup_path) { 659 if (status || vstream_ferror(client)) 660 bounce_cleanup_log(); 661 bounce_cleanup_unregister(); 662 } 663 } 664 665 static void load_helper(VSTREAM *stream, void *context) 666 { 667 BOUNCE_TEMPLATES *templates = (BOUNCE_TEMPLATES *) context; 668 669 bounce_templates_load(stream, templates); 670 } 671 672 /* pre_jail_init - pre-jail initialization */ 673 674 static void pre_jail_init(char *unused_name, char **unused_argv) 675 { 676 677 /* 678 * Bundle up a bunch of bounce template information. 679 */ 680 bounce_templates = bounce_templates_create(); 681 682 /* 683 * Load the alternate message files (if specified) before entering the 684 * chroot jail. 685 */ 686 if (*var_bounce_tmpl) 687 load_file(var_bounce_tmpl, load_helper, (void *) bounce_templates); 688 } 689 690 /* post_jail_init - initialize after entering chroot jail */ 691 692 static void post_jail_init(char *service_name, char **unused_argv) 693 { 694 bounce_hfrom_format = hfrom_format_parse(VAR_HFROM_FORMAT, var_hfrom_format); 695 696 /* 697 * Special case: dump bounce templates. This is not part of the master(5) 698 * public interface. This internal interface is used by the postconf 699 * command. It was implemented before bounce templates were isolated into 700 * modules that could have been called directly. 701 */ 702 if (strcmp(service_name, "dump_templates") == 0) { 703 bounce_templates_dump(VSTREAM_OUT, bounce_templates); 704 vstream_fflush(VSTREAM_OUT); 705 exit(0); 706 } 707 if (strcmp(service_name, "expand_templates") == 0) { 708 bounce_templates_expand(VSTREAM_OUT, bounce_templates); 709 vstream_fflush(VSTREAM_OUT); 710 exit(0); 711 } 712 713 /* 714 * Initialize. We're single threaded so we can reuse some memory upon 715 * successive requests. 716 */ 717 queue_id = vstring_alloc(10); 718 queue_name = vstring_alloc(10); 719 rcpt_buf = rcpb_create(); 720 encoding = vstring_alloc(10); 721 sender = vstring_alloc(10); 722 dsn_envid = vstring_alloc(10); 723 verp_delims = vstring_alloc(10); 724 dsn_buf = dsb_create(); 725 } 726 727 MAIL_VERSION_STAMP_DECLARE; 728 729 /* main - the main program */ 730 731 int main(int argc, char **argv) 732 { 733 static const CONFIG_INT_TABLE int_table[] = { 734 VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0, 735 0, 736 }; 737 static const CONFIG_TIME_TABLE time_table[] = { 738 VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000, 739 VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0, 740 0, 741 }; 742 static const CONFIG_STR_TABLE str_table[] = { 743 VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, 744 VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0, 745 VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0, 746 VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0, 747 VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0, 748 VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0, 749 0, 750 }; 751 static const CONFIG_NBOOL_TABLE nbool_table[] = { 752 VAR_THREADED_BOUNCE, DEF_THREADED_BOUNCE, &var_threaded_bounce, 753 VAR_REQTLS_REDACT_DSN, DEF_REQTLS_REDACT_DSN, &var_reqtls_redact_dsn, 754 0, 755 }; 756 757 /* 758 * Fingerprint executables and core dumps. 759 */ 760 MAIL_VERSION_STAMP_ALLOCATE; 761 762 /* 763 * Pass control to the single-threaded service skeleton. 764 */ 765 single_server_main(argc, argv, bounce_service, 766 CA_MAIL_SERVER_INT_TABLE(int_table), 767 CA_MAIL_SERVER_STR_TABLE(str_table), 768 CA_MAIL_SERVER_TIME_TABLE(time_table), 769 CA_MAIL_SERVER_NBOOL_TABLE(nbool_table), 770 CA_MAIL_SERVER_PRE_INIT(pre_jail_init), 771 CA_MAIL_SERVER_POST_INIT(post_jail_init), 772 CA_MAIL_SERVER_UNLIMITED, 773 0); 774 } 775