* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* Code for receiving a message and setting up spool files. */
/* Remember that this message uses wireformat. */
-DEBUG(D_receive) debug_printf("CHUNKING: writing spoolfile in wire format\n");
+DEBUG(D_receive) debug_printf("CHUNKING: %s\n",
+ fout ? "writing spoolfile in wire format" : "flushing input");
spool_file_wireformat = TRUE;
for (;;)
unsigned len = MAX(chunking_data_left, thismessage_size_limit - message_size + 1);
uschar * buf = bdat_getbuf(&len);
+ if (!buf) return END_EOF;
message_size += len;
if (fout && fwrite(buf, len, 1, fout) != 1) return END_WERROR;
}
void
receive_swallow_smtp(void)
{
-/*XXX CHUNKING: not enough. read chunks until RSET? */
if (message_ended >= END_NOTENDED)
- message_ended = read_message_data_smtp(NULL);
+ message_ended = chunking_state <= CHUNKING_OFFERED
+ ? read_message_data_smtp(NULL)
+ : read_message_bdat_smtp_wire(NULL);
}
switch(h->type)
{
case htype_add_top:
- h->next = header_list;
- header_list = h;
- DEBUG(D_receive|D_acl) debug_printf_indent(" (at top)");
- break;
+ h->next = header_list;
+ header_list = h;
+ DEBUG(D_receive|D_acl) debug_printf_indent(" (at top)");
+ break;
case htype_add_rec:
- if (last_received == NULL)
- {
- last_received = header_list;
- while (!header_testname(last_received, US"Received", 8, FALSE))
- last_received = last_received->next;
- while (last_received->next != NULL &&
- header_testname(last_received->next, US"Received", 8, FALSE))
- last_received = last_received->next;
- }
- h->next = last_received->next;
- last_received->next = h;
- DEBUG(D_receive|D_acl) debug_printf_indent(" (after Received:)");
- break;
+ if (!last_received)
+ {
+ last_received = header_list;
+ while (!header_testname(last_received, US"Received", 8, FALSE))
+ last_received = last_received->next;
+ while (last_received->next &&
+ header_testname(last_received->next, US"Received", 8, FALSE))
+ last_received = last_received->next;
+ }
+ h->next = last_received->next;
+ last_received->next = h;
+ DEBUG(D_receive|D_acl) debug_printf_indent(" (after Received:)");
+ break;
case htype_add_rfc:
- /* add header before any header which is NOT Received: or Resent- */
- last_received = header_list;
- while ( (last_received->next != NULL) &&
- ( (header_testname(last_received->next, US"Received", 8, FALSE)) ||
- (header_testname_incomplete(last_received->next, US"Resent-", 7, FALSE)) ) )
- last_received = last_received->next;
- /* last_received now points to the last Received: or Resent-* header
- in an uninterrupted chain of those header types (seen from the beginning
- of all headers. Our current header must follow it. */
- h->next = last_received->next;
- last_received->next = h;
- DEBUG(D_receive|D_acl) debug_printf_indent(" (before any non-Received: or Resent-*: header)");
- break;
+ /* add header before any header which is NOT Received: or Resent- */
+ last_received = header_list;
+ while ( last_received->next &&
+ ( (header_testname(last_received->next, US"Received", 8, FALSE)) ||
+ (header_testname_incomplete(last_received->next, US"Resent-", 7, FALSE)) ) )
+ last_received = last_received->next;
+ /* last_received now points to the last Received: or Resent-* header
+ in an uninterrupted chain of those header types (seen from the beginning
+ of all headers. Our current header must follow it. */
+ h->next = last_received->next;
+ last_received->next = h;
+ DEBUG(D_receive|D_acl) debug_printf_indent(" (before any non-Received: or Resent-*: header)");
+ break;
default:
- h->next = NULL;
- header_last->next = h;
- break;
+ h->next = NULL;
+ header_last->next = h;
+ DEBUG(D_receive|D_acl) debug_printf_indent(" ");
+ break;
}
- if (h->next == NULL) header_last = h;
+ if (!h->next) header_last = h;
/* Check for one of the known header types (From:, To:, etc.) though in
practice most added headers are going to be "other". Lower case
h->type = header_checkname(h, FALSE);
if (h->type >= 'a') h->type = htype_other;
- DEBUG(D_receive|D_acl) debug_printf_indent(" %s", header_last->text);
+ DEBUG(D_receive|D_acl) debug_printf("%s", h->text);
}
acl_added_headers = NULL;
uschar **blackholed_by_ptr)
{
FILE *mbox_file;
-uschar rfc822_file_path[2048];
+uschar * rfc822_file_path = NULL;
unsigned long mbox_size;
header_line *my_headerlist;
uschar *user_msg, *log_msg;
uschar * mbox_filename;
int rc = OK;
-memset(CS rfc822_file_path,0,2048);
-
/* check if it is a MIME message */
for (my_headerlist = header_list; my_headerlist; my_headerlist = my_headerlist->next)
rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg);
(void)fclose(mbox_file);
-if (Ustrlen(rfc822_file_path) > 0)
+if (rfc822_file_path)
{
mime_part_count = mime_part_count_buffer;
{
log_write(0, LOG_PANIC,
"acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
- goto END_MIME_ACL;
+ goto END_MIME_ACL;
}
+ rfc822_file_path = NULL;
}
/* check if we must check any message/rfc822 attachments */
if (rc == OK)
{
- uschar * scandir;
+ uschar * scandir = string_copyn(mbox_filename,
+ Ustrrchr(mbox_filename, '/') - mbox_filename);
struct dirent * entry;
DIR * tempdir;
- scandir = string_copyn(mbox_filename, Ustrrchr(mbox_filename, '/') - mbox_filename);
-
- tempdir = opendir(CS scandir);
- for (;;)
- {
- if (!(entry = readdir(tempdir)))
- break;
+ for (tempdir = opendir(CS scandir); entry = readdir(tempdir); )
if (strncmpic(US entry->d_name, US"__rfc822_", 9) == 0)
{
- (void) string_format(rfc822_file_path, sizeof(rfc822_file_path),
- "%s/%s", scandir, entry->d_name);
- DEBUG(D_receive) debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n",
- rfc822_file_path);
+ rfc822_file_path = string_sprintf("%s/%s", scandir, entry->d_name);
+ DEBUG(D_receive)
+ debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n",
+ rfc822_file_path);
break;
}
- }
closedir(tempdir);
- if (entry)
+ if (rfc822_file_path)
{
if ((mbox_file = Ufopen(rfc822_file_path, "rb")))
{
#ifdef EXPERIMENTAL_DCC
dcc_ok = 0;
#endif
- if ( smtp_input
- && smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
+ if (smtp_input)
{
- *smtp_yield_ptr = FALSE; /* No more messages after dropped connection */
+ if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
+ *smtp_yield_ptr = FALSE; /* No more messages after dropped connection */
*smtp_reply_ptr = US""; /* Indicate reply already sent */
}
message_id[0] = 0; /* Indicate no message accepted */
/* 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.XXX */
+things like ultimate message timeouts. */
received_time = message_id_tv;
(and sometimes lunatic messages can have ones that are 100s of K long) we
call store_release() for strings that have been copied - if the string is at
the start of a block (and therefore the only thing in it, because we aren't
- doing any other gets), the block gets freed. We can only do this because we
- know there are no other calls to store_get() going on. */
+ doing any other gets), the block gets freed. We can only do this release if
+ there were no allocations since the once that we want to free. */
if (ptr >= header_size - 4)
{
/* header_size += 256; */
header_size *= 2;
if (!store_extend(next->text, oldsize, header_size))
- {
- uschar *newtext = store_get(header_size);
- memcpy(newtext, next->text, ptr);
- store_release(next->text);
- next->text = newtext;
- }
+ next->text = store_newblock(next->text, header_size, ptr);
}
/* Cope with receiving a binary zero. There is dispute about whether
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 == '.' && (smtp_input || dot_ends))
+ if (ptr == 0 && ch == '.' && dot_ends)
{
ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
if (ch == '\r')
these lines in SMTP messages. There is now an option to ignore them from
specified hosts or networks. Sigh. */
- if (header_last == header_list &&
- (!smtp_input
- ||
- (sender_host_address != NULL &&
- verify_check_host(&ignore_fromline_hosts) == OK)
- ||
- (sender_host_address == NULL && ignore_fromline_local)
- ) &&
- regex_match_and_setup(regex_From, next->text, 0, -1))
+ if ( header_last == header_list
+ && ( !smtp_input
+ || ( sender_host_address
+ && verify_check_host(&ignore_fromline_hosts) == OK
+ )
+ || (!sender_host_address && ignore_fromline_local)
+ )
+ && regex_match_and_setup(regex_From, next->text, 0, -1)
+ )
{
if (!sender_address_forced)
{
uschar *uucp_sender = expand_string(uucp_from_sender);
- if (uucp_sender == NULL)
- {
+ if (!uucp_sender)
log_write(0, LOG_MAIN|LOG_PANIC,
"expansion of \"%s\" failed after matching "
"\"From \" line: %s", uucp_from_sender, expand_string_message);
- }
else
{
int start, end, domain;
uschar *errmess;
uschar *newsender = parse_extract_address(uucp_sender, &errmess,
&start, &end, &domain, TRUE);
- if (newsender != NULL)
+ if (newsender)
{
if (domain == 0 && newsender[0] != 0)
newsender = rewrite_address_qualify(newsender, FALSE);
}
else
- {
give_local_error(ERRMESS_VLONGHDRLINE,
string_sprintf("message header line longer than %d characters "
"received: message not accepted", header_line_maxsize), US"",
error_rc, stdin, header_list->next);
/* Does not return */
- }
}
/* Note if any resent- fields exist. */
switch (header_checkname(h, is_resent))
{
case htype_bcc:
- h->type = htype_bcc; /* Both Bcc: and Resent-Bcc: */
- break;
+ h->type = htype_bcc; /* Both Bcc: and Resent-Bcc: */
+ break;
case htype_cc:
- h->type = htype_cc; /* Both Cc: and Resent-Cc: */
- break;
+ h->type = htype_cc; /* Both Cc: and Resent-Cc: */
+ break;
- /* Record whether a Date: or Resent-Date: header exists, as appropriate. */
+ /* Record whether a Date: or Resent-Date: header exists, as appropriate. */
case htype_date:
- if (!resents_exist || is_resent) date_header_exists = TRUE;
- break;
+ if (!resents_exist || is_resent) date_header_exists = TRUE;
+ break;
- /* Same comments as about Return-Path: below. */
+ /* Same comments as about Return-Path: below. */
case htype_delivery_date:
- if (delivery_date_remove) h->type = htype_old;
- break;
+ if (delivery_date_remove) h->type = htype_old;
+ break;
- /* Same comments as about Return-Path: below. */
+ /* Same comments as about Return-Path: below. */
case htype_envelope_to:
- if (envelope_to_remove) h->type = htype_old;
- break;
+ if (envelope_to_remove) h->type = htype_old;
+ break;
- /* Mark all "From:" headers so they get rewritten. Save the one that is to
- be used for Sender: checking. For Sendmail compatibility, if the "From:"
- header consists of just the login id of the user who called Exim, rewrite
- it with the gecos field first. Apply this rule to Resent-From: if there
- are resent- fields. */
+ /* Mark all "From:" headers so they get rewritten. Save the one that is to
+ be used for Sender: checking. For Sendmail compatibility, if the "From:"
+ header consists of just the login id of the user who called Exim, rewrite
+ it with the gecos field first. Apply this rule to Resent-From: if there
+ are resent- fields. */
case htype_from:
- h->type = htype_from;
- if (!resents_exist || is_resent)
- {
- from_header = h;
- if (!smtp_input)
- {
- int len;
- uschar *s = Ustrchr(h->text, ':') + 1;
- while (isspace(*s)) s++;
- len = h->slen - (s - h->text) - 1;
- if (Ustrlen(originator_login) == len &&
- strncmpic(s, originator_login, len) == 0)
- {
- uschar *name = is_resent? US"Resent-From" : US"From";
- header_add(htype_from, "%s: %s <%s@%s>\n", name, originator_name,
- originator_login, qualify_domain_sender);
- from_header = header_last;
- h->type = htype_old;
- DEBUG(D_receive|D_rewrite)
- debug_printf("rewrote \"%s:\" header using gecos\n", name);
- }
- }
- }
- break;
+ h->type = htype_from;
+ if (!resents_exist || is_resent)
+ {
+ from_header = h;
+ if (!smtp_input)
+ {
+ int len;
+ uschar *s = Ustrchr(h->text, ':') + 1;
+ while (isspace(*s)) s++;
+ len = h->slen - (s - h->text) - 1;
+ if (Ustrlen(originator_login) == len &&
+ strncmpic(s, originator_login, len) == 0)
+ {
+ uschar *name = is_resent? US"Resent-From" : US"From";
+ header_add(htype_from, "%s: %s <%s@%s>\n", name, originator_name,
+ originator_login, qualify_domain_sender);
+ from_header = header_last;
+ h->type = htype_old;
+ DEBUG(D_receive|D_rewrite)
+ debug_printf("rewrote \"%s:\" header using gecos\n", name);
+ }
+ }
+ }
+ break;
- /* Identify the Message-id: header for generating "in-reply-to" in the
- autoreply transport. For incoming logging, save any resent- value. In both
- cases, take just the first of any multiples. */
+ /* Identify the Message-id: header for generating "in-reply-to" in the
+ autoreply transport. For incoming logging, save any resent- value. In both
+ cases, take just the first of any multiples. */
case htype_id:
- if (msgid_header == NULL && (!resents_exist || is_resent))
- {
- msgid_header = h;
- h->type = htype_id;
- }
- break;
+ if (!msgid_header && (!resents_exist || is_resent))
+ {
+ msgid_header = h;
+ h->type = htype_id;
+ }
+ break;
- /* Flag all Received: headers */
+ /* Flag all Received: headers */
case htype_received:
- h->type = htype_received;
- received_count++;
- break;
+ h->type = htype_received;
+ received_count++;
+ break;
- /* "Reply-to:" is just noted (there is no resent-reply-to field) */
+ /* "Reply-to:" is just noted (there is no resent-reply-to field) */
case htype_reply_to:
- h->type = htype_reply_to;
- break;
+ h->type = htype_reply_to;
+ break;
- /* The Return-path: header is supposed to be added to messages when
- they leave the SMTP system. We shouldn't receive messages that already
- contain Return-path. However, since Exim generates Return-path: on
- local delivery, resent messages may well contain it. We therefore
- provide an option (which defaults on) to remove any Return-path: headers
- on input. Removal actually means flagging as "old", which prevents the
- header being transmitted with the message. */
+ /* The Return-path: header is supposed to be added to messages when
+ they leave the SMTP system. We shouldn't receive messages that already
+ contain Return-path. However, since Exim generates Return-path: on
+ local delivery, resent messages may well contain it. We therefore
+ provide an option (which defaults on) to remove any Return-path: headers
+ on input. Removal actually means flagging as "old", which prevents the
+ header being transmitted with the message. */
case htype_return_path:
- if (return_path_remove) h->type = htype_old;
+ if (return_path_remove) h->type = htype_old;
- /* If we are testing a mail filter file, use the value of the
- Return-Path: header to set up the return_path variable, which is not
- otherwise set. However, remove any <> that surround the address
- because the variable doesn't have these. */
+ /* If we are testing a mail filter file, use the value of the
+ Return-Path: header to set up the return_path variable, which is not
+ otherwise set. However, remove any <> that surround the address
+ because the variable doesn't have these. */
- if (filter_test != FTEST_NONE)
- {
- uschar *start = h->text + 12;
- uschar *end = start + Ustrlen(start);
- while (isspace(*start)) start++;
- while (end > start && isspace(end[-1])) end--;
- if (*start == '<' && end[-1] == '>')
- {
- start++;
- end--;
- }
- return_path = string_copyn(start, end - start);
- printf("Return-path taken from \"Return-path:\" header line\n");
- }
- break;
+ if (filter_test != FTEST_NONE)
+ {
+ uschar *start = h->text + 12;
+ uschar *end = start + Ustrlen(start);
+ while (isspace(*start)) start++;
+ while (end > start && isspace(end[-1])) end--;
+ if (*start == '<' && end[-1] == '>')
+ {
+ start++;
+ end--;
+ }
+ return_path = string_copyn(start, end - start);
+ printf("Return-path taken from \"Return-path:\" header line\n");
+ }
+ break;
/* If there is a "Sender:" header and the message is locally originated,
and from an untrusted caller and suppress_local_fixups is not set, or if we
set.) */
case htype_sender:
- h->type = ((!active_local_sender_retain &&
- (
- (sender_local && !trusted_caller && !suppress_local_fixups)
- || submission_mode
- )
- ) &&
- (!resents_exist||is_resent))?
- htype_old : htype_sender;
- break;
+ h->type = !active_local_sender_retain
+ && ( sender_local && !trusted_caller && !suppress_local_fixups
+ || submission_mode
+ )
+ && (!resents_exist || is_resent)
+ ? htype_old : htype_sender;
+ break;
- /* Remember the Subject: header for logging. There is no Resent-Subject */
+ /* Remember the Subject: header for logging. There is no Resent-Subject */
case htype_subject:
- subject_header = h;
- break;
+ subject_header = h;
+ break;
- /* "To:" gets flagged, and the existence of a recipient header is noted,
- whether it's resent- or not. */
+ /* "To:" gets flagged, and the existence of a recipient header is noted,
+ whether it's resent- or not. */
case htype_to:
- h->type = htype_to;
- /****
- to_or_cc_header_exists = TRUE;
- ****/
- break;
+ h->type = htype_to;
+ /****
+ to_or_cc_header_exists = TRUE;
+ ****/
+ break;
}
}
left in id_resolution so that an appropriate wait can be done after receiving
the message, if necessary (we hope it won't be). */
-if (host_number_string != NULL)
+if (host_number_string)
{
id_resolution = (BASE_62 == 62)? 5000 : 10000;
sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
messages. This can be user-configured if required, but we had better flatten
any illegal characters therein. */
-if (msgid_header == NULL &&
- ((sender_host_address == NULL && !suppress_local_fixups)
- || submission_mode))
+if ( !msgid_header
+ && ((!sender_host_address && !suppress_local_fixups) || submission_mode))
{
uschar *p;
uschar *id_text = US"";
/* Permit only letters, digits, dots, and hyphens in the domain */
- if (message_id_domain != NULL)
+ if (message_id_domain)
{
uschar *new_id_domain = expand_string(message_id_domain);
- if (new_id_domain == NULL)
+ if (!new_id_domain)
{
if (!expand_string_forcedfail)
log_write(0, LOG_MAIN|LOG_PANIC,
"expansion of \"%s\" (message_id_header_domain) "
"failed: %s", message_id_domain, expand_string_message);
}
- else if (*new_id_domain != 0)
+ else if (*new_id_domain)
{
id_domain = new_id_domain;
- for (p = id_domain; *p != 0; p++)
+ for (p = id_domain; *p; p++)
if (!isalnum(*p) && *p != '.') *p = '-'; /* No need to test '-' ! */
}
}
/* Permit all characters except controls and RFC 2822 specials in the
additional text part. */
- if (message_id_text != NULL)
+ if (message_id_text)
{
uschar *new_id_text = expand_string(message_id_text);
- if (new_id_text == NULL)
+ if (!new_id_text)
{
if (!expand_string_forcedfail)
log_write(0, LOG_MAIN|LOG_PANIC,
"expansion of \"%s\" (message_id_header_text) "
"failed: %s", message_id_text, expand_string_message);
}
- else if (*new_id_text != 0)
+ else if (*new_id_text)
{
id_text = new_id_text;
- for (p = id_text; *p != 0; p++)
- if (mac_iscntrl_or_special(*p)) *p = '-';
+ for (p = id_text; *p; p++) if (mac_iscntrl_or_special(*p)) *p = '-';
}
}
untrusted user to set anything in the envelope (which might then get info
From:) but we still want to ensure a valid Sender: if it is required. */
-if (from_header == NULL &&
- ((sender_host_address == NULL && !suppress_local_fixups)
- || submission_mode))
+if ( !from_header
+ && ((!sender_host_address && !suppress_local_fixups) || submission_mode))
{
uschar *oname = US"";
force its value or if we have a non-SMTP message for which -f was not used
to set the sender. */
- if (sender_host_address == NULL)
+ if (!sender_host_address)
{
if (!trusted_caller || sender_name_forced ||
(!smtp_input && !sender_address_forced))
/* For non-locally submitted messages, the only time we use the originator
name is when it was forced by the /name= option on control=submission. */
- else
- {
- if (submission_name != NULL) oname = submission_name;
- }
+ else if (submission_name) oname = submission_name;
/* Envelope sender is empty */
- if (sender_address[0] == 0)
+ if (!*sender_address)
{
uschar *fromstart, *fromend;
- fromstart = string_sprintf("%sFrom: %s%s", resent_prefix,
- oname, (oname[0] == 0)? "" : " <");
- fromend = (oname[0] == 0)? US"" : US">";
+ fromstart = string_sprintf("%sFrom: %s%s",
+ resent_prefix, oname, *oname ? " <" : "");
+ fromend = *oname ? US">" : US"";
if (sender_local || local_error_message)
- {
header_add(htype_from, "%s%s@%s%s\n", fromstart,
local_part_quote(originator_login), qualify_domain_sender,
fromend);
- }
- else if (submission_mode && authenticated_id != NULL)
+
+ else if (submission_mode && authenticated_id)
{
- if (submission_domain == NULL)
- {
+ if (!submission_domain)
header_add(htype_from, "%s%s@%s%s\n", fromstart,
local_part_quote(authenticated_id), qualify_domain_sender,
fromend);
- }
- else if (submission_domain[0] == 0) /* empty => whole address set */
- {
+
+ else if (!*submission_domain) /* empty => whole address set */
header_add(htype_from, "%s%s%s\n", fromstart, authenticated_id,
fromend);
- }
+
else
- {
header_add(htype_from, "%s%s@%s%s\n", fromstart,
- local_part_quote(authenticated_id), submission_domain,
- fromend);
- }
+ local_part_quote(authenticated_id), submission_domain, fromend);
+
from_header = header_last; /* To get it checked for Sender: */
}
}
{
header_add(htype_from, "%sFrom: %s%s%s%s\n", resent_prefix,
oname,
- (oname[0] == 0)? "" : " <",
- (sender_address_unrewritten == NULL)?
- sender_address : sender_address_unrewritten,
- (oname[0] == 0)? "" : ">");
+ *oname ? " <" : "",
+ sender_address_unrewritten ? sender_address_unrewritten : sender_address,
+ *oname ? ">" : "");
from_header = header_last; /* To get it checked for Sender: */
}
here. If the From: header contains more than one address, then the call to
parse_extract_address fails, and a Sender: header is inserted, as required. */
-if (from_header != NULL &&
- (active_local_from_check &&
- ((sender_local && !trusted_caller && !suppress_local_fixups) ||
- (submission_mode && authenticated_id != NULL))
- ))
+if ( from_header
+ && ( active_local_from_check
+ && ( sender_local && !trusted_caller && !suppress_local_fixups
+ || submission_mode && authenticated_id
+ ) ) )
{
BOOL make_sender = TRUE;
int start, end, domain;
&start, &end, &domain, FALSE);
uschar *generated_sender_address;
- if (submission_mode)
- {
- if (submission_domain == NULL)
- {
- generated_sender_address = string_sprintf("%s@%s",
- local_part_quote(authenticated_id), qualify_domain_sender);
- }
- else if (submission_domain[0] == 0) /* empty => full address */
- {
- generated_sender_address = string_sprintf("%s",
- authenticated_id);
- }
- else
- {
- generated_sender_address = string_sprintf("%s@%s",
- local_part_quote(authenticated_id), submission_domain);
- }
- }
- else
- generated_sender_address = string_sprintf("%s@%s",
- local_part_quote(originator_login), qualify_domain_sender);
+ generated_sender_address = submission_mode
+ ? !submission_domain
+ ? string_sprintf("%s@%s",
+ local_part_quote(authenticated_id), qualify_domain_sender)
+ : !*submission_domain /* empty => full address */
+ ? string_sprintf("%s", authenticated_id)
+ : string_sprintf("%s@%s",
+ local_part_quote(authenticated_id), submission_domain)
+ : string_sprintf("%s@%s",
+ local_part_quote(originator_login), qualify_domain_sender);
/* Remove permitted prefixes and suffixes from the local part of the From:
address before doing the comparison with the generated sender. */
- if (from_address != NULL)
+ if (from_address)
{
int slen;
- uschar *at = (domain == 0)? NULL : from_address + domain - 1;
+ uschar *at = domain ? from_address + domain - 1 : NULL;
- if (at != NULL) *at = 0;
+ 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)
memmove(from_address+slen, from_address, Ustrlen(from_address)-slen);
from_address += slen;
}
- if (at != NULL) *at = '@';
+ if (at) *at = '@';
- if (strcmpic(generated_sender_address, from_address) == 0 ||
- (domain == 0 && strcmpic(from_address, originator_login) == 0))
+ if ( strcmpic(generated_sender_address, from_address) == 0
+ || (!domain && strcmpic(from_address, originator_login) == 0))
make_sender = FALSE;
}
appropriate rewriting rules. */
if (make_sender)
- {
- if (submission_mode && submission_name == NULL)
+ if (submission_mode && !submission_name)
header_add(htype_sender, "%sSender: %s\n", resent_prefix,
generated_sender_address);
else
resent_prefix,
submission_mode? submission_name : originator_name,
generated_sender_address);
- }
/* Ensure that a non-null envelope sender address corresponds to the
submission mode sender address. */
- if (submission_mode && sender_address[0] != 0)
+ if (submission_mode && *sender_address)
{
- if (sender_address_unrewritten == NULL)
+ if (!sender_address_unrewritten)
sender_address_unrewritten = sender_address;
sender_address = generated_sender_address;
if (Ustrcmp(sender_address_unrewritten, generated_sender_address) != 0)
/* 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. */
-if (global_rewrite_rules != NULL && sender_address_unrewritten == NULL &&
- sender_address[0] != 0)
+if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
{
sender_address = rewrite_address(sender_address, FALSE, TRUE,
global_rewrite_rules, rewrite_existflags);
As per Message-Id, we prepend if resending, else append.
*/
-if (!date_header_exists &&
- ((sender_host_address == NULL && !suppress_local_fixups)
- || submission_mode))
+if ( !date_header_exists
+ && ((!sender_host_address && !suppress_local_fixups) || submission_mode))
header_add_at_position(!resents_exist, NULL, FALSE, htype_other,
"%sDate: %s\n", resent_prefix, tod_stamp(tod_full));
DEBUG(D_receive)
{
debug_printf(">>Headers after rewriting and local additions:\n");
- for (h = header_list->next; h != NULL; h = h->next)
+ for (h = header_list->next; h; h = h->next)
debug_printf("%c %s", h->type, h->text);
debug_printf("\n");
}
of fwrite() isn't inspected; instead we call ferror() below. */
fprintf(data_file, "%s-D\n", message_id);
-if (next != NULL)
+if (next)
{
uschar *s = next->text;
int len = next->slen;
log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: "
"message too big: read=%d max=%d",
sender_address,
- (sender_fullhost == NULL)? "" : " H=",
- (sender_fullhost == NULL)? US"" : sender_fullhost,
- (sender_ident == NULL)? "" : " U=",
- (sender_ident == NULL)? US"" : sender_ident,
+ sender_fullhost ? " H=" : "",
+ sender_fullhost ? sender_fullhost : US"",
+ sender_ident ? " U=" : "",
+ sender_ident ? sender_ident : US"",
message_size,
thismessage_size_limit);
uschar *msg = string_sprintf("%s error (%s) while receiving message from %s",
input_error? "Input read" : "Spool write",
msg_errno,
- (sender_fullhost != NULL)? sender_fullhost : sender_ident);
+ sender_fullhost ? sender_fullhost : sender_ident);
log_write(0, LOG_MAIN, "Message abandoned: %s", msg);
Uunlink(spool_name); /* Lose the 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);
/* If there were any bad addresses extracted by -t, or there were no recipients
exit. (This can't be SMTP, which always ensures there's at least one
syntactically good recipient address.) */
-if (extract_recip && (bad_addresses != NULL || recipients_count == 0))
+if (extract_recip && (bad_addresses || recipients_count == 0))
{
DEBUG(D_receive)
{
if (recipients_count == 0) debug_printf("*** No recipients\n");
- if (bad_addresses != NULL)
+ if (bad_addresses)
{
error_block *eblock = bad_addresses;
debug_printf("*** Bad address(es)\n");
}
else
{
- if (bad_addresses == NULL)
+ if (!bad_addresses)
{
if (extracted_ignored)
fprintf(stderr, "exim: all -t recipients overridden by command line\n");
code. */
/*XXX eventually add excess Received: check for cutthrough case back when classifying them */
-if (received_header->text == NULL) /* Non-cutthrough case */
+if (!received_header->text) /* Non-cutthrough case */
{
received_header_gen();
#ifndef DISABLE_DKIM
if (!dkim_disable_verify)
{
- /* Finish verification, this will log individual signature results to
- the mainlog */
+ /* Finish verification */
dkim_exim_verify_finish();
/* Check if we must run the DKIM ACL */
if (acl_smtp_dkim && dkim_verify_signers && *dkim_verify_signers)
{
- uschar *dkim_verify_signers_expanded =
+ uschar * dkim_verify_signers_expanded =
expand_string(dkim_verify_signers);
- if (!dkim_verify_signers_expanded)
+ gstring * results = NULL;
+ int signer_sep = 0;
+ const uschar * ptr;
+ uschar * item;
+ gstring * seen_items = NULL;
+ int old_pool = store_pool;
+
+ store_pool = POOL_PERM; /* Allow created variables to live to data ACL */
+
+ if (!(ptr = dkim_verify_signers_expanded))
log_write(0, LOG_MAIN|LOG_PANIC,
"expansion of dkim_verify_signers option failed: %s",
expand_string_message);
- else
- {
- int sep = 0;
- const uschar * ptr = dkim_verify_signers_expanded;
- uschar * item = NULL;
- gstring * seen_items = NULL;
-
- /* Default to OK when no items are present */
- rc = OK;
- while ((item = string_nextinlist(&ptr, &sep, NULL, 0)))
- {
- /* Prevent running ACL for an empty item */
- if (!item || !*item) continue;
-
- /* Only run ACL once for each domain or identity,
- no matter how often it appears in the expanded list. */
- if (seen_items)
- {
- uschar *seen_item;
- const uschar *seen_items_list = string_from_gstring(seen_items);
- BOOL seen_this_item = FALSE;
-
- while ((seen_item = string_nextinlist(&seen_items_list, &sep,
- NULL, 0)))
- if (Ustrcmp(seen_item,item) == 0)
- {
- seen_this_item = TRUE;
- break;
- }
-
- if (seen_this_item)
- {
- DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: skipping signer %s, "
- "already seen\n", item);
- continue;
- }
-
- seen_items = string_cat(seen_items, ":");
- }
-
- seen_items = string_cat(seen_items, item);
-
- DEBUG(D_receive)
- debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n",
- item);
-
- dkim_exim_acl_setup(item);
- rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim,
- &user_msg, &log_msg);
- dkim_exim_verify_log_item();
-
- if (rc != OK)
+ /* Default to OK when no items are present */
+ rc = OK;
+ while ((item = string_nextinlist(&ptr, &signer_sep, NULL, 0)))
+ {
+ /* Prevent running ACL for an empty item */
+ if (!item || !*item) continue;
+
+ /* Only run ACL once for each domain or identity,
+ no matter how often it appears in the expanded list. */
+ if (seen_items)
+ {
+ uschar * seen_item;
+ const uschar * seen_items_list = string_from_gstring(seen_items);
+ int seen_sep = ':';
+ BOOL seen_this_item = FALSE;
+
+ while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
+ NULL, 0)))
+ if (Ustrcmp(seen_item,item) == 0)
+ {
+ seen_this_item = TRUE;
+ break;
+ }
+
+ if (seen_this_item)
{
DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
- "skipping remaining items\n", rc, item);
- cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
- break;
+ debug_printf("acl_smtp_dkim: skipping signer %s, "
+ "already seen\n", item);
+ continue;
}
- }
- add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
- if (rc == DISCARD)
- {
- recipients_count = 0;
- blackholed_by = US"DKIM ACL";
- if (log_msg)
- blackhole_log_msg = string_sprintf(": %s", log_msg);
- }
- else if (rc != OK)
- {
- Uunlink(spool_name);
- if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
- smtp_yield = FALSE; /* No more messages after dropped connection */
- smtp_reply = US""; /* Indicate reply already sent */
- message_id[0] = 0; /* Indicate no message accepted */
- goto TIDYUP; /* Skip to end of function */
- }
- }
+
+ seen_items = string_catn(seen_items, US":", 1);
+ }
+ seen_items = string_cat(seen_items, item);
+
+ rc = dkim_exim_acl_run(item, &results, &user_msg, &log_msg);
+ if (rc != OK)
+ {
+ DEBUG(D_receive)
+ debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
+ "skipping remaining items\n", rc, item);
+ cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
+ break;
+ }
+ }
+ dkim_verify_status = string_from_gstring(results);
+ store_pool = old_pool;
+ add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
+ if (rc == DISCARD)
+ {
+ recipients_count = 0;
+ blackholed_by = US"DKIM ACL";
+ if (log_msg)
+ blackhole_log_msg = string_sprintf(": %s", log_msg);
+ }
+ else if (rc != OK)
+ {
+ Uunlink(spool_name);
+ if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
+ smtp_yield = FALSE; /* No more messages after dropped connection */
+ smtp_reply = US""; /* Indicate reply already sent */
+ message_id[0] = 0; /* Indicate no message accepted */
+ goto TIDYUP; /* Skip to end of function */
+ }
}
else
dkim_exim_verify_log_all();
#endif /* DISABLE_DKIM */
#ifdef WITH_CONTENT_SCAN
- if (recipients_count > 0 &&
- acl_smtp_mime != NULL &&
- !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by))
+ if ( recipients_count > 0
+ && acl_smtp_mime
+ && !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by)
+ )
goto TIDYUP;
#endif /* WITH_CONTENT_SCAN */
{
#ifdef WITH_CONTENT_SCAN
- if (acl_not_smtp_mime != NULL &&
- !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
- &blackholed_by))
+ if ( acl_not_smtp_mime
+ && !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
+ &blackholed_by)
+ )
goto TIDYUP;
#endif /* WITH_CONTENT_SCAN */
- if (acl_not_smtp != NULL)
+ if (acl_not_smtp)
{
uschar *user_msg, *log_msg;
+ authentication_local = TRUE;
rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
if (rc == DISCARD)
{
recipients_count = 0;
blackholed_by = US"non-SMTP ACL";
- if (log_msg != NULL)
+ if (log_msg)
blackhole_log_msg = string_sprintf(": %s", log_msg);
}
else if (rc != OK)
/* The ACL can specify where rejections are to be logged, possibly
nowhere. The default is main and reject logs. */
- if (log_reject_target != 0)
+ if (log_reject_target)
log_write(0, log_reject_target, "F=<%s> rejected by non-SMTP ACL: %s",
sender_address, log_msg);
- if (user_msg == NULL) user_msg = US"local configuration problem";
+ if (!user_msg) user_msg = US"local configuration problem";
if (smtp_batched_input)
{
moan_smtp_batch(NULL, "%d %s", 550, user_msg);
switch(rc)
{
default:
- log_write(0, LOG_MAIN, "invalid return %d from local_scan(). Temporary "
- "rejection given", rc);
- goto TEMPREJECT;
+ log_write(0, LOG_MAIN, "invalid return %d from local_scan(). Temporary "
+ "rejection given", rc);
+ goto TEMPREJECT;
case LOCAL_SCAN_REJECT_NOLOGHDR:
- BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
- /* Fall through */
+ BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
+ /* Fall through */
case LOCAL_SCAN_REJECT:
- smtp_code = US"550";
- if (errmsg == NULL) errmsg = US"Administrative prohibition";
- break;
+ smtp_code = US"550";
+ if (!errmsg) errmsg = US"Administrative prohibition";
+ break;
case LOCAL_SCAN_TEMPREJECT_NOLOGHDR:
- BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
- /* Fall through */
+ BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
+ /* Fall through */
case LOCAL_SCAN_TEMPREJECT:
TEMPREJECT:
- smtp_code = US"451";
- if (errmsg == NULL) errmsg = US"Temporary local problem";
- istemp = US"temporarily ";
- break;
+ smtp_code = US"451";
+ if (!errmsg) errmsg = US"Temporary local problem";
+ istemp = US"temporarily ";
+ break;
}
- g = string_append(g, 2, US"F=",
+ g = string_append(NULL, 2, US"F=",
sender_address[0] == 0 ? US"<>" : sender_address);
g = add_host_info_for_log(g);
g = string_append(g, 2, US" M8S=", big_buffer);
}
+#ifndef DISABLE_DKIM
+if (LOGGING(dkim) && dkim_verify_overall)
+ g = string_append(g, 2, US" DKIM=", dkim_verify_overall);
+# ifdef EXPERIMENTAL_ARC
+if (LOGGING(dkim) && arc_state && Ustrcmp(arc_state, "pass") == 0)
+ g = string_catn(g, US" ARC", 4);
+# endif
+#endif
+
+if (LOGGING(receive_time))
+ g = string_append(g, 2, US" RT=", string_timediff(&received_time_taken));
+
if (*queue_name)
g = string_append(g, 2, US" Q=", queue_name);
/* If subject logging is turned on, create suitable printing-character
text. By expanding $h_subject: we make use of the MIME decoding. */
-if (LOGGING(subject) && subject_header != NULL)
+if (LOGGING(subject) && subject_header)
{
int i;
uschar *p = big_buffer;
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);
- /*FALLTRHOUGH*/
+ cutthrough_done = TMP_REJ; /* Avoid the usual immediate delivery attempt */
+ break; /* message_id needed for SMTP accept below */
default: /* Unknown response, or error. Treat as temp-reject. */
+ if (cutthrough.defer_pass) smtp_reply = US"450 Onward transmission not accepted";
cutthrough_done = TMP_REJ; /* Avoid the usual immediate delivery attempt */
break; /* message_id needed for SMTP accept below */