*************************************************/
/* 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, "\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");
+ 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 */
}
- receive_bomb_out(US"signal-exit", NULL); /* Does not return */
+ if (had_data_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 */
+ }
+ 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
}
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));
}
static void
log_close_chk(void)
{
-if (!receive_timeout)
+if (!receive_timeout && !receive_hasc())
{
struct timeval t;
timesince(&t, &received_time);
if (t.tv_sec > 30*60)
mainlog_close();
else
- {
- fd_set r;
- FD_ZERO(&r); FD_SET(0, &r);
- t.tv_sec = 30*60 - t.tv_sec; t.tv_usec = 0;
- if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
- }
+ if (poll_one_fd(0, POLLIN, (30*60 - t.tv_sec) * 1000) == 0)
+ mainlog_close();
}
}
{
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)
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
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
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;
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;
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));
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;
recipients will get here only if the conditions were right (allow_unqualified_
recipient is TRUE). */
+DEBUG(D_rewrite)
+ { debug_printf_indent("qualify & rewrite recipients list\n"); acl_level++; }
for (int i = 0; i < recipients_count; i++)
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);
+DEBUG(D_rewrite) acl_level--;
/* If there is no From: header, generate one for local (without
suppress_local_fixups) or submission_mode messages. If there is no sender
/* If there are any rewriting rules, apply them to the sender address, unless
it has already been rewritten as part of verification for SMTP input. */
+DEBUG(D_rewrite)
+ { debug_printf("global rewrite rules\n"); acl_level++; }
if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
{
/* deconst ok as src was not const */
DEBUG(D_receive|D_rewrite)
debug_printf("rewritten sender = %s\n", sender_address);
}
+DEBUG(D_rewrite) acl_level--;
/* The headers must be run through rewrite_header(), because it ensures that
documented as happening *after* recipient addresses are taken from the headers
by the -t command line option. An added Sender: gets rewritten here. */
-for (header_line * h = header_list->next; h; h = h->next)
- {
- header_line *newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
- rewrite_existflags, TRUE);
- if (newh) h = newh;
- }
+DEBUG(D_rewrite)
+ { debug_printf("rewrite headers\n"); acl_level++; }
+for (header_line * h = header_list->next, * newh; h; h = h->next)
+ if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
+ rewrite_existflags, TRUE)))
+ h = newh;
+DEBUG(D_rewrite) acl_level--;
/* An RFC 822 (sic) message is not legal unless it has at least one of "to",
/* Before sending an SMTP response in a TCP/IP session, we check to see if the
connection has gone away. This can only be done if there is no unconsumed input
waiting in the local input buffer. We can test for this by calling
-receive_smtp_buffered(). RFC 2920 (pipelining) explicitly allows for additional
+receive_hasc(). RFC 2920 (pipelining) explicitly allows for additional
input to be sent following the final dot, so the presence of following input is
not an error.
connection will vanish between the time of this test and the sending of the
response, but the chance of this happening should be small. */
-if (smtp_input && sender_host_address && !f.sender_host_notsocket &&
- !receive_smtp_buffered())
+if ( smtp_input && sender_host_address && !f.sender_host_notsocket
+ && !receive_hasc())
{
- struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
- fd_set select_check;
- FD_ZERO(&select_check);
- FD_SET(fileno(smtp_in), &select_check);
-
- if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
+ if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0)
{
int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
if (c != EOF) (receive_ungetc)(c); else
the socket. */
smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n",
- receive_smtp_buffered(),
+ receive_hasc(),
chunking_datasize, message_size+message_linecount, message_id);
chunking_state = CHUNKING_OFFERED;
}
else
- smtp_printf("250 OK id=%s\r\n", receive_smtp_buffered(), message_id);
+ smtp_printf("250 OK id=%s\r\n", receive_hasc(), message_id);
if (host_checking)
fprintf(stdout,