Prereq: "3.8.14" diff -ur --new-file /var/tmp/postfix-3.8.14/src/global/mail_version.h ./src/global/mail_version.h --- /var/tmp/postfix-3.8.14/src/global/mail_version.h 2025-12-05 15:29:39.000000000 -0500 +++ ./src/global/mail_version.h 2026-02-18 14:44:18.000000000 -0500 @@ -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 "20251205" -#define MAIL_VERSION_NUMBER "3.8.14" +#define MAIL_RELEASE_DATE "20260218" +#define MAIL_VERSION_NUMBER "3.8.15" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -ur --new-file /var/tmp/postfix-3.8.14/HISTORY ./HISTORY --- /var/tmp/postfix-3.8.14/HISTORY 2025-12-05 15:27:32.000000000 -0500 +++ ./HISTORY 2026-02-18 14:33:15.000000000 -0500 @@ -27607,3 +27607,24 @@ large for the stable releases. Instead, the command "make makefiles" will figure out how to make the compiler backwards-compatible. File: makedefs. + +20251208 + + Improved Milter error handling for messages that arrive + over a long-lived SMTP connection, by changing the default + milter_default_action from "tempfail" to the new "shutdown" + action (i.e. disconnect the remote SMTP client). + + The problem was that after a single Milter error, Postfix + could tempfail all messages that the client sends over a + long-lived connection, even if the Milter error was only + temporary. This problem was reported by Ankit Kulkarni. + + Files: proto/postconf.proto global/mail_params.h milter/milter8.c. + +20260217 + + Bugfix: (defect introduced: Postfix 2.11): panic() after + recursive logging loop with "posttls-finger -v -v -v". + Reported by Geert Hendrickx, diagnosed by Viktor Dukhovni, + and fixed by Wietse. Files: util/vstream.[hc], util/msg_vstream.c. diff -ur --new-file /var/tmp/postfix-3.8.14/html/postconf.5.html ./html/postconf.5.html --- /var/tmp/postfix-3.8.14/html/postconf.5.html 2025-11-25 12:38:55.000000000 -0500 +++ ./html/postconf.5.html 2026-02-18 15:21:00.000000000 -0500 @@ -7168,7 +7168,7 @@
milter_default_action -(default: tempfail)
+(default: see 'postconf -d milter_default_action' output)

The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter @@ -7185,11 +7185,20 @@

tempfail
Reject all further commands in this session with a temporary status code.
+
shutdown
Close the SMTP connection after sending a 421 +SMTP reply. Available in Postfix 3.11, 3.10.8, 3.9.9, 3.8.15, 3.7.20, +and later.
+
quarantine
Like "accept", but freeze the message in the "hold" queue. Available with Postfix 2.6 and later.
+

The current default action is "shutdown", i.e. disconnect the +SMTP client. With the old "tempfail" default, Postfix could tempfail +all messages that the client sends over a long-lived connection, +even if a Milter failure is only temporary.

+

This feature is available in Postfix 2.3 and later.

diff -ur --new-file /var/tmp/postfix-3.8.14/man/man5/postconf.5 ./man/man5/postconf.5 --- /var/tmp/postfix-3.8.14/man/man5/postconf.5 2025-11-25 12:34:09.000000000 -0500 +++ ./man/man5/postconf.5 2026-02-18 15:21:01.000000000 -0500 @@ -4457,7 +4457,7 @@ for a list of available macro names and their meanings. .PP This feature is available in Postfix 2.3 and later. -.SH milter_default_action (default: tempfail) +.SH milter_default_action (default: see 'postconf \-d milter_default_action' output) The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter failure). Specify one of the following: @@ -4472,12 +4472,22 @@ Reject all further commands in this session with a temporary status code. .br +.IP "shutdown" +Close the SMTP connection after sending a 421 +SMTP reply. Available in Postfix 3.11, 3.10.8, 3.9.9, 3.8.15, 3.7.20, +and later. +.br .IP "quarantine" Like "accept", but freeze the message in the "hold" queue. Available with Postfix 2.6 and later. .br .br .PP +The current default action is "shutdown", i.e. disconnect the +SMTP client. With the old "tempfail" default, Postfix could tempfail +all messages that the client sends over a long\-lived connection, +even if a Milter failure is only temporary. +.PP This feature is available in Postfix 2.3 and later. .SH milter_end_of_data_macros (default: see "postconf \-d" output) The macros that are sent to Milter (mail filter) applications diff -ur --new-file /var/tmp/postfix-3.8.14/proto/postconf.proto ./proto/postconf.proto --- /var/tmp/postfix-3.8.14/proto/postconf.proto 2025-11-25 12:33:00.000000000 -0500 +++ ./proto/postconf.proto 2026-02-18 14:33:15.000000000 -0500 @@ -12025,7 +12025,7 @@

This feature is available in Postfix 2.3 and later.

-%PARAM milter_default_action tempfail +%PARAM milter_default_action see 'postconf -d milter_default_action' output

The default action when a Milter (mail filter) response is unavailable (for example, bad Postfix configuration or Milter @@ -12042,11 +12042,20 @@

tempfail
Reject all further commands in this session with a temporary status code.
+
shutdown
Close the SMTP connection after sending a 421 +SMTP reply. Available in Postfix 3.11, 3.10.8, 3.9.9, 3.8.15, 3.7.20, +and later.
+
quarantine
Like "accept", but freeze the message in the "hold" queue. Available with Postfix 2.6 and later.
+

The current default action is "shutdown", i.e. disconnect the +SMTP client. With the old "tempfail" default, Postfix could tempfail +all messages that the client sends over a long-lived connection, +even if a Milter failure is only temporary.

+

This feature is available in Postfix 2.3 and later.

%PARAM milter_connect_timeout 30s diff -ur --new-file /var/tmp/postfix-3.8.14/src/global/mail_params.h ./src/global/mail_params.h --- /var/tmp/postfix-3.8.14/src/global/mail_params.h 2025-08-18 16:34:03.000000000 -0400 +++ ./src/global/mail_params.h 2026-02-18 14:33:15.000000000 -0500 @@ -3492,7 +3492,7 @@ extern char *var_cleanup_milters; #define VAR_MILT_DEF_ACTION "milter_default_action" -#define DEF_MILT_DEF_ACTION "tempfail" +#define DEF_MILT_DEF_ACTION "shutdown" extern char *var_milt_def_action; #define VAR_MILT_CONN_MACROS "milter_connect_macros" @@ -3547,10 +3547,6 @@ #define DEF_MILT_PROTOCOL "6" extern char *var_milt_protocol; -#define VAR_MILT_DEF_ACTION "milter_default_action" -#define DEF_MILT_DEF_ACTION "tempfail" -extern char *var_milt_def_action; - #define VAR_MILT_DAEMON_NAME "milter_macro_daemon_name" #define DEF_MILT_DAEMON_NAME "$" VAR_MYHOSTNAME extern char *var_milt_daemon_name; diff -ur --new-file /var/tmp/postfix-3.8.14/src/milter/milter8.c ./src/milter/milter8.c --- /var/tmp/postfix-3.8.14/src/milter/milter8.c 2022-05-27 14:25:10.000000000 -0400 +++ ./src/milter/milter8.c 2026-02-18 14:33:15.000000000 -0500 @@ -523,6 +523,8 @@ } if (strcasecmp(milter->def_action, "accept") == 0) { reply = 0; + } else if (strcasecmp(milter->def_action, "shutdown") == 0) { + reply = "421 4.3.5 Server configuration problem - try again later"; } else if (strcasecmp(milter->def_action, "quarantine") == 0) { reply = "H"; } else { @@ -557,6 +559,8 @@ reply = "550 5.5.0 Service unavailable"; } else if (strcasecmp(milter->def_action, "tempfail") == 0) { reply = "451 4.7.1 Service unavailable - try again later"; + } else if (strcasecmp(milter->def_action, "shutdown") == 0) { + reply = "421 4.7.1 Service unavailable - try again later"; } else if (strcasecmp(milter->def_action, "quarantine") == 0) { reply = "H"; } else { diff -ur --new-file /var/tmp/postfix-3.8.14/src/util/msg_vstream.c ./src/util/msg_vstream.c --- /var/tmp/postfix-3.8.14/src/util/msg_vstream.c 2006-06-15 14:07:16.000000000 -0400 +++ ./src/util/msg_vstream.c 2026-02-18 14:33:15.000000000 -0500 @@ -80,6 +80,7 @@ msg_tag = name; msg_stream = vp; + vstream_no_debug(vp); if (first_call) { first_call = 0; msg_output(msg_vstream_print); diff -ur --new-file /var/tmp/postfix-3.8.14/src/util/vstream.c ./src/util/vstream.c --- /var/tmp/postfix-3.8.14/src/util/vstream.c 2021-08-14 19:00:02.000000000 -0400 +++ ./src/util/vstream.c 2026-02-18 14:33:15.000000000 -0500 @@ -166,6 +166,9 @@ /* int vstream_fstat(stream, flags) /* VSTREAM *stream; /* int flags; +/* +/* void vstream_no_debug(stream) +/* VSTREAM *stream; /* DESCRIPTION /* The \fIvstream\fR module implements light-weight buffered I/O /* similar to the standard I/O routines. @@ -494,6 +497,10 @@ /* .IP VSTREAM_FLAG_OWN_VSTRING /* The stream 'owns' the VSTRING buffer, and is responsible /* for cleaning up when the stream is closed. +/* +/* vstream_no_debug() disables 'spontaneous' logging of output +/* activity on the last specified VSTREAM, to prevent recursive +/* logging. /* DIAGNOSTICS /* Panics: interface violations. Fatal errors: out of memory. /* SEE ALSO @@ -673,6 +680,8 @@ } \ } while (0) +static VSTREAM *vstream_log_veto; + /* vstream_buf_init - initialize buffer */ static void vstream_buf_init(VBUF *bp, int flags) @@ -770,7 +779,7 @@ used = bp->len - bp->cnt; left_over = used - to_flush; - if (msg_verbose > 2 && stream != VSTREAM_ERR) + if (msg_verbose > 2 && stream != vstream_log_veto) msg_info("%s: fd %d flush %ld", myname, stream->fd, (long) to_flush); if (to_flush < 0 || left_over < 0) msg_panic("%s: bad to_flush %ld", myname, (long) to_flush); @@ -833,7 +842,7 @@ } } } - if (msg_verbose > 2 && stream != VSTREAM_ERR && n != to_flush) + if (msg_verbose > 2 && stream != vstream_log_veto && n != to_flush) msg_info("%s: %d flushed %ld/%ld", myname, stream->fd, (long) n, (long) to_flush); } @@ -1858,6 +1867,13 @@ return (stream); } +/* vstream_no_debug - debug logging lockout */ + +void vstream_no_debug(VSTREAM *stream) +{ + vstream_log_veto = stream; +} + #ifdef TEST static void copy_line(ssize_t bufsize) diff -ur --new-file /var/tmp/postfix-3.8.14/src/util/vstream.h ./src/util/vstream.h --- /var/tmp/postfix-3.8.14/src/util/vstream.h 2021-08-08 08:25:14.000000000 -0400 +++ ./src/util/vstream.h 2026-02-18 14:33:15.000000000 -0500 @@ -274,6 +274,11 @@ vstream_memreopen((VSTREAM *) 0, (string), (flags)) VSTREAM *vstream_memreopen(VSTREAM *, struct VSTRING *, int); + /* + * Debug logging lockout. + */ +extern void vstream_no_debug(VSTREAM *); + /* LICENSE /* .ad /* .fi