* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
*/
BOOL
-receive_check_set_sender(uschar *newsender)
+receive_check_set_sender(const uschar * newsender)
{
-uschar *qnewsender;
+const uschar * qnewsender;
if (f.trusted_caller) return TRUE;
if (!newsender || !untrusted_set_sender) return FALSE;
qnewsender = Ustrchr(newsender, '@')
*/
void
-receive_add_recipient(uschar *recipient, int pno)
+receive_add_recipient(const uschar * recipient, int pno)
{
if (recipients_count >= recipients_list_max)
{
{
int len = 3;
smtp_message_code(&code, &len, &user_msg, NULL, TRUE);
-smtp_respond(code, len, TRUE, user_msg);
+smtp_respond(code, len, SR_FINAL, user_msg);
}
#endif
*/
BOOL
-receive_remove_recipient(uschar *recipient)
+receive_remove_recipient(const uschar * recipient)
{
DEBUG(D_receive) debug_printf("receive_remove_recipient(\"%s\") called\n",
recipient);
*/
static uschar *
-handle_lost_connection(uschar *s)
+handle_lost_connection(uschar * s)
{
log_write(L_lost_incoming_connection | L_smtp_connection, LOG_MAIN,
"%s lost while reading message data%s", smtp_get_connection_info(), s);
}
if (sender_ident)
g = string_append(g, 2, US" U=", sender_ident);
+if (LOGGING(connection_id))
+ g = string_fmt_append(g, " Ci=%lu", connection_id);
if (received_protocol)
g = string_append(g, 2, US" P=", received_protocol);
if (LOGGING(pipelining) && f.smtp_in_pipelining_advertised)
#ifdef EXPERIMENTAL_DCC
dcc_ok = 0;
#endif
- smtp_respond(US"451", 3, TRUE, US"temporary local problem");
+ smtp_respond(US"451", 3, SR_FINAL, US"temporary local problem");
message_id[0] = 0; /* Indicate no message accepted */
*smtp_reply_ptr = US""; /* Indicate reply already sent */
return FALSE; /* Indicate skip to end of receive function */
sender_address,
sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"",
sender_ident ? " U=" : "", sender_ident ? sender_ident : US"");
- smtp_printf("552 Message header not CRLF terminated\r\n", FALSE);
+ smtp_printf("552 Message header not CRLF terminated\r\n", SP_NO_MORE);
bdat_flush_data();
smtp_reply = US"";
goto TIDYUP; /* Skip to end of function */
that this has happened, in order to give a better error if there are
no recipients left. */
- else if (recipient != NULL)
+ else if (recipient)
{
if (tree_search(tree_nonrecipients, recipient) == NULL)
receive_add_recipient(recipient, -1);
/* Move on past this address */
- s = ss + (*ss? 1:0);
+ s = ss + (*ss ? 1 : 0);
while (isspace(*s)) s++;
} /* Next address */
{
Uunlink(spool_name); /* Lose data file when closed */
cancel_cutthrough_connection(TRUE, US"sender closed connection");
- message_id[0] = 0; /* Indicate no message_accepted */
smtp_reply = handle_lost_connection(US"");
smtp_yield = FALSE;
- goto TIDYUP; /* Skip to end of function */
+ goto NOT_ACCEPTED; /* Skip to end of function */
}
break;
}
}
- log_write(0, LOG_MAIN|LOG_PANIC, "%s %s found in headers",
- message_id, bad_addresses ? "bad addresses" : "no recipients");
+ log_write(0, LOG_MAIN|LOG_PANIC, "%s found in headers",
+ bad_addresses ? "bad addresses" : "no recipients");
fseek(spool_data_file, (long int)spool_data_start_offset(message_id), SEEK_SET);
int all_pass = OK;
int all_fail = FAIL;
- smtp_printf("353 PRDR content analysis beginning\r\n", TRUE);
+ smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE);
/* Loop through recipients, responses must be in same order received */
for (unsigned int c = 0; recipients_count > c; c++)
{
- uschar * addr= recipients_list[c].address;
+ const uschar * addr = recipients_list[c].address;
uschar * msg= US"PRDR R=<%s> %s";
uschar * code;
DEBUG(D_receive)
/* Check the recipients count again, as the MIME ACL might have changed
them. */
- if (acl_smtp_data != NULL && recipients_count > 0)
+ if (acl_smtp_data && recipients_count > 0)
{
rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
add_acl_headers(ACL_WHERE_DATA, US"DATA");
if (rc == LOCAL_SCAN_ACCEPT)
{
if (local_scan_data)
- for (uschar * s = local_scan_data; *s != 0; s++) if (*s == '\n') *s = ' ';
- for (int i = 0; i < recipients_count; i++)
+ for (uschar * s = local_scan_data; *s; s++) if (*s == '\n') *s = ' ';
+ for (recipient_item * r = recipients_list;
+ r < recipients_list + recipients_count; r++)
{
- recipient_item *r = recipients_list + i;
r->address = rewrite_address_qualify(r->address, TRUE);
if (r->errors_to)
r->errors_to = rewrite_address_qualify(r->errors_to, TRUE);
break;
}
- g = string_append(NULL, 2, US"F=",
- sender_address[0] == 0 ? US"<>" : sender_address);
+ g = string_append(NULL, 2, US"F=", *sender_address ? sender_address : US"<>");
g = add_host_info_for_log(g);
- log_write(0, LOG_MAIN|LOG_REJECT, "%s %srejected by local_scan(): %.256s",
- string_from_gstring(g), istemp, string_printing(errmsg));
+ log_write(0, LOG_MAIN|LOG_REJECT, "%Y %srejected by local_scan(): %.256s",
+ g, istemp, string_printing(errmsg));
if (smtp_input)
if (!smtp_batched_input)
{
- smtp_respond(smtp_code, 3, TRUE, errmsg);
+ smtp_respond(smtp_code, 3, SR_FINAL, errmsg);
smtp_reply = US""; /* Indicate reply already sent */
goto NOT_ACCEPTED; /* Skip to end of function */
}
signal(SIGINT, SIG_IGN);
#endif /* HAVE_LOCAL_SCAN */
+/* If we are faking a reject or defer, avoid sennding a DSN for the
+actually-accepted message */
+
+if (fake_response != OK)
+ for (recipient_item * r = recipients_list;
+ r < recipients_list + recipients_count; r++)
+ {
+ DEBUG(D_receive) if (r->dsn_flags & (rf_notify_success | rf_notify_delay))
+ debug_printf("DSN: clearing flags due to fake-response for message\n");
+ r->dsn_flags = r->dsn_flags & ~(rf_notify_success | rf_notify_delay)
+ | rf_notify_never;
+ }
+
/* Ensure the first time flag is set in the newly-received message. */
receive_messagecount++;
-/* Add data size to written header size. We do not count the initial file name
-that is in the file, but we do add one extra for the notional blank line that
-precedes the data. This total differs from message_size in that it include the
-added Received: header and any other headers that got created locally. */
-
if (fflush(spool_data_file))
{
errmsg = string_sprintf("Spool write error: %s", strerror(errno));
/* Does not return */
}
}
-fstat(data_fd, &statbuf);
+/* Add data size to written header size. We do not count the initial file name
+that is in the file, but we do add one extra for the notional blank line that
+precedes the data. This total differs from message_size in that it include the
+added Received: header and any other headers that got created locally. */
+
+fstat(data_fd, &statbuf);
msg_size += statbuf.st_size - spool_data_start_offset(message_id) + 1;
/* Generate a "message received" log entry. We do this by building up a dynamic
g = string_append(g, 2,
fake_response == FAIL ? US"(= " : US"<= ",
- sender_address[0] == 0 ? US"<>" : sender_address);
+ *sender_address ? sender_address : US"<>");
if (message_reference)
g = string_append(g, 2, US" R=", message_reference);
gstring_reset(g);
g = string_cat(g, US"SMTP connection lost after final dot");
g = add_host_info_for_log(g);
- log_write(0, LOG_MAIN, "%s", string_from_gstring(g));
+ log_write(0, LOG_MAIN, "%Y", g);
/* Delete the files for this aborted message. */
#endif
{
log_write(0, LOG_MAIN |
- (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
- (LOGGING(received_sender) ? LOG_SENDER : 0),
- "%s", g->s);
+ (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+ (LOGGING(received_sender) ? LOG_SENDER : 0),
+ "%Y", g);
/* Log any control actions taken by an ACL or local_scan(). */
A fflush() was done earlier in the expectation that any write errors on the
data file will be flushed(!) out thereby. Nevertheless, it is theoretically
-possible for fclose() to fail - but what to do? What has happened to the lock
-if this happens? We can at least log it; if it is observed on some platform
-then we can think about properly declaring the message not-received. */
+possible for fclose() to fail - and this has been seen on obscure filesystems
+(probably one that delayed the actual media write as long as possible)
+but what to do? What has happened to the lock if this happens?
+It's a mes because we already logged the acceptance.
+We can at least log the issue, try to remove spoolfiles and respond with
+a temp-reject. We do not want to close before logging acceptance because
+we want to hold the lock until we know that logging worked.
+Could we make this less likely by doing an fdatasync() just after the fflush()?
+That seems like a good thing on data-security grounds, but how much will it hit
+performance? */
goto TIDYUP;
if (spool_data_file && cutthrough_done == NOT_TRIED)
{
if (fclose(spool_data_file)) /* Frees the lock */
- log_write(0, LOG_MAIN|LOG_PANIC,
- "spoolfile error on close: %s", strerror(errno));
+ {
+ log_msg = string_sprintf("spoolfile error on close: %s", strerror(errno));
+ log_write(0, LOG_MAIN|LOG_PANIC |
+ (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+ (LOGGING(received_sender) ? LOG_SENDER : 0),
+ "%s", log_msg);
+ log_write(0, LOG_MAIN |
+ (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+ (LOGGING(received_sender) ? LOG_SENDER : 0),
+ "rescind the above message-accept");
+
+ Uunlink(spool_name);
+ Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
+ Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
+
+ /* Claim a data ACL temp-reject, just to get reject logging and resposponse */
+ smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg);
+ smtp_reply = US""; /* Indicate reply already sent */
+
+ message_id[0] = 0; /* no message accepted */
+ }
spool_data_file = NULL;
}
{
if (fake_response != OK)
smtp_respond(fake_response == DEFER ? US"450" : US"550",
- 3, TRUE, fake_response_text);
+ 3, SR_FINAL, fake_response_text);
/* An OK response is required; use "message" text if present. */
uschar *code = US"250";
int len = 3;
smtp_message_code(&code, &len, &user_msg, NULL, TRUE);
- smtp_respond(code, len, TRUE, user_msg);
+ smtp_respond(code, len, SR_FINAL, user_msg);
}
/* Default OK response */
else if (smtp_reply[0] != 0)
if (fake_response != OK && smtp_reply[0] == '2')
- smtp_respond(fake_response == DEFER ? US"450" : US"550", 3, TRUE,
- fake_response_text);
+ smtp_respond(fake_response == DEFER ? US"450" : US"550",
+ 3, SR_FINAL, fake_response_text);
else
- smtp_printf("%.1024s\r\n", FALSE, smtp_reply);
+ smtp_printf("%.1024s\r\n", SP_NO_MORE, smtp_reply);
switch (cutthrough_done)
{