X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b90406e36cfef4cf6aaf104c3a403f6745763b5b..e4520c7817b76d6a5453237d94b1ed10fa6d2ef3:/src/src/receive.c diff --git a/src/src/receive.c b/src/src/receive.c index 4271561d7..c4b80c236 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -2,7 +2,7 @@ * 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 */ @@ -137,9 +137,9 @@ Returns: TRUE for a trusted caller */ 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, '@') @@ -514,7 +514,7 @@ Returns: nothing */ void -receive_add_recipient(uschar *recipient, int pno) +receive_add_recipient(const uschar * recipient, int pno) { if (recipients_count >= recipients_list_max) { @@ -570,7 +570,7 @@ smtp_user_msg(uschar *code, uschar *user_msg) { 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 @@ -591,7 +591,7 @@ Returns: TRUE if it did remove something; FALSE otherwise */ BOOL -receive_remove_recipient(uschar *recipient) +receive_remove_recipient(const uschar * recipient) { DEBUG(D_receive) debug_printf("receive_remove_recipient(\"%s\") called\n", recipient); @@ -1156,7 +1156,7 @@ Returns: the SMTP response */ 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); @@ -1379,6 +1379,8 @@ if (f.tcp_in_fastopen && !f.tcp_in_fastopen_logged) } 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) @@ -1455,7 +1457,7 @@ if (!(mbox_file = spool_mbox(&mbox_size, NULL, &mbox_filename))) #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 */ @@ -2307,7 +2309,7 @@ OVERSIZE: 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 */ @@ -2667,7 +2669,7 @@ if (extract_recip) 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); @@ -2677,7 +2679,7 @@ if (extract_recip) /* Move on past this address */ - s = ss + (*ss? 1:0); + s = ss + (*ss ? 1 : 0); while (isspace(*s)) s++; } /* Next address */ @@ -3249,10 +3251,9 @@ if (!ferror(spool_data_file) && !(receive_feof)() && message_ended != END_DOT) { 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; @@ -3379,8 +3380,8 @@ if (extract_recip && (bad_addresses || recipients_count == 0)) } } - 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); @@ -3595,11 +3596,11 @@ else 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) @@ -3659,7 +3660,7 @@ else /* 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"); @@ -3859,10 +3860,10 @@ the spool file gets corrupted. Ensure that all recipients are qualified. */ 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); @@ -3920,7 +3921,7 @@ else 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 */ } @@ -3944,6 +3945,19 @@ signal(SIGTERM, SIG_IGN); 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. */ @@ -4015,11 +4029,6 @@ else 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)); @@ -4039,8 +4048,13 @@ if (fflush(spool_data_file)) /* 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 @@ -4334,9 +4348,9 @@ if(!smtp_reply) #endif { log_write(0, LOG_MAIN | - (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | - (LOGGING(received_sender) ? LOG_SENDER : 0), - "%Y", g); + (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(). */ @@ -4374,9 +4388,16 @@ a queue-runner could grab it in the window. 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; @@ -4389,8 +4410,27 @@ process_info[process_info_len] = 0; /* Remove message id */ 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 response */ + if (smtp_input) 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; } @@ -4419,7 +4459,7 @@ if (smtp_input) { 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. */ @@ -4428,7 +4468,7 @@ if (smtp_input) 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 */ @@ -4456,10 +4496,10 @@ if (smtp_input) 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) {