*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* Copyright (c) The Exim Maintainers 2020 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
/* Code for receiving a message and setting up spool files. */
the file. (When SMTP input is occurring, different functions are used by
changing the pointer variables.) */
-int
-stdin_getc(unsigned lim)
-{
-int c = getc(stdin);
+uschar stdin_buf[4096];
+uschar * stdin_inptr = stdin_buf;
+uschar * stdin_inend = stdin_buf;
-if (had_data_timeout)
- {
- fprintf(stderr, "exim: timed out while reading - message abandoned\n");
- log_write(L_lost_incoming_connection,
- LOG_MAIN, "timed out while reading local message");
- receive_bomb_out(US"data-timeout", NULL); /* Does not return */
- }
-if (had_data_sigint)
+static BOOL
+stdin_refill(void)
+{
+size_t rc = fread(stdin_buf, 1, sizeof(stdin_buf), stdin);
+if (rc <= 0)
{
- if (filter_test == FTEST_NONE)
+ if (had_data_timeout)
+ {
+ fprintf(stderr, "exim: timed out while reading - message abandoned\n");
+ log_write(L_lost_incoming_connection,
+ LOG_MAIN, "timed out while reading local message");
+ receive_bomb_out(US"data-timeout", NULL); /* Does not return */
+ }
+ if (had_data_sigint)
{
- fprintf(stderr, "\nexim: %s received - message abandoned\n",
- had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
- log_write(0, LOG_MAIN, "%s received while reading local message",
- had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
+ if (filter_test == FTEST_NONE)
+ {
+ fprintf(stderr, "\nexim: %s received - message abandoned\n",
+ had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
+ log_write(0, LOG_MAIN, "%s received while reading local message",
+ had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
+ }
+ receive_bomb_out(US"signal-exit", NULL); /* Does not return */
}
- receive_bomb_out(US"signal-exit", NULL); /* Does not return */
+ return FALSE;
}
-return c;
+stdin_inend = stdin_buf + rc;
+stdin_inptr = stdin_buf;
+return TRUE;
+}
+
+int
+stdin_getc(unsigned lim)
+{
+if (stdin_inptr >= stdin_inend)
+ if (!stdin_refill())
+ return EOF;
+return *stdin_inptr++;
+}
+
+
+BOOL
+stdin_hasc(void)
+{
+return stdin_inptr < stdin_inend;
}
int
stdin_ungetc(int c)
{
-return ungetc(c, stdin);
+if (stdin_inptr <= stdin_buf)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in stdin_ungetc");
+
+*--stdin_inptr = c;
+return c;
}
int
stdin_feof(void)
{
-return feof(stdin);
+return stdin_hasc() ? FALSE : feof(stdin);
}
int
void
receive_add_recipient(uschar *recipient, int pno)
{
-/* XXX This is a math limit; we should consider a performance/sanity limit too. */
-const int safe_recipients_limit = INT_MAX / sizeof(recipient_item) - 1;
-
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;
- if ((recipients_list_max >= safe_recipients_limit) || (recipients_list_max < 0))
+
+ 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, "Too many recipients needed: %d not satisfiable", recipients_list_max);
+ 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)
memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
static void
log_close_chk(void)
{
-if (!receive_timeout)
+if (!receive_timeout && !receive_hasc())
{
struct timeval t;
timesince(&t, &received_time);
{
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)
int error_rc = error_handling == ERRORS_SENDER
? errors_sender_rc : EXIT_FAILURE;
int header_size = 256;
-int start, end, domain;
-int id_resolution = 0;
int had_zero = 0;
int prevlines_length = 0;
+const int id_resolution = BASE_62 == 62 ? 5000 : 10000;
int ptr = 0;
uschar *timestamp;
int tslen;
+/* Time of creation of message_id */
+
+static struct timeval message_id_tv = { 0, 0 };
+
/* Release any open files that might have been cached while preparing to
accept the message - e.g. by verifying addresses - because reading a message
if (sender_host_address) dmarc_init(); /* initialize libopendmarc */
#endif
+/* In SMTP sessions we may receive several messages in one connection. Before
+each subsequent one, we wait for the clock to tick at the level of message-id
+granularity.
+This is so that the combination of time+pid is unique, even on systems where the
+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 previously created a message-id, even if we
+rejected the 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. */
+
+if (message_id_tv.tv_sec)
+ {
+ message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution;
+ exim_wait_tick(&message_id_tv, id_resolution);
+ }
+
/* 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);
+else
+ 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. */
&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
Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6);
/* Deal with the case where the host number is set. The value of the number was
-checked when it was read, to ensure it isn't too big. The timing granularity is
-left in id_resolution so that an appropriate wait can be done after receiving
-the message, if necessary (we hope it won't be). */
+checked when it was read, to ensure it isn't too big. */
if (host_number_string)
- {
- id_resolution = BASE_62 == 62 ? 5000 : 10000;
sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
string_base62((long int)(
host_number * (1000000/id_resolution) +
message_id_tv.tv_usec/id_resolution)) + 4);
- }
/* Host number not set: final field is just the fractional time at an
appropriate resolution. */
else
- {
- id_resolution = BASE_62 == 62 ? 500 : 1000;
sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4);
- }
/* Add the current message id onto the current process info string if
it will fit. */
uschar * old_id;
BOOL save_allow_domain_literals = allow_domain_literals;
allow_domain_literals = TRUE;
+ int start, end, domain;
+
old_id = parse_extract_address(Ustrchr(msgid_header->text, ':') + 1,
&errmsg, &start, &end, &domain, FALSE);
allow_domain_literals = save_allow_domain_literals;
TIDYUP:
-/* In SMTP sessions we may receive several messages in one connection. After
-each one, we wait for the clock to tick at the level of message-id granularity.
-This is so that the combination of time+pid is unique, even on systems where the
-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. */
-
-if (id_resolution != 0)
- {
- message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution;
- exim_wait_tick(&message_id_tv, id_resolution);
- id_resolution = 0;
- }
-
-
process_info[process_info_len] = 0; /* Remove message id */
if (spool_data_file && cutthrough_done == NOT_TRIED)
{