2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 01:49:47 +00:00

postfix-3.10.4

This commit is contained in:
Wietse Z Venema 2025-08-18 00:00:00 -05:00 committed by Viktor Dukhovni
parent cbbd8b65e0
commit 03efe71c9a
20 changed files with 212 additions and 58 deletions

View File

@ -29054,3 +29054,71 @@ Apologies for any names omitted.
with "TLS-Required: no". This could result in unnecessary with "TLS-Required: no". This could result in unnecessary
failures. Fix by Viktor Dukhovni & Wietse. Files: smtp/smtp.h, failures. Fix by Viktor Dukhovni & Wietse. Files: smtp/smtp.h,
smtp/smtp_policy.c, smtp/smtp_connect.c. 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 <openssl/engine.h> 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.

View File

@ -4171,7 +4171,9 @@ extern bool var_tlsp_clnt_enforce_tls;
/* Migrate an incorrect name. */ /* Migrate an incorrect name. */
#define OBS_TLSP_CLNT_LEVEL "tlsproxy_client_level" #define OBS_TLSP_CLNT_LEVEL "tlsproxy_client_level"
#define VAR_TLSP_CLNT_LEVEL "tlsproxy_client_security_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; extern char *var_tlsp_clnt_level;
#define VAR_TLSP_CLNT_PER_SITE "tlsproxy_client_per_site" #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. */ /* Migrate an incorrect name. */
#define OBS_TLSP_CLNT_POLICY "tlsproxy_client_policy" #define OBS_TLSP_CLNT_POLICY "tlsproxy_client_policy"
#define VAR_TLSP_CLNT_POLICY "tlsproxy_client_policy_maps" #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; extern char *var_tlsp_clnt_policy;
/* /*

View File

@ -20,8 +20,8 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20250710" #define MAIL_RELEASE_DATE "20250818"
#define MAIL_VERSION_NUMBER "3.10.3" #define MAIL_VERSION_NUMBER "3.10.4"
#ifdef SNAPSHOT #ifdef SNAPSHOT
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE

View File

@ -273,6 +273,7 @@ static unsigned event_server_generation;
static void (*event_server_pre_disconn) (VSTREAM *, char *, char **); static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
static void (*event_server_slow_exit) (char *, char **); static void (*event_server_slow_exit) (char *, char **);
static int event_server_watchdog = 1000; static int event_server_watchdog = 1000;
static int event_server_drain_was_called = 0;
/* event_server_exit - normal termination */ /* event_server_exit - normal termination */
@ -327,6 +328,9 @@ int event_server_drain(void)
const char *myname = "event_server_drain"; const char *myname = "event_server_drain";
int fd; int fd;
if (event_server_drain_was_called)
return (0);
switch (fork()) { switch (fork()) {
/* Try again later. */ /* Try again later. */
case -1: case -1:
@ -343,6 +347,7 @@ int event_server_drain(void)
msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd); msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
} }
var_use_limit = 1; var_use_limit = 1;
event_server_drain_was_called = 1;
return (0); return (0);
/* Let the master start a new process. */ /* Let the master start a new process. */
default: default:
@ -445,6 +450,9 @@ static void event_server_accept_local(int unused_event, void *context)
int time_left = -1; int time_left = -1;
int fd; int fd;
if (event_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv); event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = LOCAL_ACCEPT(listen_fd); fd = LOCAL_ACCEPT(listen_fd);
if (event_server_lock != 0 if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, && 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; int fd;
HTABLE *attr = 0; HTABLE *attr = 0;
if (event_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv); event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = pass_accept_attr(listen_fd, &attr); fd = pass_accept_attr(listen_fd, &attr);
if (event_server_lock != 0 if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, && 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 time_left = -1;
int fd; int fd;
if (event_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv); event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = inet_accept(listen_fd); fd = inet_accept(listen_fd);
if (event_server_lock != 0 if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,

View File

@ -260,6 +260,7 @@ static VSTREAM *multi_server_lock;
static int multi_server_in_flow_delay; static int multi_server_in_flow_delay;
static unsigned multi_server_generation; static unsigned multi_server_generation;
static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **); static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **);
static int multi_server_drain_was_called = 0;
/* multi_server_exit - normal termination */ /* multi_server_exit - normal termination */
@ -295,6 +296,9 @@ int multi_server_drain(void)
const char *myname = "multi_server_drain"; const char *myname = "multi_server_drain";
int fd; int fd;
if (multi_server_drain_was_called)
return (0);
switch (fork()) { switch (fork()) {
/* Try again later. */ /* Try again later. */
case -1: case -1:
@ -311,6 +315,7 @@ int multi_server_drain(void)
msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd); msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
} }
var_use_limit = 1; var_use_limit = 1;
multi_server_drain_was_called = 1;
return (0); return (0);
/* Let the master start a new process. */ /* Let the master start a new process. */
default: default:
@ -429,6 +434,9 @@ static void multi_server_accept_local(int unused_event, void *context)
int time_left = -1; int time_left = -1;
int fd; int fd;
if (multi_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv); multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = LOCAL_ACCEPT(listen_fd); fd = LOCAL_ACCEPT(listen_fd);
if (multi_server_lock != 0 if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, && 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; int fd;
HTABLE *attr = 0; HTABLE *attr = 0;
if (multi_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv); multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = pass_accept_attr(listen_fd, &attr); fd = pass_accept_attr(listen_fd, &attr);
if (multi_server_lock != 0 if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, && 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 time_left = -1;
int fd; int fd;
if (multi_server_drain_was_called)
return;
/* /*
* Be prepared for accept() to fail because some other process already * Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is * 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) if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv); multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = inet_accept(listen_fd); fd = inet_accept(listen_fd);
if (multi_server_lock != 0 if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,

View File

@ -996,7 +996,7 @@ static void pre_accept(char *unused_name, char **unused_argv)
if (new_event_time >= last_event_time + 1 if (new_event_time >= last_event_time + 1
&& (name = dict_changed_name()) != 0) { && (name = dict_changed_name()) != 0) {
msg_info("table %s has changed - finishing in the background", name); msg_info("table %s has changed - finishing in the background", name);
event_server_drain(); psc_drain(unused_name, unused_argv);
} else { } else {
last_event_time = new_event_time; last_event_time = new_event_time;
} }

View File

@ -414,7 +414,6 @@
#ifdef USE_TLS #ifdef USE_TLS
#include <tls_proxy.h> #include <tls_proxy.h>
#include <openssl/engine.h>
#endif #endif
/* /*

View File

@ -113,6 +113,7 @@ smtp.o: ../../include/nvtable.h
smtp.o: ../../include/recipient_list.h smtp.o: ../../include/recipient_list.h
smtp.o: ../../include/resolve_clnt.h smtp.o: ../../include/resolve_clnt.h
smtp.o: ../../include/scache.h smtp.o: ../../include/scache.h
smtp.o: ../../include/sendopts.h
smtp.o: ../../include/sock_addr.h smtp.o: ../../include/sock_addr.h
smtp.o: ../../include/string_list.h smtp.o: ../../include/string_list.h
smtp.o: ../../include/stringops.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/recipient_list.h
smtp_addr.o: ../../include/resolve_clnt.h smtp_addr.o: ../../include/resolve_clnt.h
smtp_addr.o: ../../include/scache.h smtp_addr.o: ../../include/scache.h
smtp_addr.o: ../../include/sendopts.h
smtp_addr.o: ../../include/sock_addr.h smtp_addr.o: ../../include/sock_addr.h
smtp_addr.o: ../../include/string_list.h smtp_addr.o: ../../include/string_list.h
smtp_addr.o: ../../include/stringops.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/recipient_list.h
smtp_key.o: ../../include/resolve_clnt.h smtp_key.o: ../../include/resolve_clnt.h
smtp_key.o: ../../include/scache.h smtp_key.o: ../../include/scache.h
smtp_key.o: ../../include/sendopts.h
smtp_key.o: ../../include/sock_addr.h smtp_key.o: ../../include/sock_addr.h
smtp_key.o: ../../include/string_list.h smtp_key.o: ../../include/string_list.h
smtp_key.o: ../../include/sys_defs.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/recipient_list.h
smtp_map11.o: ../../include/resolve_clnt.h smtp_map11.o: ../../include/resolve_clnt.h
smtp_map11.o: ../../include/scache.h smtp_map11.o: ../../include/scache.h
smtp_map11.o: ../../include/sendopts.h
smtp_map11.o: ../../include/sock_addr.h smtp_map11.o: ../../include/sock_addr.h
smtp_map11.o: ../../include/string_list.h smtp_map11.o: ../../include/string_list.h
smtp_map11.o: ../../include/sys_defs.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/recipient_list.h
smtp_misc.o: ../../include/resolve_clnt.h smtp_misc.o: ../../include/resolve_clnt.h
smtp_misc.o: ../../include/scache.h smtp_misc.o: ../../include/scache.h
smtp_misc.o: ../../include/sendopts.h
smtp_misc.o: ../../include/sock_addr.h smtp_misc.o: ../../include/sock_addr.h
smtp_misc.o: ../../include/string_list.h smtp_misc.o: ../../include/string_list.h
smtp_misc.o: ../../include/sys_defs.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/recipient_list.h
smtp_rcpt.o: ../../include/resolve_clnt.h smtp_rcpt.o: ../../include/resolve_clnt.h
smtp_rcpt.o: ../../include/scache.h smtp_rcpt.o: ../../include/scache.h
smtp_rcpt.o: ../../include/sendopts.h
smtp_rcpt.o: ../../include/sent.h smtp_rcpt.o: ../../include/sent.h
smtp_rcpt.o: ../../include/sock_addr.h smtp_rcpt.o: ../../include/sock_addr.h
smtp_rcpt.o: ../../include/string_list.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/recipient_list.h
smtp_reuse.o: ../../include/resolve_clnt.h smtp_reuse.o: ../../include/resolve_clnt.h
smtp_reuse.o: ../../include/scache.h smtp_reuse.o: ../../include/scache.h
smtp_reuse.o: ../../include/sendopts.h
smtp_reuse.o: ../../include/sock_addr.h smtp_reuse.o: ../../include/sock_addr.h
smtp_reuse.o: ../../include/string_list.h smtp_reuse.o: ../../include/string_list.h
smtp_reuse.o: ../../include/stringops.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/recipient_list.h
smtp_sasl_auth_cache.o: ../../include/resolve_clnt.h smtp_sasl_auth_cache.o: ../../include/resolve_clnt.h
smtp_sasl_auth_cache.o: ../../include/scache.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/sock_addr.h
smtp_sasl_auth_cache.o: ../../include/string_list.h smtp_sasl_auth_cache.o: ../../include/string_list.h
smtp_sasl_auth_cache.o: ../../include/stringops.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/recipient_list.h
smtp_sasl_glue.o: ../../include/resolve_clnt.h smtp_sasl_glue.o: ../../include/resolve_clnt.h
smtp_sasl_glue.o: ../../include/scache.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/smtp_stream.h
smtp_sasl_glue.o: ../../include/sock_addr.h smtp_sasl_glue.o: ../../include/sock_addr.h
smtp_sasl_glue.o: ../../include/split_at.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/resolve_clnt.h
smtp_sasl_proto.o: ../../include/sasl_mech_filter.h smtp_sasl_proto.o: ../../include/sasl_mech_filter.h
smtp_sasl_proto.o: ../../include/scache.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/sock_addr.h
smtp_sasl_proto.o: ../../include/string_list.h smtp_sasl_proto.o: ../../include/string_list.h
smtp_sasl_proto.o: ../../include/stringops.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/recipient_list.h
smtp_session.o: ../../include/resolve_clnt.h smtp_session.o: ../../include/resolve_clnt.h
smtp_session.o: ../../include/scache.h smtp_session.o: ../../include/scache.h
smtp_session.o: ../../include/sendopts.h
smtp_session.o: ../../include/sock_addr.h smtp_session.o: ../../include/sock_addr.h
smtp_session.o: ../../include/string_list.h smtp_session.o: ../../include/string_list.h
smtp_session.o: ../../include/stringops.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/recipient_list.h
smtp_state.o: ../../include/resolve_clnt.h smtp_state.o: ../../include/resolve_clnt.h
smtp_state.o: ../../include/scache.h smtp_state.o: ../../include/scache.h
smtp_state.o: ../../include/sendopts.h
smtp_state.o: ../../include/sock_addr.h smtp_state.o: ../../include/sock_addr.h
smtp_state.o: ../../include/string_list.h smtp_state.o: ../../include/string_list.h
smtp_state.o: ../../include/sys_defs.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/resolve_clnt.h
smtp_tls_policy.o: ../../include/sane_strtol.h smtp_tls_policy.o: ../../include/sane_strtol.h
smtp_tls_policy.o: ../../include/scache.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/sock_addr.h
smtp_tls_policy.o: ../../include/string_list.h smtp_tls_policy.o: ../../include/string_list.h
smtp_tls_policy.o: ../../include/stringops.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/recipient_list.h
smtp_tlsrpt.o: ../../include/resolve_clnt.h smtp_tlsrpt.o: ../../include/resolve_clnt.h
smtp_tlsrpt.o: ../../include/scache.h smtp_tlsrpt.o: ../../include/scache.h
smtp_tlsrpt.o: ../../include/sendopts.h
smtp_tlsrpt.o: ../../include/sock_addr.h smtp_tlsrpt.o: ../../include/sock_addr.h
smtp_tlsrpt.o: ../../include/string_list.h smtp_tlsrpt.o: ../../include/string_list.h
smtp_tlsrpt.o: ../../include/stringops.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/recipient_list.h
smtp_trouble.o: ../../include/resolve_clnt.h smtp_trouble.o: ../../include/resolve_clnt.h
smtp_trouble.o: ../../include/scache.h smtp_trouble.o: ../../include/scache.h
smtp_trouble.o: ../../include/sendopts.h
smtp_trouble.o: ../../include/smtp_stream.h smtp_trouble.o: ../../include/smtp_stream.h
smtp_trouble.o: ../../include/sock_addr.h smtp_trouble.o: ../../include/sock_addr.h
smtp_trouble.o: ../../include/string_list.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/recipient_list.h
smtp_unalias.o: ../../include/resolve_clnt.h smtp_unalias.o: ../../include/resolve_clnt.h
smtp_unalias.o: ../../include/scache.h smtp_unalias.o: ../../include/scache.h
smtp_unalias.o: ../../include/sendopts.h
smtp_unalias.o: ../../include/sock_addr.h smtp_unalias.o: ../../include/sock_addr.h
smtp_unalias.o: ../../include/string_list.h smtp_unalias.o: ../../include/string_list.h
smtp_unalias.o: ../../include/sys_defs.h smtp_unalias.o: ../../include/sys_defs.h

View File

@ -32,6 +32,7 @@
#include <tok822.h> #include <tok822.h>
#include <dsn_buf.h> #include <dsn_buf.h>
#include <header_body_checks.h> #include <header_body_checks.h>
#include <sendopts.h>
/* /*
* Postfix TLS library. * Postfix TLS library.
@ -59,9 +60,6 @@ typedef struct SMTP_ITERATOR {
VSTRING *host; /* hostname or empty */ VSTRING *host; /* hostname or empty */
VSTRING *addr; /* printable address or empty */ VSTRING *addr; /* printable address or empty */
unsigned port; /* network byte order or null */ 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 *rr; /* DNS resource record or null */
struct DNS_RR *mx; /* DNS resource record or null */ struct DNS_RR *mx; /* DNS resource record or null */
/* Private members. */ /* Private members. */
@ -69,18 +67,11 @@ typedef struct SMTP_ITERATOR {
struct SMTP_STATE *parent; /* parent linkage */ struct SMTP_STATE *parent; /* parent linkage */
} SMTP_ITERATOR; } 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 { \ #define SMTP_ITER_INIT(iter, _dest, _host, _addr, _port, state) do { \
vstring_strcpy((iter)->dest, (_dest)); \ vstring_strcpy((iter)->dest, (_dest)); \
vstring_strcpy((iter)->host, (_host)); \ vstring_strcpy((iter)->host, (_host)); \
vstring_strcpy((iter)->addr, (_addr)); \ vstring_strcpy((iter)->addr, (_addr)); \
(iter)->port = (_port); \ (iter)->port = (_port); \
IF_USE_TLS((iter)->tlsreqno = 0); \
(iter)->mx = (iter)->rr = 0; \ (iter)->mx = (iter)->rr = 0; \
vstring_strcpy((iter)->saved_dest, ""); \ vstring_strcpy((iter)->saved_dest, ""); \
(iter)->parent = (state); \ (iter)->parent = (state); \
@ -248,6 +239,12 @@ typedef struct SMTP_STATE {
unsigned logged_line_length_limit:1; unsigned logged_line_length_limit:1;
} SMTP_STATE; } 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 * Primitives to enable/disable/test connection caching and reuse based on
* the delivery request next-hop destination (i.e. not smtp_fallback_relay). * the delivery request next-hop destination (i.e. not smtp_fallback_relay).

View File

@ -507,24 +507,6 @@ static int smtp_get_effective_tls_level(DSN_BUF *why, SMTP_STATE *state)
SMTP_ITERATOR *iter = state->iterator; SMTP_ITERATOR *iter = state->iterator;
SMTP_TLS_POLICY *tls = state->tls; 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. * 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 * level of "may" to "encrypt"? This would disable falling back to
* plaintext, and could break interoperability with receivers that * plaintext, and could break interoperability with receivers that
* crank up security up to 11. * 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 #ifdef USE_TLSRPT
if (smtp_mode && var_smtp_tlsrpt_enable if (smtp_mode && var_smtp_tlsrpt_enable
&& STATE_TLS_NOT_REQUIRED(state) == 0
&& tls_level_lookup(var_smtp_tls_level) > TLS_LEV_NONE && tls_level_lookup(var_smtp_tls_level) > TLS_LEV_NONE
&& !valid_hostaddr(domain, DONT_GRIPE)) && !valid_hostaddr(domain, DONT_GRIPE))
smtp_tlsrpt_create_wrapper(state, domain); smtp_tlsrpt_create_wrapper(state, domain);

View File

@ -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 * Compute the per-site TLS enforcement level. For compatibility with the
* original TLS patch, this algorithm is gives equal precedence to host * original TLS patch, this algorithm is gives equal precedence to host
* and next-hop policies. * 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(); tls->level = global_tls_level();
site_level = TLS_LEV_NOTFOUND; site_level = TLS_LEV_NOTFOUND;
if (iter->tlsreqno) { if (STATE_TLS_NOT_REQUIRED(iter->parent)) {
if (msg_verbose) if (msg_verbose)
msg_info("%s: no tls policy lookup", __func__); msg_info("%s: no tls policy lookup", __func__);
if (tls->level > TLS_LEV_MAY) if (tls->level > TLS_LEV_MAY)

View File

@ -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, static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert,
const TLS_CLIENT_START_PROPS *props) 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. * 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 * Is the certificate trust chain trusted and matched? Any required name
* checks are now performed internally in OpenSSL. * 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; TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;
if (TLScontext->must_fail) { if (TLScontext->must_fail) {
msg_panic("%s: cert valid despite trust init failure", 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); 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;
} }
/* /*

View File

@ -120,12 +120,26 @@
/* update_error_state - safely stash away error state */ /* update_error_state - safely stash away error state */
static void update_error_state(TLS_SESS_STATE *TLScontext, int depth, static void update_error_state(X509_STORE_CTX *ctx, TLS_SESS_STATE *TLScontext,
X509 *errorcert, int errorcode) 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, * 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 (TLScontext->must_fail) {
if (depth == 0) { if (depth == 0) {
X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_UNSPECIFIED); 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); return (1);
} }
if (ok == 0) 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 (TLScontext->log_mask & TLS_LOG_VERBOSE) {
if (cert) { if (cert) {

View File

@ -1267,6 +1267,12 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params,
init_buf = vstring_alloc(100); init_buf = vstring_alloc(100);
init_key = tls_proxy_client_init_serialize(attr_print_plain, init_buf, init_key = tls_proxy_client_init_serialize(attr_print_plain, init_buf,
init_props); 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_done == 0) {
if (tlsp_pre_jail_client_param_key == 0 if (tlsp_pre_jail_client_param_key == 0
|| tlsp_pre_jail_client_init_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 * TLS_APPL_STATE instance; this makes a mismatch of TLS_CLIENT_PARAMS
* settings problematic. * settings problematic.
*/ */
if (tlsp_pre_jail_done else if (tlsp_pre_jail_client_param_key == 0
&& !been_here_fixed(tlsp_params_mismatch_filter, param_key) || tlsp_pre_jail_client_init_key == 0) {
&& strcmp(tlsp_pre_jail_client_param_key, param_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"); msg_warn("request from tlsproxy client with unexpected settings");
tlsp_log_config_diff(tlsp_pre_jail_client_param_key, param_key); tlsp_log_config_diff(tlsp_pre_jail_client_param_key, param_key);
log_hints = 1; 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_ENABLE_PARTIAL_WRITE
| SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
} }
vstring_free(init_buf); TLSP_CLIENT_INIT_RETURN(appl_state);
vstring_free(param_buf);
return (appl_state);
} }
/* tlsp_close_event - pre-handshake plaintext-client close event */ /* 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); TLSP_INIT_TIMEOUT, (void *) state);
return; return;
} else { } else {
state->flags |= TLSP_FLAG_DO_HANDSHAKE;
tlsp_request_read_event(plaintext_fd, tlsp_get_fd_event, tlsp_request_read_event(plaintext_fd, tlsp_get_fd_event,
TLSP_INIT_TIMEOUT, (void *) state); TLSP_INIT_TIMEOUT, (void *) state);
return; return;

View File

@ -105,7 +105,7 @@ TLSP_STATE *tlsp_state_create(const char *service,
{ {
TLSP_STATE *state = (TLSP_STATE *) mymalloc(sizeof(*state)); TLSP_STATE *state = (TLSP_STATE *) mymalloc(sizeof(*state));
state->flags = TLSP_FLAG_DO_HANDSHAKE; state->flags = 0;
state->service = mystrdup(service); state->service = mystrdup(service);
state->plaintext_stream = plaintext_stream; state->plaintext_stream = plaintext_stream;
state->plaintext_buf = 0; state->plaintext_buf = 0;

View File

@ -147,8 +147,8 @@
/* .IP "char *context" /* .IP "char *context"
/* Application context from the caller. /* Application context from the caller.
/* .PP /* .PP
/* dict_changed_name() returns non-zero when any dictionary needs to /* dict_changed_name() returns non-zero when any dictionary is
/* be re-opened because it has changed or because it was unlinked. /* opened read-only and has changed, or because it was unlinked.
/* A non-zero result is the name of a changed dictionary. /* A non-zero result is the name of a changed dictionary.
/* /*
/* dict_load_file_xt() reads name-value entries from the named file. /* 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; dict = ((DICT_NODE *) h->value)->dict;
if (dict->stat_fd < 0) /* not file-based */ if (dict->stat_fd < 0) /* not file-based */
continue; continue;
if (dict->mtime == 0) /* not bloody likely */ if (dict->mtime < 0) /* not bloody likely */
msg_warn("%s: table %s: null time stamp", myname, h->key); msg_warn("%s: table %s: negative time stamp", myname, h->key);
if (fstat(dict->stat_fd, &st) < 0) if (fstat(dict->stat_fd, &st) < 0)
msg_fatal("%s: fstat: %m", myname); msg_fatal("%s: fstat: %m", myname);
if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0 if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0
&& dict->mtime > 0
&& st.st_mtime != dict->mtime) && st.st_mtime != dict->mtime)
|| st.st_nlink == 0) || st.st_nlink == 0)
status = h->key; status = h->key;

View File

@ -789,7 +789,8 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
dict_db->dict.stat_fd = dbfd; dict_db->dict.stat_fd = dbfd;
if (fstat(dict_db->dict.stat_fd, &st) < 0) if (fstat(dict_db->dict.stat_fd, &st) < 0)
msg_fatal("dict_db_open: fstat: %m"); 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.uid = st.st_uid;
dict_db->dict.owner.status = (st.st_uid != 0); dict_db->dict.owner.status = (st.st_uid != 0);

View File

@ -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); msg_fatal("open database %s: cannot support GDBM", path);
if (fstat(dict_dbm->dict.stat_fd, &st) < 0) if (fstat(dict_dbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_dbm_open: fstat: %m"); 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.uid = st.st_uid;
dict_dbm->dict.owner.status = (st.st_uid != 0); dict_dbm->dict.owner.status = (st.st_uid != 0);

View File

@ -653,7 +653,8 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
msg_fatal("dict_lmdb_open: fstat: %m"); msg_fatal("dict_lmdb_open: fstat: %m");
dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd; dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd;
dict_lmdb->dict.lock_type = MYFLOCK_STYLE_FCNTL; 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.uid = st.st_uid;
dict_lmdb->dict.owner.status = (st.st_uid != 0); dict_lmdb->dict.owner.status = (st.st_uid != 0);

View File

@ -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); dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm);
if (fstat(dict_sdbm->dict.stat_fd, &st) < 0) if (fstat(dict_sdbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_sdbm_open: fstat: %m"); 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.uid = st.st_uid;
dict_sdbm->dict.owner.status = (st.st_uid != 0); dict_sdbm->dict.owner.status = (st.st_uid != 0);