X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/2fe1a124e7e7f496b39d9f348403dd5d5e69f01f..184e88237dea64ce48076cdd0184612d057cbafd:/src/src/receive.c diff --git a/src/src/receive.c b/src/src/receive.c index 75447499b..b741b05b2 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/receive.c,v 1.23 2005/09/07 10:15:33 ph10 Exp $ */ +/* $Cambridge: exim/src/src/receive.c,v 1.32 2007/01/08 10:50:18 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2007 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code for receiving a message and setting up spool files. */ @@ -899,10 +899,10 @@ add_acl_headers(uschar *acl_name) header_line *h, *next; header_line *last_received = NULL; -if (acl_warn_headers == NULL) return; +if (acl_added_headers == NULL) return; DEBUG(D_receive|D_acl) debug_printf(">>Headers added by %s ACL:\n", acl_name); -for (h = acl_warn_headers; h != NULL; h = next) +for (h = acl_added_headers; h != NULL; h = next) { next = h->next; @@ -964,7 +964,7 @@ for (h = acl_warn_headers; h != NULL; h = next) DEBUG(D_receive|D_acl) debug_printf(" %s", header_last->text); } -acl_warn_headers = NULL; +acl_added_headers = NULL; DEBUG(D_receive|D_acl) debug_printf(">>\n"); } @@ -1042,18 +1042,21 @@ memset(CS rfc822_file_path,0,2048); /* check if it is a MIME message */ my_headerlist = header_list; -while (my_headerlist != NULL) { +while (my_headerlist != NULL) + { /* skip deleted headers */ - if (my_headerlist->type == '*') { + if (my_headerlist->type == '*') + { my_headerlist = my_headerlist->next; continue; - }; - if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) { + } + 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; @@ -1067,7 +1070,7 @@ if (mbox_file == NULL) { "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"); + smtp_respond(US"451", 3, 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 */ @@ -1080,18 +1083,21 @@ 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) { +if (Ustrlen(rfc822_file_path) > 0) + { mime_part_count = mime_part_count_buffer; - if (unlink(CS rfc822_file_path) == -1) { + 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) { +if (rc == OK) + { uschar temp_path[1024]; int n; struct dirent *entry; @@ -1100,33 +1106,37 @@ if (rc == OK) { (void)string_format(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) { + 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) + { (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); - break; - }; - } while (1); - closedir(tempdir); + debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path); + break; + } + } while (1); + closedir(tempdir); - if (entry != NULL) { + if (entry != NULL) + { mbox_file = Ufopen(rfc822_file_path,"rb"); - if (mbox_file == NULL) { + 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"); @@ -1144,7 +1154,7 @@ else if (rc != OK) *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; } @@ -1160,9 +1170,10 @@ return TRUE; Either a non-null list of recipients, or the extract flag will be true, or both. The flag sender_local is true for locally generated messages. The flag submission_mode is true if an ACL has obeyed "control = submission". The flag -smtp_input is true if the message is to be handled using SMTP conventions about -termination and lines starting with dots. For non-SMTP messages, dot_ends is -true for dot-terminated messages. +suppress_local_fixups is true if an ACL has obeyed "control = +suppress_local_fixups". The flag smtp_input is true if the message is to be +handled using SMTP conventions about termination and lines starting with dots. +For non-SMTP messages, dot_ends is true for dot-terminated messages. If a message was successfully read, message_id[0] will be non-zero. @@ -1275,20 +1286,16 @@ uschar *queued_by = NULL; uschar *errmsg, *s; struct stat statbuf; -/* Final message to give to SMTP caller */ +/* Final message to give to SMTP caller, and messages from ACLs */ uschar *smtp_reply = NULL; +uschar *user_msg, *log_msg; /* Working header pointers */ header_line *h, *next; -/* Flags for noting the existence of certain headers */ - -/**** No longer check for these (Nov 2003) -BOOL to_or_cc_header_exists = FALSE; -BOOL bcc_header_exists = FALSE; -****/ +/* Flags for noting the existence of certain headers (only one left) */ BOOL date_header_exists = FALSE; @@ -1851,24 +1858,12 @@ for (h = header_list->next; h != NULL; h = h->next) switch (header_checkname(h, is_resent)) { - /* "Bcc:" gets flagged, and its existence noted, whether it's resent- or - not. */ - case htype_bcc: - h->type = htype_bcc; - /**** - bcc_header_exists = TRUE; - ****/ + h->type = htype_bcc; /* Both Bcc: and Resent-Bcc: */ break; - /* "Cc:" gets flagged, and the existence of a recipient header is noted, - whether it's resent- or not. */ - case htype_cc: - h->type = htype_cc; - /**** - to_or_cc_header_exists = TRUE; - ****/ + h->type = htype_cc; /* Both Cc: and Resent-Cc: */ break; /* Record whether a Date: or Resent-Date: header exists, as appropriate. */ @@ -1976,18 +1971,22 @@ for (h = header_list->next; h != NULL; h = h->next) break; /* If there is a "Sender:" header and the message is locally originated, - and from an untrusted caller, or if we are in submission mode for a remote - message, mark it "old" so that it will not be transmitted with the message, - unless active_local_sender_retain is set. (This can only be true if - active_local_from_check is false.) If there are any resent- headers in the - message, apply this rule to Resent-Sender: instead of Sender:. Messages - with multiple resent- header sets cannot be tidily handled. (For this - reason, at least one MUA - Pine - turns old resent- headers into X-resent- - headers when resending, leaving just one set.) */ + and from an untrusted caller and suppress_local_fixups is not set, or if we + are in submission mode for a remote message, mark it "old" so that it will + not be transmitted with the message, unless active_local_sender_retain is + set. (This can only be true if active_local_from_check is false.) If there + are any resent- headers in the message, apply this rule to Resent-Sender: + instead of Sender:. Messages with multiple resent- header sets cannot be + tidily handled. (For this reason, at least one MUA - Pine - turns old + resent- headers into X-resent- headers when resending, leaving just one + set.) */ case htype_sender: h->type = ((!active_local_sender_retain && - ((sender_local && !trusted_caller) || submission_mode) + ( + (sender_local && !trusted_caller && !suppress_local_fixups) + || submission_mode + ) ) && (!resents_exist||is_resent))? htype_old : htype_sender; @@ -2063,8 +2062,6 @@ if (extract_recip) recipients_count = recipients_list_max = 0; } - parse_allow_group = TRUE; /* Allow address group syntax */ - /* Now scan the headers */ for (h = header_list->next; h != NULL; h = h->next) @@ -2075,6 +2072,8 @@ if (extract_recip) uschar *s = Ustrchr(h->text, ':') + 1; while (isspace(*s)) s++; + parse_allow_group = TRUE; /* Allow address group syntax */ + while (*s != 0) { uschar *ss = parse_find_address_end(s, FALSE); @@ -2139,24 +2138,19 @@ if (extract_recip) s = ss + (*ss? 1:0); while (isspace(*s)) s++; - } + } /* Next address */ + + parse_allow_group = FALSE; /* Reset group syntax flags */ + parse_found_group = FALSE; /* If this was the bcc: header, mark it "old", which means it will be kept on the spool, but not transmitted as part of the message. */ - if (h->type == htype_bcc) - { - h->type = htype_old; - /**** - bcc_header_exists = FALSE; - ****/ - } + if (h->type == htype_bcc) h->type = htype_old; } /* For appropriate header line */ } /* For each header line */ - parse_allow_group = FALSE; /* Reset group syntax flags */ - parse_found_group = FALSE; } /* Now build the unique message id. This has changed several times over the @@ -2249,11 +2243,13 @@ ensure that it is an empty string. */ message_subdir[0] = split_spool_directory? message_id[5] : 0; /* Now that we have the message-id, if there is no message-id: header, generate -one, but only for local or submission mode messages. This can be -user-configured if required, but we had better flatten any illegal characters -therein. */ +one, but only for local (without suppress_local_fixups) or submission mode +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 || submission_mode)) +if (msgid_header == NULL && + ((sender_host_address == NULL && !suppress_local_fixups) + || submission_mode)) { uschar *p; uschar *id_text = US""; @@ -2327,16 +2323,18 @@ for (i = 0; i < recipients_count; i++) rewrite_address(recipients_list[i].address, TRUE, TRUE, global_rewrite_rules, rewrite_existflags); -/* If there is no From: header, generate one for local or submission_mode -messages. If there is no sender address, but the sender is local or this is a -local delivery error, use the originator login. This shouldn't happen for -genuine bounces, but might happen for autoreplies. The addition of From: must -be done *before* checking for the possible addition of a Sender: header, -because untrusted_set_sender allows an 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 || submission_mode)) +/* If there is no From: header, generate one for local (without +suppress_local_fixups) or submission_mode messages. If there is no sender +address, but the sender is local or this is a local delivery error, use the +originator login. This shouldn't happen for genuine bounces, but might happen +for autoreplies. The addition of From: must be done *before* checking for the +possible addition of a Sender: header, because untrusted_set_sender allows an +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)) { uschar *oname = US""; @@ -2417,19 +2415,19 @@ if (from_header == NULL && (sender_host_address == NULL || submission_mode)) } -/* If the sender is local, or if we are in submission mode and there is an -authenticated_id, check that an existing From: is correct, and if not, generate -a Sender: header, unless disabled. Any previously-existing Sender: header was -removed above. Note that sender_local, as well as being TRUE if the caller of -exim is not trusted, is also true if a trusted caller did not supply a -f -argument for non-smtp input. To allow trusted callers to forge From: without -supplying -f, we have to test explicitly 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 the sender is local (without suppress_local_fixups), or if we are in +submission mode and there is an authenticated_id, check that an existing From: +is correct, and if not, generate a Sender: header, unless disabled. Any +previously-existing Sender: header was removed above. Note that sender_local, +as well as being TRUE if the caller of exim is not trusted, is also true if a +trusted caller did not supply a -f argument for non-smtp input. To allow +trusted callers to forge From: without supplying -f, we have to test explicitly +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) || + ((sender_local && !trusted_caller && !suppress_local_fixups) || (submission_mode && authenticated_id != NULL)) )) { @@ -2552,30 +2550,24 @@ for (h = header_list->next; h != NULL; h = h->next) /* An RFC 822 (sic) message is not legal unless it has at least one of "to", -"cc", or "bcc". Note that although the minimal examples in RFC822 show just +"cc", or "bcc". Note that although the minimal examples in RFC 822 show just "to" or "bcc", the full syntax spec allows "cc" as well. If any resent- header exists, this applies to the set of resent- headers rather than the normal set. -The requirement for a recipient header has been removed in RFC 2822. Earlier -versions of Exim added a To: header for locally submitted messages, and an -empty Bcc: header for others or when always_bcc was set. In the light of the -changes in RFC 2822, we now always add Bcc: just in case there are still MTAs -out there that insist on the RFC 822 syntax. - -November 2003: While generally revising what Exim does to fix up headers, it -seems like a good time to remove this altogether. */ +The requirement for a recipient header has been removed in RFC 2822. At this +point in the code, earlier versions of Exim added a To: header for locally +submitted messages, and an empty Bcc: header for others. In the light of the +changes in RFC 2822, this was dropped in November 2003. */ -/****** -if (!to_or_cc_header_exists && !bcc_header_exists) - header_add(htype_bcc, "Bcc:\n"); -******/ /* If there is no date header, generate one if the message originates locally -(i.e. not over TCP/IP) or the submission mode flag is set. Messages without -Date: are not valid, but it seems to be more confusing if Exim adds one to -all remotely-originated messages. */ +(i.e. not over TCP/IP) and suppress_local_fixups is not set, or if the +submission mode flag is set. Messages without Date: are not valid, but it seems +to be more confusing if Exim adds one to all remotely-originated messages. */ -if (!date_header_exists && (sender_host_address == NULL || submission_mode)) +if (!date_header_exists && + ((sender_host_address == NULL && !suppress_local_fixups) + || submission_mode)) header_add(htype_other, "%sDate: %s\n", resent_prefix, tod_stamp(tod_full)); search_tidyup(); /* Free any cached resources */ @@ -2921,6 +2913,7 @@ $message_body_end can be extracted if needed. Allow $recipients in expansions. */ deliver_datafile = data_fd; +user_msg = NULL; if (recipients_count == 0) { @@ -2950,7 +2943,6 @@ else if (acl_smtp_data != NULL && recipients_count > 0) { - uschar *user_msg, *log_msg; rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg); add_acl_headers(US"DATA"); if (rc == DISCARD) @@ -3005,8 +2997,13 @@ else #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); + /* The ACL can specify where rejections are to be logged, possibly + nowhere. The default is main and reject logs. */ + + if (log_reject_target != 0) + 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 (smtp_batched_input) { @@ -3130,9 +3127,9 @@ else { uschar *istemp = US""; uschar *s = NULL; + uschar *smtp_code; int size = 0; int sptr = 0; - int code; errmsg = local_scan_data; @@ -3149,7 +3146,7 @@ else /* Fall through */ case LOCAL_SCAN_REJECT: - code = 550; + smtp_code = US"550"; if (errmsg == NULL) errmsg = US"Administrative prohibition"; break; @@ -3159,7 +3156,7 @@ else case LOCAL_SCAN_TEMPREJECT: TEMPREJECT: - code = 451; + smtp_code = US"451"; if (errmsg == NULL) errmsg = US"Temporary local problem"; istemp = US"temporarily "; break; @@ -3177,14 +3174,14 @@ else { if (!smtp_batched_input) { - smtp_respond(code, TRUE, errmsg); + smtp_respond(smtp_code, 3, TRUE, errmsg); message_id[0] = 0; /* Indicate no message accepted */ smtp_reply = US""; /* Indicate reply already sent */ goto TIDYUP; /* Skip to end of function */ } else { - moan_smtp_batch(NULL, "%d %s", code, errmsg); + moan_smtp_batch(NULL, "%s %s", smtp_code, errmsg); /* Does not return */ } } @@ -3503,19 +3500,35 @@ if (smtp_input) if (smtp_reply == NULL) { if (fake_response != OK) - smtp_respond(fake_response == DEFER ? 450 : 550, - TRUE, fake_response_text); + smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE, + fake_response_text); + + /* An OK response is required; use "message" text if present. */ + + else if (user_msg != NULL) + { + uschar *code = US"250"; + int len = 3; + smtp_message_code(&code, &len, &user_msg, NULL); + smtp_respond(code, len, TRUE, user_msg); + } + + /* Default OK response */ + 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"); } + + /* smtp_reply was previously set */ + 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); + smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE, + fake_response_text); else smtp_printf("%.1024s\r\n", smtp_reply); }