]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.9-20231226
authorWietse Venema <wietse@porcupine.org>
Tue, 26 Dec 2023 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Thu, 28 Dec 2023 07:18:53 +0000 (02:18 -0500)
postfix/HISTORY
postfix/src/global/cleanup_strerror.c
postfix/src/global/cleanup_user.h
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/smtpd/smtpd.c

index 380b8776547901e9cf5b913a443698dea2d40651..b16cdc2eda23199a354a7ca716d66651fa5929cf 100644 (file)
@@ -27644,17 +27644,11 @@ Apologies for any names omitted.
        mantools/postlink, proto/postconf.proto, global/mail_params.h,
        global/smtp_stream.c, global/smtp_stream.h, smtpd/smtpd.c.
 
-20231222
+20231226
 
-       Workaround: smtpd_forbid_bare_newline broke the BDAT command.
-       File: smtpd/smtpd.c.
-
-20231123
-
-       Bugfix: smtpd_forbid_bare_newline_exclusions should respect
-       XCLIENT overrides. File: smtpd/smtpd.c.
-
-20231224
-
-       Reverted change 20231221 and adopted a fix by Viktor. File:
-       smtpd/smtpd.c.
+       Cleanup: a nicer implementation of smtpd_forbid_bare_newline
+       that does not hang up the the middle of a BDAT or DATA
+       command, and that optionally includes the offending command
+       sequence in a postmaster 'protocol' notification. Files:
+       smtpd/smtpd.c, global/stp_stream.[hc], global/cleanup_user.h,
+       global/cleanup_strerror.c.
index 74a9406dae23b6169622ff441c512277d1ac5a12..09a06663efdaafc91dbb701936bae5eb2bf109d9 100644 (file)
@@ -73,6 +73,7 @@ static const CLEANUP_STAT_DETAIL cleanup_stat_map[] = {
     CLEANUP_STAT_CONT, 550, "5.7.1", "message content rejected",
     CLEANUP_STAT_WRITE, 451, "4.3.0", "queue file write error",
     CLEANUP_STAT_NOPERM, 550, "5.7.1", "service denied",
+    CLEANUP_STAT_BARE_LF, 521, "5.5.2", "bare <LF> received",
 };
 
 static CLEANUP_STAT_DETAIL cleanup_stat_success = {
index d02e9cbfe2e2c21c1abf6ef8d1b7d6e889deaa1b..9bc0b9db414bd659abc2a56921d623e635ea2cbe 100644 (file)
 #define CLEANUP_STAT_DEFER     (1<<8)  /* Temporary reject */
 #define CLEANUP_STAT_NOPERM    (1<<9)  /* Denied by non-content policy */
 
+ /*
+  * Non-cleanup errors that live in the same bitmask space, to centralize
+  * error handling.
+  */
+#define CLEANUP_STAT_BARE_LF   (1<<16) /* Bare <LF> received */
+
  /*
   * These are set when we can't bounce even if we were asked to.
   */
index 97edb7eec679684a8f74a1d7c38965fe1f2f4db1..013508eacca8b0414da5e1bf50e993fed48e3ace 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20231224"
+#define MAIL_RELEASE_DATE      "20231226"
 #define MAIL_VERSION_NUMBER    "3.9"
 
 #ifdef SNAPSHOT
index b7209009d2f36aff8021d3b7f16a8ccfa091a7b6..dccf279a711b2b1ef3e671de71ebfc03692cbb41 100644 (file)
@@ -54,6 +54,7 @@
 /*     va_list ap;
 /*
 /*     int     smtp_forbid_bare_lf;
+/*     int     smtp_seen_bare_lf;
 /* AUXILIARY API
 /*     int     smtp_get_noexcept(vp, stream, maxlen, flags)
 /*     VSTRING *vp;
 /*     smtp_vprintf() is the machine underneath smtp_printf().
 /*
 /*     smtp_get_noexcept() implements the subset of smtp_get()
-/*     without long jumps for timeout or EOF errors. Instead,
+/*     without timeouts and without making long jumps. Instead
 /*     query the stream status with vstream_feof() etc.
-/*     This function will make a VSTREAM long jump (error code
-/*     SMTP_ERR_LF) when rejecting input with a bare newline byte.
+/*     This function will set smtp_forbid_bare_lf when flagging
+/*     input with a bare newline byte.
 /*
 /*     smtp_timeout_setup() is a backwards-compatibility interface
 /*     for programs that don't require deadline or data-rate support.
 /*
 /*     smtp_forbid_bare_lf controls whether smtp_get_noexcept()
-/*     will reject input with a bare newline byte.
+/*     will set smtp_seen_bare_lf when the line that was read last
+/*     ended with a bare newline byte.
 /* DIAGNOSTICS
 /* .fi
 /* .ad
   * body content one line at a time.
   */
 int     smtp_forbid_bare_lf;
+int     smtp_seen_bare_lf;
 
 /* smtp_timeout_reset - reset per-stream error flags */
 
@@ -384,6 +387,8 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
     int     last_char;
     int     next_char;
 
+    smtp_seen_bare_lf = 0;
+
     /*
      * It's painful to do I/O with records that may span multiple buffers.
      * Allow for partial long lines (we will read the remainder later) and
@@ -428,7 +433,7 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
        vstring_truncate(vp, VSTRING_LEN(vp) - 1);
        if (smtp_forbid_bare_lf
            && (VSTRING_LEN(vp) == 0 || vstring_end(vp)[-1] != '\r'))
-           vstream_longjmp(stream, SMTP_ERR_LF);
+           smtp_seen_bare_lf = 1;
        while (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r')
            vstring_truncate(vp, VSTRING_LEN(vp) - 1);
        VSTRING_TERMINATE(vp);
index 4bcd6b59bd481682b6bab5865517c62dcbf1781b..1a894685c8b3acc0bc500d77549c5caaef0c7944 100644 (file)
@@ -32,7 +32,6 @@
 #define SMTP_ERR_QUIET 3               /* silent cleanup (application) */
 #define SMTP_ERR_NONE  4               /* non-error case */
 #define SMTP_ERR_DATA  5               /* application data error */
-#define SMTP_ERR_LF    6               /* bare <LF> protocol error */
 
 extern void smtp_stream_setup(VSTREAM *, int, int, int);
 extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
@@ -45,6 +44,7 @@ extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *);
 extern void smtp_fread_buf(VSTRING *, ssize_t len, VSTREAM *);
 extern void smtp_fputc(int, VSTREAM *);
 extern int smtp_forbid_bare_lf;
+extern int smtp_seen_bare_lf;
 
 extern void smtp_vprintf(VSTREAM *, const char *, va_list);
 
index f40070cc4939cadcfb6dd53b63d9b39ec4359de0..f3ab0305dc998d68760226ede966d2dbf76280f7 100644 (file)
@@ -1620,7 +1620,6 @@ static void tls_reset(SMTPD_STATE *);
 #define REASON_TIMEOUT         "timeout"
 #define REASON_LOST_CONNECTION "lost connection"
 #define REASON_ERROR_LIMIT     "too many errors"
-#define REASON_BARE_LF         "bare <LF> received"
 
 #ifdef USE_TLS
 
@@ -3625,6 +3624,8 @@ static void receive_data_message(SMTPD_STATE *state,
            curr_rec_type = REC_TYPE_NORM;
        else
            curr_rec_type = REC_TYPE_CONT;
+       if (smtp_seen_bare_lf)
+           state->err |= CLEANUP_STAT_BARE_LF;
        start = vstring_str(state->buffer);
        len = VSTRING_LEN(state->buffer);
        if (first) {
@@ -3792,6 +3793,12 @@ static int common_post_message_handling(SMTPD_STATE *state)
        else
            smtpd_chat_reply(state,
                             "250 2.0.0 Ok: queued as %s", state->queue_id);
+    } else if ((state->err & CLEANUP_STAT_BARE_LF) != 0) {
+       /* Disconnect immediately. */
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       msg_info("disconnect: bare <LF> received from %s", state->namaddr);
+       smtpd_chat_reply(state, "521 5.5.2 %s Error: bare <LF> received",
+                        var_myhostname);
     } else if (why && IS_SMTP_REJECT(STR(why))) {
        state->error_mask |= MAIL_ERROR_POLICY;
        smtpd_chat_reply(state, "%s", STR(why));
@@ -4079,7 +4086,6 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      */
     done = 0;
     do {
-       int     payload_err;
 
        /*
         * Do not skip the smtp_fread_buf() call if read_len == 0. We still
@@ -4093,10 +4099,6 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtp_fread_buf(state->buffer, read_len, state->client);
        state->bdat_get_stream = vstream_memreopen(
                           state->bdat_get_stream, state->buffer, O_RDONLY);
-        vstream_control(state->bdat_get_stream, CA_VSTREAM_CTL_EXCEPT,
-                        CA_VSTREAM_CTL_END);
-        if ((payload_err = vstream_setjmp(state->bdat_get_stream)) != 0)
-            vstream_longjmp(state->client, payload_err);
 
        /*
         * Read lines from the fragment. The last line may continue in the
@@ -4104,9 +4106,9 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
         */
        do {
            if (smtp_get_noexcept(state->bdat_get_buffer,
-                                     state->bdat_get_stream,
-                                     var_line_limit,
-                                     SMTP_GET_FLAG_APPEND) == '\n') {
+                                 state->bdat_get_stream,
+                                 var_line_limit,
+                                 SMTP_GET_FLAG_APPEND) == '\n') {
                /* Stopped at end-of-line. */
                curr_rec_type = REC_TYPE_NORM;
            } else if (!vstream_feof(state->bdat_get_stream)) {
@@ -4121,6 +4123,8 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                /* Skip the out_record() and VSTRING_RESET() calls below. */
                break;
            }
+           if (smtp_seen_bare_lf)
+               state->err |= CLEANUP_STAT_BARE_LF;
            start = vstring_str(state->bdat_get_buffer);
            len = VSTRING_LEN(state->bdat_get_buffer);
            if (state->err == CLEANUP_STAT_OK) {
@@ -5597,13 +5601,6 @@ static void smtpd_proto(SMTPD_STATE *state)
                             var_myhostname);
        break;
 
-    case SMTP_ERR_LF:
-       state->reason = REASON_BARE_LF;
-       if (vstream_setjmp(state->client) == 0)
-           smtpd_chat_reply(state, "521 5.5.2 %s Error: bare <LF> received",
-                            var_myhostname);
-       break;
-
     case 0:
 
        /*
@@ -5823,6 +5820,15 @@ static void smtpd_proto(SMTPD_STATE *state)
            }
            watchdog_pat();
            smtpd_chat_query(state);
+           if (smtp_seen_bare_lf) {
+               msg_info("disconnect: bare <LF> received from %s",
+                        state->namaddr);
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               smtpd_chat_reply(state,
+                                "521 5.5.2 %s Error: bare <LF> received",
+                                var_myhostname);
+               break;
+           }
            /* Safety: protect internal interfaces against malformed UTF-8. */
            if (var_smtputf8_enable
                && valid_utf8_stringz(STR(state->buffer)) == 0) {