]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.9-20240112
authorWietse Venema <wietse@porcupine.org>
Fri, 12 Jan 2024 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Sat, 13 Jan 2024 15:28:18 +0000 (10:28 -0500)
postfix/HISTORY
postfix/proto/stop
postfix/proto/stop.double-cc
postfix/proto/stop.double-history
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/smtpd/smtpd.c

index ae06945e0382755b3b9385524303b82c7e3e3617..ac672bcdd10c300b47997f354e403aac1f167c43 100644 (file)
@@ -27709,3 +27709,9 @@ Apologies for any names omitted.
        and "reject" are now more similar. Both now unconditionally
        require the standard End-of-DATA sequence <CR><LF>.<CR><LF>.
        Files: smtpd/smtpd.c, proto/postconf.proto, RELEASE_NOTES.
+
+20240112
+
+       Cleanup: updated comments and identifiers because the bare
+       newline handling has evolved. Files: global/smtp_stream.[hc],
+       Files: global/smtp_stream.[hc], smtpd/smtpd.c.
index efdde6354da0ad15e69efdc2ae2643d70150fc87..eb2bf06c0de75085908a0a774f0bf6ab6b807eaf 100644 (file)
@@ -1591,3 +1591,4 @@ ENVID
 netcat
 probers
 lf
+EOD
index 8efd133ee306395bba269298ce58fde427741e02..bff4534d17e4ad78f07e758f6d737ba471365293 100644 (file)
@@ -333,3 +333,5 @@ void  void cleanup_milter_receive state count
  Available in in Postfix version 2 3 3 7 
 length  length of 0 31 0 127 
 address  address string length 
+ whether the standard End of DATA sequence CRLF CRLF is required and
+ Require CRLF CRLF 
index eff21250f283fc301a13f8bd179f2969412b4513..98da7a09870bc6cac7cc1ba76f1b427fe94b6e7b 100644 (file)
@@ -93,3 +93,6 @@ proto  proto aliases proto virtual proto ADDRESS_REWRITING_README html
  CR LF CR CR LF There is no smuggling vulnerability
  sequence mail systems send CR LF CR CR LF instead 
  global mail_params h cleanup cleanup c cleanup cleanup_message c 
+ Files smtpd smtpd c proto postconf proto RELEASE_NOTES 
+ stable releases Files global smtp_stream hc smtpd smtpd c
+ Files global smtp_stream hc smtpd smtpd c 
index 38d4cf83b4e10d3e9ddbf3ed6cc54f9c5125c0bf..fcfea29e6082ad552017886eb6be1a7d9b9bf592 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      "20240110"
+#define MAIL_RELEASE_DATE      "20240112"
 #define MAIL_VERSION_NUMBER    "3.9"
 
 #ifdef SNAPSHOT
index 07cba37adf2aaccdb0fccb9421e0537a8b94b8ee..662950803ac280337e2973b8e7231260872fa76f 100644 (file)
@@ -53,8 +53,8 @@
 /*     char    *format;
 /*     va_list ap;
 /*
-/*     int     smtp_forbid_bare_lf;
-/*     int     smtp_detected_bare_lf;
+/*     int     smtp_detect_bare_lf;
+/*     int     smtp_got_bare_lf;
 /* AUXILIARY API
 /*     int     smtp_get_noexcept(vp, stream, maxlen, flags)
 /*     VSTRING *vp;
 /*     smtp_get_noexcept() implements the subset of smtp_get()
 /*     without timeouts and without making long jumps. Instead,
 /*     query the stream status with vstream_feof() etc.
-/*     This function will set smtp_detected_bare_lf when flagging
-/*     input with a bare newline byte.
+/*
+/*     This function assigns smtp_got_bare_lf = smtp_detect_bare_lf,
+/*     if smtp_detect_bare_lf is non-zero and the last read line
+/*     was terminated with a bare newline. Otherwise, this function
+/*     sets smtp_got_bare_lf to zero.
 /*
 /*     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 set smtp_detected_bare_lf when the line that was read
-/*     last ended with a bare newline byte.
 /* DIAGNOSTICS
 /* .fi
 /* .ad
   * the buffer. Such system calls would really hurt when receiving or sending
   * body content one line at a time.
   */
-int     smtp_forbid_bare_lf;
-int     smtp_detected_bare_lf;
+int     smtp_detect_bare_lf;
+int     smtp_got_bare_lf;
 
 /* smtp_timeout_reset - reset per-stream error flags */
 
@@ -387,7 +386,7 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
     int     last_char;
     int     next_char;
 
-    smtp_detected_bare_lf = 0;
+    smtp_got_bare_lf = 0;
 
     /*
      * It's painful to do I/O with records that may span multiple buffers.
@@ -431,9 +430,9 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
         */
     case '\n':
        vstring_truncate(vp, VSTRING_LEN(vp) - 1);
-       if (smtp_forbid_bare_lf) {
+       if (smtp_detect_bare_lf) {
            if (VSTRING_LEN(vp) == 0 || vstring_end(vp)[-1] != '\r')
-               smtp_detected_bare_lf = smtp_forbid_bare_lf;
+               smtp_got_bare_lf = smtp_detect_bare_lf;
            else
                vstring_truncate(vp, VSTRING_LEN(vp) - 1);
        } else {
index 3e1f711086b1326fab8b16a95197a8590f3ad24c..2cf011a55f0ba45dfedd0938b5a15ca8567bcf9e 100644 (file)
@@ -43,8 +43,8 @@ extern void smtp_fputs(const char *, ssize_t len, VSTREAM *);
 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_detected_bare_lf;
+extern int smtp_detect_bare_lf;
+extern int smtp_got_bare_lf;
 
 extern void smtp_vprintf(VSTREAM *, const char *, va_list);
 
index b798f7bdee808124ed09737bbe8e7f21eaa7ce06..9cc8c0c81940cc2cc539b3339ffa6d598d14fc13 100644 (file)
@@ -1651,18 +1651,35 @@ static DICT *smtpd_cmd_filter;
 int     smtpd_hfrom_format;
 
  /*
-  * Bare newline handling.
+  * Bare LF and End-of-DATA controls (bare CR is handled elsewhere).
+  * 
+  * At the smtp_get*() line reader level, setting any of these flags in the
+  * smtp_detect_bare_lf variable enables the detection of bare newlines. The
+  * line reader will set the same flags in the smtp_got_bare_lf variable
+  * after it detects a bare newline, otherwise it clears smtp_got_bare_lf.
+  * 
+  * At the SMTP command level, the flags in smtp_got_bare_lf control whether
+  * commands ending in a bare newline are rejected.
+  * 
+  * At the DATA and BDAT content level, the flags in smtp_got_bare_lf control
+  * whether the standard End-of-DATA sequence CRLF.CRLF is required, and
+  * whether lines ending in bare newlines are rejected.
+  * 
+  * Postfix implements "delayed reject" after detecting a bare newline in BDAT
+  * or DATA content. The SMTP server delays a REJECT response until the
+  * command is finished, instead of replying and hanging up immediately. The
+  * End-of-DATA detection is secured with BARE_LF_FLAG_WANT_STD_EOD.
   */
-#define BARE_LF_FLAG_NORMALIZE (1<<0)  /* Best effort */
-#define BARE_LF_FLAG_REJECT    (1<<1)  /* Purist */
+#define BARE_LF_FLAG_WANT_STD_EOD      (1<<0)  /* Require CRLF.CRLF */
+#define BARE_LF_FLAG_REPLY_REJECT      (1<<1)  /* Reject bare newline */
 
-#define IS_BARE_LF_REJECT(m)   ((m) & BARE_LF_FLAG_REJECT)
-#define IS_BARE_LF_DETECT(m)   ((m) != 0)
+#define IS_BARE_LF_WANT_STD_EOD(m)     ((m) & BARE_LF_FLAG_WANT_STD_EOD)
+#define IS_BARE_LF_REPLY_REJECT(m)     ((m) & BARE_LF_FLAG_REPLY_REJECT)
 
-static const NAME_CODE bare_lf_masks[] = {
-    "normalize", BARE_LF_FLAG_NORMALIZE,
-    "yes", BARE_LF_FLAG_NORMALIZE,
-    "reject", BARE_LF_FLAG_REJECT,
+static const NAME_CODE bare_lf_mask_table[] = {
+    "normalize", BARE_LF_FLAG_WANT_STD_EOD,    /* The new default */
+    "yes", BARE_LF_FLAG_WANT_STD_EOD,  /* Migration aid */
+    "reject", BARE_LF_FLAG_WANT_STD_EOD | BARE_LF_FLAG_REPLY_REJECT,
     "no", 0,
     0, -1,                             /* error */
 };
@@ -3622,8 +3639,7 @@ static void receive_data_message(SMTPD_STATE *state,
     int     curr_rec_type;
     int     prev_rec_type;
     int     first = 1;
-    int     prev_detected_bare_lf = 0;
-    int     require_crlf_dot_crlf = IS_BARE_LF_DETECT(smtp_forbid_bare_lf);
+    int     prev_got_bare_lf = 0;
 
     /*
      * If deadlines are enabled, increase the time budget as message content
@@ -3645,13 +3661,13 @@ static void receive_data_message(SMTPD_STATE *state,
      * because sendmail permits it.
      */
     for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type,
-        prev_detected_bare_lf = smtp_detected_bare_lf) {
+        prev_got_bare_lf = smtp_got_bare_lf) {
        if (smtp_get(state->buffer, state->client, var_line_limit,
                     SMTP_GET_FLAG_NONE) == '\n')
            curr_rec_type = REC_TYPE_NORM;
        else
            curr_rec_type = REC_TYPE_CONT;
-       if (IS_BARE_LF_REJECT(smtp_detected_bare_lf))
+       if (IS_BARE_LF_REPLY_REJECT(smtp_got_bare_lf))
            state->err |= CLEANUP_STAT_BARE_LF;
        start = vstring_str(state->buffer);
        len = VSTRING_LEN(state->buffer);
@@ -3666,8 +3682,9 @@ static void receive_data_message(SMTPD_STATE *state,
                out_record(out_stream, REC_TYPE_NORM, "", 0);
        }
        if (prev_rec_type != REC_TYPE_CONT && *start == '.') {
-           if (len == 1 && require_crlf_dot_crlf
-               && (smtp_detected_bare_lf || prev_detected_bare_lf))
+           if (len == 1 && IS_BARE_LF_WANT_STD_EOD(smtp_detect_bare_lf)
+               && (smtp_got_bare_lf || prev_got_bare_lf))
+               /* Do not store or send to proxy filter. */
                continue;
            if (proxy == 0 ? (++start, --len) == 0 : len == 1)
                break;
@@ -4153,7 +4170,7 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                /* Skip the out_record() and VSTRING_RESET() calls below. */
                break;
            }
-           if (IS_BARE_LF_REJECT(smtp_detected_bare_lf))
+           if (IS_BARE_LF_REPLY_REJECT(smtp_got_bare_lf))
                state->err |= CLEANUP_STAT_BARE_LF;
            start = vstring_str(state->bdat_get_buffer);
            len = VSTRING_LEN(state->bdat_get_buffer);
@@ -4806,7 +4823,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      */
     xclient_allowed =
        namadr_list_match(xclient_hosts, state->name, state->addr);
-    smtp_forbid_bare_lf = (SMTPD_STAND_ALONE((state)) == 0 && bare_lf_mask
+    smtp_detect_bare_lf = (SMTPD_STAND_ALONE((state)) == 0 && bare_lf_mask
            && !namadr_list_match(bare_lf_excl, state->name, state->addr)) ?
        bare_lf_mask : 0;
     /* NOT: tls_reset() */
@@ -5850,7 +5867,7 @@ static void smtpd_proto(SMTPD_STATE *state)
            }
            watchdog_pat();
            smtpd_chat_query(state);
-           if (IS_BARE_LF_REJECT(smtp_detected_bare_lf)) {
+           if (IS_BARE_LF_REPLY_REJECT(smtp_got_bare_lf)) {
                log_whatsup(state, "reject", "bare <LF> received");
                state->error_mask |= MAIL_ERROR_PROTOCOL;
                smtpd_chat_reply(state, "%d 5.5.2 %s Error: bare <LF> received",
@@ -6206,9 +6223,9 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
        namadr_list_match(xforward_hosts, state.name, state.addr);
 
     /*
-     * Enforce strict SMTP line endings, with compatibility exclusions.
+     * Reject or normalize bare LF, with compatibility exclusions.
      */
-    smtp_forbid_bare_lf = (SMTPD_STAND_ALONE((&state)) == 0 && bare_lf_mask
+    smtp_detect_bare_lf = (SMTPD_STAND_ALONE((&state)) == 0 && bare_lf_mask
              && !namadr_list_match(bare_lf_excl, state.name, state.addr)) ?
        bare_lf_mask : 0;
 
@@ -6277,7 +6294,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
                                    MATCH_FLAG_RETURN
                                    | match_parent_style(VAR_MYNETWORKS),
                                    var_smtpd_forbid_bare_lf_excl);
-    if ((bare_lf_mask = name_code(bare_lf_masks, NAME_CODE_FLAG_NONE,
+    if ((bare_lf_mask = name_code(bare_lf_mask_table, NAME_CODE_FLAG_NONE,
                                  var_smtpd_forbid_bare_lf)) < 0)
        msg_fatal("bad parameter value: '%s = %s'",
                  VAR_SMTPD_FORBID_BARE_LF, var_smtpd_forbid_bare_lf);