Avoid using CLOCK_MONOTONIC for $received_time. Bug 2615
[exim.git] / src / src / receive.c
index 3e950ffc6e86280a8487848a18a4cd4eb939b0cb..c2b313c637e5c7be54d6a0e5c25538afba14abbe 100644 (file)
@@ -490,9 +490,16 @@ if (recipients_count >= recipients_list_max)
   {
   recipient_item *oldlist = recipients_list;
   int oldmax = recipients_list_max;
+
+  const int safe_recipients_limit = INT_MAX / 2 / sizeof(recipient_item);
+  if (recipients_list_max < 0 || recipients_list_max >= safe_recipients_limit)
+    {
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Too many recipients: %d", 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);
-  if (oldlist != NULL)
+  if (oldlist)
     memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
   }
 
@@ -1516,11 +1523,10 @@ return TRUE;
 void
 received_header_gen(void)
 {
-uschar *received;
-uschar *timestamp;
-header_line *received_header= header_list;
+uschar * received;
+uschar * timestamp = expand_string(US"${tod_full}");
+header_line * received_header= header_list;
 
-timestamp = expand_string(US"${tod_full}");
 if (recipients_count == 1) received_for = recipients_list[0].address;
 received = expand_string(received_header_text);
 received_for = NULL;
@@ -1539,14 +1545,14 @@ so all we have to do is fill in the text pointer, and set the type. However, if
 the result of the expansion is an empty string, we leave the header marked as
 "old" so as to refrain from adding a Received header. */
 
-if (received[0] == 0)
+if (!received[0])
   {
   received_header->text = string_sprintf("Received: ; %s\n", timestamp);
   received_header->type = htype_old;
   }
 else
   {
-  received_header->text = string_sprintf("%s; %s\n", received, timestamp);
+  received_header->text = string_sprintf("%s;\n\t%s\n", received, timestamp);
   received_header->type = htype_received;
   }
 
@@ -1782,15 +1788,19 @@ if (sender_host_address) dmarc_init();  /* initialize libopendmarc */
 
 /* Remember the time of reception. Exim uses time+pid for uniqueness of message
 ids, and fractions of a second are required. See the comments that precede the
-message id creation below. */
+message id creation below.
+We use a routine that if possible uses a monotonic clock, and can be used again
+after reception for the tick-wait even under the Linux non-Posix behaviour. */
 
 exim_gettime(&message_id_tv);
 
 /* For other uses of the received time we can operate with granularity of one
 second, and for that we use the global variable received_time. This is for
-things like ultimate message timeouts. */
+things like ultimate message timeouts.
+For this we do not care about the Linux suspend/resume problem, so rather than
+use exim_gettime() everywhere we use a plain gettimeofday() here. */
 
-received_time = message_id_tv;
+gettimeofday(&received_time, NULL);
 
 /* If SMTP input, set the special handler for timeouts. The alarm() calls
 happen in the smtp_getc() function when it refills its buffer. */
@@ -2123,7 +2133,8 @@ OVERSIZE:
         if (newsender)
           {
           if (domain == 0 && newsender[0] != 0)
-            newsender = rewrite_address_qualify(newsender, FALSE);
+           /* deconst ok as newsender was not const */
+            newsender = US rewrite_address_qualify(newsender, FALSE);
 
           if (filter_test != FTEST_NONE || receive_check_set_sender(newsender))
             {
@@ -2503,7 +2514,7 @@ if (extract_recip)
     {
     while (recipients_count-- > 0)
       {
-      uschar *s = rewrite_address(recipients_list[recipients_count].address,
+      const uschar * s = rewrite_address(recipients_list[recipients_count].address,
         TRUE, TRUE, global_rewrite_rules, rewrite_existflags);
       tree_add_nonrecipient(s);
       }
@@ -2554,11 +2565,12 @@ if (extract_recip)
           &domain, FALSE);
 
 #ifdef SUPPORT_I18N
-       if (string_is_utf8(recipient))
-         message_smtputf8 = TRUE;
-       else
-         allow_utf8_domains = b;
+        if (recipient)
+          if (string_is_utf8(recipient)) message_smtputf8 = TRUE;
+          else allow_utf8_domains = b;
        }
+#else
+        ;
 #endif
 
         /* Keep a list of all the bad addresses so we can send a single
@@ -2790,8 +2802,8 @@ recipients will get here only if the conditions were right (allow_unqualified_
 recipient is TRUE). */
 
 for (int i = 0; i < recipients_count; i++)
-  recipients_list[i].address =
-    rewrite_address(recipients_list[i].address, TRUE, TRUE,
+  recipients_list[i].address = /* deconst ok as src was not cont */
+    US rewrite_address(recipients_list[i].address, TRUE, TRUE,
       global_rewrite_rules, rewrite_existflags);
 
 /* If there is no From: header, generate one for local (without
@@ -2966,7 +2978,8 @@ it has already been rewritten as part of verification for SMTP input. */
 
 if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
   {
-  sender_address = rewrite_address(sender_address, FALSE, TRUE,
+  /* deconst ok as src was not const */
+  sender_address = US rewrite_address(sender_address, FALSE, TRUE,
     global_rewrite_rules, rewrite_existflags);
   DEBUG(D_receive|D_rewrite)
     debug_printf("rewritten sender = %s\n", sender_address);
@@ -3272,7 +3285,7 @@ if (fflush(spool_data_file) == EOF || ferror(spool_data_file) ||
 /* No I/O errors were encountered while writing the data file. */
 
 DEBUG(D_receive) debug_printf("Data file written for message %s\n", message_id);
-if (LOGGING(receive_time)) timesince(&received_time_taken, &received_time);
+gettimeofday(&received_time_complete, NULL);
 
 
 /* If there were any bad addresses extracted by -t, or there were no recipients
@@ -4050,7 +4063,11 @@ if (LOGGING(dkim) && arc_state && Ustrcmp(arc_state, "pass") == 0)
 #endif
 
 if (LOGGING(receive_time))
-  g = string_append(g, 2, US" RT=", string_timediff(&received_time_taken));
+  {
+  struct timeval diff = received_time_complete;
+  timediff(&diff, &received_time);
+  g = string_append(g, 2, US" RT=", string_timediff(&diff));
+  }
 
 if (*queue_name)
   g = string_append(g, 2, US" Q=", queue_name);
@@ -4313,7 +4330,10 @@ pid can be re-used within our time interval. We can't shorten the interval
 without re-designing the message-id. See comments above where the message id is
 created. This is Something For The Future.
 Do this wait any time we have created a message-id, even if we rejected the
-message.  This gives unique IDs for logging done by ACLs. */
+message.  This gives unique IDs for logging done by ACLs.
+The initial timestamp must have been obtained via exim_gettime() to avoid
+issues on Linux with suspend/resume.
+It would be Nicer to only pause before a follow-on message. */
 
 if (id_resolution != 0)
   {