SPDX: Mass-update to GPL-2.0-or-later
[exim.git] / src / src / receive.c
index 058a74cb2bf0b36e2f8e3afd29df93bc2fd0f9e1..9bf834aafdc107c11f4744f7b34dede79ddc92cf 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* Code for receiving a message and setting up spool files. */
 
@@ -527,7 +528,7 @@ if (recipients_count >= recipients_list_max)
     }
 
   recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
-  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), FALSE);
+  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), GET_UNTAINTED);
   if (oldlist)
     memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
   }
@@ -967,7 +968,7 @@ Returns:    One of the END_xxx values indicating why it stopped reading
 */
 
 static int
-read_message_bdat_smtp(FILE *fout)
+read_message_bdat_smtp(FILE * fout)
 {
 int linelength = 0, ch;
 enum CH_STATE ch_state = LF_SEEN;
@@ -1073,7 +1074,7 @@ for(;;)
 }
 
 static int
-read_message_bdat_smtp_wire(FILE *fout)
+read_message_bdat_smtp_wire(FILE * fout)
 {
 int ch;
 
@@ -1760,17 +1761,18 @@ if (extract_recip || !smtp_input)
 header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
 pointing to the end of the chain to make adding headers simple. */
 
-received_header = header_list = header_last = store_get(sizeof(header_line), FALSE);
+received_header = header_list = header_last = store_get(sizeof(header_line), GET_UNTAINTED);
 header_list->next = NULL;
 header_list->type = htype_old;
 header_list->text = NULL;
 header_list->slen = 0;
 
-/* Control block for the next header to be read. */
+/* Control block for the next header to be read.
+The data comes from the message, so is tainted. */
 
 reset_point = store_mark();
-next = store_get(sizeof(header_line), FALSE);  /* not tainted */
-next->text = store_get(header_size, TRUE);     /* tainted */
+next = store_get(sizeof(header_line), GET_UNTAINTED);
+next->text = store_get(header_size, GET_TAINTED);
 
 /* Initialize message id to be null (indicating no message read), and the
 header names list to be the normal list. Indicate there is no data file open
@@ -1888,12 +1890,15 @@ for (;;)
   /* If we hit EOF on a SMTP connection, it's an error, since incoming
   SMTP must have a correct "." terminator. */
 
-  if (ch == EOF && smtp_input /* && !smtp_batched_input */)
-    {
-    smtp_reply = handle_lost_connection(US" (header)");
-    smtp_yield = FALSE;
-    goto TIDYUP;                       /* Skip to end of function */
-    }
+  if (smtp_input /* && !smtp_batched_input */)
+    if (ch == EOF)
+      {
+      smtp_reply = handle_lost_connection(US" (header)");
+      smtp_yield = FALSE;
+      goto TIDYUP;                       /* Skip to end of function */
+      }
+    else if (ch == ERR)
+      goto TIDYUP;
 
   /* See if we are at the current header's size limit - there must be at least
   four bytes left. This allows for the new character plus a zero, plus two for
@@ -1917,10 +1922,8 @@ for (;;)
       goto OVERSIZE;
     header_size *= 2;
 
-    /* The data came from the message, so is tainted. */
-
-    if (!store_extend(next->text, TRUE, oldsize, header_size))
-      next->text = store_newblock(next->text, TRUE, header_size, ptr);
+    if (!store_extend(next->text, oldsize, header_size))
+      next->text = store_newblock(next->text, header_size, ptr);
     }
 
   /* Cope with receiving a binary zero. There is dispute about whether
@@ -1935,7 +1938,7 @@ for (;;)
   those from data files use just LF. Treat LF in local SMTP input as a
   terminator too. Treat EOF as a line terminator always. */
 
-  if (ch == EOF) goto EOL;
+  if (ch < 0) goto EOL;
 
   /* FUDGE: There are sites out there that don't send CRs before their LFs, and
   other MTAs accept this. We are therefore forced into this "liberalisation"
@@ -1960,7 +1963,7 @@ for (;;)
   prevent further reading), and break out of the loop, having freed the
   empty header, and set next = NULL to indicate no data line. */
 
-  if (ptr == 0 && ch == '.' && f.dot_ends)
+  if (f.dot_ends && ptr == 0 && ch == '.')
     {
     ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
     if (ch == '\r')
@@ -1968,7 +1971,7 @@ for (;;)
       ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
       if (ch != '\n')
         {
-        receive_ungetc(ch);
+       if (ch >= 0) receive_ungetc(ch);
         ch = '\r';              /* Revert to CR */
         }
       }
@@ -2006,7 +2009,7 @@ for (;;)
     /* Otherwise, put back the character after CR, and turn the bare CR
     into LF SP. */
 
-    ch = (receive_ungetc)(ch);
+    if (ch >= 0) (receive_ungetc)(ch);
     next->text[ptr++] = '\n';
     message_size++;
     ch = ' ';
@@ -2090,7 +2093,7 @@ OVERSIZE:
   whitespace character. If it is, we have a continuation of this header line.
   There is always space for at least one character at this point. */
 
-  if (ch != EOF)
+  if (ch >= 0)
     {
     int nextch = (receive_getc)(GETC_BUFFER_UNLIMITED);
     if (nextch == ' ' || nextch == '\t')
@@ -2100,8 +2103,9 @@ OVERSIZE:
        goto OVERSIZE;
       continue;                      /* Iterate the loop */
       }
-    else if (nextch != EOF) (receive_ungetc)(nextch);   /* For next time */
-    else ch = EOF;                   /* Cause main loop to exit at end */
+    else if (nextch >= 0)      /* not EOF, ERR etc */
+      (receive_ungetc)(nextch);   /* For next time */
+    else ch = nextch;                   /* Cause main loop to exit at end */
     }
 
   /* We have got to the real line end. Terminate the string and release store
@@ -2203,7 +2207,7 @@ OVERSIZE:
 
   else
     {
-    uschar *p = next->text;
+    uschar * p = next->text;
 
     /* If not a valid header line, break from the header reading loop, leaving
     next != NULL, indicating that it holds the first line of the body. */
@@ -2301,16 +2305,22 @@ OVERSIZE:
     }
 
   /* The line has been handled. If we have hit EOF, break out of the loop,
-  indicating no pending data line. */
+  indicating no pending data line and no more data for the message */
 
-  if (ch == EOF) { next = NULL; break; }
+  if (ch < 0)
+    {
+    next = NULL;
+    if (ch == EOF)     message_ended = END_DOT;
+    else if (ch == ERR) message_ended = END_PROTOCOL;
+    break;
+    }
 
   /* Set up for the next header */
 
   reset_point = store_mark();
   header_size = 256;
-  next = store_get(sizeof(header_line), FALSE);
-  next->text = store_get(header_size, TRUE);
+  next = store_get(sizeof(header_line), GET_UNTAINTED);
+  next->text = store_get(header_size, GET_TAINTED);
   ptr = 0;
   had_zero = 0;
   prevlines_length = 0;
@@ -2333,14 +2343,21 @@ DEBUG(D_receive)
 /* End of file on any SMTP connection is an error. If an incoming SMTP call
 is dropped immediately after valid headers, the next thing we will see is EOF.
 We must test for this specially, as further down the reading of the data is
-skipped if already at EOF. */
+skipped if already at EOF.
+In CHUNKING mode, a protocol error makes us give up on the message. */
 
-if (smtp_input && (receive_feof)())
-  {
-  smtp_reply = handle_lost_connection(US" (after header)");
-  smtp_yield = FALSE;
-  goto TIDYUP;                       /* Skip to end of function */
-  }
+if (smtp_input)
+  if ((receive_feof)())
+    {
+    smtp_reply = handle_lost_connection(US" (after header)");
+    smtp_yield = FALSE;
+    goto TIDYUP;                       /* Skip to end of function */
+    }
+  else if (message_ended == END_PROTOCOL)
+    {
+    smtp_reply = US"";                 /* no reply needed */
+    goto TIDYUP;
+    }
 
 /* If this is a filter test run and no headers were read, output a warning
 in case there is a mistake in the test message. */
@@ -2594,7 +2611,7 @@ if (extract_recip)
         white space that follows the newline must not be removed - it is part
         of the header. */
 
-        pp = recipient = store_get(ss - s + 1, is_tainted(s));
+        pp = recipient = store_get(ss - s + 1, s);
         for (uschar * p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
         *pp = 0;
 
@@ -2626,7 +2643,7 @@ if (extract_recip)
         if (!recipient && Ustrcmp(errmess, "empty address") != 0)
           {
           int len = Ustrlen(s);
-          error_block *b = store_get(sizeof(error_block), FALSE);
+          error_block * b = store_get(sizeof(error_block), GET_UNTAINTED);
           while (len > 0 && isspace(s[len-1])) len--;
           b->next = NULL;
           b->text1 = string_printing(string_copyn(s, len));
@@ -2825,7 +2842,7 @@ function may mess with the real recipients. */
 
 if (LOGGING(received_recipients))
   {
-  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
+  raw_recipients = store_get(recipients_count * sizeof(uschar *), GET_UNTAINTED);
   for (int i = 0; i < recipients_count; i++)
     raw_recipients[i] = string_copy(recipients_list[i].address);
   raw_recipients_count = recipients_count;
@@ -4240,7 +4257,8 @@ if (  smtp_input && sender_host_address && !f.sender_host_notsocket
   if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0)
     {
     int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
-    if (c != EOF) (receive_ungetc)(c); else
+    if (c != EOF) (receive_ungetc)(c);
+    else
       {
       smtp_notquit_exit(US"connection-lost", NULL, NULL);
       smtp_reply = US"";    /* No attempt to send a response */