From: Wietse Z Venema Date: Sun, 26 Oct 2025 05:00:00 +0000 (-0500) Subject: postfix-3.10.5 X-Git-Tag: v3.10.5^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd1838382c602676bcaa2de2661b2017051e2765;p=thirdparty%2Fpostfix.git postfix-3.10.5 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 78726ec06..cf1c78f50 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -29122,3 +29122,89 @@ Apologies for any names omitted. messages that contain a "TLS-Required: no" header. This can prevent TLSRPT notifications for TLSRPT notifications. Files: smtp/smtp_connect.c, smtp_tls_policy.c. + +20250816 + + Bugfix (defect introduced: Postfix 3.0, date 20140731): the + smtpd 'disconnect' command counts did not count malformed + commands with "bad syntax" and "bad UTF-8 syntax" errors. + File: smtpd/smtpd.c. + +20250819 + + Bugfix: the 20250717 workaround broke DBM library support + which is still needed on Solaris. File: util/dict_dbm.c. + +20250823 + + Bugfix (defect introduced: Postfix 3.9, date 20230517): + posttls-finger logged a zero port number. Viktor Dukhovni. + File: posttls-finger/posttls-finger.c. + +20250829 + + Postfix 3.11 forward compatibility: allow a partial 'size' + record in maildrop queue files created with Postfix 3.11 + or later, instead of logging an ugly warning. Files: + showq/showq.c, postcat/postcat.c. + +20250906 + + Workaround for an interface mis-match between the Postfix + SMTP client and MTA-STS policy plugins. This introduces a + new parameter "smtp_tls_enforce_sts_mx_patterns" (default: + "yes"). The MTA-STS plugin configuration needs to enable + TLSRPT support, so that it forwards STS policy attributes + to Postfix. This works even if Postfix TLSRPT support is + disabled at build time or at runtime. + + With the above two configurations, the Postfix SMTP client + will connect to an MX host only if its name matches any STS + policy MX host pattern, and will match a server certificate + against the MX hostname. Otherwise, the old behavior stays + in effect: connect to any MX host listed in DNS, and match + a server certificate against any STS policy MX host pattern. + 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. + +20250911 + + Bugfix (defect introduced: Postfix 3.0): the Postfix SMTP + client's connection reuse logic did not distinguish between + sessions that require SMTPUTF8 support, and sessions that + do not. The solution is to store sessions with different + SMTPUTF8 requirements under distinct connection cache storage + keys, and to preserve the availability of SMTPUTF8 support + in the connection cache, so that a reused connection will + be stored under the same keys as it was looked up with. + Finally, do not cache a connection when SMTPUTF8 is + required but the server does not support that feature. + Files: smtp/smtp.h, smtp/smtp_key.c, smtp/smtp_proto.c. + +20250919 + + Bugfix (defect introduced: Postfix 3.8, date 20220128): the + 'postconf -e' output order for new main.cf entries was no + longer deterministic. Problem reported by Oleksandr Natalenko, + diagnosis by Eray Aslan. File: postconf/postconf_edit.c. + + Add missing meta_directory and shlib_directory settings to + the stock main.cf file. Problem diagnosed by Eray Aslan. + File: conf/main.cf. + +20240924 + + TLSRPT Workaround: when policies[*].policy.policy-type is + "no-policy-found", report the TLSRPT policy domain name as + the policies[*].policy.policy-domain value. This ignores + that TLSA policies must be reported with different policy-domain + values than STS policies. File: tls/tlsrpt_wrapper.c. + +20251021 + + Cleanup: the change at 20250717 could result in warnings + with "database X is older than source file Y". Files: + util/dict.c, util/dict_db.c, util/dict_dbm.c, util/dict_lmdb.c, + util/dict_sdbm.c. diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index 1d2c8c21a..3687c8583 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -683,3 +683,5 @@ sample_directory = # readme_directory = inet_protocols = ipv4 +shlib_directory = /usr/lib/postfix/${mail_version} +meta_directory = /etc/postfix diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index f5a3945b6..8d2416cd0 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -766,6 +766,13 @@ SMTP(8) SMTP(8) Enable support for the "TLS-Required: no" message header, defined in RFC 8689. + 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 any STS policy MX host pat- + tern, and match the server certificate against the MX hostname. + OBSOLETE STARTTLS CONTROLS The following configuration parameters exist for compatibility with Postfix versions before 2.3. Support for these will be removed in a diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 4bb3b351c..0f9034a37 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -13500,6 +13500,27 @@ 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 any STS policy MX host pattern, +and match the server certificate against the MX hostname. This +setting takes effect only when an STS policy plugin has TLSRPT +support enabled, so that it forwards STS policy attributes to +Postfix. This works even if Postfix TLSRPT support is disabled at +build time or at runtime.

+ +

Without the above configuration settings for Postfix and STS +plugins, the old behavior stays in effect: connect to any MX host +listed in DNS, and match a server certificate against any STS policy +MX host pattern.

+ +

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 f5a3945b6..8d2416cd0 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -766,6 +766,13 @@ SMTP(8) SMTP(8) Enable support for the "TLS-Required: no" message header, defined in RFC 8689. + 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 any STS policy MX host pat- + tern, and match the server certificate against the MX hostname. + OBSOLETE STARTTLS CONTROLS The following configuration parameters exist for compatibility with Postfix versions before 2.3. Support for these will be removed in a diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 207b99fad..2bc52fc7a 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -8664,6 +8664,21 @@ 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 any STS policy MX host pattern, +and match the server certificate against the MX hostname. This +setting takes effect only when an STS policy plugin has TLSRPT +support enabled, so that it forwards STS policy attributes to +Postfix. This works even if Postfix TLSRPT support is disabled at +build time or at runtime. +.PP +Without the above configuration settings for Postfix and STS +plugins, the old behavior stays in effect: connect to any MX host +listed in DNS, and match a server certificate against any STS policy +MX host pattern. +.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 a6a56a53d..abdd8012d 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -688,6 +688,13 @@ information to report). .IP "\fBtls_required_enable (yes)\fR" Enable support for the "TLS\-Required: no" message header, defined in RFC 8689. +.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 any STS policy MX host pattern, +and match the server certificate against the MX hostname. +.PP .SH "OBSOLETE STARTTLS CONTROLS" .na .nf diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index b06c2d00f..2a2cb713a 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -728,6 +728,7 @@ while (<>) { s;\blmtp_tlsrpt_enable\b;$&;g; s;\blmtp_tlsrpt_socket_name\b;$&;g; s;\blmtp_tlsrpt_skip_reused_handshakes\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 f754c961c..fd90e34de 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -19496,6 +19496,23 @@ second etc. TLS handshake to report.

This feature is available in Postfix ≥ 3.10.

+%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 any STS policy MX host pattern, +and match the server certificate against the MX hostname. This +setting takes effect only when an STS policy plugin has TLSRPT +support enabled, so that it forwards STS policy attributes to +Postfix. This works even if Postfix TLSRPT support is disabled at +build time or at runtime.

+ +

Without the above configuration settings for Postfix and STS +plugins, the old behavior stays in effect: connect to any MX host +listed in DNS, and match a server certificate against any STS policy +MX host pattern.

+ +

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/src/global/mail_params.h b/postfix/src/global/mail_params.h index 375a35ead..799c61ee6 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -4492,6 +4492,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 9770f7448..3c53b1325 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,8 +20,8 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20250818" -#define MAIL_VERSION_NUMBER "3.10.4" +#define MAIL_RELEASE_DATE "20251026" +#define MAIL_VERSION_NUMBER "3.10.5" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff --git a/postfix/src/postcat/postcat.c b/postfix/src/postcat/postcat.c index 44c0ce6ba..91cdec1e1 100644 --- a/postfix/src/postcat/postcat.c +++ b/postfix/src/postcat/postcat.c @@ -348,6 +348,10 @@ static void postcat(VSTREAM *fp, VSTRING *buffer, int flags) /* Optional output (here before we update the state machine). */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); + /* Postfix 3.11 maildrop files may have preliminary SIZE record. */ + if (strncmp(VSTREAM_PATH(fp), MAIL_QUEUE_MAILDROP "/", + sizeof(MAIL_QUEUE_MAILDROP)) == 0) + continue; /* Read the message size/offset for the state machine optimizer. */ if (data_size >= 0 || data_offset >= 0) { msg_warn("file contains multiple size records"); diff --git a/postfix/src/postconf/postconf_edit.c b/postfix/src/postconf/postconf_edit.c index 437f2a870..642965817 100644 --- a/postfix/src/postconf/postconf_edit.c +++ b/postfix/src/postconf/postconf_edit.c @@ -66,6 +66,7 @@ /* System library. */ #include +#include #include #include @@ -148,6 +149,16 @@ static void pcf_gobble_cf_line(VSTRING *full_entry_buf, VSTRING *line_buf, } } +/* pcf_cmp_ht_key - qsort helper for ht_info pointer array */ + +static int pcf_cmp_ht_key(const void *a, const void *b) +{ + HTABLE_INFO **ap = (HTABLE_INFO **) a; + HTABLE_INFO **bp = (HTABLE_INFO **) b; + + return (strcmp(ap[0]->key, bp[0]->key)); +} + /* pcf_edit_main - edit main.cf file */ void pcf_edit_main(int mode, int argc, char **argv) @@ -262,7 +273,9 @@ void pcf_edit_main(int mode, int argc, char **argv) * Generate new entries for parameters that were not found. */ if (mode & PCF_EDIT_CONF) { - for (ht_info = ht = htable_list(table); *ht; ht++) { + ht_info = htable_list(table); + qsort((void *) ht_info, table->used, sizeof(*ht_info), pcf_cmp_ht_key); + for (ht = ht_info; *ht; ht++) { cvalue = (struct cvalue *) ht[0]->value; if (cvalue->found == 0) vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value); diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index baa5ca81b..38c2eae31 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -1651,7 +1651,7 @@ static void connect_remote(STATE *state, char *dest) if (level == TLS_LEV_INVALID || (state->stream = connect_addr(state, addr)) == 0) { msg_info("Failed to establish session to %s via %s:%u: %s", - dest, HNAME(addr), addr->port, + dest, HNAME(addr), ntohs(state->port), vstring_str(state->why->reason)); continue; } diff --git a/postfix/src/showq/showq.c b/postfix/src/showq/showq.c index 80e1e89e2..043c7ea7b 100644 --- a/postfix/src/showq/showq.c +++ b/postfix/src/showq/showq.c @@ -213,7 +213,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id, arrival_time = atol(start); break; case REC_TYPE_SIZE: - if (msg_size_ok == 0) { + /* Postfix 3.11 maildrop files may have preliminary SIZE record. */ + if (msg_size_ok == 0 && strcmp(queue, MAIL_QUEUE_MAILDROP) != 0) { msg_size_ok = (start[strspn(start, "0123456789 ")] == 0 && (msg_size = atol(start)) >= 0); if (msg_size_ok == 0) { diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index f8cde6978..e6269a589 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -307,6 +307,7 @@ smtp_key.o: ../../include/recipient_list.h smtp_key.o: ../../include/resolve_clnt.h smtp_key.o: ../../include/scache.h smtp_key.o: ../../include/sendopts.h +smtp_key.o: ../../include/smtputf8.h smtp_key.o: ../../include/sock_addr.h smtp_key.o: ../../include/string_list.h smtp_key.o: ../../include/sys_defs.h @@ -777,6 +778,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 diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index b77500326..b3d456a92 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -140,5 +140,8 @@ 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, +#ifdef USE_TLS + VAR_LMTP_TLS_ENF_STS_MX_PAT, DEF_LMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat, +#endif 0, }; diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index e92696c75..8116fe708 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -654,6 +654,13 @@ /* .IP "\fBtls_required_enable (yes)\fR" /* Enable support for the "TLS-Required: no" message header, defined /* in RFC 8689. +/* .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 any STS policy MX host pattern, +/* and match the server certificate against the MX hostname. +/* .PP /* OBSOLETE STARTTLS CONTROLS /* .ad /* .fi @@ -1133,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 af118926d..2f6190029 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 @@ -691,12 +692,14 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); #define SMTP_KEY_FLAG_ADDR (1<<5) /* remote address */ #define SMTP_KEY_FLAG_PORT (1<<6) /* remote port */ #define SMTP_KEY_FLAG_TLS_LEVEL (1<<7) /* requested TLS level */ +#define SMTP_KEY_FLAG_REQ_SMTPUTF8 (1<<8) /* SMTPUTF8 is required */ #define SMTP_KEY_MASK_ALL \ (SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \ SMTP_KEY_FLAG_REQ_NEXTHOP | \ SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \ - SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) + SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL | \ + SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Conditional lookup-key flags for cached connections that may be @@ -735,7 +738,8 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); */ #define SMTP_KEY_MASK_SCACHE_DEST_LABEL \ (SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \ - | SMTP_KEY_FLAG_REQ_NEXTHOP | SMTP_KEY_FLAG_TLS_LEVEL) + | SMTP_KEY_FLAG_REQ_NEXTHOP | SMTP_KEY_FLAG_TLS_LEVEL \ + | SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Connection-cache endpoint lookup key. The SENDER, CUR_NEXTHOP, HOSTNAME, @@ -750,7 +754,8 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); | COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \ | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \ | COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_ADDR | \ - SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) + SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL \ + | SMTP_KEY_FLAG_REQ_SMTPUTF8) /* * Silly little macros. diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 38e28b767..d2883341b 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, SMTP_HNAME(addr))) { + 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_key.c b/postfix/src/smtp/smtp_key.c index 643f4db7e..66126c70c 100644 --- a/postfix/src/smtp/smtp_key.c +++ b/postfix/src/smtp/smtp_key.c @@ -65,6 +65,10 @@ /* The current iterator's remote address. /* .IP SMTP_KEY_FLAG_PORT /* The current iterator's remote port. +/* .IP SMTP_KEY_FLAG_TLS_LEVEL +/* The requested TLS security level. +/* .IP SMTP_KEY_FLAG_REQ_SMTPUTF8 +/* Whether SMTPUTF8 support is required. /* .RE /* DIAGNOSTICS /* Panic: undefined flag or zero flags. Fatal: out of memory. @@ -103,12 +107,18 @@ * Global library. */ #include +#include /* * Application-specific. */ #include + /* Duplicated to minimze patch footprint. */ +#define DELIVERY_REQUIRES_SMTPUTF8(request) \ + (((request)->sendopts & SMTPUTF8_FLAG_REQUESTED) \ + && ((request)->sendopts & SMTPUTF8_FLAG_DERIVED)) + /* * We use a configurable field terminator and optional place holder for data * that is unavailable or inapplicable. We base64-encode content that @@ -209,6 +219,20 @@ char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, smtp_key_append_na(buffer, delim_na); #endif + /* + * Require SMTPUTF8 support, if applicable. TODO(wietse) if a delivery + * request does not need SMTPUTF8, should we also search the connection + * cache for a connection that is known to support it? No, because the + * connection would be saved back under a key that does not require + * SMTPUTF8 support. + */ + if (flags & SMTP_KEY_FLAG_REQ_SMTPUTF8) + smtp_key_append_uint(buffer, + DELIVERY_REQUIRES_SMTPUTF8(state->request), + delim_na); + else + smtp_key_append_na(buffer, delim_na); + VSTRING_TERMINATE(buffer); return STR(buffer); diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index 6d80ef105..64128b728 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -144,5 +144,8 @@ 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, +#ifdef USE_TLS + VAR_SMTP_TLS_ENF_STS_MX_PAT, DEF_SMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat, +#endif 0, }; diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index b89686378..2563e4ce5 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -658,14 +658,19 @@ int smtp_helo(SMTP_STATE *state) * SMTPUTF8. * * Fix 20140706: moved this before negotiating TLS, AUTH, and so on. + * + * Fix 20250911: do not cache this session because it does not satisfy the + * requirement expressed in the cache storage key. */ if ((session->features & SMTP_FEATURE_SMTPUTF8) == 0 - && DELIVERY_REQUIRES_SMTPUTF8) + && DELIVERY_REQUIRES_SMTPUTF8) { + DONT_CACHE_THIS_SESSION; return (smtp_mesg_fail(state, DSN_BY_LOCAL_MTA, SMTP_RESP_FAKE(&fake, "5.6.7"), "SMTPUTF8 is required, " "but was not offered by host %s", session->namaddr)); + } /* * Fix 20140706: don't do silly things when the remote server announces diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c index 809ffea05..3619843d7 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. @@ -31,6 +35,11 @@ /* When any required table or DNS lookups fail, the TLS level /* is set to TLS_LEV_INVALID, the "why" argument is updated /* with the error reason and the result value is zero (false). +/* When var_smtp_tls_enf_sts_mx_pat is not null, and a policy plugin +/* specifies a policy_type "sts" plus one or more mx_host_pattern +/* instances, transform the policy as follows: allow only MX hosts +/* that an match mx_host_pattern instance, and match a server +/* certificate against the server hostname. /* /* smtp_tls_policy_dummy() initializes a trivial, non-cached, /* policy with TLS disabled. @@ -38,6 +47,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 +121,7 @@ #include #include #include +#include /* Global library. */ @@ -136,6 +151,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 +577,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/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 9c11b18ca..9fef84367 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -5632,6 +5632,13 @@ static SMTPD_CMD smtpd_cmd_table[] = { {0,}, }; + /* + * In addition to counting unknown commands, the last table element also + * counts malformed commands (which aren't looked up in the command table). + */ +#define LAST_TABLE_PTR(table) ((table) + sizeof(table)/sizeof(*(table)) - 1) +static SMTPD_CMD *smtpd_cmdp_unknown = LAST_TABLE_PTR(smtpd_cmd_table); + static STRING_LIST *smtpd_noop_cmds; static STRING_LIST *smtpd_forbid_cmds; @@ -6000,6 +6007,8 @@ static void smtpd_proto(SMTPD_STATE *state) state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "500 5.5.2 Error: bad UTF-8 syntax"); state->error_count++; + state->where = SMTPD_CMD_UNKNOWN; + smtpd_cmdp_unknown->total_count += 1; continue; } /* Move into smtpd_chat_query() and update session transcript. */ @@ -6021,6 +6030,8 @@ static void smtpd_proto(SMTPD_STATE *state) state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "500 5.5.2 Error: bad syntax"); state->error_count++; + state->where = SMTPD_CMD_UNKNOWN; + smtpd_cmdp_unknown->total_count += 1; continue; } /* Ignore smtpd_noop_cmds lookup errors. Non-critical feature. */ @@ -6029,6 +6040,7 @@ static void smtpd_proto(SMTPD_STATE *state) smtpd_chat_reply(state, "250 2.0.0 Ok"); if (state->junk_cmds++ > var_smtpd_junk_cmd_limit) state->error_count++; + /* XXX We can't count these. */ continue; } for (cmdp = smtpd_cmd_table; cmdp->name != 0; cmdp++) diff --git a/postfix/src/tls/tlsrpt_wrapper.c b/postfix/src/tls/tlsrpt_wrapper.c index 99f6f0489..3feca68bf 100644 --- a/postfix/src/tls/tlsrpt_wrapper.c +++ b/postfix/src/tls/tlsrpt_wrapper.c @@ -161,7 +161,8 @@ /* policies[].policy.policy-string[]. Ignored if the tls_policy_type /* value is TLSRPT_NO_POLICY_FOUND. /* .IP tls_policy_domain (may be null) -/* policies[].policy.policy-domain. +/* policies[].policy.policy-domain. If null, this defaults to the +/* TLSRPT policy domain. /* .IP mx_host_patterns (may be null) /* policies[].policy.mx-host[]. Ignored if the tls_policy_type /* value is TLSRPT_NO_POLICY_FOUND. @@ -403,10 +404,12 @@ void trw_set_tls_policy(TLSRPT_WRAPPER *trw, PSTR_OR_NULL(mx_host_patterns)); trw->tls_policy_type = tls_policy_type; + if (tls_policy_domain == 0) + tls_policy_domain = trw->rpt_policy_domain; MYFREE_IF_SET_AND_COPY(trw->tls_policy_domain, tls_policy_domain); if (tls_policy_type == TLSRPT_NO_POLICY_FOUND) { ARGV_FREE_IF_SET_AND_CLEAR(trw->tls_policy_strings); - ARGV_FREE_IF_SET_AND_CLEAR(trw->tls_policy_strings); + ARGV_FREE_IF_SET_AND_CLEAR(trw->mx_host_patterns); } else { ARGV_FREE_IF_SET_AND_COPY(trw->tls_policy_strings, tls_policy_strings); ARGV_FREE_IF_SET_AND_COPY(trw->mx_host_patterns, mx_host_patterns); diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index 0a760c6b9..053db3c1e 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -799,6 +799,7 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_db->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff --git a/postfix/src/util/dict_dbm.c b/postfix/src/util/dict_dbm.c index b3bbe8510..45fa71295 100644 --- a/postfix/src/util/dict_dbm.c +++ b/postfix/src/util/dict_dbm.c @@ -472,7 +472,7 @@ DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) msg_fatal("open database %s: cannot support GDBM", path); if (fstat(dict_dbm->dict.stat_fd, &st) < 0) msg_fatal("dict_dbm_open: fstat: %m"); - if (open_mode == O_RDONLY) + if (open_flags == O_RDONLY) dict_dbm->dict.mtime = st.st_mtime; dict_dbm->dict.owner.uid = st.st_uid; dict_dbm->dict.owner.status = (st.st_uid != 0); @@ -482,6 +482,7 @@ DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_dbm->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff --git a/postfix/src/util/dict_lmdb.c b/postfix/src/util/dict_lmdb.c index 6f4f276ca..f672e1c05 100644 --- a/postfix/src/util/dict_lmdb.c +++ b/postfix/src/util/dict_lmdb.c @@ -666,6 +666,7 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags) * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_lmdb->dict.mtime && st.st_mtime < time((time_t *) 0) - 100) diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c index fcb2556e8..6cba5a2ec 100644 --- a/postfix/src/util/dict_sdbm.c +++ b/postfix/src/util/dict_sdbm.c @@ -459,6 +459,7 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) * the source file changed only seconds ago. */ if ((dict_flags & DICT_FLAG_LOCK) != 0 + && open_flags == O_RDONLY && stat(path, &st) == 0 && st.st_mtime > dict_sdbm->dict.mtime && st.st_mtime < time((time_t *) 0) - 100)