Reject "dot, LF" as ending data phase. Bug 3063
[exim.git] / src / src / receive.c
index 041898a6bd66a93db12a189778fd06863b682275..c6f6128327f20aaa221e83947f2c30c99492d4aa 100644 (file)
@@ -137,9 +137,9 @@ Returns:    TRUE for a trusted caller
 */
 
 BOOL
-receive_check_set_sender(uschar *newsender)
+receive_check_set_sender(const uschar * newsender)
 {
-uschar *qnewsender;
+const uschar * qnewsender;
 if (f.trusted_caller) return TRUE;
 if (!newsender || !untrusted_set_sender) return FALSE;
 qnewsender = Ustrchr(newsender, '@')
@@ -514,7 +514,7 @@ Returns:      nothing
 */
 
 void
-receive_add_recipient(uschar * recipient, int pno)
+receive_add_recipient(const uschar * recipient, int pno)
 {
 if (recipients_count >= recipients_list_max)
   {
@@ -591,7 +591,7 @@ Returns:      TRUE if it did remove something; FALSE otherwise
 */
 
 BOOL
-receive_remove_recipient(uschar *recipient)
+receive_remove_recipient(const uschar * recipient)
 {
 DEBUG(D_receive) debug_printf("receive_remove_recipient(\"%s\") called\n",
   recipient);
@@ -1960,8 +1960,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;
     }
 
@@ -1970,6 +1972,7 @@ for (;;)
   This implements the dot-doubling rule, though header lines starting with
   dots aren't exactly common. They are legal in RFC 822, though. If the
   following is CRLF or LF, this is the line that that terminates the
+
   entire message. We set message_ended to indicate this has happened (to
   prevent further reading), and break out of the loop, having freed the
   empty header, and set next = NULL to indicate no data line. */
@@ -1977,7 +1980,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')
@@ -2013,7 +2020,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;
       }
 
@@ -3600,7 +3608,7 @@ else
       /* Loop through recipients, responses must be in same order received */
       for (unsigned int c = 0; recipients_count > c; c++)
         {
-       uschar * addr= recipients_list[c].address;
+       const uschar * addr = recipients_list[c].address;
        uschar * msg= US"PRDR R=<%s> %s";
        uschar * code;
         DEBUG(D_receive)
@@ -4391,7 +4399,7 @@ data file will be flushed(!) out thereby. Nevertheless, it is theoretically
 possible for fclose() to fail - and this has been seen on obscure filesystems
 (probably one that delayed the actual media write as long as possible)
 but what to do? What has happened to the lock if this happens?
-It's a mes because we already logged the acceptance.
+It's a mess because we already logged the acceptance.
 We can at least log the issue, try to remove spoolfiles and respond with
 a temp-reject.  We do not want to close before logging acceptance because
 we want to hold the lock until we know that logging worked.
@@ -4425,8 +4433,8 @@ if (spool_data_file && cutthrough_done == NOT_TRIED)
     Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
     Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
 
-    /* Claim a data ACL temp-reject, just to get reject logging and resposponse */
-    smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg);
+    /* Claim a data ACL temp-reject, just to get reject logging and response */
+    if (smtp_input) smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg);
     smtp_reply = US"";         /* Indicate reply already sent */
 
     message_id[0] = 0;         /* no message accepted */