*************************************************/
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
-/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* 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). */
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;
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;
}
-/* 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)
{
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)
{
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;
}
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;
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;
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
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;
/* 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;
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;
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;