X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Freceive.c;h=7fa35878b9abde3609163605a355524e69eea5fd;hb=c58b88df956cd5f2b2febc6c447d8549928b454b;hp=f9a2d3c69e4c82ac515cfa9c43f7ce671f8119e3;hpb=5cb8cbc6b514db2972dffadc30b3c7f2b7fc1dcb;p=exim.git diff --git a/src/src/receive.c b/src/src/receive.c index f9a2d3c69..7fa35878b 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1,18 +1,23 @@ -/* $Cambridge: exim/src/src/receive.c,v 1.4 2004/11/17 14:32:25 ph10 Exp $ */ +/* $Cambridge: exim/src/src/receive.c,v 1.21 2005/07/01 10:49:02 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2005 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code for receiving a message and setting up spool files. */ - #include "exim.h" - +#ifdef EXPERIMENTAL_DOMAINKEYS +#define RECEIVE_GETC dk_receive_getc +#define RECEIVE_UNGETC dk_receive_ungetc +#else +#define RECEIVE_GETC receive_getc +#define RECEIVE_UNGETC receive_ungetc +#endif /************************************************* * Local static variables * @@ -95,28 +100,28 @@ return * Read space info for a partition * *************************************************/ -/* This function is called by receive_check_fs() below, and also by string -expansion for variables such as $spool_space. The field names for the statvfs +/* This function is called by receive_check_fs() below, and also by string +expansion for variables such as $spool_space. The field names for the statvfs structure are macros, because not all OS have F_FAVAIL and it seems tidier to have macros for F_BAVAIL and F_FILES as well. Some kinds of file system do not have inodes, and they return -1 for the number available. Later: It turns out that some file systems that do not have the concept of inodes return 0 rather than -1. Such systems should also return 0 for the total -number of inodes, so we require that to be greater than zero before returning +number of inodes, so we require that to be greater than zero before returning an inode count. Arguments: isspool TRUE for spool partition, FALSE for log partition inodeptr address of int to receive inode count; -1 if there isn't one - + Returns: available on-root space, in kilobytes - -1 for log partition if there isn't one - -All values are -1 if the STATFS functions are not available. + -1 for log partition if there isn't one + +All values are -1 if the STATFS functions are not available. */ -int +int receive_statvfs(BOOL isspool, int *inodeptr) { #ifdef HAVE_STATFS @@ -129,10 +134,10 @@ uschar buffer[1024]; if (isspool) { - path = spool_directory; - name = US"spool"; - } - + path = spool_directory; + name = US"spool"; + } + /* Need to cut down the log file path to the directory, and to ignore any appearance of "syslog" in it. */ @@ -140,7 +145,7 @@ else { int sep = ':'; /* Not variable - outside scripts use */ uschar *p = log_file_path; - name = US"log"; + name = US"log"; /* An empty log_file_path means "use the default". This is the same as an empty item in a list. */ @@ -153,26 +158,26 @@ else if (path == NULL) /* No log files */ { - *inodeptr = -1; - return -1; - } + *inodeptr = -1; + return -1; + } - /* An empty string means use the default, which is in the spool directory. - But don't just use the spool directory, as it is possible that the log + /* An empty string means use the default, which is in the spool directory. + But don't just use the spool directory, as it is possible that the log subdirectory has been symbolically linked elsewhere. */ - if (path[0] == 0) + if (path[0] == 0) { sprintf(CS buffer, CS"%s/log", CS spool_directory); path = buffer; - } - else + } + else { - uschar *cp; + uschar *cp; if ((cp = Ustrrchr(path, '/')) != NULL) *cp = 0; - } + } } - + /* We now have the patch; do the business */ memset(&statbuf, 0, sizeof(statbuf)); @@ -184,11 +189,11 @@ if (STATVFS(CS path, &statbuf) != 0) smtp_closedown(US"spool or log directory problem"); exim_exit(EXIT_FAILURE); } - + *inodeptr = (statbuf.F_FILES > 0)? statbuf.F_FAVAIL : -1; /* Disks are getting huge. Take care with computing the size in kilobytes. */ - + return (int)(((double)statbuf.F_BAVAIL * (double)statbuf.F_FRSIZE)/1024.0); /* Unable to find partition sizes in this environment. */ @@ -228,16 +233,16 @@ int space, inodes; if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) { - space = receive_statvfs(TRUE, &inodes); - + space = receive_statvfs(TRUE, &inodes); + DEBUG(D_receive) debug_printf("spool directory space = %dK inodes = %d " "check_space = %dK inodes = %d msg_size = %d\n", space, inodes, check_spool_space, check_spool_inodes, msg_size); - - if ((space >= 0 && space < check_spool_space) || + + if ((space >= 0 && space < check_spool_space) || (inodes >= 0 && inodes < check_spool_inodes)) - { + { log_write(0, LOG_MAIN, "spool directory space check failed: space=%d " "inodes=%d", space, inodes); return FALSE; @@ -246,22 +251,22 @@ if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) if (check_log_space > 0 || check_log_inodes > 0) { - space = receive_statvfs(FALSE, &inodes); - + space = receive_statvfs(FALSE, &inodes); + DEBUG(D_receive) debug_printf("log directory space = %dK inodes = %d " "check_space = %dK inodes = %d\n", space, inodes, check_log_space, check_log_inodes); - - if ((space >= 0 && space < check_log_space) || + + if ((space >= 0 && space < check_log_space) || (inodes >= 0 && inodes < check_log_inodes)) - { + { log_write(0, LOG_MAIN, "log directory space check failed: space=%d " "inodes=%d", space, inodes); return FALSE; } - } - + } + return TRUE; } @@ -298,8 +303,8 @@ if (spool_name[0] != 0) /* Now close the file if it is open, either as a fd or a stream. */ -if (data_file != NULL) fclose(data_file); - else if (data_fd >= 0) close(data_fd); +if (data_file != NULL) (void)fclose(data_file); + else if (data_fd >= 0) (void)close(data_fd); /* Attempt to close down an SMTP connection tidily. */ @@ -346,8 +351,9 @@ if (smtp_input) msg = US"SMTP incoming data timeout"; log_write(L_lost_incoming_connection, LOG_MAIN, "SMTP data timeout (message abandoned) on connection " - "from %s", - (sender_fullhost != NULL)? sender_fullhost : US"local process"); + "from %s F=<%s>", + (sender_fullhost != NULL)? sender_fullhost : US"local process", + sender_address); } else { @@ -427,7 +433,7 @@ if (smtp_input) } else { - if (filter_test == NULL) + if (filter_test == FTEST_NONE) { fprintf(stderr, "\nexim: %s received - message abandoned\n", (sig == SIGTERM)? "SIGTERM" : "SIGINT"); @@ -470,6 +476,11 @@ if (recipients_count >= recipients_list_max) recipients_list[recipients_count].address = recipient; recipients_list[recipients_count].pno = pno; +#ifdef EXPERIMENTAL_BRIGHTMAIL +recipients_list[recipients_count].bmi_optin = bmi_current_optin; +/* reset optin string pointer for next recipient */ +bmi_current_optin = NULL; +#endif recipients_list[recipients_count++].errors_to = NULL; } @@ -500,7 +511,7 @@ for (count = 0; count < recipients_count; count++) { if ((--recipients_count - count) > 0) memmove(recipients_list + count, recipients_list + count + 1, - (recipients_count - count)*sizeof(recipient_item)); + (recipients_count - count)*sizeof(recipient_item)); return TRUE; } } @@ -560,7 +571,7 @@ if (!dot_ends) { register int last_ch = '\n'; - for (; (ch = (receive_getc)()) != EOF; last_ch = ch) + for (; (ch = (RECEIVE_GETC)()) != EOF; last_ch = ch) { if (ch == 0) body_zerocount++; if (last_ch == '\r' && ch != '\n') @@ -590,7 +601,7 @@ if (!dot_ends) ch_state = 1; -while ((ch = (receive_getc)()) != EOF) +while ((ch = (RECEIVE_GETC)()) != EOF) { if (ch == 0) body_zerocount++; switch (ch_state) @@ -691,7 +702,7 @@ read_message_data_smtp(FILE *fout) int ch_state = 0; register int ch; -while ((ch = (receive_getc)()) != EOF) +while ((ch = (RECEIVE_GETC)()) != EOF) { if (ch == 0) body_zerocount++; switch (ch_state) @@ -854,7 +865,7 @@ if (error_handling == ERRORS_SENDER) error_rc = EXIT_FAILURE; } else fprintf(stderr, "exim: %s%s\n", text2, text1); /* Sic */ -fclose(f); +(void)fclose(f); exim_exit(error_rc); } @@ -918,6 +929,21 @@ for (h = acl_warn_headers; h != NULL; h = next) DEBUG(D_receive|D_acl) debug_printf(" (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(" (before any non-Received: or Resent-*: header)"); + break; + default: h->next = NULL; header_last->next = h; @@ -982,6 +1008,148 @@ return s; +#ifdef WITH_CONTENT_SCAN + +/************************************************* +* Run the MIME ACL on a message * +*************************************************/ + +/* This code is in a subroutine so that it can be used for both SMTP +and non-SMTP messages. It is called with a non-NULL ACL pointer. + +Arguments: + acl The ACL to run (acl_smtp_mime or acl_not_smtp_mime) + smtp_yield_ptr Set FALSE to kill messages after dropped connection + smtp_reply_ptr Where SMTP reply is being built + blackholed_by_ptr Where "blackholed by" message is being built + +Returns: TRUE to carry on; FALSE to abandon the message +*/ + +static BOOL +run_mime_acl(uschar *acl, BOOL *smtp_yield_ptr, uschar **smtp_reply_ptr, + uschar **blackholed_by_ptr) +{ +FILE *mbox_file; +uschar rfc822_file_path[2048]; +unsigned long mbox_size; +header_line *my_headerlist; +uschar *user_msg, *log_msg; +int mime_part_count_buffer = -1; +int rc; + +memset(CS rfc822_file_path,0,2048); + +/* check if it is a MIME message */ +my_headerlist = header_list; +while (my_headerlist != NULL) { + /* skip deleted headers */ + if (my_headerlist->type == '*') { + my_headerlist = my_headerlist->next; + continue; + }; + if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) { + DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n"); + goto DO_MIME_ACL; + }; + my_headerlist = my_headerlist->next; +}; + +DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n"); +return TRUE; + +DO_MIME_ACL: +/* make sure the eml mbox file is spooled up */ +mbox_file = spool_mbox(&mbox_size); +if (mbox_file == NULL) { + /* error while spooling */ + log_write(0, LOG_MAIN|LOG_PANIC, + "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected."); + Uunlink(spool_name); + unspool_mbox(); + smtp_respond(451, TRUE, 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 */ +}; + +mime_is_rfc822 = 0; + +MIME_ACL_CHECK: +mime_part_count = -1; +rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg); +(void)fclose(mbox_file); + +if (Ustrlen(rfc822_file_path) > 0) { + mime_part_count = mime_part_count_buffer; + + if (unlink(CS rfc822_file_path) == -1) { + log_write(0, LOG_PANIC, + "acl_smtp_mime: can't unlink RFC822 spool file, skipping."); + goto END_MIME_ACL; + }; +}; + +/* check if we must check any message/rfc822 attachments */ +if (rc == OK) { + uschar temp_path[1024]; + int n; + struct dirent *entry; + DIR *tempdir; + + snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id); + + tempdir = opendir(CS temp_path); + n = 0; + do { + entry = readdir(tempdir); + if (entry == NULL) break; + if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) { + snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name); + debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path); + break; + }; + } while (1); + closedir(tempdir); + + if (entry != NULL) { + mbox_file = Ufopen(rfc822_file_path,"rb"); + if (mbox_file == NULL) { + log_write(0, LOG_PANIC, + "acl_smtp_mime: can't open RFC822 spool file, skipping."); + unlink(CS rfc822_file_path); + goto END_MIME_ACL; + }; + /* set RFC822 expansion variable */ + mime_is_rfc822 = 1; + mime_part_count_buffer = mime_part_count; + goto MIME_ACL_CHECK; + }; +}; + +END_MIME_ACL: +add_acl_headers(US"MIME"); +if (rc == DISCARD) + { + recipients_count = 0; + *blackholed_by_ptr = US"MIME ACL"; + } +else if (rc != OK) + { + Uunlink(spool_name); + unspool_mbox(); + if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0) + *smtp_yield_ptr = FALSE; /* No more messsages after dropped connection */ + *smtp_reply_ptr = US""; /* Indicate reply already sent */ + message_id[0] = 0; /* Indicate no message accepted */ + return FALSE; /* Cause skip to end of receive function */ + }; + +return TRUE; +} + +#endif /* WITH_CONTENT_SCAN */ + /************************************************* * Receive message * @@ -1095,6 +1263,7 @@ BOOL yield = FALSE; BOOL resents_exist = FALSE; uschar *resent_prefix = US""; uschar *blackholed_by = NULL; +uschar *blackhole_log_msg = US""; flock_t lock_data; error_block *bad_addresses = NULL; @@ -1170,11 +1339,15 @@ received_count = 1; /* For the one we will add */ if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX; -/* While reading the message, body_linecount and body_zerocount is computed. -The full message_ linecount is set up only when the headers are read back in -from the spool for delivery. */ +/* While reading the message, the following counts are computed. */ + +message_linecount = body_linecount = body_zerocount = 0; -body_linecount = body_zerocount = 0; +#ifdef EXPERIMENTAL_DOMAINKEYS +/* Call into DK to set up the context. Check if DK is to be run are carried out + inside dk_exim_verify_init(). */ +dk_exim_verify_init(); +#endif /* 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 @@ -1224,7 +1397,7 @@ next->text. */ for (;;) { - int ch = (receive_getc)(); + int ch = (RECEIVE_GETC)(); /* If we hit EOF on a SMTP connection, it's an error, since incoming SMTP must have a correct "." terminator. */ @@ -1288,7 +1461,7 @@ for (;;) if (ch == '\n') { if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = FALSE; - else if (first_line_ended_crlf) receive_ungetc(' '); + else if (first_line_ended_crlf) RECEIVE_UNGETC(' '); goto EOL; } @@ -1303,13 +1476,13 @@ for (;;) if (ptr == 0 && ch == '.' && (smtp_input || dot_ends)) { - ch = (receive_getc)(); + ch = (RECEIVE_GETC)(); if (ch == '\r') { - ch = (receive_getc)(); + ch = (RECEIVE_GETC)(); if (ch != '\n') { - receive_ungetc(ch); + RECEIVE_UNGETC(ch); ch = '\r'; /* Revert to CR */ } } @@ -1337,7 +1510,7 @@ for (;;) if (ch == '\r') { - ch = (receive_getc)(); + ch = (RECEIVE_GETC)(); if (ch == '\n') { if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = TRUE; @@ -1347,7 +1520,7 @@ for (;;) /* Otherwise, put back the character after CR, and turn the bare CR into LF SP. */ - ch = (receive_ungetc)(ch); + ch = (RECEIVE_UNGETC)(ch); next->text[ptr++] = '\n'; message_size++; ch = ' '; @@ -1398,7 +1571,11 @@ for (;;) /* End of header line reached */ EOL: - receive_linecount++; /* For BSMTP errors */ + + /* Keep track of lines for BSMTP errors and overall message_linecount. */ + + receive_linecount++; + message_linecount++; /* Now put in the terminating newline. There is always space for at least two more characters. */ @@ -1422,14 +1599,14 @@ for (;;) if (ch != EOF) { - int nextch = (receive_getc)(); + int nextch = (RECEIVE_GETC)(); if (nextch == ' ' || nextch == '\t') { next->text[ptr++] = nextch; message_size++; continue; /* Iterate the loop */ } - else if (nextch != EOF) (receive_ungetc)(nextch); /* For next time */ + else if (nextch != EOF) (RECEIVE_UNGETC)(nextch); /* For next time */ else ch = EOF; /* Cause main loop to exit at end */ } @@ -1508,18 +1685,18 @@ for (;;) if (domain == 0 && newsender[0] != 0) newsender = rewrite_address_qualify(newsender, FALSE); - if (filter_test != NULL || receive_check_set_sender(newsender)) + if (filter_test != FTEST_NONE || receive_check_set_sender(newsender)) { sender_address = newsender; - if (trusted_caller || filter_test != NULL) + if (trusted_caller || filter_test != FTEST_NONE) { authenticated_sender = NULL; originator_name = US""; sender_local = FALSE; } - if (filter_test != NULL) + if (filter_test != FTEST_NONE) printf("Sender taken from \"From \" line\n"); } } @@ -1659,7 +1836,7 @@ if (smtp_input && (receive_feof)()) /* If this is a filter test run and no headers were read, output a warning in case there is a mistake in the test message. */ -if (filter_test != NULL && header_list->next == NULL) +if (filter_test != FTEST_NONE && header_list->next == NULL) printf("Warning: no message headers read\n"); @@ -1781,7 +1958,7 @@ for (h = header_list->next; h != NULL; h = h->next) otherwise set. However, remove any <> that surround the address because the variable doesn't have these. */ - if (filter_test != NULL) + if (filter_test != FTEST_NONE) { uschar *start = h->text + 12; uschar *end = start + Ustrlen(start); @@ -2164,31 +2341,36 @@ if (from_header == NULL && (sender_host_address == NULL || submission_mode)) if (sender_address[0] == 0) { + uschar *fromstart, *fromend; + + fromstart = string_sprintf("%sFrom: %s%s", resent_prefix, + originator_name, (originator_name[0] == 0)? "" : " <"); + fromend = (originator_name[0] == 0)? US"" : US">"; + if (sender_local || local_error_message) { - header_add(htype_from, "%sFrom: %s%s%s@%s%s\n", resent_prefix, - originator_name, - (originator_name[0] == 0)? "" : " <", - local_part_quote(originator_login), - qualify_domain_sender, - (originator_name[0] == 0)? "" : ">"); + 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) { if (submission_domain == NULL) { - header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix, - local_part_quote(authenticated_id), qualify_domain_sender); + 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 */ { - header_add(htype_from, "%sFrom: %s\n", resent_prefix, - authenticated_id); + header_add(htype_from, "%s%s%s\n", fromstart, authenticated_id, + fromend); } else { - header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix, - local_part_quote(authenticated_id), submission_domain); + header_add(htype_from, "%s%s@%s%s\n", fromstart, + local_part_quote(authenticated_id), submission_domain, + fromend); } from_header = header_last; /* To get it checked for Sender: */ } @@ -2200,15 +2382,12 @@ if (from_header == NULL && (sender_host_address == NULL || submission_mode)) else { - if (!smtp_input || sender_local) - header_add(htype_from, "%sFrom: %s%s%s%s\n", - resent_prefix, originator_name, - (originator_name[0] == 0)? "" : " <", - (sender_address_unrewritten == NULL)? - sender_address : sender_address_unrewritten, - (originator_name[0] == 0)? "" : ">"); - else - header_add(htype_from, "%sFrom: %s\n", resent_prefix, sender_address); + header_add(htype_from, "%sFrom: %s%s%s%s\n", resent_prefix, + originator_name, + (originator_name[0] == 0)? "" : " <", + (sender_address_unrewritten == NULL)? + sender_address : sender_address_unrewritten, + (originator_name[0] == 0)? "" : ">"); from_header = header_last; /* To get it checked for Sender: */ } @@ -2289,13 +2468,26 @@ if (from_header != NULL && if (make_sender) { - if (submission_mode) + if (submission_mode && originator_name[0] == 0) header_add(htype_sender, "%sSender: %s\n", resent_prefix, generated_sender_address); else header_add(htype_sender, "%sSender: %s <%s>\n", resent_prefix, 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 (sender_address_unrewritten == NULL) + sender_address_unrewritten = sender_address; + sender_address = generated_sender_address; + log_write(L_address_rewrite, LOG_MAIN, + "\"%s\" from env-from rewritten as \"%s\" by submission mode", + sender_address_unrewritten, generated_sender_address); + } } @@ -2378,7 +2570,7 @@ DEBUG(D_receive) testing mode, that is all this function does. Return TRUE if the message ended with a dot. */ -if (filter_test != NULL) +if (filter_test != FTEST_NONE) { process_info[process_info_len] = 0; return message_ended == END_DOT; @@ -2410,8 +2602,8 @@ if (data_fd < 0) /* Make sure the file's group is the Exim gid, and double-check the mode because the group setting doesn't always get set automatically. */ -fchown(data_fd, exim_uid, exim_gid); -fchmod(data_fd, SPOOL_MODE); +(void)fchown(data_fd, exim_uid, exim_gid); +(void)fchmod(data_fd, SPOOL_MODE); /* We now have data file open. Build a stream for it and lock it. We lock only the first line of the file (containing the message ID) because otherwise there @@ -2440,7 +2632,7 @@ if (next != NULL) { uschar *s = next->text; int len = next->slen; - fwrite(s, 1, len, data_file); + (void)fwrite(s, 1, len, data_file); body_linecount++; /* Assumes only 1 line */ } @@ -2458,6 +2650,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT) else message_ended = read_message_data(data_file); receive_linecount += body_linecount; /* For BSMTP errors mainly */ + message_linecount += body_linecount; /* Handle premature termination of SMTP */ @@ -2630,7 +2823,7 @@ if (extract_recip && (bad_addresses != NULL || recipients_count == 0)) if (recipients_count == 0 || error_handling == ERRORS_STDERR) { Uunlink(spool_name); - fclose(data_file); + (void)fclose(data_file); exim_exit(error_rc); } } @@ -2716,6 +2909,20 @@ else if (smtp_input && !smtp_batched_input) { + +#ifdef EXPERIMENTAL_DOMAINKEYS + dk_exim_verify_finish(); +#endif + +#ifdef WITH_CONTENT_SCAN + if (acl_smtp_mime != NULL && + !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by)) + goto TIDYUP; +#endif /* WITH_CONTENT_SCAN */ + + /* Check the recipients count again, as the MIME ACL might have changed + them. */ + if (acl_smtp_data != NULL && recipients_count > 0) { uschar *user_msg, *log_msg; @@ -2725,10 +2932,15 @@ else { recipients_count = 0; blackholed_by = US"DATA ACL"; + if (log_msg != NULL) + blackhole_log_msg = string_sprintf(": %s", log_msg); } else if (rc != OK) { Uunlink(spool_name); +#ifdef WITH_CONTENT_SCAN + unspool_mbox(); +#endif if (smtp_handle_acl_fail(ACL_WHERE_DATA, rc, user_msg, log_msg) != 0) smtp_yield = FALSE; /* No more messsages after dropped connection */ smtp_reply = US""; /* Indicate reply already sent */ @@ -2741,44 +2953,66 @@ else /* Handle non-SMTP and batch SMTP (i.e. non-interactive) messages. Note that we cannot take different actions for permanent and temporary rejections. */ - else if (acl_not_smtp != NULL) + else { - uschar *user_msg, *log_msg; - 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"; - } - else if (rc != OK) + +#ifdef WITH_CONTENT_SCAN + if (acl_not_smtp_mime != NULL && + !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply, + &blackholed_by)) + goto TIDYUP; +#endif /* WITH_CONTENT_SCAN */ + + if (acl_not_smtp != NULL) { - Uunlink(spool_name); - log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s", - sender_address, log_msg); - if (user_msg == NULL) user_msg = US"local configuration problem"; - if (smtp_batched_input) + uschar *user_msg, *log_msg; + rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg); + if (rc == DISCARD) { - moan_smtp_batch(NULL, "%d %s", 550, user_msg); - /* Does not return */ + recipients_count = 0; + blackholed_by = US"non-SMTP ACL"; + if (log_msg != NULL) + blackhole_log_msg = string_sprintf(": %s", log_msg); } - else + else if (rc != OK) { - fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET); - give_local_error(ERRMESS_LOCAL_ACL, user_msg, - US"message rejected by non-SMTP ACL: ", error_rc, data_file, - header_list); - /* Does not return */ + Uunlink(spool_name); +#ifdef WITH_CONTENT_SCAN + unspool_mbox(); +#endif + log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s", + sender_address, log_msg); + if (user_msg == NULL) user_msg = US"local configuration problem"; + if (smtp_batched_input) + { + moan_smtp_batch(NULL, "%d %s", 550, user_msg); + /* Does not return */ + } + else + { + fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET); + give_local_error(ERRMESS_LOCAL_ACL, user_msg, + US"message rejected by non-SMTP ACL: ", error_rc, data_file, + header_list); + /* Does not return */ + } } + add_acl_headers(US"non-SMTP"); } - add_acl_headers(US"non-SMTP"); } + /* The applicable ACLs have been run */ + if (deliver_freeze) frozen_by = US"ACL"; /* for later logging */ if (queue_only_policy) queued_by = US"ACL"; enable_dollar_recipients = FALSE; } +#ifdef WITH_CONTENT_SCAN +unspool_mbox(); +#endif + /* The final check on the message is to run the scan_local() function. The version supplied with Exim always accepts, but this is a hook for sysadmins to supply their own checking code. The local_scan() function is run even when all @@ -2949,6 +3183,14 @@ signal(SIGINT, SIG_IGN); deliver_firsttime = TRUE; +#ifdef EXPERIMENTAL_BRIGHTMAIL +if (bmi_run == 1) { + /* rewind data file */ + lseek(data_fd, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET); + bmi_verdicts = bmi_process_message(header_list, data_fd); +}; +#endif + /* Update the timstamp in our Received: header to account for any time taken by an ACL or by local_scan(). The new time is the time that all reception processing is complete. */ @@ -3167,7 +3409,7 @@ if (message_logs && blackholed_by == NULL) { log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s", spool_name, strerror(errno)); - close(fd); + (void)close(fd); } else { @@ -3177,7 +3419,7 @@ if (message_logs && blackholed_by == NULL) frozen_by); if (queue_only_policy) fprintf(message_log, "%s no immediate delivery: queued by %s\n", now, queued_by); - fclose(message_log); + (void)fclose(message_log); } } } @@ -3209,8 +3451,8 @@ possible for fclose() to fail - but what to do? What has happened to the lock if this happens? */ TIDYUP: -process_info[process_info_len] = 0; /* Remove message id */ -if (data_file != NULL) fclose(data_file); /* Frees the lock */ +process_info[process_info_len] = 0; /* Remove message id */ +if (data_file != NULL) (void)fclose(data_file); /* Frees the lock */ /* Now reset signal handlers to their defaults */ @@ -3235,12 +3477,23 @@ if (smtp_input) { if (smtp_reply == NULL) { - smtp_printf("250 OK id=%s\r\n", message_id); + if (fake_response != OK) + smtp_respond(fake_response == DEFER ? 450 : 550, + TRUE, fake_response_text); + else + smtp_printf("250 OK id=%s\r\n", message_id); if (host_checking) fprintf(stdout, "\n**** SMTP testing: that is not a real message id!\n\n"); } - else if (smtp_reply[0] != 0) smtp_printf("%.1024s\r\n", smtp_reply); + else if (smtp_reply[0] != 0) + { + if (fake_response != OK && (smtp_reply[0] == '2')) + smtp_respond(fake_response == DEFER ? 450 : 550, + TRUE, fake_response_text); + else + smtp_printf("%.1024s\r\n", smtp_reply); + } } /* For batched SMTP, generate an error message on failure, and do @@ -3261,7 +3514,7 @@ if (blackholed_by != NULL) uschar *detail = (local_scan_data != NULL)? string_printing(local_scan_data) : string_sprintf("(%s discarded recipients)", blackholed_by); - log_write(0, LOG_MAIN, "=> blackhole %s", detail); + log_write(0, LOG_MAIN, "=> blackhole %s%s", detail, blackhole_log_msg); log_write(0, LOG_MAIN, "Completed"); message_id[0] = 0; }