* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions concerned with verifying things. The original code for callout
int callout, int callout_overall, int callout_connect, int options,
uschar *se_mailfrom, uschar *pm_mailfrom)
{
-BOOL is_recipient = (options & vopt_is_recipient) != 0;
-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 *from_address;
uschar *random_local_part = NULL;
const uschar *save_deliver_domain = deliver_domain;
-uschar **failure_ptr = is_recipient?
- &recipient_verify_failure : &sender_verify_failure;
+uschar **failure_ptr = options & vopt_is_recipient
+ ? &recipient_verify_failure : &sender_verify_failure;
open_db dbblock;
open_db *dbm_file = NULL;
dbdata_callout_cache new_domain_record;
dbdata_callout_cache_address new_address_record;
host_item *host;
time_t callout_start_time;
-#ifdef EXPERIMENTAL_INTERNATIONAL
-BOOL utf8_offered = FALSE;
-#endif
+uschar peer_offered = 0;
new_domain_record.result = ccache_unknown;
new_domain_record.postmaster_result = ccache_unknown;
address_key = addr->address;
from_address = US"";
-if (is_recipient)
+if (options & vopt_is_recipient)
{
if (options & vopt_callout_recipsender)
{
address_key = string_sprintf("%s/<%s>", addr->address, sender_address);
from_address = sender_address;
+ if (cutthrough.delivery) options |= vopt_callout_no_cache;
}
else if (options & vopt_callout_recippmaster)
{
/* Open the callout cache database, it it exists, for reading only at this
stage, unless caching has been disabled. */
-if (callout_no_cache)
+if (options & vopt_callout_no_cache)
{
HDEBUG(D_verify) debug_printf("callout cache: disabled by no_cache\n");
}
the data in the new record. If a random check is required but hasn't been
done, skip the remaining cache processing. */
- if (callout_random) switch(cache_record->random_result)
+ if (options & vopt_callout_random) switch(cache_record->random_result)
{
case ccache_accept:
- HDEBUG(D_verify)
- debug_printf("callout cache: domain accepts random addresses\n");
- goto END_CALLOUT; /* Default yield is OK */
+ HDEBUG(D_verify)
+ debug_printf("callout cache: domain accepts random addresses\n");
+ goto END_CALLOUT; /* Default yield is OK */
case ccache_reject:
- HDEBUG(D_verify)
- debug_printf("callout cache: domain rejects random addresses\n");
- callout_random = FALSE;
- new_domain_record.random_result = ccache_reject;
- new_domain_record.random_stamp = cache_record->random_stamp;
- break;
+ HDEBUG(D_verify)
+ debug_printf("callout cache: domain rejects random addresses\n");
+ options &= ~vopt_callout_random;
+ new_domain_record.random_result = ccache_reject;
+ new_domain_record.random_stamp = cache_record->random_stamp;
+ break;
default:
- HDEBUG(D_verify)
- debug_printf("callout cache: need to check random address handling "
- "(not cached or cache expired)\n");
- goto END_CACHE;
+ HDEBUG(D_verify)
+ debug_printf("callout cache: need to check random address handling "
+ "(not cached or cache expired)\n");
+ goto END_CACHE;
}
/* If a postmaster check is requested, but there was a previous failure,
with a random local part, ensure that such a local part is available. If not,
log the fact, but carry on without randomming. */
- if (callout_random && callout_random_local_part != NULL)
+ if (options & vopt_callout_random && callout_random_local_part != NULL)
if (!(random_local_part = expand_string(callout_random_local_part)))
log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
"callout_random_local_part: %s", expand_string_message);
&& port == cutthrough.host.port
)
{
- uschar * resp;
+ uschar * resp = NULL;
/* Match! Send the RCPT TO, append the addr, set done */
done =
else
{
cancel_cutthrough_connection("recipient rejected");
- if (errno == ETIMEDOUT)
+ if (!resp || errno == ETIMEDOUT)
{
HDEBUG(D_verify) debug_printf("SMTP timeout\n");
}
uschar inbuffer[4096];
uschar outbuffer[1024];
uschar responsebuffer[4096];
+ uschar * size_str;
clearflag(addr, af_verify_pmfail); /* postmaster callout flag */
clearflag(addr, af_verify_nsfail); /* null sender callout flag */
if (host->dnssec == DS_YES)
{
- if( ( dane_required
- || verify_check_given_host(&ob->hosts_try_dane, host) == OK
- )
- && (rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK
+ if( dane_required
+ || verify_check_given_host(&ob->hosts_try_dane, host) == OK
)
- return rc;
+ {
+ if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required)) != OK)
+ return rc;
+ dane = TRUE;
+ }
}
else if (dane_required)
{
if (!(done= smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout)))
goto RESPONSE_FAILED;
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes"
: host->dnssec==DS_NO ? US"no" : NULL;
if (event_raise(addr->transport->event_action,
#ifdef SUPPORT_TLS
if (smtps && tls_out.active < 0) /* ssl-on-connect, first pass */
{
- tls_offered = TRUE;
+ peer_offered &= ~PEER_OFFERED_TLS;
ob->tls_tempfail_tryclear = FALSE;
}
else /* all other cases */
goto RESPONSE_FAILED;
}
#ifdef SUPPORT_TLS
- tls_offered = FALSE;
+ peer_offered &= ~PEER_OFFERED_TLS;
#endif
esmtp = FALSE;
goto esmtp_retry; /* fallback to HELO */
}
/* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
-#ifdef SUPPORT_TLS
- if (esmtp && !suppress_tls && tls_out.active < 0)
- {
- if (regex_STARTTLS == NULL) regex_STARTTLS =
- regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
- tls_offered = pcre_exec(regex_STARTTLS, NULL, CS responsebuffer,
- Ustrlen(responsebuffer), 0, PCRE_EOPT, NULL, 0) >= 0;
- }
- else
- tls_offered = FALSE;
+ peer_offered = esmtp
+ ? ehlo_response(responsebuffer, sizeof(responsebuffer),
+ (!suppress_tls && tls_out.active < 0 ? PEER_OFFERED_TLS : 0)
+ | 0 /* no IGNQ */
+ | 0 /* no PRDR */
+#ifdef SUPPORT_I18N
+ | (addr->prop.utf8_msg && !addr->prop.utf8_downcvt
+ ? PEER_OFFERED_UTF8 : 0)
#endif
+ | 0 /* no DSN */
+ | 0 /* no PIPE */
+
+ /* only care about SIZE if we have size from inbound */
+ | (message_size > 0 && ob->size_addition >= 0
+ ? PEER_OFFERED_SIZE : 0)
+ )
+ : 0;
}
+ size_str = peer_offered & PEER_OFFERED_SIZE
+ ? string_sprintf(" SIZE=%d", message_size + ob->size_addition) : US"";
+
+#ifdef SUPPORT_TLS
+ smtp_peer_options |= peer_offered & PEER_OFFERED_TLS;
+#endif
+
/* If TLS is available on this connection attempt to
start up a TLS session, unless the host is in hosts_avoid_tls. If successful,
send another EHLO - the server may give a different answer in secure mode. We
for error analysis. */
#ifdef SUPPORT_TLS
- if ( tls_offered
+ if ( peer_offered & PEER_OFFERED_TLS
&& verify_check_given_host(&ob->hosts_avoid_tls, host) != OK
&& verify_check_given_host(&ob->hosts_verify_avoid_tls, host) != OK
)
if (!smtps && !smtp_read_response(&inblock, buffer2, sizeof(buffer2), '2',
ob->command_timeout))
{
- if (errno != 0 || buffer2[0] == 0 ||
- (buffer2[0] == '4' && !ob->tls_tempfail_tryclear))
+ if ( errno != 0
+ || buffer2[0] == 0
+ || buffer2[0] == '4' && !ob->tls_tempfail_tryclear
+ )
{
Ustrncpy(responsebuffer, buffer2, sizeof(responsebuffer));
done= FALSE;
if (rc == DEFER)
{
(void)close(inblock.sock);
-# ifdef EXPERIMENTAL_EVENT
+# ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
# endif
-# ifdef EXPERIMENTAL_DANE
- if (dane)
- {
- if (!dane_required)
- {
- log_write(0, LOG_MAIN, "DANE attempt failed;"
- " trying CA-root TLS to %s [%s] (not in hosts_require_dane)",
- host->name, host->address);
- dane = FALSE;
- goto tls_negotiate;
- }
- }
- else
-# endif
- if ( ob->tls_tempfail_tryclear
- && !smtps
- && verify_check_given_host(&ob->hosts_require_tls, host) != OK
- )
+ if ( ob->tls_tempfail_tryclear
+ && !smtps
+ && verify_check_given_host(&ob->hosts_require_tls, host) != OK
+ )
{
log_write(0, LOG_MAIN, "TLS session failure:"
" delivering unencrypted to %s [%s] (not in hosts_require_tls)",
log_write(0, LOG_MAIN,
"H=%s [%s]: a TLS session is required for this host, but %s",
host->name, host->address,
- tls_offered ? "an attempt to start TLS failed"
- : "the server did not offer TLS support");
+ peer_offered & PEER_OFFERED_TLS
+ ? "an attempt to start TLS failed"
+ : "the server did not offer TLS support");
done= FALSE;
goto TLS_FAILED;
}
done = TRUE; /* so far so good; have response to HELO */
- /*XXX the EHLO response would be analyzed here for IGNOREQUOTA, SIZE, PIPELINING */
-
/* For now, transport_filter by cutthrough-delivery is not supported */
/* Need proper integration with the proper transport mechanism. */
if (cutthrough.delivery)
{
+#ifndef DISABLE_DKIM
+ uschar * s;
+#endif
if (addr->transport->filter_command)
{
cutthrough.delivery = FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
}
#ifndef DISABLE_DKIM
- if (ob->dkim_domain)
+ else if ((s = ob->dkim.dkim_domain) && (s = expand_string(s)) && *s)
{
cutthrough.delivery = FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
}
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
else if ( addr->prop.utf8_msg
&& !addr->prop.utf8_downcvt
- && !( esmtp
- && ( regex_UTF8
- || ( (regex_UTF8 = regex_must_compile(
- US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE)),
- TRUE
- ) )
- && ( (utf8_offered = pcre_exec(regex_UTF8, NULL,
- CS responsebuffer, Ustrlen(responsebuffer),
- 0, PCRE_EOPT, NULL, 0) >= 0)
- || addr->prop.utf8_downcvt_maybe
- ) ) )
+ && !(peer_offered & PEER_OFFERED_UTF8)
+ )
{
HDEBUG(D_acl|D_v) debug_printf("utf8 required but not offered\n");
errno = ERRNO_UTF8_FWD;
done = FALSE;
}
else if ( addr->prop.utf8_msg
- && (addr->prop.utf8_downcvt || !utf8_offered)
+ && (addr->prop.utf8_downcvt || !(peer_offered & PEER_OFFERED_UTF8))
&& (setflag(addr, af_utf8_downcvt),
from_address = string_address_utf8_to_alabel(from_address,
&addr->message),
/* Send the MAIL command */
(smtp_write_command(&outblock, FALSE,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
addr->prop.utf8_msg && !addr->prop.utf8_downcvt
- ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
+ ? "MAIL FROM:<%s>%s%s SMTPUTF8\r\n"
:
#endif
- "MAIL FROM:<%s>%s\r\n",
- from_address, responsebuffer) >= 0)
+ "MAIL FROM:<%s>%s%s\r\n",
+ from_address, responsebuffer, size_str) >= 0)
) &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
{
const uschar * rcpt_domain = addr->domain;
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
uschar * errstr = NULL;
if ( testflag(addr, af_utf8_downcvt)
&& (rcpt_domain = string_domain_utf8_to_alabel(rcpt_domain,
'2', callout) &&
smtp_write_command(&outblock, FALSE,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
addr->prop.utf8_msg && !addr->prop.utf8_downcvt
? "MAIL FROM:<%s> SMTPUTF8\r\n"
:
tls_close(FALSE, TRUE);
#endif
(void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
#endif
uschar * rcpt = transport_rcpt_address(addr,
addr->transport ? addr->transport->rcpt_include_affixes : FALSE);
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
/*XXX should the conversion be moved into transport_rcpt_address() ? */
uschar * dummy_errstr = NULL;
if ( testflag(addr, af_utf8_downcvt)
HDEBUG(D_verify) debug_printf("SMTP timeout\n");
send_quit = FALSE;
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
else if (errno == ERRNO_UTF8_FWD)
{
extern int acl_where; /* src/acl.c */
big_buffer, host->name, host->address,
string_printing(responsebuffer));
- addr->user_message = is_recipient?
- string_sprintf("Callout verification failed:\n%s", responsebuffer)
- :
- string_sprintf("Called: %s\nSent: %s\nResponse: %s",
+ addr->user_message = options & vopt_is_recipient
+ ? string_sprintf("Callout verification failed:\n%s", responsebuffer)
+ : string_sprintf("Called: %s\nSent: %s\nResponse: %s",
host->address, big_buffer, responsebuffer);
/* Hard rejection ends the process */
&& rcpt_count == 1
&& done
&& yield == OK
- && (options & (vopt_callout_recipsender|vopt_callout_recippmaster)) == vopt_callout_recipsender
+ && (options & (vopt_callout_recipsender|vopt_callout_recippmaster|vopt_success_on_redirect))
+ == vopt_callout_recipsender
&& !random_local_part
&& !pm_mailfrom
&& cutthrough.fd < 0
&& !lmtp
)
{
+ HDEBUG(D_acl|D_v) debug_printf("holding verify callout open for cutthrough delivery\n");
+
cutthrough.fd = outblock.sock; /* We assume no buffer in use in the outblock */
cutthrough.nrcpt = 1;
cutthrough.interface = interface;
tls_close(FALSE, TRUE);
#endif
(void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
#endif
}
implying some kind of I/O error. We don't want to write the cache in that case.
Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */
-if (!callout_no_cache && new_domain_record.result != ccache_unknown)
+if ( !(options & vopt_callout_no_cache)
+ && new_domain_record.result != ccache_unknown)
{
if ((dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE))
== NULL)
{
(void)dbfn_write(dbm_file, addr->domain, &new_domain_record,
(int)sizeof(dbdata_callout_cache));
- HDEBUG(D_verify) debug_printf("wrote callout cache domain record:\n"
+ HDEBUG(D_verify) debug_printf("wrote callout cache domain record for %s:\n"
" result=%d postmaster=%d random=%d\n",
+ addr->domain,
new_domain_record.result,
new_domain_record.postmaster_result,
new_domain_record.random_result);
if (done)
{
- if (!callout_no_cache && new_address_record.result != ccache_unknown)
+ if ( !(options & vopt_callout_no_cache)
+ && new_address_record.result != ccache_unknown)
{
if (dbm_file == NULL)
dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE);
{
(void)dbfn_write(dbm_file, address_key, &new_address_record,
(int)sizeof(dbdata_callout_cache_address));
- HDEBUG(D_verify) debug_printf("wrote %s callout cache address record\n",
- (new_address_record.result == ccache_accept)? "positive" : "negative");
+ HDEBUG(D_verify) debug_printf("wrote %s callout cache address record for %s\n",
+ new_address_record.result == ccache_accept ? "positive" : "negative",
+ address_key);
}
}
} /* done */
else /* !done */
{
uschar *dullmsg = string_sprintf("Could not complete %s verify callout",
- is_recipient? "recipient" : "sender");
+ options & vopt_is_recipient ? "recipient" : "sender");
yield = DEFER;
if (host_list->next != NULL || addr->message == NULL) addr->message = dullmsg;
"The mail server(s) for the domain may be temporarily unreachable, or\n"
"they may be permanently unreachable from this server. In the latter case,\n%s",
dullmsg, addr->address,
- is_recipient?
- "the address will never be accepted."
- :
- "you need to change the address or create an MX record for its domain\n"
- "if it is supposed to be generally accessible from the Internet.\n"
- "Talk to your mail administrator for details.");
+ options & vopt_is_recipient
+ ? "the address will never be accepted."
+ : "you need to change the address or create an MX record for its domain\n"
+ "if it is supposed to be generally accessible from the Internet.\n"
+ "Talk to your mail administrator for details.");
/* Force a specific error code */
/* Called after recipient-acl to get a cutthrough connection open when
one was requested and a recipient-verify wasn't subsequently done.
*/
-void
+int
open_cutthrough_connection( address_item * addr )
{
address_item addr2;
+int rc;
/* Use a recipient-verify-callout to set up the cutthrough connection. */
/* We must use a copy of the address for verification, because it might
addr2 = *addr;
HDEBUG(D_acl) debug_printf("----------- %s cutthrough setup ------------\n",
rcpt_count > 1 ? "more" : "start");
-(void) verify_address(&addr2, NULL,
+rc= verify_address(&addr2, NULL,
vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache,
CUTTHROUGH_CMD_TIMEOUT, -1, -1,
NULL, NULL, NULL);
HDEBUG(D_acl) debug_printf("----------- end cutthrough setup ------------\n");
-return;
+return rc;
}
}
-/* fd and use_crlf args only to match write_chunk() */
+/* fd and tctx args only to match write_chunk() */
static BOOL
-cutthrough_write_chunk(int fd, uschar * s, int len, BOOL use_crlf)
+cutthrough_write_chunk(int fd, transport_ctx * tctx, uschar * s, int len)
{
uschar * s2;
while(s && (s2 = Ustrchr(s, '\n')))
BOOL
cutthrough_headers_send(void)
{
+transport_ctx tctx;
+
if(cutthrough.fd < 0)
return FALSE;
*/
HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n");
-if (!transport_headers_send(&cutthrough.addr, cutthrough.fd,
- cutthrough.addr.transport->add_headers,
- cutthrough.addr.transport->remove_headers,
- &cutthrough_write_chunk, TRUE,
- cutthrough.addr.transport->rewrite_rules,
- cutthrough.addr.transport->rewrite_existflags))
+tctx.tblock = cutthrough.addr.transport;
+tctx.addr = &cutthrough.addr;
+tctx.check_string = US".";
+tctx.escape_string = US"..";
+tctx.options = topt_use_crlf;
+
+if (!transport_headers_send(cutthrough.fd, &tctx, &cutthrough_write_chunk))
return FALSE;
HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n");
{
BOOL allok = TRUE;
BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0);
-BOOL is_recipient = (options & vopt_is_recipient) != 0;
BOOL expn = (options & vopt_expn) != 0;
BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0;
int i;
int yield = OK;
int verify_type = expn? v_expn :
address_test_mode? v_none :
- is_recipient? v_recipient : v_sender;
+ options & vopt_is_recipient? v_recipient : v_sender;
address_item *addr_list;
address_item *addr_new = NULL;
address_item *addr_remote = NULL;
address_item *addr_local = NULL;
address_item *addr_succeed = NULL;
-uschar **failure_ptr = is_recipient?
- &recipient_verify_failure : &sender_verify_failure;
+uschar **failure_ptr = options & vopt_is_recipient
+ ? &recipient_verify_failure : &sender_verify_failure;
uschar *ko_prefix, *cr;
uschar *address = vaddr->address;
uschar *save_sender;
*failure_ptr = US"qualify";
return FAIL;
}
- address = rewrite_address_qualify(address, is_recipient);
+ address = rewrite_address_qualify(address, options & vopt_is_recipient);
}
DEBUG(D_verify)
if (global_rewrite_rules != NULL)
{
uschar *old = address;
- address = rewrite_address(address, is_recipient, FALSE,
+ address = rewrite_address(address, options & vopt_is_recipient, FALSE,
global_rewrite_rules, rewrite_existflags);
if (address != old)
{
/* Flip the legacy TLS-related variables over to the outbound set in case
they're used in the context of a transport used by verification. Reset them
-at exit from this routine. */
+at exit from this routine (so no returns allowed from here on). */
tls_modify_variables(&tls_out);
save_sender = sender_address;
+/* Observability variable for router/transport use */
+
+verify_mode = options & vopt_is_recipient ? US"R" : US"S";
+
/* Update the address structure with the possibly qualified and rewritten
address. Set it up as the starting address on the chain of new addresses. */
full_info is set, and this can only be set locally. Remote enquiries just get
information about the top level address, not anything that it generated. */
-while (addr_new != NULL)
+while (addr_new)
{
int rc;
address_item *addr = addr_new;
/* Just in case some router parameter refers to it. */
- return_path = (addr->prop.errors_address != NULL)?
- addr->prop.errors_address : sender_address;
+ return_path = addr->prop.errors_address
+ ? addr->prop.errors_address : sender_address;
/* Split the address into domain and local part, handling the %-hack if
necessary, and then route it. While routing a sender address, set
$sender_address to <> because that is what it will be if we were trying to
send a bounce to the sender. */
- if (routed != NULL) *routed = FALSE;
+ if (routed) *routed = FALSE;
if ((rc = deliver_split_address(addr)) == OK)
{
- if (!is_recipient) sender_address = null_sender;
+ if (!(options & vopt_is_recipient)) sender_address = null_sender;
rc = route_address(addr, &addr_local, &addr_remote, &addr_new,
&addr_succeed, verify_type);
sender_address = save_sender; /* Put back the real sender */
if (rc == OK)
{
- if (routed != NULL) *routed = TRUE;
+ if (routed) *routed = TRUE;
if (callout > 0)
{
- host_item *host_list = addr->host_list;
transport_instance * tp;
+ host_item * host_list = addr->host_list;
/* Make up some data for use in the case where there is no remote
transport. */
transport is configured to override the router's hosts, we must build a
host list of the transport's hosts, and find the IP addresses */
- if (tf.hosts != NULL && (host_list == NULL || tf.hosts_override))
+ if (tf.hosts && (!host_list || tf.hosts_override))
{
uschar *s;
const uschar *save_deliver_domain = deliver_domain;
deliver_domain = save_deliver_domain;
deliver_localpart = save_deliver_localpart;
- if (s == NULL)
+ if (!s)
{
log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
"\"%s\" in %s transport for callout: %s", tf.hosts,
if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
- for (host = host_list; host != NULL; host = nexthost)
+ for (host = host_list; host; host = nexthost)
{
nexthost = host->next;
if (tf.gethostbyname ||
/* Can only do a callout if we have at least one host! If the callout
fails, it will have set ${sender,recipient}_verify_failure. */
- if (host_list != NULL)
+ if (host_list)
{
HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
if (host_checking && !host_checking_callout)
#ifdef SUPPORT_TLS
deliver_set_expansions(addr);
#endif
- verify_mode = is_recipient ? US"R" : US"S";
rc = do_callout(addr, host_list, &tf, callout, callout_overall,
callout_connect, options, se_mailfrom, pm_mailfrom);
- verify_mode = NULL;
}
}
else
if (rc == FAIL)
{
allok = FALSE;
- if (f != NULL)
+ if (f)
{
address_item *p = addr->parent;
respond_printf(f, "%s%s %s", ko_prefix,
- full_info? addr->address : address,
- address_test_mode? "is undeliverable" : "failed to verify");
+ full_info ? addr->address : address,
+ address_test_mode ? "is undeliverable" : "failed to verify");
if (!expn && admin_user)
{
if (addr->basic_errno > 0)
respond_printf(f, ": %s", strerror(addr->basic_errno));
- if (addr->message != NULL)
+ if (addr->message)
respond_printf(f, ": %s", addr->message);
}
/* Show parents iff doing full info */
- if (full_info) while (p != NULL)
+ if (full_info) while (p)
{
respond_printf(f, "%s\n <-- %s", cr, p->address);
p = p->parent;
cancel_cutthrough_connection("routing hard fail");
if (!full_info)
- {
+ {
yield = copy_error(vaddr, addr, FAIL);
goto out;
- }
- else yield = FAIL;
+ }
+ yield = FAIL;
}
/* Soft failure */
else if (rc == DEFER)
{
allok = FALSE;
- if (f != NULL)
+ if (f)
{
address_item *p = addr->parent;
respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
{
if (addr->basic_errno > 0)
respond_printf(f, ": %s", strerror(addr->basic_errno));
- if (addr->message != NULL)
+ if (addr->message)
respond_printf(f, ": %s", addr->message);
else if (addr->basic_errno <= 0)
respond_printf(f, ": unknown error");
/* Show parents iff doing full info */
- if (full_info) while (p != NULL)
+ if (full_info) while (p)
{
respond_printf(f, "%s\n <-- %s", cr, p->address);
p = p->parent;
yield = copy_error(vaddr, addr, DEFER);
goto out;
}
- else if (yield == OK) yield = DEFER;
+ if (yield == OK) yield = DEFER;
}
/* If we are handling EXPN, we do not want to continue to route beyond
else if (expn)
{
uschar *ok_prefix = US"250-";
- if (addr_new == NULL)
- {
- if (addr_local == NULL && addr_remote == NULL)
+
+ if (!addr_new)
+ if (!addr_local && !addr_remote)
respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
else
respond_printf(f, "250 <%s>\r\n", address);
- }
- else while (addr_new != NULL)
+
+ else do
{
address_item *addr2 = addr_new;
addr_new = addr2->next;
- if (addr_new == NULL) ok_prefix = US"250 ";
+ if (!addr_new) ok_prefix = US"250 ";
respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
- }
+ } while (addr_new);
yield = OK;
goto out;
}
just a single new address as a special case, and continues on to verify the
generated address. */
- if (!full_info && /* Stop if short info wanted AND */
- (((addr_new == NULL || /* No new address OR */
- addr_new->next != NULL || /* More than one new address OR */
- testflag(addr_new, af_pfr))) /* New address is pfr */
- || /* OR */
- (addr_new != NULL && /* At least one new address AND */
- success_on_redirect))) /* success_on_redirect is set */
+ if ( !full_info /* Stop if short info wanted AND */
+ && ( ( !addr_new /* No new address OR */
+ || addr_new->next /* More than one new address OR */
+ || testflag(addr_new, af_pfr) /* New address is pfr */
+ )
+ || /* OR */
+ ( addr_new /* At least one new address AND */
+ && success_on_redirect /* success_on_redirect is set */
+ ) )
+ )
{
- if (f != NULL) fprintf(f, "%s %s\n", address,
- address_test_mode? "is deliverable" : "verified");
+ if (f) fprintf(f, "%s %s\n",
+ address, address_test_mode ? "is deliverable" : "verified");
/* If we have carried on to verify a child address, we want the value
of $address_data to be that of the child */
vaddr->prop.address_data = addr->prop.address_data;
+
+ /* If stopped because more than one new address, cannot cutthrough */
+
+ if (addr_new && addr_new->next)
+ cancel_cutthrough_connection("multiple addresses from routing");
+
yield = OK;
goto out;
}
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)
+if (allok && !addr_local && !addr_remote)
{
fprintf(f, "mail to %s is discarded\n", address);
goto out;
the -bv or -bt case). */
out:
+verify_mode = NULL;
tls_modify_variables(&tls_in);
return yield;
/* Now do the actual lookup; note that there is no search_close() because
of the caching arrangements. */
- handle = search_open(filename, search_type, 0, NULL, NULL);
- if (handle == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- search_error_message);
+ if (!(handle = search_open(filename, search_type, 0, NULL, NULL)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
+
result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL);
if (valueptr != NULL) *valueptr = result;
return (result != NULL)? OK : search_find_defer? DEFER: FAIL;
Note: a domain for testing RFCI is example.tld.dsn.rfc-ignorant.org
Arguments:
+ where the acl type
listptr the domain/address/data list
+ log_msgptr log message on error
Returns: OK successful lookup (i.e. the address is on the list), or
lookup deferred after +include_unknown
*/
int
-verify_check_dnsbl(const uschar **listptr)
+verify_check_dnsbl(int where, const uschar ** listptr, uschar ** log_msgptr)
{
int sep = 0;
int defer_return = FAIL;
/* See if there's explicit data to be looked up */
- key = Ustrchr(domain, '/');
- if (key != NULL) *key++ = 0;
+ if ((key = Ustrchr(domain, '/'))) *key++ = 0;
/* See if there's a list of addresses supplied after the domain name. This is
introduced by an = or a & character; if preceded by = we require all matches
and if preceded by ! we invert the result. */
- iplist = Ustrchr(domain, '=');
- if (iplist == NULL)
+ if (!(iplist = Ustrchr(domain, '=')))
{
bitmask = TRUE;
iplist = Ustrchr(domain, '&');
}
- if (iplist != NULL) /* Found either = or & */
+ if (iplist) /* Found either = or & */
{
if (iplist > domain && iplist[-1] == '!') /* Handle preceding ! */
{
}
}
+
/* If there is a comma in the domain, it indicates that a second domain for
looking up TXT records is provided, before the main domain. Otherwise we must
set domain_txt == domain. */
if (key == NULL)
{
+ if (where == ACL_WHERE_NOTSMTP_START || where == ACL_WHERE_NOTSMTP)
+ {
+ *log_msgptr = string_sprintf
+ ("cannot test auto-keyed dnslists condition in %s ACL",
+ acl_wherenames[where]);
+ return ERROR;
+ }
if (sender_host_address == NULL) return FAIL; /* can never match */
if (revadd[0] == 0) invert_address(revadd, sender_host_address);
rc = one_check_dnsbl(domain, domain_txt, sender_host_address, revadd,