From: Wietse Venema Date: Wed, 5 Jan 2011 05:00:00 +0000 (-0500) Subject: postfix-2.8-20110105 X-Git-Tag: v2.8.0-RC1~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1d5ce4f053d8e8d3dd3b1a1495fd6dbf645f575;p=thirdparty%2Fpostfix.git postfix-2.8-20110105 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 50274e0f3..214b50711 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -16340,7 +16340,7 @@ Apologies for any names omitted. Roessner. Files: util/nbbio.[hc], tlsproxy/*.[hc], postscreen/postscreen_starttlsd.c, postscreen/postscreen_smtpd.c. -20101103 +20110103 Cleanup: missing tls_level support in tlsproxy (it has no way to send plaintext, but perhaps an informative error @@ -16349,3 +16349,24 @@ Apologies for any names omitted. Cleanup: simplified the handling of throttled output (i.e. output that can't be sent because the receiver tries to be nasty). File: postscreen/postscreen_send.c. + +20110104 + + Feature: add contact information to each SMTP server reject + message. For example, "smtpd_reject_contact_information = + call 800-555-0101 for assistance", with macro expansion and + with multi-line support. Files: global/mail_params.h, + mantools/postlink, proto/postconf.proto, smtpd/smtpd.c, + smtpd/smtpd_chat.c, smtpd/smtpd_expand.[hc], util/mac_expand.[hc]. + +20110105 + + Cleanup: the forest of TLS-related booleans was shrunk. + Victor Duchovni. Files: smtpd/smtpd.c, postscreen/postscreen.c, + postscreen/postscreen_smtpd.c, tlsproxy/tlsproxy.c. + + Non-production: tlsproxy support in the Postfix SMTP server + for stress testing of the tlsproxy daemon (#ifdef TLSPROXY). + Seen from outside, Postfix works just as if it has TLS + support built into in smtpd(8). Files: smtpd/smtpd.c, + tls/tls_proxy*.[hc], tlsproxy/tlsproxy.c, util/vstream.[hc]. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 3e8792687..59f0445f8 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -34,6 +34,24 @@ is the $name of an smtpd_xxx parameter with a stress-dependent default). Other postscreen parameters always evaluate as if the stress value is equal to the empty string. +Major changes with snapshot 20110105 +==================================== + +The SMTP server now supports contact information that is appended +to "reject" responses. This includes SMTP server responses that +aren't logged to the maillog file, such as responses to syntax +errors, or unsupported commands. + +Example: + smtpd_reject_contact_information = For assistance, call 800-555-0101. + +Server response: + 550-5.5.1 Recipient address rejected: User unknown + 550 5.5.1 For assistance, call 800-555-0101. + +This feature supports macro expansion ($client_address, $localtime, +etc.), as documented in the postconf(5) manpage. + Incompatibility with snapshot 20110102 ====================================== @@ -397,59 +415,6 @@ any checks on clients in mynetworks (primarily, to avoid problems with buggy SMTP implementations in network appliances). The logging function alone is already useful for research. -postscreen(8) can be configured to drop clients that start talking -too soon, or clients that appear on DNS blocklists. For details, -see below. - postscreen(8) has been tested on FreeBSD and Linux systems. It probably needs additional work before it can be used on Solaris. -This snapshot adds three new entries to the master.cf file. - -To enable the postscreen(8) service and log client information -without blocking mail: - -1 - Comment out the "smtp inet ... smtpd" service in master.cf, - including any "-o parameter=value" entries that follow. - -2 - Uncomment the new "smtpd pass ... smtpd" service in master.cf, - and duplicate any "-o parameter=value" entries from the smtpd - service that was commented out in step 1. - -3 - Uncomment the the new "smtp inet ... postscreen" service in - master.cf. - -4 - Uncomment the new "dnsblog unix ... dnsblog" service in - master.cf. This service does DNSBL lookups for postscreen(8) - and logs results. - -5 - To enable DNSBL lookups, list some DNS blocklist sites in - main.cf, e.g., "postscreen_dnsbl_sites = zen.spamhaus.org". - Separate domain names with comma or whitespace. - -Note: you must stop and start the master daemon. This is needed -because the Postfix "pass" master service type did not work reliably -on all systems. - -To use the postscreen(8) service to block mail, edit main.cf and -specify one or more of: - -- "postscreen_greet_action = drop", to drop clients that talk before - their turn. This alone stops about one third of all known-to-be - illegitimate connections to Wietse's mail server. - -- "postscreen_hangup_action = drop", to waste no time on clients - that hang up without sending a command. On Wietse's server, only - one percent of illegitimate connections behaves like this. - -- "postscreen_dnsbl_action = drop", to drop clients that are on DNS - blocklists. Different blocklists cover different client categories. - -There is also support for permanent blacklists and whitelists; see -the postscreen(8) manual page for details. - -Note: right now, postscreen(8) "drop" actions disconnect the client -without reporting sender and recipient information. In a future -implementation, the connection may instead be passed to a dummy -SMTP protocol engine that logs sender and recipient information -before dropping the connection. diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 016482248..e243dcd86 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -2,6 +2,8 @@ Wish list: Remove this file from the stable release. + Re-run "make depend" with all plugins enabled. + anvil rate limit for sasl_username. Encapsulate nbbio buffer access and update by tlsproxy. diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 36e036254..3e7b683e6 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -13000,6 +13000,70 @@ Example: + + +
smtpd_reject_contact_information +(default: empty)
+ +

Optional contact information that is appended after each SMTP +server 4XX or 5XX response.

+ +

Example:

+ +
+/etc/postfix/main.cf:
+    smtpd_reject_contact_information = For assistance, call 800-555-0101.
+     Please provide the following information in your problem report:
+     time ($localtime) and client address ($client_address).
+
+ +

Server response:

+ +
+550-5.5.1 <user@example> Recipient address rejected: User unknown
+550 5.5.1 For assistance, call 800-555-0101. Please provide the
+following information in your problem report: time (Jan 4 15:42:00)
+and client address (192.168.1.248).
+
+ +

Note: this text is meant to make it easier to find the Postfix +logfile records for a failed SMTP session. The text itself is not +logged to the Postfix server's maillog file.

+ +

Be sure to keep the text as short as possible. Long text may +be truncated before it is logged in the senders maillog file, or +before it is returned to the sender in a delivery status notification. +

+ +

This feature supports a limited number of $name attributes in +the contact text. These are replaced by their current value for the +SMTP session:

+ +
+ +
client_address
Client IP address
+ +
client_port
Client TCP port
+ +
localtime
Server local time (Mmm dd hh:mm:ss)
+ +
recipient
The address in the RCPT TO command
+ +
sender
The address in the MAIL FROM command
+ +
+ +

For safety reasons, text that does not match $smtpd_expansion_filter +is censored.

+ +

This feature supports \n as a request for a line break in the +contact text. Postfix automatically inserts after each line break +the three-digit SMTP reply code (and optional enhanced status code) +from the original Postfix reject message.

+ +

This feature is available in Postfix 2.8 and later.

+ +
smtpd_reject_unlisted_recipient diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index e942ab4d0..841eb9cbe 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -388,7 +388,7 @@ SMTPD(8) SMTPD(8) Postfix SMTP server uses for TLS encrypted SMTP sessions. - smtpd_starttls_timeout (300s) + smtpd_starttls_timeout (see 'postconf -d' output) The time limit for Postfix SMTP server write and read operations during TLS startup and shutdown handshake procedures. @@ -647,6 +647,10 @@ SMTPD(8) SMTPD(8) The list of error classes that are reported to the postmaster. + smtpd_reject_contact_information (empty) + Optional contact information that is appended after + each SMTP server 4XX or 5XX response. + soft_bounce (no) Safety net to keep mail queued that would otherwise be returned to the sender. @@ -654,22 +658,22 @@ SMTPD(8) SMTPD(8) Available in Postfix version 2.1 and later: smtpd_authorized_xclient_hosts (empty) - What SMTP clients are allowed to use the XCLIENT + What SMTP clients are allowed to use the XCLIENT feature. KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS - As of Postfix version 2.0, the SMTP server rejects mail - for unknown recipients. This prevents the mail queue from - clogging up with undeliverable MAILER-DAEMON messages. - Additional information on this topic is in the + As of Postfix version 2.0, the SMTP server rejects mail + for unknown recipients. This prevents the mail queue from + clogging up with undeliverable MAILER-DAEMON messages. + Additional information on this topic is in the LOCAL_RECIPIENT_README and ADDRESS_CLASS_README documents. show_user_unknown_table_name (yes) - Display the name of the recipient table in the + Display the name of the recipient table in the "User unknown" responses. canonical_maps (empty) - Optional address mapping lookup tables for message + Optional address mapping lookup tables for message headers and envelopes. recipient_canonical_maps (empty) @@ -680,7 +684,7 @@ SMTPD(8) SMTPD(8) mydestination ($myhostname, localhost.$mydomain, local- host) - The list of domains that are delivered via the + The list of domains that are delivered via the $local_transport mail delivery transport. inet_interfaces (all) @@ -689,146 +693,146 @@ SMTPD(8) SMTPD(8) 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. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. local_recipient_maps (proxy:unix:passwd.byname $alias_maps) - Lookup tables with all names or addresses of local - recipients: a recipient address is local when its - domain matches $mydestination, $inet_interfaces or + Lookup tables with all names or addresses of local + recipients: a recipient address is local when its + domain matches $mydestination, $inet_interfaces or $proxy_interfaces. unknown_local_recipient_reject_code (550) - The numerical Postfix SMTP server response code - when a recipient address is local, and - $local_recipient_maps specifies a list of lookup + The numerical Postfix SMTP server response code + when a recipient address is local, and + $local_recipient_maps specifies a list of lookup tables that does not match the recipient. - Parameters concerning known/unknown recipients of relay + Parameters concerning known/unknown recipients of relay destinations: relay_domains ($mydestination) - What destination domains (and subdomains thereof) + What destination domains (and subdomains thereof) this system will relay mail to. relay_recipient_maps (empty) - Optional lookup tables with all valid addresses in + Optional lookup tables with all valid addresses in the domains that match $relay_domains. unknown_relay_recipient_reject_code (550) The numerical Postfix SMTP server reply code when a - recipient address matches $relay_domains, and - relay_recipient_maps specifies a list of lookup + recipient address matches $relay_domains, and + relay_recipient_maps specifies a list of lookup tables that does not match the recipient address. - Parameters concerning known/unknown recipients in virtual + Parameters concerning known/unknown recipients in virtual alias domains: virtual_alias_domains ($virtual_alias_maps) Postfix is final destination for the specified list - of virtual alias domains, that is, domains for - which all addresses are aliased to addresses in + of virtual alias domains, that is, domains for + which all addresses are aliased to addresses in other local or remote domains. virtual_alias_maps ($virtual_maps) - Optional lookup tables that alias specific mail - addresses or domains to other local or remote + Optional lookup tables that alias specific mail + addresses or domains to other local or remote address. unknown_virtual_alias_reject_code (550) The SMTP server reply code when a recipient address - matches $virtual_alias_domains, and $vir- - tual_alias_maps specifies a list of lookup tables + matches $virtual_alias_domains, and $vir- + tual_alias_maps specifies a list of lookup tables that does not match the recipient address. - Parameters concerning known/unknown recipients in virtual + Parameters concerning known/unknown recipients in virtual mailbox domains: virtual_mailbox_domains ($virtual_mailbox_maps) Postfix is final destination for the specified list - of domains; mail is delivered via the $vir- + of domains; mail is delivered via the $vir- tual_transport mail delivery transport. virtual_mailbox_maps (empty) - Optional lookup tables with all valid addresses in + Optional lookup tables with all valid addresses in the domains that match $virtual_mailbox_domains. unknown_virtual_mailbox_reject_code (550) The SMTP server reply code when a recipient address - matches $virtual_mailbox_domains, and $vir- + matches $virtual_mailbox_domains, and $vir- tual_mailbox_maps specifies a list of lookup tables that does not match the recipient address. RESOURCE AND RATE CONTROLS - The following parameters limit resource usage by the SMTP + The following parameters limit resource usage by the SMTP server and/or control client request rates. line_length_limit (2048) - Upon input, long lines are chopped up into pieces - of at most this length; upon delivery, long lines + Upon input, long lines are chopped up into pieces + of at most this length; upon delivery, long lines are reconstructed. queue_minfree (0) - The minimal amount of free space in bytes in the + The minimal amount of free space in bytes in the queue file system that is needed to receive mail. message_size_limit (10240000) - The maximal size in bytes of a message, including + The maximal size in bytes of a message, including envelope information. smtpd_recipient_limit (1000) - The maximal number of recipients that the Postfix + The maximal number of recipients that the Postfix SMTP server accepts per message delivery request. smtpd_timeout (normal: 300s, overload: 10s) - The time limit for sending a Postfix SMTP server - response and for receiving a remote SMTP client + The time limit for sending a Postfix SMTP server + response and for receiving a remote SMTP client request. smtpd_history_flush_threshold (100) - The maximal number of lines in the Postfix SMTP - server command history before it is flushed upon + The maximal number of lines in the Postfix SMTP + server command history before it is flushed upon receipt of EHLO, RSET, or end of DATA. Available in Postfix version 2.3 and later: smtpd_peername_lookup (yes) Attempt to look up the remote SMTP client hostname, - and verify that the name matches the client IP + and verify that the name matches the client IP address. The per SMTP client connection count and request rate lim- its are implemented in co-operation with the anvil(8) ser- - vice, and are available in Postfix version 2.2 and later. + vice, and are available in Postfix version 2.2 and later. smtpd_client_connection_count_limit (50) - How many simultaneous connections any client is + How many simultaneous connections any client is allowed to make to this service. smtpd_client_connection_rate_limit (0) The maximal number of connection attempts any - client is allowed to make to this service per time + client is allowed to make to this service per time unit. smtpd_client_message_rate_limit (0) - The maximal number of message delivery requests - that any client is allowed to make to this service + The maximal number of message delivery requests + that any client is allowed to make to this service per time unit, regardless of whether or not Postfix actually accepts those messages. smtpd_client_recipient_rate_limit (0) - The maximal number of recipient addresses that any - client is allowed to send to this service per time + The maximal number of recipient addresses that any + client is allowed to send to this service per time unit, regardless of whether or not Postfix actually accepts those recipients. smtpd_client_event_limit_exceptions ($mynetworks) - Clients that are excluded from + Clients that are excluded from smtpd_client_*_count/rate_limit restrictions. Available in Postfix version 2.3 and later: @@ -839,52 +843,52 @@ SMTPD(8) SMTPD(8) tiate with this service per time unit. TARPIT CONTROLS - When a remote SMTP client makes errors, the Postfix SMTP - server can insert delays before responding. This can help - to slow down run-away software. The behavior is con- - trolled by an error counter that counts the number of - errors within an SMTP session that a client makes without + When a remote SMTP client makes errors, the Postfix SMTP + server can insert delays before responding. This can help + to slow down run-away software. The behavior is con- + trolled by an error counter that counts the number of + errors within an SMTP session that a client makes without delivering mail. smtpd_error_sleep_time (1s) With Postfix version 2.1 and later: the SMTP server - response delay after a client has made more than - $smtpd_soft_error_limit errors, and fewer than - $smtpd_hard_error_limit errors, without delivering + response delay after a client has made more than + $smtpd_soft_error_limit errors, and fewer than + $smtpd_hard_error_limit errors, without delivering mail. smtpd_soft_error_limit (10) - The number of errors a remote SMTP client is - allowed to make without delivering mail before the + The number of errors a remote SMTP client is + allowed to make without delivering mail before the Postfix SMTP server slows down all its responses. smtpd_hard_error_limit (normal: 20, overload: 1) - The maximal number of errors a remote SMTP client + The maximal number of errors a remote SMTP client is allowed to make without delivering mail. smtpd_junk_command_limit (normal: 100, overload: 1) - The number of junk commands (NOOP, VRFY, ETRN or + The number of junk commands (NOOP, VRFY, ETRN or RSET) that a remote SMTP client can send before the - Postfix SMTP server starts to increment the error + Postfix SMTP server starts to increment the error counter with each junk command. Available in Postfix version 2.1 and later: smtpd_recipient_overshoot_limit (1000) - The number of recipients that a remote SMTP client - can send in excess of the limit specified with + The number of recipients that a remote SMTP client + can send in excess of the limit specified with $smtpd_recipient_limit, before the Postfix SMTP - server increments the per-session error count for + server increments the per-session error count for each excess recipient. ACCESS POLICY DELEGATION CONTROLS - As of version 2.1, Postfix can be configured to delegate - access policy decisions to an external server that runs - outside Postfix. See the file SMTPD_POLICY_README for + As of version 2.1, Postfix can be configured to delegate + access policy decisions to an external server that runs + outside Postfix. See the file SMTPD_POLICY_README for more information. smtpd_policy_service_max_idle (300s) - The time after which an idle SMTPD policy service + The time after which an idle SMTPD policy service connection is closed. smtpd_policy_service_max_ttl (1000s) @@ -892,151 +896,151 @@ SMTPD(8) SMTPD(8) connection is closed. smtpd_policy_service_timeout (100s) - The time limit for connecting to, writing to or + The time limit for connecting to, writing to or receiving from a delegated SMTPD policy server. ACCESS CONTROLS - The SMTPD_ACCESS_README document gives an introduction to + The SMTPD_ACCESS_README document gives an introduction to all the SMTP server access control features. smtpd_delay_reject (yes) - Wait until the RCPT TO command before evaluating + Wait until the RCPT TO command before evaluating $smtpd_client_restrictions, $smtpd_helo_restric- tions and $smtpd_sender_restrictions, or wait until - the ETRN command before evaluating + the ETRN command before evaluating $smtpd_client_restrictions and $smtpd_helo_restric- tions. - parent_domain_matches_subdomains (see 'postconf -d' out- + parent_domain_matches_subdomains (see 'postconf -d' out- put) What Postfix features match subdomains of "domain.tld" automatically, instead of requiring an explicit ".domain.tld" pattern. smtpd_client_restrictions (empty) - Optional SMTP server access restrictions in the + Optional SMTP server access restrictions in the context of a client SMTP connection request. smtpd_helo_required (no) Require that a remote SMTP client introduces itself - with the HELO or EHLO command before sending the - MAIL command or other commands that require EHLO + with the HELO or EHLO command before sending the + MAIL command or other commands that require EHLO negotiation. smtpd_helo_restrictions (empty) - Optional restrictions that the Postfix SMTP server + Optional restrictions that the Postfix SMTP server applies in the context of the SMTP HELO command. smtpd_sender_restrictions (empty) - Optional restrictions that the Postfix SMTP server + Optional restrictions that the Postfix SMTP server applies in the context of the MAIL FROM command. smtpd_recipient_restrictions (permit_mynetworks, reject_unauth_destination) The access restrictions that the Postfix SMTP - server applies in the context of the RCPT TO com- + server applies in the context of the RCPT TO com- mand. smtpd_etrn_restrictions (empty) - Optional SMTP server access restrictions in the + Optional SMTP server access restrictions in the context of a client ETRN request. allow_untrusted_routing (no) - Forward mail with sender-specified routing - (user[@%!]remote[@%!]site) from untrusted clients + Forward mail with sender-specified routing + (user[@%!]remote[@%!]site) from untrusted clients to destinations matching $relay_domains. smtpd_restriction_classes (empty) - User-defined aliases for groups of access restric- + User-defined aliases for groups of access restric- tions. smtpd_null_access_lookup_key (<>) - The lookup key to be used in SMTP access(5) tables + The lookup key to be used in SMTP access(5) tables instead of the null sender address. permit_mx_backup_networks (empty) Restrict the use of the permit_mx_backup SMTP - access feature to only domains whose primary MX + access feature to only domains whose primary MX hosts match the listed networks. Available in Postfix version 2.0 and later: smtpd_data_restrictions (empty) - Optional access restrictions that the Postfix SMTP + Optional access restrictions that the Postfix SMTP server applies in the context of the SMTP DATA com- mand. smtpd_expansion_filter (see 'postconf -d' output) - What characters are allowed in $name expansions of + What characters are allowed in $name expansions of RBL reply templates. Available in Postfix version 2.1 and later: smtpd_reject_unlisted_sender (no) - Request that the Postfix SMTP server rejects mail - from unknown sender addresses, even when no - explicit reject_unlisted_sender access restriction + Request that the Postfix SMTP server rejects mail + from unknown sender addresses, even when no + explicit reject_unlisted_sender access restriction is specified. smtpd_reject_unlisted_recipient (yes) - Request that the Postfix SMTP server rejects mail + Request that the Postfix SMTP server rejects mail for unknown recipient addresses, even when no - explicit reject_unlisted_recipient access restric- + explicit reject_unlisted_recipient access restric- tion is specified. Available in Postfix version 2.2 and later: smtpd_end_of_data_restrictions (empty) - Optional access restrictions that the Postfix SMTP - server applies in the context of the SMTP END-OF- + Optional access restrictions that the Postfix SMTP + server applies in the context of the SMTP END-OF- DATA command. SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS - Postfix version 2.1 introduces sender and recipient - address verification. This feature is implemented by - sending probe email messages that are not actually deliv- - ered. This feature is requested via the reject_unveri- - fied_sender and reject_unverified_recipient access - restrictions. The status of verification probes is main- + Postfix version 2.1 introduces sender and recipient + address verification. This feature is implemented by + sending probe email messages that are not actually deliv- + ered. This feature is requested via the reject_unveri- + fied_sender and reject_unverified_recipient access + restrictions. The status of verification probes is main- tained by the verify(8) server. See the file ADDRESS_VER- - IFICATION_README for information about how to configure + IFICATION_README for information about how to configure and operate the Postfix sender/recipient address verifica- tion service. address_verify_poll_count (normal: 3, overload: 1) - How many times to query the verify(8) service for - the completion of an address verification request + How many times to query the verify(8) service for + the completion of an address verification request in progress. address_verify_poll_delay (3s) - The delay between queries for the completion of an + The delay between queries for the completion of an address verification request in progress. address_verify_sender ($double_bounce_sender) - The sender address to use in address verification + The sender address to use in address verification probes; prior to Postfix 2.5 the default was "post- master". unverified_sender_reject_code (450) - The numerical Postfix SMTP server response code - when a recipient address is rejected by the + The numerical Postfix SMTP server response code + when a recipient address is rejected by the reject_unverified_sender restriction. unverified_recipient_reject_code (450) - The numerical Postfix SMTP server response when a + The numerical Postfix SMTP server response when a recipient address is rejected by the reject_unveri- fied_recipient restriction. Available in Postfix version 2.6 and later: unverified_sender_defer_code (450) - The numerical Postfix SMTP server response code - when a sender address probe fails due to a tempo- + The numerical Postfix SMTP server response code + when a sender address probe fails due to a tempo- rary error condition. unverified_recipient_defer_code (450) - The numerical Postfix SMTP server response when a - recipient address probe fails due to a temporary + The numerical Postfix SMTP server response when a + recipient address probe fails due to a temporary error condition. unverified_sender_reject_reason (empty) @@ -1050,7 +1054,7 @@ SMTPD(8) SMTPD(8) unverified_sender_tempfail_action ($reject_temp- fail_action) The Postfix SMTP server's action when reject_unver- - ified_sender fails due to a temporary error condi- + ified_sender fails due to a temporary error condi- tion. unverified_recipient_tempfail_action ($reject_temp- @@ -1060,7 +1064,7 @@ SMTPD(8) SMTPD(8) dition. ACCESS CONTROL RESPONSES - The following parameters control numerical SMTP reply + The following parameters control numerical SMTP reply codes and/or text responses. access_map_reject_code (554) @@ -1068,18 +1072,18 @@ SMTPD(8) SMTPD(8) an access(5) map "reject" action. defer_code (450) - The numerical Postfix SMTP server response code - when a remote SMTP client request is rejected by + The numerical Postfix SMTP server response code + when a remote SMTP client request is rejected by the "defer" restriction. invalid_hostname_reject_code (501) - The numerical Postfix SMTP server response code - when the client HELO or EHLO command parameter is - rejected by the reject_invalid_helo_hostname + The numerical Postfix SMTP server response code + when the client HELO or EHLO command parameter is + rejected by the reject_invalid_helo_hostname restriction. maps_rbl_reject_code (554) - The numerical Postfix SMTP server response code + The numerical Postfix SMTP server response code when a remote SMTP client request is blocked by the reject_rbl_client, reject_rhsbl_client, reject_rhsbl_reverse_client, reject_rhsbl_sender or @@ -1087,53 +1091,53 @@ SMTPD(8) SMTPD(8) non_fqdn_reject_code (504) The numerical Postfix SMTP server reply code when a - client request is rejected by the + client request is rejected by the reject_non_fqdn_helo_hostname, reject_non_fqdn_sender or reject_non_fqdn_recipient restriction. plaintext_reject_code (450) - The numerical Postfix SMTP server response code - when a request is rejected by the reject_plain- + The numerical Postfix SMTP server response code + when a request is rejected by the reject_plain- text_session restriction. reject_code (554) - The numerical Postfix SMTP server response code - when a remote SMTP client request is rejected by + The numerical Postfix SMTP server response code + when a remote SMTP client request is rejected by the "reject" restriction. relay_domains_reject_code (554) - The numerical Postfix SMTP server response code - when a client request is rejected by the + The numerical Postfix SMTP server response code + when a client request is rejected by the reject_unauth_destination recipient restriction. unknown_address_reject_code (450) - The numerical Postfix SMTP server response code - when a sender or recipient address is rejected by + The numerical Postfix SMTP server response code + when a sender or recipient address is rejected by the reject_unknown_sender_domain or reject_unknown_recipient_domain restriction. unknown_client_reject_code (450) - The numerical Postfix SMTP server response code - when a client without valid address <=> name map- + The numerical Postfix SMTP server response code + when a client without valid address <=> name map- ping is rejected by the reject_unknown_client_host- name restriction. unknown_hostname_reject_code (450) - The numerical Postfix SMTP server response code - when the hostname specified with the HELO or EHLO - command is rejected by the + The numerical Postfix SMTP server response code + when the hostname specified with the HELO or EHLO + command is rejected by the reject_unknown_helo_hostname restriction. Available in Postfix version 2.0 and later: default_rbl_reply (see 'postconf -d' output) - The default SMTP server response template for a - request that is rejected by an RBL-based restric- + The default SMTP server response template for a + request that is rejected by an RBL-based restric- tion. multi_recipient_bounce_reject_code (550) - The numerical Postfix SMTP server response code + The numerical Postfix SMTP server response code when a remote SMTP client request is blocked by the reject_multi_recipient_bounce restriction. @@ -1144,38 +1148,38 @@ SMTPD(8) SMTPD(8) access_map_defer_code (450) The numerical Postfix SMTP server response code for - an access(5) map "defer" action, including + an access(5) map "defer" action, including "defer_if_permit" or "defer_if_reject". reject_tempfail_action (defer_if_permit) The Postfix SMTP server's action when a reject-type - restriction fails due to a temporary error condi- + restriction fails due to a temporary error condi- tion. unknown_helo_hostname_tempfail_action ($reject_temp- fail_action) - The Postfix SMTP server's action when + The Postfix SMTP server's action when reject_unknown_helo_hostname fails due to an tempo- rary error condition. unknown_address_tempfail_action ($reject_tempfail_action) - The Postfix SMTP server's action when + The Postfix SMTP server's action when reject_unknown_sender_domain or - reject_unknown_recipient_domain fail due to a tem- + reject_unknown_recipient_domain fail due to a tem- porary error condition. MISCELLANEOUS CONTROLS 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. command_directory (see 'postconf -d' output) - The location of all postfix administrative com- + The location of all postfix administrative com- mands. double_bounce_sender (double-bounce) @@ -1196,37 +1200,37 @@ SMTPD(8) SMTPD(8) and most Postfix daemon processes. max_idle (100s) - The maximum amount of time that an idle Postfix - daemon process waits for an incoming connection + The maximum amount of time that an idle Postfix + daemon process waits for an incoming connection before terminating voluntarily. max_use (100) - The maximal number of incoming connections that a - Postfix daemon process will service before termi- + The maximal number of incoming connections that a + Postfix daemon process will service before termi- nating voluntarily. myhostname (see 'postconf -d' output) The internet hostname of this mail system. mynetworks (see 'postconf -d' output) - The list of "trusted" SMTP clients that have more + The list of "trusted" SMTP clients that have more privileges than "strangers". myorigin ($myhostname) The domain name that locally-posted mail appears to - come from, and that locally posted mail is deliv- + come from, and that locally posted mail is deliv- ered to. 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. queue_directory (see 'postconf -d' output) - The location of the Postfix top-level queue direc- + The location of the Postfix top-level queue direc- tory. recipient_delimiter (empty) @@ -1234,28 +1238,28 @@ SMTPD(8) SMTPD(8) sions (user+foo). smtpd_banner ($myhostname ESMTP $mail_name) - The text that follows the 220 status code in the + The text that follows the 220 status code in the SMTP greeting banner. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - 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 in Postfix version 2.2 and later: smtpd_forbidden_commands (CONNECT, GET, POST) List of commands that cause the Postfix SMTP server - to immediately terminate the session with a 221 + to immediately terminate the session with a 221 code. Available in Postfix version 2.5 and later: smtpd_client_port_logging (no) - Enable logging of the remote SMTP client port in + Enable logging of the remote SMTP client port in addition to the hostname and IP address. SEE ALSO @@ -1285,7 +1289,7 @@ SMTPD(8) SMTPD(8) XFORWARD_README, Postfix XFORWARD extension 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/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 66beefb09..0258f573c 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -8094,6 +8094,67 @@ smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination .fi .ad .ft R +.SH smtpd_reject_contact_information (default: empty) +Optional contact information that is appended after each SMTP +server 4XX or 5XX response. +.PP +Example: +.PP +.nf +.na +.ft C +/etc/postfix/main.cf: + smtpd_reject_contact_information = For assistance, call 800-555-0101. + Please provide the following information in your problem report: + time ($localtime) and client address ($client_address). +.fi +.ad +.ft R +.PP +Server response: +.PP +.nf +.na +.ft C +550-5.5.1 Recipient address rejected: User unknown +550 5.5.1 For assistance, call 800-555-0101. Please provide the +following information in your problem report: time (Jan 4 15:42:00) +and client address (192.168.1.248). +.fi +.ad +.ft R +.PP +Note: this text is meant to make it easier to find the Postfix +logfile records for a failed SMTP session. The text itself is not +logged to the Postfix server's maillog file. +.PP +Be sure to keep the text as short as possible. Long text may +be truncated before it is logged in the senders maillog file, or +before it is returned to the sender in a delivery status notification. +.PP +This feature supports a limited number of $name attributes in +the contact text. These are replaced by their current value for the +SMTP session: +.IP "client_address" +Client IP address +.IP "client_port" +Client TCP port +.IP "localtime" +Server local time (Mmm dd hh:mm:ss) +.IP "recipient" +The address in the RCPT TO command +.IP "sender" +The address in the MAIL FROM command +.PP +For safety reasons, text that does not match $smtpd_expansion_filter +is censored. +.PP +This feature supports \en as a request for a line break in the +contact text. Postfix automatically inserts after each line break +the three-digit SMTP reply code (and optional enhanced status code) +from the original Postfix reject message. +.PP +This feature is available in Postfix 2.8 and later. .SH smtpd_reject_unlisted_recipient (default: yes) Request that the Postfix SMTP server rejects mail for unknown recipient addresses, even when no explicit reject_unlisted_recipient diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 1dd8cc5ae..a4f7fd5ea 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -341,7 +341,7 @@ smtpd_use_tls and smtpd_enforce_tls. .IP "\fBsmtpd_sasl_tls_security_options ($smtpd_sasl_security_options)\fR" The SASL authentication security options that the Postfix SMTP server uses for TLS encrypted SMTP sessions. -.IP "\fBsmtpd_starttls_timeout (300s)\fR" +.IP "\fBsmtpd_starttls_timeout (see 'postconf -d' output)\fR" The time limit for Postfix SMTP server write and read operations during TLS startup and shutdown handshake procedures. .IP "\fBsmtpd_tls_CAfile (empty)\fR" @@ -527,6 +527,9 @@ before-queue content inspection by non_smtpd_milters, header_checks and body_checks. .IP "\fBnotify_classes (resource, software)\fR" The list of error classes that are reported to the postmaster. +.IP "\fBsmtpd_reject_contact_information (empty)\fR" +Optional contact information that is appended after each SMTP +server 4XX or 5XX response. .IP "\fBsoft_bounce (no)\fR" Safety net to keep mail queued that would otherwise be returned to the sender. diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 937495de4..e77614fe5 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -666,6 +666,7 @@ while (<>) { s;\bsmtpd_tls_always_issue_session_ids\b;$&;g; s;\bsmtpd_tls_wrappermode\b;$&;g; s;\bsmtpd_use_tls\b;$&;g; + s;\bsmtpd_reject_contact_information\b;$&;g; s;\btls_daemon_random_bytes\b;$&;g; s;\btls_daemon_random_source\b;$&;g; s;\btls_ran[-]*\n* *[]*dom_bytes\b;$&;g; diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 0a44cfdfc..c39a711cc 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -13822,3 +13822,62 @@ for further details.

This feature is available in Postfix 2.8 and later.

+%PARAM smtpd_reject_contact_information + +

Optional contact information that is appended after each SMTP +server 4XX or 5XX response.

+ +

Example:

+ +
+/etc/postfix/main.cf:
+    smtpd_reject_contact_information = For assistance, call 800-555-0101.
+     Please provide the following information in your problem report:
+     time ($localtime) and client address ($client_address).
+
+ +

Server response:

+ +
+550-5.5.1 <user@example> Recipient address rejected: User unknown
+550 5.5.1 For assistance, call 800-555-0101. Please provide the
+following information in your problem report: time (Jan 4 15:42:00)
+and client address (192.168.1.248).
+
+ +

Note: this text is meant to make it easier to find the Postfix +logfile records for a failed SMTP session. The text itself is not +logged to the Postfix server's maillog file.

+ +

Be sure to keep the text as short as possible. Long text may +be truncated before it is logged in the senders maillog file, or +before it is returned to the sender in a delivery status notification. +

+ +

This feature supports a limited number of $name attributes in +the contact text. These are replaced by their current value for the +SMTP session:

+ +
+ +
client_address
Client IP address
+ +
client_port
Client TCP port
+ +
localtime
Server local time (Mmm dd hh:mm:ss)
+ +
recipient
The address in the RCPT TO command
+ +
sender
The address in the MAIL FROM command
+ +
+ +

For safety reasons, text that does not match $smtpd_expansion_filter +is censored.

+ +

This feature supports \n as a request for a line break in the +contact text. Postfix automatically inserts after each line break +the three-digit SMTP reply code (and optional enhanced status code) +from the original Postfix reject message.

+ +

This feature is available in Postfix 2.8 and later.

diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 6c1e0166d..47ab4d16a 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -802,6 +802,7 @@ dict_ldap.o: ../../include/match_list.h dict_ldap.o: ../../include/match_ops.h dict_ldap.o: ../../include/msg.h dict_ldap.o: ../../include/mymalloc.h +dict_ldap.o: ../../include/name_code.h dict_ldap.o: ../../include/stringops.h dict_ldap.o: ../../include/sys_defs.h dict_ldap.o: ../../include/vbuf.h @@ -811,6 +812,7 @@ dict_ldap.o: cfg_parser.h dict_ldap.o: db_common.h dict_ldap.o: dict_ldap.c dict_ldap.o: dict_ldap.h +dict_ldap.o: mail_conf.h dict_ldap.o: string_list.h dict_mysql.o: ../../include/sys_defs.h dict_mysql.o: dict_mysql.c diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index a0796063b..c5644526b 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -3554,6 +3554,13 @@ extern int var_tlsp_tls_scache_timeout; #define DEF_TLSP_TLS_SET_SESSID "$" VAR_SMTPD_TLS_SET_SESSID extern bool var_tlsp_tls_set_sessid; + /* + * SMTPD "reject" contact info. + */ +#define VAR_SMTPD_REJ_CONTACT "smtpd_reject_contact_information" +#define DEF_SMTPD_REJ_CONTACT "" +extern char *var_smtpd_rej_contact; + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index c3c97b5ad..84e825473 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -111,6 +111,7 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_ERRTO "errors-to" #define MAIL_ATTR_RRCPT "return-receipt" #define MAIL_ATTR_TIME "time" +#define MAIL_ATTR_LOCALTIME "localtime" #define MAIL_ATTR_CREATE_TIME "create_time" #define MAIL_ATTR_RULE "rule" #define MAIL_ATTR_ADDR "address" @@ -244,6 +245,14 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_ROLE_SERVER "server" #define MAIL_ATTR_ROLE_CLIENT "client" #define MAIL_ATTR_TIMEOUT "timeout" +#define MAIL_ATTR_PEER_CN "peer_CN" +#define MAIL_ATTR_ISSUER_CN "issuer_CN" +#define MAIL_ATTR_PEER_FPT "peer_fingerprint" +#define MAIL_ATTR_PEER_STATUS "peer_status" +#define MAIL_ATTR_CIPHER_PROTOCOL "cipher_protocol" +#define MAIL_ATTR_CIPHER_NAME "cipher_name" +#define MAIL_ATTR_CIPHER_USEBITS "cipher_usebits" +#define MAIL_ATTR_CIPHER_ALGBITS "cipher_algbits" /* LICENSE /* .ad diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index c7ae8e44e..ffb3e0e7e 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 "20110103" +#define MAIL_RELEASE_DATE "20110105" #define MAIL_VERSION_NUMBER "2.8" #ifdef SNAPSHOT diff --git a/postfix/src/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in index 5e41241a9..615ebb8f8 100644 --- a/postfix/src/postscreen/Makefile.in +++ b/postfix/src/postscreen/Makefile.in @@ -234,9 +234,13 @@ postscreen_starttls.o: ../../include/match_list.h postscreen_starttls.o: ../../include/match_ops.h postscreen_starttls.o: ../../include/msg.h postscreen_starttls.o: ../../include/mymalloc.h +postscreen_starttls.o: ../../include/name_code.h +postscreen_starttls.o: ../../include/name_mask.h postscreen_starttls.o: ../../include/string_list.h postscreen_starttls.o: ../../include/stringops.h postscreen_starttls.o: ../../include/sys_defs.h +postscreen_starttls.o: ../../include/tls.h +postscreen_starttls.o: ../../include/tls_proxy.h postscreen_starttls.o: ../../include/vbuf.h postscreen_starttls.o: ../../include/vstream.h postscreen_starttls.o: ../../include/vstring.h diff --git a/postfix/src/postscreen/postscreen_smtpd.c b/postfix/src/postscreen/postscreen_smtpd.c index 07ebc8ca8..5384eb80e 100644 --- a/postfix/src/postscreen/postscreen_smtpd.c +++ b/postfix/src/postscreen/postscreen_smtpd.c @@ -205,20 +205,6 @@ static void psc_smtpd_read_event(int, char *); static MAPS *psc_ehlo_discard_maps; static int psc_ehlo_discard_mask; - /* - * STARTTLS support. Note the complete absence of #ifdef USE_TLS throughout - * the postscreen(8) source code. If Postfix is built without TLS support, - * then the TLS proxy will simply report that TLS is not available, and - * conventional error handling will take care of the issue. - */ -static int psc_tls_use_tls; -static int psc_tls_enforce_tls; - -#ifdef TODO_USE_SASL_AUTH -static int psc_tls_auth_only; - -#endif - /* * Encapsulation. We must not forget turn off input/timer events when we * terminate the SMTP protocol engine. @@ -261,7 +247,7 @@ static int psc_helo_cmd(PSC_STATE *state, char *args) /* psc_smtpd_format_ehlo_reply - format EHLO response */ static void psc_smtpd_format_ehlo_reply(VSTRING *buf, int discard_mask - /*, const char *sasl_mechanism_list */) + /* , const char *sasl_mechanism_list */ ) { const char *myname = "psc_smtpd_format_ehlo_reply"; int saved_len = 0; @@ -291,12 +277,11 @@ static void psc_smtpd_format_ehlo_reply(VSTRING *buf, int discard_mask PSC_EHLO_APPEND(saved_len, psc_temp, "250-VRFY\r\n"); if ((discard_mask & EHLO_MASK_ETRN) == 0) PSC_EHLO_APPEND(saved_len, psc_temp, "250-ETRN\r\n"); - if ((discard_mask & EHLO_MASK_STARTTLS) == 0 - && (psc_tls_use_tls || psc_tls_enforce_tls)) + if ((discard_mask & EHLO_MASK_STARTTLS) == 0 && var_psc_use_tls) PSC_EHLO_APPEND(saved_len, psc_temp, "250-STARTTLS\r\n"); #ifdef TODO_SASL_AUTH if ((discard_mask & EHLO_MASK_AUTH) == 0 && sasl_mechanism_list - && (psc_tls_auth_only == 0 || (discard_mask & EHLO_MASK_STARTTLS))) { + && (!var_psc_tls_auth_only || (discard_mask & EHLO_MASK_STARTTLS))) { PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH %s", sasl_mechanism_list); if (var_broken_auth_clients) PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH=%s", sasl_mechanism_list); @@ -393,7 +378,7 @@ static int psc_starttls_cmd(PSC_STATE *state, char *args) if (state->flags & PSC_STATE_FLAG_USING_TLS) return (PSC_SEND_REPLY(state, "554 5.5.1 Error: TLS already active\r\n")); - if (psc_tls_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS)) + if (var_psc_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS)) return (PSC_SEND_REPLY(state, "502 5.5.1 Error: command not implemented\r\n")); @@ -955,7 +940,7 @@ static void psc_smtpd_read_event(int event, char *context) if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) { write_stat = PSC_SEND_REPLY(state, "502 5.5.2 Error: command not recognized\r\n"); - } else if (psc_tls_enforce_tls + } else if (var_psc_enforce_tls && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0 && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) { write_stat = PSC_SEND_REPLY(state, @@ -1052,8 +1037,14 @@ void psc_smtpd_init(void) psc_smtpd_helo_reply = mystrdup(STR(psc_temp)); /* - * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply - * depends on this. + * STARTTLS support. Note the complete absence of #ifdef USE_TLS + * throughout the postscreen(8) source code. If Postfix is built without + * TLS support, then the TLS proxy will simply report that TLS is not + * available, and conventional error handling will take care of the + * issue. + * + * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply depends + * on this. */ if (*var_psc_tls_level) { switch (tls_level_lookup(var_psc_tls_level)) { @@ -1079,11 +1070,9 @@ void psc_smtpd_init(void) break; } } - psc_tls_enforce_tls = var_psc_enforce_tls; - psc_tls_use_tls = var_psc_use_tls || var_psc_enforce_tls; + var_psc_use_tls = var_psc_use_tls || var_psc_enforce_tls; #ifdef TODO_SASL_AUTH - if (var_psc_tls_auth_only || psc_tls_enforce_tls) - psc_tls_auth_only = 1; + var_psc_tls_auth_only = var_psc_tls_auth_only || var_psc_enforce_tls; #endif /* diff --git a/postfix/src/postscreen/postscreen_starttls.c b/postfix/src/postscreen/postscreen_starttls.c index f43b53ec0..9d8c12805 100644 --- a/postfix/src/postscreen/postscreen_starttls.c +++ b/postfix/src/postscreen/postscreen_starttls.c @@ -55,6 +55,10 @@ #include #include +/* TLS library. */ + +#include + /* Application-specific. */ #include @@ -74,7 +78,6 @@ typedef struct { PSC_STATE *smtp_state; /* SMTP session state */ } PSC_STARTTLS; -#define TLSPROXY_SERVICE "tlsproxy" #define TLSPROXY_INIT_TIMEOUT 10 /* psc_starttls_finish - complete negotiation with TLS proxy */ @@ -155,9 +158,15 @@ static void psc_starttls_finish(int event, char *context) * Replace our SMTP client stream by the TLS proxy stream. Once the * TLS handshake is done, the TLS proxy will deliver plaintext SMTP * commands to postscreen(8). + * + * Swap the file descriptors from under the VSTREAM so that we don't + * have to worry about loss of user-configurable VSTREAM attributes. */ - vstream_fclose(smtp_state->smtp_client_stream); - smtp_state->smtp_client_stream = tlsproxy_stream; + vstream_fpurge(smtp_state->smtp_client_stream, VSTREAM_PURGE_BOTH); + vstream_control(smtp_state->smtp_client_stream, + VSTREAM_CTL_SWAP_FD, tlsproxy_stream, + VSTREAM_CTL_END); + vstream_fclose(tlsproxy_stream); /* direct-to-client stream! */ smtp_state->flags |= PSC_STATE_FLAG_USING_TLS; } @@ -210,7 +219,7 @@ void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event) smtp_state->smtp_client_port, (char *) 0); attr_print(tlsproxy_stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt, - ATTR_TYPE_STR, MAIL_ATTR_ROLE, MAIL_ATTR_ROLE_SERVER, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER, ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit, ATTR_TYPE_END); myfree(remote_endpt); diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 0273877d6..856e8b8e6 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -1,13 +1,15 @@ SHELL = /bin/sh SRCS = smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \ smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \ - smtpd_xforward.c smtpd_dsn_fix.c smtpd_milter.c smtpd_resolve.c + smtpd_xforward.c smtpd_dsn_fix.c smtpd_milter.c smtpd_resolve.c \ + smtpd_expand.c OBJS = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \ smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \ - smtpd_xforward.o smtpd_dsn_fix.o smtpd_milter.o smtpd_resolve.o + smtpd_xforward.o smtpd_dsn_fix.o smtpd_milter.o smtpd_resolve.o \ + smtpd_expand.o HDRS = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \ smtpd_sasl_glue.h smtpd_proxy.h smtpd_dsn_fix.h smtpd_milter.h \ - smtpd_resolve.h + smtpd_resolve.h smtpd_expand.h TESTSRC = smtpd_token_test.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) @@ -156,6 +158,8 @@ smtpd.o: ../../include/input_transp.h smtpd.o: ../../include/iostuff.h smtpd.o: ../../include/is_header.h smtpd.o: ../../include/lex_822.h +smtpd.o: ../../include/mac_expand.h +smtpd.o: ../../include/mac_parse.h smtpd.o: ../../include/mail_conf.h smtpd.o: ../../include/mail_date.h smtpd.o: ../../include/mail_error.h @@ -188,6 +192,7 @@ smtpd.o: ../../include/string_list.h smtpd.o: ../../include/stringops.h smtpd.o: ../../include/sys_defs.h smtpd.o: ../../include/tls.h +smtpd.o: ../../include/tls_proxy.h smtpd.o: ../../include/tok822.h smtpd.o: ../../include/valid_hostname.h smtpd.o: ../../include/valid_mailhost_addr.h @@ -202,6 +207,7 @@ smtpd.o: smtpd.c smtpd.o: smtpd.h smtpd.o: smtpd_chat.h smtpd.o: smtpd_check.h +smtpd.o: smtpd_expand.h smtpd.o: smtpd_milter.h smtpd.o: smtpd_proxy.h smtpd.o: smtpd_sasl_glue.h @@ -210,9 +216,12 @@ smtpd.o: smtpd_token.h smtpd_chat.o: ../../include/argv.h smtpd_chat.o: ../../include/attr.h smtpd_chat.o: ../../include/cleanup_user.h +smtpd_chat.o: ../../include/dsn_util.h smtpd_chat.o: ../../include/int_filt.h smtpd_chat.o: ../../include/iostuff.h smtpd_chat.o: ../../include/line_wrap.h +smtpd_chat.o: ../../include/mac_expand.h +smtpd_chat.o: ../../include/mac_parse.h smtpd_chat.o: ../../include/mail_addr.h smtpd_chat.o: ../../include/mail_error.h smtpd_chat.o: ../../include/mail_params.h @@ -237,6 +246,7 @@ smtpd_chat.o: ../../include/vstring.h smtpd_chat.o: smtpd.h smtpd_chat.o: smtpd_chat.c smtpd_chat.o: smtpd_chat.h +smtpd_chat.o: smtpd_expand.h smtpd_check.o: ../../include/argv.h smtpd_check.o: ../../include/attr.h smtpd_check.o: ../../include/attr_clnt.h @@ -303,12 +313,35 @@ smtpd_check.o: smtpd.h smtpd_check.o: smtpd_check.c smtpd_check.o: smtpd_check.h smtpd_check.o: smtpd_dsn_fix.h +smtpd_check.o: smtpd_expand.h smtpd_check.o: smtpd_resolve.h smtpd_check.o: smtpd_sasl_glue.h smtpd_dsn_fix.o: ../../include/msg.h smtpd_dsn_fix.o: ../../include/sys_defs.h smtpd_dsn_fix.o: smtpd_dsn_fix.c smtpd_dsn_fix.o: smtpd_dsn_fix.h +smtpd_expand.o: ../../include/argv.h +smtpd_expand.o: ../../include/attr.h +smtpd_expand.o: ../../include/iostuff.h +smtpd_expand.o: ../../include/mac_expand.h +smtpd_expand.o: ../../include/mac_parse.h +smtpd_expand.o: ../../include/mail_params.h +smtpd_expand.o: ../../include/mail_proto.h +smtpd_expand.o: ../../include/mail_stream.h +smtpd_expand.o: ../../include/milter.h +smtpd_expand.o: ../../include/msg.h +smtpd_expand.o: ../../include/myaddrinfo.h +smtpd_expand.o: ../../include/name_code.h +smtpd_expand.o: ../../include/name_mask.h +smtpd_expand.o: ../../include/stringops.h +smtpd_expand.o: ../../include/sys_defs.h +smtpd_expand.o: ../../include/tls.h +smtpd_expand.o: ../../include/vbuf.h +smtpd_expand.o: ../../include/vstream.h +smtpd_expand.o: ../../include/vstring.h +smtpd_expand.o: smtpd.h +smtpd_expand.o: smtpd_expand.c +smtpd_expand.o: smtpd_expand.h smtpd_milter.o: ../../include/argv.h smtpd_milter.o: ../../include/attr.h smtpd_milter.o: ../../include/mail_params.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 638cc95a0..0026c2571 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -309,7 +309,7 @@ /* .IP "\fBsmtpd_sasl_tls_security_options ($smtpd_sasl_security_options)\fR" /* The SASL authentication security options that the Postfix SMTP /* server uses for TLS encrypted SMTP sessions. -/* .IP "\fBsmtpd_starttls_timeout (300s)\fR" +/* .IP "\fBsmtpd_starttls_timeout (see 'postconf -d' output)\fR" /* The time limit for Postfix SMTP server write and read operations /* during TLS startup and shutdown handshake procedures. /* .IP "\fBsmtpd_tls_CAfile (empty)\fR" @@ -489,6 +489,9 @@ /* and body_checks. /* .IP "\fBnotify_classes (resource, software)\fR" /* The list of error classes that are reported to the postmaster. +/* .IP "\fBsmtpd_reject_contact_information (empty)\fR" +/* Optional contact information that is appended after each SMTP +/* server 4XX or 5XX response. /* .IP "\fBsoft_bounce (no)\fR" /* Safety net to keep mail queued that would otherwise be returned to /* the sender. @@ -1048,6 +1051,7 @@ #include #include #include +#include /* Single-threaded server skeleton. */ @@ -1067,6 +1071,7 @@ #include #include #include +#include /* * Tunable parameters. Make sure that there is some bound on the length of @@ -1182,6 +1187,7 @@ bool var_smtpd_enforce_tls; bool var_smtpd_tls_wrappermode; bool var_smtpd_tls_auth_only; char *var_smtpd_cmd_filter; +char *var_smtpd_rej_contact; #ifdef USE_TLS char *var_smtpd_relay_ccerts; @@ -1324,8 +1330,6 @@ static int ask_client_cert; #endif -static int enforce_tls; - /* * SMTP command mapping for broken clients. */ @@ -1640,7 +1644,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) ENQUEUE_FIX_REPLY(state, reply_buf, SMTPD_CMD_ETRN); #ifdef USE_TLS if ((discard_mask & EHLO_MASK_STARTTLS) == 0) - if ((state->tls_use_tls || state->tls_enforce_tls) && (!state->tls_context)) + if (var_smtpd_use_tls && (!state->tls_context)) ENQUEUE_FIX_REPLY(state, reply_buf, SMTPD_CMD_STARTTLS); #endif #ifdef USE_SASL_AUTH @@ -3958,11 +3962,11 @@ static void smtpd_start_tls(SMTPD_STATE *state) } while (0) if (cipher_grade == 0) { - cipher_grade = - enforce_tls ? var_smtpd_tls_mand_ciph : var_smtpd_tls_ciph; + cipher_grade = var_smtpd_enforce_tls ? + var_smtpd_tls_mand_ciph : var_smtpd_tls_ciph; cipher_exclusions = vstring_alloc(10); ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_excl_ciph); - if (enforce_tls) + if (var_smtpd_enforce_tls) ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_mand_excl); if (ask_client_cert) ADD_EXCLUDE(cipher_exclusions, "aNULL"); @@ -3979,7 +3983,7 @@ static void smtpd_start_tls(SMTPD_STATE *state) log_level = var_smtpd_tls_loglevel, timeout = var_smtpd_starttls_tmout, requirecert = (var_smtpd_tls_req_ccert - && state->tls_enforce_tls), + && var_smtpd_enforce_tls), serverid = state->service, namaddr = state->namaddr, cipher_grade = cipher_grade, @@ -4079,6 +4083,11 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) const char *err; int rate; +#ifdef USE_TLSPROXY + VSTREAM *proxy_stream; + +#endif + if (argc != 1) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 5.5.4 Syntax: STARTTLS"); @@ -4102,18 +4111,20 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) smtpd_chat_reply(state, "554 5.5.1 Error: TLS already active"); return (-1); } - if (state->tls_use_tls == 0 + if (var_smtpd_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS)) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "502 5.5.1 Error: command not implemented"); return (-1); } +#ifndef USE_TLS_PROXY if (smtpd_tls_ctx == 0) { state->error_mask |= MAIL_ERROR_SOFTWARE; /* RFC 4954 Section 6. */ smtpd_chat_reply(state, "454 4.7.0 TLS not available due to local problem"); return (-1); } +#endif /* * Enforce TLS handshake rate limit when this client negotiated too many @@ -4139,9 +4150,11 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) state->namaddr); return (-1); } +#ifndef USE_TLSPROXY smtpd_chat_reply(state, "220 2.0.0 Ready to start TLS"); /* Flush before we switch the stream's read/write routines. */ smtp_flush(state->client); + vstream_fpurge(state->client, VSTREAM_PURGE_READ); /* Yay! */ /* * Reset all inputs to the initial state. @@ -4159,6 +4172,73 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) */ smtpd_start_tls(state); return (0); +#else /* USE_TLSPROXY */ + + /* + * This is non-production code, for tlsproxy(8) load testing only. It + * implements enough to enable the Postfix features that depend on TLS + * encryption. + */ +#define PROXY_OPEN_FLAGS \ + (TLS_PROXY_FLAG_ROLE_SERVER | TLS_PROXY_FLAG_SEND_CONTEXT) + + proxy_stream = tls_proxy_open(PROXY_OPEN_FLAGS, state->client, state->addr, + state->port, var_smtpd_tmout); + if (proxy_stream == 0) { + state->error_mask |= MAIL_ERROR_SOFTWARE; + /* RFC 4954 Section 6. */ + smtpd_chat_reply(state, "454 4.7.0 TLS not available due to local problem"); + return (-1); + } + smtpd_chat_reply(state, "220 2.0.0 Ready to start TLS"); + smtp_flush(state->client); + vstream_fpurge(state->client, VSTREAM_PURGE_READ); + + /* + * Reset all inputs to the initial state. + * + * XXX RFC 2487 does not forbid the use of STARTTLS while mail transfer is + * in progress, so we have to allow it even when it makes no sense. + */ + helo_reset(state); + mail_reset(state); + rcpt_reset(state); +#ifdef USE_SASL_AUTH + if (var_smtpd_sasl_enable) { + if (smtpd_sasl_is_active(state)) { + smtpd_sasl_auth_reset(state); + smtpd_sasl_deactivate(state); + } + smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS, + var_smtpd_sasl_tls_opts); + } +#endif + + /* + * To insert tlsproxy(8) between this process and the SMTP client, we + * swap the file descriptors between the proxy_stream and state->client + * VSTREAMS, so that we don't have to worry about loss of all the + * user-configurable state->client attributes (such as longjump buffers). + */ + vstream_control(proxy_stream, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_END); + vstream_control(state->client, VSTREAM_CTL_SWAP_FD, proxy_stream, + VSTREAM_CTL_END); + (void) vstream_fclose(proxy_stream); /* direct-to-client stream! */ + + /* + * After plumbing the plaintext stream, receive the TLS context object. + * For this we must use the same VSTREAM buffer that we also use to + * receive subsequent SMTP commands. + * + * When the TLS handshake fails, the conversation is in an unknown state. + * There is nothing we can do except to disconnect from the client. + */ + state->tls_context = tls_proxy_state_receive(state->client); + if (state->tls_context == 0) + vstream_longjmp(state->client, SMTP_ERR_EOF); + + return (0); +#endif /* USE_TLSPROXY */ } /* tls_reset - undo STARTTLS */ @@ -4174,8 +4254,12 @@ static void tls_reset(SMTPD_STATE *state) if (vstream_feof(state->client) || vstream_ferror(state->client)) failure = 1; vstream_fflush(state->client); /* NOT: smtp_flush() */ +#ifndef USE_TLSPROXY tls_server_stop(smtpd_tls_ctx, state->client, var_smtpd_starttls_tmout, failure, state->tls_context); +#else + tls_proxy_state_free(state->tls_context); +#endif state->tls_context = 0; } } @@ -4294,6 +4378,9 @@ static void smtpd_proto(SMTPD_STATE *state) */ #ifdef USE_TLS if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_tls_wrappermode) { +#ifdef USE_TLSPROXY + msg_fatal("Wrapper-mode is unimplemented."); +#else /* USE_TLSPROXY */ if (smtpd_tls_ctx == 0) { msg_warn("Wrapper-mode request dropped from %s for service %s." " TLS context initialization failed. For details see" @@ -4314,6 +4401,7 @@ static void smtpd_proto(SMTPD_STATE *state) break; } smtpd_start_tls(state); +#endif /* USE_TLSPROXY */ } #endif @@ -4473,7 +4561,7 @@ static void smtpd_proto(SMTPD_STATE *state) #ifdef USE_SASL_AUTH if (var_smtpd_sasl_enable && smtpd_sasl_is_active(state) == 0 #ifdef USE_TLS - && state->tls_context == 0 && !state->tls_auth_only + && state->tls_context == 0 && !var_smtpd_tls_auth_only #else && var_smtpd_tls_auth_only == 0 #endif @@ -4558,7 +4646,7 @@ static void smtpd_proto(SMTPD_STATE *state) continue; } #ifdef USE_TLS - if (state->tls_enforce_tls && + if (var_smtpd_enforce_tls && !state->tls_context && (cmdp->flags & SMTPD_CMD_FLAG_PRE_TLS) == 0) { smtpd_chat_reply(state, @@ -4674,26 +4762,13 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv) msg_info("connect from %s", state.namaddr); /* - * With TLS wrapper mode, we run on a dedicated port and turn on TLS - * before actually speaking the SMTP protocol. This implies TLS enforce - * mode. - * - * With non-wrapper mode, TLS enforce mode implies that we don't advertise - * AUTH before the client issues STARTTLS. + * Disable TLS when running in stand-alone mode via "sendmail -bs". */ -#ifdef USE_TLS - if (!SMTPD_STAND_ALONE((&state))) { - if (var_smtpd_tls_wrappermode) { - state.tls_use_tls = 1; - state.tls_enforce_tls = 1; - } else { - state.tls_use_tls = var_smtpd_use_tls | var_smtpd_enforce_tls; - state.tls_enforce_tls = var_smtpd_enforce_tls; - } - if (var_smtpd_tls_auth_only || state.tls_enforce_tls) - state.tls_auth_only = 1; + if (SMTPD_STAND_ALONE((&state))) { + var_smtpd_use_tls = 0; + var_smtpd_enforce_tls = 0; + var_smtpd_tls_auth_only = 0; } -#endif /* * XCLIENT must not override its own access control. @@ -4742,7 +4817,6 @@ static void pre_accept(char *unused_name, char **unused_argv) static void pre_jail_init(char *unused_name, char **unused_argv) { - int use_tls; /* * Initialize blacklist/etc. patterns before entering the chroot jail, in @@ -4767,6 +4841,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) */ if (getuid() == 0 || getuid() == var_owner_uid) smtpd_check_init(); + smtpd_expand_init(); debug_peer_init(); if (var_smtpd_sasl_enable) @@ -4818,8 +4893,18 @@ static void pre_jail_init(char *unused_name, char **unused_argv) break; } } - enforce_tls = var_smtpd_tls_wrappermode || var_smtpd_enforce_tls; - use_tls = var_smtpd_use_tls || enforce_tls; + + /* + * With TLS wrapper mode, we run on a dedicated port and turn on TLS + * before actually speaking the SMTP protocol. This implies TLS enforce + * mode. + * + * With non-wrapper mode, TLS enforce mode implies that we don't advertise + * AUTH before the client issues STARTTLS. + */ + var_smtpd_enforce_tls = var_smtpd_tls_wrappermode || var_smtpd_enforce_tls; + var_smtpd_tls_auth_only = var_smtpd_tls_auth_only || var_smtpd_enforce_tls; + var_smtpd_use_tls = var_smtpd_use_tls || var_smtpd_enforce_tls; /* * Keys can only be loaded when running with suitable permissions. When @@ -4827,7 +4912,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) * announce STARTTLS support. */ if (getuid() == 0 || getuid() == var_owner_uid) { - if (use_tls) { + if (var_smtpd_use_tls) { #ifdef USE_TLS TLS_SERVER_INIT_PROPS props; const char *cert_file; @@ -4843,7 +4928,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) */ ask_client_cert = require_server_cert = (var_smtpd_tls_ask_ccert - || (enforce_tls && var_smtpd_tls_req_ccert)); + || (var_smtpd_enforce_tls && var_smtpd_tls_req_ccert)); if (strcasecmp(var_smtpd_tls_cert_file, "none") == 0) { no_server_cert_ok = 1; cert_file = ""; @@ -4857,7 +4942,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) /* Some TLS configuration errors are not show stoppers. */ if (!have_server_cert && require_server_cert) msg_warn("Need a server cert to request client certs"); - if (!enforce_tls && var_smtpd_tls_req_ccert) + if (!var_smtpd_enforce_tls && var_smtpd_tls_req_ccert) msg_warn("Can't require client certs unless TLS is required"); /* After a show-stopper error, reply with 454 to STARTTLS. */ if (have_server_cert || (no_server_cert_ok && !require_server_cert)) @@ -4888,7 +4973,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) dh512_param_file = var_smtpd_tls_dh512_param_file, eecdh_grade = var_smtpd_tls_eecdh, - protocols = enforce_tls ? + protocols = var_smtpd_enforce_tls ? var_smtpd_tls_mand_proto : var_smtpd_tls_proto, ask_ccert = ask_client_cert, @@ -5175,6 +5260,7 @@ int main(int argc, char **argv) static const CONFIG_RAW_TABLE raw_table[] = { VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0, VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply, 1, 0, + VAR_SMTPD_REJ_CONTACT, DEF_SMTPD_REJ_CONTACT, &var_smtpd_rej_contact, 0, 0, 0, }; diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index 931dcbcfd..9b98ac7d3 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -165,9 +165,6 @@ typedef struct { * TLS related state. */ #ifdef USE_TLS - int tls_use_tls; /* can use TLS */ - int tls_enforce_tls; /* must use TLS */ - int tls_auth_only; /* use SASL over TLS only */ TLS_SESS_STATE *tls_context; /* TLS session state */ #endif diff --git a/postfix/src/smtpd/smtpd_chat.c b/postfix/src/smtpd/smtpd_chat.c index fac66d3d6..72f17fd43 100644 --- a/postfix/src/smtpd/smtpd_chat.c +++ b/postfix/src/smtpd/smtpd_chat.c @@ -83,10 +83,12 @@ #include #include #include +#include /* Application-specific. */ #include "smtpd.h" +#include "smtpd_expand.h" #include "smtpd_chat.h" #define STR vstring_str @@ -145,6 +147,7 @@ void smtpd_chat_reply(SMTPD_STATE *state, const char *format,...) char *cp; char *next; char *end; + ssize_t dsn_len; /* * Slow down clients that make errors. Sleep-on-anything slows down @@ -153,9 +156,48 @@ void smtpd_chat_reply(SMTPD_STATE *state, const char *format,...) if (state->error_count >= var_smtpd_soft_erlim) sleep(delay = var_smtpd_err_sleep); + /* + * The caller may send multi-line text, so we can't assume that there is + * only one SMTP reply code at the beginning of the response. + */ va_start(ap, format); vstring_vsprintf(state->buffer, format, ap); va_end(ap); + + /* + * Append the optional contact footer. Caution: as we append parts from + * the buffer to itself, extend the buffer before updating it, or else we + * have a dangling pointer bug. + */ + if (*var_smtpd_rej_contact + && (*(cp = STR(state->buffer)) == '4' || *cp == '5') + && ISDIGIT(cp[1]) && ISDIGIT(cp[2]) && cp[3] == ' ') { + dsn_len = dsn_valid(cp + 4); + for (cp = var_smtpd_rej_contact, end = cp + strlen(cp);;) { + if ((next = strstr(cp, "\\n")) != 0) { + *next = 0; + } else { + next = end; + } + /* Append a clone of the SMTP reply code. */ + VSTRING_SPACE(state->buffer, sizeof("\r\n550 ")); + vstring_sprintf_append(state->buffer, "\r\n%.3s ", + STR(state->buffer)); + /* Append a clone of the optional enhanced status code. */ + if (dsn_len > 0) { + VSTRING_SPACE(state->buffer, dsn_len + 1); + vstring_sprintf_append(state->buffer, "%.*s ", + (int) dsn_len, STR(state->buffer) + 4); + } + /* Append the actual contact information. */ + smtpd_expand(state, state->buffer, cp, MAC_EXP_FLAG_APPEND); + if (next < end) { + *next = '\\'; + cp = next + 2; + } else + break; + } + } /* All 5xx replies must have a 5.xx.xx detail code. */ for (cp = STR(state->buffer), end = cp + strlen(STR(state->buffer));;) { if (var_soft_bounce) { @@ -168,6 +210,7 @@ void smtpd_chat_reply(SMTPD_STATE *state, const char *format,...) /* This is why we use strlen() above instead of VSTRING_LEN(). */ if ((next = strstr(cp, "\r\n")) != 0) { *next = 0; + cp[3] = '-'; /* contact footer kludge */ } else { next = end; } diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index c1b2330bf..e381a36f3 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -246,6 +246,7 @@ #include "smtpd_check.h" #include "smtpd_dsn_fix.h" #include "smtpd_resolve.h" +#include "smtpd_expand.h" #define RESTRICTION_SEPARATORS ", \t\r\n" @@ -331,11 +332,6 @@ static HTABLE *policy_clnt_table; static ARGV *local_rewrite_clients; - /* - * Pre-parsed expansion filter. - */ -static VSTRING *expand_filter; - /* * The routine that recursively applies restrictions. */ @@ -704,12 +700,6 @@ void smtpd_check_init(void) fail_required(VAR_RCPT_CHECKS, rcpt_required); #endif - /* - * Expand the expansion filter :-) - */ - expand_filter = vstring_alloc(10); - unescape(expand_filter, var_smtpd_exp_filter); - /* * Local rewrite policy. */ @@ -2828,123 +2818,6 @@ static int check_mail_access(SMTPD_STATE *state, const char *table, CHECK_MAIL_ACCESS_RETURN(SMTPD_CHECK_DUNNO); } -/* smtpd_expand_unknown - report unknown macro name */ - -static void smtpd_expand_unknown(const char *name) -{ - msg_warn("unknown macro name \"%s\" in expansion request", name); -} - -/* smtpd_expand_addr - return address or substring thereof */ - -static const char *smtpd_expand_addr(VSTRING *buf, const char *addr, - const char *name, int prefix_len) -{ - const char *p; - const char *suffix; - - /* - * Return NULL only for unknown names in expansion requests. - */ - if (addr == 0) - return (""); - - suffix = name + prefix_len; - - /* - * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP. - */ - if (*suffix == 0) { - if (*addr) - return (addr); - else - return ("<>"); - } - - /* - * "sender_name" or "recipient_name". - */ -#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) - - else if (STREQ(suffix, MAIL_ATTR_S_NAME)) { - if (*addr) { - if ((p = strrchr(addr, '@')) != 0) { - vstring_strncpy(buf, addr, p - addr); - return (STR(buf)); - } else { - return (addr); - } - } else - return ("<>"); - } - - /* - * "sender_domain" or "recipient_domain". - */ - else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) { - if (*addr) { - if ((p = strrchr(addr, '@')) != 0) { - return (p + 1); - } else { - return (""); - } - } else - return (""); - } - - /* - * Unknown. Return NULL to indicate an "unknown name" error. - */ - else { - smtpd_expand_unknown(name); - return (0); - } -} - -/* smtpd_expand_lookup - generic SMTP attribute $name expansion */ - -static const char *smtpd_expand_lookup(const char *name, int unused_mode, - char *context) -{ - SMTPD_STATE *state = (SMTPD_STATE *) context; - - if (state->expand_buf == 0) - state->expand_buf = vstring_alloc(10); - - if (msg_verbose > 1) - msg_info("smtpd_expand_lookup: ${%s}", name); - -#define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0) -#define CONST_LEN(x) (sizeof(x) - 1) - - /* - * Don't query main.cf parameters, as the result of expansion could - * reveal system-internal information in server replies. - * - * Return NULL only for non-existent names. - */ - if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { - return (state->namaddr); - } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) { - return (state->addr); - } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) { - return (state->name); - } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) { - return (state->reverse_name); - } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) { - return (state->helo_name ? state->helo_name : ""); - } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { - return (smtpd_expand_addr(state->expand_buf, state->sender, - name, CONST_LEN(MAIL_ATTR_SENDER))); - } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) { - return (smtpd_expand_addr(state->expand_buf, state->recipient, - name, CONST_LEN(MAIL_ATTR_RECIP))); - } else { - smtpd_expand_unknown(name); - return (0); - } -} - /* Support for different DNSXL lookup results. */ static SMTPD_RBL_STATE dnsxl_stat_soft[1]; @@ -3061,6 +2934,8 @@ static const char *rbl_expand_lookup(const char *name, int mode, SMTPD_RBL_EXPAND_CONTEXT *rbl_exp = (SMTPD_RBL_EXPAND_CONTEXT *) context; SMTPD_STATE *state = rbl_exp->state; +#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) + if (state->expand_buf == 0) state->expand_buf = vstring_alloc(10); @@ -3121,7 +2996,7 @@ static int rbl_reject_reply(SMTPD_STATE *state, const SMTPD_RBL_STATE *rbl, if (template == 0) template = var_def_rbl_reply; if (mac_expand(why, template, MAC_EXP_FLAG_NONE, - STR(expand_filter), rbl_expand_lookup, + STR(smtpd_expand_filter), rbl_expand_lookup, (char *) &rbl_exp) == 0) break; if (template == var_def_rbl_reply) diff --git a/postfix/src/smtpd/smtpd_expand.c b/postfix/src/smtpd/smtpd_expand.c new file mode 100644 index 000000000..6683f4e0f --- /dev/null +++ b/postfix/src/smtpd/smtpd_expand.c @@ -0,0 +1,238 @@ +/*++ +/* NAME +/* smtpd_expand 3 +/* SUMMARY +/* SMTP server macro expansion +/* SYNOPSIS +/* #include +/* #include +/* +/* void smtpd_expand_init() +/* +/* int smtpd_expand(state, result, template, flags) +/* SMTPD_STATE *state; +/* VSTRING *result; +/* const char *template; +/* int flags; +/* LOW_LEVEL INTERFACE +/* VSTRING *smtpd_expand_filter; +/* +/* const char *smtpd_expand_lookup(name, unused_mode, context) +/* const char *name; +/* int unused_mode; +/* char *context; +/* const char *template; +/* DESCRIPTION +/* This module expands session-related macros. +/* +/* smtpd_expand_init() performs one-time initialization. +/* +/* smtpd_expand() expands macros in the template, using session +/* attributes in the state argument, and writes the result to +/* the result argument. The flags and result value are as with +/* mac_expand(). +/* +/* smtpd_expand_filter and smtpd_expand_lookup() provide access +/* to lower-level interfaces that are used by smtpd_expand(). +/* smtpd_expand_lookup() returns null when a string is not +/* found (or when it is a null pointer). +/* DIAGNOSTICS +/* Panic: interface violations. Fatal errors: out of memory. +/* internal protocol errors. smtpd_expand() returns the binary +/* OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF +/* (undefined macro name). +/* 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 + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include +#include + + /* + * Pre-parsed expansion filter. + */ +VSTRING *smtpd_expand_filter; + + /* + * SLMs. + */ +#define STR vstring_str + +/* smtpd_expand_init - initialize once during process lifetime */ + +void smtpd_expand_init(void) +{ + + /* + * Expand the expansion filter :-) + */ + smtpd_expand_filter = vstring_alloc(10); + unescape(smtpd_expand_filter, var_smtpd_exp_filter); +} + +/* smtpd_expand_unknown - report unknown macro name */ + +static void smtpd_expand_unknown(const char *name) +{ + msg_warn("unknown macro name \"%s\" in expansion request", name); +} + +/* smtpd_expand_addr - return address or substring thereof */ + +static const char *smtpd_expand_addr(VSTRING *buf, const char *addr, + const char *name, int prefix_len) +{ + const char *p; + const char *suffix; + + /* + * Return NULL only for unknown names in expansion requests. + */ + if (addr == 0) + return (""); + + suffix = name + prefix_len; + + /* + * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP. + */ + if (*suffix == 0) { + if (*addr) + return (addr); + else + return ("<>"); + } + + /* + * "sender_name" or "recipient_name". + */ +#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) + + else if (STREQ(suffix, MAIL_ATTR_S_NAME)) { + if (*addr) { + if ((p = strrchr(addr, '@')) != 0) { + vstring_strncpy(buf, addr, p - addr); + return (STR(buf)); + } else { + return (addr); + } + } else + return ("<>"); + } + + /* + * "sender_domain" or "recipient_domain". + */ + else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) { + if (*addr) { + if ((p = strrchr(addr, '@')) != 0) { + return (p + 1); + } else { + return (""); + } + } else + return (""); + } + + /* + * Unknown. Return NULL to indicate an "unknown name" error. + */ + else { + smtpd_expand_unknown(name); + return (0); + } +} + +/* smtpd_expand_lookup - generic SMTP attribute $name expansion */ + +const char *smtpd_expand_lookup(const char *name, int unused_mode, + char *context) +{ + SMTPD_STATE *state = (SMTPD_STATE *) context; + time_t now; + struct tm *lt; + + if (state->expand_buf == 0) + state->expand_buf = vstring_alloc(10); + + if (msg_verbose > 1) + msg_info("smtpd_expand_lookup: ${%s}", name); + +#define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0) +#define CONST_LEN(x) (sizeof(x) - 1) + + /* + * Don't query main.cf parameters, as the result of expansion could + * reveal system-internal information in server replies. + * + * Return NULL only for non-existent names. + */ + if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { + return (state->namaddr); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) { + return (state->port); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) { + return (state->addr); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) { + return (state->name); + } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) { + return (state->reverse_name); + } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) { + return (state->helo_name ? state->helo_name : ""); + } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { + return (smtpd_expand_addr(state->expand_buf, state->sender, + name, CONST_LEN(MAIL_ATTR_SENDER))); + } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) { + return (smtpd_expand_addr(state->expand_buf, state->recipient, + name, CONST_LEN(MAIL_ATTR_RECIP))); + } if (STREQ(name, MAIL_ATTR_LOCALTIME)) { + if (time(&now) == (time_t) - 1) + msg_fatal("time lookup failed: %m"); + lt = localtime(&now); + VSTRING_RESET(state->expand_buf); + do { + VSTRING_SPACE(state->expand_buf, 100); + } while (strftime(STR(state->expand_buf), + vstring_avail(state->expand_buf), + "%b %d %H:%M:%S", lt) == 0); + return (STR(state->expand_buf)); + } else { + smtpd_expand_unknown(name); + return (0); + } +} + +/* smtpd_expand - expand session attributes in string */ + +int smtpd_expand(SMTPD_STATE *state, VSTRING *result, + const char *template, int flags) +{ + return (mac_expand(result, template, flags, STR(smtpd_expand_filter), + smtpd_expand_lookup, (char *) state)); +} diff --git a/postfix/src/smtpd/smtpd_expand.h b/postfix/src/smtpd/smtpd_expand.h new file mode 100644 index 000000000..7c0f838ac --- /dev/null +++ b/postfix/src/smtpd/smtpd_expand.h @@ -0,0 +1,35 @@ +/*++ +/* NAME +/* smtpd_expand 3h +/* SUMMARY +/* SMTP server macro expansion +/* SYNOPSIS +/* #include +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include +#include + + /* + * External interface. + */ +VSTRING *smtpd_expand_filter; +void smtpd_expand_init(void); +const char *smtpd_expand_lookup(const char *, int, char *); +int smtpd_expand(SMTPD_STATE *, VSTRING *, const char *, int); + +/* 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 +/*--*/ diff --git a/postfix/src/smtpd/smtpd_sasl_proto.c b/postfix/src/smtpd/smtpd_sasl_proto.c index 9fcdc1ed0..f419dc6bb 100644 --- a/postfix/src/smtpd/smtpd_sasl_proto.c +++ b/postfix/src/smtpd/smtpd_sasl_proto.c @@ -166,7 +166,7 @@ int smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } } #ifdef USE_TLS - if (state->tls_auth_only && !state->tls_context) { + if (var_smtpd_tls_auth_only && !state->tls_context) { state->error_mask |= MAIL_ERROR_PROTOCOL; /* RFC 4954, Section 4. */ smtpd_chat_reply(state, "504 5.5.4 Encryption required for requested authentication mechanism"); diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index 24091fa61..8dc77a0b0 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -138,9 +138,6 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream, state->dsn_buf = vstring_alloc(100); state->dsn_orcpt_buf = vstring_alloc(100); #ifdef USE_TLS - state->tls_use_tls = 0; - state->tls_enforce_tls = 0; - state->tls_auth_only = 0; state->tls_context = 0; #endif diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index 74c04bcaa..f47ae4ec6 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -3,13 +3,15 @@ SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c \ tls_prng_exch.c tls_stream.c tls_bio_ops.c tls_misc.c tls_dh.c \ tls_rsa.c tls_verify.c tls_certkey.c tls_session.c \ tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c \ - tls_level.c + tls_level.c \ + tls_proxy_clnt.c tls_proxy_print.c tls_proxy_scan.c OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o \ tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \ tls_rsa.o tls_verify.o tls_certkey.o tls_session.o \ tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o \ - tls_level.o -HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h + tls_level.o \ + tls_proxy_clnt.o tls_proxy_print.o tls_proxy_scan.o +HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h TESTSRC = DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) @@ -200,6 +202,49 @@ tls_prng_file.o: ../../include/mymalloc.h tls_prng_file.o: ../../include/sys_defs.h tls_prng_file.o: tls_prng.h tls_prng_file.o: tls_prng_file.c +tls_proxy_clnt.o: ../../include/argv.h +tls_proxy_clnt.o: ../../include/attr.h +tls_proxy_clnt.o: ../../include/connect.h +tls_proxy_clnt.o: ../../include/iostuff.h +tls_proxy_clnt.o: ../../include/mail_proto.h +tls_proxy_clnt.o: ../../include/msg.h +tls_proxy_clnt.o: ../../include/mymalloc.h +tls_proxy_clnt.o: ../../include/name_code.h +tls_proxy_clnt.o: ../../include/name_mask.h +tls_proxy_clnt.o: ../../include/stringops.h +tls_proxy_clnt.o: ../../include/sys_defs.h +tls_proxy_clnt.o: ../../include/vbuf.h +tls_proxy_clnt.o: ../../include/vstream.h +tls_proxy_clnt.o: ../../include/vstring.h +tls_proxy_clnt.o: tls.h +tls_proxy_clnt.o: tls_proxy.h +tls_proxy_clnt.o: tls_proxy_clnt.c +tls_proxy_print.o: ../../include/argv.h +tls_proxy_print.o: ../../include/attr.h +tls_proxy_print.o: ../../include/iostuff.h +tls_proxy_print.o: ../../include/mail_proto.h +tls_proxy_print.o: ../../include/name_code.h +tls_proxy_print.o: ../../include/name_mask.h +tls_proxy_print.o: ../../include/sys_defs.h +tls_proxy_print.o: ../../include/vbuf.h +tls_proxy_print.o: ../../include/vstream.h +tls_proxy_print.o: ../../include/vstring.h +tls_proxy_print.o: tls.h +tls_proxy_print.o: tls_proxy.h +tls_proxy_print.o: tls_proxy_print.c +tls_proxy_scan.o: ../../include/argv.h +tls_proxy_scan.o: ../../include/attr.h +tls_proxy_scan.o: ../../include/iostuff.h +tls_proxy_scan.o: ../../include/mail_proto.h +tls_proxy_scan.o: ../../include/name_code.h +tls_proxy_scan.o: ../../include/name_mask.h +tls_proxy_scan.o: ../../include/sys_defs.h +tls_proxy_scan.o: ../../include/vbuf.h +tls_proxy_scan.o: ../../include/vstream.h +tls_proxy_scan.o: ../../include/vstring.h +tls_proxy_scan.o: tls.h +tls_proxy_scan.o: tls_proxy.h +tls_proxy_scan.o: tls_proxy_scan.c tls_rsa.o: ../../include/argv.h tls_rsa.o: ../../include/name_code.h tls_rsa.o: ../../include/name_mask.h diff --git a/postfix/src/tls/tls_proxy.h b/postfix/src/tls/tls_proxy.h new file mode 100644 index 000000000..3cf093a51 --- /dev/null +++ b/postfix/src/tls/tls_proxy.h @@ -0,0 +1,56 @@ +#ifndef _TLS_PROXY_H_INCLUDED_ +#define _TLS_PROXY_H_INCLUDED_ + +/*++ +/* NAME +/* tls_proxy_clnt 3h +/* SUMMARY +/* postscreen TLS proxy support +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include +#include + + /* + * TLS library. + */ +#include + + /* + * External interface. + */ +#define TLSPROXY_SERVICE "tlsproxy" + +#define TLS_PROXY_FLAG_ROLE_SERVER (1<<0) /* request server role */ +#define TLS_PROXY_FLAG_ROLE_CLIENT (1<<1) /* request client role */ +#define TLS_PROXY_FLAG_SEND_CONTEXT (1<<2) /* send TLS context */ + +#ifdef USE_TLS + +extern VSTREAM *tls_proxy_open(int, VSTREAM *, const char *, + const char *, int); +extern TLS_SESS_STATE *tls_proxy_state_receive(VSTREAM *); +extern void tls_proxy_state_free(TLS_SESS_STATE *); +extern int tls_proxy_print_state(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_scan_state(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); + +#endif + +/* 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 +/*--*/ + +#endif diff --git a/postfix/src/tls/tls_proxy_clnt.c b/postfix/src/tls/tls_proxy_clnt.c new file mode 100644 index 000000000..9f723d21a --- /dev/null +++ b/postfix/src/tls/tls_proxy_clnt.c @@ -0,0 +1,226 @@ +/*++ +/* NAME +/* tlsproxy_clnt 3 +/* SUMMARY +/* postscreen TLS proxy support +/* SYNOPSIS +/* #include +/* +/* VSTREAM *tls_proxy_open(flags, peer_stream, peer_addr, +/* peer_port, timeout) +/* int flags; +/* VSTREAM *peer_stream; +/* const char *peer_addr; +/* const char *peer_port; +/* int timeout; +/* +/* TLS_SESS_STATE *tls_proxy_state_receive(proxy_stream) +/* VSTREAM *proxy_stream; +/* +/* void tls_proxy_state_free(tls_context) +/* TLS_SESS_STATE *tls_context; +/* DESCRIPTION +/* tls_proxy_open() prepares for inserting the tlsproxy(8) +/* daemon between the current process and a remote peer (the +/* actual insert operation is described in the next paragraph). +/* The result value is a null pointer on failure. The peer_stream +/* is not closed. The resulting proxy stream is single-buffered. +/* +/* After this, it is a good idea to use the VSTREAM_CTL_SWAP_FD +/* request to swap the file descriptors between the plaintext +/* peer_stream and the proxy stream from tls_proxy_open(). +/* This avoids the loss of application-configurable VSTREAM +/* attributes on the plaintext peer_stream (such as longjmp +/* buffer, timeout, etc.). Once the file descriptors are +/* swapped, the proxy stream should be closed. +/* +/* tls_proxy_state_receive() receives the TLS context object +/* for the named proxy stream. This function must be called +/* only if the TLS_PROXY_SEND_CONTEXT flag was specified in +/* the tls_proxy_open() call. Note that this TLS context object +/* is not compatible with tls_session_free(). It must be given +/* to tls_proxy_state_free() instead. +/* +/* After this, the proxy_stream is ready for plain-text I/O. +/* +/* tls_proxy_state_free() destroys a TLS context object that +/* was received with tls_proxy_state_receive(). +/* +/* Arguments: +/* .IP flags +/* Bit-wise OR of: +/* .RS +/* .IP TLS_PROXY_FLAG_ROLE_SERVER +/* Request the TLS server proxy role. +/* .IP TLS_PROXY_FLAG_ROLE_CLIENT +/* Request the TLS client proxy role. +/* .IP TLS_PROXY_FLAG_SEND_CONTEXT +/* Send the TLS context object. +/* .RE +/* .IP peer_stream +/* Stream that connects the current process to a remote peer. +/* .IP peer_addr +/* Printable IP address of the remote peer_stream endpoint. +/* .IP peer_port +/* Printable TCP port of the remote peer_stream endpoint. +/* .IP timeout +/* Time limit that the tlsproxy(8) daemon should use. +/* .IP proxy_stream +/* Stream from tls_proxy_open(). +/* .IP tls_context +/* TLS session object from tls_proxy_state_receive(). +/* 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 +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library. */ + +#include +#include +#include +#include /* concatenate() */ + +/* Global library. */ + +#include + +/* TLS library-specific. */ + +#include +#include + +#define TLSPROXY_INIT_TIMEOUT 10 + +/* tls_proxy_open - open negotiations with TLS proxy */ + +VSTREAM *tls_proxy_open(int flags, VSTREAM *peer_stream, + const char *peer_addr, + const char *peer_port, + int timeout) +{ + VSTREAM *tlsproxy_stream; + char *remote_endpt; + int status; + int fd; + + /* + * Connect to the tlsproxy(8) daemon. We report all errors + * asynchronously, to avoid having to maintain multiple delivery paths. + */ + if ((fd = LOCAL_CONNECT("private/" TLSPROXY_SERVICE, BLOCKING, + TLSPROXY_INIT_TIMEOUT)) < 0) { + msg_warn("connect to %s service: %m", TLSPROXY_SERVICE); + return (0); + } + + /* + * Initial handshake. Send the data attributes now, and send the client + * file descriptor in a later transaction. + * + * XXX The formatted endpoint should be a state member. Then, we can + * simplify all the format strings throughout the program. + */ + tlsproxy_stream = vstream_fdopen(fd, O_RDWR); + remote_endpt = concatenate("[", peer_addr, "]:", + peer_port, (char *) 0); + attr_print(tlsproxy_stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, timeout, + ATTR_TYPE_END); + myfree(remote_endpt); + if (vstream_fflush(tlsproxy_stream) != 0) { + msg_warn("error sending request to %s service: %m", TLSPROXY_SERVICE); + vstream_fclose(tlsproxy_stream); + return (0); + } + + /* + * Receive the "TLS is available" indication. + * + * This may seem out of order, but we must have a read transaction between + * sending the request attributes and sending the SMTP client file + * descriptor. We can't assume UNIX-domain socket semantics here. + */ + if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1 || status == 0) { + + /* + * The TLS proxy reports that the TLS engine is not available (due to + * configuration error, or other causes). + */ + msg_warn("%s service role \"%s\" is not available", + TLSPROXY_SERVICE, + (flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "server" : + (flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "client" : + "bogus role"); + vstream_fclose(tlsproxy_stream); + return (0); + } + + /* + * Send the remote SMTP client file descriptor. + */ + if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream), + vstream_fileno(peer_stream)) < 0) { + + /* + * Some error: drop the TLS proxy stream. + */ + msg_warn("sending file handle to %s service: %m", TLSPROXY_SERVICE); + vstream_fclose(tlsproxy_stream); + return (0); + } + return (tlsproxy_stream); +} + +/* tls_proxy_state_receive - receive TLS session object from tlsproxy(8) */ + +TLS_SESS_STATE *tls_proxy_state_receive(VSTREAM *proxy_stream) +{ + TLS_SESS_STATE *tls_context; + + tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context)); + + if (attr_scan(proxy_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_FUNC, tls_proxy_scan_state, (char *) tls_context, + ATTR_TYPE_END) != 1) { + tls_proxy_state_free(tls_context); + return (0); + } else { + return (tls_context); + } +} + +/* tls_proxy_state_free - destroy object from tls_proxy_state_receive() */ + +void tls_proxy_state_free(TLS_SESS_STATE *tls_context) +{ + if (tls_context->peer_CN) + myfree(tls_context->peer_CN); + if (tls_context->issuer_CN) + myfree(tls_context->issuer_CN); + if (tls_context->peer_fingerprint) + myfree(tls_context->peer_fingerprint); + if (tls_context->protocol) + myfree((char *) tls_context->protocol); + if (tls_context->cipher_name) + myfree((char *) tls_context->cipher_name); + myfree((char *) tls_context); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_print.c b/postfix/src/tls/tls_proxy_print.c new file mode 100644 index 000000000..da759fdeb --- /dev/null +++ b/postfix/src/tls/tls_proxy_print.c @@ -0,0 +1,84 @@ +/*++ +/* NAME +/* tls_proxy_print +/* SUMMARY +/* write DSN structure to stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_print_state(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_print_state() writes a TLS_SESS_STATE structure +/* to the named stream using the specified attribute print +/* routine. TLS_SESS_STATE() is meant to be passed as a call-back +/* to attr_print(), thusly: +/* +/* ... ATTR_TYPE_FUNC, tls_proxy_print_state, (void *) tls_context, ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* 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 +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* Global library. */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_print_state - send TLS session state over stream */ + +int tls_proxy_print_state(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SESS_STATE *tp = (TLS_SESS_STATE *) ptr; + int ret; + +#define STRING_OR_EMPTY(s) ((s) ? (s) : "") + + ret = print_fn(fp, flags | ATTR_FLAG_MORE, + ATTR_TYPE_STR, MAIL_ATTR_PEER_CN, + STRING_OR_EMPTY(tp->peer_CN), + ATTR_TYPE_STR, MAIL_ATTR_ISSUER_CN, + STRING_OR_EMPTY(tp->issuer_CN), + ATTR_TYPE_STR, MAIL_ATTR_PEER_FPT, + STRING_OR_EMPTY(tp->peer_fingerprint), + ATTR_TYPE_INT, MAIL_ATTR_PEER_STATUS, + tp->peer_status, + ATTR_TYPE_STR, MAIL_ATTR_CIPHER_PROTOCOL, + STRING_OR_EMPTY(tp->protocol), + ATTR_TYPE_STR, MAIL_ATTR_CIPHER_NAME, + STRING_OR_EMPTY(tp->cipher_name), + ATTR_TYPE_INT, MAIL_ATTR_CIPHER_USEBITS, + tp->cipher_usebits, + ATTR_TYPE_INT, MAIL_ATTR_CIPHER_ALGBITS, + tp->cipher_algbits, + ATTR_TYPE_END); + return (ret); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_scan.c b/postfix/src/tls/tls_proxy_scan.c new file mode 100644 index 000000000..c68472743 --- /dev/null +++ b/postfix/src/tls/tls_proxy_scan.c @@ -0,0 +1,91 @@ +/*++ +/* NAME +/* tls_proxy_scan +/* SUMMARY +/* read TLS session state from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_scan_state(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_scan_state() reads a TLS_SESS_STATE structure +/* from the named stream using the specified attribute scan +/* routine. tls_proxy_scan_state() is meant to be passed as +/* a call-back to attr_scan(), thusly: +/* +/* ... ATTR_TYPE_FUNC, tls_proxy_scan_state, (void *) tls_context, ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* 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 +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* Global library. */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_scan_state - receive TLS session state from stream */ + +int tls_proxy_scan_state(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SESS_STATE *tls_context = (TLS_SESS_STATE *) ptr; + int ret; + VSTRING *peer_CN = vstring_alloc(25); + VSTRING *issuer_CN = vstring_alloc(25); + VSTRING *peer_fingerprint = vstring_alloc(25); + VSTRING *protocol = vstring_alloc(25); + VSTRING *cipher_name = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(ptr, 0, sizeof(TLS_SESS_STATE)); + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + ATTR_TYPE_STR, MAIL_ATTR_PEER_CN, peer_CN, + ATTR_TYPE_STR, MAIL_ATTR_ISSUER_CN, issuer_CN, + ATTR_TYPE_STR, MAIL_ATTR_PEER_FPT, peer_fingerprint, + ATTR_TYPE_INT, MAIL_ATTR_PEER_STATUS, + &tls_context->peer_status, + ATTR_TYPE_STR, MAIL_ATTR_CIPHER_PROTOCOL, protocol, + ATTR_TYPE_STR, MAIL_ATTR_CIPHER_NAME, cipher_name, + ATTR_TYPE_INT, MAIL_ATTR_CIPHER_USEBITS, + &tls_context->cipher_usebits, + ATTR_TYPE_INT, MAIL_ATTR_CIPHER_ALGBITS, + &tls_context->cipher_algbits, + ATTR_TYPE_END); + tls_context->peer_CN = vstring_export(peer_CN); + tls_context->issuer_CN = vstring_export(issuer_CN); + tls_context->peer_fingerprint = vstring_export(peer_fingerprint); + tls_context->protocol = vstring_export(protocol); + tls_context->cipher_name = vstring_export(cipher_name); + return (ret == 8 ? 1 : -1); +} + +#endif diff --git a/postfix/src/tlsproxy/Makefile.in b/postfix/src/tlsproxy/Makefile.in index 9b21b01d9..eb75dc5b7 100644 --- a/postfix/src/tlsproxy/Makefile.in +++ b/postfix/src/tlsproxy/Makefile.in @@ -74,6 +74,7 @@ tlsproxy.o: ../../include/name_mask.h tlsproxy.o: ../../include/nbbio.h tlsproxy.o: ../../include/sys_defs.h tlsproxy.o: ../../include/tls.h +tlsproxy.o: ../../include/tls_proxy.h tlsproxy.o: ../../include/vbuf.h tlsproxy.o: ../../include/vstream.h tlsproxy.o: ../../include/vstring.h diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index a7351e6a3..8786f29bf 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -218,6 +218,7 @@ #ifdef USE_TLS #define TLS_INTERNAL /* XXX */ #include +#include /* * Application-specific. @@ -292,8 +293,6 @@ int var_tlsp_watchdog; */ static TLS_APPL_STATE *tlsp_server_ctx; static int ask_client_cert; -static int enforce_tls; -static int tlsp_tls_enforce_tls; /* * SLMs. @@ -468,6 +467,15 @@ static void tlsp_strategy(TLSP_STATE *state) tlsp_state_free(state); return; } + if ((state->req_flags & TLS_PROXY_FLAG_SEND_CONTEXT) != 0 + && (attr_print(state->plaintext_stream, ATTR_FLAG_NONE, + ATTR_TYPE_FUNC, tls_proxy_print_state, + (char *) state->tls_context, ATTR_TYPE_END) != 0 + || vstream_fflush(state->plaintext_stream) != 0)) { + msg_warn("cannot send TLS context: %m"); + tlsp_state_free(state); + return; + } state->flags &= ~TLSP_FLAG_DO_HANDSHAKE; } @@ -630,7 +638,7 @@ static void tlsp_ciphertext_event(int event, char *context) msg_warn("deadlock on plaintext stream for %s", state->remote_endpt); else - msg_warn("read/write %s for %s", + msg_warn("ciphertext read/write %s for %s", event == EVENT_TIME ? "timeout" : "error", state->remote_endpt); tlsp_state_free(state); @@ -668,10 +676,10 @@ static void tlsp_start_tls(TLSP_STATE *state) if (cipher_grade == 0) { cipher_grade = - enforce_tls ? var_tlsp_tls_mand_ciph : var_tlsp_tls_ciph; + var_tlsp_enforce_tls ? var_tlsp_tls_mand_ciph : var_tlsp_tls_ciph; cipher_exclusions = vstring_alloc(10); ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_excl_ciph); - if (enforce_tls) + if (var_tlsp_enforce_tls) ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_mand_excl); if (ask_client_cert) ADD_EXCLUDE(cipher_exclusions, "aNULL"); @@ -683,7 +691,7 @@ static void tlsp_start_tls(TLSP_STATE *state) log_level = var_tlsp_tls_loglevel, timeout = 0, /* unused */ requirecert = (var_tlsp_tls_req_ccert - && tlsp_tls_enforce_tls), + && var_tlsp_enforce_tls), serverid = state->service, namaddr = state->remote_endpt, cipher_grade = cipher_grade, @@ -779,17 +787,15 @@ static void tlsp_get_request_event(int event, char *context) VSTREAM *plaintext_stream = state->plaintext_stream; int plaintext_fd = vstream_fileno(plaintext_stream); static VSTRING *remote_endpt; - static VSTRING *role; + int req_flags; int timeout; int ready; /* * One-time initialization. */ - if (remote_endpt == 0) { + if (remote_endpt == 0) remote_endpt = vstring_alloc(10); - role = vstring_alloc(10); - } /* * At this point we still manually manage plaintext read/write/timeout @@ -807,7 +813,7 @@ static void tlsp_get_request_event(int event, char *context) if (event != EVENT_READ || attr_scan(plaintext_stream, ATTR_FLAG_STRICT, ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt, - ATTR_TYPE_STR, MAIL_ATTR_ROLE, role, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &req_flags, ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, &timeout, ATTR_TYPE_END) != 3) { msg_warn("%s: receive request attributes: %m", myname); @@ -820,7 +826,7 @@ static void tlsp_get_request_event(int event, char *context) * If the requested TLS engine is unavailable, hang up after making sure * that the plaintext peer has received our "sorry" indication. */ - ready = (strcmp(STR(role), MAIL_ATTR_ROLE_SERVER) == 0 + ready = ((req_flags & TLS_PROXY_FLAG_ROLE_SERVER) != 0 && tlsp_server_ctx != 0); if (attr_print(plaintext_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, MAIL_ATTR_STATUS, ready, @@ -841,7 +847,11 @@ static void tlsp_get_request_event(int event, char *context) */ else { state->remote_endpt = mystrdup(STR(remote_endpt)); - msg_info("CONNECT %s", state->remote_endpt); + msg_info("CONNECT %s %s", + (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" : + (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" : + "(bogus direction)", state->remote_endpt); + state->req_flags = req_flags; state->timeout = timeout + 10; /* XXX */ event_enable_read(plaintext_fd, tlsp_get_fd_event, (char *) state); event_request_timer(tlsp_get_fd_event, (char *) state, @@ -868,10 +878,13 @@ static void tlsp_service(VSTREAM *plaintext_stream, /* * This program handles multiple connections, so it must not block. We * use event-driven code for all operations that introduce latency. + * Except that attribute lists are sent/received synchronously, once the + * socket is found to be ready for transmission. */ non_blocking(plaintext_fd, NON_BLOCKING); vstream_control(plaintext_stream, VSTREAM_CTL_PATH, "plaintext", + VSTREAM_CTL_TIMEOUT, 5, VSTREAM_CTL_END); /* @@ -922,8 +935,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv) break; } } - tlsp_tls_enforce_tls = var_tlsp_enforce_tls; - if (!(var_tlsp_use_tls || var_tlsp_enforce_tls)) { + var_tlsp_use_tls = var_tlsp_use_tls || var_tlsp_enforce_tls; + if (!var_tlsp_use_tls) { msg_warn("TLS service is requested, but disabled with %s or %s", VAR_TLSP_TLS_LEVEL, VAR_TLSP_USE_TLS); return; @@ -937,7 +950,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) */ ask_client_cert = require_server_cert = (var_tlsp_tls_ask_ccert - || (enforce_tls && var_tlsp_tls_req_ccert)); + || (var_tlsp_enforce_tls && var_tlsp_tls_req_ccert)); if (strcasecmp(var_tlsp_tls_cert_file, "none") == 0) { no_server_cert_ok = 1; cert_file = ""; @@ -951,7 +964,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) /* Some TLS configuration errors are not show stoppers. */ if (!have_server_cert && require_server_cert) msg_warn("Need a server cert to request client certs"); - if (!enforce_tls && var_tlsp_tls_req_ccert) + if (!var_tlsp_enforce_tls && var_tlsp_tls_req_ccert) msg_warn("Can't require client certs unless TLS is required"); /* After a show-stopper error, log a warning. */ if (have_server_cert || (no_server_cert_ok && !require_server_cert)) @@ -980,7 +993,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) dh512_param_file = var_tlsp_tls_dh512_param_file, eecdh_grade = var_tlsp_tls_eecdh, - protocols = enforce_tls ? + protocols = var_tlsp_enforce_tls ? var_tlsp_tls_mand_proto : var_tlsp_tls_proto, ask_ccert = ask_client_cert, diff --git a/postfix/src/tlsproxy/tlsproxy.h b/postfix/src/tlsproxy/tlsproxy.h index 0c4d129c7..340e02fff 100644 --- a/postfix/src/tlsproxy/tlsproxy.h +++ b/postfix/src/tlsproxy/tlsproxy.h @@ -24,6 +24,7 @@ */ typedef struct { int flags; /* see below */ + int req_flags; /* request flags, see tls_proxy.h */ char *service; /* argv[0] */ VSTREAM *plaintext_stream; /* local peer: postscreen(8), etc. */ NBBIO *plaintext_buf; /* plaintext buffer */ diff --git a/postfix/src/util/mac_expand.c b/postfix/src/util/mac_expand.c index 3bd304616..049d7c6ee 100644 --- a/postfix/src/util/mac_expand.c +++ b/postfix/src/util/mac_expand.c @@ -47,6 +47,8 @@ /* .IP MAC_EXP_FLAG_RECURSE /* Expand macros in lookup results. This should never be done with /* data whose origin is untrusted. +/* .IP MAC_EXP_FLAG_APPEND +/* Append text to the result buffer. /* .PP /* The constant MAC_EXP_FLAG_NONE specifies a manifest null value. /* .RE @@ -231,7 +233,8 @@ int mac_expand(VSTRING *result, const char *pattern, int flags, mc.context = context; mc.status = 0; mc.level = 0; - VSTRING_RESET(result); + if ((flags & MAC_EXP_FLAG_APPEND) == 0) + VSTRING_RESET(result); status = mac_parse(pattern, mac_expand_callback, (char *) &mc); VSTRING_TERMINATE(result); diff --git a/postfix/src/util/mac_expand.h b/postfix/src/util/mac_expand.h index 5ae6b5b99..6cd375a39 100644 --- a/postfix/src/util/mac_expand.h +++ b/postfix/src/util/mac_expand.h @@ -22,6 +22,7 @@ */ #define MAC_EXP_FLAG_NONE (0) #define MAC_EXP_FLAG_RECURSE (1<<0) +#define MAC_EXP_FLAG_APPEND (1<<1) /* * Real lookup or just a test? diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index 28e4c0a87..ba3e842b1 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -267,6 +267,10 @@ /* The argument specifies the file descriptor to be used for writing. /* This feature is limited to double-buffered streams, and makes the /* stream non-seekable. +/* .IP "VSTREAM_CTL_SWAP_FD (VSTREAM *)" +/* The argument specifies a VSTREAM pointer; the request swaps the +/* file descriptor members of the two streams. This feature is limited +/* to streams that are both double-buffered or both single-buffered. /* .IP "VSTREAM_CTL_DUPFD (int)" /* The argument specifies a minimum file descriptor value. If /* the actual stream's file descriptors are below the minimum, @@ -1222,6 +1226,9 @@ void vstream_control(VSTREAM *stream, int name,...) int floor; int old_fd; ssize_t req_bufsize = 0; + VSTREAM *stream2; + +#define SWAP(type,a,b) do { type temp = (a); (a) = (b); (b) = (temp); } while (0) for (va_start(ap, name); name != VSTREAM_CTL_END; name = va_arg(ap, int)) { switch (name) { @@ -1263,8 +1270,20 @@ void vstream_control(VSTREAM *stream, int name,...) stream->write_fd = va_arg(ap, int); stream->buf.flags |= VSTREAM_FLAG_NSEEK; break; - case VSTREAM_CTL_WAITPID_FN: - stream->waitpid_fn = va_arg(ap, VSTREAM_WAITPID_FN); + case VSTREAM_CTL_SWAP_FD: + stream2 = va_arg(ap, VSTREAM *); + if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) + != (stream2->buf.flags & VSTREAM_FLAG_DOUBLE)) + msg_panic("VSTREAM_CTL_SWAP_FD can't swap descriptors between " + "single-buffered and double-buffered streams"); + if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) { + SWAP(int, stream->read_fd, stream2->read_fd); + SWAP(int, stream->write_fd, stream2->write_fd); + stream->fd = ((stream->buf.flags & VSTREAM_FLAG_WRITE) ? + stream->write_fd : stream->read_fd); + } else { + SWAP(int, stream->fd, stream2->fd); + } break; case VSTREAM_CTL_TIMEOUT: if (stream->timeout == 0) diff --git a/postfix/src/util/vstream.h b/postfix/src/util/vstream.h index 943953f67..3c6c16aea 100644 --- a/postfix/src/util/vstream.h +++ b/postfix/src/util/vstream.h @@ -132,6 +132,7 @@ extern void vstream_control(VSTREAM *, int,...); #define VSTREAM_CTL_DUPFD 11 #endif #define VSTREAM_CTL_BUFSIZE 12 +#define VSTREAM_CTL_SWAP_FD 13 extern VSTREAM *PRINTFLIKE(1, 2) vstream_printf(const char *,...); extern VSTREAM *PRINTFLIKE(2, 3) vstream_fprintf(VSTREAM *, const char *,...); diff --git a/postfix/src/xsasl/Makefile.in b/postfix/src/xsasl/Makefile.in index 56dd1d637..0a46cbc64 100644 --- a/postfix/src/xsasl/Makefile.in +++ b/postfix/src/xsasl/Makefile.in @@ -132,6 +132,7 @@ xsasl_dovecot_server.o: ../../include/connect.h xsasl_dovecot_server.o: ../../include/iostuff.h xsasl_dovecot_server.o: ../../include/mail_params.h xsasl_dovecot_server.o: ../../include/msg.h +xsasl_dovecot_server.o: ../../include/myaddrinfo.h xsasl_dovecot_server.o: ../../include/mymalloc.h xsasl_dovecot_server.o: ../../include/name_mask.h xsasl_dovecot_server.o: ../../include/split_at.h