From 03efe71c9a6e3a0bbd34be36782c513a912f302e Mon Sep 17 00:00:00 2001 From: Wietse Z Venema Date: Mon, 18 Aug 2025 00:00:00 -0500 Subject: [PATCH] postfix-3.10.4 --- postfix/HISTORY | 68 +++++++++++++++++++++ postfix/src/global/mail_params.h | 8 ++- postfix/src/global/mail_version.h | 4 +- postfix/src/master/event_server.c | 20 ++++++ postfix/src/master/multi_server.c | 20 ++++++ postfix/src/postscreen/postscreen.c | 2 +- postfix/src/posttls-finger/posttls-finger.c | 1 - postfix/src/smtp/Makefile.in | 16 +++++ postfix/src/smtp/smtp.h | 17 +++--- postfix/src/smtp/smtp_connect.c | 24 ++------ postfix/src/smtp/smtp_tls_policy.c | 9 ++- postfix/src/tls/tls_client.c | 10 ++- postfix/src/tls/tls_verify.c | 28 ++++++--- postfix/src/tlsproxy/tlsproxy.c | 20 ++++-- postfix/src/tlsproxy/tlsproxy_state.c | 2 +- postfix/src/util/dict.c | 9 +-- postfix/src/util/dict_db.c | 3 +- postfix/src/util/dict_dbm.c | 3 +- postfix/src/util/dict_lmdb.c | 3 +- postfix/src/util/dict_sdbm.c | 3 +- 20 files changed, 212 insertions(+), 58 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 6206bed16..78726ec06 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -29054,3 +29054,71 @@ Apologies for any names omitted. with "TLS-Required: no". This could result in unnecessary failures. Fix by Viktor Dukhovni & Wietse. Files: smtp/smtp.h, smtp/smtp_policy.c, smtp/smtp_connect.c. + +20250710 + + Bugfix (defect introduced: postfix-2.2, date 20050203): + after detecting a lookup table change, and after starting + a new postscreen process, the old postscreen process logged + an ENOTSOCK error while attempting to accept a connection + on a socket that it was no longer listening on. This error + was introduced first in the multi_server skeleton code, and + was five years later duplicated in the event_server skeleton + that was created for postscreen. Problem reported by Florian + Piekert. Files: master/multi_server.c, master/event_server.c. + +20250714 + + Deleted an dependency, because the feature is + being removed from OpenSSL, and Postfix no longer needs it. File: + posttls-finger/posttls-finger.c. + +20250716 + + Bugfix (defect introduced: Postfix 2.8, date 20101230): + after detecting a cache table change and before starting a + new postscreen process, the old postscreen process did not + close the postscreen_cache_map, and therefore kept an + exclusive lock that could prevent a new postscreen process + from starting. Problem reported by Florian Piekert. File: + postscreen/postscreen.c. + +20250717 + + Workaround: Postfix daemons no longer automatically restart + after a btree:, dbm:, hash:, lmdb:, or sdbm: table file + modification time change, when they opened that table for + writing. Files: util/dict.c, util/dict_db.c, util/dict_dbm.c, + util/dict_lmdb.c, util/dict_sdbm.c. + +20250730 + + Bugfix (defect introduced: Postfix 3.6, date 20200710): + Postfix TLS client code logged "Untrusted TLS connection" + (wrong) instead of "Trusted TLS connection" (right), for a + new or resumed TLS session, when a server offered a trusted + (valid PKI trust chain) certificate that did not match the + expected server name pattern. Viktor Dukhovni. Files: + tls/tls_client.c, tls/tls_verify.c. + +20250801 + + Bugfix (defect introduced: Postfix 3.7): incorrect backwards + compatible support for the legacy configuration parameters + tlsproxy_client_level and tlsproxy_client_policy. This + disabled the tlsproxy TLS client role when a legacy parameter + was set. Reported by John Doe, diagnosed by Viktor Dukhovni. + File: global/mail_params.h. + + Bugfix (defect introduced: Postfix 3.4): with the TLS client + role disabled by configuration, the tlsproxy daemon + dereferenced a null pointer while handling a tlsproxy client + request. Reported by John Doe. File: tlsproxy/tlsproxy.c. + +20250803 + + Cleanup: with "tls_required_enable = yes", the Postfix SMTP + client will no longer maintain TLSRPT statistics for + 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. diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 0aa05ba00..375a35ead 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -4171,7 +4171,9 @@ extern bool var_tlsp_clnt_enforce_tls; /* Migrate an incorrect name. */ #define OBS_TLSP_CLNT_LEVEL "tlsproxy_client_level" #define VAR_TLSP_CLNT_LEVEL "tlsproxy_client_security_level" -#define DEF_TLSP_CLNT_LEVEL "${" OBS_TLSP_CLNT_LEVEL ":$" VAR_SMTP_TLS_LEVEL "}" +#define DEF_TLSP_CLNT_LEVEL "${" OBS_TLSP_CLNT_LEVEL "?{$" \ + OBS_TLSP_CLNT_LEVEL "}:{$" \ + VAR_SMTP_TLS_LEVEL "}}" extern char *var_tlsp_clnt_level; #define VAR_TLSP_CLNT_PER_SITE "tlsproxy_client_per_site" @@ -4181,7 +4183,9 @@ extern char *var_tlsp_clnt_per_site; /* Migrate an incorrect name. */ #define OBS_TLSP_CLNT_POLICY "tlsproxy_client_policy" #define VAR_TLSP_CLNT_POLICY "tlsproxy_client_policy_maps" -#define DEF_TLSP_CLNT_POLICY "${" OBS_TLSP_CLNT_POLICY ":$" VAR_SMTP_TLS_POLICY "}" +#define DEF_TLSP_CLNT_POLICY "${" OBS_TLSP_CLNT_POLICY "?{$" \ + OBS_TLSP_CLNT_POLICY "}:{$" \ + VAR_SMTP_TLS_POLICY "}}" extern char *var_tlsp_clnt_policy; /* diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 81a59fc37..9770f7448 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 "20250710" -#define MAIL_VERSION_NUMBER "3.10.3" +#define MAIL_RELEASE_DATE "20250818" +#define MAIL_VERSION_NUMBER "3.10.4" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff --git a/postfix/src/master/event_server.c b/postfix/src/master/event_server.c index 9802bdf2f..ff280db57 100644 --- a/postfix/src/master/event_server.c +++ b/postfix/src/master/event_server.c @@ -273,6 +273,7 @@ static unsigned event_server_generation; static void (*event_server_pre_disconn) (VSTREAM *, char *, char **); static void (*event_server_slow_exit) (char *, char **); static int event_server_watchdog = 1000; +static int event_server_drain_was_called = 0; /* event_server_exit - normal termination */ @@ -327,6 +328,9 @@ int event_server_drain(void) const char *myname = "event_server_drain"; int fd; + if (event_server_drain_was_called) + return (0); + switch (fork()) { /* Try again later. */ case -1: @@ -343,6 +347,7 @@ int event_server_drain(void) msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd); } var_use_limit = 1; + event_server_drain_was_called = 1; return (0); /* Let the master start a new process. */ default: @@ -445,6 +450,9 @@ static void event_server_accept_local(int unused_event, void *context) int time_left = -1; int fd; + if (event_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -457,6 +465,8 @@ static void event_server_accept_local(int unused_event, void *context) if (event_server_pre_accept) event_server_pre_accept(event_server_name, event_server_argv); + if (event_server_drain_was_called) + return; fd = LOCAL_ACCEPT(listen_fd); if (event_server_lock != 0 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, @@ -483,6 +493,9 @@ static void event_server_accept_pass(int unused_event, void *context) int fd; HTABLE *attr = 0; + if (event_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -495,6 +508,8 @@ static void event_server_accept_pass(int unused_event, void *context) if (event_server_pre_accept) event_server_pre_accept(event_server_name, event_server_argv); + if (event_server_drain_was_called) + return; fd = pass_accept_attr(listen_fd, &attr); if (event_server_lock != 0 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, @@ -520,6 +535,9 @@ static void event_server_accept_inet(int unused_event, void *context) int time_left = -1; int fd; + if (event_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -532,6 +550,8 @@ static void event_server_accept_inet(int unused_event, void *context) if (event_server_pre_accept) event_server_pre_accept(event_server_name, event_server_argv); + if (event_server_drain_was_called) + return; fd = inet_accept(listen_fd); if (event_server_lock != 0 && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c index 6150f229a..4e744d4d1 100644 --- a/postfix/src/master/multi_server.c +++ b/postfix/src/master/multi_server.c @@ -260,6 +260,7 @@ static VSTREAM *multi_server_lock; static int multi_server_in_flow_delay; static unsigned multi_server_generation; static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **); +static int multi_server_drain_was_called = 0; /* multi_server_exit - normal termination */ @@ -295,6 +296,9 @@ int multi_server_drain(void) const char *myname = "multi_server_drain"; int fd; + if (multi_server_drain_was_called) + return (0); + switch (fork()) { /* Try again later. */ case -1: @@ -311,6 +315,7 @@ int multi_server_drain(void) msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd); } var_use_limit = 1; + multi_server_drain_was_called = 1; return (0); /* Let the master start a new process. */ default: @@ -429,6 +434,9 @@ static void multi_server_accept_local(int unused_event, void *context) int time_left = -1; int fd; + if (multi_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -441,6 +449,8 @@ static void multi_server_accept_local(int unused_event, void *context) if (multi_server_pre_accept) multi_server_pre_accept(multi_server_name, multi_server_argv); + if (multi_server_drain_was_called) + return; fd = LOCAL_ACCEPT(listen_fd); if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, @@ -467,6 +477,9 @@ static void multi_server_accept_pass(int unused_event, void *context) int fd; HTABLE *attr = 0; + if (multi_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -479,6 +492,8 @@ static void multi_server_accept_pass(int unused_event, void *context) if (multi_server_pre_accept) multi_server_pre_accept(multi_server_name, multi_server_argv); + if (multi_server_drain_was_called) + return; fd = pass_accept_attr(listen_fd, &attr); if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, @@ -504,6 +519,9 @@ static void multi_server_accept_inet(int unused_event, void *context) int time_left = -1; int fd; + if (multi_server_drain_was_called) + return; + /* * Be prepared for accept() to fail because some other process already * got the connection (the number of processes competing for clients is @@ -516,6 +534,8 @@ static void multi_server_accept_inet(int unused_event, void *context) if (multi_server_pre_accept) multi_server_pre_accept(multi_server_name, multi_server_argv); + if (multi_server_drain_was_called) + return; fd = inet_accept(listen_fd); if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index ebb680c06..2744dd15f 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -996,7 +996,7 @@ static void pre_accept(char *unused_name, char **unused_argv) if (new_event_time >= last_event_time + 1 && (name = dict_changed_name()) != 0) { msg_info("table %s has changed - finishing in the background", name); - event_server_drain(); + psc_drain(unused_name, unused_argv); } else { last_event_time = new_event_time; } diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index dc25a3e09..baa5ca81b 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -414,7 +414,6 @@ #ifdef USE_TLS #include -#include #endif /* diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index 44add46b2..f8cde6978 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -113,6 +113,7 @@ smtp.o: ../../include/nvtable.h smtp.o: ../../include/recipient_list.h smtp.o: ../../include/resolve_clnt.h smtp.o: ../../include/scache.h +smtp.o: ../../include/sendopts.h smtp.o: ../../include/sock_addr.h smtp.o: ../../include/string_list.h smtp.o: ../../include/stringops.h @@ -158,6 +159,7 @@ smtp_addr.o: ../../include/own_inet_addr.h smtp_addr.o: ../../include/recipient_list.h smtp_addr.o: ../../include/resolve_clnt.h smtp_addr.o: ../../include/scache.h +smtp_addr.o: ../../include/sendopts.h smtp_addr.o: ../../include/sock_addr.h smtp_addr.o: ../../include/string_list.h smtp_addr.o: ../../include/stringops.h @@ -304,6 +306,7 @@ smtp_key.o: ../../include/nvtable.h 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/sock_addr.h smtp_key.o: ../../include/string_list.h smtp_key.o: ../../include/sys_defs.h @@ -344,6 +347,7 @@ smtp_map11.o: ../../include/quote_flags.h smtp_map11.o: ../../include/recipient_list.h smtp_map11.o: ../../include/resolve_clnt.h smtp_map11.o: ../../include/scache.h +smtp_map11.o: ../../include/sendopts.h smtp_map11.o: ../../include/sock_addr.h smtp_map11.o: ../../include/string_list.h smtp_map11.o: ../../include/sys_defs.h @@ -384,6 +388,7 @@ smtp_misc.o: ../../include/quote_flags.h smtp_misc.o: ../../include/recipient_list.h smtp_misc.o: ../../include/resolve_clnt.h smtp_misc.o: ../../include/scache.h +smtp_misc.o: ../../include/sendopts.h smtp_misc.o: ../../include/sock_addr.h smtp_misc.o: ../../include/string_list.h smtp_misc.o: ../../include/sys_defs.h @@ -491,6 +496,7 @@ smtp_rcpt.o: ../../include/nvtable.h smtp_rcpt.o: ../../include/recipient_list.h smtp_rcpt.o: ../../include/resolve_clnt.h smtp_rcpt.o: ../../include/scache.h +smtp_rcpt.o: ../../include/sendopts.h smtp_rcpt.o: ../../include/sent.h smtp_rcpt.o: ../../include/sock_addr.h smtp_rcpt.o: ../../include/string_list.h @@ -530,6 +536,7 @@ smtp_reuse.o: ../../include/nvtable.h smtp_reuse.o: ../../include/recipient_list.h smtp_reuse.o: ../../include/resolve_clnt.h smtp_reuse.o: ../../include/scache.h +smtp_reuse.o: ../../include/sendopts.h smtp_reuse.o: ../../include/sock_addr.h smtp_reuse.o: ../../include/string_list.h smtp_reuse.o: ../../include/stringops.h @@ -572,6 +579,7 @@ smtp_sasl_auth_cache.o: ../../include/nvtable.h smtp_sasl_auth_cache.o: ../../include/recipient_list.h smtp_sasl_auth_cache.o: ../../include/resolve_clnt.h smtp_sasl_auth_cache.o: ../../include/scache.h +smtp_sasl_auth_cache.o: ../../include/sendopts.h smtp_sasl_auth_cache.o: ../../include/sock_addr.h smtp_sasl_auth_cache.o: ../../include/string_list.h smtp_sasl_auth_cache.o: ../../include/stringops.h @@ -613,6 +621,7 @@ smtp_sasl_glue.o: ../../include/nvtable.h smtp_sasl_glue.o: ../../include/recipient_list.h smtp_sasl_glue.o: ../../include/resolve_clnt.h smtp_sasl_glue.o: ../../include/scache.h +smtp_sasl_glue.o: ../../include/sendopts.h smtp_sasl_glue.o: ../../include/smtp_stream.h smtp_sasl_glue.o: ../../include/sock_addr.h smtp_sasl_glue.o: ../../include/split_at.h @@ -657,6 +666,7 @@ smtp_sasl_proto.o: ../../include/recipient_list.h smtp_sasl_proto.o: ../../include/resolve_clnt.h smtp_sasl_proto.o: ../../include/sasl_mech_filter.h smtp_sasl_proto.o: ../../include/scache.h +smtp_sasl_proto.o: ../../include/sendopts.h smtp_sasl_proto.o: ../../include/sock_addr.h smtp_sasl_proto.o: ../../include/string_list.h smtp_sasl_proto.o: ../../include/stringops.h @@ -697,6 +707,7 @@ smtp_session.o: ../../include/nvtable.h smtp_session.o: ../../include/recipient_list.h smtp_session.o: ../../include/resolve_clnt.h smtp_session.o: ../../include/scache.h +smtp_session.o: ../../include/sendopts.h smtp_session.o: ../../include/sock_addr.h smtp_session.o: ../../include/string_list.h smtp_session.o: ../../include/stringops.h @@ -737,6 +748,7 @@ smtp_state.o: ../../include/nvtable.h smtp_state.o: ../../include/recipient_list.h smtp_state.o: ../../include/resolve_clnt.h smtp_state.o: ../../include/scache.h +smtp_state.o: ../../include/sendopts.h smtp_state.o: ../../include/sock_addr.h smtp_state.o: ../../include/string_list.h smtp_state.o: ../../include/sys_defs.h @@ -778,6 +790,7 @@ smtp_tls_policy.o: ../../include/recipient_list.h smtp_tls_policy.o: ../../include/resolve_clnt.h smtp_tls_policy.o: ../../include/sane_strtol.h smtp_tls_policy.o: ../../include/scache.h +smtp_tls_policy.o: ../../include/sendopts.h smtp_tls_policy.o: ../../include/sock_addr.h smtp_tls_policy.o: ../../include/string_list.h smtp_tls_policy.o: ../../include/stringops.h @@ -821,6 +834,7 @@ smtp_tlsrpt.o: ../../include/nvtable.h smtp_tlsrpt.o: ../../include/recipient_list.h smtp_tlsrpt.o: ../../include/resolve_clnt.h smtp_tlsrpt.o: ../../include/scache.h +smtp_tlsrpt.o: ../../include/sendopts.h smtp_tlsrpt.o: ../../include/sock_addr.h smtp_tlsrpt.o: ../../include/string_list.h smtp_tlsrpt.o: ../../include/stringops.h @@ -864,6 +878,7 @@ smtp_trouble.o: ../../include/nvtable.h smtp_trouble.o: ../../include/recipient_list.h smtp_trouble.o: ../../include/resolve_clnt.h smtp_trouble.o: ../../include/scache.h +smtp_trouble.o: ../../include/sendopts.h smtp_trouble.o: ../../include/smtp_stream.h smtp_trouble.o: ../../include/sock_addr.h smtp_trouble.o: ../../include/string_list.h @@ -903,6 +918,7 @@ smtp_unalias.o: ../../include/nvtable.h smtp_unalias.o: ../../include/recipient_list.h smtp_unalias.o: ../../include/resolve_clnt.h smtp_unalias.o: ../../include/scache.h +smtp_unalias.o: ../../include/sendopts.h smtp_unalias.o: ../../include/sock_addr.h smtp_unalias.o: ../../include/string_list.h smtp_unalias.o: ../../include/sys_defs.h diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 7214661a6..af118926d 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -32,6 +32,7 @@ #include #include #include +#include /* * Postfix TLS library. @@ -59,9 +60,6 @@ typedef struct SMTP_ITERATOR { VSTRING *host; /* hostname or empty */ VSTRING *addr; /* printable address or empty */ unsigned port; /* network byte order or null */ -#ifdef USE_TLS - int tlsreqno; /* "TLS-Required: no" */ -#endif struct DNS_RR *rr; /* DNS resource record or null */ struct DNS_RR *mx; /* DNS resource record or null */ /* Private members. */ @@ -69,18 +67,11 @@ typedef struct SMTP_ITERATOR { struct SMTP_STATE *parent; /* parent linkage */ } SMTP_ITERATOR; -#ifdef USE_TLS -#define IF_USE_TLS(...) (__VA_ARGS__) -#else -#define IF_USE_TLS(...) -#endif - #define SMTP_ITER_INIT(iter, _dest, _host, _addr, _port, state) do { \ vstring_strcpy((iter)->dest, (_dest)); \ vstring_strcpy((iter)->host, (_host)); \ vstring_strcpy((iter)->addr, (_addr)); \ (iter)->port = (_port); \ - IF_USE_TLS((iter)->tlsreqno = 0); \ (iter)->mx = (iter)->rr = 0; \ vstring_strcpy((iter)->saved_dest, ""); \ (iter)->parent = (state); \ @@ -248,6 +239,12 @@ typedef struct SMTP_STATE { unsigned logged_line_length_limit:1; } SMTP_STATE; +#ifdef USE_TLS +#define STATE_TLS_NOT_REQUIRED(state) \ + (var_tls_required_enable && \ + ((state)->request->sendopts & SOPT_REQUIRETLS_HEADER)) +#endif + /* * Primitives to enable/disable/test connection caching and reuse based on * the delivery request next-hop destination (i.e. not smtp_fallback_relay). diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index e4b60791a..38e28b767 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -507,24 +507,6 @@ static int smtp_get_effective_tls_level(DSN_BUF *why, SMTP_STATE *state) SMTP_ITERATOR *iter = state->iterator; SMTP_TLS_POLICY *tls = state->tls; - /* - * If the message contains a "TLS-Required: no" header, update the - * iterator to limit the policy at TLS_LEV_MAY. - * - * We must do this early to avoid possible failure if TLSA record lookups - * fail, or if TLSA records are found, but can't be activated because the - * security level has been reset to "may". - * - * Note that the REQUIRETLS verb in ESMTP overrides the "TLS-Required: no" - * header. - */ -#ifdef USE_TLS - if (var_tls_required_enable - && (state->request->sendopts & SOPT_REQUIRETLS_HEADER)) { - iter->tlsreqno = 1; - } -#endif - /* * Determine the TLS level for this destination. */ @@ -976,9 +958,15 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop, * level of "may" to "encrypt"? This would disable falling back to * plaintext, and could break interoperability with receivers that * crank up security up to 11. + * + * With "TLS-Required: no" in effect, the SMTP client ignores the + * recipient-side policy mechanism TLSRPT, in addition to the already + * ignored DANE and MTA-STS mechanisms. This prevents TLSRPT + * notifications for all SMTP deliveries that do not require TLS. */ #ifdef USE_TLSRPT if (smtp_mode && var_smtp_tlsrpt_enable + && STATE_TLS_NOT_REQUIRED(state) == 0 && tls_level_lookup(var_smtp_tls_level) > TLS_LEV_NONE && !valid_hostaddr(domain, DONT_GRIPE)) smtp_tlsrpt_create_wrapper(state, domain); diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c index 6b9ee66e6..809ffea05 100644 --- a/postfix/src/smtp/smtp_tls_policy.c +++ b/postfix/src/smtp/smtp_tls_policy.c @@ -647,11 +647,18 @@ static void *policy_create(const char *unused_key, void *context) * Compute the per-site TLS enforcement level. For compatibility with the * original TLS patch, this algorithm is gives equal precedence to host * and next-hop policies. + * + * When "TLS-Required: no" is in effect, skip TLS policy lookup and limit + * the security level to "may". Do not reset the security level after + * policy lookup, as that would result in errors. For example, when TLSA + * records are looked up for security level "dane", and then the security + * level is reset to "may", the activation of those TLSA records will + * fail. */ tls->level = global_tls_level(); site_level = TLS_LEV_NOTFOUND; - if (iter->tlsreqno) { + if (STATE_TLS_NOT_REQUIRED(iter->parent)) { if (msg_verbose) msg_info("%s: no tls policy lookup", __func__); if (tls->level > TLS_LEV_MAY) diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index 55d336602..a7b511f7a 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -313,6 +313,7 @@ static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext) static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert, const TLS_CLIENT_START_PROPS *props) { + int x509_err = SSL_get_verify_result(TLScontext->con); /* * On exit both peer_CN and issuer_CN should be set. @@ -324,7 +325,7 @@ static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert, * Is the certificate trust chain trusted and matched? Any required name * checks are now performed internally in OpenSSL. */ - if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) { + if (x509_err == X509_V_OK) { TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; if (TLScontext->must_fail) { msg_panic("%s: cert valid despite trust init failure", @@ -356,6 +357,13 @@ static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert, tls_dane_log(TLScontext); } } + } else if (TLS_MUST_MATCH(TLScontext->level) && + x509_err == X509_V_ERR_HOSTNAME_MISMATCH) { + /* + * If the only error is a hostname mismatch, the certificate must have + * been trusted. + */ + TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; } /* diff --git a/postfix/src/tls/tls_verify.c b/postfix/src/tls/tls_verify.c index 6725dc41e..9c7191c45 100644 --- a/postfix/src/tls/tls_verify.c +++ b/postfix/src/tls/tls_verify.c @@ -120,12 +120,26 @@ /* update_error_state - safely stash away error state */ -static void update_error_state(TLS_SESS_STATE *TLScontext, int depth, - X509 *errorcert, int errorcode) +static void update_error_state(X509_STORE_CTX *ctx, TLS_SESS_STATE *TLScontext, + int depth, X509 *errorcert, int errorcode) { - /* No news is good news */ - if (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth) - return; + + /* + * Report the error that is closest to the leaf certificate, any errors + * higher up the chain are immaterial until the "inner" errors are fixed. + * + * We special-case "X509_V_ERR_HOSTNAME_MISMATCH" (at depth 0) in order to + * distinguish between untrusted certificates and trusted certificates + * with a hostname mismatch. Any other error has a higher priority. + */ + if (TLScontext->errordepth >= 0) { + if ((TLScontext->errordepth <= depth && + TLScontext->errorcode != X509_V_ERR_HOSTNAME_MISMATCH) || + errorcode == X509_V_ERR_HOSTNAME_MISMATCH) { + X509_STORE_CTX_set_error(ctx, TLScontext->errorcode); + return; + } + } /* * The certificate pointer is stable during the verification callback, @@ -179,12 +193,12 @@ int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx) if (TLScontext->must_fail) { if (depth == 0) { X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_UNSPECIFIED); - update_error_state(TLScontext, depth, cert, err); + update_error_state(ctx, TLScontext, depth, cert, err); } return (1); } if (ok == 0) - update_error_state(TLScontext, depth, cert, err); + update_error_state(ctx, TLScontext, depth, cert, err); if (TLScontext->log_mask & TLS_LOG_VERBOSE) { if (cert) { diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index 5159d54a8..4084e2341 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -1267,6 +1267,12 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, init_buf = vstring_alloc(100); init_key = tls_proxy_client_init_serialize(attr_print_plain, init_buf, init_props); +#define TLSP_CLIENT_INIT_RETURN(retval) do { \ + vstring_free(init_buf); \ + vstring_free(param_buf); \ + return (retval); \ + } while (0) + if (tlsp_pre_jail_done == 0) { if (tlsp_pre_jail_client_param_key == 0 || tlsp_pre_jail_client_init_key == 0) { @@ -1284,9 +1290,12 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, * TLS_APPL_STATE instance; this makes a mismatch of TLS_CLIENT_PARAMS * settings problematic. */ - if (tlsp_pre_jail_done - && !been_here_fixed(tlsp_params_mismatch_filter, param_key) - && strcmp(tlsp_pre_jail_client_param_key, param_key) != 0) { + else if (tlsp_pre_jail_client_param_key == 0 + || tlsp_pre_jail_client_init_key == 0) { + msg_warn("TLS client role is disabled by configuration"); + TLSP_CLIENT_INIT_RETURN(0); + } else if (!been_here_fixed(tlsp_params_mismatch_filter, param_key) + && strcmp(tlsp_pre_jail_client_param_key, param_key) != 0) { msg_warn("request from tlsproxy client with unexpected settings"); tlsp_log_config_diff(tlsp_pre_jail_client_param_key, param_key); log_hints = 1; @@ -1361,9 +1370,7 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); } - vstring_free(init_buf); - vstring_free(param_buf); - return (appl_state); + TLSP_CLIENT_INIT_RETURN(appl_state); } /* tlsp_close_event - pre-handshake plaintext-client close event */ @@ -1497,6 +1504,7 @@ static void tlsp_get_request_event(int event, void *context) TLSP_INIT_TIMEOUT, (void *) state); return; } else { + state->flags |= TLSP_FLAG_DO_HANDSHAKE; tlsp_request_read_event(plaintext_fd, tlsp_get_fd_event, TLSP_INIT_TIMEOUT, (void *) state); return; diff --git a/postfix/src/tlsproxy/tlsproxy_state.c b/postfix/src/tlsproxy/tlsproxy_state.c index df6cbda1d..4a08d17fe 100644 --- a/postfix/src/tlsproxy/tlsproxy_state.c +++ b/postfix/src/tlsproxy/tlsproxy_state.c @@ -105,7 +105,7 @@ TLSP_STATE *tlsp_state_create(const char *service, { TLSP_STATE *state = (TLSP_STATE *) mymalloc(sizeof(*state)); - state->flags = TLSP_FLAG_DO_HANDSHAKE; + state->flags = 0; state->service = mystrdup(service); state->plaintext_stream = plaintext_stream; state->plaintext_buf = 0; diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 35c02db05..3a553f8ce 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -147,8 +147,8 @@ /* .IP "char *context" /* Application context from the caller. /* .PP -/* dict_changed_name() returns non-zero when any dictionary needs to -/* be re-opened because it has changed or because it was unlinked. +/* dict_changed_name() returns non-zero when any dictionary is +/* opened read-only and has changed, or because it was unlinked. /* A non-zero result is the name of a changed dictionary. /* /* dict_load_file_xt() reads name-value entries from the named file. @@ -601,11 +601,12 @@ const char *dict_changed_name(void) dict = ((DICT_NODE *) h->value)->dict; if (dict->stat_fd < 0) /* not file-based */ continue; - if (dict->mtime == 0) /* not bloody likely */ - msg_warn("%s: table %s: null time stamp", myname, h->key); + if (dict->mtime < 0) /* not bloody likely */ + msg_warn("%s: table %s: negative time stamp", myname, h->key); if (fstat(dict->stat_fd, &st) < 0) msg_fatal("%s: fstat: %m", myname); if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0 + && dict->mtime > 0 && st.st_mtime != dict->mtime) || st.st_nlink == 0) status = h->key; diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index b2d0c336f..0a760c6b9 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -789,7 +789,8 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, dict_db->dict.stat_fd = dbfd; if (fstat(dict_db->dict.stat_fd, &st) < 0) msg_fatal("dict_db_open: fstat: %m"); - dict_db->dict.mtime = st.st_mtime; + if (open_flags == O_RDONLY) + dict_db->dict.mtime = st.st_mtime; dict_db->dict.owner.uid = st.st_uid; dict_db->dict.owner.status = (st.st_uid != 0); diff --git a/postfix/src/util/dict_dbm.c b/postfix/src/util/dict_dbm.c index e47b7eedf..b3bbe8510 100644 --- a/postfix/src/util/dict_dbm.c +++ b/postfix/src/util/dict_dbm.c @@ -472,7 +472,8 @@ 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"); - dict_dbm->dict.mtime = st.st_mtime; + if (open_mode == 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); diff --git a/postfix/src/util/dict_lmdb.c b/postfix/src/util/dict_lmdb.c index bed20e0c4..6f4f276ca 100644 --- a/postfix/src/util/dict_lmdb.c +++ b/postfix/src/util/dict_lmdb.c @@ -653,7 +653,8 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags) msg_fatal("dict_lmdb_open: fstat: %m"); dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd; dict_lmdb->dict.lock_type = MYFLOCK_STYLE_FCNTL; - dict_lmdb->dict.mtime = st.st_mtime; + if (open_flags == O_RDONLY) + dict_lmdb->dict.mtime = st.st_mtime; dict_lmdb->dict.owner.uid = st.st_uid; dict_lmdb->dict.owner.status = (st.st_uid != 0); diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c index 23371dc7c..fcb2556e8 100644 --- a/postfix/src/util/dict_sdbm.c +++ b/postfix/src/util/dict_sdbm.c @@ -449,7 +449,8 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm); if (fstat(dict_sdbm->dict.stat_fd, &st) < 0) msg_fatal("dict_sdbm_open: fstat: %m"); - dict_sdbm->dict.mtime = st.st_mtime; + if (open_flags == O_RDONLY) + dict_sdbm->dict.mtime = st.st_mtime; dict_sdbm->dict.owner.uid = st.st_uid; dict_sdbm->dict.owner.status = (st.st_uid != 0);