From f172a89c065d732898181b0b3f8e7abdae533d06 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Tue, 9 Jul 2024 10:44:57 +0800
Subject: [PATCH] Reject "dot, LF" as ending data phase. Bug 3063

---
 src/receive.c | 15 +++++++++++----
 src/smtp_in.c | 13 ++++++++-----
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/src/receive.c b/src/receive.c
index 0a27c79..8639fa9 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -1948,8 +1948,10 @@ for (;;)
 
   if (ch == '\n')
     {
-    if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = FALSE;
-      else if (first_line_ended_crlf) receive_ungetc(' ');
+    if (first_line_ended_crlf == TRUE_UNSET)
+      first_line_ended_crlf = FALSE;
+    else if (first_line_ended_crlf)
+      receive_ungetc(' ');
     goto EOL;
     }
 
@@ -1965,7 +1967,11 @@ for (;;)
   if (f.dot_ends && ptr == 0 && ch == '.')
     {
     ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
-    if (ch == '\r')
+    if (ch == '\n' && first_line_ended_crlf == TRUE /* and not TRUE_UNSET */ )
+    		/* dot, LF  but we are in CRLF mode.  Attack? */
+      ch = ' ';	/* replace the LF with a space */
+
+    else if (ch == '\r')
       {
       ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
       if (ch != '\n')
@@ -2001,7 +2007,8 @@ for (;;)
     ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
     if (ch == '\n')
       {
-      if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = TRUE;
+      if (first_line_ended_crlf == TRUE_UNSET)
+	first_line_ended_crlf = TRUE;
       goto EOL;
       }
 
diff --git a/src/smtp_in.c b/src/smtp_in.c
index edb0adf..3119bad 100644
--- a/src/smtp_in.c
+++ b/src/smtp_in.c
@@ -5432,15 +5432,18 @@ while (done <= 0)
 	}
 
       if (chunking_state > CHUNKING_OFFERED)
-	rc = OK;			/* No predata ACL or go-ahead output for BDAT */
+	rc = OK;	/* There is no predata ACL or go-ahead output for BDAT */
       else
 	{
-	/* If there is an ACL, re-check the synchronization afterwards, since the
-	ACL may have delayed.  To handle cutthrough delivery enforce a dummy call
-	to get the DATA command sent. */
+	/* If there is a predata-ACL, re-check the synchronization afterwards,
+	since the ACL may have delayed.  To handle cutthrough delivery enforce a
+	dummy call to get the DATA command sent. */
 
 	if (!acl_smtp_predata && cutthrough.cctx.sock < 0)
-	  rc = OK;
+    {
+       if (!check_sync()) goto SYNC_FAILURE;
+          rc = OK;
+    }
 	else
 	  {
 	  uschar * acl = acl_smtp_predata ? acl_smtp_predata : US"accept";
-- 
2.27.0

