From: Wietse Venema Date: Thu, 12 Jan 2006 05:00:00 +0000 (-0500) Subject: postfix-2.3-20060112 X-Git-Tag: v2.3-RC1~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a934ab940e9c88458f95ace79535047f9b57541c;p=thirdparty%2Fpostfix.git postfix-2.3-20060112 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 772688817..1d5e8ce8e 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -19,6 +19,7 @@ -TBOUNCE_INFO -TBOUNCE_LOG -TBOUNCE_LOG_DSN_BUF +-TBOUNCE_LOG_FORGE -TBOUNCE_LOG_RCPT_BUF -TBOUNCE_STAT -TBOUNCE_TEMPLATE @@ -91,7 +92,7 @@ -TDSN -TDSN_BUF -TDSN_SPLIT --TDSN_VAR +-TDSN_STAT -TEXPAND_ATTR -TFILE -TFORWARD_INFO @@ -169,7 +170,6 @@ -TRCPT_BUF -TRECIPIENT -TRECIPIENT_LIST --TRECIPIENT_VAR -TREC_TYPE_NAME -TRESOLVE_REPLY -TRESPONSE diff --git a/postfix/HISTORY b/postfix/HISTORY index 87355d1e6..8a4f3200f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -11692,6 +11692,8 @@ Apologies for any names omitted. 20051229 + The following workaround was removed 20060103. + Workaround: when mail is still queued after 3000 seconds, the SMTP client no longer pipelines the DOT+QUIT commands. The 20050929 paranoia about malformed server replies @@ -11727,8 +11729,108 @@ Apologies for any names omitted. The administrator still has the option to turn off pipelining by hand if loss of mail is a concern. +20060103 + + Bugfix: the 20051217 fix (when a SASL client password is + found, defer delivery when no server-announced mechanism + survives the smtp_sasl_mechanism_filter) did the mechanism + test too early, so that it could trip up with deliveries + to servers that we don't have a SASL password for. Files: + smtp/smtp_sasl_proto.c, smtp/smtp_proto.c. + +20060104 + + Safety: new "smtp_cname_overrides_servername" parameter. + The default value ("no") is NOT backwards compatible. This + avoids surprises with the hostname that is used for logging, + SASL password lookup, TLS policy decisions, or TLS certificate + verification. The change makes the 20051221 behavior more + configurable. Files: smtp/smtp_addr.c, smtp/smtp_connect.c, + proto/postconf.proto. + +20060105 + + Cleanup: removed the unused DSN "code" attribute; removed + surrogate SMTP replies for errors that were not reported + by a remote SMTP server, making several DSN-related functions + and macros redundant; cleaned up some bizarre code for DSN + attribute memory management in the SMTP client. + +20060106 + + Cleanup: eliminated the global smtp_errno variable, which + had become redundant after introducing DSN support. Files: + smtp/smtp_addr.c, smtp/smtp_connect.c. + +20060107 + + Cleanup: removed more bizarre code for DSN attribute memory + management in the queue manager, bounce server, and in + delivery agents. + +20060109 + + Bugfix: smtp_sasl_tls_opts was unimplemented. File: + smtp/smtp_sasl_proto.c. + + Cleanup: more bounce logfile code cleanup. Files: + global/bounce_log.c, bounce/bounce_notify_util.c, + bounce/bounce.c, bounce/bounce_notify_verp.c, + bounce/bounce_one_service.c, showq/showq.c + +20060110 + + Cleanup: more bounce logfile code cleanup. Files: + global/bounce_log.c, bounce/bounce_notify_util.c. + + Bugfix: the VERP bouncer never handled the case of a missing + bounce logfile. Found while doing more logfile code cleanup. + File: bounce/bounce_notify_verp.c. + + Feature: smtp_sasl_tls_verified_security_options for + connections where the server certificate passed verification. + The default value is $smtp_sasl_tls_security_options, which + in turn defaults to $smtp_sasl_security_options. + +20060111 + + Optimization: mystrdup() and mystrndup() now return a pointer + to a fixed read-only memory location instead of allocating + memory for zero-length null-terminated strings. This saves + lots of memory for unused recipient attributes. If this + change causes problems (for example, you have an ancient + sscanf() implementation that writes to its input) then + compile Postfix with -DNO_SHARED_EMPTY_STRINGS. + + Cleanup: eliminated null pointer members in DSN structures. + Instead we now use the optimized mystrdup() for empty + strings. For safety sake we keep the tests for null pointers + in input, but we always produce empty strings on output. + Files: global/dsn.c, global/dsn.h, global/dsn_buf.h, + global/dsn_print.c. + + Cleanup: eliminated ad-hoc code for passing recipients in + the queue manager delivery request protocol. Postfix now + uses proper object activation/passivation instead. Files: + *qmgr/qmgr_deliver.c, global/deliver_request.c, + global/deliver_pass.c. + +20060112 + + Feature: to simplify debugging the bounce server logs the + old and new queue ID when notifying the sender or postmaster. + Files: global/post_mail.c, bounce/bounce_notify_service.c, + bounce/bounce_one_service.c, bounce/bounce_notify_verp.c, + bounce/bounce_warn_service.c, bounce/bounce_trace_service.c. + Open problems: + Privacy: remove local command/pathname details from remote + delivery status reports, and log them via local msg_warn(). + + Remove defer(8) and trace(8) references and man pages. These + are services not program names. + "postsuper -r" no longer resets the message arrival time, because pickup(8) no longer overrides queue file time stamp information. This can be a problem when mail "on hold" is diff --git a/postfix/README_FILES/OVERVIEW b/postfix/README_FILES/OVERVIEW index 1d9ae180f..c9d40269f 100644 --- a/postfix/README_FILES/OVERVIEW +++ b/postfix/README_FILES/OVERVIEW @@ -210,11 +210,12 @@ queues. Network -> smtpd(8) <-> anvil(8) - * The bounce(8), defer(8) and trace(8) servers each maintain their own queue - directory trees with per-message logfiles. This information is used to send - delivery or non-delivery notifications to the sender. + * The bounce(8) server implements the bounce, defer and trace services, which + maintain separate directory trees with per-message logfiles. This + information is used to send delivery or non-delivery notifications to the + sender. - The trace(8) service implements support for the Postfix "sendmail -bv" and + The trace service implements support for the Postfix "sendmail -bv" and "sendmail -v" commands which produce reports about how Postfix delivers mail, and is available with Postfix version 2.1 and later. See DEBUG_README for examples. @@ -227,8 +228,8 @@ queues. | v v (Non-) bounce(8) Queue id, - delivery <- defer(8) <- recipient, - notice trace(8) status + delivery <- defer <- recipient, + notice trace status ^ | | v diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index fe5033314..96233b96b 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -17,6 +17,23 @@ Incompatibility with Postfix 2.1 and earlier If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2 before proceeding. +Incompatibility with snapshot 20060112 +====================================== + +The queue manager delivery request protocol has changed. You must +reload Postfix when upgrading. If you omit this step, delivery +agents complain with "warning: unexpected attribute original_recipient" +and mail will not be delivered. + +The Postfix SMTP/LMTP client by default no longer allows DNS CNAME +records to override the server hostname that is used for logging, +SASL password lookup, TLS policy selection and TLS server certificate +verification. Specify "smtp_cname_overrides_servername = no" to get +the old behavior. + +Postfix DSN reports no longer make up their own surrogate SMTP +replies for errors that were not reported by a remote SMTP server. + Incompatibility with snapshot 20060103 ====================================== diff --git a/postfix/html/bounce.5.html b/postfix/html/bounce.5.html index b4900f166..104247f9e 100644 --- a/postfix/html/bounce.5.html +++ b/postfix/html/bounce.5.html @@ -48,10 +48,10 @@ BOUNCE(5) BOUNCE(5) appear in the delayed mail notification text. Once the result is satisfactory, copy the template to the - Postfix configuration directory and specify in main.cf + Postfix configuration directory and specify in main.cf something like: - /etc/postfix/main.cf: + /etc/postfix/main.cf: bounce_template_file = /etc/postfix/bounce.cf TEMPLATE FILE FORMAT @@ -68,33 +68,41 @@ BOUNCE(5) BOUNCE(5) with the shell or with Perl (template_name = <<'EOF'). Here is an example: - # The failure template is used for undeliverable mail. + # The failure template is used for undeliverable mail. - failure_template = <<EOF - Charset: us-ascii - From: MAILER-DAEMON (Mail Delivery System) - Subject: Undelivered Mail Returned to Sender - Postmaster-Subject: Postmaster Copy: Undelivered Mail + failure_template = <<EOF + Charset: us-ascii + From: MAILER-DAEMON (Mail Delivery System) + Subject: Undelivered Mail Returned to Sender + Postmaster-Subject: Postmaster Copy: Undelivered Mail - This is the $mail_name program at host $myhostname. + This is the $mail_name program at host $myhostname. - I'm sorry to have to inform you that your message could not - be delivered to one or more recipients. It's attached below. + I'm sorry to have to inform you that your message could not + be delivered to one or more recipients. It's attached below. - For further assistance, please send mail to <postmaster> + For further assistance, please send mail to <postmaster> - If you do so, please include this problem report. You can - delete your own text from the attached returned message. + If you do so, please include this problem report. You can + delete your own text from the attached returned message. - The $mail_name program - EOF + The $mail_name program + EOF - No special meaning is given to the backslash character or - to leading whitespace; these are always taken literally. + The usage and specification of bounce templates is subject + to the following restrictions: - Outside the << context, lines beginning with "#" are - ignored, as are empty lines, and lines consisting of - whitespace only. + o No special meaning is given to the backslash char- + acter or to leading whitespace; these are always + taken literally. + + o Inside the << context, the "$" character is spe- + cial. To produce a "$" character as output, specify + "$$". + + o Outside the << context, lines beginning with "#" + are ignored, as are empty lines, and lines consist- + ing of whitespace only. Examples of all templates can be found in the file bounce.cf.default in the Postfix configuration directory. @@ -137,7 +145,7 @@ BOUNCE(5) BOUNCE(5) o Template message headers must not span multiple lines. - o Template message headers must not contain main.cf + o Template message headers must not contain main.cf $parameters. o Template message headers must contain ASCII charac- @@ -146,8 +154,8 @@ BOUNCE(5) BOUNCE(5) TEMPLATE MESSAGE TEXT FORMAT The second portion of a bounce template consists of mes- sage text. As the above example shows, template message - text may contain main.cf $parameters. Besides the parame- - ters that are defined in main.cf, the following parameters + text may contain main.cf $parameters. Besides the parame- + ters that are defined in main.cf, the following parameters are treated specially depending on the suffix that is appended to their name. diff --git a/postfix/html/bounce.8.html b/postfix/html/bounce.8.html index b63647871..da749a991 100644 --- a/postfix/html/bounce.8.html +++ b/postfix/html/bounce.8.html @@ -17,7 +17,7 @@ BOUNCE(8) BOUNCE(8) delivery status information. Each log file is named after the queue file that it corresponds to, and is kept in a queue subdirectory named after the service name in the - master.cf file (either bounce, defer or trace). This pro- + master.cf file (either bounce, defer or trace). This pro- gram expects to be run from the master(8) process manager. The bounce(8) daemon processes two types of service @@ -52,7 +52,7 @@ BOUNCE(8) BOUNCE(8) Problems and transactions are logged to syslogd(8). CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically, as + Changes to main.cf are picked up automatically, as bounce(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -82,8 +82,8 @@ BOUNCE(8) BOUNCE(8) sage templates. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/discard.8.html b/postfix/html/discard.8.html index 01fd6d459..2fb77c2e1 100644 --- a/postfix/html/discard.8.html +++ b/postfix/html/discard.8.html @@ -47,7 +47,7 @@ DISCARD(8) DISCARD(8) ble. CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically as dis- + Changes to main.cf are picked up automatically as dis- card(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -55,8 +55,8 @@ DISCARD(8) DISCARD(8) postconf(5) for more details including examples. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/error.8.html b/postfix/html/error.8.html index 338b6c9fd..5cf408609 100644 --- a/postfix/html/error.8.html +++ b/postfix/html/error.8.html @@ -47,7 +47,7 @@ ERROR(8) ERROR(8) ble. CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically as error(8) + Changes to main.cf are picked up automatically as error(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -65,8 +65,8 @@ ERROR(8) ERROR(8) mail that Postfix did not receive. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/pipe.8.html b/postfix/html/pipe.8.html index faa3c00f4..8eda4d5f3 100644 --- a/postfix/html/pipe.8.html +++ b/postfix/html/pipe.8.html @@ -32,19 +32,19 @@ PIPE(8) PIPE(8) SINGLE-RECIPIENT DELIVERY Some external commands cannot handle more than one recipi- ent per delivery request. Examples of such transports are - pagers, fax machines, and so on. + pagers or fax machines. To prevent Postfix from sending multiple recipients per delivery request, specify transport_destination_recipient_limit = 1 - in the Postfix main.cf file, where transport is the name - in the first column of the Postfix master.cf entry for the + in the Postfix main.cf file, where transport is the name + in the first column of the Postfix master.cf entry for the pipe-based delivery transport. COMMAND ATTRIBUTE SYNTAX - The external command attributes are given in the master.cf + The external command attributes are given in the master.cf file at the end of a service definition. The syntax is as follows: @@ -330,7 +330,7 @@ PIPE(8) PIPE(8) fore security sensitive. CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically as pipe(8) + Changes to main.cf are picked up automatically as pipe(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -360,8 +360,8 @@ PIPE(8) PIPE(8) MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 44758e17e..6a8686f24 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -3091,6 +3091,17 @@ programs.

+ + +
lmtp_cname_overrides_servername +(default: yes)
+ +

The LMTP-specific version of the smtp_cname_overrides_servername +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_connect_timeout @@ -3582,7 +3593,7 @@ Example:
lmtp_sasl_tls_security_options -(default: $var_lmtp_sasl_opts)
+(default: $lmtp_sasl_security_options)

The LMTP-specific version of the smtp_sasl_tls_security_options configuration parameter. See there for details.

@@ -3590,6 +3601,18 @@ configuration parameter. See there for details.

This feature is available in Postfix 2.3 and later.

+
+ +
lmtp_sasl_tls_verified_security_options +(default: $lmtp_sasl_tls_security_options)
+ +

The LMTP-specific version of the +smtp_sasl_tls_verified_security_options configuration parameter. +See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_sasl_type @@ -6399,6 +6422,22 @@ IP hosting, but can be a problem on multi-homed firewalls. See the but this form is not recommended here.

+ + +
smtp_cname_overrides_servername +(default: version dependent)
+ +

Allow DNS CNAME records to override the servername that the +Postfix SMTP client uses for logging, SASL password lookup, TLS +policy decisions, or TLS certificate verification. The value "no" +hardens Postfix smtp_tls_per_site hostname-based policies against +false hostname information in DNS CNAME records, and makes SASL +password file lookups more predictable. This is the default setting +as of Postfix 2.3.

+ +

This feature is available in Postfix 2.2.9 and later.

+ +
smtp_connect_timeout @@ -7192,6 +7231,18 @@ Example: client uses for TLS encrypted SMTP sessions.

+ + +
smtp_sasl_tls_verified_security_options +(default: $smtp_sasl_tls_security_options)
+ +

The SASL authentication security options that the Postfix SMTP +client uses for TLS encrypted SMTP sessions with a verified server +certificate.

+ +

This feature is available in Postfix 2.3 and later.

+ +
smtp_sasl_type @@ -7527,12 +7578,47 @@ server certificate was issued by a trusted CA. -

Special hint for enforcement mode: since no secure DNS lookup -mechanism is available, the recommended setup is: specify local -transport(5) table entries for sensitive domains with explicit -smtp:[mailhost] destinations (since you can assure security of this -table unlike DNS), then specify MUST for these mail hosts in the -smtp_tls_per_site table.

+

Special hints for enforcement mode: since no secure DNS lookup +mechanism is available, the recommended setup is:

+ +
+ +
Postfix 2.2.9
+ +
    + +
  • Specify "smtp_cname_overrides_servername = no". This avoids +false hostname information in DNS CNAME records that could bypass +a hostname-based TLS usage policy. + +
  • Specify local transport(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy. + +
  • Specify MUST for these mail hosts in the smtp_tls_per_site +table. + +
+ +
Postfix < 2.2.9
+ +
    + +
  • Specify local transport(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy, but cannot avoid false hostname +information in DNS CNAME records. + +
  • Specify MUST for these mail hosts in the smtp_tls_per_site +table. + +
+ +
+ +

diff --git a/postfix/html/showq.8.html b/postfix/html/showq.8.html index 2638a0f60..5cb1f446f 100644 --- a/postfix/html/showq.8.html +++ b/postfix/html/showq.8.html @@ -40,7 +40,7 @@ SHOWQ(8) SHOWQ(8) the maildrop directory. CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically as showq(8) + Changes to main.cf are picked up automatically as showq(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -48,8 +48,8 @@ SHOWQ(8) SHOWQ(8) postconf(5) for more details including examples. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 9c0b5d460..54aef3151 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -105,7 +105,6 @@ SMTP(8) SMTP(8) RFC 1652 (8bit-MIME transport) RFC 1870 (Message Size Declaration) RFC 2033 (LMTP protocol) - RFC 2034 (Enhanced Status Codes) RFC 2045 (MIME: Format of Internet Message Bodies) RFC 2046 (MIME: Media Types) RFC 2554 (AUTH command) @@ -220,18 +219,26 @@ SMTP(8) SMTP(8) locally valid address into a globally valid address when sending mail across the Internet. + Available in Postfix version 2.2.9 and later: + + smtp_cname_overrides_servername (version dependent) + Allow DNS CNAME records to override the servername + that the Postfix SMTP client uses for logging, SASL + password lookup, TLS policy decisions, or TLS cer- + tificate verification. + Available in Postfix version 2.3 and later: lmtp_discard_lhlo_keyword_address_maps (empty) - Lookup tables, indexed by the remote LMTP server - address, with case insensitive lists of LHLO key- - words (pipelining, starttls, auth, etc.) that the + Lookup tables, indexed by the remote LMTP server + address, with case insensitive lists of LHLO key- + words (pipelining, starttls, auth, etc.) that the LMTP client will ignore in the LHLO response from a remote LMTP server. lmtp_discard_lhlo_keywords ($myhostname) - A case insensitive list of LHLO keywords (pipelin- - ing, starttls, auth, etc.) that the LMTP client + A case insensitive list of LHLO keywords (pipelin- + ing, starttls, auth, etc.) that the LMTP client will ignore in the LHLO response from a remote LMTP server. @@ -239,7 +246,7 @@ SMTP(8) SMTP(8) Available in Postfix version 2.0 and later: disable_mime_output_conversion (no) - Disable the conversion of 8BITMIME format to 7BIT + Disable the conversion of 8BITMIME format to 7BIT format. mime_boundary_length_limit (2048) @@ -254,132 +261,132 @@ SMTP(8) SMTP(8) Available in Postfix version 2.1 and later: smtp_send_xforward_command (no) - Send the non-standard XFORWARD command when the - Postfix SMTP server EHLO response announces XFOR- + Send the non-standard XFORWARD command when the + Postfix SMTP server EHLO response announces XFOR- WARD support. SASL AUTHENTICATION CONTROLS smtp_sasl_auth_enable (no) - Enable SASL authentication in the Postfix SMTP + Enable SASL authentication in the Postfix SMTP client. smtp_sasl_password_maps (empty) - Optional SMTP client lookup tables with one user- - name:password entry per remote hostname or domain, + Optional SMTP client lookup tables with one user- + name:password entry per remote hostname or domain, or sender address when sender-dependent authentica- tion is enabled. smtp_sasl_security_options (noplaintext, noanonymous) - SASL security options; as of Postfix 2.3 the list - of available features depends on the SASL client - implementation that is selected with + SASL security options; as of Postfix 2.3 the list + of available features depends on the SASL client + implementation that is selected with smtp_sasl_type. Available in Postfix version 2.2 and later: smtp_sasl_mechanism_filter (empty) - If non-empty, a Postfix SMTP client filter for the - remote SMTP server's list of offered SASL mecha- + If non-empty, a Postfix SMTP client filter for the + remote SMTP server's list of offered SASL mecha- nisms. Available in Postfix version 2.3 and later: smtp_sender_dependent_authentication (no) - Enable sender-dependent authentication in the SMTP - client; this is available only with SASL authenti- - cation, and disables SMTP connection caching to - ensure that mail from different senders will use + Enable sender-dependent authentication in the SMTP + client; this is available only with SASL authenti- + cation, and disables SMTP connection caching to + ensure that mail from different senders will use the appropriate credentials. smtp_sasl_path (empty) - Implementation-specific information that is passed - through to the SASL plug-in implementation that is + Implementation-specific information that is passed + through to the SASL plug-in implementation that is selected with smtp_sasl_type. smtp_sasl_type (cyrus) - The SASL plug-in type that the Postfix SMTP client + The SASL plug-in type that the Postfix SMTP client should use for authentication. STARTTLS SUPPORT CONTROLS - Detailed information about STARTTLS configuration may be + Detailed information about STARTTLS configuration may be found in the TLS_README document. smtp_use_tls (no) - Opportunistic mode: use TLS when a remote SMTP - server announces STARTTLS support, otherwise send + Opportunistic mode: use TLS when a remote SMTP + server announces STARTTLS support, otherwise send the mail in the clear. smtp_enforce_tls (no) - Enforcement mode: require that remote SMTP servers - use TLS encryption, and never send mail in the + Enforcement mode: require that remote SMTP servers + use TLS encryption, and never send mail in the clear. smtp_sasl_tls_security_options ($smtp_sasl_secu- rity_options) - The SASL authentication security options that the - Postfix SMTP client uses for TLS encrypted SMTP + The SASL authentication security options that the + Postfix SMTP client uses for TLS encrypted SMTP sessions. smtp_starttls_timeout (300s) - Time limit for Postfix SMTP client write and read - operations during TLS startup and shutdown hand- + Time limit for Postfix SMTP client write and read + operations during TLS startup and shutdown hand- shake procedures. smtp_tls_CAfile (empty) - The file with the certificate of the certification - authority (CA) that issued the Postfix SMTP client + The file with the certificate of the certification + authority (CA) that issued the Postfix SMTP client certificate. smtp_tls_CApath (empty) - Directory with PEM format certificate authority - certificates that the Postfix SMTP client uses to + Directory with PEM format certificate authority + certificates that the Postfix SMTP client uses to verify a remote SMTP server certificate. smtp_tls_cert_file (empty) - File with the Postfix SMTP client RSA certificate + File with the Postfix SMTP client RSA certificate in PEM format. smtp_tls_cipherlist (empty) - Controls the Postfix SMTP client TLS cipher selec- + Controls the Postfix SMTP client TLS cipher selec- tion scheme. smtp_tls_dcert_file (empty) - File with the Postfix SMTP client DSA certificate + File with the Postfix SMTP client DSA certificate in PEM format. smtp_tls_dkey_file ($smtp_tls_dcert_file) - File with the Postfix SMTP client DSA private key + File with the Postfix SMTP client DSA private key in PEM format. smtp_tls_enforce_peername (yes) - When TLS encryption is enforced, require that the + When TLS encryption is enforced, require that the remote SMTP server hostname matches the information in the remote SMTP server certificate. smtp_tls_key_file ($smtp_tls_cert_file) - File with the Postfix SMTP client RSA private key + File with the Postfix SMTP client RSA private key in PEM format. smtp_tls_loglevel (0) - Enable additional Postfix SMTP client logging of + Enable additional Postfix SMTP client logging of TLS activity. smtp_tls_note_starttls_offer (no) - Log the hostname of a remote SMTP server that - offers STARTTLS, when TLS is not already enabled + Log the hostname of a remote SMTP server that + offers STARTTLS, when TLS is not already enabled for that server. smtp_tls_per_site (empty) Optional lookup tables with the Postfix SMTP client - TLS usage policy by next-hop domain name and by + TLS usage policy by next-hop domain name and by remote SMTP server hostname. smtp_tls_scert_verifydepth (5) - The verification depth for remote SMTP server cer- + The verification depth for remote SMTP server cer- tificates. smtp_tls_session_cache_database (empty) - Name of the file containing the optional Postfix + Name of the file containing the optional Postfix SMTP client TLS session cache. smtp_tls_session_cache_timeout (3600s) @@ -387,35 +394,43 @@ SMTP(8) SMTP(8) sion cache information. tls_daemon_random_bytes (32) - The number of pseudo-random bytes that an smtp(8) - or smtpd(8) process requests from the tlsmgr(8) - server in order to seed its internal pseudo random + The number of pseudo-random bytes that an smtp(8) + or smtpd(8) process requests from the tlsmgr(8) + server in order to seed its internal pseudo random number generator (PRNG). + Available in Postfix version 2.3 and later: + + smtp_sasl_tls_verified_security_options + ($smtp_sasl_tls_security_options) + The SASL authentication security options that the + Postfix SMTP client uses for TLS encrypted SMTP + sessions with a verified server certificate. + RESOURCE AND RATE CONTROLS smtp_destination_concurrency_limit ($default_destina- tion_concurrency_limit) - The maximal number of parallel deliveries to the - same destination via the smtp message delivery + The maximal number of parallel deliveries to the + same destination via the smtp message delivery transport. smtp_destination_recipient_limit ($default_destina- tion_recipient_limit) - The maximal number of recipients per delivery via + The maximal number of recipients per delivery via the smtp message delivery transport. smtp_connect_timeout (30s) - The SMTP client time limit for completing a TCP + The SMTP client time limit for completing a TCP connection, or zero (use the operating system built-in time limit). smtp_helo_timeout (300s) - The SMTP client time limit for sending the HELO or - EHLO command, and for receiving the initial server + The SMTP client time limit for sending the HELO or + EHLO command, and for receiving the initial server response. lmtp_lhlo_timeout (300s) - The LMTP client time limit for sending the LHLO + The LMTP client time limit for sending the LHLO command, and for receiving the initial server response. @@ -424,30 +439,30 @@ SMTP(8) SMTP(8) command, and for receiving the server response. smtp_mail_timeout (300s) - The SMTP client time limit for sending the MAIL - FROM command, and for receiving the server + The SMTP client time limit for sending the MAIL + FROM command, and for receiving the server response. smtp_rcpt_timeout (300s) - The SMTP client time limit for sending the SMTP - RCPT TO command, and for receiving the server + The SMTP client time limit for sending the SMTP + RCPT TO command, and for receiving the server response. smtp_data_init_timeout (120s) - The SMTP client time limit for sending the SMTP - DATA command, and for receiving the server + The SMTP client time limit for sending the SMTP + DATA command, and for receiving the server response. smtp_data_xfer_timeout (180s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP ".", and for receiving the server response. smtp_quit_timeout (300s) - The SMTP client time limit for sending the QUIT + The SMTP client time limit for sending the QUIT command, and for receiving the server response. Available in Postfix version 2.1 and later: @@ -458,12 +473,12 @@ SMTP(8) SMTP(8) lookups, or zero (no limit). smtp_mx_session_limit (2) - The maximal number of SMTP sessions per delivery - request before giving up or delivering to a fall- + The maximal number of SMTP sessions per delivery + request before giving up or delivering to a fall- back relay host, or zero (no limit). smtp_rset_timeout (20s) - The SMTP client time limit for sending the RSET + The SMTP client time limit for sending the RSET command, and for receiving the server response. Available in Postfix version 2.2 and earlier: @@ -475,11 +490,11 @@ SMTP(8) SMTP(8) Available in Postfix version 2.2 and later: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - Temporarily enable SMTP connection caching while a + Temporarily enable SMTP connection caching while a destination has a high volume of mail in the active queue. @@ -489,57 +504,57 @@ SMTP(8) SMTP(8) smtp_connection_cache_time_limit (2s) When SMTP connection caching is enabled, the amount - of time that an unused SMTP client socket is kept + of time that an unused SMTP client socket is kept open before it is closed. Available in Postfix version 2.3 and later: connection_cache_protocol_timeout (5s) - Time limit for connection cache connect, send or + Time limit for connection cache connect, send or receive operations. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - The increment in verbose logging level when a - remote client or server matches a pattern in the + The increment in verbose logging level when a + remote client or server matches a pattern in the debug_peer_list parameter. debug_peer_list (empty) - Optional list of remote client or server hostname - or network address patterns that cause the verbose - logging level to increase by the amount specified + Optional list of remote client or server hostname + or network address patterns that cause the verbose + logging level to increase by the amount specified in $debug_peer_level. error_notice_recipient (postmaster) - The recipient of postmaster notifications about - mail delivery problems that are caused by policy, + The recipient of postmaster notifications about + mail delivery problems that are caused by policy, resource, software or protocol errors. notify_classes (resource, software) - The list of error classes that are reported to the + The list of error classes that are reported to the postmaster. MISCELLANEOUS CONTROLS best_mx_transport (empty) - Where the Postfix SMTP client should deliver mail + Where the Postfix SMTP client should deliver mail when it detects a "mail loops back to myself" error condition. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - How much time a Postfix daemon process may take to - handle a request before it is terminated by a + How much time a Postfix daemon process may take to + handle a request before it is terminated by a built-in watchdog timer. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal + The maximal number of digits after the decimal point when logging sub-second delay values. disable_dns_lookups (no) - Disable DNS lookups in the Postfix SMTP and LMTP + Disable DNS lookups in the Postfix SMTP and LMTP clients. inet_interfaces (all) @@ -547,7 +562,7 @@ SMTP(8) SMTP(8) tem receives mail on. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) @@ -555,74 +570,74 @@ SMTP(8) SMTP(8) over an internal communication channel. lmtp_tcp_port (24) - The default TCP port that the Postfix LMTP client + The default TCP port that the Postfix LMTP client connects to. max_idle (100s) - The maximum amount of time that an idle Postfix - daemon process waits for the next service request + The maximum amount of time that an idle Postfix + daemon process waits for the next service request before exiting. max_use (100) - The maximal number of connection requests before a + The maximal number of connection requests before a Postfix daemon process terminates. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. proxy_interfaces (empty) The network interface addresses that this mail sys- - tem receives mail on by way of a proxy or network + tem receives mail on by way of a proxy or network address translation unit. smtp_bind_address (empty) An optional numerical network address that the SMTP - client should bind to when making an IPv4 connec- + client should bind to when making an IPv4 connec- tion. smtp_bind_address6 (empty) An optional numerical network address that the SMTP - client should bind to when making an IPv6 connec- + client should bind to when making an IPv6 connec- tion. smtp_helo_name ($myhostname) - The hostname to send in the SMTP EHLO or HELO com- + The hostname to send in the SMTP EHLO or HELO com- mand. lmtp_lhlo_name ($myhostname) The hostname to send in the LMTP LHLO command. smtp_host_lookup (dns) - What mechanisms when the SMTP client uses to look + What mechanisms when the SMTP client uses to look up a host's IP address. smtp_randomize_addresses (yes) - Randomize the order of equal-preference MX host + Randomize the order of equal-preference MX host addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - The mail system name that is prepended to the - process name in syslog records, so that "smtpd" + The mail system name that is prepended to the + process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". Available with Postfix 2.2 and earlier: fallback_relay (empty) - Optional list of relay hosts for SMTP destinations + Optional list of relay hosts for SMTP destinations that can't be found or that are unreachable. Available with Postfix 2.3 and later: smtp_fallback_relay ($fallback_relay) - Optional list of relay hosts for SMTP destinations + Optional list of relay hosts for SMTP destinations that can't be found or that are unreachable. SEE ALSO @@ -640,7 +655,7 @@ SMTP(8) SMTP(8) TLS_README, Postfix STARTTLS howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 4304450d9..371d10f56 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -33,7 +33,7 @@ SMTPD(8) SMTPD(8) The SMTP server implements a variety of policies for con- nection requests, and for parameters given to HELO, ETRN, MAIL FROM, VRFY and RCPT TO commands. They are detailed - below and in the main.cf configuration file. + below and in the main.cf configuration file. SECURITY The SMTP server is moderately security-sensitive. It talks @@ -47,7 +47,6 @@ SMTPD(8) SMTPD(8) RFC 1869 (SMTP service extensions) RFC 1870 (Message Size Declaration) RFC 1985 (ETRN command) - RFC 2034 (Enhanced Status Codes) RFC 2554 (AUTH command) RFC 2821 (SMTP protocol) RFC 2920 (SMTP Pipelining) @@ -63,7 +62,7 @@ SMTPD(8) SMTPD(8) policy violations, and of other trouble. CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically, as + Changes to main.cf are picked up automatically, as smtpd(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -872,8 +871,8 @@ SMTPD(8) SMTPD(8) MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/html/verify.8.html b/postfix/html/verify.8.html index 9f12a5d41..23dce7167 100644 --- a/postfix/html/verify.8.html +++ b/postfix/html/verify.8.html @@ -70,7 +70,7 @@ VERIFY(8) VERIFY(8) This violates a basic Postfix principle. CONFIGURATION PARAMETERS - Changes to main.cf are not picked up automatically, as + Changes to main.cf are not picked up automatically, as verify(8) processes are persistent. Use the command "post- fix reload" after a configuration change. @@ -137,8 +137,8 @@ VERIFY(8) VERIFY(8) MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and - master.cf configuration files. + The default location of the Postfix main.cf and + master.cf configuration files. daemon_timeout (18000s) How much time a Postfix daemon process may take to diff --git a/postfix/man/man5/bounce.5 b/postfix/man/man5/bounce.5 index 4bbe6463a..4d2d591f0 100644 --- a/postfix/man/man5/bounce.5 +++ b/postfix/man/man5/bounce.5 @@ -75,7 +75,7 @@ only. You can change the word EOF, but you can't enclose it in quotes as with the shell or with Perl (\fItemplate_name\fB = <<'EOF'\fR). Here is an example: -.in +2 +.in +4 .nf .na # The failure template is used for undeliverable mail. @@ -99,16 +99,22 @@ delete your own text from the attached returned message. .ti +12 The $mail_name program EOF -.in -2 +.in -4 .ad .fi - +.PP +The usage and specification of bounce templates is +subject to the following restrictions: +.IP \(bu No special meaning is given to the backslash character or to leading whitespace; these are always taken literally. - +.IP \(bu +Inside the << context, the "$" character is special. To +produce a "$" character as output, specify "$$". +.IP \(bu Outside the << context, lines beginning with "#" are ignored, as are empty lines, and lines consisting of whitespace only. - +.PP Examples of all templates can be found in the file \fBbounce.cf.default\fR in the Postfix configuration directory. diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 7e1dece6e..ddde62dd4 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -1666,6 +1666,11 @@ command. Most of these limitations will be removed after Postfix implements a connection cache that is shared among multiple LMTP client programs. +.SH lmtp_cname_overrides_servername (default: yes) +The LMTP-specific version of the smtp_cname_overrides_servername +configuration parameter. See there for details. +.PP +This feature is available in Postfix 2.3 and later. .SH lmtp_connect_timeout (default: 0s) The LMTP client time limit for completing a TCP connection, or zero (use the operating system built-in time limit). When no @@ -1910,11 +1915,17 @@ lmtp_sasl_security_options = noplaintext .fi .ad .ft R -.SH lmtp_sasl_tls_security_options (default: $var_lmtp_sasl_opts) +.SH lmtp_sasl_tls_security_options (default: $lmtp_sasl_security_options) The LMTP-specific version of the smtp_sasl_tls_security_options configuration parameter. See there for details. .PP This feature is available in Postfix 2.3 and later. +.SH lmtp_sasl_tls_verified_security_options (default: $lmtp_sasl_tls_security_options) +The LMTP-specific version of the +smtp_sasl_tls_verified_security_options configuration parameter. +See there for details. +.PP +This feature is available in Postfix 2.3 and later. .SH lmtp_sasl_type (default: cyrus) The SASL plug-in type that the Postfix LMTP client should use for authentication. The available types are listed with the @@ -3569,6 +3580,16 @@ inet_interfaces documentation for more detail. .PP Note 2: address information may be enclosed inside [], but this form is not recommended here. +.SH smtp_cname_overrides_servername (default: version dependent) +Allow DNS CNAME records to override the servername that the +Postfix SMTP client uses for logging, SASL password lookup, TLS +policy decisions, or TLS certificate verification. The value "no" +hardens Postfix smtp_tls_per_site hostname-based policies against +false hostname information in DNS CNAME records, and makes SASL +password file lookups more predictable. This is the default setting +as of Postfix 2.3. +.PP +This feature is available in Postfix 2.2.9 and later. .SH smtp_connect_timeout (default: 30s) The SMTP client time limit for completing a TCP connection, or zero (use the operating system built-in time limit). @@ -4014,6 +4035,12 @@ smtp_sasl_security_options = noplaintext .SH smtp_sasl_tls_security_options (default: $smtp_sasl_security_options) The SASL authentication security options that the Postfix SMTP client uses for TLS encrypted SMTP sessions. +.SH smtp_sasl_tls_verified_security_options (default: $smtp_sasl_tls_security_options) +The SASL authentication security options that the Postfix SMTP +client uses for TLS encrypted SMTP sessions with a verified server +certificate. +.PP +This feature is available in Postfix 2.3 and later. .SH smtp_sasl_type (default: cyrus) The SASL plug-in type that the Postfix SMTP client should use for authentication. The available types are listed with the @@ -4239,12 +4266,32 @@ not require that the remote SMTP server hostname matches the information in the remote SMTP server certificate, or that the server certificate was issued by a trusted CA. .PP -Special hint for enforcement mode: since no secure DNS lookup -mechanism is available, the recommended setup is: specify local -\fBtransport\fR(5) table entries for sensitive domains with explicit -smtp:[mailhost] destinations (since you can assure security of this -table unlike DNS), then specify MUST for these mail hosts in the -smtp_tls_per_site table. +Special hints for enforcement mode: since no secure DNS lookup +mechanism is available, the recommended setup is: +.IP "Postfix 2.2.9" +.IP \(bu +Specify "smtp_cname_overrides_servername = no". This avoids +false hostname information in DNS CNAME records that could bypass +a hostname-based TLS usage policy. +.IP \(bu +Specify local \fBtransport\fR(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy. +.IP \(bu +Specify MUST for these mail hosts in the smtp_tls_per_site +table. +.IP "Postfix < 2.2.9" +.IP \(bu +Specify local \fBtransport\fR(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy, but cannot avoid false hostname +information in DNS CNAME records. +.IP \(bu +Specify MUST for these mail hosts in the smtp_tls_per_site +table. +.PP .SH smtp_tls_scert_verifydepth (default: 5) The verification depth for remote SMTP server certificates. A depth of 1 is sufficient, if the certificate is directly issued by diff --git a/postfix/man/man8/pipe.8 b/postfix/man/man8/pipe.8 index 70da797c9..c3f653824 100644 --- a/postfix/man/man8/pipe.8 +++ b/postfix/man/man8/pipe.8 @@ -32,8 +32,8 @@ appropriate. .ad .fi Some external commands cannot handle more than one recipient -per delivery request. Examples of such transports are pagers, -fax machines, and so on. +per delivery request. Examples of such transports are pagers +or fax machines. To prevent Postfix from sending multiple recipients per delivery request, specify diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 0b3b09396..5c82b4c33 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -99,7 +99,6 @@ RFC 1651 (SMTP service extensions) RFC 1652 (8bit-MIME transport) RFC 1870 (Message Size Declaration) RFC 2033 (LMTP protocol) -RFC 2034 (Enhanced Status Codes) RFC 2045 (MIME: Format of Internet Message Bodies) RFC 2046 (MIME: Media Types) RFC 2554 (AUTH command) @@ -202,6 +201,12 @@ Optional lookup tables that perform address rewriting in the SMTP client, typically to transform a locally valid address into a globally valid address when sending mail across the Internet. .PP +Available in Postfix version 2.2.9 and later: +.IP "\fBsmtp_cname_overrides_servername (version dependent)\fR" +Allow DNS CNAME records to override the servername that the +Postfix SMTP client uses for logging, SASL password lookup, TLS +policy decisions, or TLS certificate verification. +.PP Available in Postfix version 2.3 and later: .IP "\fBlmtp_discard_lhlo_keyword_address_maps (empty)\fR" Lookup tables, indexed by the remote LMTP server address, with @@ -327,6 +332,12 @@ information. The number of pseudo-random bytes that an \fBsmtp\fR(8) or \fBsmtpd\fR(8) process requests from the \fBtlsmgr\fR(8) server in order to seed its internal pseudo random number generator (PRNG). +.PP +Available in Postfix version 2.3 and later: +.IP "\fBsmtp_sasl_tls_verified_security_options ($smtp_sasl_tls_security_options)\fR" +The SASL authentication security options that the Postfix SMTP +client uses for TLS encrypted SMTP sessions with a verified server +certificate. .SH "RESOURCE AND RATE CONTROLS" .na .nf diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 2a8762e81..fdc89d215 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -50,7 +50,6 @@ RFC 1652 (8bit-MIME transport) RFC 1869 (SMTP service extensions) RFC 1870 (Message Size Declaration) RFC 1985 (ETRN command) -RFC 2034 (Enhanced Status Codes) RFC 2554 (AUTH command) RFC 2821 (SMTP protocol) RFC 2920 (SMTP Pipelining) @@ -114,9 +113,9 @@ What SMTP clients Postfix will not offer AUTH support to. Available in Postfix version 2.2 and later: .IP "\fBsmtpd_discard_ehlo_keyword_address_maps (empty)\fR" Lookup tables, indexed by the remote SMTP client address, with -case insensitive lists of EHLO keywords (pipelining, starttls, -auth, etc.) that the SMTP server will not send in the EHLO response -to a remote SMTP client. +case insensitive lists of EHLO keywords (pipelining, starttls, auth, +etc.) that the SMTP server will not send in the EHLO response to a +remote SMTP client. .IP "\fBsmtpd_discard_ehlo_keywords (empty)\fR" A case insensitive list of EHLO keywords (pipelining, starttls, auth, etc.) that the SMTP server will not send in the EHLO response diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index c2c674a05..8af68581f 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -199,6 +199,7 @@ while (<>) { s;\blmtp_discard_lhlo_keyword_address_maps\b;$&;g; s;\blmtp_discard_lhlo_keywords\b;$&;g; s;\blmtp_sasl_tls_security_options\b;$&;g; + s;\blmtp_sasl_tls_verified_security_options\b;$&;g; s;\blmtp_sasl_mechanism_filter\b;$&;g; s;\blmtp_host_lookup\b;$&;g; s;\blmtp_connection_cache_destinations\b;$&;g; @@ -355,6 +356,7 @@ while (<>) { s;\bsmtp_always_send_ehlo\b;$&;g; s;\bsmtp_bind_address\b;$&;g; s;\bsmtp_bind_address6\b;$&;g; + s;\bsmtp_cname_overrides_servername\b;$&;g; s;\bsmtp_connect_timeout\b;$&;g; s;\bsmtp_connection_cache_on_demand\b;$&;g; @@ -499,8 +501,8 @@ while (<>) { s;\bsmtp_enforce_tls\b;$&;g; s;\bsmtp_fallback_relay\b;$&;g; - s;\bsmtp_sasl_tls_security_options\b;$&;g; - s;\bsmtp_sasl_tls_verified_security_options\b;$&;g; + s;\bsmtp_[-]*\n* *[]*sasl_[-]*\n* *[]*tls_[-]*\n* *[]*secu[-]*\n* *[]*rity_options\b;$&;g; + s;\bsmtp_sasl_tls_verified_secu[-]*\n* *[]*rity_options\b;$&;g; s;\bsmtp_sasl_type\b;$&;g; s;\bsmtp_starttls_timeout\b;$&;g; s;\bsmtp_tls_CAfile\b;$&;g; diff --git a/postfix/proto/bounce b/postfix/proto/bounce index f8ffca51b..aaf5fd43f 100644 --- a/postfix/proto/bounce +++ b/postfix/proto/bounce @@ -65,7 +65,7 @@ # it in quotes as with the shell or with Perl (\fItemplate_name\fB # = <<'EOF'\fR). Here is an example: # -# .in +2 +# .in +4 # .nf # .na # # The failure template is used for undeliverable mail. @@ -89,16 +89,22 @@ # .ti +12 # The $mail_name program # EOF -# .in -2 +# .in -4 # .ad # .fi -# +# .PP +# The usage and specification of bounce templates is +# subject to the following restrictions: +# .IP \(bu # No special meaning is given to the backslash character or # to leading whitespace; these are always taken literally. -# +# .IP \(bu +# Inside the << context, the "$" character is special. To +# produce a "$" character as output, specify "$$". +# .IP \(bu # Outside the << context, lines beginning with "#" are ignored, # as are empty lines, and lines consisting of whitespace only. -# +# .PP # Examples of all templates can be found in the file # \fBbounce.cf.default\fR in the Postfix configuration # directory. diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 65e620d06..e4ac74bfb 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -8538,12 +8538,47 @@ server certificate was issued by a trusted CA. -

Special hint for enforcement mode: since no secure DNS lookup -mechanism is available, the recommended setup is: specify local -transport(5) table entries for sensitive domains with explicit -smtp:[mailhost] destinations (since you can assure security of this -table unlike DNS), then specify MUST for these mail hosts in the -smtp_tls_per_site table.

+

Special hints for enforcement mode: since no secure DNS lookup +mechanism is available, the recommended setup is:

+ +
+ +
Postfix 2.2.9
+ +
    + +
  • Specify "smtp_cname_overrides_servername = no". This avoids +false hostname information in DNS CNAME records that could bypass +a hostname-based TLS usage policy. + +
  • Specify local transport(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy. + +
  • Specify MUST for these mail hosts in the smtp_tls_per_site +table. + +
+ +
Postfix < 2.2.9
+ +
    + +
  • Specify local transport(5) table entries for sensitive domains +with explicit smtp:[mailhost] destinations. This avoids false +hostname information in DNS MX records that could bypass a +hostname-based TLS usage policy, but cannot avoid false hostname +information in DNS CNAME records. + +
  • Specify MUST for these mail hosts in the smtp_tls_per_site +table. + +
+ +
+ +

%PARAM smtp_tls_scert_verifydepth 5 @@ -8866,7 +8901,7 @@ for receiving the initial server response.

Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). The default time unit is s (seconds).

-%PARAM lmtp_sasl_tls_security_options $var_lmtp_sasl_opts +%PARAM lmtp_sasl_tls_security_options $lmtp_sasl_security_options

The LMTP-specific version of the smtp_sasl_tls_security_options configuration parameter. See there for details.

@@ -9148,3 +9183,38 @@ mailbox_command_maps, mailbox_command, home_mailbox, mail_spool_directory, fallback_transport_maps, fallback_transport and luser_relay.

This feature is available in Postfix 2.3 and later.

+ +%PARAM smtp_cname_overrides_servername version dependent + +

Allow DNS CNAME records to override the servername that the +Postfix SMTP client uses for logging, SASL password lookup, TLS +policy decisions, or TLS certificate verification. The value "no" +hardens Postfix smtp_tls_per_site hostname-based policies against +false hostname information in DNS CNAME records, and makes SASL +password file lookups more predictable. This is the default setting +as of Postfix 2.3.

+ +

This feature is available in Postfix 2.2.9 and later.

+ +%PARAM lmtp_cname_overrides_servername yes + +

The LMTP-specific version of the smtp_cname_overrides_servername +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +%PARAM smtp_sasl_tls_verified_security_options $smtp_sasl_tls_security_options + +

The SASL authentication security options that the Postfix SMTP +client uses for TLS encrypted SMTP sessions with a verified server +certificate.

+ +

This feature is available in Postfix 2.3 and later.

+ +%PARAM lmtp_sasl_tls_verified_security_options $lmtp_sasl_tls_security_options + +

The LMTP-specific version of the +smtp_sasl_tls_verified_security_options configuration parameter. +See there for details.

+ +

This feature is available in Postfix 2.3 and later.

diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c index 1a19890c7..c7a824ca5 100644 --- a/postfix/src/bounce/bounce.c +++ b/postfix/src/bounce/bounce.c @@ -194,14 +194,14 @@ BOUNCE_TEMPLATES *bounce_templates; #define STR vstring_str +#define VS_NEUTER(s) printable(vstring_str(s), '?') + /* bounce_append_proto - bounce_append server protocol */ static int bounce_append_proto(char *service_name, VSTREAM *client) { char *myname = "bounce_append_proto"; int flags; - RECIPIENT_VAR rcpt; - DSN_VAR dsn; /* * Read and validate the client request. @@ -215,17 +215,31 @@ static int bounce_append_proto(char *service_name, VSTREAM *client) msg_warn("malformed request"); return (-1); } + + /* + * Sanitize input. + */ if (mail_queue_id_ok(STR(queue_id)) == 0) { msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); return (-1); } - (void) RECIPIENT_FROM_RCPT_BUF(&rcpt, rcpt_buf); - (void) DSN_FROM_DSN_BUF(&dsn, dsn_buf); + VS_NEUTER(rcpt_buf->address); + VS_NEUTER(rcpt_buf->orig_addr); + VS_NEUTER(rcpt_buf->dsn_orcpt); + VS_NEUTER(dsn_buf->status); + VS_NEUTER(dsn_buf->action); + VS_NEUTER(dsn_buf->reason); + VS_NEUTER(dsn_buf->dtype); + VS_NEUTER(dsn_buf->dtext); + VS_NEUTER(dsn_buf->mtype); + VS_NEUTER(dsn_buf->mname); + (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); + (void) DSN_FROM_DSN_BUF(dsn_buf); /* - * Beware: some dsn or rcpt fields may be null; access dsn_buf and - * rcpt_buf instead. See DSN_FROM_DSN_BUF(), RECIPIENT_FROM_RCPT_BUF(), - * and bounce_log(3). + * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and + * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and + * RECIPIENT_FROM_RCPT_BUF(). */ if (msg_verbose) 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", @@ -246,7 +260,7 @@ static int bounce_append_proto(char *service_name, VSTREAM *client) * Execute the request. */ return (bounce_append_service(flags, service_name, STR(queue_id), - &rcpt, &dsn)); + &rcpt_buf->rcpt, &dsn_buf->dsn)); } /* bounce_notify_proto - bounce_notify server protocol */ @@ -275,6 +289,10 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, msg_warn("malformed request"); return (-1); } + + /* + * Sanitize input. + */ if (mail_queue_name_ok(STR(queue_name)) == 0) { msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); return (-1); @@ -329,6 +347,10 @@ static int bounce_verp_proto(char *service_name, VSTREAM *client) msg_warn("malformed request"); return (-1); } + + /* + * Sanitize input. + */ if (mail_queue_name_ok(STR(queue_name)) == 0) { msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); return (-1); @@ -380,8 +402,6 @@ static int bounce_one_proto(char *service_name, VSTREAM *client) char *myname = "bounce_one_proto"; int flags; int dsn_ret; - RECIPIENT rcpt; - DSN dsn; /* * Read and validate the client request. @@ -400,6 +420,10 @@ static int bounce_one_proto(char *service_name, VSTREAM *client) msg_warn("malformed request"); return (-1); } + + /* + * Sanitize input. + */ if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) { msg_warn("wrong service name \"%s\" for one-recipient bouncing", service_name); @@ -414,13 +438,23 @@ static int bounce_one_proto(char *service_name, VSTREAM *client) return (-1); } printable(STR(dsn_envid), '?'); - (void) RECIPIENT_FROM_RCPT_BUF(&rcpt, rcpt_buf); - (void) DSN_FROM_DSN_BUF(&dsn, dsn_buf); + VS_NEUTER(rcpt_buf->address); + VS_NEUTER(rcpt_buf->orig_addr); + VS_NEUTER(rcpt_buf->dsn_orcpt); + VS_NEUTER(dsn_buf->status); + VS_NEUTER(dsn_buf->action); + VS_NEUTER(dsn_buf->reason); + VS_NEUTER(dsn_buf->dtype); + VS_NEUTER(dsn_buf->dtext); + VS_NEUTER(dsn_buf->mtype); + VS_NEUTER(dsn_buf->mname); + (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); + (void) DSN_FROM_DSN_BUF(dsn_buf); /* - * Beware: some dsn or rcpt fields may be null; access dsn_buf and - * rcpt_buf instead. See DSN_FROM_DSN_BUF(), RECIPIENT_FROM_RCPT_BUF(), - * and bounce_log(3). + * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and + * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and + * RECIPIENT_FROM_RCPT_BUF(). */ if (msg_verbose) 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", @@ -436,7 +470,7 @@ static int bounce_one_proto(char *service_name, VSTREAM *client) */ return (bounce_one_service(flags, STR(queue_name), STR(queue_id), STR(encoding), STR(sender), STR(dsn_envid), - dsn_ret, &rcpt, &dsn, bounce_templates)); + dsn_ret, rcpt_buf, dsn_buf, bounce_templates)); } /* bounce_service - parse bounce command type and delegate */ @@ -536,7 +570,9 @@ static void post_jail_init(char *service_name, char **unused_argv) /* * Special case: dump bounce templates. This is not part of the master(5) - * public interface. + * public interface. This internal interface is used by the postconf + * command. It was implemented before bounce templates were isolated + * into modules that could have been called directly. */ if (strcmp(service_name, "dump_templates") == 0) { bounce_templates_dump(VSTREAM_OUT, bounce_templates); diff --git a/postfix/src/bounce/bounce_append_service.c b/postfix/src/bounce/bounce_append_service.c index 868b03e68..582bb1977 100644 --- a/postfix/src/bounce/bounce_append_service.c +++ b/postfix/src/bounce/bounce_append_service.c @@ -10,8 +10,8 @@ /* int flags; /* char *service; /* char *queue_id; -/* RECIPIENT_VAR *rcpt; -/* DSN_VAR *dsn; +/* RECIPIENT *rcpt; +/* DSN *dsn; /* DESCRIPTION /* This module implements the server side of the bounce_append() /* (append bounce log) request. This routine either succeeds or @@ -67,7 +67,7 @@ /* bounce_append_service - append bounce log */ int bounce_append_service(int unused_flags, char *service, char *queue_id, - RECIPIENT_VAR *rcpt, DSN_VAR *dsn) + RECIPIENT *rcpt, DSN *dsn) { VSTRING *in_buf = vstring_alloc(100); VSTREAM *log; @@ -113,49 +113,41 @@ int bounce_append_service(int unused_flags, char *service, char *queue_id, msg_fatal("seek file %s %s: %m", service, queue_id); #define NOT_NULL_EMPTY(s) ((s) != 0 && *(s) != 0) -#define ST_NEUTER(s) printable((s), '?') -#define VS_NEUTER(s) printable(vstring_str(s), '?') +#define STR(x) vstring_str(x) vstream_fputs("\n", log); if (var_oldlog_compat) { vstream_fprintf(log, "<%s>: %s\n", *rcpt->address == 0 ? "" : - VS_NEUTER(quote_822_local(in_buf, rcpt->address)), - ST_NEUTER(dsn->reason)); + STR(quote_822_local(in_buf, rcpt->address)), + dsn->reason); } vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_RECIP, *rcpt->address ? - VS_NEUTER(quote_822_local(in_buf, rcpt->address)) : "<>"); + STR(quote_822_local(in_buf, rcpt->address)) : "<>"); if (NOT_NULL_EMPTY(rcpt->orig_addr) && strcasecmp(rcpt->address, rcpt->orig_addr) != 0) vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ORCPT, - VS_NEUTER(quote_822_local(in_buf, rcpt->orig_addr))); + STR(quote_822_local(in_buf, rcpt->orig_addr))); if (rcpt->offset > 0) vstream_fprintf(log, "%s=%ld\n", MAIL_ATTR_OFFSET, rcpt->offset); if (NOT_NULL_EMPTY(rcpt->dsn_orcpt)) - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ORCPT, - ST_NEUTER(rcpt->dsn_orcpt)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt); if (rcpt->dsn_notify != 0) vstream_fprintf(log, "%s=%d\n", MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify); if (NOT_NULL_EMPTY(dsn->status)) - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_STATUS, - ST_NEUTER(dsn->status)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_STATUS, dsn->status); if (NOT_NULL_EMPTY(dsn->action)) - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ACTION, - ST_NEUTER(dsn->action)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ACTION, dsn->action); if (NOT_NULL_EMPTY(dsn->dtype) && NOT_NULL_EMPTY(dsn->dtext)) { - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTYPE, - ST_NEUTER(dsn->dtype)); - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTEXT, - ST_NEUTER(dsn->dtext)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTYPE, dsn->dtype); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTEXT, dsn->dtext); } if (NOT_NULL_EMPTY(dsn->mtype) && NOT_NULL_EMPTY(dsn->mname)) { - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MTYPE, - ST_NEUTER(dsn->mtype)); - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MNAME, - ST_NEUTER(dsn->mname)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MTYPE, dsn->mtype); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MNAME, dsn->mname); } if (NOT_NULL_EMPTY(dsn->reason)) - vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, ST_NEUTER(dsn->reason)); + vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, dsn->reason); vstream_fputs("\n", log); if (vstream_fflush(log) != 0 || fsync(vstream_fileno(log)) < 0) { diff --git a/postfix/src/bounce/bounce_notify_service.c b/postfix/src/bounce/bounce_notify_service.c index c02ffb9c3..8c3550594 100644 --- a/postfix/src/bounce/bounce_notify_service.c +++ b/postfix/src/bounce/bounce_notify_service.c @@ -92,6 +92,7 @@ int bounce_notify_service(int flags, char *service, char *queue_name, VSTREAM *bounce; int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes); + VSTRING *new_id = vstring_alloc(10); char *postmaster; int count; @@ -174,7 +175,8 @@ int bounce_notify_service(int flags, char *service, char *queue_name, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Double bounce to Postmaster. This is the last opportunity @@ -192,6 +194,9 @@ int bounce_notify_service(int flags, char *service, char *queue_name, DSN_NOTIFY_OVERRIDE) > 0) { bounce_original(bounce, bounce_info, DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: postmaster non-delivery notification: %s", + queue_id, STR(new_id)); } else { /* No applicable recipients found - cancel this notice. */ (void) vstream_fclose(bounce); @@ -209,7 +214,8 @@ int bounce_notify_service(int flags, char *service, char *queue_name, else { if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Send the bounce message header, some boilerplate text that @@ -228,6 +234,9 @@ int bounce_notify_service(int flags, char *service, char *queue_name, bounce_original(bounce, bounce_info, dsn_ret ? dsn_ret : DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: sender non-delivery notification: %s", + queue_id, STR(new_id)); } else { /* No applicable recipients found - cancel this notice. */ (void) vstream_fclose(bounce); @@ -259,7 +268,8 @@ int bounce_notify_service(int flags, char *service, char *queue_name, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { count = -1; if (bounce_header(bounce, bounce_info, postmaster, POSTMASTER_COPY) == 0 @@ -270,6 +280,9 @@ int bounce_notify_service(int flags, char *service, char *queue_name, DSN_NOTIFY_OVERRIDE) > 0) { bounce_original(bounce, bounce_info, DSN_RET_HDRS); postmaster_status = post_mail_fclose(bounce); + if (postmaster_status == 0) + msg_info("%s: postmaster non-delivery notification: %s", + queue_id, STR(new_id)); } else { /* No applicable recipients found - cancel this notice. */ (void) vstream_fclose(bounce); @@ -278,8 +291,8 @@ int bounce_notify_service(int flags, char *service, char *queue_name, } } if (postmaster_status) - msg_warn("postmaster notice failed while bouncing to %s", - recipient); + msg_warn("%s: postmaster notice failed while bouncing to %s", + queue_id, recipient); } } @@ -302,6 +315,7 @@ int bounce_notify_service(int flags, char *service, char *queue_name, * Cleanup. */ bounce_mail_free(bounce_info); + vstring_free(new_id); return (bounce_status); } diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c index 0078b680c..39dc887e7 100644 --- a/postfix/src/bounce/bounce_notify_util.c +++ b/postfix/src/bounce/bounce_notify_util.c @@ -22,15 +22,15 @@ /* const BOUNCE_TEMPLATE *template; /* /* BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id, encoding, -/* dsn_envid, dsn_notify, rcpt, dsn, -/* template) +/* dsn_envid, dsn_notify, rcpt_buf, +/* dsn_buf, template) /* const char *queue_name; /* const char *queue_id; /* const char *encoding; /* int dsn_notify; /* const char *dsn_envid; -/* RECIPIENT *rcpt; -/* DSN *dsn; +/* RCPT_BUF *rcpt_buf; +/* DSN_BUF *dsn_buf; /* const BOUNCE_TEMPLATE *template; /* /* void bounce_mail_free(bounce_info) @@ -160,6 +160,7 @@ #include #include #include +#include /* sscanf() */ #include #include #include @@ -211,6 +212,8 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, const char *queue_id, const char *encoding, const char *dsn_envid, + RCPT_BUF *rcpt_buf, + DSN_BUF *dsn_buf, BOUNCE_TEMPLATE *template, BOUNCE_LOG *log_handle) { @@ -218,7 +221,7 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, int rec_type; /* - * Bundle up a bunch of parameters and initialize information. that will + * Bundle up a bunch of parameters and initialize information that will * be discovered on the fly. */ bounce_info = (BOUNCE_INFO *) mymalloc(sizeof(*bounce_info)); @@ -245,6 +248,8 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, bounce_info->arrival_time = 0; bounce_info->orig_offs = 0; bounce_info->message_size = 0; + bounce_info->rcpt_buf = rcpt_buf; + bounce_info->dsn_buf = dsn_buf; bounce_info->log_handle = log_handle; /* @@ -278,9 +283,9 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, msg_fatal("open %s %s: %m", service, queue_id); /* - * Skip over the original message envelope records. If the envelope is - * corrupted just send whatever we can (remember this is a best effort, - * it does not have to be perfect). + * Get time/size/sender information from the original message envelope + * records. If the envelope is corrupted just send whatever we can + * (remember this is a best effort, it does not have to be perfect). * * Lock the file for shared use, so that queue manager leaves it alone after * restarting. @@ -294,20 +299,44 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, VSTREAM_PATH(bounce_info->orig_fp)); while ((rec_type = rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0) { + + /* + * Postfix version dependent: data offset in SIZE record. + */ if (rec_type == REC_TYPE_SIZE) { - if (bounce_info->message_size == 0 - && (bounce_info->message_size = atol(STR(bounce_info->buf))) < 0) + if (bounce_info->message_size == 0) + sscanf(STR(bounce_info->buf), "%ld %ld", + &bounce_info->message_size, + &bounce_info->orig_offs); + if (bounce_info->message_size < 0) bounce_info->message_size = 0; - } else if (rec_type == REC_TYPE_TIME) { + if (bounce_info->orig_offs < 0) + bounce_info->orig_offs = 0; + } + + /* + * Information for the Arrival-Date: attribute. + */ + else if (rec_type == REC_TYPE_TIME) { if (bounce_info->arrival_time == 0 && (bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0) bounce_info->arrival_time = 0; - } else if (rec_type == REC_TYPE_FROM) { + } + + /* + * Information for the X-Postfix-Sender: attribute. + */ + else if (rec_type == REC_TYPE_FROM) { quote_822_local_flags(bounce_info->sender, VSTRING_LEN(bounce_info->buf) ? STR(bounce_info->buf) : mail_addr_mail_daemon(), 0); - } else if (rec_type == REC_TYPE_MESG) { + } + + /* + * Backwards compatibility: no data offset in SIZE record. + */ + else if (rec_type == REC_TYPE_MESG) { /* XXX Future: sender+recipient after message content. */ if (VSTRING_LEN(bounce_info->sender) == 0) msg_warn("%s: no sender before message content record", @@ -315,6 +344,10 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service, bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp); break; } + if (bounce_info->orig_offs > 0 + && bounce_info->arrival_time > 0 + && VSTRING_LEN(bounce_info->sender) > 0) + break; } } return (bounce_info); @@ -331,6 +364,8 @@ BOUNCE_INFO *bounce_mail_init(const char *service, { BOUNCE_INFO *bounce_info; BOUNCE_LOG *log_handle; + RCPT_BUF *rcpt_buf; + DSN_BUF *dsn_buf; /* * Initialize the bounce_info structure. If the bounce log cannot be @@ -340,11 +375,18 @@ BOUNCE_INFO *bounce_mail_init(const char *service, * job. But if the system IS running out of resources, raise a fatal * run-time error and force a backoff. */ - if ((log_handle = bounce_log_open(service, queue_id, O_RDONLY, 0)) == 0 - && errno != ENOENT) - msg_fatal("open %s %s: %m", service, queue_id); + if ((log_handle = bounce_log_open(service, queue_id, O_RDONLY, 0)) == 0) { + if (errno != ENOENT) + msg_fatal("open %s %s: %m", service, queue_id); + rcpt_buf = 0; + dsn_buf = 0; + } else { + rcpt_buf = rcpb_create(); + dsn_buf = dsb_create(); + } bounce_info = bounce_mail_alloc(service, queue_name, queue_id, encoding, - dsn_envid, template, log_handle); + dsn_envid, rcpt_buf, dsn_buf, + template, log_handle); return (bounce_info); } @@ -354,20 +396,18 @@ BOUNCE_INFO *bounce_mail_one_init(const char *queue_name, const char *queue_id, const char *encoding, const char *dsn_envid, - RECIPIENT *rcpt, - DSN *dsn, + RCPT_BUF *rcpt_buf, + DSN_BUF *dsn_buf, BOUNCE_TEMPLATE *template) { BOUNCE_INFO *bounce_info; - BOUNCE_LOG *log_handle; /* - * Initialize the bounce_info structure. Forge a logfile record for just - * one recipient. + * Initialize the bounce_info structure for just one recipient. */ - log_handle = bounce_log_forge(rcpt, dsn); bounce_info = bounce_mail_alloc("none", queue_name, queue_id, encoding, - dsn_envid, template, log_handle); + dsn_envid, rcpt_buf, dsn_buf, template, + (BOUNCE_LOG *) 0); return (bounce_info); } @@ -375,9 +415,13 @@ BOUNCE_INFO *bounce_mail_one_init(const char *queue_name, void bounce_mail_free(BOUNCE_INFO *bounce_info) { - if (bounce_info->log_handle && bounce_log_close(bounce_info->log_handle)) - msg_warn("%s: read bounce log %s: %m", - bounce_info->queue_id, bounce_info->queue_id); + if (bounce_info->log_handle) { + if (bounce_log_close(bounce_info->log_handle)) + msg_warn("%s: read bounce log %s: %m", + bounce_info->queue_id, bounce_info->queue_id); + rcpb_free(bounce_info->rcpt_buf); + dsb_free(bounce_info->dsn_buf); + } if (bounce_info->orig_fp && vstream_fclose(bounce_info->orig_fp)) msg_warn("%s: read message file %s %s: %m", bounce_info->queue_id, bounce_info->queue_name, @@ -480,6 +524,8 @@ static void bounce_print_wrap(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; + DSN *dsn = &bounce_info->dsn_buf->dsn; /* * Mask control and non-ASCII characters (done in bounce_log_read()), @@ -487,16 +533,15 @@ int bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info) * piped into other programs. Sort of like TCP Wrapper's safe_finger * program. */ +#define NON_NULL_EMPTY(s) ((s) && *(s)) + post_mail_fputs(bounce, ""); - if (bounce_info->log_handle->rcpt.orig_addr) { + if (NON_NULL_EMPTY(rcpt->orig_addr)) { bounce_print_wrap(bounce, bounce_info, "<%s> (expanded from <%s>): %s", - bounce_info->log_handle->rcpt.address, - bounce_info->log_handle->rcpt.orig_addr, - bounce_info->log_handle->dsn.reason); + rcpt->address, rcpt->orig_addr, dsn->reason); } else { bounce_print_wrap(bounce, bounce_info, "<%s>: %s", - bounce_info->log_handle->rcpt.address, - bounce_info->log_handle->dsn.reason); + rcpt->address, dsn->reason); } return (vstream_ferror(bounce)); } @@ -506,6 +551,7 @@ int bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info) int bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int notify_filter) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; int count = 0; /* @@ -520,13 +566,15 @@ int bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info, if (bounce_info->log_handle == 0 || bounce_log_rewind(bounce_info->log_handle)) { if (IS_FAILURE_TEMPLATE(bounce_info->template)) { + post_mail_fputs(bounce, ""); post_mail_fputs(bounce, "\t--- Delivery report unavailable ---"); count = 1; /* XXX don't abort */ } } else { - while (bounce_log_read(bounce_info->log_handle) != 0) { - if (bounce_info->log_handle->rcpt.dsn_notify == 0 /* compat */ - || (bounce_info->log_handle->rcpt.dsn_notify & notify_filter)) { + while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf, + bounce_info->dsn_buf) != 0) { + if (rcpt->dsn_notify == 0 /* compat */ + || (rcpt->dsn_notify & notify_filter)) { count++; if (bounce_recipient_log(bounce, bounce_info) != 0) break; @@ -561,7 +609,7 @@ int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) #if 0 post_mail_fprintf(bounce, "Received-From-MTA: dns; %s", "whatever"); #endif - if (bounce_info->dsn_envid) { + if (NON_NULL_EMPTY(bounce_info->dsn_envid)) { post_mail_fprintf(bounce, "Original-Envelope-Id: %s", bounce_info->dsn_envid); } @@ -580,9 +628,11 @@ int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; + DSN *dsn = &bounce_info->dsn_buf->dsn; + post_mail_fputs(bounce, ""); - post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s", - bounce_info->log_handle->rcpt.address); + post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s", rcpt->address); /* * XXX DSN @@ -603,35 +653,29 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) * Postfix always reports an Original-Recipient field, because it is more * more useful and more consistent. */ - if (bounce_info->log_handle->rcpt.dsn_orcpt) { - post_mail_fprintf(bounce, "Original-Recipient: %s", - bounce_info->log_handle->rcpt.dsn_orcpt); - } else if (bounce_info->log_handle->rcpt.orig_addr) { + if (NON_NULL_EMPTY(rcpt->dsn_orcpt)) { + post_mail_fprintf(bounce, "Original-Recipient: %s", rcpt->dsn_orcpt); + } else if (NON_NULL_EMPTY(rcpt->orig_addr)) { post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s", - bounce_info->log_handle->rcpt.orig_addr); + rcpt->orig_addr); } post_mail_fprintf(bounce, "Action: %s", IS_FAILURE_TEMPLATE(bounce_info->template) ? - "failed" : bounce_info->log_handle->dsn.action); - post_mail_fprintf(bounce, "Status: %s", - bounce_info->log_handle->dsn.status); - if (bounce_info->log_handle->dsn.mtype - && bounce_info->log_handle->dsn.mname) + "failed" : dsn->action); + post_mail_fprintf(bounce, "Status: %s", dsn->status); + if (NON_NULL_EMPTY(dsn->mtype) && NON_NULL_EMPTY(dsn->mname)) bounce_print_wrap(bounce, bounce_info, "Remote-MTA: %s; %s", - bounce_info->log_handle->dsn.mtype, - bounce_info->log_handle->dsn.mname); - if (bounce_info->log_handle->dsn.dtype - && bounce_info->log_handle->dsn.dtext) + dsn->mtype, dsn->mname); + if (NON_NULL_EMPTY(dsn->dtype) && NON_NULL_EMPTY(dsn->dtext)) bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: %s; %s", - bounce_info->log_handle->dsn.dtype, - bounce_info->log_handle->dsn.dtext); + dsn->dtype, dsn->dtext); else bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-%s; %s", - bounce_info->mail_name, - bounce_info->log_handle->dsn.reason); + bounce_info->mail_name, dsn->reason); #if 0 - post_mail_fprintf(bounce, "Last-Attempt-Date: %s", - bounce_info->log_handle->log_time); + if (dsn->time > 0) + post_mail_fprintf(bounce, "Last-Attempt-Date: %s", + mail_date(dsn->time)); #endif if (IS_DELAY_TEMPLATE(bounce_info->template)) post_mail_fprintf(bounce, "Will-Retry-Until: %s", @@ -644,6 +688,7 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) int bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int notify_filter) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; int count = 0; /* @@ -660,9 +705,10 @@ int bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info, if (IS_FAILURE_TEMPLATE(bounce_info->template)) count = 1; /* XXX don't abort */ } else { - while (bounce_log_read(bounce_info->log_handle) != 0) { - if (bounce_info->log_handle->rcpt.dsn_notify == 0 /* compat */ - || (bounce_info->log_handle->rcpt.dsn_notify & notify_filter)) { + while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf, + bounce_info->dsn_buf) != 0) { + if (rcpt->dsn_notify == 0 /* compat */ + || (rcpt->dsn_notify & notify_filter)) { count++; if (bounce_recipient_dsn(bounce, bounce_info) != 0) break; @@ -752,22 +798,23 @@ int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, void bounce_delrcpt(BOUNCE_INFO *bounce_info) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; + if (bounce_info->orig_fp != 0 && bounce_info->log_handle != 0 && bounce_log_rewind(bounce_info->log_handle) == 0) - while (bounce_log_read(bounce_info->log_handle) != 0) - if (bounce_info->log_handle->rcpt.offset > 0) - deliver_completed(bounce_info->orig_fp, - bounce_info->log_handle->rcpt.offset); + while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf, + bounce_info->dsn_buf) != 0) + if (rcpt->offset > 0) + deliver_completed(bounce_info->orig_fp, rcpt->offset); } /* bounce_delrcpt_one - delete one recipient from original queue file */ void bounce_delrcpt_one(BOUNCE_INFO *bounce_info) { - if (bounce_info->orig_fp != 0 - && bounce_info->log_handle != 0 - && bounce_info->log_handle->rcpt.offset > 0) - deliver_completed(bounce_info->orig_fp, - bounce_info->log_handle->rcpt.offset); + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; + + if (bounce_info->orig_fp != 0 && rcpt->offset > 0) + deliver_completed(bounce_info->orig_fp, rcpt->offset); } diff --git a/postfix/src/bounce/bounce_notify_verp.c b/postfix/src/bounce/bounce_notify_verp.c index e1f69dc01..9a1913103 100644 --- a/postfix/src/bounce/bounce_notify_verp.c +++ b/postfix/src/bounce/bounce_notify_verp.c @@ -97,7 +97,8 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes); char *postmaster; - VSTRING *verp_buf = vstring_alloc(100); + VSTRING *verp_buf; + VSTRING *new_id; /* * Sanity checks. We must be called only for undeliverable non-bounce @@ -114,6 +115,27 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, bounce_info = bounce_mail_init(service, queue_name, queue_id, encoding, dsn_envid, ts->failure); + /* + * If we have no recipient list then we can't send VERP replies. Send + * *something* anyway so that the mail is not lost in a black hole. + */ + if (bounce_info->log_handle == 0) { + DSN_BUF *dsn_buf = dsb_create(); + RCPT_BUF *rcpt_buf = rcpb_create(); + + dsb_simple(dsn_buf, "5.0.0", "(error report unavailable)"); + (void) DSN_FROM_DSN_BUF(dsn_buf); + vstring_strcpy(rcpt_buf->address, "(recipient address unavailable)"); + (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); + bounce_status = bounce_one_service(flags, queue_name, queue_id, + encoding, recipient, dsn_envid, + dsn_ret, rcpt_buf, dsn_buf, ts); + rcpb_free(rcpt_buf); + dsb_free(dsn_buf); + bounce_mail_free(bounce_info); + return (bounce_status); + } + #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ #define NULL_TRACE_FLAGS 0 @@ -121,20 +143,24 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, * A non-bounce message was returned. Send a single bounce, one per * recipient. */ - while (bounce_log_read(bounce_info->log_handle) != 0) { + verp_buf = vstring_alloc(100); + new_id = vstring_alloc(10); + while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf, + bounce_info->dsn_buf) != 0) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; /* * Notify the originator, subject to DSN NOTIFY restrictions. */ - if (bounce_info->log_handle->rcpt.dsn_notify != 0 /* compat */ - && (bounce_info->log_handle->rcpt.dsn_notify & DSN_NOTIFY_FAILURE) == 0) { + if (rcpt->dsn_notify != 0 /* compat */ + && (rcpt->dsn_notify & DSN_NOTIFY_FAILURE) == 0) { bounce_status = 0; } else { - verp_sender(verp_buf, verp_delims, recipient, - bounce_info->log_handle->rcpt.address); + verp_sender(verp_buf, verp_delims, recipient, rcpt->address); if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf), CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Send the bounce message header, some boilerplate text that @@ -150,6 +176,9 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, bounce_original(bounce, bounce_info, dsn_ret ? dsn_ret : DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: sender non-delivery notification: %s", + queue_id, STR(new_id)); } else bounce_status = 1; @@ -189,7 +218,8 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { if (bounce_header(bounce, bounce_info, postmaster, POSTMASTER_COPY) == 0 && bounce_recipient_log(bounce, bounce_info) == 0 @@ -197,12 +227,15 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, && bounce_recipient_dsn(bounce, bounce_info) == 0) bounce_original(bounce, bounce_info, DSN_RET_HDRS); postmaster_status = post_mail_fclose(bounce); + if (postmaster_status == 0) + msg_info("%s: postmaster non-delivery notification: %s", + queue_id, STR(new_id)); } else postmaster_status = 1; if (postmaster_status) - msg_warn("postmaster notice failed while bouncing to %s", - recipient); + msg_warn("%s: postmaster notice failed while bouncing to %s", + queue_id, recipient); } } @@ -220,6 +253,7 @@ int bounce_notify_verp(int flags, char *service, char *queue_name, */ bounce_mail_free(bounce_info); vstring_free(verp_buf); + vstring_free(new_id); return (bounce_status); } diff --git a/postfix/src/bounce/bounce_one_service.c b/postfix/src/bounce/bounce_one_service.c index d6355afba..6d6ca629a 100644 --- a/postfix/src/bounce/bounce_one_service.c +++ b/postfix/src/bounce/bounce_one_service.c @@ -8,7 +8,7 @@ /* /* int bounce_one_service(flags, queue_name, queue_id, encoding, /* orig_sender, envid, ret, -/* rcpt, dsn, templates) +/* rcpt_buf, dsn_buf, templates) /* int flags; /* char *queue_name; /* char *queue_id; @@ -16,8 +16,8 @@ /* char *orig_sender; /* char *envid; /* int ret; -/* RECIPIENT *rcpt; -/* DSN *dsn; +/* RCPT_BUF *rcpt_buf; +/* DSN_BUF *dsn_buf; /* BOUNCE_TEMPLATES *templates; /* DESCRIPTION /* This module implements the server side of the bounce_one() @@ -86,7 +86,7 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, char *encoding, char *orig_sender, char *dsn_envid, int dsn_ret, - RECIPIENT *rcpt, DSN *dsn, + RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf, BOUNCE_TEMPLATES *ts) { BOUNCE_INFO *bounce_info; @@ -95,12 +95,14 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, VSTREAM *bounce; int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes); + VSTRING *new_id = vstring_alloc(10); /* * Initialize. Open queue file, bounce log, etc. */ bounce_info = bounce_mail_one_init(queue_name, queue_id, encoding, - dsn_envid, rcpt, dsn, ts->failure); + dsn_envid, rcpt_buf, dsn_buf, + ts->failure); #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ #define NULL_TRACE_FLAGS 0 @@ -146,7 +148,8 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), var_2bounce_rcpt, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Double bounce to Postmaster. This is the last opportunity @@ -161,6 +164,9 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, && bounce_recipient_dsn(bounce, bounce_info) == 0) bounce_original(bounce, bounce_info, DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: postmaster non-delivery notification: %s", + queue_id, STR(new_id)); } } } @@ -170,13 +176,16 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, * restrictions. */ else { - if (bounce_info->log_handle->rcpt.dsn_notify != 0 /* compat */ - && (bounce_info->log_handle->rcpt.dsn_notify & DSN_NOTIFY_FAILURE) == 0) { + RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; + + if (rcpt->dsn_notify != 0 /* compat */ + && (rcpt->dsn_notify & DSN_NOTIFY_FAILURE) == 0) { bounce_status = 0; } else { if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Send the bounce message header, some boilerplate text that @@ -192,6 +201,9 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, bounce_original(bounce, bounce_info, dsn_ret ? dsn_ret : DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: sender non-delivery notification: %s", + queue_id, STR(new_id)); } } @@ -217,7 +229,8 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), var_bounce_rcpt, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { if (bounce_header(bounce, bounce_info, var_bounce_rcpt, POSTMASTER_COPY) == 0 && bounce_recipient_log(bounce, bounce_info) == 0 @@ -225,10 +238,13 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, && bounce_recipient_dsn(bounce, bounce_info) == 0) bounce_original(bounce, bounce_info, DSN_RET_HDRS); postmaster_status = post_mail_fclose(bounce); + if (postmaster_status == 0) + msg_info("%s: postmaster non-delivery notification: %s", + queue_id, STR(new_id)); } if (postmaster_status) - msg_warn("postmaster notice failed while bouncing to %s", - orig_sender); + msg_warn("%s: postmaster notice failed while bouncing to %s", + queue_id, orig_sender); } } @@ -242,6 +258,7 @@ int bounce_one_service(int flags, char *queue_name, char *queue_id, * Cleanup. */ bounce_mail_free(bounce_info); + vstring_free(new_id); return (bounce_status); } diff --git a/postfix/src/bounce/bounce_service.h b/postfix/src/bounce/bounce_service.h index fb3af89c7..0a9bc4d02 100644 --- a/postfix/src/bounce/bounce_service.h +++ b/postfix/src/bounce/bounce_service.h @@ -26,7 +26,7 @@ /* * bounce_append_service.c */ -extern int bounce_append_service(int, char *, char *, RECIPIENT_VAR *, DSN_VAR *); +extern int bounce_append_service(int, char *, char *, RECIPIENT *, DSN *); /* * bounce_notify_service.c @@ -51,7 +51,7 @@ extern int bounce_notify_verp(int, char *, char *, char *, char *, char *, char /* * bounce_one_service.c */ -extern int bounce_one_service(int, char *, char *, char *, char *, char *, int, RECIPIENT *, DSN *, BOUNCE_TEMPLATES *); +extern int bounce_one_service(int, char *, char *, char *, char *, char *, int, RCPT_BUF *, DSN_BUF *, BOUNCE_TEMPLATES *); /* * bounce_cleanup.c @@ -80,6 +80,8 @@ typedef struct { long orig_offs; /* start of content */ time_t arrival_time; /* time of arrival */ long message_size; /* size of content */ + RCPT_BUF *rcpt_buf; /* recipient info */ + DSN_BUF *dsn_buf; /* delivery status info */ BOUNCE_LOG *log_handle; /* open logfile */ char *mail_name; /* $mail_name, cooked */ } BOUNCE_INFO; @@ -87,7 +89,7 @@ typedef struct { /* */ extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, const char *, BOUNCE_TEMPLATE *); -extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, RECIPIENT *, DSN *, BOUNCE_TEMPLATE *); +extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, RCPT_BUF *, DSN_BUF *, BOUNCE_TEMPLATE *); extern void bounce_mail_free(BOUNCE_INFO *); extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *, int); extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *); diff --git a/postfix/src/bounce/bounce_templates.c b/postfix/src/bounce/bounce_templates.c index 381763429..b01f12686 100644 --- a/postfix/src/bounce/bounce_templates.c +++ b/postfix/src/bounce/bounce_templates.c @@ -130,7 +130,7 @@ static const char *def_bounce_delay_body[] = { "# THIS IS A WARNING ONLY. YOU DO NOT NEED TO RESEND YOUR MESSAGE. #", "####################################################################", "", - "Your message could not be delivered for $delay_warning_time_hours hour(s)." + "Your message could not be delivered for more than $delay_warning_time_hours hour(s)." , "It will be retried until it is $maximal_queue_lifetime_days day(s) old.", "", diff --git a/postfix/src/bounce/bounce_trace_service.c b/postfix/src/bounce/bounce_trace_service.c index 04cf425ce..747e6f400 100644 --- a/postfix/src/bounce/bounce_trace_service.c +++ b/postfix/src/bounce/bounce_trace_service.c @@ -83,6 +83,7 @@ int bounce_trace_service(int flags, char *service, char *queue_name, BOUNCE_INFO *bounce_info; int bounce_status = 1; VSTREAM *bounce; + VSTRING *new_id = vstring_alloc(10); int count; /* @@ -140,7 +141,8 @@ int bounce_trace_service(int flags, char *service, char *queue_name, */ if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { count = -1; if (bounce_header(bounce, bounce_info, recipient, NO_POSTMASTER_COPY) == 0 @@ -152,6 +154,9 @@ int bounce_trace_service(int flags, char *service, char *queue_name, DSN_NOTIFY_OVERRIDE) > 0) { bounce_original(bounce, bounce_info, DSN_RET_HDRS); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: sender delivery status notification: %s", + queue_id, STR(new_id)); } else { (void) vstream_fclose(bounce); if (count == 0) @@ -171,6 +176,7 @@ int bounce_trace_service(int flags, char *service, char *queue_name, * Cleanup. */ bounce_mail_free(bounce_info); + vstring_free(new_id); return (bounce_status); } diff --git a/postfix/src/bounce/bounce_warn_service.c b/postfix/src/bounce/bounce_warn_service.c index f446dd6d5..98db272ea 100644 --- a/postfix/src/bounce/bounce_warn_service.c +++ b/postfix/src/bounce/bounce_warn_service.c @@ -92,6 +92,7 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, VSTREAM *bounce; int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes); + VSTRING *new_id = vstring_alloc(10); char *postmaster; int count; @@ -164,7 +165,8 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Double bounce to Postmaster. This is the last opportunity @@ -182,6 +184,9 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, DSN_NOTIFY_OVERRIDE) > 0) { bounce_original(bounce, bounce_info, DSN_RET_FULL); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: postmaster delay notification: %s", + queue_id, STR(new_id)); } else { (void) vstream_fclose(bounce); if (count == 0) @@ -198,7 +203,8 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, else { if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { /* * Send the bounce message header, some boilerplate text that @@ -216,6 +222,9 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, DSN_NOTIFY_DELAY) > 0) { bounce_original(bounce, bounce_info, DSN_RET_HDRS); bounce_status = post_mail_fclose(bounce); + if (bounce_status == 0) + msg_info("%s: sender delay notification: %s", + queue_id, STR(new_id)); } else { (void) vstream_fclose(bounce); if (count == 0) @@ -244,7 +253,8 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS)) != 0) { + NULL_TRACE_FLAGS, + new_id)) != 0) { count = -1; if (bounce_header(bounce, bounce_info, postmaster, POSTMASTER_COPY) == 0 @@ -255,6 +265,9 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, DSN_NOTIFY_OVERRIDE) > 0) { bounce_original(bounce, bounce_info, DSN_RET_HDRS); postmaster_status = post_mail_fclose(bounce); + if (postmaster_status == 0) + msg_info("%s: postmaster delay notification: %s", + queue_id, STR(new_id)); } else { (void) vstream_fclose(bounce); if (count == 0) @@ -262,8 +275,8 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, } } if (postmaster_status) - msg_warn("postmaster notice failed while bouncing to %s", - recipient); + msg_warn("%s: postmaster notice failed while warning %s", + queue_id, recipient); } } @@ -271,6 +284,7 @@ int bounce_warn_service(int unused_flags, char *service, char *queue_name, * Cleanup. */ bounce_mail_free(bounce_info); + vstring_free(new_id); return (bounce_status); } diff --git a/postfix/src/dns/dns.h b/postfix/src/dns/dns.h index 415c4703b..705623831 100644 --- a/postfix/src/dns/dns.h +++ b/postfix/src/dns/dns.h @@ -80,7 +80,7 @@ typedef struct DNS_FIXED { * named after the things one can expect to find in a DNS resource record. */ typedef struct DNS_RR { - char *name; /* name, mystrdup()ed */ + char *qname; /* query name, mystrdup()ed */ char *rname; /* reply name, mystrdup()ed */ unsigned short type; /* T_A, T_CNAME, etc. */ unsigned short class; /* C_IN, etc. */ diff --git a/postfix/src/dns/dns_rr.c b/postfix/src/dns/dns_rr.c index e4dc0f85e..e2027ba47 100644 --- a/postfix/src/dns/dns_rr.c +++ b/postfix/src/dns/dns_rr.c @@ -6,9 +6,9 @@ /* SYNOPSIS /* #include /* -/* DNS_RR *dns_rr_create(name, rname, type, class, ttl, preference, +/* DNS_RR *dns_rr_create(qname, rname, type, class, ttl, preference, /* data, data_len) -/* const char *name; +/* const char *qname; /* const char *rname; /* unsigned short type; /* unsigned short class; @@ -46,7 +46,7 @@ /* information, and maintain lists of DNS resource records. /* /* dns_rr_create() creates and initializes one resource record. -/* The \fIname\fR field specifies the query name. +/* The \fIqname\fR field specifies the query name. /* The \fIrname\fR field specifies the reply name. /* \fIpreference\fR is used for MX records; \fIdata\fR is a null /* pointer or specifies optional resource-specific data; @@ -59,6 +59,7 @@ /* /* dns_rr_append() appends a resource record to a (list of) resource /* record(s). +/* A null input list is explicitly allowed. /* /* dns_rr_sort() sorts a list of resource records into ascending /* order according to a user-specified criterion. The result is the @@ -71,6 +72,7 @@ /* /* dns_rr_remove() removes the specified record from the specified list. /* The updated list is the result value. +/* The record MUST be a list member. /* LICENSE /* .ad /* .fi @@ -100,7 +102,7 @@ /* dns_rr_create - fill in resource record structure */ -DNS_RR *dns_rr_create(const char *name, const char *rname, +DNS_RR *dns_rr_create(const char *qname, const char *rname, ushort type, ushort class, unsigned int ttl, unsigned pref, const char *data, size_t data_len) @@ -108,7 +110,7 @@ DNS_RR *dns_rr_create(const char *name, const char *rname, DNS_RR *rr; rr = (DNS_RR *) mymalloc(sizeof(*rr) + data_len - 1); - rr->name = mystrdup(name); + rr->qname = mystrdup(qname); rr->rname = mystrdup(rname); rr->type = type; rr->class = class; @@ -128,7 +130,7 @@ void dns_rr_free(DNS_RR *rr) if (rr) { if (rr->next) dns_rr_free(rr->next); - myfree(rr->name); + myfree(rr->qname); myfree(rr->rname); myfree((char *) rr); } @@ -146,7 +148,7 @@ DNS_RR *dns_rr_copy(DNS_RR *src) */ dst = (DNS_RR *) mymalloc(len); memcpy((char *) dst, (char *) src, len); - dst->name = mystrdup(src->name); + dst->qname = mystrdup(src->qname); dst->rname = mystrdup(src->rname); dst->next = 0; return (dst); diff --git a/postfix/src/error/error.c b/postfix/src/error/error.c index c7be3d6ec..1a13a7613 100644 --- a/postfix/src/error/error.c +++ b/postfix/src/error/error.c @@ -178,8 +178,7 @@ static int deliver_message(DELIVER_REQUEST *request) rcpt = request->rcpt_list.info + nrcpt; if (rcpt->offset >= 0) { status = bounce_append(BOUNCE_FLAGS(request), request->queue_id, - &request->msg_stats, rcpt, "none", - &dsn); + &request->msg_stats, rcpt, "none", &dsn); if (status == 0) deliver_completed(src, rcpt->offset); result |= status; diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index e46bf79a6..1a6faf282 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -642,6 +642,7 @@ deliver_pass.o: dsn_buf.h deliver_pass.o: mail_params.h deliver_pass.o: mail_proto.h deliver_pass.o: msg_stats.h +deliver_pass.o: rcpt_print.h deliver_pass.o: recipient_list.h deliver_request.o: ../../include/attr.h deliver_request.o: ../../include/iostuff.h @@ -655,12 +656,12 @@ deliver_request.o: ../../include/vstring.h deliver_request.o: deliver_request.c deliver_request.o: deliver_request.h deliver_request.o: dsn.h -deliver_request.o: dsn_buf.h deliver_request.o: dsn_print.h deliver_request.o: mail_open_ok.h deliver_request.o: mail_proto.h deliver_request.o: mail_queue.h deliver_request.o: msg_stats.h +deliver_request.o: rcpt_buf.h deliver_request.o: recipient_list.h dict_ldap.o: ../../include/argv.h dict_ldap.o: ../../include/binhash.h @@ -763,16 +764,14 @@ dsb_scan.o: ../../include/vstream.h dsb_scan.o: ../../include/vstring.h dsb_scan.o: dsb_scan.c dsb_scan.o: dsb_scan.h +dsb_scan.o: dsn.h dsb_scan.o: dsn_buf.h dsb_scan.o: mail_proto.h dsn.o: ../../include/msg.h dsn.o: ../../include/mymalloc.h dsn.o: ../../include/sys_defs.h -dsn.o: ../../include/vbuf.h -dsn.o: ../../include/vstring.h dsn.o: dsn.c dsn.o: dsn.h -dsn.o: dsn_buf.h dsn_attr_map.o: ../../include/attr.h dsn_attr_map.o: ../../include/iostuff.h dsn_attr_map.o: ../../include/sys_defs.h @@ -787,6 +786,7 @@ dsn_buf.o: ../../include/mymalloc.h dsn_buf.o: ../../include/sys_defs.h dsn_buf.o: ../../include/vbuf.h dsn_buf.o: ../../include/vstring.h +dsn_buf.o: dsn.h dsn_buf.o: dsn_buf.c dsn_buf.o: dsn_buf.h dsn_mask.o: ../../include/msg.h @@ -800,9 +800,7 @@ dsn_print.o: ../../include/iostuff.h dsn_print.o: ../../include/sys_defs.h dsn_print.o: ../../include/vbuf.h dsn_print.o: ../../include/vstream.h -dsn_print.o: ../../include/vstring.h dsn_print.o: dsn.h -dsn_print.o: dsn_buf.h dsn_print.o: dsn_print.c dsn_print.o: dsn_print.h dsn_print.o: mail_proto.h @@ -888,7 +886,6 @@ log_adhoc.o: ../../include/vbuf.h log_adhoc.o: ../../include/vstream.h log_adhoc.o: ../../include/vstring.h log_adhoc.o: dsn.h -log_adhoc.o: dsn_buf.h log_adhoc.o: log_adhoc.c log_adhoc.o: log_adhoc.h log_adhoc.o: mail_params.h @@ -1041,6 +1038,7 @@ mail_copy.o: ../../include/vbuf.h mail_copy.o: ../../include/vstream.h mail_copy.o: ../../include/vstring.h mail_copy.o: ../../include/vstring_vstream.h +mail_copy.o: dsn.h mail_copy.o: dsn_buf.h mail_copy.o: mail_addr.h mail_copy.o: mail_copy.c @@ -1217,7 +1215,6 @@ mark_corrupt.o: ../../include/vstream.h mark_corrupt.o: ../../include/vstring.h mark_corrupt.o: deliver_request.h mark_corrupt.o: dsn.h -mark_corrupt.o: dsn_buf.h mark_corrupt.o: mail_params.h mark_corrupt.o: mail_queue.h mark_corrupt.o: mark_corrupt.c @@ -1249,6 +1246,7 @@ mbox_open.o: ../../include/vstream.h mbox_open.o: ../../include/vstring.h mbox_open.o: deliver_flock.h mbox_open.o: dot_lockfile.h +mbox_open.o: dsn.h mbox_open.o: dsn_buf.h mbox_open.o: mbox_conf.h mbox_open.o: mbox_open.c @@ -1266,7 +1264,14 @@ mime_state.o: mail_params.h mime_state.o: mime_state.c mime_state.o: mime_state.h mime_state.o: rec_type.h +mkmap_cdb.o: ../../include/argv.h +mkmap_cdb.o: ../../include/dict.h +mkmap_cdb.o: ../../include/dict_cdb.h +mkmap_cdb.o: ../../include/mymalloc.h mkmap_cdb.o: ../../include/sys_defs.h +mkmap_cdb.o: ../../include/vbuf.h +mkmap_cdb.o: ../../include/vstream.h +mkmap_cdb.o: mkmap.h mkmap_cdb.o: mkmap_cdb.c mkmap_db.o: ../../include/argv.h mkmap_db.o: ../../include/dict.h @@ -1407,6 +1412,7 @@ pipe_command.o: ../../include/timed_wait.h pipe_command.o: ../../include/vbuf.h pipe_command.o: ../../include/vstream.h pipe_command.o: ../../include/vstring.h +pipe_command.o: dsn.h pipe_command.o: dsn_buf.h pipe_command.o: dsn_util.h pipe_command.o: mail_copy.h @@ -1453,6 +1459,7 @@ rcpt_buf.o: ../../include/vstring.h rcpt_buf.o: mail_proto.h rcpt_buf.o: rcpt_buf.c rcpt_buf.o: rcpt_buf.h +rcpt_buf.o: recipient_list.h rcpt_print.o: ../../include/attr.h rcpt_print.o: ../../include/iostuff.h rcpt_print.o: ../../include/sys_defs.h @@ -1754,7 +1761,6 @@ verify.o: ../../include/vstream.h verify.o: ../../include/vstring.h verify.o: deliver_request.h verify.o: dsn.h -verify.o: dsn_buf.h verify.o: log_adhoc.h verify.o: mail_params.h verify.o: mail_proto.h @@ -1773,7 +1779,6 @@ verify_clnt.o: ../../include/vstring.h verify_clnt.o: clnt_stream.h verify_clnt.o: deliver_request.h verify_clnt.o: dsn.h -verify_clnt.o: dsn_buf.h verify_clnt.o: mail_params.h verify_clnt.o: mail_proto.h verify_clnt.o: msg_stats.h diff --git a/postfix/src/global/bounce.h b/postfix/src/global/bounce.h index bde6451c1..31f7398d2 100644 --- a/postfix/src/global/bounce.h +++ b/postfix/src/global/bounce.h @@ -20,6 +20,7 @@ * Global library. */ #include +#include /* * Client interface. diff --git a/postfix/src/global/bounce_log.c b/postfix/src/global/bounce_log.c index 0fac7f986..d93198609 100644 --- a/postfix/src/global/bounce_log.c +++ b/postfix/src/global/bounce_log.c @@ -8,9 +8,7 @@ /* /* typedef struct { /* .in +4 -/* /* Non-null: rcpt.address, dsn.{status,action,text} */ -/* RECIPIENT rcpt; -/* DSN dsn; +/* /* No public members. */ /* .in -4 /* } BOUNCE_LOG; /* @@ -20,16 +18,14 @@ /* int flags; /* mode_t mode; /* -/* BOUNCE_LOG *bounce_log_read(bp) +/* BOUNCE_LOG *bounce_log_read(bp, rcpt, dsn) /* BOUNCE_LOG *bp; +/* RCPT_BUF *rcpt; +/* DSN_BUF *dsn; /* /* void bounce_log_rewind(bp) /* BOUNCE_LOG *bp; /* -/* BOUNCE_LOG *bounce_log_forge(rcpt, dsn) -/* RECIPIENT *rcpt; -/* DSN *dsn; -/* /* void bounce_log_close(bp) /* BOUNCE_LOG *bp; /* DESCRIPTION @@ -55,12 +51,6 @@ /* are marked as done). The result is 0 in case of success, -1 in case /* of problems. /* -/* bounce_log_forge() forges one recipient status record -/* without actually accessing a logfile. No copy is made -/* of strings with recipient or status information. -/* The result cannot be used for any logfile access operation -/* and must be disposed of by passing it to bounce_log_close(). -/* /* bounce_log_close() closes an open bounce or defer logfile and /* releases memory for the specified handle. The result is non-zero /* in case of I/O errors. @@ -75,38 +65,10 @@ /* File open flags, as with open(2). /* .IP mode /* File permissions, as with open(2). -/* .PP -/* Recipient results: -/* .IP address -/* The final recipient address in RFC 822 external form, or <> -/* in case of the null recipient address. -/* .IP dsn_orcpt -/* Null pointer or DSN original recipient. -/* .IP orig_addr -/* Null pointer or the original recipient address in RFC 822 -/* external form. -/* .IP dsn_notify -/* Zero or DSN notify flags. -/* .IP offset -/* Zero or queue file offset of recipient record. -/* .PP -/* Delivery status results: -/* .IP dsn_status -/* RFC 3463-compatible enhanced status code (digit.digits.digits). -/* .IP dsn_action -/* "delivered", "failed", "delayed" and so on. -/* .IP reason -/* The text that explains why the recipient was undeliverable. -/* .IP dsn_dtype -/* Null pointer or RFC 3464-compatible diagnostic type. -/* .IP dsn_dtext -/* Null pointer or RFC 3464-compatible diagnostic text. -/* .IP dsn_mtype -/* Null pointer or RFC 3464-compatible remote MTA type. -/* .IP dsn_mname -/* Null pointer or RFC 3464-compatible remote MTA name. -/* .PP -/* Other fields will be added as the code evolves. +/* .IP rcpt +/* Recipient buffer. The RECIPIENT member is updated. +/* .IP dsn +/* Delivery status information. The DSN member is updated. /* LICENSE /* .ad /* .fi @@ -141,8 +103,6 @@ #include #include #include -#include -#include #include /* Application-specific. */ @@ -160,10 +120,8 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, #define STREQ(x,y) (strcmp((x),(y)) == 0) /* - * TODO: peek at the first byte to see if this is an old-style log - * (: text) or a new-style extensible log with multiple - * attributes per recipient. That would not help during a transition from - * old to new style, where one can expect to find mixed format files. + * Logfiles may contain a mixture of old-style (: text) and + * new-style entries with multiple attributes per recipient. * * Kluge up default DSN status and action for old-style logfiles. */ @@ -173,8 +131,6 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp)); bp->fp = fp; bp->buf = vstring_alloc(100); - bp->rcpt_buf = rcpb_create(); - bp->dsn_buf = dsb_create(); if (STREQ(queue_name, MAIL_QUEUE_DEFER)) { bp->compat_status = mystrdup("4.0.0"); bp->compat_action = mystrdup("delayed"); @@ -188,7 +144,8 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, /* bounce_log_read - read one record from bounce log file */ -BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) +BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf, + DSN_BUF *dsn_buf) { char *recipient; char *text; @@ -202,24 +159,11 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) #define FOUND 1 /* in logfile entry */ /* - * Initialize. See also DSN_FROM_DSN_BUF() and bounce_log_forge() for - * null and non-null fields. + * Initialize. */ state = START; - bp->rcpt.address = "(recipient address unavailable)"; - bp->dsn.status = bp->compat_status; - bp->dsn.action = bp->compat_action; - bp->dsn.reason = "(description unavailable)"; - - bp->rcpt.orig_addr = 0; - bp->rcpt.dsn_orcpt = 0; - bp->rcpt.dsn_notify = 0; - bp->rcpt.offset = 0; - - bp->dsn.dtype = 0; - bp->dsn.dtext = 0; - bp->dsn.mtype = 0; - bp->dsn.mname = 0; + rcpb_reset(rcpt_buf); + dsb_reset(dsn_buf); /* * Support mixed logfile formats to make migration easier. The same file @@ -227,7 +171,9 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) * backwards compatibility, we even have old format followed by new * format within the same logfile entry! */ - while ((vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) { + for (;;) { + if ((vstring_get_nonl(bp->buf, bp->fp) == VSTREAM_EOF)) + return (0); /* * Logfile entries are separated by blank lines. Even the old ad-hoc @@ -237,7 +183,7 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) */ if (STR(bp->buf)[0] == 0) { if (state == FOUND) - return (bp); + break; state = START; continue; } @@ -259,7 +205,7 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) char *name; char *value; long offset; - long notify; + int notify; /* * Split into name and value. @@ -273,51 +219,33 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) * Save attribute value. */ if (STREQ(name, MAIL_ATTR_RECIP)) { - bp->rcpt.address = - STR(vstring_strcpy(bp->rcpt_buf->address, *value ? - value : "(MAILER-DAEMON)")); + vstring_strcpy(rcpt_buf->address, *value ? + value : "(MAILER-DAEMON)"); } else if (STREQ(name, MAIL_ATTR_ORCPT)) { - bp->rcpt.orig_addr = - STR(vstring_strcpy(bp->rcpt_buf->orig_addr, *value ? - value : "(MAILER-DAEMON)")); + vstring_strcpy(rcpt_buf->orig_addr, *value ? + value : "(MAILER-DAEMON)"); } else if (STREQ(name, MAIL_ATTR_DSN_ORCPT)) { - if (*value) - bp->rcpt.dsn_orcpt = - STR(vstring_strcpy(bp->rcpt_buf->dsn_orcpt, value)); + vstring_strcpy(rcpt_buf->dsn_orcpt, value); } else if (STREQ(name, MAIL_ATTR_DSN_NOTIFY)) { if ((notify = atoi(value)) > 0 && DSN_NOTIFY_OK(notify)) - bp->rcpt.dsn_notify = notify; + rcpt_buf->dsn_notify = notify; } else if (STREQ(name, MAIL_ATTR_OFFSET)) { if ((offset = atol(value)) > 0) - bp->rcpt.offset = offset; + rcpt_buf->offset = offset; } else if (STREQ(name, MAIL_ATTR_DSN_STATUS)) { - if (*value) - bp->dsn.status = - STR(vstring_strcpy(bp->dsn_buf->status, value)); + vstring_strcpy(dsn_buf->status, value); } else if (STREQ(name, MAIL_ATTR_DSN_ACTION)) { - if (*value) - bp->dsn.action = - STR(vstring_strcpy(bp->dsn_buf->action, value)); + vstring_strcpy(dsn_buf->action, value); } else if (STREQ(name, MAIL_ATTR_DSN_DTYPE)) { - if (*value) - bp->dsn.dtype = - STR(vstring_strcpy(bp->dsn_buf->dtype, value)); + vstring_strcpy(dsn_buf->dtype, value); } else if (STREQ(name, MAIL_ATTR_DSN_DTEXT)) { - if (*value) - bp->dsn.dtext = - STR(vstring_strcpy(bp->dsn_buf->dtext, value)); + vstring_strcpy(dsn_buf->dtext, value); } else if (STREQ(name, MAIL_ATTR_DSN_MTYPE)) { - if (*value) - bp->dsn.mtype = - STR(vstring_strcpy(bp->dsn_buf->mtype, value)); + vstring_strcpy(dsn_buf->mtype, value); } else if (STREQ(name, MAIL_ATTR_DSN_MNAME)) { - if (*value) - bp->dsn.mname = - STR(vstring_strcpy(bp->dsn_buf->mname, value)); + vstring_strcpy(dsn_buf->mname, value); } else if (STREQ(name, MAIL_ATTR_WHY)) { - if (*value) - bp->dsn.reason = - STR(vstring_strcpy(bp->dsn_buf->reason, value)); + vstring_strcpy(dsn_buf->reason, value); } else { msg_warn("%s: unknown attribute name: %s, ignored", VSTREAM_PATH(bp->fp), name); @@ -340,9 +268,8 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) continue; } *cp = 0; - vstring_strcpy(bp->rcpt_buf->address, *recipient ? + vstring_strcpy(rcpt_buf->address, *recipient ? recipient : "(MAILER-DAEMON)"); - bp->rcpt.address = STR(bp->rcpt_buf->address); /* * Find the text that explains why mail was not deliverable. @@ -350,69 +277,26 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) text = cp + 2; while (*text && ISSPACE(*text)) text++; - vstring_strcpy(bp->dsn_buf->reason, text); - if (*text) - bp->dsn.reason = STR(bp->dsn_buf->reason); + vstring_strcpy(dsn_buf->reason, text); } - return (0); -} - -/* bounce_log_forge - forge one recipient status record */ - -BOUNCE_LOG *bounce_log_forge(RECIPIENT *rcpt, DSN *dsn) -{ - BOUNCE_LOG *bp; - - /* - * Create a partial record. No point copying information that doesn't - * need to be. - */ - bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp)); - bp->fp = 0; - bp->buf = 0; - bp->rcpt_buf = 0; - bp->dsn_buf = 0; - bp->compat_status = 0; - bp->compat_action = 0; - - bp->rcpt = *rcpt; - bp->dsn = *dsn; - - /* - * Finalize. See also DSN_FROM_DSN_BUF() and bounce_log_read() for null - * and non-null fields. - */ -#define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0) -#define EMPTY_STRING(s) ((s) != 0 && *(s) == 0) /* - * Replace null pointers and empty strings by place holders. + * Specify place holders for missing fields. See also DSN_FROM_DSN_BUF() + * and RECIPIENT_FROM_RCPT_BUF() for null and non-null fields. */ - if (bp->rcpt.address == 0) - bp->rcpt.address = "(recipient address unavailable)"; - if (NULL_OR_EMPTY(bp->dsn.status)) - bp->dsn.status = "(unavailable)"; - if (NULL_OR_EMPTY(bp->dsn.action)) - bp->dsn.action = "(unavailable)"; - if (NULL_OR_EMPTY(bp->dsn.reason)) - bp->dsn.reason = "(description unavailable)"; - - /* - * Replace empty strings by null pointers. - */ - if (EMPTY_STRING(bp->rcpt.orig_addr)) - bp->rcpt.orig_addr = 0; - if (EMPTY_STRING(bp->rcpt.dsn_orcpt)) - bp->rcpt.dsn_orcpt = 0; - - if (EMPTY_STRING(bp->dsn.dtype)) - bp->dsn.dtype = 0; - if (EMPTY_STRING(bp->dsn.dtext)) - bp->dsn.dtext = 0; - if (EMPTY_STRING(bp->dsn.mtype)) - bp->dsn.mtype = 0; - if (EMPTY_STRING(bp->dsn.mname)) - bp->dsn.mname = 0; +#define BUF_NODATA(buf) (STR(buf)[0] == 0) +#define BUF_ASSIGN(buf, text) vstring_strcpy((buf), (text)) + + if (BUF_NODATA(rcpt_buf->address)) + BUF_ASSIGN(rcpt_buf->address, "(recipient address unavailable)"); + if (BUF_NODATA(dsn_buf->status)) + BUF_ASSIGN(dsn_buf->status, bp->compat_status); + if (BUF_NODATA(dsn_buf->action)) + BUF_ASSIGN(dsn_buf->action, bp->compat_action); + if (BUF_NODATA(dsn_buf->reason)) + BUF_ASSIGN(dsn_buf->reason, "(description unavailable)"); + (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf); + (void) DSN_FROM_DSN_BUF(dsn_buf); return (bp); } @@ -422,20 +306,10 @@ int bounce_log_close(BOUNCE_LOG *bp) { int ret; - if (bp->fp) - ret = vstream_fclose(bp->fp); - else - ret = 0; - if (bp->buf) - vstring_free(bp->buf); - if (bp->rcpt_buf) - rcpb_free(bp->rcpt_buf); - if (bp->dsn_buf) - dsb_free(bp->dsn_buf); - if (bp->compat_status) - myfree(bp->compat_status); - if (bp->compat_action) - myfree(bp->compat_action); + ret = vstream_fclose(bp->fp); + vstring_free(bp->buf); + myfree(bp->compat_status); + myfree(bp->compat_action); myfree((char *) bp); return (ret); diff --git a/postfix/src/global/bounce_log.h b/postfix/src/global/bounce_log.h index 235772ed3..03b78b2c4 100644 --- a/postfix/src/global/bounce_log.h +++ b/postfix/src/global/bounce_log.h @@ -23,28 +23,20 @@ #include #include #include -#include /* * External interface. */ typedef struct { - /* Private. */ VSTREAM *fp; /* open file */ VSTRING *buf; /* I/O buffer */ - RCPT_BUF *rcpt_buf; /* recipient info */ - DSN_BUF *dsn_buf; /* delivery status */ char *compat_status; /* old logfile compatibility */ char *compat_action; /* old logfile compatibility */ - /* Public. */ - RECIPIENT rcpt; /* recipient info */ - DSN dsn; /* delivery status */ } BOUNCE_LOG; extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, mode_t); -extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *); +extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *); extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *); -extern BOUNCE_LOG *bounce_log_forge(RECIPIENT *, DSN *); extern int bounce_log_close(BOUNCE_LOG *); #define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET) diff --git a/postfix/src/global/deliver_pass.c b/postfix/src/global/deliver_pass.c index 91675b495..8938e6a88 100644 --- a/postfix/src/global/deliver_pass.c +++ b/postfix/src/global/deliver_pass.c @@ -69,6 +69,7 @@ #include #include #include +#include #define DELIVER_PASS_DEFER 1 #define DELIVER_PASS_UNKNOWN 2 @@ -116,12 +117,10 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request, ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, request->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, request->sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context, - ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, rcpt->offset, - ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt, - ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify, - ATTR_TYPE_STR, MAIL_ATTR_ORCPT, rcpt->orig_addr, - ATTR_TYPE_STR, MAIL_ATTR_RECIP, rcpt->address, - ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0, + ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, 1, + ATTR_TYPE_END); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, ATTR_TYPE_END); if (vstream_fflush(stream)) { @@ -192,17 +191,13 @@ int deliver_pass(const char *class, const char *service, */ if (deliver_pass_initial_reply(stream) != 0 || deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) { - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable"); + (void) DSN_SIMPLE(&dsn, "4.3.0", "mail transport unavailable"); status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, "none", &dsn); } else if ((status = deliver_pass_final_reply(stream, dsb)) == DELIVER_PASS_UNKNOWN) { - DSN_SMTP(&dsn, "4.3.0", - "451 unknown mail transport error", - "unknown mail transport error"); + (void) DSN_SIMPLE(&dsn, "4.3.0", "unknown mail transport error"); status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, "none", &dsn); @@ -227,6 +222,11 @@ int deliver_pass_all(const char *class, const char *service, RECIPIENT *rcpt; int status = 0; + /* + * XXX We should find out if the target transport can handle + * multi-recipient requests. Unfortunately such code is hard to test, + * rarely used, and therefore will be buggy. + */ list = &request->rcpt_list; for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) status |= deliver_pass(class, service, request, rcpt); diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index 1391e5d7c..029d2fdef 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -112,6 +112,7 @@ #include "dsn.h" #include "dsn_print.h" #include "deliver_request.h" +#include "rcpt_buf.h" /* deliver_request_initial - send initial status code */ @@ -143,13 +144,12 @@ static int deliver_request_final(VSTREAM *stream, DELIVER_REQUEST *request, { DSN *hop_status; int err; + /* XXX This DSN structure initialization bypasses integrity checks. */ static DSN dummy_dsn = {"", "", "", "", "", "", ""}; /* * Send the status and the optional reason. */ -#define STRING_OR_EMPTY(s) ((s) ? (s) : "") - if ((hop_status = request->hop_status) == 0) hop_status = &dummy_dsn; if (msg_verbose) @@ -185,8 +185,6 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) static VSTRING *queue_id; static VSTRING *nexthop; static VSTRING *encoding; - static VSTRING *dsn_orcpt; - static VSTRING *orig_addr; static VSTRING *address; static VSTRING *client_name; static VSTRING *client_addr; @@ -197,9 +195,9 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) static VSTRING *sasl_sender; static VSTRING *rewrite_context; static VSTRING *dsn_envid; - long offset; + static RCPT_BUF *rcpt_buf; + int rcpt_count; int dsn_ret; - int dsn_notify; /* * Initialize. For some reason I wanted to allow for multiple instances @@ -211,9 +209,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) queue_id = vstring_alloc(10); nexthop = vstring_alloc(10); encoding = vstring_alloc(10); - dsn_orcpt = vstring_alloc(10); - orig_addr = vstring_alloc(10); - address = vstring_alloc(10); + address = vstring_alloc(10); client_name = vstring_alloc(10); client_addr = vstring_alloc(10); client_proto = vstring_alloc(10); @@ -223,13 +219,14 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) sasl_sender = vstring_alloc(10); rewrite_context = vstring_alloc(10); dsn_envid = vstring_alloc(10); + rcpt_buf = rcpb_create(); } /* * Extract the queue file name, data offset, and sender address. Abort * the conversation when they send bad information. */ - if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, + if (attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request->flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, @@ -249,7 +246,8 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, rewrite_context, - ATTR_TYPE_END) != 19) { + ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, &rcpt_count, + ATTR_TYPE_END) != 20) { msg_warn("%s: error receiving common attributes", myname); return (-1); } @@ -281,28 +279,18 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) * Extract the recipient offset and address list. Skip over any * attributes from the sender that we do not understand. */ - for (;;) { - if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, - ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset, + while (rcpt_count-- > 0) { + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, ATTR_TYPE_END) != 1) { - msg_warn("%s: error receiving offset attribute", myname); - return (-1); - } - if (offset == 0) - break; - if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, - ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, dsn_orcpt, - ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, &dsn_notify, - ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_addr, - ATTR_TYPE_STR, MAIL_ATTR_RECIP, address, - ATTR_TYPE_END) != 4) { msg_warn("%s: error receiving recipient attributes", myname); return (-1); } - recipient_list_add(&request->rcpt_list, offset, - vstring_str(dsn_orcpt), dsn_notify, - vstring_str(orig_addr), - vstring_str(address)); + recipient_list_add(&request->rcpt_list, rcpt_buf->offset, + vstring_str(rcpt_buf->dsn_orcpt), + rcpt_buf->dsn_notify, + vstring_str(rcpt_buf->orig_addr), + vstring_str(rcpt_buf->address)); } if (request->rcpt_list.len <= 0) { msg_warn("%s: no recipients in delivery request for destination %s", diff --git a/postfix/src/global/dsn.c b/postfix/src/global/dsn.c index b233f56b0..aa78c3b9c 100644 --- a/postfix/src/global/dsn.c +++ b/postfix/src/global/dsn.c @@ -8,17 +8,17 @@ /* /* typedef struct { /* .in +4 -/* char *status; /* RFC 3463 status */ -/* char *action; /* null or RFC 3464 action */ -/* char *reason; /* human-readable text */ -/* char *dtype; /* null or diagnostic type */ -/* char *dtext; /* null or diagnostic code */ -/* char *mtype; /* null or MTA type */ -/* char *mname; /* null or remote MTA */ +/* const char *status; /* RFC 3463 status */ +/* const char *action; /* null or RFC 3464 action */ +/* const char *reason; /* human-readable text */ +/* const char *dtype; /* null or diagnostic type */ +/* const char *dtext; /* null or diagnostic code */ +/* const char *mtype; /* null or MTA type */ +/* const char *mname; /* null or remote MTA */ /* .in -4 /* } DSN; /* -/* DSN *create(status, action, reason, dtype, dtext, mtype, mname) +/* DSN *create(status, action, reason, dtype, dtext, mtype, mname) /* const char *status; /* const char *action; /* const char *reason; @@ -27,11 +27,15 @@ /* const char *mtype; /* const char *mname; /* -/* DSN *copy(dsn) -/* DSN *dsn; +/* DSN *DSN_COPY(dsn) +/* DSN *dsn; /* -/* DSN *DSN_ASSIGN(dsn, status, action, reason, dtype, dtext, mtype, mname) -/* DSN *dsn; +/* void dsn_free(dsn) +/* DSN *dsn; +/* +/* DSN *DSN_ASSIGN(dsn, status, action, reason, dtype, dtext, +/* mtype, mname) +/* DSN *dsn; /* const char *status; /* const char *action; /* const char *reason; @@ -40,21 +44,11 @@ /* const char *mtype; /* const char *mname; /* -/* DSN *DSN_SIMPLE(dsn, status, action, reason) -/* DSN *dsn; +/* DSN *DSN_SIMPLE(dsn, status, action, reason) +/* DSN *dsn; /* const char *status; /* const char *action; /* const char *reason; -/* -/* DSN *DSN_SMTP(dsn, status, action, smtp_dtext, reason) -/* DSN *dsn; -/* const char *status; -/* const char *action; -/* const char *smtp_dtext; -/* const char *reason; -/* -/* void dsn_free(dsn) -/* DSN *dsn; /* DESCRIPTION /* This module maintains delivery error information. For a /* description of structure field members see "Arguments" @@ -75,10 +69,8 @@ /* for stack-based short-lived storage. /* /* DSN_SIMPLE() takes the minimally required subset of all the -/* parameters and resets the rest to zero. -/* -/* DSN_SMTP() handles the common case of an SMTP-type -/* diagnostic code that was generated by the local MTA. +/* attributes and sets the rest to empty strings. +/* This is a wrapper around the DSN_ASSIGN() macro. /* /* Arguments: /* .IP reason @@ -88,8 +80,8 @@ /* .IP status /* Enhanced status code as specified in RFC 3463. /* .IP action -/* Action as defined in RFC 3464. If null, a default action -/* is chosen. +/* DSN_NO_ACTION, empty string, or action as defined in RFC 3464. +/* If no action is specified, a default action is chosen. /* .IP dtype /* DSN_NO_DTYPE, empty string, or diagnostic code type as /* specified in RFC 3464. @@ -102,7 +94,7 @@ /* DSN_NO_MNAME, empty string, or remote MTA as specified in /* RFC 3464. /* DIAGNOSTICS -/* Panic: null status or reason. +/* Panic: null or empty status or reason. /* Fatal: out of memory. /* LICENSE /* .ad @@ -140,8 +132,13 @@ DSN *dsn_create(const char *status, const char *action, const char *reason, dsn = (DSN *) mymalloc(sizeof(*dsn)); /* - * Status and reason must not be null. Other members may be null pointers - * or empty strings. Null/empty members are represented as null pointers. + * Status and reason must not be empty. Other members may be empty + * strings. + * + * Early implementations represented unavailable information with null + * pointers. This resulted in code that was difficult to maintain. We now + * use empty strings instead. For safety sake we keep the null pointer + * test for input, but we always convert to empty string on output. */ #define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0) @@ -151,7 +148,7 @@ DSN *dsn_create(const char *status, const char *action, const char *reason, dsn->status = mystrdup(status); if (NULL_OR_EMPTY(action)) - dsn->action = 0; + dsn->action = mystrdup(""); else dsn->action = mystrdup(action); @@ -161,15 +158,15 @@ DSN *dsn_create(const char *status, const char *action, const char *reason, dsn->reason = mystrdup(reason); if (NULL_OR_EMPTY(dtype) || NULL_OR_EMPTY(dtext)) { - dsn->dtype = 0; - dsn->dtext = 0; + dsn->dtype = mystrdup(""); + dsn->dtext = mystrdup(""); } else { dsn->dtype = mystrdup(dtype); dsn->dtext = mystrdup(dtext); } if (NULL_OR_EMPTY(mtype) || NULL_OR_EMPTY(mname)) { - dsn->mtype = 0; - dsn->mname = 0; + dsn->mtype = mystrdup(""); + dsn->mname = mystrdup(""); } else { dsn->mtype = mystrdup(mtype); dsn->mname = mystrdup(mname); @@ -182,16 +179,11 @@ DSN *dsn_create(const char *status, const char *action, const char *reason, void dsn_free(DSN *dsn) { myfree((char *) dsn->status); - if (dsn->action) - myfree((char *) dsn->action); + myfree((char *) dsn->action); myfree((char *) dsn->reason); - if (dsn->dtype) - myfree((char *) dsn->dtype); - if (dsn->dtext) - myfree((char *) dsn->dtext); - if (dsn->mtype) - myfree((char *) dsn->mtype); - if (dsn->mname) - myfree((char *) dsn->mname); + myfree((char *) dsn->dtype); + myfree((char *) dsn->dtext); + myfree((char *) dsn->mtype); + myfree((char *) dsn->mname); myfree((char *) dsn); } diff --git a/postfix/src/global/dsn.h b/postfix/src/global/dsn.h index 333545f4b..bf49dcb16 100644 --- a/postfix/src/global/dsn.h +++ b/postfix/src/global/dsn.h @@ -11,11 +11,6 @@ /* DESCRIPTION /* .nf - /* - * Global library. - */ -#include - /* * External interface. */ @@ -29,19 +24,6 @@ typedef struct { const char *mname; /* Null / RFC 3464 remote MTA */ } DSN; - /* - * Ditto, without const poisoning. - */ -typedef struct { - char *status; /* RFC 3463 status */ - char *action; /* Null / RFC 3464 action */ - char *reason; /* descriptive reason */ - char *dtype; /* Null / RFC 3464 diagnostic type */ - char *dtext; /* Null / RFC 3464 diagnostic code */ - char *mtype; /* Null / RFC 3464 MTA type */ - char *mname; /* Null / RFC 3464 remote MTA */ -} DSN_VAR; - extern DSN *dsn_create(const char *, const char *, const char *, const char *, const char *, const char *, const char *); extern void dsn_free(DSN *); @@ -58,55 +40,36 @@ extern void dsn_free(DSN *); #define DSN_SIMPLE(dsn, _status, _reason) \ (((dsn)->status = (_status)), \ - ((dsn)->action = 0), \ + ((dsn)->action = DSN_NO_ACTION), \ ((dsn)->reason = (_reason)), \ - ((dsn)->dtype = 0), \ - ((dsn)->dtext = 0), \ - ((dsn)->mtype = 0), \ - ((dsn)->mname = 0), \ + ((dsn)->dtype = DSN_NO_DTYPE), \ + ((dsn)->dtext = DSN_NO_DTEXT), \ + ((dsn)->mtype = DSN_NO_MTYPE), \ + ((dsn)->mname = DSN_NO_MNAME), \ (dsn)) -#define DSN_SMTP(dsn, _status, _dtext, _reason) \ - (((dsn)->status = (_status)), \ - ((dsn)->action = 0), \ - ((dsn)->reason = (_reason)), \ - ((dsn)->dtype = DSB_DTYPE_SMTP), \ - ((dsn)->dtext = _dtext), \ - ((dsn)->mtype = 0), \ - ((dsn)->mname = 0), \ - (dsn)) - -#define DSN_NO_DTYPE 0 -#define DSN_NO_DTEXT 0 -#define DSN_NO_MTYPE 0 -#define DSN_NO_MNAME 0 +#define DSN_NO_ACTION "" +#define DSN_NO_DTYPE "" +#define DSN_NO_DTEXT "" +#define DSN_NO_MTYPE "" +#define DSN_NO_MNAME "" /* - * In order to save space in the queue manager, some DSN fields may be null - * pointers so that we don't waste memory making copies of empty strings. In - * addition, sanity requires that the status and reason are never null or + * Early implementations represented unavailable information with null + * pointers. This resulted in code that is hard to maintain. We now use + * empty strings instead. This does not waste precious memory as long as we + * can represent empty strings efficiently by collapsing them. + * + * The only restriction left is that the status and reason are never null or * empty; this is enforced by dsn_create() which is invoked by DSN_COPY(). - * This complicates the bounce_log(3) and bounce(8) daemons, as well as the - * server reply parsing code in the smtp(8) and lmtp(8) clients. They must - * be able to cope with null pointers, and they must never supply empty - * strings for the required fields. + * This complicates the server reply parsing code in the smtp(8) and lmtp(8) + * clients. they must never supply empty strings for these required fields. */ #define DSN_COPY(dsn) \ dsn_create((dsn)->status, (dsn)->action, (dsn)->reason, \ (dsn)->dtype, (dsn)->dtext, \ (dsn)->mtype, (dsn)->mname) -#define DSN_STRING_OR_NULL(s) ((s)[0] ? (s) : 0) - -#define DSN_FROM_DSN_BUF(dsn, dsb) \ - DSN_ASSIGN((dsn), vstring_str((dsb)->status), \ - DSN_STRING_OR_NULL(vstring_str((dsb)->action)), \ - vstring_str((dsb)->reason), \ - DSN_STRING_OR_NULL(vstring_str((dsb)->dtype)), \ - DSN_STRING_OR_NULL(vstring_str((dsb)->dtext)), \ - DSN_STRING_OR_NULL(vstring_str((dsb)->mtype)), \ - DSN_STRING_OR_NULL(vstring_str((dsb)->mname))) - /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/dsn_buf.c b/postfix/src/global/dsn_buf.c index c80bc6250..c3c3a7e30 100644 --- a/postfix/src/global/dsn_buf.c +++ b/postfix/src/global/dsn_buf.c @@ -1,6 +1,6 @@ /*++ /* NAME -/* dsbuf 3 +/* dsn_buf 3 /* SUMMARY /* delivery status buffer /* SYNOPSIS @@ -8,20 +8,23 @@ /* /* typedef struct { /* .in +4 +/* /* Convenience member */ +/* DSN dsn; /* light-weight, dsn(3) */ +/* /* Formal members... */ /* VSTRING *status; /* RFC 3463 */ /* VSTRING *action; /* RFC 3464 */ /* VSTRING *mtype; /* dns */ /* VSTRING *mname; /* host or domain */ /* VSTRING *dtype; /* smtp, x-unix */ -/* int dcode; /* RFC 2821, sysexits.h */ /* VSTRING *dtext; /* RFC 2821, sysexits.h */ +/* /* Informal members... */ /* VSTRING *reason; /* informal text */ /* .in -4 /* } DSN_BUF; /* /* DSN_BUF *dsb_create(void) /* -/* DSN_BUF *dsb_update(dsb, status, action, mtype, mname, dtype, dcode, +/* DSN_BUF *dsb_update(dsb, status, action, mtype, mname, dtype, /* dtext, reason_fmt, ...) /* DSN_BUF *dsb; /* const char *status; @@ -29,7 +32,6 @@ /* const char *mtype; /* const char *mname; /* const char *dtype; -/* int dcode; /* const char *dtext; /* const char *reason_fmt; /* @@ -38,17 +40,12 @@ /* const char *status; /* const char *reason_fmt; /* -/* DSN_BUF *dsb_unix(dsb, status, dcode, dtext, reason_fmt, ...) +/* DSN_BUF *dsb_unix(dsb, status, dtext, reason_fmt, ...) /* DSN_BUF *dsb; /* const char *status; /* const char *reason_fmt; /* -/* DSN_BUF *dsb_smtp(dsb, status, dcode, dtext, reason_fmt, ...) -/* DSN_BUF *dsb; -/* const char *status; -/* const char *reason_fmt; -/* -/* DSN_BUF *dsb_formal(dsb, status, action, mtype, mname, dtype, dcode, +/* DSN_BUF *dsb_formal(dsb, status, action, mtype, mname, dtype, /* dtext) /* DSN_BUF *dsb; /* const char *status; @@ -56,7 +53,6 @@ /* const char *mtype; /* const char *mname; /* const char *dtype; -/* int dcode; /* const char *dtext; /* /* DSN_BUF *dsb_status(dsb, status) @@ -64,12 +60,17 @@ /* const char *status; /* /* void dsb_reset(dsb) +/* DSN_BUF *dsb; /* /* void dsb_free(dsb) +/* DSN_BUF *dsb; +/* +/* DSN *DSN_FROM_DSN_BUF(dsb) +/* DSN_BUF *dsb; /* DESCRIPTION /* This module implements a simple to update delivery status -/* buffer for Postfix-internal use. Typically it is populated -/* in course of delivery attempt, and then formatted into a +/* buffer for Postfix-internal use. Typically it is filled in +/* the course of delivery attempt, and then formatted into a /* DSN structure for external notification. /* /* dsb_create() creates initialized storage for formal RFC 3464 @@ -84,8 +85,6 @@ /* text, and informal text, sets the diagnostic type to UNIX, /* and resets all other fields to defaults. /* -/* dsb_smtp() does the same for SMTP style diagnostics. -/* /* dsb_formal() updates all fields except the informal text. /* /* dsb_status() updates the status field, and resets all @@ -97,6 +96,11 @@ /* dsb_free() recycles the storage that was allocated by /* dsb_create(), and so on. /* +/* DSN_FROM_DSN_BUF() populates the DSN member with a shallow +/* copy of the contents of the formal and informal fields, and +/* returns a pointer to the DSN member. This is typically used +/* for external reporting. +/* /* Arguments: /* .IP dsb /* Delivery status buffer. @@ -108,24 +112,20 @@ /* matter here are "expanded" and "relayed"; all other values /* are already implied by the context. /* .IP mtype +/* The remote MTA type. /* The only valid type is DSB_MTYPE_DNS. The macro DSB_SKIP_RMTA /* conveniently expands into a null argument list for the /* remote MTA type and name. /* .IP mname /* Remote MTA name. /* .IP dtype +/* The reply type. /* DSB_DTYPE_SMTP or DSB_DTYPE_UNIX. The macro DSB_SKIP_REPLY /* conveniently expands into a null argument list for the reply -/* type, code and text. -/* .IP dcode -/* Numerical reply code. The reply code is reset when dtype is -/* DSB_SKIP_REPLY. +/* type and text. /* .IP dtext /* The reply text. The reply text is reset when dtype is /* DSB_SKIP_REPLY. -/* .IP reply_fmt -/* The reply text format. The reply text is reset when type -/* is DSB_SKIP_REPLY. /* .IP reason_fmt /* The informal reason format. /* SEE ALSO @@ -179,7 +179,6 @@ DSN_BUF *dsb_create(void) dsb->mtype = vstring_alloc(10); dsb->mname = vstring_alloc(100); dsb->dtype = vstring_alloc(10); - dsb->dcode = 0; dsb->dtext = vstring_alloc(100); dsb->reason = vstring_alloc(100); @@ -200,13 +199,22 @@ void dsb_free(DSN_BUF *dsb) myfree((char *) dsb); } + /* + * Initial versions of this code represented unavailable inputs with null + * pointers, which produced fragile and hard to maintain code. The current + * code uses empty strings instead of null pointers. + * + * For safety we keep the test for null pointers in input. It's cheap. + */ #define DSB_TRUNCATE(s) (STR(s)[0] = 0) +#define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0) + #define DSB_ACTION(dsb, stat, act) \ - vstring_strcpy((dsb)->action, (act) && *(act) ? (act) : "") + vstring_strcpy((dsb)->action, !NULL_OR_EMPTY(act) ? (act) : "") #define DSB_MTA(dsb, type, name) do { \ - if ((type) == 0) { \ + if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(name)) { \ DSB_TRUNCATE((dsb)->mtype); \ DSB_TRUNCATE((dsb)->mname); \ } else { \ @@ -215,11 +223,21 @@ void dsb_free(DSN_BUF *dsb) } \ } while (0) +#define DSB_DIAG(dsb, type, text) do { \ + if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(text)) { \ + DSB_TRUNCATE((dsb)->dtype); \ + DSB_TRUNCATE((dsb)->dtext); \ + } else { \ + vstring_strcpy((dsb)->dtype, (type)); \ + vstring_strcpy((dsb)->dtext, (text)); \ + } \ +} while (0) + /* dsb_update - update formal attributes and informal text */ DSN_BUF *dsb_update(DSN_BUF *dsb, const char *status, const char *action, const char *mtype, const char *mname, - const char *dtype, int dcode, const char *dtext, + const char *dtype, const char *dtext, const char *format,...) { va_list ap; @@ -227,15 +245,7 @@ DSN_BUF *dsb_update(DSN_BUF *dsb, const char *status, const char *action, vstring_strcpy(dsb->status, status); DSB_ACTION(dsb, status, action); DSB_MTA(dsb, mtype, mname); - if (dtype == 0) { - DSB_TRUNCATE(dsb->dtype); - dsb->dcode = 0; - DSB_TRUNCATE(dsb->dtext); - } else { - vstring_strcpy(dsb->dtype, dtype); - dsb->dcode = dcode; - vstring_strcpy(dsb->dtext, dtext); - } + DSB_DIAG(dsb, dtype, dtext); va_start(ap, format); vstring_vsprintf(dsb->reason, format, ap); va_end(ap); @@ -243,7 +253,7 @@ DSN_BUF *dsb_update(DSN_BUF *dsb, const char *status, const char *action, return (dsb); } -/* dsb_simple - update status and text */ +/* dsb_simple - update status and informal text */ DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...) { @@ -254,7 +264,6 @@ DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...) DSB_TRUNCATE(dsb->mtype); DSB_TRUNCATE(dsb->mname); DSB_TRUNCATE(dsb->dtype); - dsb->dcode = 0; DSB_TRUNCATE(dsb->dtext); va_start(ap, format); vstring_vsprintf(dsb->reason, format, ap); @@ -263,9 +272,9 @@ DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...) return (dsb); } -/* dsb_unix - update status, UNIX diagnostic and text */ +/* dsb_unix - update status, UNIX diagnostic and informal text */ -DSN_BUF *dsb_unix(DSN_BUF *dsb, const char *status, int dcode, +DSN_BUF *dsb_unix(DSN_BUF *dsb, const char *status, const char *dtext, const char *format,...) { va_list ap; @@ -275,28 +284,6 @@ DSN_BUF *dsb_unix(DSN_BUF *dsb, const char *status, int dcode, DSB_TRUNCATE(dsb->mtype); DSB_TRUNCATE(dsb->mname); vstring_strcpy(dsb->dtype, DSB_DTYPE_UNIX); - dsb->dcode = dcode; - vstring_strcpy(dsb->dtext, dtext); - va_start(ap, format); - vstring_vsprintf(dsb->reason, format, ap); - va_end(ap); - - return (dsb); -} - -/* dsb_smtp - update status, SMTP diagnostic and text */ - -DSN_BUF *dsb_smtp(DSN_BUF *dsb, const char *status, int dcode, - const char *dtext, const char *format,...) -{ - va_list ap; - - vstring_strcpy(dsb->status, status); - DSB_TRUNCATE(dsb->action); - DSB_TRUNCATE(dsb->mtype); - DSB_TRUNCATE(dsb->mname); - vstring_strcpy(dsb->dtype, DSB_DTYPE_SMTP); - dsb->dcode = dcode; vstring_strcpy(dsb->dtext, dtext); va_start(ap, format); vstring_vsprintf(dsb->reason, format, ap); @@ -309,21 +296,12 @@ DSN_BUF *dsb_smtp(DSN_BUF *dsb, const char *status, int dcode, DSN_BUF *dsb_formal(DSN_BUF *dsb, const char *status, const char *action, const char *mtype, const char *mname, - const char *dtype, int dcode, - const char *dtext) + const char *dtype, const char *dtext) { vstring_strcpy(dsb->status, status); DSB_ACTION(dsb, status, action); DSB_MTA(dsb, mtype, mname); - if (dtype == 0) { - DSB_TRUNCATE(dsb->dtype); - dsb->dcode = 0; - DSB_TRUNCATE(dsb->dtext); - } else { - vstring_strcpy(dsb->dtype, dtype); - dsb->dcode = dcode; - vstring_strcpy(dsb->dtext, dtext); - } + DSB_DIAG(dsb, dtype, dtext); return (dsb); } @@ -336,7 +314,6 @@ DSN_BUF *dsb_status(DSN_BUF *dsb, const char *status) DSB_TRUNCATE(dsb->mtype); DSB_TRUNCATE(dsb->mname); DSB_TRUNCATE(dsb->dtype); - dsb->dcode = 0; DSB_TRUNCATE(dsb->dtext); return (dsb); } @@ -350,7 +327,6 @@ void dsb_reset(DSN_BUF *dsb) DSB_TRUNCATE(dsb->mtype); DSB_TRUNCATE(dsb->mname); DSB_TRUNCATE(dsb->dtype); - dsb->dcode = 0; DSB_TRUNCATE(dsb->dtext); DSB_TRUNCATE(dsb->reason); } diff --git a/postfix/src/global/dsn_buf.h b/postfix/src/global/dsn_buf.h index 17dd7fc38..b38f46d0d 100644 --- a/postfix/src/global/dsn_buf.h +++ b/postfix/src/global/dsn_buf.h @@ -3,9 +3,9 @@ /*++ /* NAME -/* dsbuf 3h +/* dsn_buf 3h /* SUMMARY -/* DSN support routines +/* delivery status buffer /* SYNOPSIS /* #include /* DESCRIPTION @@ -16,17 +16,24 @@ */ #include + /* + * Global library. + */ +#include + /* * Delivery status buffer, Postfix-internal form. */ typedef struct { + DSN dsn; /* convenience */ + /* Formal members. */ VSTRING *status; /* RFC 3463 */ VSTRING *action; /* RFC 3464 */ VSTRING *mtype; /* null or remote MTA type */ VSTRING *mname; /* null or remote MTA name */ - VSTRING *dtype; /* null, smtp, x-unix-command */ - int dcode; /* null, RFC 2821, sysexits.h */ + VSTRING *dtype; /* null, smtp, x-unix */ VSTRING *dtext; /* null, RFC 2821, sysexits.h */ + /* Informal free text. */ VSTRING *reason; /* free text */ } DSN_BUF; @@ -36,23 +43,38 @@ typedef struct { #define DSB_MTYPE_NONE ((char *) 0) #define DSB_MTYPE_DNS "dns" /* RFC 2821 */ -#define DSB_SKIP_REPLY (char *) 0, (int) 0, " " /* XXX Bogus? */ +#define DSB_SKIP_REPLY (char *) 0, " " /* XXX Bogus? */ #define DSB_DTYPE_NONE ((char *) 0) #define DSB_DTYPE_SMTP "smtp" /* RFC 2821 */ #define DSB_DTYPE_UNIX "x-unix" /* sysexits.h */ #define DSB_DTYPE_SASL "x-sasl" /* libsasl */ extern DSN_BUF *dsb_create(void); -extern DSN_BUF *PRINTFLIKE(9, 10) dsb_update(DSN_BUF *, const char *, const char *, const char *, const char *, const char *, int, const char *, const char *,...); +extern DSN_BUF *PRINTFLIKE(8, 9) dsb_update(DSN_BUF *, const char *, const char *, const char *, const char *, const char *, const char *, const char *,...); extern DSN_BUF *PRINTFLIKE(3, 4) dsb_simple(DSN_BUF *, const char *, const char *,...); -extern DSN_BUF *PRINTFLIKE(5, 6) dsb_smtp(DSN_BUF *, const char *, int, const char *, const char *,...); -extern DSN_BUF *PRINTFLIKE(5, 6) dsb_unix(DSN_BUF *, const char *, int, const char *, const char *,...); -extern DSN_BUF *PRINTFLIKE(5, 6) dsb_smtp(DSN_BUF *, const char *, int, const char *, const char *,...); -extern DSN_BUF *dsb_formal(DSN_BUF *, const char *, const char *, const char *, const char *, const char *, int, const char *); +extern DSN_BUF *PRINTFLIKE(4, 5) dsb_unix(DSN_BUF *, const char *, const char *, const char *,...); +extern DSN_BUF *PRINTFLIKE(4, 5) dsb_smtp(DSN_BUF *, const char *, const char *, const char *,...); +extern DSN_BUF *dsb_formal(DSN_BUF *, const char *, const char *, const char *, const char *, const char *, const char *); extern DSN_BUF *dsb_status(DSN_BUF *, const char *); extern void dsb_reset(DSN_BUF *); extern void dsb_free(DSN_BUF *); + /* + * Early implementations of the DSN structure represented unavailable + * information with null pointers. This resulted in hard to maintain code. + * We now use empty strings instead, so there is no need anymore to convert + * empty strings to null pointers in the macro below. + */ +#define DSN_FROM_DSN_BUF(dsb) \ + DSN_ASSIGN(&(dsb)->dsn, \ + vstring_str((dsb)->status), \ + vstring_str((dsb)->action), \ + vstring_str((dsb)->reason), \ + vstring_str((dsb)->dtype), \ + vstring_str((dsb)->dtext), \ + vstring_str((dsb)->mtype), \ + vstring_str((dsb)->mname)) + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/dsn_print.c b/postfix/src/global/dsn_print.c index ea1dc4924..9b21a6904 100644 --- a/postfix/src/global/dsn_print.c +++ b/postfix/src/global/dsn_print.c @@ -51,19 +51,17 @@ int dsn_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, DSN *dsn = (DSN *) ptr; int ret; -#define S(s) ((s) ? (s) : "") - /* * The attribute order is determined by backwards compatibility. It can * be sanitized after all the ad-hoc DSN read/write code is replaced. */ ret = print_fn(fp, flags | ATTR_FLAG_MORE, ATTR_TYPE_STR, MAIL_ATTR_DSN_STATUS, dsn->status, - ATTR_TYPE_STR, MAIL_ATTR_DSN_DTYPE, S(dsn->dtype), - ATTR_TYPE_STR, MAIL_ATTR_DSN_DTEXT, S(dsn->dtext), - ATTR_TYPE_STR, MAIL_ATTR_DSN_MTYPE, S(dsn->mtype), - ATTR_TYPE_STR, MAIL_ATTR_DSN_MNAME, S(dsn->mname), - ATTR_TYPE_STR, MAIL_ATTR_DSN_ACTION, S(dsn->action), + ATTR_TYPE_STR, MAIL_ATTR_DSN_DTYPE, dsn->dtype, + ATTR_TYPE_STR, MAIL_ATTR_DSN_DTEXT, dsn->dtext, + ATTR_TYPE_STR, MAIL_ATTR_DSN_MTYPE, dsn->mtype, + ATTR_TYPE_STR, MAIL_ATTR_DSN_MNAME, dsn->mname, + ATTR_TYPE_STR, MAIL_ATTR_DSN_ACTION, dsn->action, ATTR_TYPE_STR, MAIL_ATTR_WHY, dsn->reason, ATTR_TYPE_END); return (ret); diff --git a/postfix/src/global/dsn_util.c b/postfix/src/global/dsn_util.c index a4d7ceed5..52b997a33 100644 --- a/postfix/src/global/dsn_util.c +++ b/postfix/src/global/dsn_util.c @@ -12,7 +12,7 @@ /* /* typedef struct { /* .in +4 -/* DSN_BUF dsn; /* RFC 3463 status */ +/* DSN_STAT dsn; /* RFC 3463 status */ /* const char *text; /* Free text */ /* .in -4 /* } DSN_SPLIT; diff --git a/postfix/src/global/dsn_util.h b/postfix/src/global/dsn_util.h index fbcbfd231..8657a3e50 100644 --- a/postfix/src/global/dsn_util.h +++ b/postfix/src/global/dsn_util.h @@ -33,7 +33,7 @@ */ typedef struct { char data[DSN_SIZE]; /* NOT a public interface */ -} DSN_BUFFER; +} DSN_STAT; #define DSN_UPDATE(dsn_buf, dsn, len) do { \ if (len >= sizeof((dsn_buf).data)) \ @@ -51,7 +51,7 @@ typedef struct { * Split flat text into detail code and free text. */ typedef struct { - DSN_BUFFER dsn; /* RFC 3463 status */ + DSN_STAT dsn; /* RFC 3463 status */ const char *text; /* free text */ } DSN_SPLIT; diff --git a/postfix/src/global/mail_copy.c b/postfix/src/global/mail_copy.c index 33d41c491..42753d854 100644 --- a/postfix/src/global/mail_copy.c +++ b/postfix/src/global/mail_copy.c @@ -268,11 +268,11 @@ int mail_copy(const char *sender, if (why && read_error) dsb_unix(why, TRY_AGAIN_ERROR(errno) ? "4.3.0" : "5.3.0", - EX_IOERR, sys_exits_detail(EX_IOERR)->text, + sys_exits_detail(EX_IOERR)->text, "error reading message: %m"); if (why && write_error) dsb_unix(why, mbox_dsn(errno, "5.3.0"), - EX_IOERR, sys_exits_detail(EX_IOERR)->text, + sys_exits_detail(EX_IOERR)->text, "error writing message: %m"); /* diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 97f39f26a..9a0c60f0e 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1329,6 +1329,12 @@ extern char *var_smtp_sasl_type; #define DEF_LMTP_SASL_TLS_OPTS "$" VAR_LMTP_SASL_OPTS extern char *var_smtp_sasl_tls_opts; +#define VAR_SMTP_SASL_TLSV_OPTS "smtp_sasl_tls_verified_security_options" +#define DEF_SMTP_SASL_TLSV_OPTS "$" VAR_SMTP_SASL_TLS_OPTS +#define VAR_LMTP_SASL_TLSV_OPTS "lmtp_sasl_tls_verified_security_options" +#define DEF_LMTP_SASL_TLSV_OPTS "$" VAR_LMTP_SASL_TLS_OPTS +extern char *var_smtp_sasl_tlsv_opts; + /* * LMTP server. The soft error limit determines how many errors an LMTP * client may make before we start to slow down; the hard error limit @@ -2532,6 +2538,15 @@ extern char *var_bounce_tmpl; #define DEF_LMTP_SENDER_AUTH 0 extern bool var_smtp_sender_auth; + /* + * Allow CNAME lookup result to override the server hostname. + */ +#define VAR_SMTP_CNAME_OVERR "smtp_cname_overrides_servername" +#define DEF_SMTP_CNAME_OVERR 0 +#define VAR_LMTP_CNAME_OVERR "lmtp_cname_overrides_servername" +#define DEF_LMTP_CNAME_OVERR 0 +extern bool var_smtp_cname_overr; + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 2ffcc128a..6e5855287 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -98,6 +98,7 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_QUEUE "queue_name" #define MAIL_ATTR_QUEUEID "queue_id" #define MAIL_ATTR_SENDER "sender" +#define MAIL_ATTR_RCPT_COUNT "recipient_count" #define MAIL_ATTR_ORCPT "original_recipient" #define MAIL_ATTR_RECIP "recipient" #define MAIL_ATTR_WHY "reason" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index ee8ce66aa..f77b11e48 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20060103" +#define MAIL_RELEASE_DATE "20060112" #define MAIL_VERSION_NUMBER "2.3" #ifdef SNAPSHOT diff --git a/postfix/src/global/msg_stats_print.c b/postfix/src/global/msg_stats_print.c index 5765e3e33..98d468dcd 100644 --- a/postfix/src/global/msg_stats_print.c +++ b/postfix/src/global/msg_stats_print.c @@ -47,7 +47,7 @@ /* msg_stats_print - write MSG_STATS to stream */ int msg_stats_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, - int flags, void *ptr) + int flags, void *ptr) { int ret; diff --git a/postfix/src/global/pipe_command.c b/postfix/src/global/pipe_command.c index 245e492dc..b0caa5cba 100644 --- a/postfix/src/global/pipe_command.c +++ b/postfix/src/global/pipe_command.c @@ -427,7 +427,7 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...) */ case -1: msg_warn("fork: %m"); - dsb_unix(why, "4.3.0", EX_OSERR, sys_exits_detail(EX_OSERR)->text, + dsb_unix(why, "4.3.0", sys_exits_detail(EX_OSERR)->text, "Delivery failed: %m"); return (PIPE_STAT_DEFER); @@ -553,7 +553,7 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...) args.uid, args.gid) < 0) msg_fatal("wait: %m"); if (pipe_command_timeout) { - dsb_unix(why, "5.3.0", EX_SOFTWARE, log_len ? + dsb_unix(why, "5.3.0", log_len ? log_buf : sys_exits_detail(EX_SOFTWARE)->text, "Command time limit exceeded: \"%s\"%s%s", args.command, @@ -567,7 +567,7 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...) */ if (!NORMAL_EXIT_STATUS(wait_status)) { if (WIFSIGNALED(wait_status)) { - dsb_unix(why, "5.3.0", EX_SOFTWARE, log_len ? + dsb_unix(why, "5.3.0", log_len ? log_buf : sys_exits_detail(EX_SOFTWARE)->text, "Command died with signal %d: \"%s\"%s%s", WTERMSIG(wait_status), args.command, @@ -577,15 +577,14 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...) /* Use "D.S.N text" command output. XXX What diagnostic code? */ else if (dsn_valid(log_buf) > 0) { dsn_split(&dp, "5.3.0", log_buf); - dsb_unix(why, DSN_STATUS(dp.dsn), DSN_CLASS(dp.dsn) == '4' ? - EX_TEMPFAIL : EX_UNAVAILABLE, dp.text, "%s", dp.text); + dsb_unix(why, DSN_STATUS(dp.dsn), dp.text, "%s", dp.text); return (DSN_CLASS(dp.dsn) == '4' ? PIPE_STAT_DEFER : PIPE_STAT_BOUNCE); } /* Use compatible exit status. */ else if (SYS_EXITS_CODE(WEXITSTATUS(wait_status))) { sp = sys_exits_detail(WEXITSTATUS(wait_status)); - dsb_unix(why, sp->dsn, WEXITSTATUS(wait_status), + dsb_unix(why, sp->dsn, log_len ? log_buf : sp->text, "%s%s%s", sp->text, log_len ? ". Command output: " : "", log_buf); return (sp->dsn[0] == '4' ? @@ -594,7 +593,7 @@ int pipe_command(VSTREAM *src, DSN_BUF *why,...) /* No "D.S.N text" or compatible status. Fake it. */ else { sp = sys_exits_detail(WEXITSTATUS(wait_status)); - dsb_unix(why, sp->dsn, WEXITSTATUS(wait_status), + dsb_unix(why, sp->dsn, log_len ? log_buf : sp->text, "Command died with status %d: \"%s\"%s%s", WEXITSTATUS(wait_status), args.command, diff --git a/postfix/src/global/post_mail.c b/postfix/src/global/post_mail.c index 0904e6e0c..e1c46796d 100644 --- a/postfix/src/global/post_mail.c +++ b/postfix/src/global/post_mail.c @@ -6,26 +6,30 @@ /* SYNOPSIS /* #include /* -/* VSTREAM *post_mail_fopen(sender, recipient, cleanup_flags, trace_flags) +/* VSTREAM *post_mail_fopen(sender, recipient, cleanup_flags, trace_flags, +/* queue_id) /* const char *sender; /* const char *recipient; /* int cleanup_flags; /* int trace_flags; +/* VSTRING *queue_id; /* /* VSTREAM *post_mail_fopen_nowait(sender, recipient, -/* cleanup_flags, trace_flags) +/* cleanup_flags, trace_flags, queue_id) /* const char *sender; /* const char *recipient; /* int cleanup_flags; /* int trace_flags; +/* VSTRING *queue_id; /* /* void post_mail_fopen_async(sender, recipient, /* cleanup_flags, trace_flags, -/* notify, context) +/* queue_id, notify, context) /* const char *sender; /* const char *recipient; /* int cleanup_flags; /* int trace_flags; +/* VSTRING *queue_id; /* void (*notify)(VSTREAM *stream, char *context); /* char *context; /* @@ -96,8 +100,9 @@ /* \fB\fR. /* .IP trace_flags /* Message tracing flags as specified in \fB\fR. -/* .IP via -/* The name of the service responsible for posting this message. +/* .IP queue_id +/* Null pointer, or pointer to buffer that receives the queue +/* ID of the new message. /* .IP stream /* A stream opened by mail_post_fopen(). /* .IP notify @@ -169,15 +174,17 @@ typedef struct { POST_MAIL_NOTIFY notify; void *context; VSTREAM *stream; + VSTRING *queue_id; } POST_MAIL_STATE; /* post_mail_init - initial negotiations */ static void post_mail_init(VSTREAM *stream, const char *sender, const char *recipient, - int cleanup_flags, int trace_flags) + int cleanup_flags, int trace_flags, + VSTRING *queue_id) { - VSTRING *id = vstring_alloc(100); + VSTRING *id = queue_id ? queue_id : vstring_alloc(100); struct timeval now; const char *date; @@ -217,31 +224,36 @@ static void post_mail_init(VSTREAM *stream, const char *sender, var_myhostname, var_mail_name); post_mail_fprintf(stream, "\tid %s; %s", vstring_str(id), date); post_mail_fprintf(stream, "Date: %s", date); - vstring_free(id); + if (queue_id == 0) + vstring_free(id); } /* post_mail_fopen - prepare for posting a message */ VSTREAM *post_mail_fopen(const char *sender, const char *recipient, - int cleanup_flags, int trace_flags) + int cleanup_flags, int trace_flags, + VSTRING *queue_id) { VSTREAM *stream; stream = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service); - post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags); + post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags, + queue_id); return (stream); } /* post_mail_fopen_nowait - prepare for posting a message */ VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient, - int cleanup_flags, int trace_flags) + int cleanup_flags, int trace_flags, + VSTRING *queue_id) { VSTREAM *stream; if ((stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING)) != 0) - post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags); + post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags, + queue_id); return (stream); } @@ -281,7 +293,7 @@ static void post_mail_open_event(int event, char *context) event_disable_readwrite(vstream_fileno(state->stream)); post_mail_init(state->stream, state->sender, state->recipient, state->cleanup_flags, - state->trace_flags); + state->trace_flags, state->queue_id); myfree(state->sender); myfree(state->recipient); state->notify(state->stream, state->context); @@ -332,6 +344,7 @@ static void post_mail_open_event(int event, char *context) void post_mail_fopen_async(const char *sender, const char *recipient, int cleanup_flags, int trace_flags, + VSTRING *queue_id, void (*notify) (VSTREAM *, void *), void *context) { @@ -347,6 +360,7 @@ void post_mail_fopen_async(const char *sender, const char *recipient, state->notify = notify; state->context = context; state->stream = stream; + state->queue_id = queue_id; /* * To keep interfaces as simple as possible we report all errors via the diff --git a/postfix/src/global/post_mail.h b/postfix/src/global/post_mail.h index d0a0acecc..e55a8d166 100644 --- a/postfix/src/global/post_mail.h +++ b/postfix/src/global/post_mail.h @@ -15,6 +15,7 @@ * Utility library. */ #include +#include /* * Global library. @@ -25,9 +26,9 @@ * External interface. */ typedef void (*POST_MAIL_NOTIFY)(VSTREAM *, void *); -extern VSTREAM *post_mail_fopen(const char *, const char *, int, int); -extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int, int); -extern void post_mail_fopen_async(const char *, const char *, int, int, POST_MAIL_NOTIFY, void *); +extern VSTREAM *post_mail_fopen(const char *, const char *, int, int, VSTRING *); +extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int, int, VSTRING *); +extern void post_mail_fopen_async(const char *, const char *, int, int, VSTRING *, POST_MAIL_NOTIFY, void *); extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...); extern int post_mail_fputs(VSTREAM *, const char *); extern int post_mail_buffer(VSTREAM *, const char *, int); diff --git a/postfix/src/global/rcpt_buf.c b/postfix/src/global/rcpt_buf.c index 2417a5cb1..cfb1b4178 100644 --- a/postfix/src/global/rcpt_buf.c +++ b/postfix/src/global/rcpt_buf.c @@ -7,6 +7,7 @@ /* #include /* /* typedef struct { +/* RECIPIENT rcpt; /* convenience */ /* .in +4 /* VSTRING *address; /* final recipient */ /* VSTRING *orig_addr; /* original recipient */ @@ -16,10 +17,16 @@ /* .in -4 /* } RCPT_BUF; /* +/* RECIPIENT *RECIPIENT_FROM_RCPT_BUF(rcpb) +/* RCPT_BUF *rcpb; +/* /* RCPT_BUF *rcpb_create(void) /* -/* void rcpb_free(rcpt) -/* RCPT_BUF *rcpt; +/* void rcpb_reset(rcpb) +/* RCPT_BUF *rcpb; +/* +/* void rcpb_free(rcpb) +/* RCPT_BUF *rcpb; /* /* int rcpb_scan(scan_fn, stream, flags, ptr) /* ATTR_SCAN_MASTER_FN scan_fn; @@ -27,14 +34,17 @@ /* int flags; /* void *ptr; /* DESCRIPTION +/* RECIPIENT_FROM_RCPT_BUF() populates the rcpt member with +/* a shallow copy of the contents of the other fields. +/* /* rcpb_scan() reads a recipient buffer from the named stream /* using the specified attribute scan routine. rcpb_scan() /* is meant to be passed as a call-back to attr_scan(), thusly: /* /* ... ATTR_SCAN_FUNC, rcpb_scan, (void *) rcpt_buf, ... /* -/* rcpb_create() and rcpb_free() create and destroy -/* recipient buffer instances. +/* rcpb_create(), rcpb_reset() and rcpb_free() create, wipe +/* and destroy recipient buffer instances. /* DIAGNOSTICS /* Fatal: out of memory. /* LICENSE @@ -80,6 +90,19 @@ RCPT_BUF *rcpb_create(void) return (rcpt); } +/* rcpb_reset - reset recipient buffer */ + +void rcpb_reset(RCPT_BUF *rcpt) +{ +#define BUF_TRUNCATE(s) (vstring_str(s)[0] = 0) + + rcpt->offset = 0; + BUF_TRUNCATE(rcpt->dsn_orcpt); + rcpt->dsn_notify = 0; + BUF_TRUNCATE(rcpt->orig_addr); + BUF_TRUNCATE(rcpt->address); +} + /* rcpb_free - destroy recipient buffer */ void rcpb_free(RCPT_BUF *rcpt) diff --git a/postfix/src/global/rcpt_buf.h b/postfix/src/global/rcpt_buf.h index 0dbee35c8..9b2994c0a 100644 --- a/postfix/src/global/rcpt_buf.h +++ b/postfix/src/global/rcpt_buf.h @@ -18,10 +18,16 @@ #include #include + /* + * Global library. + */ +#include + /* * External interface. */ typedef struct { + RECIPIENT rcpt; /* convenience */ VSTRING *address; /* final recipient */ VSTRING *orig_addr; /* original recipient */ VSTRING *dsn_orcpt; /* dsn original recipient */ @@ -30,16 +36,17 @@ typedef struct { } RCPT_BUF; extern RCPT_BUF *rcpb_create(void); +extern void rcpb_reset(RCPT_BUF *); extern void rcpb_free(RCPT_BUF *); extern int rcpb_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); -#define RECIPIENT_FROM_RCPT_BUF(rcpt, buf) \ - ((rcpt)->address = vstring_str((buf)->address), \ - (rcpt)->orig_addr = vstring_str((buf)->orig_addr), \ - (rcpt)->dsn_orcpt = vstring_str((buf)->dsn_orcpt), \ - (rcpt)->dsn_notify = (buf)->dsn_notify, \ - (rcpt)->offset = (buf)->offset, \ - (rcpt)) +#define RECIPIENT_FROM_RCPT_BUF(buf) \ + ((buf)->rcpt.address = vstring_str((buf)->address), \ + (buf)->rcpt.orig_addr = vstring_str((buf)->orig_addr), \ + (buf)->rcpt.dsn_orcpt = vstring_str((buf)->dsn_orcpt), \ + (buf)->rcpt.dsn_notify = (buf)->dsn_notify, \ + (buf)->rcpt.offset = (buf)->offset, \ + &(buf)->rcpt) /* LICENSE /* .ad diff --git a/postfix/src/global/rcpt_print.c b/postfix/src/global/rcpt_print.c index 47af47032..1c3b723f8 100644 --- a/postfix/src/global/rcpt_print.c +++ b/postfix/src/global/rcpt_print.c @@ -52,8 +52,6 @@ int rcpt_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, RECIPIENT *rcpt = (RECIPIENT *) ptr; int ret; -#define S(s) ((s) ? (s) : "") - /* * The attribute order is determined by backwards compatibility. It can * be sanitized after all the ad-hoc recipient read/write code is @@ -61,10 +59,10 @@ int rcpt_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, */ ret = print_fn(fp, flags | ATTR_FLAG_MORE, - ATTR_TYPE_STR, MAIL_ATTR_ORCPT, S(rcpt->orig_addr), + ATTR_TYPE_STR, MAIL_ATTR_ORCPT, rcpt->orig_addr, ATTR_TYPE_STR, MAIL_ATTR_RECIP, rcpt->address, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, rcpt->offset, - ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, S(rcpt->dsn_orcpt), + ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt, ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify, ATTR_TYPE_END); return (ret); diff --git a/postfix/src/global/recipient_list.c b/postfix/src/global/recipient_list.c index 8d2c964f9..a39979241 100644 --- a/postfix/src/global/recipient_list.c +++ b/postfix/src/global/recipient_list.c @@ -15,9 +15,9 @@ /* char *address; /* union { /* .in +4 -/* int status; -/* struct QMGR_QUEUE *queue; -/* char *addr_type; +/* int status; +/* struct QMGR_QUEUE *queue; +/* char *addr_type; /* .in -4 /* } /* .in -4 diff --git a/postfix/src/global/recipient_list.h b/postfix/src/global/recipient_list.h index e617b4212..6e9617218 100644 --- a/postfix/src/global/recipient_list.h +++ b/postfix/src/global/recipient_list.h @@ -46,22 +46,6 @@ typedef struct RECIPIENT { myfree((char *) (ptr)); (ptr) = mystrdup(new); \ } while (0) - /* - * Same without const poisning. - */ -typedef struct RECIPIENT_VAR { - long offset; /* REC_TYPE_RCPT byte */ - char *dsn_orcpt; /* DSN original recipient */ - int dsn_notify; /* DSN notify flags */ - char *orig_addr; /* null or original recipient */ - char *address; /* complete address */ - union { /* Application specific. */ - int status; /* SMTP client */ - struct QMGR_QUEUE *queue; /* Queue manager */ - char *addr_type; /* DSN */ - } u; -} RECIPIENT_VAR; - typedef struct RECIPIENT_LIST { RECIPIENT *info; int len; diff --git a/postfix/src/global/smtp_stream.c b/postfix/src/global/smtp_stream.c index 5b3d6e040..24507d5ee 100644 --- a/postfix/src/global/smtp_stream.c +++ b/postfix/src/global/smtp_stream.c @@ -95,10 +95,6 @@ /* An I/O error happened, or the peer has disconnected unexpectedly. /* .IP SMTP_ERR_TIME /* The time limit specified to smtp_timeout_setup() was exceeded. -/* .IP SMTP_ERR_PROTO -/* A protocol error happened. -/* This error is never generated by the smtp_stream(3) module, but -/* is defined for application-specific use. /* .IP SMTP_ERR_QUIET /* Perform silent cleanup; the error was already reported by /* the application. diff --git a/postfix/src/global/smtp_stream.h b/postfix/src/global/smtp_stream.h index 190baf50d..a09a13f89 100644 --- a/postfix/src/global/smtp_stream.h +++ b/postfix/src/global/smtp_stream.h @@ -28,7 +28,6 @@ */ #define SMTP_ERR_EOF 1 /* unexpected client disconnect */ #define SMTP_ERR_TIME 2 /* time out */ -#define SMTP_ERR_PROTO 3 /* protocol (application) */ #define SMTP_ERR_QUIET 4 /* silent cleanup (application) */ extern void smtp_timeout_setup(VSTREAM *, int); diff --git a/postfix/src/local/local.h b/postfix/src/local/local.h index 2e3d79359..67c3a9403 100644 --- a/postfix/src/local/local.h +++ b/postfix/src/local/local.h @@ -88,7 +88,6 @@ typedef struct DELIVER_ATTR { char *exp_from; /* expanded_from */ DELIVER_REQUEST *request; /* the kitchen sink */ DSN_BUF *why; /* delivery status */ - DSN dsn; /* delivery status */ } DELIVER_ATTR; extern void deliver_attr_init(DELIVER_ATTR *); @@ -132,15 +131,15 @@ typedef struct LOCAL_STATE { #define BOUNCE_ATTR(attr) \ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \ - DSN_FROM_DSN_BUF(&attr.dsn, attr.why) + DSN_FROM_DSN_BUF(attr.why) #define BOUNCE_ONE_ATTR(attr) \ attr.queue_name, attr.queue_id, attr.encoding, \ attr.sender, attr.dsn_envid, attr.dsn_ret, \ &attr.msg_stats, &attr.rcpt, attr.relay, \ - DSN_FROM_DSN_BUF(&attr.dsn, attr.why) + DSN_FROM_DSN_BUF(attr.why) #define SENT_ATTR(attr) \ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \ - DSN_FROM_DSN_BUF(&attr.dsn, attr.why) + DSN_FROM_DSN_BUF(attr.why) #define OPENED_ATTR(attr) \ attr.queue_id, attr.sender #define COPY_ATTR(attr) \ diff --git a/postfix/src/local/unknown.c b/postfix/src/local/unknown.c index cc0a07458..c6d7ed9f0 100644 --- a/postfix/src/local/unknown.c +++ b/postfix/src/local/unknown.c @@ -152,8 +152,8 @@ int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) /* * Bounce the message when no luser relay is specified. */ - dsb_smtp(state.msg_attr.why, "5.1.1", 550, "550 user unknown", - "unknown user: \"%s\"", state.msg_attr.local); + dsb_simple(state.msg_attr.why, "5.1.1", + "unknown user: \"%s\"", state.msg_attr.local); return (bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); } diff --git a/postfix/src/master/Makefile.in b/postfix/src/master/Makefile.in index 36cfa45cd..c7e70f939 100644 --- a/postfix/src/master/Makefile.in +++ b/postfix/src/master/Makefile.in @@ -135,6 +135,7 @@ master_ent.o: ../../include/myaddrinfo.h master_ent.o: ../../include/mymalloc.h master_ent.o: ../../include/own_inet_addr.h master_ent.o: ../../include/readlline.h +master_ent.o: ../../include/sock_addr.h master_ent.o: ../../include/stringops.h master_ent.o: ../../include/sys_defs.h master_ent.o: ../../include/vbuf.h diff --git a/postfix/src/oqmgr/Makefile.in b/postfix/src/oqmgr/Makefile.in index 1815ddbcb..accc7a2ed 100644 --- a/postfix/src/oqmgr/Makefile.in +++ b/postfix/src/oqmgr/Makefile.in @@ -64,7 +64,6 @@ qmgr.o: ../../include/argv.h qmgr.o: ../../include/attr.h qmgr.o: ../../include/dict.h qmgr.o: ../../include/dsn.h -qmgr.o: ../../include/dsn_buf.h qmgr.o: ../../include/events.h qmgr.o: ../../include/flush_clnt.h qmgr.o: ../../include/iostuff.h @@ -74,7 +73,6 @@ qmgr.o: ../../include/mail_params.h qmgr.o: ../../include/mail_proto.h qmgr.o: ../../include/mail_queue.h qmgr.o: ../../include/mail_server.h -qmgr.o: ../../include/maps.h qmgr.o: ../../include/master_proto.h qmgr.o: ../../include/msg.h qmgr.o: ../../include/recipient_list.h @@ -86,12 +84,10 @@ qmgr.o: ../../include/vstring.h qmgr.o: qmgr.c qmgr.o: qmgr.h qmgr_active.o: ../../include/abounce.h -qmgr_active.o: ../../include/argv.h qmgr_active.o: ../../include/attr.h qmgr_active.o: ../../include/bounce.h qmgr_active.o: ../../include/defer.h qmgr_active.o: ../../include/deliver_request.h -qmgr_active.o: ../../include/dict.h qmgr_active.o: ../../include/dsn.h qmgr_active.o: ../../include/dsn_buf.h qmgr_active.o: ../../include/dsn_mask.h @@ -99,7 +95,6 @@ qmgr_active.o: ../../include/events.h qmgr_active.o: ../../include/mail_open_ok.h qmgr_active.o: ../../include/mail_params.h qmgr_active.o: ../../include/mail_queue.h -qmgr_active.o: ../../include/maps.h qmgr_active.o: ../../include/msg.h qmgr_active.o: ../../include/msg_stats.h qmgr_active.o: ../../include/mymalloc.h @@ -114,15 +109,12 @@ qmgr_active.o: ../../include/vstream.h qmgr_active.o: ../../include/vstring.h qmgr_active.o: qmgr.h qmgr_active.o: qmgr_active.c -qmgr_bounce.o: ../../include/argv.h qmgr_bounce.o: ../../include/attr.h qmgr_bounce.o: ../../include/bounce.h qmgr_bounce.o: ../../include/deliver_completed.h qmgr_bounce.o: ../../include/deliver_request.h -qmgr_bounce.o: ../../include/dict.h qmgr_bounce.o: ../../include/dsn.h qmgr_bounce.o: ../../include/dsn_buf.h -qmgr_bounce.o: ../../include/maps.h qmgr_bounce.o: ../../include/msg_stats.h qmgr_bounce.o: ../../include/recipient_list.h qmgr_bounce.o: ../../include/scan_dir.h @@ -132,15 +124,12 @@ qmgr_bounce.o: ../../include/vstream.h qmgr_bounce.o: ../../include/vstring.h qmgr_bounce.o: qmgr.h qmgr_bounce.o: qmgr_bounce.c -qmgr_defer.o: ../../include/argv.h qmgr_defer.o: ../../include/attr.h qmgr_defer.o: ../../include/bounce.h qmgr_defer.o: ../../include/defer.h qmgr_defer.o: ../../include/deliver_request.h -qmgr_defer.o: ../../include/dict.h qmgr_defer.o: ../../include/dsn.h qmgr_defer.o: ../../include/dsn_buf.h -qmgr_defer.o: ../../include/maps.h qmgr_defer.o: ../../include/msg.h qmgr_defer.o: ../../include/msg_stats.h qmgr_defer.o: ../../include/recipient_list.h @@ -151,10 +140,8 @@ qmgr_defer.o: ../../include/vstream.h qmgr_defer.o: ../../include/vstring.h qmgr_defer.o: qmgr.h qmgr_defer.o: qmgr_defer.c -qmgr_deliver.o: ../../include/argv.h qmgr_deliver.o: ../../include/attr.h qmgr_deliver.o: ../../include/deliver_request.h -qmgr_deliver.o: ../../include/dict.h qmgr_deliver.o: ../../include/dsb_scan.h qmgr_deliver.o: ../../include/dsn.h qmgr_deliver.o: ../../include/dsn_buf.h @@ -164,9 +151,9 @@ qmgr_deliver.o: ../../include/iostuff.h qmgr_deliver.o: ../../include/mail_params.h qmgr_deliver.o: ../../include/mail_proto.h qmgr_deliver.o: ../../include/mail_queue.h -qmgr_deliver.o: ../../include/maps.h qmgr_deliver.o: ../../include/msg.h qmgr_deliver.o: ../../include/msg_stats.h +qmgr_deliver.o: ../../include/rcpt_print.h qmgr_deliver.o: ../../include/recipient_list.h qmgr_deliver.o: ../../include/scan_dir.h qmgr_deliver.o: ../../include/stringops.h @@ -178,29 +165,20 @@ qmgr_deliver.o: ../../include/vstring.h qmgr_deliver.o: ../../include/vstring_vstream.h qmgr_deliver.o: qmgr.h qmgr_deliver.o: qmgr_deliver.c -qmgr_enable.o: ../../include/argv.h -qmgr_enable.o: ../../include/dict.h qmgr_enable.o: ../../include/dsn.h -qmgr_enable.o: ../../include/dsn_buf.h -qmgr_enable.o: ../../include/maps.h qmgr_enable.o: ../../include/msg.h qmgr_enable.o: ../../include/recipient_list.h qmgr_enable.o: ../../include/scan_dir.h qmgr_enable.o: ../../include/sys_defs.h qmgr_enable.o: ../../include/vbuf.h qmgr_enable.o: ../../include/vstream.h -qmgr_enable.o: ../../include/vstring.h qmgr_enable.o: qmgr.h qmgr_enable.o: qmgr_enable.c -qmgr_entry.o: ../../include/argv.h qmgr_entry.o: ../../include/attr.h qmgr_entry.o: ../../include/deliver_request.h -qmgr_entry.o: ../../include/dict.h qmgr_entry.o: ../../include/dsn.h -qmgr_entry.o: ../../include/dsn_buf.h qmgr_entry.o: ../../include/events.h qmgr_entry.o: ../../include/mail_params.h -qmgr_entry.o: ../../include/maps.h qmgr_entry.o: ../../include/msg.h qmgr_entry.o: ../../include/msg_stats.h qmgr_entry.o: ../../include/mymalloc.h @@ -224,11 +202,9 @@ qmgr_message.o: ../../include/dsn_attr_map.h qmgr_message.o: ../../include/dsn_buf.h qmgr_message.o: ../../include/dsn_mask.h qmgr_message.o: ../../include/iostuff.h -qmgr_message.o: ../../include/mail_addr_find.h qmgr_message.o: ../../include/mail_params.h qmgr_message.o: ../../include/mail_proto.h qmgr_message.o: ../../include/mail_queue.h -qmgr_message.o: ../../include/maps.h qmgr_message.o: ../../include/msg.h qmgr_message.o: ../../include/msg_stats.h qmgr_message.o: ../../include/myflock.h @@ -253,13 +229,9 @@ qmgr_message.o: ../../include/vstream.h qmgr_message.o: ../../include/vstring.h qmgr_message.o: qmgr.h qmgr_message.o: qmgr_message.c -qmgr_move.o: ../../include/argv.h -qmgr_move.o: ../../include/dict.h qmgr_move.o: ../../include/dsn.h -qmgr_move.o: ../../include/dsn_buf.h qmgr_move.o: ../../include/mail_queue.h qmgr_move.o: ../../include/mail_scan_dir.h -qmgr_move.o: ../../include/maps.h qmgr_move.o: ../../include/msg.h qmgr_move.o: ../../include/recipient_list.h qmgr_move.o: ../../include/scan_dir.h @@ -269,14 +241,10 @@ qmgr_move.o: ../../include/vstream.h qmgr_move.o: ../../include/vstring.h qmgr_move.o: qmgr.h qmgr_move.o: qmgr_move.c -qmgr_queue.o: ../../include/argv.h -qmgr_queue.o: ../../include/dict.h qmgr_queue.o: ../../include/dsn.h -qmgr_queue.o: ../../include/dsn_buf.h qmgr_queue.o: ../../include/events.h qmgr_queue.o: ../../include/htable.h qmgr_queue.o: ../../include/mail_params.h -qmgr_queue.o: ../../include/maps.h qmgr_queue.o: ../../include/msg.h qmgr_queue.o: ../../include/mymalloc.h qmgr_queue.o: ../../include/recipient_list.h @@ -284,15 +252,10 @@ qmgr_queue.o: ../../include/scan_dir.h qmgr_queue.o: ../../include/sys_defs.h qmgr_queue.o: ../../include/vbuf.h qmgr_queue.o: ../../include/vstream.h -qmgr_queue.o: ../../include/vstring.h qmgr_queue.o: qmgr.h qmgr_queue.o: qmgr_queue.c -qmgr_scan.o: ../../include/argv.h -qmgr_scan.o: ../../include/dict.h qmgr_scan.o: ../../include/dsn.h -qmgr_scan.o: ../../include/dsn_buf.h qmgr_scan.o: ../../include/mail_scan_dir.h -qmgr_scan.o: ../../include/maps.h qmgr_scan.o: ../../include/msg.h qmgr_scan.o: ../../include/mymalloc.h qmgr_scan.o: ../../include/recipient_list.h @@ -300,21 +263,16 @@ qmgr_scan.o: ../../include/scan_dir.h qmgr_scan.o: ../../include/sys_defs.h qmgr_scan.o: ../../include/vbuf.h qmgr_scan.o: ../../include/vstream.h -qmgr_scan.o: ../../include/vstring.h qmgr_scan.o: qmgr.h qmgr_scan.o: qmgr_scan.c -qmgr_transport.o: ../../include/argv.h qmgr_transport.o: ../../include/attr.h -qmgr_transport.o: ../../include/dict.h qmgr_transport.o: ../../include/dsn.h -qmgr_transport.o: ../../include/dsn_buf.h qmgr_transport.o: ../../include/events.h qmgr_transport.o: ../../include/htable.h qmgr_transport.o: ../../include/iostuff.h qmgr_transport.o: ../../include/mail_conf.h qmgr_transport.o: ../../include/mail_params.h qmgr_transport.o: ../../include/mail_proto.h -qmgr_transport.o: ../../include/maps.h qmgr_transport.o: ../../include/msg.h qmgr_transport.o: ../../include/mymalloc.h qmgr_transport.o: ../../include/recipient_list.h @@ -322,6 +280,5 @@ qmgr_transport.o: ../../include/scan_dir.h qmgr_transport.o: ../../include/sys_defs.h qmgr_transport.o: ../../include/vbuf.h qmgr_transport.o: ../../include/vstream.h -qmgr_transport.o: ../../include/vstring.h qmgr_transport.o: qmgr.h qmgr_transport.o: qmgr_transport.c diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c index 7f392d319..1f813ce4d 100644 --- a/postfix/src/oqmgr/qmgr_deliver.c +++ b/postfix/src/oqmgr/qmgr_deliver.c @@ -68,6 +68,7 @@ #include #include #include +#include /* Application-specific. */ @@ -150,8 +151,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) flags = message->tflags | entry->queue->dflags | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT); - QMGR_MSG_STATS(&stats, message); - attr_print(stream, ATTR_FLAG_MORE, + (void) QMGR_MSG_STATS(&stats, message); + attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id, @@ -171,20 +172,14 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, message->rewrite_context, + ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, list.len, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); for (recipient = list.info; recipient < list.info + list.len; recipient++) - attr_print(stream, ATTR_FLAG_MORE, - ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset, - ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, recipient->dsn_orcpt, - ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, recipient->dsn_notify, - ATTR_TYPE_STR, MAIL_ATTR_ORCPT, recipient->orig_addr, - ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address, + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_FUNC, rcpt_print, (void *) recipient, ATTR_TYPE_END); - attr_print(stream, ATTR_FLAG_NONE, - ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0, - ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("write to process (%s): %m", entry->queue->transport->name); return (-1); @@ -218,7 +213,6 @@ static void qmgr_deliver_update(int unused_event, char *context) QMGR_MESSAGE *message = entry->message; static DSN_BUF *dsb; int status; - DSN dsn; RECIPIENT *recipient; int nrcpt; @@ -251,9 +245,8 @@ static void qmgr_deliver_update(int unused_event, char *context) if (status == DELIVER_STAT_CRASH) { message->flags |= DELIVER_STAT_DEFER; qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 unknown mail transport error", - "unknown mail transport error")); + DSN_SIMPLE(&dsb->dsn, "4.3.0", + "unknown mail transport error")); msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description", transport->name); @@ -269,9 +262,9 @@ static void qmgr_deliver_update(int unused_event, char *context) */ for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) { recipient = entry->rcpt_list.info + nrcpt; - qmgr_defer_recipient(message, recipient, &dsn); + qmgr_defer_recipient(message, recipient, &dsb->dsn); } - qmgr_defer_transport(transport, &dsn); + qmgr_defer_transport(transport, &dsb->dsn); } /* @@ -282,21 +275,23 @@ static void qmgr_deliver_update(int unused_event, char *context) * (the todo list); stay away from queue entries that have been selected * (the busy list), or we would have dangling pointers. The queue itself * won't go away before we dispose of the current queue entry. + * + * XXX Caution: DSN_COPY() will panic on empty status or reason. */ #define SUSPENDED "delivery temporarily suspended: " if (status == DELIVER_STAT_DEFER) { message->flags |= DELIVER_STAT_DEFER; if (VSTRING_LEN(dsb->status)) { - /* Sanitize the DSN status from the delivery agent. */ + /* Sanitize the DSN status/reason from the delivery agent. */ if (!dsn_valid(vstring_str(dsb->status))) vstring_strcpy(dsb->status, "4.0.0"); if (VSTRING_LEN(dsb->reason) == 0) vstring_strcpy(dsb->reason, "unknown error"); vstring_prepend(dsb->reason, SUSPENDED, sizeof(SUSPENDED) - 1); - qmgr_queue_throttle(queue, DSN_FROM_DSN_BUF(&dsn, dsb)); + qmgr_queue_throttle(queue, DSN_FROM_DSN_BUF(dsb)); if (queue->window == 0) - qmgr_defer_todo(queue, &dsn); + qmgr_defer_todo(queue, &dsb->dsn); } } @@ -339,9 +334,8 @@ void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) */ if (qmgr_deliver_initial_reply(stream) != 0) { qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); qmgr_defer_transport(transport, &dsn); (void) vstream_fclose(stream); return; @@ -369,9 +363,8 @@ void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) if (qmgr_deliver_send_request(entry, stream) < 0) { qmgr_entry_unselect(queue, entry); qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); qmgr_defer_transport(transport, &dsn); /* warning: entry and queue may be dangling pointers here */ (void) vstream_fclose(stream); diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index a973ffa65..146c7c678 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -854,15 +854,13 @@ static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient, resolve_clnt_verify_from(message->sender, addr, reply); if (reply->flags & RESOLVE_FLAG_FAIL) { qmgr_defer_recipient(message, recipient, - DSN_SMTP(&dsn, "4.3.0", - "451 address resolver failure", - "address resolver failure")); + DSN_SIMPLE(&dsn, "4.3.0", + "address resolver failure")); return (-1); } else if (reply->flags & RESOLVE_FLAG_ERROR) { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 bad address syntax", - "bad address syntax")); + DSN_SIMPLE(&dsn, "5.1.3", + "bad address syntax")); return (-1); } else { return (0); @@ -948,9 +946,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) */ if (recipient->address[0] == 0) { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 null recipient address", - "null recipient address")); + DSN_SIMPLE(&dsn, "5.1.3", + "null recipient address")); continue; } @@ -967,9 +964,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) */ if (var_allow_min_user == 0 && recipient->address[0] == '-') { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 bad address syntax", - "bad address syntax")); + DSN_SIMPLE(&dsn, "5.1.3", + "bad address syntax")); continue; } @@ -1015,9 +1011,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) break; if (*cpp) { qmgr_defer_recipient(message, recipient, - DSN_SMTP(&dsn, "4.3.2", - "450 delivery suspended", - "deferred transport")); + DSN_SIMPLE(&dsn, "4.3.2", + "deferred transport")); continue; } } diff --git a/postfix/src/oqmgr/qmgr_transport.c b/postfix/src/oqmgr/qmgr_transport.c index 756dd4809..d31f7bd39 100644 --- a/postfix/src/oqmgr/qmgr_transport.c +++ b/postfix/src/oqmgr/qmgr_transport.c @@ -289,9 +289,8 @@ void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT if ((stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name, BLOCK_MODE)) == 0) { msg_warn("connect to transport %s: %m", transport->name); qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); return; } alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc)); diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index e365a3e9d..967d9fb5a 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -24,8 +24,8 @@ /* .ad /* .fi /* Some external commands cannot handle more than one recipient -/* per delivery request. Examples of such transports are pagers, -/* fax machines, and so on. +/* per delivery request. Examples of such transports are pagers +/* or fax machines. /* /* To prevent Postfix from sending multiple recipients per delivery /* request, specify @@ -882,7 +882,6 @@ static int eval_command_status(int command_status, char *service, int status; int result = 0; int n; - DSN dsn; /* * Depending on the result, bounce or defer the message, and mark the @@ -892,12 +891,12 @@ static int eval_command_status(int command_status, char *service, case PIPE_STAT_OK: dsb_update(why, "2.0.0", "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "delivered via %s service", service); - (void) DSN_FROM_DSN_BUF(&dsn, why); + (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - service, &dsn); + service, &why->dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(src, rcpt->offset); result |= status; @@ -905,14 +904,14 @@ static int eval_command_status(int command_status, char *service, break; case PIPE_STAT_BOUNCE: case PIPE_STAT_DEFER: - (void) DSN_FROM_DSN_BUF(&dsn, why); + (void) DSN_FROM_DSN_BUF(why); if (STR(why->status)[0] != '4') { for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - service, &dsn); + service, &why->dsn); if (status == 0) deliver_completed(src, rcpt->offset); result |= status; @@ -923,7 +922,7 @@ static int eval_command_status(int command_status, char *service, result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - service, &dsn); + service, &why->dsn); } } break; @@ -948,7 +947,6 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv) static PIPE_ATTR attr; RECIPIENT_LIST *rcpt_list = &request->rcpt_list; DSN_BUF *why = dsb_create(); - DSN dsn; VSTRING *buf; ARGV *expanded_argv = 0; int deliver_status; @@ -1029,11 +1027,12 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv) deliver_status = 0; dsb_simple(why, "2.0.0", "delivers to command: %s", attr.command[0]); + (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, - rcpt, service, DSN_FROM_DSN_BUF(&dsn, why)); + rcpt, service, &why->dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(request->fp, rcpt->offset); deliver_status |= status; diff --git a/postfix/src/postlock/Makefile.in b/postfix/src/postlock/Makefile.in index dffba604f..284f7c686 100644 --- a/postfix/src/postlock/Makefile.in +++ b/postfix/src/postlock/Makefile.in @@ -58,6 +58,7 @@ depend: $(MAKES) postlock.o: ../../include/argv.h postlock.o: ../../include/deliver_flock.h postlock.o: ../../include/dot_lockfile.h +postlock.o: ../../include/dsn.h postlock.o: ../../include/dsn_buf.h postlock.o: ../../include/dsn_util.h postlock.o: ../../include/iostuff.h diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index dde0e834f..d7d52652c 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -66,7 +66,6 @@ qmgr.o: ../../include/argv.h qmgr.o: ../../include/attr.h qmgr.o: ../../include/dict.h qmgr.o: ../../include/dsn.h -qmgr.o: ../../include/dsn_buf.h qmgr.o: ../../include/events.h qmgr.o: ../../include/flush_clnt.h qmgr.o: ../../include/iostuff.h @@ -76,7 +75,6 @@ qmgr.o: ../../include/mail_params.h qmgr.o: ../../include/mail_proto.h qmgr.o: ../../include/mail_queue.h qmgr.o: ../../include/mail_server.h -qmgr.o: ../../include/maps.h qmgr.o: ../../include/master_proto.h qmgr.o: ../../include/msg.h qmgr.o: ../../include/recipient_list.h @@ -88,12 +86,10 @@ qmgr.o: ../../include/vstring.h qmgr.o: qmgr.c qmgr.o: qmgr.h qmgr_active.o: ../../include/abounce.h -qmgr_active.o: ../../include/argv.h qmgr_active.o: ../../include/attr.h qmgr_active.o: ../../include/bounce.h qmgr_active.o: ../../include/defer.h qmgr_active.o: ../../include/deliver_request.h -qmgr_active.o: ../../include/dict.h qmgr_active.o: ../../include/dsn.h qmgr_active.o: ../../include/dsn_buf.h qmgr_active.o: ../../include/dsn_mask.h @@ -101,7 +97,6 @@ qmgr_active.o: ../../include/events.h qmgr_active.o: ../../include/mail_open_ok.h qmgr_active.o: ../../include/mail_params.h qmgr_active.o: ../../include/mail_queue.h -qmgr_active.o: ../../include/maps.h qmgr_active.o: ../../include/msg.h qmgr_active.o: ../../include/msg_stats.h qmgr_active.o: ../../include/mymalloc.h @@ -116,15 +111,12 @@ qmgr_active.o: ../../include/vstream.h qmgr_active.o: ../../include/vstring.h qmgr_active.o: qmgr.h qmgr_active.o: qmgr_active.c -qmgr_bounce.o: ../../include/argv.h qmgr_bounce.o: ../../include/attr.h qmgr_bounce.o: ../../include/bounce.h qmgr_bounce.o: ../../include/deliver_completed.h qmgr_bounce.o: ../../include/deliver_request.h -qmgr_bounce.o: ../../include/dict.h qmgr_bounce.o: ../../include/dsn.h qmgr_bounce.o: ../../include/dsn_buf.h -qmgr_bounce.o: ../../include/maps.h qmgr_bounce.o: ../../include/msg_stats.h qmgr_bounce.o: ../../include/recipient_list.h qmgr_bounce.o: ../../include/scan_dir.h @@ -134,15 +126,12 @@ qmgr_bounce.o: ../../include/vstream.h qmgr_bounce.o: ../../include/vstring.h qmgr_bounce.o: qmgr.h qmgr_bounce.o: qmgr_bounce.c -qmgr_defer.o: ../../include/argv.h qmgr_defer.o: ../../include/attr.h qmgr_defer.o: ../../include/bounce.h qmgr_defer.o: ../../include/defer.h qmgr_defer.o: ../../include/deliver_request.h -qmgr_defer.o: ../../include/dict.h qmgr_defer.o: ../../include/dsn.h qmgr_defer.o: ../../include/dsn_buf.h -qmgr_defer.o: ../../include/maps.h qmgr_defer.o: ../../include/msg.h qmgr_defer.o: ../../include/msg_stats.h qmgr_defer.o: ../../include/recipient_list.h @@ -153,10 +142,8 @@ qmgr_defer.o: ../../include/vstream.h qmgr_defer.o: ../../include/vstring.h qmgr_defer.o: qmgr.h qmgr_defer.o: qmgr_defer.c -qmgr_deliver.o: ../../include/argv.h qmgr_deliver.o: ../../include/attr.h qmgr_deliver.o: ../../include/deliver_request.h -qmgr_deliver.o: ../../include/dict.h qmgr_deliver.o: ../../include/dsb_scan.h qmgr_deliver.o: ../../include/dsn.h qmgr_deliver.o: ../../include/dsn_buf.h @@ -166,9 +153,9 @@ qmgr_deliver.o: ../../include/iostuff.h qmgr_deliver.o: ../../include/mail_params.h qmgr_deliver.o: ../../include/mail_proto.h qmgr_deliver.o: ../../include/mail_queue.h -qmgr_deliver.o: ../../include/maps.h qmgr_deliver.o: ../../include/msg.h qmgr_deliver.o: ../../include/msg_stats.h +qmgr_deliver.o: ../../include/rcpt_print.h qmgr_deliver.o: ../../include/recipient_list.h qmgr_deliver.o: ../../include/scan_dir.h qmgr_deliver.o: ../../include/stringops.h @@ -180,29 +167,20 @@ qmgr_deliver.o: ../../include/vstring.h qmgr_deliver.o: ../../include/vstring_vstream.h qmgr_deliver.o: qmgr.h qmgr_deliver.o: qmgr_deliver.c -qmgr_enable.o: ../../include/argv.h -qmgr_enable.o: ../../include/dict.h qmgr_enable.o: ../../include/dsn.h -qmgr_enable.o: ../../include/dsn_buf.h -qmgr_enable.o: ../../include/maps.h qmgr_enable.o: ../../include/msg.h qmgr_enable.o: ../../include/recipient_list.h qmgr_enable.o: ../../include/scan_dir.h qmgr_enable.o: ../../include/sys_defs.h qmgr_enable.o: ../../include/vbuf.h qmgr_enable.o: ../../include/vstream.h -qmgr_enable.o: ../../include/vstring.h qmgr_enable.o: qmgr.h qmgr_enable.o: qmgr_enable.c -qmgr_entry.o: ../../include/argv.h qmgr_entry.o: ../../include/attr.h qmgr_entry.o: ../../include/deliver_request.h -qmgr_entry.o: ../../include/dict.h qmgr_entry.o: ../../include/dsn.h -qmgr_entry.o: ../../include/dsn_buf.h qmgr_entry.o: ../../include/events.h qmgr_entry.o: ../../include/mail_params.h -qmgr_entry.o: ../../include/maps.h qmgr_entry.o: ../../include/msg.h qmgr_entry.o: ../../include/msg_stats.h qmgr_entry.o: ../../include/mymalloc.h @@ -214,12 +192,8 @@ qmgr_entry.o: ../../include/vstream.h qmgr_entry.o: ../../include/vstring.h qmgr_entry.o: qmgr.h qmgr_entry.o: qmgr_entry.c -qmgr_job.o: ../../include/argv.h -qmgr_job.o: ../../include/dict.h qmgr_job.o: ../../include/dsn.h -qmgr_job.o: ../../include/dsn_buf.h qmgr_job.o: ../../include/htable.h -qmgr_job.o: ../../include/maps.h qmgr_job.o: ../../include/msg.h qmgr_job.o: ../../include/mymalloc.h qmgr_job.o: ../../include/recipient_list.h @@ -228,7 +202,6 @@ qmgr_job.o: ../../include/scan_dir.h qmgr_job.o: ../../include/sys_defs.h qmgr_job.o: ../../include/vbuf.h qmgr_job.o: ../../include/vstream.h -qmgr_job.o: ../../include/vstring.h qmgr_job.o: qmgr.h qmgr_job.o: qmgr_job.c qmgr_message.o: ../../include/argv.h @@ -243,11 +216,9 @@ qmgr_message.o: ../../include/dsn_attr_map.h qmgr_message.o: ../../include/dsn_buf.h qmgr_message.o: ../../include/dsn_mask.h qmgr_message.o: ../../include/iostuff.h -qmgr_message.o: ../../include/mail_addr_find.h qmgr_message.o: ../../include/mail_params.h qmgr_message.o: ../../include/mail_proto.h qmgr_message.o: ../../include/mail_queue.h -qmgr_message.o: ../../include/maps.h qmgr_message.o: ../../include/msg.h qmgr_message.o: ../../include/msg_stats.h qmgr_message.o: ../../include/myflock.h @@ -273,13 +244,9 @@ qmgr_message.o: ../../include/vstream.h qmgr_message.o: ../../include/vstring.h qmgr_message.o: qmgr.h qmgr_message.o: qmgr_message.c -qmgr_move.o: ../../include/argv.h -qmgr_move.o: ../../include/dict.h qmgr_move.o: ../../include/dsn.h -qmgr_move.o: ../../include/dsn_buf.h qmgr_move.o: ../../include/mail_queue.h qmgr_move.o: ../../include/mail_scan_dir.h -qmgr_move.o: ../../include/maps.h qmgr_move.o: ../../include/msg.h qmgr_move.o: ../../include/recipient_list.h qmgr_move.o: ../../include/scan_dir.h @@ -289,12 +256,8 @@ qmgr_move.o: ../../include/vstream.h qmgr_move.o: ../../include/vstring.h qmgr_move.o: qmgr.h qmgr_move.o: qmgr_move.c -qmgr_peer.o: ../../include/argv.h -qmgr_peer.o: ../../include/dict.h qmgr_peer.o: ../../include/dsn.h -qmgr_peer.o: ../../include/dsn_buf.h qmgr_peer.o: ../../include/htable.h -qmgr_peer.o: ../../include/maps.h qmgr_peer.o: ../../include/msg.h qmgr_peer.o: ../../include/mymalloc.h qmgr_peer.o: ../../include/recipient_list.h @@ -302,17 +265,12 @@ qmgr_peer.o: ../../include/scan_dir.h qmgr_peer.o: ../../include/sys_defs.h qmgr_peer.o: ../../include/vbuf.h qmgr_peer.o: ../../include/vstream.h -qmgr_peer.o: ../../include/vstring.h qmgr_peer.o: qmgr.h qmgr_peer.o: qmgr_peer.c -qmgr_queue.o: ../../include/argv.h -qmgr_queue.o: ../../include/dict.h qmgr_queue.o: ../../include/dsn.h -qmgr_queue.o: ../../include/dsn_buf.h qmgr_queue.o: ../../include/events.h qmgr_queue.o: ../../include/htable.h qmgr_queue.o: ../../include/mail_params.h -qmgr_queue.o: ../../include/maps.h qmgr_queue.o: ../../include/msg.h qmgr_queue.o: ../../include/mymalloc.h qmgr_queue.o: ../../include/recipient_list.h @@ -320,15 +278,10 @@ qmgr_queue.o: ../../include/scan_dir.h qmgr_queue.o: ../../include/sys_defs.h qmgr_queue.o: ../../include/vbuf.h qmgr_queue.o: ../../include/vstream.h -qmgr_queue.o: ../../include/vstring.h qmgr_queue.o: qmgr.h qmgr_queue.o: qmgr_queue.c -qmgr_scan.o: ../../include/argv.h -qmgr_scan.o: ../../include/dict.h qmgr_scan.o: ../../include/dsn.h -qmgr_scan.o: ../../include/dsn_buf.h qmgr_scan.o: ../../include/mail_scan_dir.h -qmgr_scan.o: ../../include/maps.h qmgr_scan.o: ../../include/msg.h qmgr_scan.o: ../../include/mymalloc.h qmgr_scan.o: ../../include/recipient_list.h @@ -336,21 +289,16 @@ qmgr_scan.o: ../../include/scan_dir.h qmgr_scan.o: ../../include/sys_defs.h qmgr_scan.o: ../../include/vbuf.h qmgr_scan.o: ../../include/vstream.h -qmgr_scan.o: ../../include/vstring.h qmgr_scan.o: qmgr.h qmgr_scan.o: qmgr_scan.c -qmgr_transport.o: ../../include/argv.h qmgr_transport.o: ../../include/attr.h -qmgr_transport.o: ../../include/dict.h qmgr_transport.o: ../../include/dsn.h -qmgr_transport.o: ../../include/dsn_buf.h qmgr_transport.o: ../../include/events.h qmgr_transport.o: ../../include/htable.h qmgr_transport.o: ../../include/iostuff.h qmgr_transport.o: ../../include/mail_conf.h qmgr_transport.o: ../../include/mail_params.h qmgr_transport.o: ../../include/mail_proto.h -qmgr_transport.o: ../../include/maps.h qmgr_transport.o: ../../include/msg.h qmgr_transport.o: ../../include/mymalloc.h qmgr_transport.o: ../../include/recipient_list.h @@ -358,6 +306,5 @@ qmgr_transport.o: ../../include/scan_dir.h qmgr_transport.o: ../../include/sys_defs.h qmgr_transport.o: ../../include/vbuf.h qmgr_transport.o: ../../include/vstream.h -qmgr_transport.o: ../../include/vstring.h qmgr_transport.o: qmgr.h qmgr_transport.o: qmgr_transport.c diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index a2d96f511..9dc54c2f5 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -73,6 +73,7 @@ #include #include #include +#include /* Application-specific. */ @@ -155,8 +156,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) flags = message->tflags | entry->queue->dflags | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT); - QMGR_MSG_STATS(&stats, message); - attr_print(stream, ATTR_FLAG_MORE, + (void) QMGR_MSG_STATS(&stats, message); + attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id, @@ -176,20 +177,14 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, message->rewrite_context, + ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, list.len, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); for (recipient = list.info; recipient < list.info + list.len; recipient++) - attr_print(stream, ATTR_FLAG_MORE, - ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset, - ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, recipient->dsn_orcpt, - ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, recipient->dsn_notify, - ATTR_TYPE_STR, MAIL_ATTR_ORCPT, recipient->orig_addr, - ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address, + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_FUNC, rcpt_print, (void *) recipient, ATTR_TYPE_END); - attr_print(stream, ATTR_FLAG_NONE, - ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0, - ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("write to process (%s): %m", entry->queue->transport->name); return (-1); @@ -223,7 +218,6 @@ static void qmgr_deliver_update(int unused_event, char *context) QMGR_MESSAGE *message = entry->message; static DSN_BUF *dsb; int status; - DSN dsn; RECIPIENT *recipient; int nrcpt; @@ -256,9 +250,8 @@ static void qmgr_deliver_update(int unused_event, char *context) if (status == DELIVER_STAT_CRASH) { message->flags |= DELIVER_STAT_DEFER; qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 unknown mail transport error", - "unknown mail transport error")); + DSN_SIMPLE(&dsb->dsn, "4.3.0", + "unknown mail transport error")); msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description", transport->name); @@ -274,9 +267,9 @@ static void qmgr_deliver_update(int unused_event, char *context) */ for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) { recipient = entry->rcpt_list.info + nrcpt; - qmgr_defer_recipient(message, recipient, &dsn); + qmgr_defer_recipient(message, recipient, &dsb->dsn); } - qmgr_defer_transport(transport, &dsn); + qmgr_defer_transport(transport, &dsb->dsn); } /* @@ -287,21 +280,23 @@ static void qmgr_deliver_update(int unused_event, char *context) * (the todo list); stay away from queue entries that have been selected * (the busy list), or we would have dangling pointers. The queue itself * won't go away before we dispose of the current queue entry. + * + * XXX Caution: DSN_COPY() will panic on empty status or reason. */ #define SUSPENDED "delivery temporarily suspended: " if (status == DELIVER_STAT_DEFER) { message->flags |= DELIVER_STAT_DEFER; if (VSTRING_LEN(dsb->status)) { - /* Sanitize the DSN status from the delivery agent. */ + /* Sanitize the DSN status/reason from the delivery agent. */ if (!dsn_valid(vstring_str(dsb->status))) vstring_strcpy(dsb->status, "4.0.0"); if (VSTRING_LEN(dsb->reason) == 0) vstring_strcpy(dsb->reason, "unknown error"); vstring_prepend(dsb->reason, SUSPENDED, sizeof(SUSPENDED) - 1); - qmgr_queue_throttle(queue, DSN_FROM_DSN_BUF(&dsn, dsb)); + qmgr_queue_throttle(queue, DSN_FROM_DSN_BUF(dsb)); if (queue->window == 0) - qmgr_defer_todo(queue, &dsn); + qmgr_defer_todo(queue, &dsb->dsn); } } @@ -343,9 +338,8 @@ void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) */ if (qmgr_deliver_initial_reply(stream) != 0) { qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); qmgr_defer_transport(transport, &dsn); (void) vstream_fclose(stream); return; @@ -372,9 +366,8 @@ void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) if (qmgr_deliver_send_request(entry, stream) < 0) { qmgr_entry_unselect(entry); qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); qmgr_defer_transport(transport, &dsn); /* warning: entry may be a dangling pointer here */ (void) vstream_fclose(stream); diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index bd4ab56e2..fdef95bce 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -896,15 +896,13 @@ static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient, resolve_clnt_verify_from(message->sender, addr, reply); if (reply->flags & RESOLVE_FLAG_FAIL) { qmgr_defer_recipient(message, recipient, - DSN_SMTP(&dsn, "4.3.0", - "451 address resolver failure", - "address resolver failure")); + DSN_SIMPLE(&dsn, "4.3.0", + "address resolver failure")); return (-1); } else if (reply->flags & RESOLVE_FLAG_ERROR) { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 bad address syntax", - "bad address syntax")); + DSN_SIMPLE(&dsn, "5.1.3", + "bad address syntax")); return (-1); } else { return (0); @@ -990,9 +988,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) */ if (recipient->address[0] == 0) { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 null recipient address", - "null recipient address")); + DSN_SIMPLE(&dsn, "5.1.3", + "null recipient address")); continue; } @@ -1009,9 +1006,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) */ if (var_allow_min_user == 0 && recipient->address[0] == '-') { qmgr_bounce_recipient(message, recipient, - DSN_SMTP(&dsn, "5.1.3", - "553 bad address syntax", - "bad address syntax")); + DSN_SIMPLE(&dsn, "5.1.3", + "bad address syntax")); continue; } @@ -1057,9 +1053,8 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) break; if (*cpp) { qmgr_defer_recipient(message, recipient, - DSN_SMTP(&dsn, "4.3.2", - "450 delivery suspended", - "deferred transport")); + DSN_SIMPLE(&dsn, "4.3.2", + "deferred transport")); continue; } } diff --git a/postfix/src/qmgr/qmgr_transport.c b/postfix/src/qmgr/qmgr_transport.c index 036d15b20..14a4593ac 100644 --- a/postfix/src/qmgr/qmgr_transport.c +++ b/postfix/src/qmgr/qmgr_transport.c @@ -294,9 +294,8 @@ void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT if ((stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name, BLOCK_MODE)) == 0) { msg_warn("connect to transport %s: %m", transport->name); qmgr_transport_throttle(transport, - DSN_SMTP(&dsn, "4.3.0", - "451 mail transport unavailable", - "mail transport unavailable")); + DSN_SIMPLE(&dsn, "4.3.0", + "mail transport unavailable")); return; } alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc)); diff --git a/postfix/src/qmqpd/Makefile.in b/postfix/src/qmqpd/Makefile.in index aaf91d5e3..1ba772ef3 100644 --- a/postfix/src/qmqpd/Makefile.in +++ b/postfix/src/qmqpd/Makefile.in @@ -91,6 +91,7 @@ qmqpd.o: qmqpd.h qmqpd_peer.o: ../../include/attr.h qmqpd_peer.o: ../../include/inet_proto.h qmqpd_peer.o: ../../include/iostuff.h +qmqpd_peer.o: ../../include/mail_params.h qmqpd_peer.o: ../../include/mail_proto.h qmqpd_peer.o: ../../include/mail_stream.h qmqpd_peer.o: ../../include/msg.h diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index 45f391281..a2ce8a62e 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -62,7 +62,6 @@ sendmail.o: ../../include/connect.h sendmail.o: ../../include/debug_process.h sendmail.o: ../../include/deliver_request.h sendmail.o: ../../include/dsn.h -sendmail.o: ../../include/dsn_buf.h sendmail.o: ../../include/dsn_mask.h sendmail.o: ../../include/fullname.h sendmail.o: ../../include/header_opts.h diff --git a/postfix/src/showq/showq.c b/postfix/src/showq/showq.c index 806f02795..ef7e2a38f 100644 --- a/postfix/src/showq/showq.c +++ b/postfix/src/showq/showq.c @@ -143,7 +143,8 @@ char *var_empty_addr; #define SENDER_FORMAT "%-11s%8ld %20.20s %s\n" #define DROP_FORMAT "%-10s%c%8ld %20.20s (maildrop queue, sender UID %u)\n" -static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *); +static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *, +HTABLE *); #define STR(x) vstring_str(x) @@ -160,6 +161,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id, long msg_size = 0; BOUNCE_LOG *logfile; HTABLE *dup_filter = 0; + RCPT_BUF *rcpt_buf = 0; + DSN_BUF *dsn_buf = 0; char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : strcmp(queue, MAIL_QUEUE_HOLD) == 0 ? '!' : ' '); int msg_size_ok = 0; @@ -236,47 +239,58 @@ static void showq_report(VSTREAM *client, char *queue, char *id, && dup_filter == 0 && (logfile = bounce_log_open(MAIL_QUEUE_DEFER, id, O_RDONLY, 0)) != 0) { dup_filter = htable_create(var_dup_filter_limit); - showq_reasons(client, logfile, dup_filter); + if (rcpt_buf == 0) + rcpt_buf = rcpb_create(); + if (dsn_buf == 0) + dsn_buf = dsb_create(); + showq_reasons(client, logfile, rcpt_buf, dsn_buf, dup_filter); if (bounce_log_close(logfile)) msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id); } } vstring_free(buf); vstring_free(printable_quoted_addr); + if (rcpt_buf) + rcpb_free(rcpt_buf); + if (dsn_buf) + dsb_free(dsn_buf); if (dup_filter) htable_free(dup_filter, (void (*) (char *)) 0); } /* showq_reasons - show deferral reasons */ -static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, HTABLE *dup_filter) +static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf, +DSN_BUF *dsn_buf, HTABLE *dup_filter) { char *saved_reason = 0; int padding; + RECIPIENT *rcpt = &rcpt_buf->rcpt; + DSN *dsn = &dsn_buf->dsn; - while (bounce_log_read(bp) != 0) { + while (bounce_log_read(bp, rcpt_buf, dsn_buf) != 0) { /* * Update the duplicate filter. */ if (var_dup_filter_limit == 0 || dup_filter->used < var_dup_filter_limit) - if (htable_locate(dup_filter, bp->rcpt.address) == 0) - htable_enter(dup_filter, bp->rcpt.address, (char *) 0); + if (htable_locate(dup_filter, rcpt->address) == 0) + htable_enter(dup_filter, rcpt->address, (char *) 0); /* * Don't print the reason when the previous recipient had the same * problem. */ - if (saved_reason == 0 || strcmp(saved_reason, bp->dsn.reason) != 0) { + if (saved_reason == 0 || strcmp(saved_reason, dsn->reason) != 0) { if (saved_reason) myfree(saved_reason); - saved_reason = mystrdup(bp->dsn.reason); + saved_reason = mystrdup(dsn->reason); if ((padding = 76 - strlen(saved_reason)) < 0) padding = 0; vstream_fprintf(client, "%*s(%s)\n", padding, "", saved_reason); } - vstream_fprintf(client, STRING_FORMAT, "", "", "", bp->rcpt.address); + vstream_fprintf(client, STRING_FORMAT, "", "", "", rcpt->address); } if (saved_reason) myfree(saved_reason); diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index 00a4ed30b..668daea67 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -1,12 +1,10 @@ SHELL = /bin/sh SRCS = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \ smtp_addr.c smtp_trouble.c smtp_state.c smtp_rcpt.c \ - smtp_sasl_proto.c smtp_sasl_glue.c smtp_reuse.c smtp_map11.c \ - smtp_dsn.c + smtp_sasl_proto.c smtp_sasl_glue.c smtp_reuse.c smtp_map11.c OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \ smtp_addr.o smtp_trouble.o smtp_state.o smtp_rcpt.o \ - smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \ - smtp_dsn.o + smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o HDRS = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h TESTSRC = DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) @@ -234,30 +232,6 @@ smtp_connect.o: smtp.h smtp_connect.o: smtp_addr.h smtp_connect.o: smtp_connect.c smtp_connect.o: smtp_reuse.h -smtp_dsn.o: ../../include/argv.h -smtp_dsn.o: ../../include/attr.h -smtp_dsn.o: ../../include/deliver_request.h -smtp_dsn.o: ../../include/dict.h -smtp_dsn.o: ../../include/dsn.h -smtp_dsn.o: ../../include/dsn_buf.h -smtp_dsn.o: ../../include/htable.h -smtp_dsn.o: ../../include/mail_params.h -smtp_dsn.o: ../../include/maps.h -smtp_dsn.o: ../../include/match_list.h -smtp_dsn.o: ../../include/match_ops.h -smtp_dsn.o: ../../include/msg_stats.h -smtp_dsn.o: ../../include/recipient_list.h -smtp_dsn.o: ../../include/resolve_clnt.h -smtp_dsn.o: ../../include/scache.h -smtp_dsn.o: ../../include/string_list.h -smtp_dsn.o: ../../include/sys_defs.h -smtp_dsn.o: ../../include/tls.h -smtp_dsn.o: ../../include/tok822.h -smtp_dsn.o: ../../include/vbuf.h -smtp_dsn.o: ../../include/vstream.h -smtp_dsn.o: ../../include/vstring.h -smtp_dsn.o: smtp.h -smtp_dsn.o: smtp_dsn.c smtp_map11.o: ../../include/argv.h smtp_map11.o: ../../include/attr.h smtp_map11.o: ../../include/deliver_request.h diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index efb85e3e6..980b4fd0e 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -7,6 +7,7 @@ VAR_LMTP_SASL_PATH, DEF_LMTP_SASL_PATH, &var_smtp_sasl_path, 0, 0, #ifdef USE_TLS VAR_LMTP_SASL_TLS_OPTS, DEF_LMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0, + VAR_LMTP_SASL_TLSV_OPTS, DEF_LMTP_SASL_TLSV_OPTS, &var_smtp_sasl_tlsv_opts, 0, 0, #endif VAR_LMTP_SASL_MECHS, DEF_LMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0, VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0, @@ -70,5 +71,6 @@ VAR_LMTP_TLS_NOTEOFFER, DEF_LMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer, #endif VAR_LMTP_SENDER_AUTH, DEF_LMTP_SENDER_AUTH, &var_smtp_sender_auth, + VAR_LMTP_CNAME_OVERR, DEF_LMTP_CNAME_OVERR, &var_smtp_cname_overr, 0, }; diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index cc1199d4a..a05bc8ae2 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -85,7 +85,6 @@ /* RFC 1652 (8bit-MIME transport) /* RFC 1870 (Message Size Declaration) /* RFC 2033 (LMTP protocol) -/* RFC 2034 (Enhanced Status Codes) /* RFC 2045 (MIME: Format of Internet Message Bodies) /* RFC 2046 (MIME: Media Types) /* RFC 2554 (AUTH command) @@ -180,6 +179,12 @@ /* SMTP client, typically to transform a locally valid address into /* a globally valid address when sending mail across the Internet. /* .PP +/* Available in Postfix version 2.2.9 and later: +/* .IP "\fBsmtp_cname_overrides_servername (version dependent)\fR" +/* Allow DNS CNAME records to override the servername that the +/* Postfix SMTP client uses for logging, SASL password lookup, TLS +/* policy decisions, or TLS certificate verification. +/* .PP /* Available in Postfix version 2.3 and later: /* .IP "\fBlmtp_discard_lhlo_keyword_address_maps (empty)\fR" /* Lookup tables, indexed by the remote LMTP server address, with @@ -297,6 +302,12 @@ /* The number of pseudo-random bytes that an \fBsmtp\fR(8) or \fBsmtpd\fR(8) /* process requests from the \fBtlsmgr\fR(8) server in order to seed its /* internal pseudo random number generator (PRNG). +/* .PP +/* Available in Postfix version 2.3 and later: +/* .IP "\fBsmtp_sasl_tls_verified_security_options ($smtp_sasl_tls_security_options)\fR" +/* The SASL authentication security options that the Postfix SMTP +/* client uses for TLS encrypted SMTP sessions with a verified server +/* certificate. /* RESOURCE AND RATE CONTROLS /* .ad /* .fi @@ -606,6 +617,7 @@ char *var_smtp_tls_per_site; #ifdef USE_TLS int var_smtp_starttls_tmout; char *var_smtp_sasl_tls_opts; +char *var_smtp_sasl_tlsv_opts; bool var_smtp_tls_enforce_peername; int var_smtp_tls_scert_vd; bool var_smtp_tls_note_starttls_offer; @@ -617,12 +629,11 @@ char *var_prop_extension; bool var_smtp_sender_auth; char *var_lmtp_tcp_port; int var_scache_proto_tmout; +bool var_smtp_cname_overr; /* - * Global variables. smtp_errno is set by the address lookup routines and by - * the connection management routines. + * Global variables. */ -int smtp_errno; int smtp_host_lookup_mask; STRING_LIST *smtp_cache_dest; SCACHE *smtp_scache; diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 9e4e5c8ed..e79832fb0 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -8,6 +8,11 @@ /* DESCRIPTION /* .nf + /* + * System library. + */ +#include + /* * Utility library. */ @@ -77,7 +82,7 @@ typedef struct SMTP_STATE { /* * DSN Support introduced major bloat in error processing. */ - VSTRING *dsn_reason; /* on-the-fly formatting buffer */ + DSN_BUF *why; /* on-the-fly formatting buffer */ } SMTP_STATE; #define SET_NEXTHOP_STATE(state, lookup_mx, domain, port) { \ @@ -140,12 +145,14 @@ typedef struct SMTP_STATE { /* * smtp.c */ -extern int smtp_errno; /* XXX can we get rid of this? */ +#define SMTP_HAS_DSN(why) (STR((why)->status)[0] != 0) +#define SMTP_HAS_SOFT_DSN(why) (STR((why)->status)[0] == '4') +#define SMTP_HAS_HARD_DSN(why) (STR((why)->status)[0] == '5') +#define SMTP_HAS_LOOP_DSN(why) \ + (SMTP_HAS_DSN(why) && strcmp(STR((why)->status) + 1, ".4.6") == 0) -#define SMTP_ERR_NONE 0 /* no error */ -#define SMTP_ERR_FAIL 1 /* permanent error */ -#define SMTP_ERR_RETRY 2 /* temporary error */ -#define SMTP_ERR_LOOP 3 /* mailer loop */ +#define SMTP_SET_SOFT_DSN(why) (STR((why)->status)[0] = '4') +#define SMTP_SET_HARD_DSN(why) (STR((why)->status)[0] = '5') extern int smtp_host_lookup_mask; /* host lookup methods to use */ @@ -228,6 +235,11 @@ extern void smtp_tls_list_init(void); #endif + /* + * What's in a name? + */ +#define SMTP_HNAME(rr) (var_smtp_cname_overr ? (rr)->rname : (rr)->qname) + /* * smtp_connect.c */ @@ -320,12 +332,14 @@ extern void smtp_chat_init(SMTP_SESSION *); extern void smtp_chat_reset(SMTP_SESSION *); extern void smtp_chat_notify(SMTP_SESSION *); -#define SMTP_RESP_FAKE(resp, _code, _dsn, _str) \ - ((resp)->code = (_code), \ +#define SMTP_RESP_FAKE(resp, _dsn) \ + ((resp)->code = 0, \ (resp)->dsn = (_dsn), \ - (resp)->str = (_str), \ + (resp)->str = DSN_BY_LOCAL_MTA, \ (resp)) +#define DSN_BY_LOCAL_MTA ((char *) 0) /* DSN issued by local MTA */ + /* * These operations implement a redundant mark-and-sweep algorithm that * explicitly accounts for the fate of every recipient. The interface is @@ -370,7 +384,7 @@ extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *); /* * smtp_trouble.c */ -extern int smtp_sess_fail(SMTP_STATE *, DSN_BUF *); +extern int smtp_sess_fail(SMTP_STATE *); extern int PRINTFLIKE(4, 5) smtp_site_fail(SMTP_STATE *, const char *, SMTP_RESP *, const char *,...); extern int PRINTFLIKE(4, 5) smtp_mesg_fail(SMTP_STATE *, const char *, @@ -399,26 +413,6 @@ extern int smtp_map11_external(VSTRING *, MAPS *, int); extern int smtp_map11_tree(TOK822 *, MAPS *, int); extern int smtp_map11_internal(VSTRING *, MAPS *, int); - /* - * smtp_dsn.c - */ -extern void PRINTFLIKE(6, 7) smtp_dsn_update(DSN_BUF *, const char *, - const char *, - int, - const char *, - const char *,...); -extern void vsmtp_dsn_update(DSN_BUF *, const char *, const char *, - int, const char *, - const char *, va_list); -extern void smtp_dsn_formal(DSN_BUF *, const char *, const char *, int, - const char *); - -#define SMTP_DSN_ASSIGN(dsn, mta, stat, resp, why) \ - DSN_ASSIGN((dsn), (stat), DSB_DEF_ACTION, (why), DSB_DTYPE_SMTP, (resp), \ - (mta) ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, (mta)) - -#define DSN_BY_LOCAL_MTA ((char *) 0) /* DSN issued by local MTA */ - /* * Silly little macros. */ diff --git a/postfix/src/smtp/smtp_addr.c b/postfix/src/smtp/smtp_addr.c index ddc06c87e..bb9f0d147 100644 --- a/postfix/src/smtp/smtp_addr.c +++ b/postfix/src/smtp/smtp_addr.c @@ -48,16 +48,7 @@ /* when DNS lookups are explicitly disabled. /* /* All routines either return a DNS_RR pointer, or return a null -/* pointer and set the \fIsmtp_errno\fR global variable accordingly: -/* .IP SMTP_ERR_RETRY -/* The request failed due to a soft error, and should be retried later. -/* .IP SMTP_ERR_FAIL -/* The request attempt failed due to a hard error. -/* .IP SMTP_ERR_LOOP -/* The local machine is the best mail exchanger. -/* .PP -/* In addition, a description of the problem is made available -/* via the \fIwhy\fR argument. +/* pointer and update the \fIwhy\fR argument accordingly. /* LICENSE /* .ad /* .fi @@ -120,7 +111,7 @@ static void smtp_print_addr(char *what, DNS_RR *addr_list) msg_warn("skipping record type %s: %m", dns_strtype(addr->type)); } else { msg_info("pref %4d host %s/%s", - addr->pref, addr->name, + addr->pref, SMTP_HNAME(addr), hostaddr.buf); } } @@ -170,22 +161,14 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, addr_list = dns_rr_append(addr_list, addr); return (addr_list); default: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "4.4.3", 450, "450 Host not found"); - smtp_errno = SMTP_ERR_RETRY; + dsb_status(why, "4.4.3"); return (addr_list); case DNS_FAIL: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "5.4.3", 550, "550 Name server failure"); - if (smtp_errno != SMTP_ERR_RETRY) - smtp_errno = SMTP_ERR_FAIL; + dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.3" : "5.4.3"); return (addr_list); case DNS_INVAL: case DNS_NOTFOUND: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "5.4.4", 550, "550 Host not found"); - if (smtp_errno != SMTP_ERR_RETRY) - smtp_errno = SMTP_ERR_FAIL; + dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4"); /* maybe native naming service will succeed */ break; } @@ -206,14 +189,11 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, if (smtp_host_lookup_mask & SMTP_HOST_FLAG_NATIVE) { if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - DSN_NOHOST(aierr) ? "4.4.4" : "4.3.0", - 450, "450 Host not found", - "unable to look up host %s: %s", - host, MAI_STRERROR(aierr)); - if (smtp_errno != SMTP_ERR_RETRY) - smtp_errno = - (RETRY_AI_ERROR(aierr) ? SMTP_ERR_RETRY : SMTP_ERR_FAIL); + dsb_simple(why, (SMTP_HAS_SOFT_DSN(why) || RETRY_AI_ERROR(aierr)) ? + (DSN_NOHOST(aierr) ? "4.4.4" : "4.3.0") : + (DSN_NOHOST(aierr) ? "5.4.4" : "5.3.0"), + "unable to look up host %s: %s", + host, MAI_STRERROR(aierr)); } else { for (found = 0, res = res0; res != 0; res = res->ai_next) { if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { @@ -229,11 +209,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, } freeaddrinfo(res0); if (found == 0) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "5.4.4", 550, "550 Host not found", - "%s: host not found", host); - if (smtp_errno != SMTP_ERR_RETRY) - smtp_errno = SMTP_ERR_FAIL; + dsb_simple(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4", + "%s: host not found", host); } return (addr_list); } @@ -257,10 +234,11 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, DSN_BUF *why) * with DNS lookups (except if we're backup MX, and all the better MX * hosts can't be found). * - * XXX 2821: update smtp_errno (0->FAIL upon unrecoverable lookup error, - * any->RETRY upon temporary lookup error) so that we can correctly - * handle the case of no resolvable MX host. Currently this is always - * treated as a soft error. RFC 2821 wants a more precise response. + * XXX 2821: update the error status (0->FAIL upon unrecoverable lookup + * error, any->RETRY upon temporary lookup error) so that we can + * correctly handle the case of no resolvable MX host. Currently this is + * always treated as a soft error. RFC 2821 wants a more precise + * response. */ for (rr = mx_names; rr; rr = rr->next) { if (rr->type != T_MX) @@ -349,7 +327,7 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why, unsigned best_pref; unsigned best_found; - smtp_errno = SMTP_ERR_NONE; /* Paranoia */ + dsb_reset(why); /* Paranoia */ /* * Preferences from DNS use 0..32767, fall-backs use 32768+. @@ -406,16 +384,12 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why, */ switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why->reason)) { default: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "4.4.3", 450, "450 Host not found"); - smtp_errno = SMTP_ERR_RETRY; + dsb_status(why, "4.4.3"); if (var_ign_mx_lookup_err) addr_list = smtp_host_addr(name, misc_flags, why); break; case DNS_FAIL: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "5.4.3", 550, "550 Name server failure"); - smtp_errno = SMTP_ERR_FAIL; + dsb_status(why, "5.4.3"); if (var_ign_mx_lookup_err) addr_list = smtp_host_addr(name, misc_flags, why); break; @@ -425,9 +399,15 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why, addr_list = smtp_addr_list(mx_names, why); dns_rr_free(mx_names); if (addr_list == 0) { - /* DSN and text does not change. */ - if (var_smtp_defer_mxaddr) - smtp_errno = SMTP_ERR_RETRY; + /* Text does not change. */ + if (var_smtp_defer_mxaddr) { + /* Don't clobber the null terminator. */ + if (SMTP_HAS_HARD_DSN(why)) + SMTP_SET_SOFT_DSN(why); /* XXX */ + /* Require some error status. */ + else if (!SMTP_HAS_SOFT_DSN(why)) + msg_panic("smtp_domain_addr: bad status"); + } msg_warn("no MX host for %s has a valid address record", name); break; } @@ -439,17 +419,11 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why, addr_list = smtp_truncate_self(addr_list, self->pref); if (addr_list == 0) { if (best_pref != best_found) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "4.4.4", 450, "450 Host not found", - "unable to find primary relay for %s", - name); - smtp_errno = SMTP_ERR_RETRY; + dsb_simple(why, "4.4.4", + "unable to find primary relay for %s", name); } else { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "5.4.6", 550, "550 Mailer loop", - "mail for %s loops back to myself", - name); - smtp_errno = SMTP_ERR_LOOP; + dsb_simple(why, "5.4.6", "mail for %s loops back to myself", + name); } } } @@ -459,9 +433,7 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why, } break; case DNS_INVAL: - smtp_dsn_formal(why, DSN_BY_LOCAL_MTA, - "5.4.4", 550, "550 Host not found"); - smtp_errno = SMTP_ERR_FAIL; + dsb_status(why, "5.4.4"); break; case DNS_NOTFOUND: addr_list = smtp_host_addr(name, misc_flags, why); @@ -481,7 +453,7 @@ DNS_RR *smtp_host_addr(char *host, int misc_flags, DSN_BUF *why) { DNS_RR *addr_list; - smtp_errno = SMTP_ERR_NONE; /* Paranoia */ + dsb_reset(why); /* Paranoia */ /* * If the host is specified by numerical address, just convert the @@ -493,10 +465,7 @@ DNS_RR *smtp_host_addr(char *host, int misc_flags, DSN_BUF *why) && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) && smtp_find_self(addr_list) != 0) { dns_rr_free(addr_list); - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "5.4.6", 550, "550 Mailer loop", - "mail for %s loops back to myself", host); - smtp_errno = SMTP_ERR_LOOP; + dsb_simple(why, "5.4.6", "mail for %s loops back to myself", host); return (0); } if (addr_list && addr_list->next) { diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 0b645dc47..7b68b157c 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -400,13 +400,14 @@ void smtp_chat_notify(SMTP_SESSION *session) * generate from untrusted data. */ #define NULL_TRACE_FLAGS 0 +#define NO_QUEUE_ID ((VSTRING *) 0) #define LENGTH 78 #define INDENT 4 notice = post_mail_fopen_nowait(mail_addr_double_bounce(), var_error_rcpt, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS); + NULL_TRACE_FLAGS, NO_QUEUE_ID); if (notice == 0) { msg_warn("postmaster notify: %m"); return; diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 6e883116d..8142cc47a 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -126,17 +126,14 @@ static SMTP_SESSION *smtp_connect_unix(const char *addr, int len = strlen(addr); int sock; - smtp_errno = SMTP_ERR_NONE; /* Paranoia */ + dsb_reset(why); /* Paranoia */ /* * Sanity checks. */ if (len >= (int) sizeof(sock_un.sun_path)) { msg_warn("unix-domain name too long: %s", addr); - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, "4.3.5", - 450, "450 Mail server configuration error", - "Server configuration error"); - smtp_errno = SMTP_ERR_RETRY; + dsb_simple(why, "4.3.5", "Server configuration error"); return (0); } @@ -182,7 +179,7 @@ static SMTP_SESSION *smtp_connect_addr(const char *destination, DNS_RR *addr, char *bind_addr; char *bind_var; - smtp_errno = SMTP_ERR_NONE; /* Paranoia */ + dsb_reset(why); /* Paranoia */ /* * Sanity checks. @@ -190,10 +187,7 @@ static SMTP_SESSION *smtp_connect_addr(const char *destination, DNS_RR *addr, if (dns_rr_to_sa(addr, port, sa, &salen) != 0) { msg_warn("%s: skip address type %s: %m", myname, dns_strtype(addr->type)); - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, "4.4.0", - 451, "451 network address conversion failed", - "network address conversion failed: %m"); - smtp_errno = SMTP_ERR_RETRY; + dsb_simple(why, "4.4.0", "network address conversion failed: %m"); return (0); } @@ -271,9 +265,9 @@ static SMTP_SESSION *smtp_connect_addr(const char *destination, DNS_RR *addr, SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0); if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", - myname, addr->name, hostaddr.buf, ntohs(port)); + myname, SMTP_HNAME(addr), hostaddr.buf, ntohs(port)); - return (smtp_connect_sock(sock, sa, salen, addr->name, hostaddr.buf, + return (smtp_connect_sock(sock, sa, salen, SMTP_HNAME(addr), hostaddr.buf, port, destination, why, sess_flags)); } @@ -290,7 +284,6 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa, int conn_stat; int saved_errno; VSTREAM *stream; - int ch; time_t start_time; start_time = time((time_t *) 0); @@ -303,54 +296,12 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa, } else { conn_stat = sane_connect(sock, sa, salen); } - /* XXX 42X Means connection error, but only 421 is defined. */ if (conn_stat < 0) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "4.4.1", 420, "420 Unable to connect to server", - "connect to %s[%s]: %m", name, addr); - smtp_errno = SMTP_ERR_RETRY; + dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr); close(sock); return (0); } - - /* - * Following code is obsolete now that the SMTP client will connect to - * alternate hosts when a session fails before "MAIL FROM". - */ -#if 1 stream = vstream_fdopen(sock, O_RDWR); -#else - - /* - * Skip this host if it takes no action within some time limit. XXX Some - * MTAs use 426 to indicate a timeout error. - */ - if (read_wait(sock, var_smtp_helo_tmout) < 0) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "4.4.2", 426, "426 No response from server", - "connect to %s[%s]: read timeout", - addr->name, hostaddr.buf); - smtp_errno = SMTP_ERR_RETRY; - close(sock); - return (0); - } - - /* - * Skip this host if it disconnects without talking to us. - */ - stream = vstream_fdopen(sock, O_RDWR); - if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "4.4.0", 421, "421 Lost connection", - "connect to %s[%s]: server dropped connection" - " without sending the initial greeting", - addr->name, hostaddr.buf); - smtp_errno = SMTP_ERR_RETRY; - vstream_fclose(stream); - return (0); - } - vstream_ungetc(stream, ch); -#endif /* * Bundle up what we have into a nice SMTP_SESSION object. @@ -473,11 +424,11 @@ static void smtp_cleanup_session(SMTP_STATE *state) /* smtp_connect_local - connect to local server */ -static void smtp_connect_local(SMTP_STATE *state, const char *path, - DSN_BUF *why) +static void smtp_connect_local(SMTP_STATE *state, const char *path) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session; + DSN_BUF *why = state->why; /* * It's too painful to weave this code into the SMTP connection @@ -660,13 +611,14 @@ static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx, /* smtp_connect_remote - establish remote connection */ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, - char *def_service, DSN_BUF *why) + char *def_service) { DELIVER_REQUEST *request = state->request; ARGV *sites; char *dest; char **cpp; int non_fallback_sites; + DSN_BUF *why = state->why; /* * First try to deliver to the indicated destination, then try to deliver @@ -759,7 +711,7 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, * Don't try fall-back hosts if mail loops to myself. That would just * make the problem worse. */ - if (addr_list == 0 && smtp_errno == SMTP_ERR_LOOP) + if (addr_list == 0 && SMTP_HAS_LOOP_DSN(why)) state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP; /* @@ -885,23 +837,22 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, if (SMTP_RCPT_LEFT(state) > 0) { /* - * In case of a "no error" indication we make up an excuse; this can - * happen when the fall-back relay was already tried via a cached - * connection, so that the address list scrubber left behind an empty - * list. + * In case of a "no error" indication we make up an excuse: we did + * find the host address, but we did not attempt to connect to it. + * This can happen when the fall-back relay was already tried via a + * cached connection, so that the address list scrubber left behind + * an empty list. */ - if (smtp_errno == SMTP_ERR_NONE) { - smtp_dsn_update(why, DSN_BY_LOCAL_MTA, - "4.3.0", 450, "450 Server unavailable", - "server unavailable or unable to receive mail"); - smtp_errno = SMTP_ERR_RETRY; + if (!SMTP_HAS_DSN(why)) { + dsb_simple(why, "4.3.0", + "server unavailable or unable to receive mail"); } /* * Pay attention to what could be configuration problems, and pretend * that these are recoverable rather than bouncing the mail. */ - else if (smtp_errno != SMTP_ERR_RETRY + else if (!SMTP_HAS_SOFT_DSN(why) && (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) { /* @@ -912,7 +863,6 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, msg_warn("%s configuration problem", VAR_SMTP_FALLBACK); vstring_strcpy(why->status, "4.3.5"); /* XXX Keep the diagnostic code and MTA. */ - smtp_errno = SMTP_ERR_RETRY; } /* @@ -923,18 +873,17 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, msg_warn("%s configuration problem", VAR_RELAYHOST); vstring_strcpy(why->status, "4.3.5"); /* XXX Keep the diagnostic code and MTA. */ - smtp_errno = SMTP_ERR_RETRY; } /* * Mail for the next-hop destination loops back to myself. Pass * the mail to the best_mx_transport or bounce it. */ - else if (smtp_errno == SMTP_ERR_LOOP && *var_bestmx_transp) { + else if (SMTP_HAS_LOOP_DSN(why) && *var_bestmx_transp) { + dsb_reset(why); /* XXX */ state->status = deliver_pass_all(MAIL_CLASS_PRIVATE, var_bestmx_transp, request); - smtp_errno = 0; /* XXX */ SMTP_RCPT_LEFT(state) = 0; /* XXX */ } } @@ -953,7 +902,6 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop, int smtp_connect(SMTP_STATE *state) { DELIVER_REQUEST *request = state->request; - DSN_BUF *why = dsb_create(); char *destination = request->nexthop; /* @@ -975,11 +923,11 @@ int smtp_connect(SMTP_STATE *state) */ if (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) { if (strncmp(destination, "unix:", 5) == 0) { - smtp_connect_local(state, destination + 5, why); + smtp_connect_local(state, destination + 5); } else { if (strncmp(destination, "inet:", 5) == 0) destination += 5; - smtp_connect_remote(state, destination, DEF_LMTP_SERVICE, why); + smtp_connect_remote(state, destination, DEF_LMTP_SERVICE); } } @@ -992,7 +940,7 @@ int smtp_connect(SMTP_STATE *state) * Postfix configurations that have a host with such a name. */ else { - smtp_connect_remote(state, destination, DEF_SMTP_SERVICE, why); + smtp_connect_remote(state, destination, DEF_SMTP_SERVICE); } /* @@ -1005,20 +953,10 @@ int smtp_connect(SMTP_STATE *state) * deferred recipients at the end. We'd probably still want to bounce * recipients immediately, so we'd end up with another chunk of code for * defer logging only. - * - * XXX Unlike enhanced status codes, changing a 4xx into 5xx SMTP code is - * not simply a matter of changing the initial digit. What we're doing - * here is correct only under specific conditions, such as changing 450 - * into 550 or vice versa. */ if (SMTP_RCPT_LEFT(state) > 0) { state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER; /* XXX */ - if (smtp_errno == SMTP_ERR_RETRY) - STR(why->status)[0] = STR(why->dtext)[0] = '4'; /* XXX */ - else - STR(why->status)[0] = STR(why->dtext)[0] = '5'; /* XXX */ - why->dcode = atoi(STR(why->dtext)); /* XXX */ - smtp_sess_fail(state, why); + smtp_sess_fail(state); /* * Sanity check. Don't silently lose recipients. @@ -1027,6 +965,5 @@ int smtp_connect(SMTP_STATE *state) if (SMTP_RCPT_LEFT(state) > 0) msg_panic("smtp_connect: left-over recipients"); } - dsb_free(why); return (state->status); } diff --git a/postfix/src/smtp/smtp_dsn.c b/postfix/src/smtp/smtp_dsn.c deleted file mode 100644 index a48701ec0..000000000 --- a/postfix/src/smtp/smtp_dsn.c +++ /dev/null @@ -1,149 +0,0 @@ -/*++ -/* NAME -/* smtp_dsn 3 -/* SUMMARY -/* application-specific DSN wrappers -/* SYNOPSIS -/* #include -/* -/* void smtp_dsn_update(dsb, mta_name, status, code, reply, -/* reason_fmt, ...) -/* SMTP_DSN *dsb; -/* const char *mta_name; -/* const char *status; -/* int code; -/* const char *reply; -/* const char *reason_fmt; -/* -/* void vsmtp_dsn_update(dsb, mta_name, status, code, reply, -/* reason_fmt, ap) -/* SMTP_DSN *dsb; -/* const char *mta_name; -/* const char *status; -/* int code; -/* const char *reply; -/* const char *reason_fmt; -/* va_list ap; -/* -/* void smtp_dsn_formal(dsb, mta_name, status, code, reply) -/* DSN_BUF *dsb; -/* const char *mta_name; -/* const char *status; -/* int code; -/* const char *reply; -/* -/* DSN *SMTP_DSN_ASSIGN(dsn, mta_name, status, action, reply, reason) -/* DSN *dsn; -/* const char *mta_name; -/* const char *status; -/* const char *action; -/* const char *reply; -/* const char *reason; -/* DESCRIPTION -/* This module implements application-specific wrappers for -/* the dsbuf(3) delivery status information module. The purpose -/* of the wrappers is to eliminate clutter from the code. -/* -/* smtp_dsn_update() updates the formal and informal delivery -/* status attributes. -/* -/* vsmtp_dsn_update() implements an alternative interface. -/* -/* smtp_dsn_formal() updates the formal delivery status -/* attributes and leaves the informal reason attribute unmodified. -/* -/* SMTP_DSN_ASSIGN() is a wrapper around the DSN_ASSIGN macro. -/* -/* Arguments: -/* .IP dsb -/* Delivery status information. See dsbuf(3). -/* .IP mta_name -/* The name of the MTA that issued the response given with the -/* status and reply arguments. Specify DSN_BY_LOCAL_MTA for -/* status and "reply" information that was issued by the local -/* MTA. -/* .IP status -/* RFC 3463 status code. -/* .IP code -/* SMTP reply code. -/* .IP reply -/* SMTP reply code followed by text. The bounce(8) server -/* replaces non-printable characters by '?', so it is a good -/* idea to replace embedded newline characters by spaces -/* before using this module. -/* .IP reason_fmt -/* Format string for the informal reason attribute. -/* .IP DIAGNOSTICS -/* Fatal: out of memory. Panic: invalid arguments. -/* BUGS -/* It seems wasteful to copy mostly-constant information into -/* VSTRING buffers, but it's unavoidable if one needs to -/* delegate work to a subordinate routine, and report the error -/* after the subordinate has terminated. -/* LICENSE -/* .ad -/* .fi -/* The Secure Mailer license must be distributed with this software. -/* AUTHOR(S) -/* Wietse Venema -/* IBM T.J. Watson Research -/* P.O. Box 704 -/* Yorktown Heights, NY 10598, USA -/*--*/ - -/* System library. */ - -#include -#include /* 44BSD stdarg.h uses abort() */ -#include - -/* Utility library. */ - -#include - -/* Global library. */ - -#include -#include - -/* Application-specific. */ - -#include - -/* smtp_dsn_update - update formal and informal DSN attributes */ - -void smtp_dsn_update(DSN_BUF *why, const char *mta_name, - const char *status, int code, - const char *reply, - const char *format,...) -{ - va_list ap; - - va_start(ap, format); - vsmtp_dsn_update(why, mta_name, status, code, reply, format, ap); - va_end(ap); -} - -/* vsmtp_dsn_update - update formal and informal DSN attributes */ - -void vsmtp_dsn_update(DSN_BUF *why, const char *mta_name, - const char *status, int code, - const char *reply, - const char *format, va_list ap) -{ - dsb_formal(why, status, DSB_DEF_ACTION, - mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, - mta_name, var_procname, code, reply); - vstring_vsprintf(why->reason, format, ap); -} - -/* smtp_dsn_formal - update formal DSN attributes only */ - -void smtp_dsn_formal(DSN_BUF *why, const char *mta_name, - const char *status, int code, - const char *reply) -{ - dsb_formal(why, status, DSB_DEF_ACTION, - mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, - mta_name, var_procname, code, reply); -} diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index f3a1494b1..2aed9efa1 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -8,6 +8,7 @@ VAR_SMTP_SASL_PATH, DEF_SMTP_SASL_PATH, &var_smtp_sasl_path, 0, 0, #ifdef USE_TLS VAR_SMTP_SASL_TLS_OPTS, DEF_SMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0, + VAR_SMTP_SASL_TLSV_OPTS, DEF_SMTP_SASL_TLSV_OPTS, &var_smtp_sasl_tlsv_opts, 0, 0, #endif VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0, VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0, @@ -74,5 +75,6 @@ VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer, #endif VAR_SMTP_SENDER_AUTH, DEF_SMTP_SENDER_AUTH, &var_smtp_sender_auth, + VAR_SMTP_CNAME_OVERR, DEF_SMTP_CNAME_OVERR, &var_smtp_cname_overr, 0, }; diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 337fda0a0..5cee7ff28 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -405,14 +405,12 @@ int smtp_helo(SMTP_STATE *state) session->namaddrport, var_myhostname); if (session->features & SMTP_FEATURE_BEST_MX) return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 554, "5.4.6", - "554 Mailer loop"), + SMTP_RESP_FAKE(&fake, "5.4.6"), "mail for %s loops back to myself", request->nexthop)); else return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 450, "4.4.6", - "450 Mailer loop"), + SMTP_RESP_FAKE(&fake, "4.4.6"), "mail for %s loops back to myself", request->nexthop)); } @@ -542,10 +540,8 @@ int smtp_helo(SMTP_STATE *state) smtp_chat_cmd(session, "STARTTLS"); if ((resp = smtp_chat_resp(session))->code / 100 == 2) { #ifdef USE_SASL_AUTH - if (session->sasl_mechanism_list) { - myfree(session->sasl_mechanism_list); - session->sasl_mechanism_list = 0; - } + if (session->features & SMTP_FEATURE_AUTH) + smtp_sasl_cleanup(session); #endif session->features = saved_features; /* XXX Mix-up of per-session and per-request flags. */ @@ -578,39 +574,26 @@ int smtp_helo(SMTP_STATE *state) if (session->tls_enforce_tls) { if (!(session->features & SMTP_FEATURE_STARTTLS)) { return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 421, "4.7.4", - "421 TLS is required, but unavailable"), + SMTP_RESP_FAKE(&fake, "4.7.4"), "TLS is required, but was not offered by host %s", session->namaddr)); } else if (smtp_tls_ctx == 0) { return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 421, "4.7.5", - "421 TLS is required, but unavailable"), + SMTP_RESP_FAKE(&fake, "4.7.5"), "TLS is required, but our TLS engine is unavailable")); } else { msg_warn("%s: TLS is required but unavailable, don't know why", myname); return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 421, "4.7.0", - "421 TLS is required, but unavailable"), + SMTP_RESP_FAKE(&fake, "4.7.0"), "TLS is required, but unavailable")); } } } #endif #ifdef USE_SASL_AUTH - if (var_smtp_sasl_enable && (session->features & SMTP_FEATURE_AUTH)) { - if (session->sasl_mechanism_list != 0) - return (smtp_sasl_helo_login(state)); - else - return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 421, "4.7.0", - "421 SASL authentication failed: " - "server offered no compatible authentication mechanisms"), - "SASL authentication failed: " - "server %s offered no compatible authentication mechanisms", - session->namaddr)); - } + if (var_smtp_sasl_enable && (session->features & SMTP_FEATURE_AUTH)) + return (smtp_sasl_helo_login(state)); #endif return (0); @@ -669,8 +652,7 @@ static int smtp_start_tls(SMTP_STATE *state) vstring_free(serverid); if (session->tls_context == 0) return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 421, "4.7.5", - "421 TLS handshake failure"), + SMTP_RESP_FAKE(&fake, "4.7.5"), "Cannot start TLS: handshake failure")); /* @@ -860,14 +842,11 @@ static void smtp_mime_fail(SMTP_STATE *state, int mime_errs) { MIME_STATE_DETAIL *detail; SMTP_RESP fake; - char *text; detail = mime_state_detail(mime_errs); - text = concatenate("554 ", detail->text, (char *) 0); smtp_mesg_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 554, detail->dsn, text), + SMTP_RESP_FAKE(&fake, detail->dsn), "%s", detail->text); - myfree(text); } /* smtp_loop - exercise the SMTP protocol engine */ @@ -1638,8 +1617,7 @@ int smtp_xfer(SMTP_STATE *state) */ if (session->size_limit > 0 && session->size_limit < request->data_size) { smtp_mesg_fail(state, DSN_BY_LOCAL_MTA, - SMTP_RESP_FAKE(&fake, 552, "5.3.4", - "552 message too large"), + SMTP_RESP_FAKE(&fake, "5.3.4"), "message size %lu exceeds size limit %.0f of server %s", request->data_size, (double) session->size_limit, session->namaddr); diff --git a/postfix/src/smtp/smtp_rcpt.c b/postfix/src/smtp/smtp_rcpt.c index 1b64f6b06..31599464b 100644 --- a/postfix/src/smtp/smtp_rcpt.c +++ b/postfix/src/smtp/smtp_rcpt.c @@ -131,7 +131,7 @@ void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; - DSN dsn; + DSN_BUF *why = state->why; int status; /* @@ -144,13 +144,12 @@ void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) if (session->features & SMTP_FEATURE_DSN) rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS; - (void) SMTP_DSN_ASSIGN(&dsn, session->host, resp->dsn, - resp->str, resp->str); - dsn.action = "relayed"; + dsb_update(why, resp->dsn, "relayed", DSB_MTYPE_DNS, session->host, + DSB_DTYPE_SMTP, resp->str, "%s", resp->str); status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - session->namaddrport, &dsn); + session->namaddrport, DSN_FROM_DSN_BUF(why)); if (status == 0) if (request->flags & DEL_REQ_FLAG_SUCCESS) deliver_completed(state->src, rcpt->offset); diff --git a/postfix/src/smtp/smtp_sasl_glue.c b/postfix/src/smtp/smtp_sasl_glue.c index b08ed135c..38e78ddcc 100644 --- a/postfix/src/smtp/smtp_sasl_glue.c +++ b/postfix/src/smtp/smtp_sasl_glue.c @@ -283,8 +283,9 @@ int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why) session->sasl_passwd, &mechanism, session->sasl_reply); if (result != XSASL_AUTH_OK) { - dsb_update(why, "4.7.0", DSB_DEF_ACTION, DSB_SKIP_RMTA, DSB_DTYPE_SASL, - 421, STR(session->sasl_reply), + dsb_update(why, "4.7.0", DSB_DEF_ACTION, DSB_SKIP_RMTA, + DSB_DTYPE_SASL, STR(session->sasl_reply), + "SASL authentication failed; " "cannot authenticate to server %s: %s", session->namaddr, STR(session->sasl_reply)); return (-1); @@ -317,8 +318,8 @@ int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why) session->sasl_reply); if (result != XSASL_AUTH_OK) { dsb_update(why, "4.7.0", DSB_DEF_ACTION, /* Fix 200512 */ - DSB_SKIP_RMTA, DSB_DTYPE_SASL, - 421, STR(session->sasl_reply), + DSB_SKIP_RMTA, DSB_DTYPE_SASL, STR(session->sasl_reply), + "SASL authentication failed; " "cannot authenticate to server %s: %s", session->namaddr, STR(session->sasl_reply)); return (-1); /* Fix 200512 */ @@ -334,9 +335,11 @@ int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why) * We completed the authentication protocol. */ if (resp->code / 100 != 2) { - smtp_dsn_update(why, session->host, resp->dsn, resp->code, resp->str, - "SASL authentication failed; server %s said: %s", - session->namaddr, resp->str); + dsb_update(why, resp->dsn, DSB_DEF_ACTION, + DSB_MTYPE_DNS, session->host, + var_procname, resp->str, + "SASL authentication failed; server %s said: %s", + session->namaddr, resp->str); return (0); } return (1); diff --git a/postfix/src/smtp/smtp_sasl_proto.c b/postfix/src/smtp/smtp_sasl_proto.c index 699f163d2..0799d2c44 100644 --- a/postfix/src/smtp/smtp_sasl_proto.c +++ b/postfix/src/smtp/smtp_sasl_proto.c @@ -149,7 +149,7 @@ void smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words) int smtp_sasl_helo_login(SMTP_STATE *state) { SMTP_SESSION *session = state->session; - DSN_BUF *why; + DSN_BUF *why = state->why; int ret; /* @@ -168,16 +168,28 @@ int smtp_sasl_helo_login(SMTP_STATE *state) * error is unrecoverable from a session point of view - the session will * not be reused. */ - why = dsb_create(); ret = 0; - smtp_sasl_start(session, VAR_SMTP_SASL_OPTS, var_smtp_sasl_opts); - if (smtp_sasl_authenticate(session, why) <= 0) { - vstring_prepend(why->reason, "Authentication failed: ", - sizeof("Authentication failed: ") - 1); - ret = smtp_sess_fail(state, why); + if (session->sasl_mechanism_list == 0) { + dsb_simple(why, "4.7.0", "SASL authentication failed: " + "server %s offered no compatible authentication mechanisms for this type of connection security", + session->namaddr); + ret = smtp_sess_fail(state); /* Session reuse is disabled. */ + } else { + if (session->tls_context == 0) + smtp_sasl_start(session, VAR_SMTP_SASL_OPTS, + var_smtp_sasl_opts); + else if (session->tls_context->peer_verified == 0) + smtp_sasl_start(session, VAR_SMTP_SASL_TLS_OPTS, + var_smtp_sasl_tls_opts); + else + smtp_sasl_start(session, VAR_SMTP_SASL_TLSV_OPTS, + var_smtp_sasl_tlsv_opts); + if (smtp_sasl_authenticate(session, why) <= 0) { + ret = smtp_sess_fail(state); + /* Session reuse is disabled. */ + } } - dsb_free(why); return (ret); } diff --git a/postfix/src/smtp/smtp_state.c b/postfix/src/smtp/smtp_state.c index 9f364b671..b396397a1 100644 --- a/postfix/src/smtp/smtp_state.c +++ b/postfix/src/smtp/smtp_state.c @@ -76,7 +76,7 @@ SMTP_STATE *smtp_state_alloc(void) state->endp_prop = 0; state->cache_used = 0; } - state->dsn_reason = 0; + state->why = dsb_create(); /* * The process name, "smtp" or "lmtp", is also used as the DSN server @@ -112,8 +112,8 @@ void smtp_state_free(SMTP_STATE *state) vstring_free(state->endp_prop); if (state->cache_used) htable_free(state->cache_used, (void (*) (char *)) 0); - if (state->dsn_reason) - vstring_free(state->dsn_reason); + if (state->why) + dsb_free(state->why); myfree((char *) state); } diff --git a/postfix/src/smtp/smtp_trouble.c b/postfix/src/smtp/smtp_trouble.c index 4ddef7dcc..761aee970 100644 --- a/postfix/src/smtp/smtp_trouble.c +++ b/postfix/src/smtp/smtp_trouble.c @@ -6,9 +6,8 @@ /* SYNOPSIS /* #include "smtp.h" /* -/* int smtp_sess_fail(state, why) +/* int smtp_sess_fail(state) /* SMTP_STATE *state; -/* DSN_BUF *why; /* /* int smtp_site_fail(state, mta_name, resp, format, ...) /* SMTP_STATE *state; @@ -183,13 +182,14 @@ static void smtp_check_code(SMTP_SESSION *session, int code) /* smtp_bulk_fail - skip, defer or bounce recipients, maybe throttle queue */ -static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue) +static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; + DSN_BUF *why = state->why; RECIPIENT *rcpt; int status; - int soft_error = (dsn->status[0] == '4'); + int soft_error = (STR(why->status)[0] == '4'); int nrcpt; /* @@ -198,7 +198,7 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue) * why we're skipping this host. */ if (soft_error && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) { - msg_info("%s: %s", request->queue_id, dsn->reason); + msg_info("%s: %s", request->queue_id, STR(why->reason)); for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; if (SMTP_RCPT_ISMARKED(rcpt)) @@ -230,6 +230,7 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue) } else GETTIMEOFDAY(&request->msg_stats.deliver_done); + (void) DSN_FROM_DSN_BUF(why); for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; if (SMTP_RCPT_ISMARKED(rcpt)) @@ -237,14 +238,14 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue) status = (soft_error ? defer_append : bounce_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - session ? session->namaddrport : "none", dsn); + session ? session->namaddrport : "none", &why->dsn); if (status == 0) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); state->status |= status; } if (throttle_queue && soft_error && request->hop_status == 0) - request->hop_status = DSN_COPY(dsn); + request->hop_status = DSN_COPY(&why->dsn); } /* @@ -258,57 +259,42 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue) /* smtp_sess_fail - skip site, defer or bounce all recipients */ -int smtp_sess_fail(SMTP_STATE *state, DSN_BUF *why) +int smtp_sess_fail(SMTP_STATE *state) { - DSN dsn; /* - * We need to incur the expense of copying lots of strings into VSTRING - * buffers when the error information is collected by a routine that - * terminates BEFORE the error is reported. If no copies were made, the - * information would not be frozen in time. + * We can't avoid copying copying lots of strings into VSTRING buffers, + * because this error information is collected by a routine that + * terminates BEFORE the error is reported. */ - return (smtp_bulk_fail(state, DSN_FROM_DSN_BUF(&dsn, why), SMTP_THROTTLE)); + return (smtp_bulk_fail(state, SMTP_THROTTLE)); } /* vsmtp_fill_dsn - fill in temporary DSN structure */ -static void vsmtp_fill_dsn(SMTP_STATE *state, DSN *dsn, const char *mta_name, +static void vsmtp_fill_dsn(SMTP_STATE *state, const char *mta_name, const char *status, const char *reply, const char *format, va_list ap) { + DSN_BUF *why = state->why; /* - * We can avoid the cost of copying lots of strings into VSTRING buffers - * when the error information is collected by the routine that terminates - * AFTER the error is reported. In this case, the information is already - * frozen in time, so we don't need to make copies. + * We could avoid copying lots of strings into VSTRING buffers, because + * this error information is given to us by a routine that terminates + * AFTER the error is reported. However, this results in ugly kludges + * when informal text needs to be formatted. So we maintain consistency + * with other error reporting in the SMTP client even if we waste a few + * cycles. */ - if (state->dsn_reason == 0) - state->dsn_reason = vstring_alloc(100); - else - VSTRING_RESET(state->dsn_reason); - if (mta_name && reply[0] != '4' && reply[0] != '5') { - vstring_strcpy(state->dsn_reason, "Protocol error: "); - mta_name = DSN_BY_LOCAL_MTA; + VSTRING_RESET(why->reason); + if (mta_name && reply && reply[0] != '4' && reply[0] != '5') { + vstring_strcpy(why->reason, "Protocol error: "); status = "5.5.0"; - reply = "501 Protocol error in server reply"; } - vstring_vsprintf_append(state->dsn_reason, format, ap); - SMTP_DSN_ASSIGN(dsn, mta_name, status, reply, STR(state->dsn_reason)); -} - -/* smtp_fill_dsn - fill in temporary DSN structure */ - -static void smtp_fill_dsn(SMTP_STATE *state, DSN *dsn, const char *mta_name, - const char *status, const char *reply, - const char *format,...) -{ - va_list ap; - - va_start(ap, format); - vsmtp_fill_dsn(state, dsn, mta_name, status, reply, format, ap); - va_end(ap); + vstring_vsprintf_append(why->reason, format, ap); + dsb_formal(why, status, DSB_DEF_ACTION, + mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, mta_name, + reply ? DSB_DTYPE_SMTP : DSB_DTYPE_NONE, reply); } /* smtp_site_fail - throttle this queue; skip, defer or bounce all recipients */ @@ -316,14 +302,13 @@ static void smtp_fill_dsn(SMTP_STATE *state, DSN *dsn, const char *mta_name, int smtp_site_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp, const char *format,...) { - DSN dsn; va_list ap; /* * Initialize. */ va_start(ap, format); - vsmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap); + vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap); va_end(ap); if (state->session && mta_name) @@ -332,7 +317,7 @@ int smtp_site_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp, /* * Skip, defer or bounce recipients, and throttle this queue. */ - return (smtp_bulk_fail(state, &dsn, SMTP_THROTTLE)); + return (smtp_bulk_fail(state, SMTP_THROTTLE)); } /* smtp_mesg_fail - skip, defer or bounce all recipients; no queue throttle */ @@ -341,13 +326,12 @@ int smtp_mesg_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp, const char *format,...) { va_list ap; - DSN dsn; /* * Initialize. */ va_start(ap, format); - vsmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap); + vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap); va_end(ap); if (state->session && mta_name) @@ -356,7 +340,7 @@ int smtp_mesg_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp, /* * Skip, defer or bounce recipients, but don't throttle this queue. */ - return (smtp_bulk_fail(state, &dsn, SMTP_NOTHROTTLE)); + return (smtp_bulk_fail(state, SMTP_NOTHROTTLE)); } /* smtp_rcpt_fail - skip, defer, or bounce recipient */ @@ -366,7 +350,7 @@ void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; - DSN dsn; + DSN_BUF *why = state->why; int status; int soft_error; va_list ap; @@ -381,9 +365,9 @@ void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, * Initialize. */ va_start(ap, format); - vsmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap); + vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap); va_end(ap); - soft_error = dsn.status[0] == '4'; + soft_error = STR(why->status)[0] == '4'; if (state->session && mta_name) smtp_check_code(state->session, resp->code); @@ -394,7 +378,7 @@ void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, * why we're skipping this recipient now. */ if (soft_error && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) { - msg_info("%s: %s", request->queue_id, dsn.reason); + msg_info("%s: %s", request->queue_id, STR(why->reason)); SMTP_RCPT_KEEP(state, rcpt); } @@ -407,10 +391,11 @@ void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, * that did qualify for delivery to a backup server. */ else { + (void) DSN_FROM_DSN_BUF(state->why); status = (soft_error ? defer_append : bounce_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, - session ? session->namaddrport : "none", &dsn); + session ? session->namaddrport : "none", &why->dsn); if (status == 0) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); @@ -423,7 +408,7 @@ void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, int smtp_stream_except(SMTP_STATE *state, int code, const char *description) { SMTP_SESSION *session = state->session; - DSN dsn; + DSN_BUF *why = state->why; /* * Sanity check. @@ -438,23 +423,13 @@ int smtp_stream_except(SMTP_STATE *state, int code, const char *description) default: msg_panic("smtp_stream_except: unknown exception %d", code); case SMTP_ERR_EOF: - smtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA, - "4.4.2", "421 lost connection", - "lost connection with %s while %s", - session->namaddr, description); + dsb_simple(why, "4.4.2", "lost connection with %s while %s", + session->namaddr, description); break; case SMTP_ERR_TIME: - smtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA, - "4.4.2", "426 conversation timed out", - "conversation with %s timed out while %s", - session->namaddr, description); - break; - case SMTP_ERR_PROTO: - smtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA, - "4.5.0", "403 remote protocol error", - "remote protocol error in reply from %s while %s", - session->namaddr, description); + dsb_simple(why, "4.4.2", "conversation with %s timed out while %s", + session->namaddr, description); break; } - return (smtp_bulk_fail(state, &dsn, SMTP_THROTTLE)); + return (smtp_bulk_fail(state, SMTP_THROTTLE)); } diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index da78675d0..2776c4c91 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -215,7 +215,6 @@ smtpd_check.o: ../../include/dict.h smtpd_check.o: ../../include/dns.h smtpd_check.o: ../../include/domain_list.h smtpd_check.o: ../../include/dsn.h -smtpd_check.o: ../../include/dsn_buf.h smtpd_check.o: ../../include/dsn_util.h smtpd_check.o: ../../include/fsspace.h smtpd_check.o: ../../include/htable.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 9457a1505..664f3ddd8 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -40,7 +40,6 @@ /* RFC 1869 (SMTP service extensions) /* RFC 1870 (Message Size Declaration) /* RFC 1985 (ETRN command) -/* RFC 2034 (Enhanced Status Codes) /* RFC 2554 (AUTH command) /* RFC 2821 (SMTP protocol) /* RFC 2920 (SMTP Pipelining) @@ -98,9 +97,9 @@ /* Available in Postfix version 2.2 and later: /* .IP "\fBsmtpd_discard_ehlo_keyword_address_maps (empty)\fR" /* Lookup tables, indexed by the remote SMTP client address, with -/* case insensitive lists of EHLO keywords (pipelining, starttls, -/* auth, etc.) that the SMTP server will not send in the EHLO response -/* to a remote SMTP client. +/* case insensitive lists of EHLO keywords (pipelining, starttls, auth, +/* etc.) that the SMTP server will not send in the EHLO response to a +/* remote SMTP client. /* .IP "\fBsmtpd_discard_ehlo_keywords (empty)\fR" /* A case insensitive list of EHLO keywords (pipelining, starttls, /* auth, etc.) that the SMTP server will not send in the EHLO response diff --git a/postfix/src/smtpd/smtpd_chat.c b/postfix/src/smtpd/smtpd_chat.c index 2962b1efb..d91b8131a 100644 --- a/postfix/src/smtpd/smtpd_chat.c +++ b/postfix/src/smtpd/smtpd_chat.c @@ -214,13 +214,14 @@ void smtpd_chat_notify(SMTPD_STATE *state) * generate from untrusted data. */ #define NULL_TRACE_FLAGS 0 +#define NO_QUEUE_ID ((VSTRING *) 0) #define LENGTH 78 #define INDENT 4 notice = post_mail_fopen_nowait(mail_addr_double_bounce(), var_error_rcpt, CLEANUP_FLAG_MASK_INTERNAL, - NULL_TRACE_FLAGS); + NULL_TRACE_FLAGS, NO_QUEUE_ID); if (notice == 0) { msg_warn("postmaster notify: %m"); return; diff --git a/postfix/src/util/mymalloc.c b/postfix/src/util/mymalloc.c index 91b4af281..1c8165da7 100644 --- a/postfix/src/util/mymalloc.c +++ b/postfix/src/util/mymalloc.c @@ -31,6 +31,12 @@ /* handling. A call of these functions either succeeds or it does /* not return at all. /* +/* To save memory, zero-length strings are shared and read-only. +/* The caller must not attempt to modify the null terminator. +/* This code is enabled unless NO_SHARED_EMPTY_STRINGS is +/* defined at compile time (for example, you have an sscanf() +/* routine that pushes characters back into its input). +/* /* mymalloc() allocates the requested amount of memory. The memory /* is not set to zero. /* @@ -118,6 +124,22 @@ typedef struct MBLOCK { #define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len) + /* + * Optimization for short strings. We share one copy with multiple callers. + * This differs from normal heap memory in two ways, because the memory is + * shared: + * + * - It must be read-only to avoid horrible bugs. This is OK because there is + * no legitimate reason to modify the null terminator. + * + * - myfree() cannot overwrite the memory with a filler pattern like it can do + * with heap memory. Therefore, some dangling pointer bugs will be masked. + */ +#ifndef NO_SHARED_EMPTY_STRINGS +static const char empty_string[] = ""; + +#endif + /* mymalloc - allocate memory or bust */ char *mymalloc(ssize_t len) @@ -141,6 +163,11 @@ char *myrealloc(char *ptr, ssize_t len) MBLOCK *real_ptr; ssize_t old_len; +#ifndef NO_SHARED_EMPTY_STRINGS + if (ptr == empty_string) + return (mymalloc(len)); +#endif + if (len < 1) msg_panic("myrealloc: requested length %ld", (long) len); CHECK_IN_PTR(ptr, real_ptr, old_len, "myrealloc"); @@ -159,9 +186,15 @@ void myfree(char *ptr) MBLOCK *real_ptr; ssize_t len; - CHECK_IN_PTR(ptr, real_ptr, len, "myfree"); - memset((char *) real_ptr, FILLER, SPACE_FOR(len)); - free((char *) real_ptr); +#ifndef NO_SHARED_EMPTY_STRINGS + if (ptr != empty_string) { +#endif + CHECK_IN_PTR(ptr, real_ptr, len, "myfree"); + memset((char *) real_ptr, FILLER, SPACE_FOR(len)); + free((char *) real_ptr); +#ifndef NO_SHARED_EMPTY_STRINGS + } +#endif } /* mystrdup - save string to heap */ @@ -170,6 +203,10 @@ char *mystrdup(const char *str) { if (str == 0) msg_panic("mystrdup: null pointer argument"); +#ifndef NO_SHARED_EMPTY_STRINGS + if (*str == 0) + return ((char *) empty_string); +#endif return (strcpy(mymalloc(strlen(str) + 1), str)); } @@ -184,6 +221,10 @@ char *mystrndup(const char *str, ssize_t len) msg_panic("mystrndup: null pointer argument"); if (len < 0) msg_panic("mystrndup: requested length %ld", (long) len); +#ifndef NO_SHARED_EMPTY_STRINGS + if (*str == 0) + return ((char *) empty_string); +#endif if ((cp = memchr(str, 0, len)) != 0) len = cp - str; result = memcpy(mymalloc(len + 1), str, len); diff --git a/postfix/src/util/netstring.c b/postfix/src/util/netstring.c index 7dfee0a34..54c793321 100644 --- a/postfix/src/util/netstring.c +++ b/postfix/src/util/netstring.c @@ -204,6 +204,9 @@ ssize_t netstring_get_length(VSTREAM *stream) if (!ISDIGIT(ch)) netstring_except(stream, NETSTRING_ERR_FORMAT); len = len * 10 + ch - '0'; + /* vstream_fread() would read zero bytes. Reject input anyway. */ + if (len < 0) + netstring_except(stream, NETSTRING_ERR_SIZE); break; } } diff --git a/postfix/src/util/vstring.c b/postfix/src/util/vstring.c index c050f6381..df65a69bc 100644 --- a/postfix/src/util/vstring.c +++ b/postfix/src/util/vstring.c @@ -491,7 +491,6 @@ char *vstring_memchr(VSTRING *vp, int ch) VSTRING *vstring_insert(VSTRING *vp, ssize_t start, const char *buf, ssize_t len) { - const char *myname = "vstring_insert"; ssize_t new_len; /* diff --git a/postfix/src/verify/Makefile.in b/postfix/src/verify/Makefile.in index 3592ffaa9..b5a1a2884 100644 --- a/postfix/src/verify/Makefile.in +++ b/postfix/src/verify/Makefile.in @@ -62,7 +62,6 @@ verify.o: ../../include/deliver_request.h verify.o: ../../include/dict.h verify.o: ../../include/dict_ht.h verify.o: ../../include/dsn.h -verify.o: ../../include/dsn_buf.h verify.o: ../../include/htable.h verify.o: ../../include/iostuff.h verify.o: ../../include/mail_conf.h diff --git a/postfix/src/verify/verify.c b/postfix/src/verify/verify.c index 0ae579b97..ecc0d5f39 100644 --- a/postfix/src/verify/verify.c +++ b/postfix/src/verify/verify.c @@ -454,6 +454,7 @@ static void verify_query_service(VSTREAM *client_stream) "" : var_verify_sender, STR(addr), CLEANUP_FLAG_MASK_INTERNAL, DEL_REQ_FLAG_MTA_VRFY, + (VSTRING *) 0, verify_post_mail_action, (void *) 0); if (updated != 0 || var_verify_neg_cache != 0) { diff --git a/postfix/src/virtual/unknown.c b/postfix/src/virtual/unknown.c index 54208df14..d789a471e 100644 --- a/postfix/src/virtual/unknown.c +++ b/postfix/src/virtual/unknown.c @@ -58,8 +58,8 @@ int deliver_unknown(LOCAL_STATE state) if (msg_verbose) MSG_LOG_STATE(myname, state); - dsb_smtp(state.msg_attr.why, "5.1.1", 550, "550 user unknown", - "unknown user: \"%s\"", state.msg_attr.user); + dsb_simple(state.msg_attr.why, "5.1.1", + "unknown user: \"%s\"", state.msg_attr.user); return (bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); } diff --git a/postfix/src/virtual/virtual.h b/postfix/src/virtual/virtual.h index b74936067..75dd6cd2e 100644 --- a/postfix/src/virtual/virtual.h +++ b/postfix/src/virtual/virtual.h @@ -76,7 +76,6 @@ typedef struct DELIVER_ATTR { char *relay; /* relay host */ MSG_STATS msg_stats; /* time profile */ DSN_BUF *why; /* delivery status */ - DSN dsn; /* delivery status */ } DELIVER_ATTR; extern void deliver_attr_init(DELIVER_ATTR *); @@ -103,10 +102,10 @@ typedef struct LOCAL_STATE { #define BOUNCE_ATTR(attr) \ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \ - DSN_FROM_DSN_BUF(&attr.dsn, attr.why) + DSN_FROM_DSN_BUF(attr.why) #define SENT_ATTR(attr) \ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \ - DSN_FROM_DSN_BUF(&attr.dsn, attr.why) + DSN_FROM_DSN_BUF(attr.why) #define COPY_ATTR(attr) \ attr.sender, attr.rcpt.orig_addr, attr.delivered, attr.fp