X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ead37e6cf7dd3108cf1b197d3fa58ca52935c6bd..e8bc7fca1bef99f0b14fe791594be95cfed134f2:/src/src/receive.c diff --git a/src/src/receive.c b/src/src/receive.c index 56de9fbb3..0466cab8d 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code for receiving a message and setting up spool files. */ @@ -13,6 +13,10 @@ extern int dcc_ok; #endif +#ifdef EXPERIMENTAL_DMARC +# include "dmarc.h" +#endif /* EXPERIMENTAL_DMARC */ + /************************************************* * Local static variables * *************************************************/ @@ -493,6 +497,10 @@ recipients_list[recipients_count].bmi_optin = bmi_current_optin; /* reset optin string pointer for next recipient */ bmi_current_optin = NULL; #endif +#ifdef EXPERIMENTAL_DSN +recipients_list[recipients_count].orcpt = NULL; +recipients_list[recipients_count].dsn_flags = 0; +#endif recipients_list[recipients_count++].errors_to = NULL; } @@ -502,30 +510,32 @@ recipients_list[recipients_count++].errors_to = NULL; /************************************************* * Send user response message * *************************************************/ - + /* This function is passed a default response code and a user message. It calls smtp_message_code() to check and possibly modify the response code, and then calls smtp_respond() to transmit the response. I put this into a function just to avoid a lot of repetition. - -Arguments: + +Arguments: code the response code user_msg the user message Returns: nothing -*/ - -static void +*/ + +#ifndef DISABLE_PRDR +static void smtp_user_msg(uschar *code, uschar *user_msg) -{ +{ int len = 3; smtp_message_code(&code, &len, &user_msg, NULL); smtp_respond(code, len, TRUE, user_msg); -} - - - - +} +#endif + + + + /************************************************* * Remove a recipient from the list * @@ -674,6 +684,7 @@ while ((ch = (receive_getc)()) != EOF) case 1: /* After written "\n" */ if (ch == '.') { ch_state = 3; continue; } + if (ch == '\r') { ch_state = 2; continue; } if (ch != '\n') ch_state = 0; else linelength = -1; break; @@ -978,38 +989,41 @@ Returns: nothing */ static void -add_acl_headers(uschar *acl_name) +add_acl_headers(int where, uschar *acl_name) { header_line *h, *next; header_line *last_received = NULL; +switch(where) + { + case ACL_WHERE_DKIM: + case ACL_WHERE_MIME: + case ACL_WHERE_DATA: + if (cutthrough_fd >= 0 && (acl_removed_headers || acl_added_headers)) + { + log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs" + " will not take effect on cutthrough deliveries"); + return; + } + } + if (acl_removed_headers != NULL) { DEBUG(D_receive|D_acl) debug_printf(">>Headers removed by %s ACL:\n", acl_name); - for (h = header_list; h != NULL; h = h->next) + for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old) { - uschar *list; - BOOL include_header; - - if (h->type == htype_old) continue; - - include_header = TRUE; - list = acl_removed_headers; - + uschar * list = acl_removed_headers; int sep = ':'; /* This is specified as a colon-separated list */ uschar *s; uschar buffer[128]; - while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) - != NULL) - { - int len = Ustrlen(s); - if (header_testname(h, s, len, FALSE)) + + while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) + if (header_testname(h, s, Ustrlen(s), FALSE)) { h->type = htype_old; DEBUG(D_receive|D_acl) debug_printf(" %s", h->text); } - } } acl_removed_headers = NULL; DEBUG(D_receive|D_acl) debug_printf(">>\n"); @@ -1218,47 +1232,45 @@ if (Ustrlen(rfc822_file_path) > 0) if (rc == OK) { uschar temp_path[1024]; - int n; - struct dirent *entry; - DIR *tempdir; + struct dirent * entry; + DIR * tempdir; - (void)string_format(temp_path, 1024, "%s/scan/%s", spool_directory, - message_id); + (void) string_format(temp_path, sizeof(temp_path), "%s/scan/%s", + spool_directory, message_id); tempdir = opendir(CS temp_path); - n = 0; - do + for (;;) { - entry = readdir(tempdir); - if (entry == NULL) break; - if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) + if (!(entry = readdir(tempdir))) + break; + if (strncmpic(US entry->d_name, US"__rfc822_", 9) == 0) { - (void)string_format(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); + (void) string_format(rfc822_file_path, sizeof(rfc822_file_path), + "%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) + if (entry) { - mbox_file = Ufopen(rfc822_file_path,"rb"); - if (mbox_file == NULL) + if ((mbox_file = Ufopen(rfc822_file_path, "rb"))) { - 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; } - /* set RFC822 expansion variable */ - mime_is_rfc822 = 1; - mime_part_count_buffer = mime_part_count; - goto MIME_ACL_CHECK; + log_write(0, LOG_PANIC, + "acl_smtp_mime: can't open RFC822 spool file, skipping."); + unlink(CS rfc822_file_path); } } END_MIME_ACL: -add_acl_headers(US"MIME"); +add_acl_headers(ACL_WHERE_MIME, US"MIME"); if (rc == DISCARD) { recipients_count = 0; @@ -1271,9 +1283,10 @@ else if (rc != OK) #ifdef EXPERIMENTAL_DCC dcc_ok = 0; #endif - if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0) + if (smtp_input && 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 */ + *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 */ } @@ -1447,7 +1460,7 @@ BOOL resents_exist = FALSE; uschar *resent_prefix = US""; uschar *blackholed_by = NULL; uschar *blackhole_log_msg = US""; -int cutthrough_done = 0; +enum {NOT_TRIED, TMP_REJ, PERM_REJ, ACCEPTED} cutthrough_done = NOT_TRIED; flock_t lock_data; error_block *bad_addresses = NULL; @@ -1478,6 +1491,10 @@ header_line *subject_header = NULL; header_line *msgid_header = NULL; header_line *received_header; +#ifdef EXPERIMENTAL_DMARC +int dmarc_up = 0; +#endif /* EXPERIMENTAL_DMARC */ + /* Variables for use when building the Received: header. */ uschar *timestamp; @@ -1534,6 +1551,11 @@ message_linecount = body_linecount = body_zerocount = if (smtp_input && !smtp_batched_input && !dkim_disable_verify) dkim_exim_verify_init(); #endif +#ifdef EXPERIMENTAL_DMARC +/* initialize libopendmarc */ +dmarc_up = dmarc_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 message id creation below. */ @@ -2704,7 +2726,6 @@ if (from_header != NULL && } } - /* 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. */ @@ -2811,10 +2832,10 @@ if (cutthrough_fd >= 0) goto TIDYUP; /* Skip to end of function */ } received_header_gen(); - add_acl_headers(US"MAIL or RCPT"); + add_acl_headers(ACL_WHERE_RCPT, US"MAIL or RCPT"); (void) cutthrough_headers_send(); } - + /* Open a new spool file for the data portion of the message. We need to access it both via a file descriptor and a stream. Try to make the @@ -3103,7 +3124,7 @@ if (received_header->text == NULL) /* Non-cutthrough case */ /* If an ACL from any RCPT commands set up any warning headers to add, do so now, before running the DATA ACL. */ - add_acl_headers(US"MAIL or RCPT"); + add_acl_headers(ACL_WHERE_RCPT, US"MAIL or RCPT"); } else message_body_size = (fstat(data_fd, &statbuf) == 0)? @@ -3177,7 +3198,7 @@ else uschar seen_item_buf[256]; uschar *seen_items_list = seen_items; int seen_this_item = 0; - + while ((seen_item = string_nextinlist(&seen_items_list, &sep, seen_item_buf, sizeof(seen_item_buf))) != NULL) @@ -3186,7 +3207,7 @@ else { seen_this_item = 1; break; - } + } } if (seen_this_item > 0) @@ -3195,7 +3216,7 @@ else debug_printf("acl_smtp_dkim: skipping signer %s, already seen\n", item); continue; } - + seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,":"); } @@ -3216,7 +3237,7 @@ else break; } } - add_acl_headers(US"DKIM"); + add_acl_headers(ACL_WHERE_DKIM, US"DKIM"); if (rc == DISCARD) { recipients_count = 0; @@ -3245,8 +3266,12 @@ else goto TIDYUP; #endif /* WITH_CONTENT_SCAN */ -#ifdef EXPERIMENTAL_PRDR - if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr != NULL ) +#ifdef EXPERIMENTAL_DMARC + dmarc_up = dmarc_store_data(from_header); +#endif /* EXPERIMENTAL_DMARC */ + +#ifndef DISABLE_PRDR + if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr) { unsigned int c; int all_pass = OK; @@ -3293,7 +3318,7 @@ else } if (log_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg); else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg); - else log_write(0, LOG_MAIN, CS msg); + else log_write(0, LOG_MAIN, "%s", CS msg); if (rc != OK) { receive_remove_recipient(addr); c--; } } @@ -3314,7 +3339,7 @@ else } else prdr_requested = FALSE; -#endif /* EXPERIMENTAL_PRDR */ +#endif /* !DISABLE_PRDR */ /* Check the recipients count again, as the MIME ACL might have changed them. */ @@ -3322,7 +3347,7 @@ else if (acl_smtp_data != NULL && recipients_count > 0) { rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg); - add_acl_headers(US"DATA"); + add_acl_headers(ACL_WHERE_DATA, US"DATA"); if (rc == DISCARD) { recipients_count = 0; @@ -3405,7 +3430,7 @@ else /* Does not return */ } } - add_acl_headers(US"non-SMTP"); + add_acl_headers(ACL_WHERE_NOTSMTP, US"non-SMTP"); } } @@ -3707,21 +3732,20 @@ if (message_reference != NULL) s = add_host_info_for_log(s, &size, &sptr); #ifdef SUPPORT_TLS -if ((log_extra_selector & LX_tls_cipher) != 0 && tls_in.cipher != NULL) +if (log_extra_selector & LX_tls_cipher && tls_in.cipher) s = string_append(s, &size, &sptr, 2, US" X=", tls_in.cipher); -if ((log_extra_selector & LX_tls_certificate_verified) != 0 && - tls_in.cipher != NULL) +if (log_extra_selector & LX_tls_certificate_verified && tls_in.cipher) s = string_append(s, &size, &sptr, 2, US" CV=", tls_in.certificate_verified? "yes":"no"); -if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_in.peerdn != NULL) +if (log_extra_selector & LX_tls_peerdn && tls_in.peerdn) s = string_append(s, &size, &sptr, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\""); -if ((log_extra_selector & LX_tls_sni) != 0 && tls_in.sni != NULL) +if (log_extra_selector & LX_tls_sni && tls_in.sni) s = string_append(s, &size, &sptr, 3, US" SNI=\"", string_printing(tls_in.sni), US"\""); #endif -if (sender_host_authenticated != NULL) +if (sender_host_authenticated) { s = string_append(s, &size, &sptr, 2, US" A=", sender_host_authenticated); if (authenticated_id != NULL) @@ -3732,11 +3756,16 @@ if (sender_host_authenticated != NULL) } } -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (prdr_requested) s = string_append(s, &size, &sptr, 1, US" PRDR"); #endif +#ifdef EXPERIMENTAL_PROXY +if (proxy_session && log_extra_selector & LX_proxy) + s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host_address); +#endif + sprintf(CS big_buffer, "%d", msg_size); s = string_append(s, &size, &sptr, 2, US" S=", big_buffer); @@ -3930,7 +3959,6 @@ for this message. */ XXX We do not handle queue-only, freezing, or blackholes. */ -cutthrough_done = 0; if(cutthrough_fd >= 0) { uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the messsage */ @@ -3938,26 +3966,26 @@ if(cutthrough_fd >= 0) switch(msg[0]) { case '2': /* Accept. Do the same to the source; dump any spoolfiles. */ - cutthrough_done = 3; + cutthrough_done = ACCEPTED; break; /* message_id needed for SMTP accept below */ - + default: /* Unknown response, or error. Treat as temp-reject. */ case '4': /* Temp-reject. Keep spoolfiles and accept. */ - cutthrough_done = 1; /* Avoid the usual immediate delivery attempt */ + cutthrough_done = TMP_REJ; /* Avoid the usual immediate delivery attempt */ break; /* message_id needed for SMTP accept below */ - + case '5': /* Perm-reject. Do the same to the source. Dump any spoolfiles */ smtp_reply= msg; /* Pass on the exact error */ - cutthrough_done = 2; + cutthrough_done = PERM_REJ; break; } } -if(smtp_reply == NULL -#ifdef EXPERIMENTAL_PRDR - || prdr_requested +#ifndef DISABLE_PRDR +if(!smtp_reply || prdr_requested) +#else +if(!smtp_reply) #endif - ) { log_write(0, LOG_MAIN | (((log_extra_selector & LX_received_recipients) != 0)? LOG_RECIPIENTS : 0) | @@ -4062,8 +4090,8 @@ if (smtp_input) switch (cutthrough_done) { - case 3: log_write(0, LOG_MAIN, "Completed"); /* Delivery was done */ - case 2: { /* Delete spool files */ + case ACCEPTED: log_write(0, LOG_MAIN, "Completed");/* Delivery was done */ + case PERM_REJ: { /* Delete spool files */ sprintf(CS spool_name, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id); Uunlink(spool_name); @@ -4074,7 +4102,7 @@ if (smtp_input) message_subdir, message_id); Uunlink(spool_name); } - case 1: message_id[0] = 0; /* Prevent a delivery from starting */ + case TMP_REJ: message_id[0] = 0; /* Prevent a delivery from starting */ default:break; } cutthrough_delivery = FALSE;