X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/cb45303cf2a8d9922702f13db42b3285c48f6aa7..107077d7fd6736711bf5cd980221723401d37c51:/src/src/verify.c diff --git a/src/src/verify.c b/src/src/verify.c index ed0898c9b..d8ebf5925 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 - 2021 */ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ +/* Copyright (c) University of Cambridge 1995 - 2023 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* Functions concerned with verifying things. The original code for callout caching was contributed by Kevin Fleming (but I hacked it around a bit). */ @@ -445,6 +446,21 @@ return done; } + + +/* A rcpt callout, or cached record of one, verified the address. +Set $domain_data and $local_part_data to detainted versions. +*/ +static void +callout_verified_rcpt(const address_item * addr) +{ +address_item a = {.address = addr->address}; +if (deliver_split_address(&a) != OK) return; +deliver_localpart_data = string_copy_taint(a.local_part, GET_UNTAINTED); +deliver_domain_data = string_copy_taint(a.domain, GET_UNTAINTED); +} + + /************************************************* * Do callout verification for an address * *************************************************/ @@ -693,6 +709,30 @@ tls_retry_connection: if (yield != OK) { errno = addr->basic_errno; + + /* For certain errors we want specifically to log the transport name, + for ease of fixing config errors. Slightly ugly doing it here, but we want + to not leak that also in the SMTP response. */ + switch (errno) + { + case EPROTOTYPE: + case ENOPROTOOPT: + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EOPNOTSUPP: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + case EADDRINUSE: + case EADDRNOTAVAIL: + case ENETDOWN: + case ENETUNREACH: + log_write(0, LOG_MAIN|LOG_PANIC, + "%s verify %s (making calloout connection): T=%s %s", + options & vopt_is_recipient ? "sender" : "recipient", + yield == FAIL ? "fail" : "defer", + transport_name, strerror(errno)); + } + transport_name = NULL; deliver_host = deliver_host_address = NULL; deliver_domain = save_deliver_domain; @@ -1040,6 +1080,8 @@ no_conn: HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n"); } #ifndef DISABLE_DKIM + /* DKIM signing needs to add a header after seeing the whole body, so we cannot just copy + body bytes to the outbound as they are received, which is the intent of cutthrough. */ if (ob->dkim.dkim_domain) { cutthrough.delivery= FALSE; @@ -1311,7 +1353,13 @@ cutthrough_data_puts(US"\r\n", 2); } -/* Get and check response from cutthrough target */ +/* Get and check response from cutthrough target. +Used for +- nonfirst RCPT +- predata +- data finaldot +- cutthrough conn close +*/ static uschar cutthrough_response(client_conn_ctx * cctx, char expect, uschar ** copy, int timeout) { @@ -1325,7 +1373,7 @@ sx.inblock.ptr = inbuffer; sx.inblock.ptrend = inbuffer; sx.inblock.cctx = cctx; if(!smtp_read_response(&sx, responsebuffer, sizeof(responsebuffer), expect, timeout)) - cancel_cutthrough_connection(TRUE, US"target timeout on read"); + cancel_cutthrough_connection(TRUE, US"unexpected response to smtp command"); if(copy) { @@ -1952,6 +2000,12 @@ while (addr_new) #ifndef DISABLE_TLS deliver_set_expansions(NULL); #endif + if ( options & vopt_is_recipient + && rc == OK + /* set to "random", with OK, for an accepted random */ + && !recipient_verify_failure + ) + callout_verified_rcpt(addr); } } else if (local_verify) @@ -2934,7 +2988,7 @@ dots). */ for (t = ss; isdigit(*t) || *t == '.'; ) t++; if (!*t || (*t == '/' && t != ss)) { - *error = US"malformed IPv4 address or address mask"; + *error = string_sprintf("malformed IPv4 address or address mask: %.*s", (int)(t - ss), ss); return ERROR; } @@ -3053,7 +3107,7 @@ digits, full stops, and hyphens (the constituents of domain names). Allow underscores, as they are all too commonly found. Sigh. Also, if allow_utf8_domains is set, allow top-bit characters. */ -for (t = ss; *t != 0; t++) +for (t = ss; *t; t++) if (!isalnum(*t) && *t != '.' && *t != '-' && *t != '_' && (!allow_utf8_domains || *t < 128)) break; @@ -3061,7 +3115,7 @@ for (t = ss; *t != 0; t++) its IP address and match against that. Note that a multi-homed host will add items to the chain. */ -if (*t == 0) +if (!*t) { int rc; host_item h; @@ -3092,8 +3146,8 @@ outgoing hosts, the name is always given explicitly. If it is NULL, it means we must use sender_host_name and its aliases, looking them up if necessary. */ if (cb->host_name) /* Explicit host name given */ - return match_check_string(cb->host_name, ss, -1, TRUE, TRUE, TRUE, - valueptr); + return match_check_string(cb->host_name, ss, -1, + MCS_PARTIAL | MCS_CASELESS | MCS_AT_SPECIAL | cb->flags, valueptr); /* Host name not given; in principle we need the sender host name and its aliases. However, for query-style lookups, we do not need the name if the @@ -3122,7 +3176,9 @@ if ((semicolon = Ustrchr(ss, ';'))) if (isquery) { - switch(match_check_string(US"", ss, -1, TRUE, TRUE, TRUE, valueptr)) + switch(match_check_string(US"", ss, -1, + MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE), + valueptr)) { case OK: return OK; case DEFER: return DEFER; @@ -3148,7 +3204,9 @@ if (!sender_host_name) /* Match on the sender host name, using the general matching function */ -switch(match_check_string(sender_host_name, ss, -1, TRUE, TRUE, TRUE, valueptr)) +switch(match_check_string(sender_host_name, ss, -1, + MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE), + valueptr)) { case OK: return OK; case DEFER: return DEFER; @@ -3158,7 +3216,9 @@ switch(match_check_string(sender_host_name, ss, -1, TRUE, TRUE, TRUE, valueptr)) aliases = sender_host_aliases; while (*aliases) - switch(match_check_string(*aliases++, ss, -1, TRUE, TRUE, TRUE, valueptr)) + switch(match_check_string(*aliases++, ss, -1, + MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE), + valueptr)) { case OK: return OK; case DEFER: return DEFER; @@ -3234,8 +3294,8 @@ rc = match_check_list( check_host, /* function for testing */ &cb, /* argument for function */ MCL_HOST, /* type of check */ - (host_address == sender_host_address)? - US"host" : host_address, /* text for debugging */ + host_address == sender_host_address + ? US"host" : host_address, /* text for debugging */ valueptr); /* where to pass back data */ deliver_host_address = save_host_address; return rc;