X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/929ba01ccb7fafbe89e4fa60e93ab2b5f4aab1df..26da7e207f1978012085c096366d623dc15b9778:/src/src/verify.c diff --git a/src/src/verify.c b/src/src/verify.c index b33ebb6df..8881926b5 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/verify.c,v 1.34 2006/02/21 16:24:19 ph10 Exp $ */ +/* $Cambridge: exim/src/src/verify.c,v 1.39 2006/09/25 11:25:37 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -148,6 +148,7 @@ BOOL callout_no_cache = (options & vopt_callout_no_cache) != 0; BOOL callout_random = (options & vopt_callout_random) != 0; int yield = OK; +int old_domain_cache_result = ccache_accept; BOOL done = FALSE; uschar *address_key; uschar *from_address; @@ -228,10 +229,18 @@ if (dbm_file != NULL) if (cache_record != NULL) { - /* If an early command (up to and including MAIL FROM:<>) was rejected, - there is no point carrying on. The callout fails. */ - - if (cache_record->result == ccache_reject) + /* In most cases, if an early command (up to and including MAIL FROM:<>) + was rejected, there is no point carrying on. The callout fails. However, if + we are doing a recipient verification with use_sender or use_postmaster + set, a previous failure of MAIL FROM:<> doesn't count, because this time we + will be using a non-empty sender. We have to remember this situation so as + not to disturb the cached domain value if this whole verification succeeds + (we don't want it turning into "accept"). */ + + old_domain_cache_result = cache_record->result; + + if (cache_record->result == ccache_reject || + (*from_address == 0 && cache_record->result == ccache_reject_mfnull)) { setflag(addr, af_verify_nsfail); HDEBUG(D_verify) @@ -380,6 +389,7 @@ for (host = host_list; host != NULL && !done; host = host->next) int host_af; int port = 25; BOOL send_quit = TRUE; + uschar *active_hostname = smtp_active_hostname; uschar *helo = US"HELO"; uschar *interface = NULL; /* Outgoing interface to use; NULL => any */ uschar inbuffer[4096]; @@ -426,6 +436,17 @@ for (host = host_list; host != NULL && !done; host = host->next) log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, addr->message); + /* Expand the helo_data string to find the host name to use. */ + + if (tf->helo_data != NULL) + { + uschar *s = expand_string(tf->helo_data); + if (active_hostname == NULL) + log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's " + "helo_data value for callout: %s", expand_string_message); + else active_hostname = s; + } + deliver_host = deliver_host_address = NULL; deliver_domain = save_deliver_domain; @@ -462,50 +483,73 @@ for (host = host_list; host != NULL && !done; host = host->next) continue; } - /* Wait for initial response, and then run the initial SMTP commands. The - smtp_write_command() function leaves its command in big_buffer. This is - used in error responses. Initialize it in case the connection is - rejected. */ + /* Wait for initial response, and send HELO. The smtp_write_command() + function leaves its command in big_buffer. This is used in error responses. + Initialize it in case the connection is rejected. */ Ustrcpy(big_buffer, "initial connection"); done = smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout) && - smtp_write_command(&outblock, FALSE, "%s %s\r\n", helo, - smtp_active_hostname) >= 0 && + active_hostname) >= 0 && smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), - '2', callout) && + '2', callout); + /* Failure to accept HELO is cached; this blocks the whole domain for all + senders. I/O errors and defer responses are not cached. */ + + if (!done) + { + *failure_ptr = US"mail"; /* At or before MAIL */ + if (errno == 0 && responsebuffer[0] == '5') + { + setflag(addr, af_verify_nsfail); + new_domain_record.result = ccache_reject; + } + } + + /* Send the MAIL command */ + + else done = smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n", from_address) >= 0 && smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout); - /* If the host gave an initial error, or does not accept HELO or MAIL - FROM:<>, arrange to cache this information, but don't record anything for an - I/O error or a defer. Do not cache rejections when a non-empty sender has - been used, because that blocks the whole domain for all senders. */ + /* If the host does not accept MAIL FROM:<>, arrange to cache this + information, but again, don't record anything for an I/O error or a defer. Do + not cache rejections of MAIL when a non-empty sender has been used, because + that blocks the whole domain for all senders. */ if (!done) { - *failure_ptr = US"mail"; + *failure_ptr = US"mail"; /* At or before MAIL */ if (errno == 0 && responsebuffer[0] == '5') { setflag(addr, af_verify_nsfail); - if (from_address[0] == 0) new_domain_record.result = ccache_reject; + if (from_address[0] == 0) + new_domain_record.result = ccache_reject_mfnull; } } /* Otherwise, proceed to check a "random" address (if required), then the given address, and the postmaster address (if required). Between each check, issue RSET, because some servers accept only one recipient after MAIL - FROM:<>. */ + FROM:<>. + + Before doing this, set the result in the domain cache record to "accept", + unless its previous value was ccache_reject_mfnull. In that case, the domain + rejects MAIL FROM:<> and we want to continue to remember that. When that is + the case, we have got here only in the case of a recipient verification with + a non-null sender. */ else { - new_domain_record.result = ccache_accept; + new_domain_record.result = + (old_domain_cache_result == ccache_reject_mfnull)? + ccache_reject_mfnull: ccache_accept; /* Do the random local part check first */ @@ -685,7 +729,7 @@ However, there may be domain-specific information to cache in both cases. The value of the result field in the new_domain record is ccache_unknown if there was an error before or with MAIL FROM:, and errno was not zero, implying some kind of I/O error. We don't want to write the cache in that case. -Otherwise the value is ccache_accept or ccache_reject. */ +Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */ if (!callout_no_cache && new_domain_record.result != ccache_unknown) { @@ -793,6 +837,7 @@ if (addr != vaddr) vaddr->user_message = addr->user_message; vaddr->basic_errno = addr->basic_errno; vaddr->more_errno = addr->more_errno; + vaddr->p.address_data = addr->p.address_data; } return yield; } @@ -1040,10 +1085,21 @@ while (addr_new != NULL) { host_item *host_list = addr->host_list; - /* Default, if no remote transport, to NULL for the interface (=> any), - "smtp" for the port, and "smtp" for the protocol. */ - - transport_feedback tf = { NULL, US"smtp", US"smtp", NULL, FALSE, FALSE }; + /* Make up some data for use in the case where there is no remote + transport. */ + + transport_feedback tf = { + NULL, /* interface (=> any) */ + US"smtp", /* port */ + US"smtp", /* protocol */ + NULL, /* hosts */ + US"$smtp_active_hostname", /* helo_data */ + FALSE, /* hosts_override */ + FALSE, /* hosts_randomize */ + FALSE, /* gethostbyname */ + TRUE, /* qualify_single */ + FALSE /* search_parents */ + }; /* If verification yielded a remote transport, we want to use that transport's options, so as to mimic what would happen if we were really @@ -1261,9 +1317,12 @@ or autoreplies, and there were no errors or deferments, the message is to be discarded, usually because of the use of :blackhole: in an alias file. */ if (allok && addr_local == NULL && addr_remote == NULL) + { fprintf(f, "mail to %s is discarded\n", address); + return yield; + } -else for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++) +for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++) { while (addr_list != NULL) { @@ -1276,6 +1335,19 @@ else for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++) if(addr->p.srs_sender) fprintf(f, " [srs = %s]", addr->p.srs_sender); #endif + + /* If the address is a duplicate, show something about it. */ + + if (!testflag(addr, af_pfr)) + { + tree_node *tnode; + if ((tnode = tree_search(tree_duplicates, addr->unique)) != NULL) + fprintf(f, " [duplicate, would not be delivered]"); + else tree_add_duplicate(addr->unique, addr); + } + + /* Now show its parents */ + while (p != NULL) { fprintf(f, "\n <-- %s", p->address); @@ -2124,6 +2196,7 @@ if (*t == 0) h.name = ss; h.address = NULL; h.mx = MX_NONE; + rc = host_find_byname(&h, NULL, NULL, FALSE); if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL) {