]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.9.9 v3.9.9
authorWietse Z Venema <wietse@porcupine.org>
Wed, 18 Feb 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Thu, 19 Feb 2026 02:21:35 +0000 (13:21 +1100)
postfix/HISTORY
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/proto/postconf.proto
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/milter/milter8.c
postfix/src/util/msg_vstream.c
postfix/src/util/vstream.c
postfix/src/util/vstream.h

index f8585561080efee01b2d127979c4c65cfd712881..3cf6d402727f4db30eeb6cb41690597745843eed 100644 (file)
@@ -28261,3 +28261,24 @@ Apologies for any names omitted.
        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.
index d012b8d1749ef396252006f953f22dfede24acde..f90dbb8af6a794169b83302dc9cc3769239866c0 100644 (file)
@@ -7280,7 +7280,7 @@ for a list of available macro names and their meanings.  </p>
 </DD>
 
 <DT><b><a name="milter_default_action">milter_default_action</a>
-(default: tempfail)</b></DT><DD>
+(default: see 'postconf -d <a href="postconf.5.html#milter_default_action">milter_default_action</a>' output)</b></DT><DD>
 
 <p> The default action when a Milter (mail filter) response is
 unavailable (for example, bad Postfix configuration or Milter
@@ -7297,11 +7297,20 @@ with a permanent status code.</dd>
 <dt>tempfail</dt> <dd>Reject all further commands in this session
 with a temporary status code. </dd>
 
+<dt>shutdown</dt> <dd>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. </dd>
+
 <dt>quarantine</dt> <dd>Like "accept", but freeze the message in
 the "<a href="QSHAPE_README.html#hold_queue">hold" queue</a>. Available with Postfix 2.6 and later. </dd>
 
 </dl>
 
+<p> 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. </p>
+
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
index d8038c327afe057ffb5c794148d6df60f180304a..cf1a1287eee26872c9348f933cac56364f8e83bd 100644 (file)
@@ -4539,7 +4539,7 @@ filter) applications after the SMTP DATA command. See MILTER_README
 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:
@@ -4554,12 +4554,22 @@ with a permanent status code.
 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
index abd3924cbc162a318bb5adee37b2f0bb8ed28c95..8a3e4b3c7b95db753ef45371a0b9c675c4c76d13 100644 (file)
@@ -12187,7 +12187,7 @@ will not reply for each individual message header.</dd>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
-%PARAM milter_default_action tempfail
+%PARAM milter_default_action see 'postconf -d milter_default_action' output
 
 <p> The default action when a Milter (mail filter) response is
 unavailable (for example, bad Postfix configuration or Milter
@@ -12204,11 +12204,20 @@ with a permanent status code.</dd>
 <dt>tempfail</dt> <dd>Reject all further commands in this session
 with a temporary status code. </dd>
 
+<dt>shutdown</dt> <dd>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. </dd>
+
 <dt>quarantine</dt> <dd>Like "accept", but freeze the message in
 the "hold" queue. Available with Postfix 2.6 and later. </dd>
 
 </dl>
 
+<p> 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. </p>
+
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 %PARAM milter_connect_timeout 30s
index 7a3ce797fafd5a57cf60dc626d64c846f3cae1a1..e4ad40a6fa3bf12e31e108cfeb164952e03313e5 100644 (file)
@@ -3512,7 +3512,7 @@ extern char *var_smtpd_milter_maps;
 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"
@@ -3567,10 +3567,6 @@ extern int var_milt_msg_time;
 #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;
index acfd0bf1bc25e3d3aebf747649d493f3c2671ab3..0142198dcb5121886b16c846333d09cc04c7d4c1 100644 (file)
@@ -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.9.8"
+#define MAIL_RELEASE_DATE      "20260218"
+#define MAIL_VERSION_NUMBER    "3.9.9"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_DATE      "-" MAIL_RELEASE_DATE
index 6c9a1eec46f18951c0d9b1868577ee01bea75bc0..b504ffc059e4aae7af5ed74d51083ad23ed23cc3 100644 (file)
@@ -523,6 +523,8 @@ static int milter8_conf_error(MILTER8 *milter)
     }
     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 @@ static int milter8_comm_error(MILTER8 *milter)
        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 {
index b6e24e60902ca8bd80147e23815b2a16dcdf407a..3477b546b04b179af4b3803c599e1420a1e89b12 100644 (file)
@@ -80,6 +80,7 @@ void    msg_vstream_init(const char *name, VSTREAM *vp)
 
     msg_tag = name;
     msg_stream = vp;
+    vstream_no_debug(vp);
     if (first_call) {
        first_call = 0;
        msg_output(msg_vstream_print);
index affbcc0dfdacb002ec97ae3d397595075e138786..5acfb0f1023648c3d8d1a90e03435828a88ee1d2 100644 (file)
 /*     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.
 /* .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
@@ -674,6 +681,8 @@ VSTREAM vstream_fstd[] = {
        } \
     } while (0)
 
+static VSTREAM *vstream_log_veto;
+
 /* vstream_buf_init - initialize buffer */
 
 static void vstream_buf_init(VBUF *bp, int flags)
@@ -771,7 +780,7 @@ static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush)
     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);
@@ -834,7 +843,7 @@ static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush)
                }
            }
        }
-       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);
     }
@@ -1890,6 +1899,13 @@ VSTREAM *vstream_memreopen(VSTREAM *stream, VSTRING *string, int flags)
     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)
index 23688c745330da3fe951d4a969ee676f32e64dd5..d308253f87dcda1b63bdfde8b5af4eabc953e8a4 100644 (file)
@@ -274,6 +274,11 @@ extern int vstream_tweak_tcp(VSTREAM *);
        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