diff --git a/postfix/HISTORY b/postfix/HISTORY index 214b50711..29ce6f50f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -16326,6 +16326,10 @@ Apologies for any names omitted. stress-dependent. Files: global/mail_params.h, proto/postconf.proto. + Compatibility: postscreen_discard_ehlo_keyword(s|maps) + support for compatibility with smtpd_discard_ehlo_keyword(s|maps). + Files: postscreen/postscreen_smtpd.c. + 20110102 Feature: STARTTLS support for the postscreen(8) daemon. @@ -16353,7 +16357,7 @@ Apologies for any names omitted. 20110104 Feature: add contact information to each SMTP server reject - message. For example, "smtpd_reject_contact_information = + message. For example, "smtpd_reject_footer = 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, @@ -16370,3 +16374,35 @@ Apologies for any names omitted. 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]. + + Bugfix (introduced with the Postfix TLS patch): discard + plaintext following the STARTTLS command or response. This + matters only for the minority of SMTP clients that actually + verify server certificates. Files: smtpd/smtpd.c, + smtp/smtp_proto.c. + +20110106: + + Non-production: cleaned up the tlsproxy support in the + Postfix SMTP server for stress testing of the tlsproxy + daemon (still #ifdef TLSPROXY). File: smtpd/smtpd.c. + +20110107 + + Cleanup: smtpd_reject_contact_information is renamed to + smtpd_reject_footer, because it can be used for non-contact + information. + + Compatibility: postscreen_reject_footer support for + compatibility with smtpd_reject_footer. Files: + global/smtp_reply_footer.[hc], global/mail_conf.[hc], + postscreen/postscreen_expand.c, postscreen/postscreen_send.c, + postscreen/postscreen.c, smtpd/smtpd_chat.c. + + Compatibility: postscreen_command_filter support for + compatibility with smtpd_command_filter. Files: + postscreen/postscreen_dict.c, postscreen/postscreen_smtpd.c + + Cleanup: postscreen(8) now displays control characters in + PREGREET responses as C-style \letter escapes, instead of + "?". File: postscreen/postscreen_early.c. diff --git a/postfix/README_FILES/POSTSCREEN_README b/postfix/README_FILES/POSTSCREEN_README index 52ae2a09b..aa7943119 100644 --- a/postfix/README_FILES/POSTSCREEN_README +++ b/postfix/README_FILES/POSTSCREEN_README @@ -197,7 +197,8 @@ elapsed, postscreen(8) logs this as: Translation: the client at [address]:port sent count bytes before its turn to speak. This happened time seconds after the postscreen_greet_wait timer was started. The text is what the client sent (truncated to 100 bytes, and with -non-printable characters replaced with "?"). +non-printable characters replaced with C-style escapes such as \r for carriage- +return and \n for newline). The postscreen_greet_action parameter specifies the action that is taken next. See "When tests fail before the 220 SMTP server greeting" below. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 59f0445f8..bb8ba6de5 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -43,7 +43,7 @@ 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. + smtpd_reject_footer = For assistance, call 800-555-0101. Server response: 550-5.5.1 Recipient address rejected: User unknown @@ -52,6 +52,10 @@ Server response: This feature supports macro expansion ($client_address, $localtime, etc.), as documented in the postconf(5) manpage. +This feature is also supported as postscreen_reject_footer +using the same setting as smtpd_reject_footer by +default. + Incompatibility with snapshot 20110102 ====================================== diff --git a/postfix/WISHLIST b/postfix/WISHLIST index e243dcd86..510ae4ba8 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -4,6 +4,21 @@ Wish list: Re-run "make depend" with all plugins enabled. + Make very clear in postscreen manpage and readme that this + program is not to be used against your own mail clients. + + Test postscreen on Solaris. + + match_list support that does not recompile CIDR patterns + on every call. + + tlsproxy(8) should receive TLS preferences from postscreen(8) + and smtpd(8), instead of reading them from main.cf. This + means that many tlsproxy_ parameters become postscreen_ + parameters. This also means that tls_server_init() must not + "validate" preferences that are supplied later at + tls_server_start() time, which was dubious design anyway. + anvil rate limit for sasl_username. Encapsulate nbbio buffer access and update by tlsproxy. @@ -29,9 +44,6 @@ Wish list: This would apply to postmaster notices and bounce messages (DKIM), and address verification (BATV). - Replace sscanf() numerical conversions by strto[dl]() - for better error reporting. - As postscreen implements more ESMTP keywords, need to copy inter-operability features from smtpd to filter keywords and command syntax. @@ -65,7 +77,7 @@ Wish list: the same cleanup_service value for receiving remote mail and for submitting postmaster problem reports. Do we need separate mumble_cleanup_service_name parameters for "inject", - "notify" and "forward" (with backwards compatinble defaults)? + "notify" and "forward" (with backwards compatible defaults)? IF/ENDIF support for CIDR tables. diff --git a/postfix/html/POSTSCREEN_README.html b/postfix/html/POSTSCREEN_README.html index f9c4e5ae3..34ec3b5ba 100644 --- a/postfix/html/POSTSCREEN_README.html +++ b/postfix/html/POSTSCREEN_README.html @@ -269,7 +269,8 @@ an empty teaser banner:

bytes before its turn to speak. This happened time seconds after the postscreen_greet_wait timer was started. The text is what the client sent (truncated to 100 bytes, and with non-printable -characters replaced with "?").

+characters replaced with C-style escapes such as \r for carriage-return +and \n for newline).

The postscreen_greet_action parameter specifies the action that is taken next. See "When tests fail diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 3e7b683e6..817fbe3da 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -6811,6 +6811,17 @@ and error commands.

This feature is available in Postfix 2.8.

+ + +
postscreen_command_filter +(default: $smtpd_command_filter)
+ +

A mechanism to transform commands from remote SMTP clients. +See smtpd_command_filter for further details.

+ +

This feature is available in Postfix 2.8 and later.

+ +
postscreen_command_time_limit @@ -7032,6 +7043,18 @@ for details.

Preferably, use postscreen_tls_security_level instead.

+ + +
postscreen_expansion_filter +(default: see "postconf -d" output)
+ +

List of characters that are permitted in postscreen_reject_footer +attribute expansions. See smtpd_expansion_filter for further +details.

+ +

This feature is available in Postfix 2.8 and later.

+ +
postscreen_forbidden_commands @@ -7302,6 +7325,17 @@ receive a 421 reponse.

This feature is available in Postfix 2.8.

+ + +
postscreen_reject_footer +(default: $smtpd_reject_footer)
+ +

Optional information that is appended after a 4XX or 5XX server +response. See smtpd_reject_footer for further details.

+ +

This feature is available in Postfix 2.8 and later.

+ +
postscreen_tls_security_level @@ -13002,64 +13036,79 @@ Example: -
smtpd_reject_contact_information +
smtpd_reject_footer (default: empty)
-

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

+

Optional 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.
+    smtpd_reject_footer = For assistance, call 800-555-0101.
      Please provide the following information in your problem report:
-     time ($localtime) and client address ($client_address).
+     time ($localtime), client ($client_address) and server
+     ($server_name).
 

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).
+    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),
+    client (192.168.1.248) and server (mail1.example.com).
 
-

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.

+

Note: the above 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 SMTP 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. -

+be truncated before it is logged in the Postfix SMTP server's 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 +the footer text. These are replaced by their current value for the SMTP session:

-
client_address
Client IP address
+
client_address
The Client IP address that +is logged in the maillog file.
-
client_port
Client TCP port
+
client_port
The client TCP port that is +logged in the maillog file.
-
localtime
Server local time (Mmm dd hh:mm:ss)
+
localtime
The server local time (Mmm dd +hh:mm:ss) that is logged in the maillog file.
-
recipient
The address in the RCPT TO command
- -
sender
The address in the MAIL FROM command
+
server_name
The server's myhostname value. +This attribute is made available for sites with multiple MTAs +(perhaps behind a load-balancer), where the server name can help +the server support team to quickly find the right log files.
-

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

+

Notes:

-

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.

+
    + +
  • NOT SUPPORTED are other attributes such as sender, recipient, +or main.cf parameters.

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

    + +
+ +

This feature supports the two-character sequence \n as a request +for a line break in the footer 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/html/postscreen.8.html b/postfix/html/postscreen.8.html index 4f7250d7e..41499a6cc 100644 --- a/postfix/html/postscreen.8.html +++ b/postfix/html/postscreen.8.html @@ -106,55 +106,59 @@ POSTSCREEN(8) POSTSCREEN(8) ter value is the empty string. COMPATIBILITY CONTROLS + postscreen_command_filter ($smtpd_command_filter) + A mechanism to transform commands from remote SMTP + clients. + postscreen_discard_ehlo_keyword_address_maps ($smtpd_dis- card_ehlo_keyword_address_maps) - Lookup tables, indexed by the remote SMTP client - address, with case insensitive lists of EHLO key- - words (pipelining, starttls, auth, etc.) that the - postscreen(8) server will not send in the EHLO + Lookup tables, indexed by the remote SMTP client + address, with case insensitive lists of EHLO key- + words (pipelining, starttls, auth, etc.) that the + postscreen(8) server will not send in the EHLO response to a remote SMTP client. postscreen_discard_ehlo_keywords ($smtpd_discard_ehlo_key- words) - A case insensitive list of EHLO keywords (pipelin- - ing, starttls, auth, etc.) that the postscreen(8) - server will not send in the EHLO response to a + A case insensitive list of EHLO keywords (pipelin- + ing, starttls, auth, etc.) that the postscreen(8) + server will not send in the EHLO response to a remote SMTP client. TRIAGE PARAMETERS postscreen_bare_newline_action (ignore) - The action that postscreen(8) takes when an SMTP - client sends a bare newline character, that is, a + The action that postscreen(8) takes when an SMTP + client sends a bare newline character, that is, a newline not preceded by carriage return. postscreen_bare_newline_enable (no) - Enable "bare newline" SMTP protocol tests in the + Enable "bare newline" SMTP protocol tests in the postscreen(8) server. postscreen_blacklist_action (ignore) - The action that postscreen(8) takes when an SMTP - client is permanently blacklisted with the + The action that postscreen(8) takes when an SMTP + client is permanently blacklisted with the postscreen_blacklist_networks parameter. postscreen_blacklist_networks (empty) Network addresses that are permanently blacklisted; - see the postscreen_blacklist_action parameter for + see the postscreen_blacklist_action parameter for possible actions. postscreen_disable_vrfy_command ($disable_vrfy_command) - Disable the SMTP VRFY command in the postscreen(8) + Disable the SMTP VRFY command in the postscreen(8) daemon. postscreen_dnsbl_action (ignore) - The action that postscreen(8) takes when an SMTP + The action that postscreen(8) takes when an SMTP client's combined DNSBL score is equal to or - greater than a threshold (as defined with the + greater than a threshold (as defined with the postscreen_dnsbl_sites and postscreen_dnsbl_thresh- old parameters). postscreen_dnsbl_reply_map (empty) - A mapping from actual DNSBL domain name which - includes a secret password, to the DNSBL domain + A mapping from actual DNSBL domain name which + includes a secret password, to the DNSBL domain name that postscreen will reply with when it rejects mail. @@ -163,16 +167,16 @@ POSTSCREEN(8) POSTSCREEN(8) weight factors. postscreen_dnsbl_threshold (1) - The inclusive lower bound for blocking an SMTP + The inclusive lower bound for blocking an SMTP client, based on its combined DNSBL score as - defined with the postscreen_dnsbl_sites parameter. + defined with the postscreen_dnsbl_sites parameter. postscreen_forbidden_commands ($smtpd_forbidden_commands) List of commands that the postscreen(8) server con- siders in violation of the SMTP protocol. postscreen_greet_action (ignore) - The action that postscreen(8) takes when an SMTP + The action that postscreen(8) takes when an SMTP client speaks before its turn within the time spec- ified with the postscreen_greet_wait parameter. @@ -180,157 +184,162 @@ POSTSCREEN(8) POSTSCREEN(8) The text in the optional "220-text..." server response that postscreen(8) sends ahead of the real Postfix SMTP server's "220 text..." response, in an - attempt to confuse bad SMTP clients so that they + attempt to confuse bad SMTP clients so that they speak before their turn (pre-greet). postscreen_greet_wait (${stress?2}${stress:6}s) The amount of time that postscreen(8) will wait for - an SMTP client to send a command before its turn, - and for DNS blocklist lookup results to arrive - (default: up to 2 seconds under stress, up to 6 + an SMTP client to send a command before its turn, + and for DNS blocklist lookup results to arrive + (default: up to 2 seconds under stress, up to 6 seconds otherwise). postscreen_helo_required ($smtpd_helo_required) - Require that a remote SMTP client sends HELO or + Require that a remote SMTP client sends HELO or EHLO before commencing a MAIL transaction. postscreen_non_smtp_command_action (drop) - The action that postscreen(8) takes when an SMTP - client sends non-SMTP commands as specified with + The action that postscreen(8) takes when an SMTP + client sends non-SMTP commands as specified with the postscreen_forbidden_commands parameter. postscreen_non_smtp_command_enable (no) - Enable "non-SMTP command" tests in the + Enable "non-SMTP command" tests in the postscreen(8) server. postscreen_pipelining_action (enforce) - The action that postscreen(8) takes when an SMTP - client sends multiple commands instead of sending - one command and waiting for the server to respond. + The action that postscreen(8) takes when an SMTP + client sends multiple commands instead of sending + one command and waiting for the server to respond. postscreen_pipelining_enable (no) - Enable "pipelining" SMTP protocol tests in the + Enable "pipelining" SMTP protocol tests in the postscreen(8) server. postscreen_whitelist_networks ($mynetworks) Network addresses that are permanently whitelisted, - and that will not be subjected to postscreen(8) + and that will not be subjected to postscreen(8) checks. smtpd_service_name (smtpd) - The internal service that postscreen(8) forwards + The internal service that postscreen(8) forwards allowed connections to. CACHE CONTROLS postscreen_cache_cleanup_interval (12h) - The amount of time between postscreen(8) cache + The amount of time between postscreen(8) cache cleanup runs. postscreen_cache_map (btree:$data_directory/ps_cache) - Persistent storage for the postscreen(8) server + Persistent storage for the postscreen(8) server decisions. postscreen_cache_retention_time (7d) The amount of time that postscreen(8) will cache an - expired temporary whitelist entry before it is + expired temporary whitelist entry before it is removed. postscreen_bare_newline_ttl (30d) - The amount of time that postscreen(8) will cache - results from a successful "bare newline" SMTP pro- + The amount of time that postscreen(8) will cache + results from a successful "bare newline" SMTP pro- tocol test. postscreen_dnsbl_ttl (1h) - The amount of time that postscreen(8) will cache + The amount of time that postscreen(8) will cache results from a successful DNS blocklist test. postscreen_greet_ttl (1d) - The amount of time that postscreen(8) will cache + The amount of time that postscreen(8) will cache results from a successful PREGREET test. postscreen_non_smtp_command_ttl (30d) - The amount of time that postscreen(8) will cache - results from a successful "non_smtp_command" SMTP + The amount of time that postscreen(8) will cache + results from a successful "non_smtp_command" SMTP protocol test. postscreen_pipelining_ttl (30d) - The amount of time that postscreen(8) will cache - results from a successful "pipelining" SMTP proto- + The amount of time that postscreen(8) will cache + results from a successful "pipelining" SMTP proto- col test. RESOURCE CONTROLS 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. postscreen_client_connection_count_limit ($smtpd_client_connection_count_limit) - How many simultaneous connections any client is + How many simultaneous connections any client is allowed to have with the postscreen(8) daemon. postscreen_command_count_limit (20) - The limit on the total number of commands per SMTP - session for postscreen(8)'s built-in SMTP protocol + The limit on the total number of commands per SMTP + session for postscreen(8)'s built-in SMTP protocol engine. postscreen_command_time_limit (${stress?10}${stress:300}s) - The command "read" time limit for postscreen(8)'s + The command "read" time limit for postscreen(8)'s built-in SMTP protocol engine. postscreen_post_queue_limit ($default_process_limit) - The number of clients that can be waiting for ser- + The number of clients that can be waiting for ser- vice from a real SMTP server process. postscreen_pre_queue_limit ($default_process_limit) - The number of non-whitelisted clients that can be - waiting for a decision whether they will receive + The number of non-whitelisted clients that can be + waiting for a decision whether they will receive service from a real SMTP server process. postscreen_watchdog_timeout (10s) - How much time a postscreen(8) process may take to - respond to an SMTP client command or to perform a + How much time a postscreen(8) process may take to + respond to an SMTP client command or to perform a cache operation before it is terminated by a built- in watchdog timer. STARTTLS CONTROLS postscreen_tls_security_level ($smtpd_tls_security_level) - The SMTP TLS security level for the postscreen(8) - server; when a non-empty value is specified, this + The SMTP TLS security level for the postscreen(8) + server; when a non-empty value is specified, this overrides the obsolete parameters postscreen_use_tls and postscreen_enforce_tls. OBSOLETE STARTTLS SUPPORT CONTROLS - These parameters are supported for compatibility with + These parameters are supported for compatibility with smtpd(8) legacy parameters. postscreen_use_tls ($smtpd_use_tls) - Opportunistic TLS: announce STARTTLS support to - SMTP clients, but do not require that clients use + Opportunistic TLS: announce STARTTLS support to + SMTP clients, but do not require that clients use TLS encryption. postscreen_enforce_tls ($smtpd_enforce_tls) - Mandatory TLS: announce STARTTLS support to SMTP - clients, and require that clients use TLS encryp- + Mandatory TLS: announce STARTTLS support to SMTP + clients, and require that clients use TLS encryp- tion. +TROUBLE SHOOTING CONTROLS + postscreen_expansion_filter (see 'postconf -d' output) + List of characters that are permitted in + postscreen_reject_footer attribute expansions. + + postscreen_reject_footer ($smtpd_reject_footer) + Optional information that is appended after a 4XX + or 5XX server response. + 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. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal + The maximal number of digits after the decimal point when logging sub-second delay values. command_directory (see 'postconf -d' output) - The location of all postfix administrative com- + The location of all postfix administrative com- mands. - ipc_timeout (3600s) - The time limit for sending or receiving information - over an internal communication channel. - max_idle (100s) The maximum amount of time that an idle Postfix daemon process waits for an incoming connection diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 841eb9cbe..a7aa8245f 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -647,9 +647,9 @@ 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. + smtpd_reject_footer (empty) + Optional information that is appended after each + SMTP server 4XX or 5XX response. soft_bounce (no) Safety net to keep mail queued that would otherwise diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 0258f573c..9fcc06c53 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -3835,6 +3835,11 @@ no need to enforce separate limits on the number of junk commands and error commands. .PP This feature is available in Postfix 2.8. +.SH postscreen_command_filter (default: $smtpd_command_filter) +A mechanism to transform commands from remote SMTP clients. +See smtpd_command_filter for further details. +.PP +This feature is available in Postfix 2.8 and later. .SH postscreen_command_time_limit (default: ${stress?10}${stress:300}s) The command "read" time limit for \fBpostscreen\fR(8)'s built-in SMTP protocol engine. This bounds the time to receive an entire command. @@ -3994,6 +3999,12 @@ for details. .PP This feature is available in Postfix 2.8 and later. Preferably, use postscreen_tls_security_level instead. +.SH postscreen_expansion_filter (default: see "postconf -d" output) +List of characters that are permitted in postscreen_reject_footer +attribute expansions. See smtpd_expansion_filter for further +details. +.PP +This feature is available in Postfix 2.8 and later. .SH postscreen_forbidden_commands (default: $smtpd_forbidden_commands) List of commands that the \fBpostscreen\fR(8) server considers in violation of the SMTP protocol. See smtpd_forbidden_commands for @@ -4149,6 +4160,11 @@ process. When this queue is full, all non-whitelisted clients will receive a 421 reponse. .PP This feature is available in Postfix 2.8. +.SH postscreen_reject_footer (default: $smtpd_reject_footer) +Optional information that is appended after a 4XX or 5XX server +response. See smtpd_reject_footer for further details. +.PP +This feature is available in Postfix 2.8 and later. .SH postscreen_tls_security_level (default: $smtpd_tls_security_level) The SMTP TLS security level for the \fBpostscreen\fR(8) server; when a non-empty value is specified, this overrides the obsolete parameters @@ -8094,9 +8110,9 @@ 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. +.SH smtpd_reject_footer (default: empty) +Optional information that is appended after each SMTP server +4XX or 5XX response. .PP Example: .PP @@ -8104,9 +8120,10 @@ Example: .na .ft C /etc/postfix/main.cf: - smtpd_reject_contact_information = For assistance, call 800-555-0101. + smtpd_reject_footer = For assistance, call 800-555-0101. Please provide the following information in your problem report: - time ($localtime) and client address ($client_address). + time ($localtime), client ($client_address) and server + ($server_name). .fi .ad .ft R @@ -8116,43 +8133,53 @@ Server response: .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). + 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), + client (192.168.1.248) and server (mail1.example.com). .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. +Note: the above 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 SMTP 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. +be truncated before it is logged in the Postfix SMTP server's 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 +the footer 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 +.IP "\fBclient_address\fR" +The Client IP address that +is logged in the maillog file. +.IP "\fBclient_port\fR" +The client TCP port that is +logged in the maillog file. +.IP "\fBlocaltime\fR" +The server local time (Mmm dd +hh:mm:ss) that is logged in the maillog file. +.IP "\fBserver_name\fR" +The server's myhostname value. +This attribute is made available for sites with multiple MTAs +(perhaps behind a load-balancer), where the server name can help +the server support team to quickly find the right log files. .PP -For safety reasons, text that does not match $smtpd_expansion_filter -is censored. +Notes: +.IP \(bu +NOT SUPPORTED are other attributes such as sender, recipient, +or main.cf parameters. +.IP \(bu +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. +This feature supports the two-character sequence \en as a request +for a line break in the footer 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) diff --git a/postfix/man/man8/postscreen.8 b/postfix/man/man8/postscreen.8 index 67b09c982..e6822c0bc 100644 --- a/postfix/man/man8/postscreen.8 +++ b/postfix/man/man8/postscreen.8 @@ -119,6 +119,8 @@ parameter value is the empty string. .nf .ad .fi +.IP "\fBpostscreen_command_filter ($smtpd_command_filter)\fR" +A mechanism to transform commands from remote SMTP clients. .IP "\fBpostscreen_discard_ehlo_keyword_address_maps ($smtpd_discard_ehlo_keyword_address_maps)\fR" Lookup tables, indexed by the remote SMTP client address, with case insensitive lists of EHLO keywords (pipelining, starttls, auth, @@ -282,6 +284,17 @@ but do not require that clients use TLS encryption. .IP "\fBpostscreen_enforce_tls ($smtpd_enforce_tls)\fR" Mandatory TLS: announce STARTTLS support to SMTP clients, and require that clients use TLS encryption. +.SH "TROUBLE SHOOTING CONTROLS" +.na +.nf +.ad +.fi +.IP "\fBpostscreen_expansion_filter (see 'postconf -d' output)\fR" +List of characters that are permitted in postscreen_reject_footer +attribute expansions. +.IP "\fBpostscreen_reject_footer ($smtpd_reject_footer)\fR" +Optional information that is appended after a 4XX or 5XX server +response. .SH "MISCELLANEOUS CONTROLS" .na .nf @@ -295,9 +308,6 @@ The maximal number of digits after the decimal point when logging sub-second delay values. .IP "\fBcommand_directory (see 'postconf -d' output)\fR" The location of all postfix administrative commands. -.IP "\fBipc_timeout (3600s)\fR" -The time limit for sending or receiving information over an internal -communication channel. .IP "\fBmax_idle (100s)\fR" The maximum amount of time that an idle Postfix daemon process waits for an incoming connection before terminating voluntarily. diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index a4f7fd5ea..005495efd 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -527,9 +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 "\fBsmtpd_reject_footer (empty)\fR" +Optional 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 e77614fe5..96269579a 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -666,7 +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;\bsmtpd_reject_footer\b;$&;g; s;\btls_daemon_random_bytes\b;$&;g; s;\btls_daemon_random_source\b;$&;g; s;\btls_ran[-]*\n* *[]*dom_bytes\b;$&;g; @@ -954,6 +954,9 @@ while (<>) { s;\bpostscreen_use_tls\b;$&;g; s;\bpostscreen_discard_ehlo_keyword_address_maps\b;$&;g; s;\bpostscreen_discard_ehlo_keywords\b;$&;g; + s;\bpostscreen_expansion_filter\b;$&;g; + s;\bpostscreen_reject_footer\b;$&;g; + s;\bpostscreen_command_filter\b;$&;g; s;\btlsproxy_watchdog_timeout\b;$&;g; s;\btlsproxy_enforce_tls\b;$&;g; diff --git a/postfix/proto/POSTSCREEN_README.html b/postfix/proto/POSTSCREEN_README.html index e744ef554..5adef7580 100644 --- a/postfix/proto/POSTSCREEN_README.html +++ b/postfix/proto/POSTSCREEN_README.html @@ -269,7 +269,8 @@ postscreen_greet_wait time has elapsed, postscreen(8) logs this as: bytes before its turn to speak. This happened time seconds after the postscreen_greet_wait timer was started. The text is what the client sent (truncated to 100 bytes, and with non-printable -characters replaced with "?").

+characters replaced with C-style escapes such as \r for carriage-return +and \n for newline).

The postscreen_greet_action parameter specifies the action that is taken next. See "When tests fail diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index c39a711cc..2885e9807 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -13822,62 +13822,99 @@ for further details.

This feature is available in Postfix 2.8 and later.

-%PARAM smtpd_reject_contact_information +%PARAM smtpd_reject_footer -

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

+

Optional 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.
+    smtpd_reject_footer = For assistance, call 800-555-0101.
      Please provide the following information in your problem report:
-     time ($localtime) and client address ($client_address).
+     time ($localtime), client ($client_address) and server
+     ($server_name).
 

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).
+    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),
+    client (192.168.1.248) and server (mail1.example.com).
 
-

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.

+

Note: the above 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 SMTP 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. -

+be truncated before it is logged in the Postfix SMTP server's 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 +the footer text. These are replaced by their current value for the SMTP session:

-
client_address
Client IP address
+
client_address
The Client IP address that +is logged in the maillog file.
-
client_port
Client TCP port
+
client_port
The client TCP port that is +logged in the maillog file.
-
localtime
Server local time (Mmm dd hh:mm:ss)
+
localtime
The server local time (Mmm dd +hh:mm:ss) that is logged in the maillog file.
-
recipient
The address in the RCPT TO command
- -
sender
The address in the MAIL FROM command
+
server_name
The server's myhostname value. +This attribute is made available for sites with multiple MTAs +(perhaps behind a load-balancer), where the server name can help +the server support team to quickly find the right log files.
-

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

+

Notes:

-

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.

+
    + +
  • NOT SUPPORTED are other attributes such as sender, recipient, +or main.cf parameters.

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

    + +
+ +

This feature supports the two-character sequence \n as a request +for a line break in the footer 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.

+ +%PARAM postscreen_expansion_filter see "postconf -d" output + +

List of characters that are permitted in postscreen_reject_footer +attribute expansions. See smtpd_expansion_filter for further +details.

+ +

This feature is available in Postfix 2.8 and later.

+ +%PARAM postscreen_reject_footer $smtpd_reject_footer + +

Optional information that is appended after a 4XX or 5XX server +response. See smtpd_reject_footer for further details.

+ +

This feature is available in Postfix 2.8 and later.

+ +%PARAM postscreen_command_filter $smtpd_command_filter + +

A mechanism to transform commands from remote SMTP clients. +See smtpd_command_filter for further details.

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 47ab4d16a..4ee8d8677 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -29,7 +29,8 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \ user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \ verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \ fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \ - match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c + match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \ + smtp_reply_footer.c OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ @@ -60,7 +61,8 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \ verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \ fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \ - match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o + match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \ + smtp_reply_footer.o HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ @@ -85,7 +87,7 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \ verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \ fold_addr.h header_body_checks.h data_redirect.h match_service.h \ - addr_match_list.h + addr_match_list.h smtp_reply_footer.h TESTSRC = rec2stream.c stream2rec.c recdump.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) @@ -795,25 +797,8 @@ delivered_hdr.o: quote_822_local.h delivered_hdr.o: quote_flags.h delivered_hdr.o: rec_type.h delivered_hdr.o: record.h -dict_ldap.o: ../../include/argv.h -dict_ldap.o: ../../include/binhash.h -dict_ldap.o: ../../include/dict.h -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 -dict_ldap.o: ../../include/vstream.h -dict_ldap.o: ../../include/vstring.h -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 dict_pgsql.o: ../../include/sys_defs.h @@ -1444,15 +1429,7 @@ mime_state.o: mail_params.h mime_state.o: mime_state.c mime_state.o: mime_state.h mime_state.o: rec_type.h -mkmap_cdb.o: ../../include/argv.h -mkmap_cdb.o: ../../include/dict.h -mkmap_cdb.o: ../../include/dict_cdb.h -mkmap_cdb.o: ../../include/mymalloc.h mkmap_cdb.o: ../../include/sys_defs.h -mkmap_cdb.o: ../../include/vbuf.h -mkmap_cdb.o: ../../include/vstream.h -mkmap_cdb.o: ../../include/vstring.h -mkmap_cdb.o: mkmap.h mkmap_cdb.o: mkmap_cdb.c mkmap_db.o: ../../include/argv.h mkmap_db.o: ../../include/dict.h @@ -1829,6 +1806,15 @@ sent.o: sent.c sent.o: sent.h sent.o: trace.h sent.o: verify.h +smtp_reply_footer.o: ../../include/mac_expand.h +smtp_reply_footer.o: ../../include/mac_parse.h +smtp_reply_footer.o: ../../include/msg.h +smtp_reply_footer.o: ../../include/sys_defs.h +smtp_reply_footer.o: ../../include/vbuf.h +smtp_reply_footer.o: ../../include/vstring.h +smtp_reply_footer.o: dsn_util.h +smtp_reply_footer.o: smtp_reply_footer.c +smtp_reply_footer.o: smtp_reply_footer.h smtp_stream.o: ../../include/iostuff.h smtp_stream.o: ../../include/msg.h smtp_stream.o: ../../include/sys_defs.h diff --git a/postfix/src/global/mail_conf.c b/postfix/src/global/mail_conf.c index c5d3d4321..1fc7847fc 100644 --- a/postfix/src/global/mail_conf.c +++ b/postfix/src/global/mail_conf.c @@ -22,6 +22,9 @@ /* const char *mail_conf_eval(string) /* const char *string; /* +/* const char *mail_conf_eval_once(string) +/* const char *string; +/* /* const char *mail_conf_lookup_eval(name) /* const char *name; /* DESCRIPTION @@ -51,6 +54,11 @@ /* string argument. The result is volatile and should be copied /* if it is to be used for any appreciable amount of time. /* +/* mail_conf_eval_once() non-recursively expands any $parameters +/* in the string argument. The result is volatile and should +/* be copied if it is to be used for any appreciable amount +/* of time. +/* /* mail_conf_lookup_eval() looks up the named parameter, and expands any /* $parameters in the result. The result is volatile and should be /* copied if it is to be used for any appreciable amount of time. @@ -201,6 +209,15 @@ const char *mail_conf_eval(const char *string) return (dict_eval(CONFIG_DICT, string, RECURSIVE)); } +/* mail_conf_eval_once - expand one level of macros in string */ + +const char *mail_conf_eval_once(const char *string) +{ +#define NONRECURSIVE 0 + + return (dict_eval(CONFIG_DICT, string, NONRECURSIVE)); +} + /* mail_conf_lookup - lookup named variable */ const char *mail_conf_lookup(const char *name) diff --git a/postfix/src/global/mail_conf.h b/postfix/src/global/mail_conf.h index 5c0509214..ea6e8bd25 100644 --- a/postfix/src/global/mail_conf.h +++ b/postfix/src/global/mail_conf.h @@ -40,6 +40,7 @@ extern void mail_conf_flush(void); extern void mail_conf_update(const char *, const char *); extern const char *mail_conf_lookup(const char *); extern const char *mail_conf_eval(const char *); +extern const char *mail_conf_eval_once(const char *); extern const char *mail_conf_lookup_eval(const char *); /* diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index c5644526b..fa01c5293 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -3423,6 +3423,18 @@ extern bool var_psc_disable_vrfy; #define DEF_PSC_CCONN_LIMIT "$" VAR_SMTPD_CCONN_LIMIT extern int var_psc_cconn_limit; +#define VAR_PSC_REJ_FOOTER "postscreen_reject_footer" +#define DEF_PSC_REJ_FOOTER "$" VAR_SMTPD_REJ_FOOTER +extern char *var_psc_rej_footer; + +#define VAR_PSC_EXP_FILTER "postscreen_expansion_filter" +#define DEF_PSC_EXP_FILTER "$" VAR_SMTPD_EXP_FILTER +extern char *var_psc_exp_filter; + +#define VAR_PSC_CMD_FILTER "postscreen_command_filter" +#define DEF_PSC_CMD_FILTER "" +extern char *var_psc_cmd_filter; + #define VAR_DNSBLOG_DELAY "dnsblog_reply_delay" #define DEF_DNSBLOG_DELAY "0s" extern int var_dnsblog_delay; @@ -3557,9 +3569,9 @@ 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; +#define VAR_SMTPD_REJ_FOOTER "smtpd_reject_footer" +#define DEF_SMTPD_REJ_FOOTER "" +extern char *var_smtpd_rej_footer; /* LICENSE /* .ad diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 84e825473..d33f0ccb4 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -254,6 +254,11 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_CIPHER_USEBITS "cipher_usebits" #define MAIL_ATTR_CIPHER_ALGBITS "cipher_algbits" + /* + * SMTP reply footer support. + */ +#define MAIL_ATTR_SERVER_NAME "server_name" + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index ffb3e0e7e..e92f57391 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 "20110105" +#define MAIL_RELEASE_DATE "20110108" #define MAIL_VERSION_NUMBER "2.8" #ifdef SNAPSHOT diff --git a/postfix/src/global/smtp_reply_footer.c b/postfix/src/global/smtp_reply_footer.c new file mode 100644 index 000000000..5018a4706 --- /dev/null +++ b/postfix/src/global/smtp_reply_footer.c @@ -0,0 +1,166 @@ +/*++ +/* NAME +/* smtp_reply_footer 3 +/* SUMMARY +/* SMTP reply footer text support +/* SYNOPSIS +/* #include +/* +/* int smtp_reply_footer(buffer, start, template, filter, +/* lookup, context) +/* VSTRING *buffer; +/* ssize_t start; +/* char *template; +/* const char *filter; +/* const char *(*lookup) (const char *name, char *context); +/* char *context; +/* DESCRIPTION +/* smtp_reply_footer() expands a reply template to an existing +/* reply text. +/* +/* Arguments: +/* .IP buffer +/* Result buffer. This should contain a properly formatted +/* one-line or multi-line SMTP reply, with or without the final +/* . The reply code and optional enhanced status code +/* will be replicated in the footer text. One space character +/* after the SMTP reply code is replaced by '-'. If the existing +/* reply ends in , the result text will also end in +/* . +/* .IP start +/* The beginning of the SMTP reply that the footer will be +/* appended to. This supports applications that buffer up +/* multiple responses in one buffer. +/* .IP template +/* Template text, with optional $name attributes that will be +/* expanded. The two-character sequence "\n" is replaced by a +/* line break followed by a copy of the original SMTP reply +/* code and optional enhanced status code. +/* .IP filter +/* The set of characters that are allowed in attribute expansion. +/* .IP lookup +/* Attribute name/value lookup function. The result value must +/* be a null for a name that is not found, otherwise a pointer +/* to null-terminated string. +/* .IP context +/* Call-back context for the lookup function. +/* SEE ALSO +/* mac_expand(3) macro expansion +/* DIAGNOSTICS +/* smtp_reply_footer() returns 0 upon success, -1 if the +/* existing reply text is malformed. +/* +/* Fatal errors: memory allocation problem. +/* 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 +#include + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include + +/* SLMs. */ + +#define STR vstring_str + +int smtp_reply_footer(VSTRING *buffer, ssize_t start, + char *template, + const char *filter, + MAC_EXP_LOOKUP_FN lookup, + char *context) +{ + const char *myname = "smtp_reply_footer"; + char *cp; + char *next; + char *end; + ssize_t dsn_len; + int crlf_at_end = 0; + + /* + * Sanity check. + */ + if (start < 0 || start > VSTRING_LEN(buffer)) + msg_panic("%s: bad start: %ld", myname, (long) start); + if (*template == 0) + msg_panic("%s: empty template", myname); + + /* + * Scan and patch the original response. If the response is not what we + * expect, we stop making changes. + */ + for (cp = STR(buffer) + start, end = cp + strlen(cp);;) { + if (!ISDIGIT(cp[0]) || !ISDIGIT(cp[1]) || !ISDIGIT(cp[2]) + || (cp[3] != ' ' && cp[3] != '-')) + return (-1); + cp[3] = '-'; + if ((next = strstr(cp, "\r\n")) == 0) { + next = end; + break; + } + cp = next + 2; + if (cp == end) { + crlf_at_end = 1; + break; + } + } + + /* + * Truncate text after the first null, and truncate the trailing CRLF. + */ + if (next < vstring_end(buffer)) + vstring_truncate(buffer, next - STR(buffer)); + + /* + * Append the footer text one line at a time. Caution: before we append + * parts from the buffer to itself, we must extend the buffer first, + * otherwise we would have a dangling pointer "read" bug. + */ + dsn_len = dsn_valid(STR(buffer) + start + 4); + for (cp = template, end = cp + strlen(cp);;) { + if ((next = strstr(cp, "\\n")) != 0) { + *next = 0; + } else { + next = end; + } + /* Append a clone of the SMTP reply code. */ + vstring_strcat(buffer, "\r\n"); + VSTRING_SPACE(buffer, 3); + vstring_strncat(buffer, STR(buffer) + start, 3); + vstring_strcat(buffer, next != end ? "-" : " "); + /* Append a clone of the optional enhanced status code. */ + if (dsn_len > 0) { + VSTRING_SPACE(buffer, dsn_len); + vstring_strncat(buffer, STR(buffer) + start + 4, (int) dsn_len); + vstring_strcat(buffer, " "); + } + /* Append one line of footer text. */ + mac_expand(buffer, cp, MAC_EXP_FLAG_APPEND, filter, lookup, context); + if (next < end) { + *next = '\\'; + cp = next + 2; + } else + break; + } + if (crlf_at_end) + vstring_strcat(buffer, "\r\n"); + return (0); +} diff --git a/postfix/src/global/smtp_reply_footer.h b/postfix/src/global/smtp_reply_footer.h new file mode 100644 index 000000000..6cb65f60e --- /dev/null +++ b/postfix/src/global/smtp_reply_footer.h @@ -0,0 +1,37 @@ +#ifndef _SMTP_REPLY_FOOTER_H_INCLUDED_ +#define _SMTP_REPLY_FOOTER_H_INCLUDED_ + +/*++ +/* NAME +/* smtp_reply_footer 3h +/* SUMMARY +/* SMTP reply footer text support +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include +#include + + /* + * External interface. + */ +extern int smtp_reply_footer(VSTRING *, ssize_t, char *, const char *, + MAC_EXP_LOOKUP_FN, char *); + +/* 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/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in index 615ebb8f8..013f0f7b4 100644 --- a/postfix/src/postscreen/Makefile.in +++ b/postfix/src/postscreen/Makefile.in @@ -2,11 +2,11 @@ SHELL = /bin/sh SRCS = postscreen.c postscreen_dict.c postscreen_dnsbl.c \ postscreen_early.c postscreen_smtpd.c postscreen_misc.c \ postscreen_state.c postscreen_tests.c postscreen_send.c \ - postscreen_starttls.c + postscreen_starttls.c postscreen_expand.c OBJS = postscreen.o postscreen_dict.o postscreen_dnsbl.o \ postscreen_early.o postscreen_smtpd.o postscreen_misc.o \ postscreen_state.o postscreen_tests.o postscreen_send.o \ - postscreen_starttls.o + postscreen_starttls.o postscreen_expand.o HDRS = TESTSRC = DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) @@ -78,6 +78,7 @@ postscreen.o: ../../include/mail_params.h postscreen.o: ../../include/mail_proto.h postscreen.o: ../../include/mail_server.h postscreen.o: ../../include/mail_version.h +postscreen.o: ../../include/maps.h postscreen.o: ../../include/match_list.h postscreen.o: ../../include/match_ops.h postscreen.o: ../../include/msg.h @@ -98,6 +99,7 @@ postscreen_dict.o: ../../include/dict.h postscreen_dict.o: ../../include/dict_cache.h postscreen_dict.o: ../../include/events.h postscreen_dict.o: ../../include/htable.h +postscreen_dict.o: ../../include/maps.h postscreen_dict.o: ../../include/match_list.h postscreen_dict.o: ../../include/match_ops.h postscreen_dict.o: ../../include/msg.h @@ -120,6 +122,7 @@ postscreen_dnsbl.o: ../../include/iostuff.h postscreen_dnsbl.o: ../../include/ip_match.h postscreen_dnsbl.o: ../../include/mail_params.h postscreen_dnsbl.o: ../../include/mail_proto.h +postscreen_dnsbl.o: ../../include/maps.h postscreen_dnsbl.o: ../../include/match_list.h postscreen_dnsbl.o: ../../include/match_ops.h postscreen_dnsbl.o: ../../include/msg.h @@ -141,6 +144,7 @@ postscreen_early.o: ../../include/dict_cache.h postscreen_early.o: ../../include/events.h postscreen_early.o: ../../include/htable.h postscreen_early.o: ../../include/mail_params.h +postscreen_early.o: ../../include/maps.h postscreen_early.o: ../../include/match_list.h postscreen_early.o: ../../include/match_ops.h postscreen_early.o: ../../include/msg.h @@ -153,6 +157,28 @@ postscreen_early.o: ../../include/vstream.h postscreen_early.o: ../../include/vstring.h postscreen_early.o: postscreen.h postscreen_early.o: postscreen_early.c +postscreen_expand.o: ../../include/addr_match_list.h +postscreen_expand.o: ../../include/argv.h +postscreen_expand.o: ../../include/attr.h +postscreen_expand.o: ../../include/dict.h +postscreen_expand.o: ../../include/dict_cache.h +postscreen_expand.o: ../../include/events.h +postscreen_expand.o: ../../include/htable.h +postscreen_expand.o: ../../include/iostuff.h +postscreen_expand.o: ../../include/mail_params.h +postscreen_expand.o: ../../include/mail_proto.h +postscreen_expand.o: ../../include/maps.h +postscreen_expand.o: ../../include/match_list.h +postscreen_expand.o: ../../include/match_ops.h +postscreen_expand.o: ../../include/msg.h +postscreen_expand.o: ../../include/string_list.h +postscreen_expand.o: ../../include/stringops.h +postscreen_expand.o: ../../include/sys_defs.h +postscreen_expand.o: ../../include/vbuf.h +postscreen_expand.o: ../../include/vstream.h +postscreen_expand.o: ../../include/vstring.h +postscreen_expand.o: postscreen.h +postscreen_expand.o: postscreen_expand.c postscreen_misc.o: ../../include/addr_match_list.h postscreen_misc.o: ../../include/argv.h postscreen_misc.o: ../../include/dict.h @@ -162,6 +188,7 @@ postscreen_misc.o: ../../include/format_tv.h postscreen_misc.o: ../../include/htable.h postscreen_misc.o: ../../include/iostuff.h postscreen_misc.o: ../../include/mail_params.h +postscreen_misc.o: ../../include/maps.h postscreen_misc.o: ../../include/match_list.h postscreen_misc.o: ../../include/match_ops.h postscreen_misc.o: ../../include/msg.h @@ -180,10 +207,14 @@ postscreen_send.o: ../../include/dict_cache.h postscreen_send.o: ../../include/events.h postscreen_send.o: ../../include/htable.h postscreen_send.o: ../../include/iostuff.h +postscreen_send.o: ../../include/mac_expand.h +postscreen_send.o: ../../include/mac_parse.h postscreen_send.o: ../../include/mail_params.h +postscreen_send.o: ../../include/maps.h postscreen_send.o: ../../include/match_list.h postscreen_send.o: ../../include/match_ops.h postscreen_send.o: ../../include/msg.h +postscreen_send.o: ../../include/smtp_reply_footer.h postscreen_send.o: ../../include/string_list.h postscreen_send.o: ../../include/sys_defs.h postscreen_send.o: ../../include/vbuf.h @@ -201,6 +232,7 @@ postscreen_smtpd.o: ../../include/events.h postscreen_smtpd.o: ../../include/htable.h postscreen_smtpd.o: ../../include/iostuff.h postscreen_smtpd.o: ../../include/is_header.h +postscreen_smtpd.o: ../../include/lex_822.h postscreen_smtpd.o: ../../include/mail_params.h postscreen_smtpd.o: ../../include/mail_proto.h postscreen_smtpd.o: ../../include/maps.h @@ -230,6 +262,7 @@ postscreen_starttls.o: ../../include/htable.h postscreen_starttls.o: ../../include/iostuff.h postscreen_starttls.o: ../../include/mail_params.h postscreen_starttls.o: ../../include/mail_proto.h +postscreen_starttls.o: ../../include/maps.h postscreen_starttls.o: ../../include/match_list.h postscreen_starttls.o: ../../include/match_ops.h postscreen_starttls.o: ../../include/msg.h @@ -256,6 +289,7 @@ postscreen_state.o: ../../include/htable.h postscreen_state.o: ../../include/iostuff.h postscreen_state.o: ../../include/mail_proto.h postscreen_state.o: ../../include/mail_server.h +postscreen_state.o: ../../include/maps.h postscreen_state.o: ../../include/match_list.h postscreen_state.o: ../../include/match_ops.h postscreen_state.o: ../../include/msg.h @@ -275,6 +309,7 @@ postscreen_tests.o: ../../include/dict_cache.h postscreen_tests.o: ../../include/events.h postscreen_tests.o: ../../include/htable.h postscreen_tests.o: ../../include/mail_params.h +postscreen_tests.o: ../../include/maps.h postscreen_tests.o: ../../include/match_list.h postscreen_tests.o: ../../include/match_ops.h postscreen_tests.o: ../../include/msg.h diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index 580955461..cc7f3aa41 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -101,6 +101,8 @@ /* COMPATIBILITY CONTROLS /* .ad /* .fi +/* .IP "\fBpostscreen_command_filter ($smtpd_command_filter)\fR" +/* A mechanism to transform commands from remote SMTP clients. /* .IP "\fBpostscreen_discard_ehlo_keyword_address_maps ($smtpd_discard_ehlo_keyword_address_maps)\fR" /* Lookup tables, indexed by the remote SMTP client address, with /* case insensitive lists of EHLO keywords (pipelining, starttls, auth, @@ -254,6 +256,15 @@ /* .IP "\fBpostscreen_enforce_tls ($smtpd_enforce_tls)\fR" /* Mandatory TLS: announce STARTTLS support to SMTP clients, and /* require that clients use TLS encryption. +/* TROUBLE SHOOTING CONTROLS +/* .ad +/* .fi +/* .IP "\fBpostscreen_expansion_filter (see 'postconf -d' output)\fR" +/* List of characters that are permitted in postscreen_reject_footer +/* attribute expansions. +/* .IP "\fBpostscreen_reject_footer ($smtpd_reject_footer)\fR" +/* Optional information that is appended after a 4XX or 5XX server +/* response. /* MISCELLANEOUS CONTROLS /* .ad /* .fi @@ -265,9 +276,6 @@ /* sub-second delay values. /* .IP "\fBcommand_directory (see 'postconf -d' output)\fR" /* The location of all postfix administrative commands. -/* .IP "\fBipc_timeout (3600s)\fR" -/* The time limit for sending or receiving information over an internal -/* communication channel. /* .IP "\fBmax_idle (100s)\fR" /* The maximum amount of time that an idle Postfix daemon process waits /* for an incoming connection before terminating voluntarily. @@ -353,6 +361,9 @@ char *var_smtpd_banner; bool var_disable_vrfy_cmd; bool var_helo_required; +char *var_smtpd_cmd_filter; +char *var_psc_cmd_filter; + char *var_smtpd_forbid_cmds; char *var_psc_forbid_cmds; @@ -410,9 +421,15 @@ int var_psc_barlf_ttl; int var_psc_cmd_count; char *var_psc_cmd_time; +char *var_smtpd_rej_footer; +char *var_psc_rej_footer; + int var_smtpd_cconn_limit; int var_psc_cconn_limit; +char *var_smtpd_exp_filter; +char *var_psc_exp_filter; + /* * Global variables. */ @@ -835,6 +852,7 @@ static void post_jail_init(char *unused_name, char **unused_argv) 0, -1, }; int cache_flags; + const char *tmp; /* * This routine runs after the skeleton code has entered the chroot jail. @@ -843,6 +861,24 @@ static void post_jail_init(char *unused_name, char **unused_argv) */ var_use_limit = 0; + /* + * Workaround for parameters whose values may contain "$", and that have + * a default of "$parametername". Not sure if it would be a good idea to + * always to this in the mail_conf_raw(3) module. + */ + if (*var_psc_rej_footer == '$' + && mail_conf_lookup(var_psc_rej_footer + 1)) { + tmp = mail_conf_eval_once(var_psc_rej_footer); + myfree(var_psc_rej_footer); + var_psc_rej_footer = mystrdup(tmp); + } + if (*var_psc_exp_filter == '$' + && mail_conf_lookup(var_psc_exp_filter + 1)) { + tmp = mail_conf_eval_once(var_psc_exp_filter); + myfree(var_psc_exp_filter); + var_psc_exp_filter = mystrdup(tmp); + } + /* * Other one-time initialization. */ @@ -952,6 +988,7 @@ int main(int argc, char **argv) VAR_SMTPD_EHLO_DIS_WORDS, DEF_SMTPD_EHLO_DIS_WORDS, &var_smtpd_ehlo_dis_words, 0, 0, VAR_SMTPD_EHLO_DIS_MAPS, DEF_SMTPD_EHLO_DIS_MAPS, &var_smtpd_ehlo_dis_maps, 0, 0, VAR_SMTPD_TLS_LEVEL, DEF_SMTPD_TLS_LEVEL, &var_smtpd_tls_level, 0, 0, + VAR_SMTPD_CMD_FILTER, DEF_SMTPD_CMD_FILTER, &var_smtpd_cmd_filter, 0, 0, VAR_PSC_CACHE_MAP, DEF_PSC_CACHE_MAP, &var_psc_cache_map, 0, 0, VAR_PSC_PREGR_BANNER, DEF_PSC_PREGR_BANNER, &var_psc_pregr_banner, 0, 0, VAR_PSC_PREGR_ACTION, DEF_PSC_PREGR_ACTION, &var_psc_pregr_action, 1, 0, @@ -968,6 +1005,7 @@ int main(int argc, char **argv) VAR_PSC_EHLO_DIS_MAPS, DEF_PSC_EHLO_DIS_MAPS, &var_psc_ehlo_dis_maps, 0, 0, VAR_PSC_DNSBL_REPLY, DEF_PSC_DNSBL_REPLY, &var_psc_dnsbl_reply, 0, 0, VAR_PSC_TLS_LEVEL, DEF_PSC_TLS_LEVEL, &var_psc_tls_level, 0, 0, + VAR_PSC_CMD_FILTER, DEF_PSC_CMD_FILTER, &var_psc_cmd_filter, 0, 0, 0, }; static const CONFIG_INT_TABLE int_table[] = { @@ -1007,6 +1045,10 @@ int main(int argc, char **argv) }; static const CONFIG_RAW_TABLE raw_table[] = { VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, &var_psc_cmd_time, 1, 0, + VAR_SMTPD_REJ_FOOTER, DEF_SMTPD_REJ_FOOTER, &var_smtpd_rej_footer, 0, 0, + VAR_PSC_REJ_FOOTER, DEF_PSC_REJ_FOOTER, &var_psc_rej_footer, 0, 0, + VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0, + VAR_PSC_EXP_FILTER, DEF_PSC_EXP_FILTER, &var_psc_exp_filter, 1, 0, 0, }; static const CONFIG_NBOOL_TABLE nbool_table[] = { diff --git a/postfix/src/postscreen/postscreen.h b/postfix/src/postscreen/postscreen.h index f5b894e3d..74f35a30d 100644 --- a/postfix/src/postscreen/postscreen.h +++ b/postfix/src/postscreen/postscreen.h @@ -26,6 +26,7 @@ */ #include #include +#include /* * Preliminary stuff, to be fixed. @@ -67,6 +68,7 @@ typedef struct { int read_state; /* command read state machine */ /* smtpd(8) compatibility */ int ehlo_discard_mask; /* EHLO filter */ + VSTRING *expand_buf; /* macro expansion */ } PSC_STATE; #define PSC_TIME_STAMP_NEW (0) /* test was never passed */ @@ -384,6 +386,8 @@ extern const char *psc_print_state_flags(int, const char *); extern int psc_addr_match_list_match(ADDR_MATCH_LIST *, const char *); extern const char *psc_cache_lookup(DICT_CACHE *, const char *); extern void psc_cache_update(DICT_CACHE *, const char *, const char *); +const char *psc_dict_get(DICT *, const char *); +const char *psc_maps_find(MAPS *, const char *, int); /* * postscreen_dnsbl.c @@ -448,6 +452,13 @@ extern void psc_send_socket(PSC_STATE *); */ extern void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN); + /* + * postscreen_expand.c + */ +extern VSTRING *psc_expand_filter; +extern void psc_expand_init(void); +extern const char *psc_expand_lookup(const char *, int, char *); + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/postscreen/postscreen_dict.c b/postfix/src/postscreen/postscreen_dict.c index 92c0ba450..1db010251 100644 --- a/postfix/src/postscreen/postscreen_dict.c +++ b/postfix/src/postscreen/postscreen_dict.c @@ -18,6 +18,15 @@ /* DICT_CACHE *cache; /* const char *key; /* const char *value; +/* +/* void psc_dict_get(dict, key) +/* DICT *dict; +/* const char *key; +/* +/* void psc_maps_find(maps, key, flags) +/* MAPS *maps; +/* const char *key; +/* int flags; /* DESCRIPTION /* This module implements wrappers around time-critical table /* access functions. The functions log a warning when table @@ -28,6 +37,9 @@ /* /* psc_cache_lookup() and psc_cache_update() are wrappers around /* the corresponding dict_cache() methods. +/* +/* psc_dict_get() and psc_maps_find() are wrappers around +/* dict_get() and maps_find(), respectively. /* LICENSE /* .ad /* .fi @@ -46,6 +58,11 @@ /* Utility library. */ #include +#include + +/* Global library. */ + +#include /* Application-specific. */ @@ -105,3 +122,29 @@ void psc_cache_update(DICT_CACHE *cache, const char *key, const char *value) dict_cache_update(cache, key, value); PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update"); } + +/* psc_dict_get - time-critical table lookup */ + +const char *psc_dict_get(DICT *dict, const char *key) +{ + const char *myname = "psc_dict_get"; + const char *result; + + PSC_GET_TIME_BEFORE_LOOKUP; + result = dict_get(dict, key); + PSC_CHECK_TIME_AFTER_LOOKUP(dict->name, "lookup"); + return (result); +} + +/* psc_maps_find - time-critical table lookup */ + +const char *psc_maps_find(MAPS *maps, const char *key, int flags) +{ + const char *myname = "psc_maps_find"; + const char *result; + + PSC_GET_TIME_BEFORE_LOOKUP; + result = maps_find(maps, key, flags); + PSC_CHECK_TIME_AFTER_LOOKUP(maps->title, "lookup"); + return (result); +} diff --git a/postfix/src/postscreen/postscreen_early.c b/postfix/src/postscreen/postscreen_early.c index 807a0c9d5..cd77f5afd 100644 --- a/postfix/src/postscreen/postscreen_early.c +++ b/postfix/src/postscreen/postscreen_early.c @@ -48,6 +48,7 @@ #include static char *psc_teaser_greeting; +static VSTRING *psc_escape_buf; /* psc_early_event - handle pre-greet, EOF, and DNSBL results. */ @@ -172,9 +173,10 @@ static void psc_early_event(int event, char *context) return; } read_buf[read_count] = 0; + escape(psc_escape_buf, read_buf, read_count); msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count, psc_format_delta_time(psc_temp, state->start_time, &elapsed), - PSC_CLIENT_ADDR_PORT(state), printable(read_buf, '?')); + PSC_CLIENT_ADDR_PORT(state), STR(psc_escape_buf)); PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL); switch (psc_pregr_action) { case PSC_ACT_DROP: @@ -288,5 +290,6 @@ void psc_early_init(void) if (*var_psc_pregr_banner) { vstring_sprintf(psc_temp, "220-%s\r\n", var_psc_pregr_banner); psc_teaser_greeting = mystrdup(STR(psc_temp)); + psc_escape_buf = vstring_alloc(100); } } diff --git a/postfix/src/postscreen/postscreen_expand.c b/postfix/src/postscreen/postscreen_expand.c new file mode 100644 index 000000000..24e6728e9 --- /dev/null +++ b/postfix/src/postscreen/postscreen_expand.c @@ -0,0 +1,141 @@ +/*++ +/* NAME +/* postscreen_expand 3 +/* SUMMARY +/* SMTP server macro expansion +/* SYNOPSIS +/* #include +/* +/* void psc_expand_init() +/* +/* VSTRING *psc_expand_filter; +/* +/* const char *psc_expand_lookup(name, unused_mode, context) +/* const char *name; +/* int unused_mode; +/* char *context; +/* DESCRIPTION +/* This module expands session-related macros. +/* +/* psc_expand_init() performs one-time initialization +/* of the psc_expand_filter buffer. +/* +/* The psc_expand_filter buffer contains the characters +/* that are allowed in macro expansion, as specified with the +/* psc_expand_filter configuration parameter. +/* +/* psc_expand_lookup() returns the value of the named +/* macro or a null pointer. +/* +/* Arguments: +/* .IP name +/* Macro name. +/* .IP context +/* Call-back context (a PSC_STATE pointer). +/* DIAGNOSTICS +/* Panic: interface violations. Fatal errors: out of memory. +/* internal protocol errors. postscreen_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 + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + + /* + * Pre-parsed expansion filter. + */ +VSTRING *psc_expand_filter; + +/* psc_expand_init - initialize once during process lifetime */ + +void psc_expand_init(void) +{ + + /* + * Expand the expansion filter :-) + */ + psc_expand_filter = vstring_alloc(10); + unescape(psc_expand_filter, var_psc_exp_filter); +} + +/* psc_expand_lookup - generic SMTP attribute $name expansion */ + +const char *psc_expand_lookup(const char *name, int unused_mode, + char *context) +{ + PSC_STATE *state = (PSC_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("psc_expand_lookup: ${%s}", name); + +#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) +#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. + * + * XXX: This said, multiple servers may be behind a single client-visible + * name or IP address, and each may generate its own logs. Therefore, it + * may be useful to expose the replying MTA id (myhostname) in the + * contact footer, to identify the right logs. So while we don't expose + * the raw configuration dictionary, we do expose "$myhostname" as + * expanded in var_myhostname. + * + * Return NULL only for non-existent names. + */ + if (STREQ(name, MAIL_ATTR_SERVER_NAME)) { + return (var_myhostname); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) { + return (state->smtp_client_addr); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) { + return (state->smtp_client_port); + } 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 { + msg_warn("unknown macro name \"%s\" in expansion request", name); + return (0); + } +} diff --git a/postfix/src/postscreen/postscreen_send.c b/postfix/src/postscreen/postscreen_send.c index d74e60049..808afa69d 100644 --- a/postfix/src/postscreen/postscreen_send.c +++ b/postfix/src/postscreen/postscreen_send.c @@ -58,6 +58,7 @@ /* Global library. */ #include +#include /* Application-specific. */ @@ -74,7 +75,7 @@ int psc_send_reply(PSC_STATE *state, const char *text) { - int start; + ssize_t start; int ret; if (msg_verbose) @@ -87,6 +88,10 @@ int psc_send_reply(PSC_STATE *state, const char *text) */ start = VSTRING_LEN(state->send_buf); vstring_strcat(state->send_buf, text); + if (*var_psc_rej_footer && (*text == '4' || *text == '5')) + smtp_reply_footer(state->send_buf, start, var_psc_rej_footer, + STR(psc_expand_filter), psc_expand_lookup, + (char *) state); /* * XXX For soft_bounce support, it is not sufficient to fix replies here. diff --git a/postfix/src/postscreen/postscreen_smtpd.c b/postfix/src/postscreen/postscreen_smtpd.c index 5384eb80e..377347eb8 100644 --- a/postfix/src/postscreen/postscreen_smtpd.c +++ b/postfix/src/postscreen/postscreen_smtpd.c @@ -143,6 +143,7 @@ #include #include #include +#include /* TLS library. */ @@ -205,6 +206,11 @@ static void psc_smtpd_read_event(int, char *); static MAPS *psc_ehlo_discard_maps; static int psc_ehlo_discard_mask; + /* + * Command editing filter. + */ +static DICT *psc_cmd_filter; + /* * Encapsulation. We must not forget turn off input/timer events when we * terminate the SMTP protocol engine. @@ -319,8 +325,8 @@ static int psc_ehlo_cmd(PSC_STATE *state, char *args) * smtpd(8) compatibility: dynamic reply filtering. */ if (psc_ehlo_discard_maps != 0 - && (ehlo_words = maps_find(psc_ehlo_discard_maps, - state->smtp_client_addr, 0)) != 0 + && (ehlo_words = psc_maps_find(psc_ehlo_discard_maps, + state->smtp_client_addr, 0)) != 0 && (discard_mask = ehlo_mask(ehlo_words)) != psc_ehlo_discard_mask) { if (discard_mask && !(discard_mask & EHLO_MASK_SILENT)) msg_info("[%s]%s: discarding EHLO keywords: %s", @@ -348,13 +354,14 @@ static void psc_starttls_resume(int unused_event, char *context) PSC_STATE *state = (PSC_STATE *) context; /* - * Reset SMTP server state if STARTTLS was successful. Todo: reset SASL - * AUTH state. Dovecot responses may change when it knows that a - * connection is encrypted. + * Reset SMTP server state if STARTTLS was successful. */ if (state->flags & PSC_STATE_FLAG_USING_TLS) { PSC_STRING_RESET(state->helo_name); PSC_STRING_RESET(state->sender); +#ifdef TODO_SASL_AUTH + /* Reset SASL AUTH state. Dovecot responses may change. */ +#endif } /* @@ -791,11 +798,28 @@ static void psc_smtpd_read_event(int event, char *context) } /* - * Terminate the command line, and reset the command buffer write - * pointer and state machine in preparation for the next command. For - * this to work as expected, VSTRING_RESET() must be non-destructive. + * Terminate the command buffer, and apply the last-resort command + * editing workaround. */ VSTRING_TERMINATE(state->cmd_buffer); + if (psc_cmd_filter != 0) { + const char *cp; + + for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++) + /* void */ ; + if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) { + msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"", + state->smtp_client_addr, state->smtp_client_port, + STR(state->cmd_buffer), cp); + vstring_strcpy(state->cmd_buffer, cp); + } + } + + /* + * Reset the command buffer write pointer and state machine in + * preparation for the next command. For this to work as expected, + * VSTRING_RESET() must be non-destructive. + */ state->read_state = PSC_SMTPD_CMD_ST_ANY; VSTRING_RESET(state->cmd_buffer); @@ -1099,6 +1123,12 @@ void psc_smtpd_init(void) vstring_sprintf(psc_temp, "421 %s Service unavailable - try again later\r\n", var_myhostname); psc_smtpd_421_reply = mystrdup(STR(psc_temp)); + + /* + * Initialize the reply footer. + */ + if (*var_psc_rej_footer) + psc_expand_init(); } /* psc_smtpd_pre_jail_init - per-process deep protocol test initialization */ @@ -1113,8 +1143,16 @@ void psc_smtpd_pre_jail_init(void) * * XXX Bugger. This means we have to restart when the table changes! */ - psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS, - var_psc_ehlo_dis_maps, - DICT_FLAG_LOCK); + if (*var_psc_ehlo_dis_maps) + psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS, + var_psc_ehlo_dis_maps, + DICT_FLAG_LOCK); psc_ehlo_discard_mask = ehlo_mask(var_psc_ehlo_dis_words); + + /* + * Last-resort command editing support. + */ + if (*var_psc_cmd_filter) + psc_cmd_filter = dict_open(var_psc_cmd_filter, O_RDONLY, + DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); } diff --git a/postfix/src/postscreen/postscreen_state.c b/postfix/src/postscreen/postscreen_state.c index 97ffae132..bb205d5e1 100644 --- a/postfix/src/postscreen/postscreen_state.c +++ b/postfix/src/postscreen/postscreen_state.c @@ -165,6 +165,7 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream, state->cmd_buffer = 0; state->read_state = 0; state->ehlo_discard_mask = 0; /* XXX Should be ~0 */ + state->expand_buf = 0; /* * Update the stress level. @@ -225,6 +226,8 @@ void psc_free_session_state(PSC_STATE *state) myfree(state->sender); if (state->cmd_buffer) vstring_free(state->cmd_buffer); + if (state->expand_buf) + vstring_free(state->expand_buf); myfree((char *) state); if (psc_check_queue_length < 0 || psc_post_queue_length < 0) diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index c288a210c..6a8750e3a 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -849,6 +849,10 @@ static int smtp_start_tls(SMTP_STATE *state) SMTP_RESP_FAKE(&fake, "4.7.5"), "Server certificate not verified")); + + /* At this point there must not be any pending plaintext. */ + vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH); + /* * At this point we have to re-negotiate the "EHLO" to reget the * feature-list. diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 856e8b8e6..44792befb 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -216,7 +216,6 @@ 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 @@ -236,6 +235,7 @@ smtpd_chat.o: ../../include/name_mask.h smtpd_chat.o: ../../include/post_mail.h smtpd_chat.o: ../../include/rec_type.h smtpd_chat.o: ../../include/record.h +smtpd_chat.o: ../../include/smtp_reply_footer.h smtpd_chat.o: ../../include/smtp_stream.h smtpd_chat.o: ../../include/stringops.h smtpd_chat.o: ../../include/sys_defs.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 0026c2571..0ce3d8580 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -489,9 +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 "\fBsmtpd_reject_footer (empty)\fR" +/* Optional 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. @@ -1187,7 +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; +char *var_smtpd_rej_footer; #ifdef USE_TLS char *var_smtpd_relay_ccerts; @@ -3936,10 +3936,51 @@ static void chat_reset(SMTPD_STATE *state, int threshold) static void smtpd_start_tls(SMTPD_STATE *state) { int rate; + int cert_present; + int requirecert; + +#ifdef USE_TLSPROXY + + /* + * This is non-production code, for tlsproxy(8) load testing only. It + * implements enough to enable some Postfix features that depend on TLS + * encryption. + * + * To insert tlsproxy(8) between this process and the SMTP client, we swap + * the file descriptors between the state->tlsproxy and state->client + * VSTREAMS, so that we don't lose all the user-configurable + * state->client attributes (such as longjump buffers or timeouts). + * + * As we implement tlsproy support in the Postfix SMTP client we should + * develop a usable abstraction that encapsulates this stream plumbing in + * a library module. + */ + vstream_control(state->tlsproxy, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_END); + vstream_control(state->client, VSTREAM_CTL_SWAP_FD, state->tlsproxy, + VSTREAM_CTL_END); + (void) vstream_fclose(state->tlsproxy); /* direct-to-client stream! */ + state->tlsproxy = 0; + + /* + * 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. The attribute protocol is robust + * enough that an adversary cannot inject their own bogus TLS context + * attributes into the stream. + */ + state->tls_context = tls_proxy_context_receive(state->client); + + /* + * XXX Maybe it is better to send this information to tlsproxy(8) when + * requesting service, effectively making a remote tls_server_start() + * call. + */ + requirecert = (var_smtpd_tls_req_ccert && var_smtpd_enforce_tls); + +#else /* USE_TLSPROXY */ TLS_SERVER_START_PROPS props; static char *cipher_grade; static VSTRING *cipher_exclusions; - int cert_present; /* * Wrapper mode uses a dedicated port and always requires TLS. @@ -3976,20 +4017,23 @@ static void smtpd_start_tls(SMTPD_STATE *state) * Perform the TLS handshake now. Check the client certificate * requirements later, if necessary. */ + requirecert = (var_smtpd_tls_req_ccert && var_smtpd_enforce_tls); + state->tls_context = TLS_SERVER_START(&props, ctx = smtpd_tls_ctx, stream = state->client, log_level = var_smtpd_tls_loglevel, timeout = var_smtpd_starttls_tmout, - requirecert = (var_smtpd_tls_req_ccert - && var_smtpd_enforce_tls), + requirecert = requirecert, serverid = state->service, namaddr = state->namaddr, cipher_grade = cipher_grade, cipher_exclusions = STR(cipher_exclusions), fpt_dgst = var_smtpd_tls_fpt_dgst); +#endif /* USE_TLSPROXY */ + /* * For new (i.e. not re-used) TLS sessions, increment the client's new * TLS session rate counter. We enforce the limit here only for human @@ -4034,7 +4078,7 @@ static void smtpd_start_tls(SMTPD_STATE *state) * here. We have a usable TLS session with the client, so no need to * disable I/O, ... we can even be polite and send "421 ...". */ - if (props.requirecert && TLS_CERT_IS_TRUSTED(state->tls_context) == 0) { + if (requirecert && TLS_CERT_IS_TRUSTED(state->tls_context) == 0) { /* * Fetch and reject the next command (should be EHLO), then @@ -4083,11 +4127,6 @@ 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"); @@ -4117,14 +4156,32 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) smtpd_chat_reply(state, "502 5.5.1 Error: command not implemented"); return (-1); } -#ifndef USE_TLS_PROXY +#ifdef USE_TLSPROXY + + /* + * Note: state->tlsproxy is left open when smtp_flush() calls longjmp(), + * so we garbage-collect the VSTREAM in smtpd_state_reset(). + */ +#define PROXY_OPEN_FLAGS \ + (TLS_PROXY_FLAG_ROLE_SERVER | TLS_PROXY_FLAG_SEND_CONTEXT) + + state->tlsproxy = tls_proxy_open(PROXY_OPEN_FLAGS, state->client, + state->addr, state->port, + var_smtpd_tmout); + if (state->tlsproxy == 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); + } +#else /* USE_TLSPROXY */ 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 +#endif /* USE_TLSPROXY */ /* * Enforce TLS handshake rate limit when this client negotiated too many @@ -4148,13 +4205,17 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) smtpd_chat_reply(state, "454 4.7.0 Error: too many new TLS sessions from %s", state->namaddr); +#ifdef USE_TLSPROXY + (void) vstream_fclose(state->tlsproxy); + state->tlsproxy = 0; +#endif 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. */ + /* Flush before we switch read/write routines or file descriptors. */ smtp_flush(state->client); - vstream_fpurge(state->client, VSTREAM_PURGE_READ); /* Yay! */ + /* At this point there must not be any pending plaintext. */ + vstream_fpurge(state->client, VSTREAM_PURGE_BOTH); /* * Reset all inputs to the initial state. @@ -4172,73 +4233,6 @@ 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 */ @@ -4254,11 +4248,11 @@ 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 +#ifdef USE_TLSPROXY + tls_proxy_context_free(state->tls_context); +#else 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; } @@ -4379,7 +4373,17 @@ 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."); + /* We garbage-collect the VSTREAM in smtpd_state_reset() */ + state->tlsproxy = tls_proxy_open(PROXY_OPEN_FLAGS, state->client, + state->addr, state->port, + var_smtpd_tmout); + if (state->tlsproxy == 0) { + msg_warn("Wrapper-mode request dropped from %s for service %s." + " TLS context initialization failed. For details see" + " earlier warnings in your logs.", + state->namaddr, state->service); + break; + } #else /* USE_TLSPROXY */ if (smtpd_tls_ctx == 0) { msg_warn("Wrapper-mode request dropped from %s for service %s." @@ -4388,6 +4392,7 @@ static void smtpd_proto(SMTPD_STATE *state) state->namaddr, state->service); break; } +#endif /* USE_TLSPROXY */ if (var_smtpd_cntls_limit > 0 && !xclient_allowed && anvil_clnt @@ -4401,7 +4406,6 @@ static void smtpd_proto(SMTPD_STATE *state) break; } smtpd_start_tls(state); -#endif /* USE_TLSPROXY */ } #endif @@ -4517,25 +4521,6 @@ static void smtpd_proto(SMTPD_STATE *state) smtp_flush(state->client); #endif } else { -#ifdef PREGREET - if (*var_stress == 0 && strcmp(state->name, "unknown") == 0) { - smtpd_chat_reply(state, "220-%s", var_smtpd_banner); - smtp_flush(state->client); - if (read_wait(vstream_fileno(state->client), 1) == 0) { - int n = peekfd(vstream_fileno(state->client)); - - smtpd_chat_query(state); - msg_info("PREGREET %d from %s: %s", - n, state->namaddr, vstring_str(state->buffer)); - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, - "521 %s ESMTP not accepting connections", - var_myhostname); - /* Not: state->error_count++; */ - break; - } - } -#endif smtpd_chat_reply(state, "220 %s", var_smtpd_banner); } } @@ -4587,7 +4572,7 @@ static void smtpd_proto(SMTPD_STATE *state) for (cp = STR(state->buffer); *cp && IS_SPACE_TAB(*cp); cp++) /* void */ ; if ((cp = dict_get(smtpd_cmd_filter, cp)) != 0) { - msg_info("%s: replacing client command \"%s\" with \"%s\"", + msg_info("%s: replacing command \"%.100s\" with \"%.100s\"", state->namaddr, STR(state->buffer), cp); vstring_strcpy(state->buffer, cp); } @@ -4914,6 +4899,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) if (getuid() == 0 || getuid() == var_owner_uid) { if (var_smtpd_use_tls) { #ifdef USE_TLS +#ifndef USE_TLSPROXY TLS_SERVER_INIT_PROPS props; const char *cert_file; int have_server_cert; @@ -4980,6 +4966,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) fpt_dgst = var_smtpd_tls_fpt_dgst); else msg_warn("No server certs available. TLS won't be enabled"); +#endif /* USE_TLSPROXY */ #else msg_warn("TLS has been selected, but TLS support is not compiled in"); #endif @@ -5260,7 +5247,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, + VAR_SMTPD_REJ_FOOTER, DEF_SMTPD_REJ_FOOTER, &var_smtpd_rej_footer, 0, 0, 0, }; diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index 9b98ac7d3..0ffa1ee41 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -165,6 +165,9 @@ typedef struct { * TLS related state. */ #ifdef USE_TLS +#ifdef USE_TLSPROXY + VSTREAM *tlsproxy; /* tlsproxy(8) temp. handle */ +#endif 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 72f17fd43..da6e80ce6 100644 --- a/postfix/src/smtpd/smtpd_chat.c +++ b/postfix/src/smtpd/smtpd_chat.c @@ -83,7 +83,7 @@ #include #include #include -#include +#include /* Application-specific. */ @@ -147,7 +147,6 @@ 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 @@ -156,48 +155,16 @@ 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; - } - } + if (*var_smtpd_rej_footer + && (*(cp = STR(state->buffer)) == '4' || *cp == '5')) + smtp_reply_footer(state->buffer, 0, var_smtpd_rej_footer, + STR(smtpd_expand_filter), smtpd_expand_lookup, + (char *) state); + /* 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) { diff --git a/postfix/src/smtpd/smtpd_expand.c b/postfix/src/smtpd/smtpd_expand.c index 6683f4e0f..06dfa1b04 100644 --- a/postfix/src/smtpd/smtpd_expand.c +++ b/postfix/src/smtpd/smtpd_expand.c @@ -191,9 +191,18 @@ const char *smtpd_expand_lookup(const char *name, int unused_mode, * Don't query main.cf parameters, as the result of expansion could * reveal system-internal information in server replies. * + * XXX: This said, multiple servers may be behind a single client-visible + * name or IP address, and each may generate its own logs. Therefore, it + * may be useful to expose the replying MTA id (myhostname) in the + * contact footer, to identify the right logs. So while we don't expose + * the raw configuration dictionary, we do expose "$myhostname" as + * expanded in var_myhostname. + * * Return NULL only for non-existent names. */ - if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { + if (STREQ(name, MAIL_ATTR_SERVER_NAME)) { + return (var_myhostname); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { return (state->namaddr); } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) { return (state->port); diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index 8dc77a0b0..98f2f5b83 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -138,6 +138,9 @@ 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 +#ifdef USE_TLSPROXY + state->tlsproxy = 0; +#endif state->tls_context = 0; #endif @@ -208,4 +211,8 @@ void smtpd_state_reset(SMTPD_STATE *state) vstring_free(state->dsn_buf); if (state->dsn_orcpt_buf) vstring_free(state->dsn_orcpt_buf); +#if (defined(USE_TLS) && defined(USE_TLSPROXY)) + if (state->tlsproxy) /* still open after longjmp */ + vstream_fclose(state->tlsproxy); +#endif } diff --git a/postfix/src/tls/tls_proxy.h b/postfix/src/tls/tls_proxy.h index 3cf093a51..fb8092323 100644 --- a/postfix/src/tls/tls_proxy.h +++ b/postfix/src/tls/tls_proxy.h @@ -35,10 +35,10 @@ 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 *); +extern TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *); +extern void tls_proxy_context_free(TLS_SESS_STATE *); +extern int tls_proxy_context_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); #endif diff --git a/postfix/src/tls/tls_proxy_clnt.c b/postfix/src/tls/tls_proxy_clnt.c index 9f723d21a..a6877975d 100644 --- a/postfix/src/tls/tls_proxy_clnt.c +++ b/postfix/src/tls/tls_proxy_clnt.c @@ -14,10 +14,10 @@ /* const char *peer_port; /* int timeout; /* -/* TLS_SESS_STATE *tls_proxy_state_receive(proxy_stream) +/* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream) /* VSTREAM *proxy_stream; /* -/* void tls_proxy_state_free(tls_context) +/* void tls_proxy_context_free(tls_context) /* TLS_SESS_STATE *tls_context; /* DESCRIPTION /* tls_proxy_open() prepares for inserting the tlsproxy(8) @@ -34,17 +34,17 @@ /* buffer, timeout, etc.). Once the file descriptors are /* swapped, the proxy stream should be closed. /* -/* tls_proxy_state_receive() receives the TLS context object +/* tls_proxy_context_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. +/* to tls_proxy_context_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(). +/* tls_proxy_context_free() destroys a TLS context object that +/* was received with tls_proxy_context_receive(). /* /* Arguments: /* .IP flags @@ -68,7 +68,7 @@ /* .IP proxy_stream /* Stream from tls_proxy_open(). /* .IP tls_context -/* TLS session object from tls_proxy_state_receive(). +/* TLS session object from tls_proxy_context_receive(). /* LICENSE /* .ad /* .fi @@ -188,27 +188,27 @@ VSTREAM *tls_proxy_open(int flags, VSTREAM *peer_stream, return (tlsproxy_stream); } -/* tls_proxy_state_receive - receive TLS session object from tlsproxy(8) */ +/* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */ -TLS_SESS_STATE *tls_proxy_state_receive(VSTREAM *proxy_stream) +TLS_SESS_STATE *tls_proxy_context_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_FUNC, tls_proxy_context_scan, (char *) tls_context, ATTR_TYPE_END) != 1) { - tls_proxy_state_free(tls_context); + tls_proxy_context_free(tls_context); return (0); } else { return (tls_context); } } -/* tls_proxy_state_free - destroy object from tls_proxy_state_receive() */ +/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */ -void tls_proxy_state_free(TLS_SESS_STATE *tls_context) +void tls_proxy_context_free(TLS_SESS_STATE *tls_context) { if (tls_context->peer_CN) myfree(tls_context->peer_CN); diff --git a/postfix/src/tls/tls_proxy_print.c b/postfix/src/tls/tls_proxy_print.c index da759fdeb..36bfc112f 100644 --- a/postfix/src/tls/tls_proxy_print.c +++ b/postfix/src/tls/tls_proxy_print.c @@ -6,18 +6,18 @@ /* SYNOPSIS /* #include /* -/* int tls_proxy_print_state(print_fn, stream, flags, ptr) +/* int tls_proxy_context_print(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 +/* tls_proxy_context_print() 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, ... +/* ... ATTR_TYPE_FUNC, tls_proxy_context_print, (void *) tls_context, ... /* DIAGNOSTICS /* Fatal: out of memory. /* LICENSE @@ -50,9 +50,9 @@ #include #include -/* tls_proxy_print_state - send TLS session state over stream */ +/* tls_proxy_context_print - send TLS session state over stream */ -int tls_proxy_print_state(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, +int tls_proxy_context_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, int flags, void *ptr) { TLS_SESS_STATE *tp = (TLS_SESS_STATE *) ptr; diff --git a/postfix/src/tls/tls_proxy_scan.c b/postfix/src/tls/tls_proxy_scan.c index c68472743..fd5621036 100644 --- a/postfix/src/tls/tls_proxy_scan.c +++ b/postfix/src/tls/tls_proxy_scan.c @@ -6,18 +6,18 @@ /* SYNOPSIS /* #include /* -/* int tls_proxy_scan_state(scan_fn, stream, flags, ptr) +/* int tls_proxy_context_scan(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 +/* tls_proxy_context_scan() 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 +/* routine. tls_proxy_context_scan() is meant to be passed as /* a call-back to attr_scan(), thusly: /* -/* ... ATTR_TYPE_FUNC, tls_proxy_scan_state, (void *) tls_context, ... +/* ... ATTR_TYPE_FUNC, tls_proxy_context_scan, (void *) tls_context, ... /* DIAGNOSTICS /* Fatal: out of memory. /* LICENSE @@ -50,9 +50,9 @@ #include #include -/* tls_proxy_scan_state - receive TLS session state from stream */ +/* tls_proxy_context_scan - receive TLS session state from stream */ -int tls_proxy_scan_state(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, +int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, int flags, void *ptr) { TLS_SESS_STATE *tls_context = (TLS_SESS_STATE *) ptr; diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index 8786f29bf..aefe43872 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -469,7 +469,7 @@ static void tlsp_strategy(TLSP_STATE *state) } 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, + ATTR_TYPE_FUNC, tls_proxy_context_print, (char *) state->tls_context, ATTR_TYPE_END) != 0 || vstream_fflush(state->plaintext_stream) != 0)) { msg_warn("cannot send TLS context: %m");