From: Wietse Z Venema Date: Sat, 6 Sep 2025 05:00:00 +0000 (-0500) Subject: postfix-3.11-20250906 X-Git-Tag: v3.11.0-RC1~27 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=2a9680f6b99936fff653afebded7b37aee49e3b7;p=thirdparty%2Fpostfix.git postfix-3.11-20250906 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 53b03a912..bd2c2beec 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -29593,3 +29593,14 @@ Apologies for any names omitted. when dict_open() was called recursively, after dict_proxy_open() changed the name of a dictionary on-the-fly by skipping a proxy: prefix). File: util/dict_open.c. + +20250906 + + Bugfix: with "smtp_tls_enforce_sts_mx_patterns = yes" (the + default) transform the TLS policy from an STS policy plugin + as follows: connect to an MX host only if its name matches + an STS policy MX host pattern, and match the server + certificate against the MX hostname. Files: mantools/postlink, + proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c, + smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c, + smtp/smtp_tls_policy.c, smtp/smtp_tls_policy_test.c. diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index ba706a170..e116f43aa 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -762,45 +762,54 @@ SMTP(8) SMTP(8) When set to "yes", report the TLSRPT status only for "new" TLS sessions. + Available in Postfix version 3.10.5 and later: + + smtp_tls_enforce_sts_mx_patterns (yes) + Transform the TLS policy from an STS policy plugin: connect to + an MX host only if its name matches the STS policy MX host pat- + tern, and match the server certificate against the MX hostname. + + Available in Postfix version 3.11 and later: + tls_required_enable (yes) Enable support for the "TLS-Required: no" message header, defined in RFC 8689. OBSOLETE STARTTLS CONTROLS - The following configuration parameters exist for compatibility with - Postfix versions before 2.3. Support for these will be removed in a + The following configuration parameters exist for compatibility with + Postfix versions before 2.3. Support for these will be removed in a future release. smtp_use_tls (no) - Opportunistic mode: use TLS when a remote SMTP server announces + Opportunistic mode: use TLS when a remote SMTP server announces STARTTLS support, otherwise send the mail in the clear. smtp_enforce_tls (no) - Enforcement mode: require that remote SMTP servers use TLS + Enforcement mode: require that remote SMTP servers use TLS encryption, and never send mail in the clear. smtp_tls_enforce_peername (yes) - With mandatory TLS encryption, require that the remote SMTP - server hostname matches the information in the remote SMTP + With mandatory TLS encryption, require that the remote SMTP + server hostname matches the information in the remote SMTP server certificate. smtp_tls_per_site (empty) - Optional lookup tables with the Postfix SMTP client TLS usage - policy by next-hop destination and by remote SMTP server host- + Optional lookup tables with the Postfix SMTP client TLS usage + policy by next-hop destination and by remote SMTP server host- name. smtp_tls_cipherlist (empty) - Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS + Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS cipher list. RESOURCE AND RATE CONTROLS smtp_connect_timeout (30s) - The Postfix SMTP client time limit for completing a TCP connec- + The Postfix SMTP client time limit for completing a TCP connec- tion, or zero (use the operating system built-in time limit). smtp_helo_timeout (300s) - The Postfix SMTP client time limit for sending the HELO or EHLO - command, and for receiving the initial remote SMTP server + The Postfix SMTP client time limit for sending the HELO or EHLO + command, and for receiving the initial remote SMTP server response. lmtp_lhlo_timeout (300s) @@ -812,19 +821,19 @@ SMTP(8) SMTP(8) mand, and for receiving the remote SMTP server response. smtp_mail_timeout (300s) - The Postfix SMTP client time limit for sending the MAIL FROM + The Postfix SMTP client time limit for sending the MAIL FROM command, and for receiving the remote SMTP server response. smtp_rcpt_timeout (300s) - The Postfix SMTP client time limit for sending the SMTP RCPT TO + The Postfix SMTP client time limit for sending the SMTP RCPT TO command, and for receiving the remote SMTP server response. smtp_data_init_timeout (120s) - The Postfix SMTP client time limit for sending the SMTP DATA + The Postfix SMTP client time limit for sending the SMTP DATA command, and for receiving the remote SMTP server response. smtp_data_xfer_timeout (180s) - The Postfix SMTP client time limit for sending the SMTP message + The Postfix SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) @@ -838,13 +847,13 @@ SMTP(8) SMTP(8) Available in Postfix version 2.1 and later: smtp_mx_address_limit (5) - The maximal number of MX (mail exchanger) IP addresses that can - result from Postfix SMTP client mail exchanger lookups, or zero + The maximal number of MX (mail exchanger) IP addresses that can + result from Postfix SMTP client mail exchanger lookups, or zero (no limit). smtp_mx_session_limit (2) - The maximal number of SMTP sessions per delivery request before - the Postfix SMTP client gives up or delivers to a fall-back + The maximal number of SMTP sessions per delivery request before + the Postfix SMTP client gives up or delivers to a fall-back relay host, or zero (no limit). smtp_rset_timeout (20s) @@ -854,17 +863,17 @@ SMTP(8) SMTP(8) Available in Postfix version 2.2 and earlier: lmtp_cache_connection (yes) - Keep Postfix LMTP client connections open for up to $max_idle + Keep Postfix LMTP client connections open for up to $max_idle seconds. Available in Postfix version 2.2 and later: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the specified + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - Temporarily enable SMTP connection caching while a destination + Temporarily enable SMTP connection caching while a destination has a high volume of mail in the active queue. smtp_connection_reuse_time_limit (300s) @@ -878,23 +887,23 @@ SMTP(8) SMTP(8) Available in Postfix version 2.3 and later: connection_cache_protocol_timeout (5s) - Time limit for connection cache connect, send or receive opera- + Time limit for connection cache connect, send or receive opera- tions. Available in Postfix version 2.9 - 3.6: smtp_per_record_deadline (no) - Change the behavior of the smtp_*_timeout time limits, from a - time limit per read or write system call, to a time limit to - send or receive a complete record (an SMTP command line, SMTP - response line, SMTP message content line, or TLS protocol mes- + Change the behavior of the smtp_*_timeout time limits, from a + time limit per read or write system call, to a time limit to + send or receive a complete record (an SMTP command line, SMTP + response line, SMTP message content line, or TLS protocol mes- sage). Available in Postfix version 2.11 and later: smtp_connection_reuse_count_limit (0) - When SMTP connection caching is enabled, the number of times - that an SMTP session may be reused before it is closed, or zero + When SMTP connection caching is enabled, the number of times + that an SMTP session may be reused before it is closed, or zero (no limit). Available in Postfix version 3.4 and later: @@ -905,13 +914,13 @@ SMTP(8) SMTP(8) Available in Postfix version 3.7 and later: smtp_per_request_deadline (no) - Change the behavior of the smtp_*_timeout time limits, from a - time limit per plaintext or TLS read or write call, to a com- - bined time limit for sending a complete SMTP request and for + Change the behavior of the smtp_*_timeout time limits, from a + time limit per plaintext or TLS read or write call, to a com- + bined time limit for sending a complete SMTP request and for receiving a complete SMTP response. smtp_min_data_rate (500) - The minimum plaintext data transfer rate in bytes/second for + The minimum plaintext data transfer rate in bytes/second for DATA requests, when deadlines are enabled with smtp_per_request_deadline. @@ -919,54 +928,54 @@ SMTP(8) SMTP(8) transport_destination_concurrency_limit ($default_destination_concur- rency_limit) - A transport-specific override for the default_destination_con- + A transport-specific override for the default_destination_con- currency_limit parameter value, where transport is the master.cf name of the message delivery transport. transport_destination_recipient_limit ($default_destination_recipi- ent_limit) A transport-specific override for the default_destination_recip- - ient_limit parameter value, where transport is the master.cf + ient_limit parameter value, where transport is the master.cf name of the message delivery transport. SMTPUTF8 CONTROLS Preliminary SMTPUTF8 support is introduced with Postfix 3.0. smtputf8_enable (yes) - Enable preliminary SMTPUTF8 support for the protocols described + Enable preliminary SMTPUTF8 support for the protocols described in RFC 6531, RFC 6532, and RFC 6533. smtputf8_autodetect_classes (sendmail, verify) - Detect that a message requires SMTPUTF8 support for the speci- + Detect that a message requires SMTPUTF8 support for the speci- fied mail origin classes. Available in Postfix version 3.2 and later: enable_idna2003_compatibility (no) - Enable 'transitional' compatibility between IDNA2003 and - IDNA2008, when converting UTF-8 domain names to/from the ASCII + Enable 'transitional' compatibility between IDNA2003 and + IDNA2008, when converting UTF-8 domain names to/from the ASCII form that is used for DNS lookups. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - The increment in verbose logging level when a nexthop destina- - tion, remote client or server name or network address matches a + The increment in verbose logging level when a nexthop destina- + tion, remote client or server name or network address matches a pattern given with the debug_peer_list parameter. debug_peer_list (empty) - Optional list of nexthop destination, remote client or server - name or network address patterns that, if matched, cause the - verbose logging level to increase by the amount specified in + Optional list of nexthop destination, remote client or server + name or network address patterns that, if matched, cause the + verbose logging level to increase by the amount specified in $debug_peer_level. error_notice_recipient (postmaster) - The recipient of postmaster notifications about mail delivery + The recipient of postmaster notifications about mail delivery problems that are caused by policy, resource, software or proto- col errors. internal_mail_filter_classes (empty) - What categories of Postfix-generated mail are subject to - before-queue content inspection by non_smtpd_milters, + What categories of Postfix-generated mail are subject to + before-queue content inspection by non_smtpd_milters, header_checks and body_checks. notify_classes (resource, software) @@ -974,46 +983,46 @@ SMTP(8) SMTP(8) MISCELLANEOUS CONTROLS best_mx_transport (empty) - Where the Postfix SMTP client should deliver mail when it + Where the Postfix SMTP client should deliver mail when it detects a "mail loops back to myself" error condition. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and master.cf con- + The default location of the Postfix main.cf and master.cf con- figuration files. daemon_timeout (18000s) - How much time a Postfix daemon process may take to handle a + How much time a Postfix daemon process may take to handle a request before it is terminated by a built-in watchdog timer. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal point when log- + The maximal number of digits after the decimal point when log- ging delay values. disable_dns_lookups (no) Disable DNS lookups in the Postfix SMTP and LMTP clients. inet_interfaces (all) - The local network interface addresses that this mail system + The local network interface addresses that this mail system receives mail on. inet_protocols (see 'postconf -d' output) - The Internet protocols Postfix will attempt to use when making + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) - The time limit for sending or receiving information over an + The time limit for sending or receiving information over an internal communication channel. lmtp_assume_final (no) - When a remote LMTP server announces no DSN support, assume that - the server performs final delivery, and send "delivered" deliv- + When a remote LMTP server announces no DSN support, assume that + the server performs final delivery, and send "delivered" deliv- ery status notifications instead of "relayed". lmtp_tcp_port (24) The default TCP port that the Postfix LMTP client connects to. max_idle (100s) - The maximum amount of time that an idle Postfix daemon process + The maximum amount of time that an idle Postfix daemon process waits for an incoming connection before terminating voluntarily. max_use (100) @@ -1027,21 +1036,21 @@ SMTP(8) SMTP(8) The process name of a Postfix command or daemon process. proxy_interfaces (empty) - The remote network interface addresses that this mail system - receives mail on by way of a proxy or network address transla- + The remote network interface addresses that this mail system + receives mail on by way of a proxy or network address transla- tion unit. smtp_address_preference (any) The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP - client will try first, when a destination has IPv6 and IPv4 + client will try first, when a destination has IPv6 and IPv4 addresses with equal MX preference. smtp_bind_address (empty) - An optional numerical network address that the Postfix SMTP + An optional numerical network address that the Postfix SMTP client should bind to when making an IPv4 connection. smtp_bind_address6 (empty) - An optional numerical network address that the Postfix SMTP + An optional numerical network address that the Postfix SMTP client should bind to when making an IPv6 connection. smtp_helo_name ($myhostname) @@ -1061,7 +1070,7 @@ SMTP(8) SMTP(8) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - A prefix that is prepended to the process name in syslog + A prefix that is prepended to the process name in syslog records, so that, for example, "smtpd" becomes "prefix/smtpd". Available with Postfix 2.2 and earlier: @@ -1073,14 +1082,14 @@ SMTP(8) SMTP(8) Available with Postfix 2.3 and later: smtp_fallback_relay ($fallback_relay) - Optional list of relay destinations that will be used when an - SMTP destination is not found, or when delivery fails due to a + Optional list of relay destinations that will be used when an + SMTP destination is not found, or when delivery fails due to a non-permanent error. Available with Postfix 3.0 and later: smtp_address_verify_target (rcpt) - In the context of email address verification, the SMTP protocol + In the context of email address verification, the SMTP protocol stage that determines whether an email address is deliverable. Available with Postfix 3.1 and later: @@ -1102,7 +1111,7 @@ SMTP(8) SMTP(8) Available in Postfix 3.7 and later: smtp_bind_address_enforce (no) - Defer delivery when the Postfix SMTP client cannot apply the + Defer delivery when the Postfix SMTP client cannot apply the smtp_bind_address or smtp_bind_address6 setting. SEE ALSO diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 1f4b51a07..e3ad23702 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -5787,6 +5787,16 @@ configuration parameter. See there for details.

This feature is available in Postfix 2.3 and later.

+ + +
lmtp_tls_enforce_sts_mx_patterns +(default: yes)
+ +

See smtp_tls_enforce_sts_mx_patterns.

+ +

This feature is available in Postfix ≥ 3.10.5.

+ +
lmtp_tls_exclude_ciphers @@ -13539,6 +13549,18 @@ CommonName of this attacker will be logged).

Postfix 2.3 and later use smtp_tls_security_level instead.

+ + +
smtp_tls_enforce_sts_mx_patterns +(default: yes)
+ +

Transform the TLS policy from an STS policy plugin: connect to +an MX host only if its name matches the STS policy MX host pattern, +and match the server certificate against the MX hostname.

+ +

This feature is available in Postfix ≥ 3.10.5.

+ +
smtp_tls_exclude_ciphers diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index ba706a170..e116f43aa 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -762,45 +762,54 @@ SMTP(8) SMTP(8) When set to "yes", report the TLSRPT status only for "new" TLS sessions. + Available in Postfix version 3.10.5 and later: + + smtp_tls_enforce_sts_mx_patterns (yes) + Transform the TLS policy from an STS policy plugin: connect to + an MX host only if its name matches the STS policy MX host pat- + tern, and match the server certificate against the MX hostname. + + Available in Postfix version 3.11 and later: + tls_required_enable (yes) Enable support for the "TLS-Required: no" message header, defined in RFC 8689. OBSOLETE STARTTLS CONTROLS - The following configuration parameters exist for compatibility with - Postfix versions before 2.3. Support for these will be removed in a + The following configuration parameters exist for compatibility with + Postfix versions before 2.3. Support for these will be removed in a future release. smtp_use_tls (no) - Opportunistic mode: use TLS when a remote SMTP server announces + Opportunistic mode: use TLS when a remote SMTP server announces STARTTLS support, otherwise send the mail in the clear. smtp_enforce_tls (no) - Enforcement mode: require that remote SMTP servers use TLS + Enforcement mode: require that remote SMTP servers use TLS encryption, and never send mail in the clear. smtp_tls_enforce_peername (yes) - With mandatory TLS encryption, require that the remote SMTP - server hostname matches the information in the remote SMTP + With mandatory TLS encryption, require that the remote SMTP + server hostname matches the information in the remote SMTP server certificate. smtp_tls_per_site (empty) - Optional lookup tables with the Postfix SMTP client TLS usage - policy by next-hop destination and by remote SMTP server host- + Optional lookup tables with the Postfix SMTP client TLS usage + policy by next-hop destination and by remote SMTP server host- name. smtp_tls_cipherlist (empty) - Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS + Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS cipher list. RESOURCE AND RATE CONTROLS smtp_connect_timeout (30s) - The Postfix SMTP client time limit for completing a TCP connec- + The Postfix SMTP client time limit for completing a TCP connec- tion, or zero (use the operating system built-in time limit). smtp_helo_timeout (300s) - The Postfix SMTP client time limit for sending the HELO or EHLO - command, and for receiving the initial remote SMTP server + The Postfix SMTP client time limit for sending the HELO or EHLO + command, and for receiving the initial remote SMTP server response. lmtp_lhlo_timeout (300s) @@ -812,19 +821,19 @@ SMTP(8) SMTP(8) mand, and for receiving the remote SMTP server response. smtp_mail_timeout (300s) - The Postfix SMTP client time limit for sending the MAIL FROM + The Postfix SMTP client time limit for sending the MAIL FROM command, and for receiving the remote SMTP server response. smtp_rcpt_timeout (300s) - The Postfix SMTP client time limit for sending the SMTP RCPT TO + The Postfix SMTP client time limit for sending the SMTP RCPT TO command, and for receiving the remote SMTP server response. smtp_data_init_timeout (120s) - The Postfix SMTP client time limit for sending the SMTP DATA + The Postfix SMTP client time limit for sending the SMTP DATA command, and for receiving the remote SMTP server response. smtp_data_xfer_timeout (180s) - The Postfix SMTP client time limit for sending the SMTP message + The Postfix SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) @@ -838,13 +847,13 @@ SMTP(8) SMTP(8) Available in Postfix version 2.1 and later: smtp_mx_address_limit (5) - The maximal number of MX (mail exchanger) IP addresses that can - result from Postfix SMTP client mail exchanger lookups, or zero + The maximal number of MX (mail exchanger) IP addresses that can + result from Postfix SMTP client mail exchanger lookups, or zero (no limit). smtp_mx_session_limit (2) - The maximal number of SMTP sessions per delivery request before - the Postfix SMTP client gives up or delivers to a fall-back + The maximal number of SMTP sessions per delivery request before + the Postfix SMTP client gives up or delivers to a fall-back relay host, or zero (no limit). smtp_rset_timeout (20s) @@ -854,17 +863,17 @@ SMTP(8) SMTP(8) Available in Postfix version 2.2 and earlier: lmtp_cache_connection (yes) - Keep Postfix LMTP client connections open for up to $max_idle + Keep Postfix LMTP client connections open for up to $max_idle seconds. Available in Postfix version 2.2 and later: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the specified + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - Temporarily enable SMTP connection caching while a destination + Temporarily enable SMTP connection caching while a destination has a high volume of mail in the active queue. smtp_connection_reuse_time_limit (300s) @@ -878,23 +887,23 @@ SMTP(8) SMTP(8) Available in Postfix version 2.3 and later: connection_cache_protocol_timeout (5s) - Time limit for connection cache connect, send or receive opera- + Time limit for connection cache connect, send or receive opera- tions. Available in Postfix version 2.9 - 3.6: smtp_per_record_deadline (no) - Change the behavior of the smtp_*_timeout time limits, from a - time limit per read or write system call, to a time limit to - send or receive a complete record (an SMTP command line, SMTP - response line, SMTP message content line, or TLS protocol mes- + Change the behavior of the smtp_*_timeout time limits, from a + time limit per read or write system call, to a time limit to + send or receive a complete record (an SMTP command line, SMTP + response line, SMTP message content line, or TLS protocol mes- sage). Available in Postfix version 2.11 and later: smtp_connection_reuse_count_limit (0) - When SMTP connection caching is enabled, the number of times - that an SMTP session may be reused before it is closed, or zero + When SMTP connection caching is enabled, the number of times + that an SMTP session may be reused before it is closed, or zero (no limit). Available in Postfix version 3.4 and later: @@ -905,13 +914,13 @@ SMTP(8) SMTP(8) Available in Postfix version 3.7 and later: smtp_per_request_deadline (no) - Change the behavior of the smtp_*_timeout time limits, from a - time limit per plaintext or TLS read or write call, to a com- - bined time limit for sending a complete SMTP request and for + Change the behavior of the smtp_*_timeout time limits, from a + time limit per plaintext or TLS read or write call, to a com- + bined time limit for sending a complete SMTP request and for receiving a complete SMTP response. smtp_min_data_rate (500) - The minimum plaintext data transfer rate in bytes/second for + The minimum plaintext data transfer rate in bytes/second for DATA requests, when deadlines are enabled with smtp_per_request_deadline. @@ -919,54 +928,54 @@ SMTP(8) SMTP(8) transport_destination_concurrency_limit ($default_destination_concur- rency_limit) - A transport-specific override for the default_destination_con- + A transport-specific override for the default_destination_con- currency_limit parameter value, where transport is the master.cf name of the message delivery transport. transport_destination_recipient_limit ($default_destination_recipi- ent_limit) A transport-specific override for the default_destination_recip- - ient_limit parameter value, where transport is the master.cf + ient_limit parameter value, where transport is the master.cf name of the message delivery transport. SMTPUTF8 CONTROLS Preliminary SMTPUTF8 support is introduced with Postfix 3.0. smtputf8_enable (yes) - Enable preliminary SMTPUTF8 support for the protocols described + Enable preliminary SMTPUTF8 support for the protocols described in RFC 6531, RFC 6532, and RFC 6533. smtputf8_autodetect_classes (sendmail, verify) - Detect that a message requires SMTPUTF8 support for the speci- + Detect that a message requires SMTPUTF8 support for the speci- fied mail origin classes. Available in Postfix version 3.2 and later: enable_idna2003_compatibility (no) - Enable 'transitional' compatibility between IDNA2003 and - IDNA2008, when converting UTF-8 domain names to/from the ASCII + Enable 'transitional' compatibility between IDNA2003 and + IDNA2008, when converting UTF-8 domain names to/from the ASCII form that is used for DNS lookups. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - The increment in verbose logging level when a nexthop destina- - tion, remote client or server name or network address matches a + The increment in verbose logging level when a nexthop destina- + tion, remote client or server name or network address matches a pattern given with the debug_peer_list parameter. debug_peer_list (empty) - Optional list of nexthop destination, remote client or server - name or network address patterns that, if matched, cause the - verbose logging level to increase by the amount specified in + Optional list of nexthop destination, remote client or server + name or network address patterns that, if matched, cause the + verbose logging level to increase by the amount specified in $debug_peer_level. error_notice_recipient (postmaster) - The recipient of postmaster notifications about mail delivery + The recipient of postmaster notifications about mail delivery problems that are caused by policy, resource, software or proto- col errors. internal_mail_filter_classes (empty) - What categories of Postfix-generated mail are subject to - before-queue content inspection by non_smtpd_milters, + What categories of Postfix-generated mail are subject to + before-queue content inspection by non_smtpd_milters, header_checks and body_checks. notify_classes (resource, software) @@ -974,46 +983,46 @@ SMTP(8) SMTP(8) MISCELLANEOUS CONTROLS best_mx_transport (empty) - Where the Postfix SMTP client should deliver mail when it + Where the Postfix SMTP client should deliver mail when it detects a "mail loops back to myself" error condition. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and master.cf con- + The default location of the Postfix main.cf and master.cf con- figuration files. daemon_timeout (18000s) - How much time a Postfix daemon process may take to handle a + How much time a Postfix daemon process may take to handle a request before it is terminated by a built-in watchdog timer. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal point when log- + The maximal number of digits after the decimal point when log- ging delay values. disable_dns_lookups (no) Disable DNS lookups in the Postfix SMTP and LMTP clients. inet_interfaces (all) - The local network interface addresses that this mail system + The local network interface addresses that this mail system receives mail on. inet_protocols (see 'postconf -d' output) - The Internet protocols Postfix will attempt to use when making + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) - The time limit for sending or receiving information over an + The time limit for sending or receiving information over an internal communication channel. lmtp_assume_final (no) - When a remote LMTP server announces no DSN support, assume that - the server performs final delivery, and send "delivered" deliv- + When a remote LMTP server announces no DSN support, assume that + the server performs final delivery, and send "delivered" deliv- ery status notifications instead of "relayed". lmtp_tcp_port (24) The default TCP port that the Postfix LMTP client connects to. max_idle (100s) - The maximum amount of time that an idle Postfix daemon process + The maximum amount of time that an idle Postfix daemon process waits for an incoming connection before terminating voluntarily. max_use (100) @@ -1027,21 +1036,21 @@ SMTP(8) SMTP(8) The process name of a Postfix command or daemon process. proxy_interfaces (empty) - The remote network interface addresses that this mail system - receives mail on by way of a proxy or network address transla- + The remote network interface addresses that this mail system + receives mail on by way of a proxy or network address transla- tion unit. smtp_address_preference (any) The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP - client will try first, when a destination has IPv6 and IPv4 + client will try first, when a destination has IPv6 and IPv4 addresses with equal MX preference. smtp_bind_address (empty) - An optional numerical network address that the Postfix SMTP + An optional numerical network address that the Postfix SMTP client should bind to when making an IPv4 connection. smtp_bind_address6 (empty) - An optional numerical network address that the Postfix SMTP + An optional numerical network address that the Postfix SMTP client should bind to when making an IPv6 connection. smtp_helo_name ($myhostname) @@ -1061,7 +1070,7 @@ SMTP(8) SMTP(8) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - A prefix that is prepended to the process name in syslog + A prefix that is prepended to the process name in syslog records, so that, for example, "smtpd" becomes "prefix/smtpd". Available with Postfix 2.2 and earlier: @@ -1073,14 +1082,14 @@ SMTP(8) SMTP(8) Available with Postfix 2.3 and later: smtp_fallback_relay ($fallback_relay) - Optional list of relay destinations that will be used when an - SMTP destination is not found, or when delivery fails due to a + Optional list of relay destinations that will be used when an + SMTP destination is not found, or when delivery fails due to a non-permanent error. Available with Postfix 3.0 and later: smtp_address_verify_target (rcpt) - In the context of email address verification, the SMTP protocol + In the context of email address verification, the SMTP protocol stage that determines whether an email address is deliverable. Available with Postfix 3.1 and later: @@ -1102,7 +1111,7 @@ SMTP(8) SMTP(8) Available in Postfix 3.7 and later: smtp_bind_address_enforce (no) - Defer delivery when the Postfix SMTP client cannot apply the + Defer delivery when the Postfix SMTP client cannot apply the smtp_bind_address or smtp_bind_address6 setting. SEE ALSO diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 22757a2e1..31bfc0375 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -3499,6 +3499,10 @@ The LMTP\-specific version of the smtp_tls_enforce_peername configuration parameter. See there for details. .PP This feature is available in Postfix 2.3 and later. +.SH lmtp_tls_enforce_sts_mx_patterns (default: yes) +See smtp_tls_enforce_sts_mx_patterns. +.PP +This feature is available in Postfix >= 3.10.5. .SH lmtp_tls_exclude_ciphers (default: empty) The LMTP\-specific version of the smtp_tls_exclude_ciphers configuration parameter. See there for details. @@ -8697,6 +8701,12 @@ CommonName of this attacker will be logged). .PP This feature is available in Postfix 2.2 and later. With Postfix 2.3 and later use smtp_tls_security_level instead. +.SH smtp_tls_enforce_sts_mx_patterns (default: yes) +Transform the TLS policy from an STS policy plugin: connect to +an MX host only if its name matches the STS policy MX host pattern, +and match the server certificate against the MX hostname. +.PP +This feature is available in Postfix >= 3.10.5. .SH smtp_tls_exclude_ciphers (default: empty) List of ciphers or cipher types to exclude from the Postfix SMTP client cipher diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index ff7921bd8..dde3d5c7d 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -684,6 +684,14 @@ by a local TLSRPT reporting service. .IP "\fBsmtp_tlsrpt_skip_reused_handshakes (Postfix >= 3.11: no, Postfix 3.10: yes)\fR" When set to "yes", report the TLSRPT status only for "new" TLS sessions. +.PP +Available in Postfix version 3.10.5 and later: +.IP "\fBsmtp_tls_enforce_sts_mx_patterns (yes)\fR" +Transform the TLS policy from an STS policy plugin: connect to +an MX host only if its name matches the STS policy MX host pattern, +and match the server certificate against the MX hostname. +.PP +Available in Postfix version 3.11 and later: .IP "\fBtls_required_enable (yes)\fR" Enable support for the "TLS\-Required: no" message header, defined in RFC 8689. diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 061e0aef1..2b174bcac 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -729,6 +729,8 @@ while (<>) { s;\blmtp_tlsrpt_enable\b;$&;g; s;\blmtp_tlsrpt_socket_name\b;$&;g; s;\blmtp_tlsrpt_skip_reused_handshakes\b;$&;g; + s;\blmtp_tls_enforce_sts_mx_patterns\b;$&;g; + s;\bsmtp_tls_enforce_sts_mx_patterns\b;$&;g; s;\bsmtpd_enforce_tls\b;$&;g; s;\bsmtpd_sasl_tls_security_options\b;$&;g; s;\bsmtpd_sasl_type\b;$&;g; diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 4b0ca1212..cbaf202ec 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -19566,6 +19566,20 @@ second etc. TLS handshake to report.

This feature is available in Postfix ≥ 3.10.

+%PARAM lmtp_tls_enforce_sts_mx_patterns yes + +

See smtp_tls_enforce_sts_mx_patterns.

+ +

This feature is available in Postfix ≥ 3.10.5.

+ +%PARAM smtp_tls_enforce_sts_mx_patterns yes + +

Transform the TLS policy from an STS policy plugin: connect to +an MX host only if its name matches the STS policy MX host pattern, +and match the server certificate against the MX hostname.

+ +

This feature is available in Postfix ≥ 3.10.5.

+ %PARAM full_name_encoding_charset utf-8

The character set name (also called "charset") that Postfix diff --git a/postfix/proto/stop.spell-cc b/postfix/proto/stop.spell-cc index ff0517210..4313fb9d7 100644 --- a/postfix/proto/stop.spell-cc +++ b/postfix/proto/stop.spell-cc @@ -1868,3 +1868,5 @@ deduplicates intmax lflag REPLYCODE +PTEST +finalizer diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 551020a86..28a879f1c 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -4514,6 +4514,12 @@ extern char *var_smtp_tlsrpt_sockname; #define DEF_LMTP_TLSRPT_SKIP_REUSED_HS DEF_SMTP_TLSRPT_SKIP_REUSED_HS extern int var_smtp_tlsrpt_skip_reused_hs; +#define VAR_SMTP_TLS_ENF_STS_MX_PAT "smtp_tls_enforce_sts_mx_patterns" +#define DEF_SMTP_TLS_ENF_STS_MX_PAT "yes" +#define VAR_LMTP_TLS_ENF_STS_MX_PAT "lmtp_tls_enforce_sts_mx_patterns" +#define DEF_LMTP_TLS_ENF_STS_MX_PAT "yes" +extern bool var_smtp_tls_enf_sts_mx_pat; + /* * RFC 2047 encoding of full name info. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 85e924775..564e97222 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 "20250825" +#define MAIL_RELEASE_DATE "20250906" #define MAIL_VERSION_NUMBER "3.11" #ifdef SNAPSHOT diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index f8cde6978..25002c658 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -8,10 +8,10 @@ OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \ smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \ smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o HDRS = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h -TESTSRC = +TESTSRC = smtp_policy_test.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) -TESTPROG= smtp_unalias smtp_map11 +TESTPROG= smtp_unalias smtp_map11 smtp_tls_policy_test PROG = smtp INC_DIR = ../../include LIBS = ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \ @@ -33,7 +33,7 @@ Makefile: Makefile.in test: $(TESTPROG) -tests: smtp_map11_test +tests: smtp_map11_test test_smtp_tls_policy root_tests: @@ -64,6 +64,14 @@ smtp_map11_test: smtp_map11 smtp_map11.ref diff smtp_map11.ref smtp_map11.tmp rm -f smtp_map11.tmp +SMTP_POLICY_TEST_OBJ = smtp_tls_policy_test.o smtp_tls_policy.o smtp_state.o smtp_key.o + +smtp_tls_policy_test: $(SMTP_POLICY_TEST_OBJ) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(SMTP_POLICY_TEST_OBJ) $(LIBS) $(SYSLIBS) + +test_smtp_tls_policy: smtp_tls_policy_test + $(SHLIB_ENV) $(VALGRIND) ./smtp_tls_policy_test + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ @@ -777,6 +785,7 @@ smtp_tls_policy.o: ../../include/htable.h smtp_tls_policy.o: ../../include/mail_params.h smtp_tls_policy.o: ../../include/maps.h smtp_tls_policy.o: ../../include/match_list.h +smtp_tls_policy.o: ../../include/midna_domain.h smtp_tls_policy.o: ../../include/mime_state.h smtp_tls_policy.o: ../../include/msg.h smtp_tls_policy.o: ../../include/msg_stats.h @@ -806,6 +815,46 @@ smtp_tls_policy.o: ../../include/vstream.h smtp_tls_policy.o: ../../include/vstring.h smtp_tls_policy.o: smtp.h smtp_tls_policy.o: smtp_tls_policy.c +smtp_tls_policy_test.o: ../../include/argv.h +smtp_tls_policy_test.o: ../../include/attr.h +smtp_tls_policy_test.o: ../../include/check_arg.h +smtp_tls_policy_test.o: ../../include/deliver_request.h +smtp_tls_policy_test.o: ../../include/dict.h +smtp_tls_policy_test.o: ../../include/dns.h +smtp_tls_policy_test.o: ../../include/dsn.h +smtp_tls_policy_test.o: ../../include/dsn_buf.h +smtp_tls_policy_test.o: ../../include/header_body_checks.h +smtp_tls_policy_test.o: ../../include/header_opts.h +smtp_tls_policy_test.o: ../../include/htable.h +smtp_tls_policy_test.o: ../../include/mail_params.h +smtp_tls_policy_test.o: ../../include/maps.h +smtp_tls_policy_test.o: ../../include/match_list.h +smtp_tls_policy_test.o: ../../include/mime_state.h +smtp_tls_policy_test.o: ../../include/msg.h +smtp_tls_policy_test.o: ../../include/msg_stats.h +smtp_tls_policy_test.o: ../../include/msg_vstream.h +smtp_tls_policy_test.o: ../../include/myaddrinfo.h +smtp_tls_policy_test.o: ../../include/myflock.h +smtp_tls_policy_test.o: ../../include/mymalloc.h +smtp_tls_policy_test.o: ../../include/name_code.h +smtp_tls_policy_test.o: ../../include/name_mask.h +smtp_tls_policy_test.o: ../../include/nvtable.h +smtp_tls_policy_test.o: ../../include/recipient_list.h +smtp_tls_policy_test.o: ../../include/resolve_clnt.h +smtp_tls_policy_test.o: ../../include/scache.h +smtp_tls_policy_test.o: ../../include/sendopts.h +smtp_tls_policy_test.o: ../../include/sock_addr.h +smtp_tls_policy_test.o: ../../include/string_list.h +smtp_tls_policy_test.o: ../../include/stringops.h +smtp_tls_policy_test.o: ../../include/sys_defs.h +smtp_tls_policy_test.o: ../../include/tls.h +smtp_tls_policy_test.o: ../../include/tls_proxy.h +smtp_tls_policy_test.o: ../../include/tok822.h +smtp_tls_policy_test.o: ../../include/vbuf.h +smtp_tls_policy_test.o: ../../include/vstream.h +smtp_tls_policy_test.o: ../../include/vstring.h +smtp_tls_policy_test.o: smtp.h +smtp_tls_policy_test.o: smtp_tls_policy_test.c smtp_tlsrpt.o: ../../include/argv.h smtp_tlsrpt.o: ../../include/attr.h smtp_tlsrpt.o: ../../include/check_arg.h diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index b77500326..963081b54 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -140,5 +140,6 @@ VAR_LMTP_REQ_DEADLINE, DEF_LMTP_REQ_DEADLINE, &var_smtp_req_deadline, VAR_LMTP_TLSRPT_ENABLE, DEF_LMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable, VAR_LMTP_TLSRPT_SKIP_REUSED_HS, DEF_LMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs, + VAR_LMTP_TLS_ENF_STS_MX_PAT, DEF_LMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat, 0, }; diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 76e1a3801..beb46033c 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -650,6 +650,14 @@ /* .IP "\fBsmtp_tlsrpt_skip_reused_handshakes (Postfix >= 3.11: no, Postfix 3.10: yes)\fR" /* When set to "yes", report the TLSRPT status only for "new" TLS /* sessions. +/* .PP +/* Available in Postfix version 3.10.5 and later: +/* .IP "\fBsmtp_tls_enforce_sts_mx_patterns (yes)\fR" +/* Transform the TLS policy from an STS policy plugin: connect to +/* an MX host only if its name matches the STS policy MX host pattern, +/* and match the server certificate against the MX hostname. +/* .PP +/* Available in Postfix version 3.11 and later: /* .IP "\fBtls_required_enable (yes)\fR" /* Enable support for the "TLS-Required: no" message header, defined /* in RFC 8689. @@ -1132,6 +1140,7 @@ bool var_smtp_tls_blk_early_mail_reply; bool var_smtp_tls_force_tlsa; char *var_smtp_tls_insecure_mx_policy; bool var_smtp_tls_enable_rpk; +bool var_smtp_tls_enf_sts_mx_pat; #endif diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 874f9481c..28cca83a4 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -137,6 +137,7 @@ typedef struct SMTP_TLS_POLICY { extern void smtp_tls_list_init(void); extern int smtp_tls_policy_cache_query(DSN_BUF *, SMTP_TLS_POLICY *, SMTP_ITERATOR *); extern void smtp_tls_policy_cache_flush(void); +extern int smtp_tls_authorize_mx_hostname(SMTP_TLS_POLICY *, const char *); /* * Macros must use distinct names for local temporary variables, otherwise diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index fb3494523..7a93e638c 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -1124,6 +1124,11 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop, continue; /* XXX Assume there is no code at the end of this loop. */ } + /* Skip MX hosts that lack authorization. */ + if (!smtp_tls_authorize_mx_hostname(state->tls, addr->qname)) { + continue; + /* XXX Assume there is no code at the end of this loop. */ + } /* Disable TLS when retrying after a handshake failure */ if (retry_plain) { state->tls->level = TLS_LEV_NONE; diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index 6d80ef105..8569cb9f5 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -144,5 +144,6 @@ VAR_SMTP_REQ_DEADLINE, DEF_SMTP_REQ_DEADLINE, &var_smtp_req_deadline, VAR_SMTP_TLSRPT_ENABLE, DEF_SMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable, VAR_SMTP_TLSRPT_SKIP_REUSED_HS, DEF_SMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs, + VAR_SMTP_TLS_ENF_STS_MX_PAT, DEF_SMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat, 0, }; diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c index 809ffea05..76f38aa3e 100644 --- a/postfix/src/smtp/smtp_tls_policy.c +++ b/postfix/src/smtp/smtp_tls_policy.c @@ -17,6 +17,10 @@ /* SMTP_TLS_POLICY *tls; /* /* void smtp_tls_policy_cache_flush() +/* +/* int smtp_tls_authorize_mx_hostname(tls, qname) +/* SMTP_TLS_POLICY *tls; +/* const char *qname; /* DESCRIPTION /* smtp_tls_list_init() initializes lookup tables used by the TLS /* policy engine. @@ -38,6 +42,11 @@ /* smtp_tls_policy_cache_flush() destroys the TLS policy cache /* and contents. /* +/* smtp_tls_authorize_mx_hostname() authorizes an MX host if the +/* name used for host lookup satisfies a TLS policy MX name +/* constraint (for example, an STS policy MX pattern), or if the +/* TLS policy has no name constraint. +/* /* Arguments: /* .IP why /* A pointer to a DSN_BUF which holds error status information when @@ -107,6 +116,7 @@ #include #include #include +#include /* Global library. */ @@ -136,6 +146,51 @@ static void dane_init(SMTP_TLS_POLICY *, SMTP_ITERATOR *); static MAPS *tls_policy; /* lookup table(s) */ static MAPS *tls_per_site; /* lookup table(s) */ +/* match_sts_mx_host_pattern - match hostname against STS policy MX pattern */ + +static int match_sts_mx_host_pattern(const char *pattern, const char *qname) +{ + const char *first_dot_in_qname; + + /* Caller guarantees that inputs are in ASCII form. */ + return (strcasecmp(qname, pattern) == 0 + || (pattern[0] == '*' && pattern[1] == '.' && pattern[2] != 0 + && (first_dot_in_qname = strchr(qname, '.')) != 0 + && first_dot_in_qname > qname + && strcasecmp(first_dot_in_qname + 1, pattern + 2) == 0)); +} + +/* smtp_tls_authorize_mx_hostname - enforce applicable MX hostname policy */ + +int smtp_tls_authorize_mx_hostname(SMTP_TLS_POLICY *tls, const char *name) +{ + +#define SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls) (var_smtp_tls_enf_sts_mx_pat \ + && (tls)->ext_policy_type != 0 \ + && strcasecmp((tls)->ext_policy_type, "sts") == 0 \ + && (tls)->matchargv != 0 && (tls)->ext_mx_host_patterns != 0) + + /* Enforce STS policy MX patterns. */ + if (SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls)) { + const char *aname; + char **pattp; + +#ifndef NO_EAI + if (!allascii(name) && (aname = midna_domain_to_ascii(name)) != 0) { + if (msg_verbose) + msg_info("%s asciified to %s", name, aname); + } else +#endif + aname = name; + for (pattp = tls->ext_mx_host_patterns->argv; *pattp; pattp++) + if (match_sts_mx_host_pattern(*pattp, aname)) + return (1); + return (0); + } + /* No applicable policy name patterns. */ + return (1); +} + /* smtp_tls_list_init - initialize per-site policy lists */ void smtp_tls_list_init(void) @@ -517,6 +572,10 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level, INVALID_RETURN(tls->why, site_level); } } + if (SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls)) { + argv_truncate(tls->matchargv, 0); + argv_add(tls->matchargv, "hostname", (char *) 0); + } FREE_RETURN; } diff --git a/postfix/src/smtp/smtp_tls_policy_test.c b/postfix/src/smtp/smtp_tls_policy_test.c new file mode 100644 index 000000000..f37ac9875 --- /dev/null +++ b/postfix/src/smtp/smtp_tls_policy_test.c @@ -0,0 +1,503 @@ +/*++ +/* NAME +/* smtp_tls_policy_test 1t +/* SUMMARY +/* smtp_tls_policy unit tests +/* SYNOPSIS +/* ./smtp_tls_policy_test +/* DESCRIPTION +/* smtp_tls_policy_test runs and logs each configured test, reports +/* if a test is a PASS or FAIL, and returns an exit status of zero +/* if all tests are a PASS. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* porcupine.org +/*--*/ + + /* + * System library. + */ +#include +#include + + /* + * Utility library. + */ +#include +#include +#include +#include +#include +#include + +#ifdef USE_TLS + +#define PASS (0) +#define FAIL (1) + + /* + * Global library. + */ +#include + + /* + * TLS library. + */ + + /* + * SMTP client. + */ +#include + + /* + * Surrogate dependencies. Parameters are initialized without $name + * expansion, and can be changed by tests. + */ +char *var_smtp_tls_policy; +char *var_smtp_tls_per_site; +char *var_smtp_tls_ciph; +bool var_smtp_tls_conn_reuse; +bool var_smtp_tls_enable_rpk; +char *var_smtp_tls_level; +int smtp_host_lookup_mask; +int var_smtp_cache_conn; +char *var_smtp_tls_mand_ciph; +char *var_smtp_tls_mand_excl; +char *var_smtp_dns_res_opt; +char *var_smtp_dns_support; +char *var_smtp_tls_insecure_mx_policy; +int var_ign_mx_lookup_err; +bool var_smtp_enforce_tls; +bool var_smtp_tls_enforce_peername; +bool var_smtp_tls_force_tlsa; +char *var_smtp_tls_fpt_cmatch; +char *var_smtp_tls_mand_proto; +char *var_smtp_tls_proto; +char *var_smtp_tls_sec_cmatch; +char *var_smtp_tls_sni; +char *var_smtp_tls_tafile; +char *var_smtp_tls_vfy_cmatch; +bool var_smtp_use_tls; +char *var_smtp_tls_excl_ciph; +bool var_smtp_tls_enf_sts_mx_pat; + + /* + * Other globals. + */ +int smtp_mode; +int smtp_tls_insecure_mx_policy; +unsigned smtp_dns_res_opt; +int smtp_dns_support; +int smtp_host_lookup_mask; + + /* + * Pre-test initializer to make tests independent. + */ +static void test_setup(void) +{ + var_smtp_tls_policy = DEF_SMTP_TLS_POLICY; + var_smtp_tls_per_site = DEF_SMTP_TLS_PER_SITE; + var_smtp_tls_ciph = DEF_SMTP_TLS_CIPH; + var_smtp_tls_conn_reuse = DEF_SMTP_TLS_CONN_REUSE; + var_smtp_tls_enable_rpk = DEF_SMTP_TLS_ENABLE_RPK; + var_smtp_tls_level = "may"; + var_smtp_cache_conn = 2; + var_smtp_tls_mand_ciph = DEF_SMTP_TLS_MAND_CIPH; + var_smtp_tls_mand_excl = DEF_SMTP_TLS_MAND_EXCL; + var_smtp_dns_res_opt = DEF_SMTP_DNS_RES_OPT; + var_smtp_dns_support = DEF_SMTP_DNS_SUPPORT; + var_smtp_tls_insecure_mx_policy = DEF_SMTP_TLS_INSECURE_MX_POLICY; + var_ign_mx_lookup_err = DEF_IGN_MX_LOOKUP_ERR; + var_smtp_enforce_tls = DEF_SMTP_ENFORCE_TLS; + var_smtp_tls_enforce_peername = DEF_SMTP_TLS_ENFORCE_PN; + var_smtp_tls_force_tlsa = DEF_SMTP_TLS_FORCE_TLSA; + var_smtp_tls_fpt_cmatch = DEF_SMTP_TLS_FPT_CMATCH; + var_smtp_tls_mand_proto = DEF_SMTP_TLS_MAND_PROTO; + var_smtp_tls_proto = DEF_SMTP_TLS_PROTO; + var_smtp_tls_sec_cmatch = DEF_SMTP_TLS_SEC_CMATCH; + var_smtp_tls_sni = DEF_SMTP_TLS_SNI; + var_smtp_tls_tafile = DEF_SMTP_TLS_TAFILE; + var_smtp_tls_vfy_cmatch = DEF_SMTP_TLS_VFY_CMATCH; + var_smtp_use_tls = DEF_SMTP_USE_TLS; + var_smtp_tls_excl_ciph = DEF_SMTP_TLS_EXCL_CIPH; + var_smtp_tls_enf_sts_mx_pat = 1; + + smtp_mode = 1; + + smtp_tls_policy_cache_flush(); +} + + /* + * Post-test finalizer to help memory leak tests. + */ +static void test_teardown(void) +{ + smtp_tls_policy_cache_flush(); +} + + /* + * Test helpers. TODO(wietse) adopt PTEST which does a nicer job. + */ +static int match_int(const char *what, int want, int got) +{ + if (want != got) { + msg_warn("%s: got %d, want %d", what, got, want); + return (0); + } + return (1); +} + +#define STR_OR_NULL(s) ((s)? (s) : "NULL") + +static int match_cstr(const char *what, const char *want, const char *got) +{ + if (!want != !got) { + msg_warn("%s: got '%s', want '%s'", what, STR_OR_NULL(got), + STR_OR_NULL(want)); + return (0); + } + if (want != 0 && strcmp(got, want) != 0) { + msg_warn("%s: got '%s', want '%s'", what, got, want); + return (0); + } + return (1); +} + +#define WANT_ARGV_MAX 5 + +struct WANT_ARGV { + ssize_t argc; + char *argv[WANT_ARGV_MAX]; +}; + +#define ARGV_OR_NULL(a) ((a)? ("argv") : "NULL") + +static int match_argv(const char *what, const struct WANT_ARGV * want, + const ARGV *got) +{ + if (!want != !got) { + msg_warn("%s: got '%s', want '%s'", what, ARGV_OR_NULL(got), + ARGV_OR_NULL(want)); + return (0); + } + if (match_int("argc", want->argc, got->argc) == 0) { + return (0); + } else { + VSTRING *buf; + int idx; + int equal; + + buf = vstring_alloc(100); + for (equal = 1, idx = 0; idx < want->argc; idx++) { + vstring_sprintf(buf, "%s->argv[%d]", what, idx); + if (match_cstr(STR(buf), want->argv[idx], got->argv[idx]) == 0) + equal = 0; + } + vstring_free(buf); + return (equal); + } +} + + /* + * Limited policy for STS tests. + */ +struct WANT_SMTP_TLS_POLICY { + int level; /* TLS enforcement level */ +#if 0 + char *protocols; /* Acceptable SSL protocols */ + char *grade; /* Cipher grade: "export", ... */ + VSTRING *exclusions; /* Excluded SSL ciphers */ + char *protocols; /* Acceptable SSL protocols */ + char *grade; /* Cipher grade: "export", ... */ + VSTRING *exclusions; /* Excluded SSL ciphers */ +#endif + struct WANT_ARGV matchargv; /* Cert match patterns */ +#if 0 + DSN_BUF *why; /* Lookup error status */ + TLS_DANE *dane; /* DANE TLSA digests */ +#endif + char *sni; /* Optional SNI name when not DANE */ +#if 0 + int conn_reuse; /* enable connection reuse */ + int enable_rpk; /* Enable server->client RPK */ +#endif + int ext_policy_ttl; /* TTL from DNS etc. */ + char *ext_policy_type; /* (sts) */ + struct WANT_ARGV ext_policy_strings;/* policy strings from DNS etc. */ + char *ext_policy_domain; /* policy scope */ + struct WANT_ARGV ext_mx_host_patterns; /* (sts) MX host patterns */ + char *ext_policy_failure; /* (sts) policy failure */ +}; + +#define POLICY_OR_NULL(p) ((p)? ("policy") : "NULL") + +static int match_smtp_tls_policy(const char *what, + const struct WANT_SMTP_TLS_POLICY * want, + const SMTP_TLS_POLICY *got) +{ + int equal = 1; + + if (!want != !got) { + msg_warn("%s: got '%s', want '%s'", what, POLICY_OR_NULL(got), + POLICY_OR_NULL(want)); + return (0); + } + if (match_int("level", want->level, got->level) == 0) { + msg_warn("%s->level mismatch", what); + equal = 0; + } + if (match_argv("matchargv", &want->matchargv, got->matchargv) == 0) { + msg_warn("%s->matchargv mismatch", what); + equal = 0; + } + if (match_cstr("sni", want->sni, got->sni) == 0) { + msg_warn("%s->sni mismatch", what); + equal = 0; + } + if (match_int("ext_policy_ttl", want->ext_policy_ttl, got->ext_policy_ttl) == 0) { + msg_warn("%s->ext_policy_ttl mismatch", what); + equal = 0; + } + if (match_cstr("ext_policy_type", want->ext_policy_type, + got->ext_policy_type) == 0) { + msg_warn("%s->ext_policy_type mismatch", what); + equal = 0; + } + if (match_argv("ext_policy_strings", &want->ext_policy_strings, + got->ext_policy_strings) == 0) { + msg_warn("%s->ext_policy_strings mismatch", what); + equal = 0; + } + if (match_cstr("ext_policy_domain", want->ext_policy_domain, + got->ext_policy_domain) == 0) { + msg_warn("%s->ext_policy_domain mismatch", what); + equal = 0; + } + if (match_argv("ext_mx_host_patterns", &want->ext_mx_host_patterns, + got->ext_mx_host_patterns) == 0) { + msg_warn("%s->ext_mx_host_patterns mismatch", what); + equal = 0; + } + if (match_cstr("ext_policy_failure", want->ext_policy_failure, + got->ext_policy_failure) == 0) { + msg_warn("%s->ext_policy_failure mismatch", what); + equal = 0; + } + return (equal); +} + + /* + * Test structure. Some tests may bring their own. + */ +typedef struct TEST_CASE { + const char *label; + int (*action) (const struct TEST_CASE *); +} TEST_CASE; + + /* + * Verify that policies from an STS plugin are converted into Postfix TLS + * policies that match a certificate against the server hostname, and that + * other policy attributes are stored appropriately. A later test will + * verify that MX hostnames are matched against the STS policy MX hostname + * patterns. + */ +static int sts_policy_smoke_test(const struct TEST_CASE *tp) +{ + var_smtp_tls_policy = + "static:{secure match=example:.example " + "servername=example policy_ttl=123 " + "policy_type=sts policy_string=one " + "policy_string=two policy_domain=example " + "mx_host_pattern=example mx_host_pattern=*.example}"; + static const struct WANT_SMTP_TLS_POLICY want_policy = { + .level = TLS_LEV_SECURE, + .matchargv = {.argc = 1,.argv = {"hostname"}}, + .sni = "example", + .ext_policy_ttl = 123, + .ext_policy_type = "sts", + .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}}, + .ext_policy_domain = "example", + .ext_mx_host_patterns = {.argc = 2,.argv = {"example", "*.example"}} + }; + SMTP_STATE *state = smtp_state_alloc(); + const char *domain = "example"; + const char *host = "mail.example"; + const char *addr = "10.0.1.1"; + int port = 25; + int match; + + var_smtp_tls_enf_sts_mx_pat = 1; + var_smtp_tls_level = "secure"; + smtp_tls_list_init(); + SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state); + if ((match = smtp_tls_policy_cache_query(state->why, state->tls, + state->iterator)) == 0) { + msg_warn("smtp_tls_policy_cache_query failed: %s", + STR(state->why->reason)); + } else { + match = match_smtp_tls_policy("policy", &want_policy, state->tls); + } + smtp_state_free(state); + smtp_tls_policy_cache_flush(); + return (match ? PASS : FAIL); +} + + /* + * Verify that the historical support for policies from STS plugins is still + * available. STS plugins generate a policy that will match a certificate + * against all MX patterns, after converting a pattern "*.domain" to + * ".domain", and do not constrain the allowed MX hostnames. + */ +static int obs_sts_policy_smoke_test(const struct TEST_CASE *tp) +{ + var_smtp_tls_policy = + "static:{secure match=example:.example " + "servername=example policy_ttl=123 " + "policy_type=sts policy_string=one " + "policy_string=two policy_domain=example " + "mx_host_pattern=example mx_host_pattern=*.example}"; + static const struct WANT_SMTP_TLS_POLICY want_policy = { + .level = TLS_LEV_SECURE, + .matchargv = {.argc = 2,.argv = {"example", ".example"}}, + .sni = "example", + .ext_policy_ttl = 123, + .ext_policy_type = "sts", + .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}}, + .ext_policy_domain = "example", + .ext_mx_host_patterns = {.argc = 2,.argv = {"example", "*.example"}} + }; + SMTP_STATE *state = smtp_state_alloc(); + const char *domain = "example"; + const char *host = "mail.example"; + const char *addr = "10.0.1.1"; + int port = 25; + int match; + + var_smtp_tls_enf_sts_mx_pat = 0; + var_smtp_tls_level = "secure"; + smtp_tls_list_init(); + SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state); + if ((match = smtp_tls_policy_cache_query(state->why, state->tls, + state->iterator)) == 0) { + msg_warn("smtp_tls_policy_cache_query failed: %s", + STR(state->why->reason)); + } else { + match = match_smtp_tls_policy("policy", &want_policy, state->tls); + } + smtp_state_free(state); + smtp_tls_policy_cache_flush(); + return (match ? PASS : FAIL); +} + + /* + * Test the MX host authorization constraints. + */ +static int test_hostname_authorization(const struct TEST_CASE *tp) +{ + var_smtp_tls_policy = + "static:{secure match=example.com:.example.com " + "servername=example.com policy_ttl=123 " + "policy_type=sts policy_string=one " + "policy_string=two policy_domain=example.com " + "mx_host_pattern=example.com mx_host_pattern=*.example.com}"; + static const struct WANT_SMTP_TLS_POLICY want_policy = { + .level = TLS_LEV_SECURE, + .matchargv = {.argc = 1,.argv = {"hostname"}}, + .sni = "example.com", + .ext_policy_ttl = 123, + .ext_policy_type = "sts", + .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}}, + .ext_policy_domain = "example.com", + .ext_mx_host_patterns = {.argc = 2,.argv = {"example.com", "*.example.com"}} + }; + SMTP_STATE *state = smtp_state_alloc(); + const char *domain = "example.com"; + const char *host = "mail.example.com"; + const char *addr = "10.0.1.1"; + int port = 25; + int match; + static const char *permit_domains[] = { + "example.com", "mail.example.com", 0, + }; + static const char *reject_domains[] = { + ".example.com", "foo.bar.example.com", 0, + }; + const char *const * cpp; + + var_smtp_tls_enf_sts_mx_pat = 1; + var_smtp_tls_level = "secure"; + smtp_tls_list_init(); + SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state); + if ((match = smtp_tls_policy_cache_query(state->why, state->tls, + state->iterator)) == 0) { + msg_warn("smtp_tls_policy_cache_query failed: %s", + STR(state->why->reason)); + } else { + match = match_smtp_tls_policy("policy", &want_policy, state->tls); + } + if (match == 0) + return (FAIL); + + /* Verify that 'good' MX host names are authorized. */ + for (cpp = permit_domains; *cpp; cpp++) { + if (!smtp_tls_authorize_mx_hostname(state->tls, *cpp)) { + msg_warn("hostname '%s' is not authorized", *cpp); + match = 0; + } + } + /* Verify that 'wrong' MX host names are not authorized. */ + for (cpp = reject_domains; *cpp; cpp++) { + if (smtp_tls_authorize_mx_hostname(state->tls, *cpp)) { + msg_warn("hostname '%s' is authorized", *cpp); + match = 0; + } + } + + smtp_state_free(state); + smtp_tls_policy_cache_flush(); + return (match ? PASS : FAIL); +} + +static const struct TEST_CASE test_cases[] = { + {"sts_policy_smoke_test", sts_policy_smoke_test,}, + {"obs_sts_policy_smoke_test", obs_sts_policy_smoke_test,}, + {"test_hostname_authorization", test_hostname_authorization}, + {0}, +}; + +int main(int argc, char **argv) +{ + static int tests_passed = 0; + static int tests_failed = 0; + const struct TEST_CASE *tp; + + msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR); + + for (tp = test_cases; tp->label; tp++) { + msg_info("RUN %s", tp->label); + test_setup(); + if (tp->action(tp) == PASS) { + msg_info("PASS %s", tp->label); + tests_passed += 1; + } else { + msg_info("FAIL %s", tp->label); + tests_failed += 1; + } + test_teardown(); + } + msg_info("PASS=%d FAIL=%d", tests_passed, tests_failed); + exit(tests_failed != 0); +} + +#else + +int main(int argc, char **argv) +{ + msg_fatal("this program requires `#define USE_TLS'"); +} + +#endif