Fix parsing of cmdline -os & -pr options. Bug 2538
[exim.git] / src / src / receive.c
index ed2afb31748f148d537c6531895a68aba01ab755..8f3bfefacd162cfaaa75d85b0f765e0322983034 100644 (file)
@@ -14,9 +14,9 @@
 extern int dcc_ok;
 #endif
 
-#ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
 # include "dmarc.h"
-#endif /* EXPERIMENTAL_DMARC */
+#endif
 
 /*************************************************
 *                Local static variables          *
@@ -489,7 +489,7 @@ if (recipients_count >= recipients_list_max)
   recipient_item *oldlist = recipients_list;
   int oldmax = recipients_list_max;
   recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
-  recipients_list = store_get(recipients_list_max * sizeof(recipient_item));
+  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), FALSE);
   if (oldlist != NULL)
     memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
   }
@@ -645,6 +645,11 @@ if (!f.dot_ends)
   {
   int last_ch = '\n';
 
+/*XXX we do a gettimeofday before checking for every received char,
+which is hardly clever.  The function-indirection doesn't help, but
+an additional function to check for nonempty read buffer would help.
+See stdin_getc() / smtp_getc() / tls_getc() / bdat_getc(). */
+
   for ( ;
        log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF;
        last_ch = ch)
@@ -1343,7 +1348,7 @@ if (received_protocol)
 if (LOGGING(pipelining) && f.smtp_in_pipelining_advertised)
   {
   g = string_catn(g, US" L", 2);
-#ifdef SUPPORT_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
   if (f.smtp_in_early_pipe_used)
     g = string_catn(g, US"*", 1);
   else if (f.smtp_in_early_pipe_advertised)
@@ -1399,6 +1404,7 @@ for (header_line * my_headerlist = header_list; my_headerlist;
     goto DO_MIME_ACL;
     }
 
+mime_part_count = -1;
 DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
 return TRUE;
 
@@ -1677,6 +1683,7 @@ uschar *frozen_by = NULL;
 uschar *queued_by = NULL;
 
 uschar *errmsg;
+rmark rcvd_log_reset_point;
 gstring * g;
 struct stat statbuf;
 
@@ -1687,6 +1694,7 @@ uschar *user_msg, *log_msg;
 
 /* Working header pointers */
 
+rmark reset_point;
 header_line *next;
 
 /* Flags for noting the existence of certain headers (only one left) */
@@ -1701,10 +1709,6 @@ header_line *msgid_header = NULL;
 header_line *received_header;
 BOOL msgid_header_newly_created = FALSE;
 
-#ifdef EXPERIMENTAL_DMARC
-int dmarc_up = 0;
-#endif /* EXPERIMENTAL_DMARC */
-
 /* Variables for use when building the Received: header. */
 
 uschar *timestamp;
@@ -1727,7 +1731,7 @@ 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));
+received_header = header_list = header_last = store_get(sizeof(header_line), FALSE);
 header_list->next = NULL;
 header_list->type = htype_old;
 header_list->text = NULL;
@@ -1735,8 +1739,9 @@ header_list->slen = 0;
 
 /* Control block for the next header to be read. */
 
-next = store_get(sizeof(header_line));
-next->text = store_get(header_size);
+reset_point = store_mark();
+next = store_get(sizeof(header_line), FALSE);  /* not tainted */
+next->text = store_get(header_size, TRUE);     /* 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
@@ -1757,6 +1762,13 @@ if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX;
 message_linecount = body_linecount = body_zerocount =
   max_received_linelength = 0;
 
+#ifdef WITH_CONTENT_SCAN
+/* reset non-per-part mime variables */
+mime_is_coverletter    = 0;
+mime_is_rfc822         = 0;
+mime_part_count        = -1;
+#endif
+
 #ifndef DISABLE_DKIM
 /* Call into DKIM to set up the context.  In CHUNKING mode
 we clear the dot-stuffing flag */
@@ -1764,9 +1776,8 @@ if (smtp_input && !smtp_batched_input && !f.dkim_disable_verify)
   dkim_exim_verify_init(chunking_state <= CHUNKING_OFFERED);
 #endif
 
-#ifdef EXPERIMENTAL_DMARC
-/* initialize libopendmarc */
-dmarc_up = dmarc_init();
+#ifdef SUPPORT_DMARC
+if (sender_host_address) dmarc_init(); /* initialize libopendmarc */
 #endif
 
 /* Remember the time of reception. Exim uses time+pid for uniqueness of message
@@ -1854,8 +1865,10 @@ for (;;)
       goto OVERSIZE;
     header_size *= 2;
 
-    if (!store_extend(next->text, oldsize, header_size))
-      next->text = store_newblock(next->text, header_size, ptr);
+    /* 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);
     }
 
   /* Cope with receiving a binary zero. There is dispute about whether
@@ -1910,7 +1923,7 @@ for (;;)
     if (ch == '\n')
       {
       message_ended = END_DOT;
-      store_reset(next);
+      reset_point = store_reset(reset_point);
       next = NULL;
       break;                    /* End character-reading loop */
       }
@@ -2016,7 +2029,7 @@ OVERSIZE:
 
   if (ptr == 1)
     {
-    store_reset(next);
+    reset_point = store_reset(reset_point);
     next = NULL;
     break;
     }
@@ -2045,7 +2058,7 @@ OVERSIZE:
 
   next->text[ptr] = 0;
   next->slen = ptr;
-  store_reset(next->text + ptr + 1);
+  store_release_above(next->text + ptr + 1);
 
   /* Check the running total size against the overall message size limit. We
   don't expect to fail here, but if the overall limit is set less than MESSAGE_
@@ -2241,9 +2254,10 @@ OVERSIZE:
 
   /* Set up for the next header */
 
+  reset_point = store_mark();
   header_size = 256;
-  next = store_get(sizeof(header_line));
-  next->text = store_get(header_size);
+  next = store_get(sizeof(header_line), FALSE);
+  next->text = store_get(header_size, TRUE);
   ptr = 0;
   had_zero = 0;
   prevlines_length = 0;
@@ -2527,7 +2541,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);
+        pp = recipient = store_get(ss - s + 1, is_tainted(s));
         for (uschar * p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
         *pp = 0;
 
@@ -2558,7 +2572,7 @@ if (extract_recip)
         if (recipient == NULL && Ustrcmp(errmess, "empty address") != 0)
           {
           int len = Ustrlen(s);
-          error_block *b = store_get(sizeof(error_block));
+          error_block *b = store_get(sizeof(error_block), FALSE);
           while (len > 0 && isspace(s[len-1])) len--;
           b->next = NULL;
           b->text1 = string_printing(string_copyn(s, len));
@@ -2688,7 +2702,7 @@ it will fit. */
 to be the least significant base-62 digit of the time of arrival. Otherwise
 ensure that it is an empty string. */
 
-message_subdir[0] = split_spool_directory ? message_id[5] : 0;
+set_subdir_str(message_subdir, message_id, 0);
 
 /* Now that we have the message-id, if there is no message-id: header, generate
 one, but only for local (without suppress_local_fixups) or submission mode
@@ -2765,7 +2779,7 @@ function may mess with the real recipients. */
 
 if (LOGGING(received_recipients))
   {
-  raw_recipients = store_get(recipients_count * sizeof(uschar *));
+  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
   for (int i = 0; i < recipients_count; i++)
     raw_recipients[i] = string_copy(recipients_list[i].address);
   raw_recipients_count = recipients_count;
@@ -2906,9 +2920,8 @@ if (  from_header
     uschar *at = domain ? from_address + domain - 1 : NULL;
 
     if (at) *at = 0;
-    from_address += route_check_prefix(from_address, local_from_prefix);
-    slen = route_check_suffix(from_address, local_from_suffix);
-    if (slen > 0)
+    from_address += route_check_prefix(from_address, local_from_prefix, NULL);
+    if ((slen = route_check_suffix(from_address, local_from_suffix, NULL)) > 0)
       {
       memmove(from_address+slen, from_address, Ustrlen(from_address)-slen);
       from_address += slen;
@@ -3493,9 +3506,9 @@ else
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */
 
-#ifdef EXPERIMENTAL_DMARC
-    dmarc_up = dmarc_store_data(from_header);
-#endif /* EXPERIMENTAL_DMARC */
+#ifdef SUPPORT_DMARC
+    dmarc_store_data(from_header);
+#endif
 
 #ifndef DISABLE_PRDR
     if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr)
@@ -3831,7 +3844,6 @@ else
     string_from_gstring(g), istemp, string_printing(errmsg));
 
   if (smtp_input)
-    {
     if (!smtp_batched_input)
       {
       smtp_respond(smtp_code, 3, TRUE, errmsg);
@@ -3842,7 +3854,6 @@ else
     else
       moan_smtp_batch(NULL, "%s %s", smtp_code, errmsg);
       /* Does not return */
-    }
   else
     {
     fseek(spool_data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
@@ -3968,6 +3979,7 @@ it first! Include any message id that is in the message - since the syntax of a
 message id is actually an addr-spec, we can use the parse routine to canonicalize
 it. */
 
+rcvd_log_reset_point = store_mark();
 g = string_get(256);
 
 g = string_append(g, 2,
@@ -4019,18 +4031,14 @@ if (proxy_session && LOGGING(proxy))
 if (chunking_state > CHUNKING_OFFERED)
   g = string_catn(g, US" K", 2);
 
-sprintf(CS big_buffer, "%d", msg_size);
-g = string_append(g, 2, US" S=", big_buffer);
+g = string_fmt_append(g, " S=%d", msg_size);
 
 /* log 8BITMIME mode announced in MAIL_FROM
    0 ... no BODY= used
    7 ... 7BIT
    8 ... 8BITMIME */
 if (LOGGING(8bitmime))
-  {
-  sprintf(CS big_buffer, "%d", body_8bitmime);
-  g = string_append(g, 2, US" M8S=", big_buffer);
-  }
+  g = string_fmt_append(g, " M8S=%d", body_8bitmime);
 
 #ifndef DISABLE_DKIM
 if (LOGGING(dkim) && dkim_verify_overall)
@@ -4231,7 +4239,7 @@ if(cutthrough.cctx.sock >= 0 && cutthrough.delivery)
 
     case '4':  /* Temp-reject. Keep spoolfiles and accept, unless defer-pass mode.
                ... for which, pass back the exact error */
-      if (cutthrough.defer_pass) smtp_reply = string_copy_malloc(msg);
+      if (cutthrough.defer_pass) smtp_reply = string_copy_perm(msg, TRUE);
       cutthrough_done = TMP_REJ;               /* Avoid the usual immediate delivery attempt */
       break;                                   /* message_id needed for SMTP accept below */
 
@@ -4241,7 +4249,7 @@ if(cutthrough.cctx.sock >= 0 && cutthrough.delivery)
       break;                                   /* message_id needed for SMTP accept below */
 
     case '5':  /* Perm-reject.  Do the same to the source.  Dump any spoolfiles */
-      smtp_reply = string_copy_malloc(msg);            /* Pass on the exact error */
+      smtp_reply = string_copy_perm(msg, TRUE);                /* Pass on the exact error */
       cutthrough_done = PERM_REJ;
       break;
     }
@@ -4268,7 +4276,8 @@ if(!smtp_reply)
   }
 f.receive_call_bombout = FALSE;
 
-store_reset(g);   /* The store for the main log message can be reused */
+/* The store for the main log message can be reused */
+rcvd_log_reset_point = store_reset(rcvd_log_reset_point);
 
 /* If the message is frozen, and freeze_tell is set, do the telling. */