X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/431b736177e2cdfd0b4da4c8545d8b732286abe1..c80c557026f3933b0472b13331924f8bd4ed9bf7:/src/src/verify.c diff --git a/src/src/verify.c b/src/src/verify.c index 3b0983919..475f52d92 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/verify.c,v 1.46 2007/01/17 11:17:58 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions concerned with verifying things. The original code for callout @@ -385,6 +383,14 @@ if (callout_overall < 0) callout_overall = 4 * callout; if (callout_connect < 0) callout_connect = callout; callout_start_time = time(NULL); +/* Before doing a real callout, if this is an SMTP connection, flush the SMTP +output because a callout might take some time. When PIPELINING is active and +there are many recipients, the total time for doing lots of callouts can add up +and cause the client to time out. So in this case we forgo the PIPELINING +optimization. */ + +if (smtp_out != NULL && !disable_callout_flush) mac_smtp_fflush(); + /* Now make connections to the hosts and do real callouts. The list of hosts is passed in as an argument. */ @@ -442,21 +448,6 @@ 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 (s == NULL) - log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's " - "helo_data value for callout: %s", addr->address, - expand_string_message); - else active_hostname = s; - } - - deliver_host = deliver_host_address = NULL; - deliver_domain = save_deliver_domain; - /* Set HELO string according to the protocol */ if (Ustrcmp(tf->protocol, "lmtp") == 0) helo = US"LHLO"; @@ -487,9 +478,26 @@ for (host = host_list; host != NULL && !done; host = host->next) { addr->message = string_sprintf("could not connect to %s [%s]: %s", host->name, host->address, strerror(errno)); + deliver_host = deliver_host_address = NULL; + deliver_domain = save_deliver_domain; continue; } + /* 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 (s == NULL) + log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's " + "helo_data value for callout: %s", addr->address, + expand_string_message); + else active_hostname = s; + } + + deliver_host = deliver_host_address = NULL; + deliver_domain = save_deliver_domain; + /* 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. */ @@ -845,6 +853,7 @@ if (addr != vaddr) vaddr->basic_errno = addr->basic_errno; vaddr->more_errno = addr->more_errno; vaddr->p.address_data = addr->p.address_data; + copyflag(vaddr, addr, af_pass_message); } return yield; } @@ -852,6 +861,42 @@ return yield; +/************************************************** +* printf that automatically handles TLS if needed * +***************************************************/ + +/* This function is used by verify_address() as a substitute for all fprintf() +calls; a direct fprintf() will not produce output in a TLS SMTP session, such +as a response to an EXPN command. smtp_in.c makes smtp_printf available but +that assumes that we always use the smtp_out FILE* when not using TLS or the +ssl buffer when we are. Instead we take a FILE* parameter and check to see if +that is smtp_out; if so, smtp_printf() with TLS support, otherwise regular +fprintf(). + +Arguments: + f the candidate FILE* to write to + format format string + ... optional arguments + +Returns: + nothing +*/ + +static void PRINTF_FUNCTION(2,3) +respond_printf(FILE *f, const char *format, ...) +{ +va_list ap; + +va_start(ap, format); +if (smtp_out && (f == smtp_out)) + smtp_vprintf(format, ap); +else + vfprintf(f, format, ap); +va_end(ap); +} + + + /************************************************* * Verify an email address * *************************************************/ @@ -951,8 +996,8 @@ if (parse_find_at(address) == NULL) if ((options & vopt_qualify) == 0) { if (f != NULL) - fprintf(f, "%sA domain is required for \"%s\"%s\n", ko_prefix, address, - cr); + respond_printf(f, "%sA domain is required for \"%s\"%s\n", + ko_prefix, address, cr); *failure_ptr = US"qualify"; return FAIL; } @@ -1216,24 +1261,25 @@ while (addr_new != NULL) { address_item *p = addr->parent; - fprintf(f, "%s%s %s", ko_prefix, full_info? addr->address : address, + respond_printf(f, "%s%s %s", ko_prefix, + full_info? addr->address : address, address_test_mode? "is undeliverable" : "failed to verify"); if (!expn && admin_user) { if (addr->basic_errno > 0) - fprintf(f, ": %s", strerror(addr->basic_errno)); + respond_printf(f, ": %s", strerror(addr->basic_errno)); if (addr->message != NULL) - fprintf(f, ": %s", addr->message); + respond_printf(f, ": %s", addr->message); } /* Show parents iff doing full info */ if (full_info) while (p != NULL) { - fprintf(f, "%s\n <-- %s", cr, p->address); + respond_printf(f, "%s\n <-- %s", cr, p->address); p = p->parent; } - fprintf(f, "%s\n", cr); + respond_printf(f, "%s\n", cr); } if (!full_info) return copy_error(vaddr, addr, FAIL); @@ -1248,28 +1294,27 @@ while (addr_new != NULL) if (f != NULL) { address_item *p = addr->parent; - fprintf(f, "%s%s cannot be resolved at this time", ko_prefix, + respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix, full_info? addr->address : address); if (!expn && admin_user) { if (addr->basic_errno > 0) - fprintf(f, ": %s", strerror(addr->basic_errno)); + respond_printf(f, ": %s", strerror(addr->basic_errno)); if (addr->message != NULL) - fprintf(f, ": %s", addr->message); + respond_printf(f, ": %s", addr->message); else if (addr->basic_errno <= 0) - fprintf(f, ": unknown error"); + respond_printf(f, ": unknown error"); } /* Show parents iff doing full info */ if (full_info) while (p != NULL) { - fprintf(f, "%s\n <-- %s", cr, p->address); + respond_printf(f, "%s\n <-- %s", cr, p->address); p = p->parent; } - fprintf(f, "%s\n", cr); + respond_printf(f, "%s\n", cr); } - if (!full_info) return copy_error(vaddr, addr, DEFER); else if (yield == OK) yield = DEFER; } @@ -1283,16 +1328,16 @@ while (addr_new != NULL) if (addr_new == NULL) { if (addr_local == NULL && addr_remote == NULL) - fprintf(f, "250 mail to <%s> is discarded\r\n", address); + respond_printf(f, "250 mail to <%s> is discarded\r\n", address); else - fprintf(f, "250 <%s>\r\n", address); + respond_printf(f, "250 <%s>\r\n", address); } else while (addr_new != NULL) { address_item *addr2 = addr_new; addr_new = addr2->next; if (addr_new == NULL) ok_prefix = US"250 "; - fprintf(f, "%s<%s>\r\n", ok_prefix, addr2->address); + respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address); } return OK; } @@ -2191,7 +2236,8 @@ if (iplookup) name, we have to fish the file off the start of the query. For a single-key lookup, the key is the current IP address, masked appropriately, and reconverted to text form, with the mask appended. For IPv6 addresses, specify - dot separators instead of colons. */ + dot separators instead of colons, except when the lookup type is "iplsearch". + */ if (mac_islookup(search_type, lookup_absfilequery)) { @@ -2206,11 +2252,13 @@ if (iplookup) filename = NULL; key = semicolon + 1; } - else + else /* Single-key style */ { + int sep = (Ustrcmp(lookup_list[search_type]->name, "iplsearch") == 0)? + ':' : '.'; insize = host_aton(cb->host_address, incoming); host_mask(insize, incoming, mlen); - (void)host_nmtoa(insize, incoming, mlen, buffer, '.'); + (void)host_nmtoa(insize, incoming, mlen, buffer, sep); key = buffer; filename = semicolon + 1; } @@ -2463,16 +2511,18 @@ return verify_check_this_host(listptr, sender_host_cache, NULL, /************************************************* -* Invert an IP address for a DNS black list * +* Invert an IP address * *************************************************/ -/* +/* Originally just used for DNS xBL lists, now also used for the +reverse_ip expansion operator. + Arguments: buffer where to put the answer address the address to invert */ -static void +void invert_address(uschar *buffer, uschar *address) { int bin[4]; @@ -2986,7 +3036,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL for (s = domain; *s != 0; s++) { - if (!isalnum(*s) && *s != '-' && *s != '.') + if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_') { log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains " "strange characters - is this right?", domain); @@ -2998,7 +3048,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL if (domain_txt != domain) for (s = domain_txt; *s != 0; s++) { - if (!isalnum(*s) && *s != '-' && *s != '.') + if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_') { log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains " "strange characters - is this right?", domain_txt); @@ -3018,6 +3068,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL if (rc == OK) { dnslist_domain = string_copy(domain_txt); + dnslist_matched = string_copy(sender_host_address); HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n", sender_host_address, dnslist_domain); } @@ -3052,6 +3103,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL if (rc == OK) { dnslist_domain = string_copy(domain_txt); + dnslist_matched = string_copy(keydomain); HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n", keydomain, dnslist_domain); return OK;