#define CUTTHROUGH_CMD_TIMEOUT 30 /* timeout for cutthrough-routing calls */
#define CUTTHROUGH_DATA_TIMEOUT 60 /* timeout for cutthrough-routing calls */
-static smtp_outblock ctblock;
+static smtp_context ctctx;
uschar ctbuffer[8192];
#define MT_NOT 1
#define MT_ALL 2
-static uschar cutthrough_response(int, char, uschar **, int);
+static uschar cutthrough_response(client_conn_ctx *, char, uschar **, int);
if ( cache_record->result == ccache_reject
|| *from_address == 0 && cache_record->result == ccache_reject_mfnull)
{
- setflag(addr, af_verify_nsfail);
HDEBUG(D_verify)
debug_printf("callout cache: domain gave initial rejection, or "
"does not accept HELO or MAIL FROM:<>\n");
case ccache_accept:
HDEBUG(D_verify)
debug_printf("callout cache: domain accepts random addresses\n");
+ *failure_ptr = US"random";
dbfn_close(dbm_file);
return TRUE; /* Default yield is OK */
transport_feedback * tf, int * yield)
{
BOOL done = FALSE;
-host_item * host;
if (addr->transport == cutthrough.addr.transport)
- for (host = host_list; host; host = host->next)
+ for (host_item * host = host_list; host; host = host->next)
if (Ustrcmp(host->address, cutthrough.host.address) == 0)
{
int host_af;
/* Match! Send the RCPT TO, set done from the response */
done =
- smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
- transport_rcpt_address(addr,
- addr->transport->rcpt_include_affixes)) >= 0 &&
- cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
+ smtp_write_command(&ctctx, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
+ transport_rcpt_address(addr,
+ addr->transport->rcpt_include_affixes)) >= 0
+ && cutthrough_response(&cutthrough.cctx, '2', &resp,
+ CUTTHROUGH_DATA_TIMEOUT) == '2';
/* This would go horribly wrong if a callout fail was ignored by ACL.
We punt by abandoning cutthrough on a reject, like the
{
smtp_transport_options_block *ob =
(smtp_transport_options_block *)addr->transport->options_block;
- host_item * host;
/* The information wasn't available in the cache, so we have to do a real
callout and save the result in the cache for next time, unless no_cache is set,
and cause the client to time out. So in this case we forgo the PIPELINING
optimization. */
- if (smtp_out && !disable_callout_flush) mac_smtp_fflush();
+ if (smtp_out && !f.disable_callout_flush) mac_smtp_fflush();
clearflag(addr, af_verify_pmfail); /* postmaster callout flag */
clearflag(addr, af_verify_nsfail); /* null sender callout flag */
coding means skipping this whole loop and doing the append separately. */
/* Can we re-use an open cutthrough connection? */
- if ( cutthrough.fd >= 0
+ if ( cutthrough.cctx.sock >= 0
&& (options & (vopt_callout_recipsender | vopt_callout_recippmaster))
== vopt_callout_recipsender
&& !random_local_part
/* If we did not use a cached connection, make connections to the hosts
and do real callouts. The list of hosts is passed in as an argument. */
- for (host = host_list; host && !done; host = host->next)
+ for (host_item * host = host_list; host && !done; host = host->next)
{
int host_af;
int port = 25;
addr->message);
sx.addrlist = addr;
- sx.host = host;
- sx.host_af = host_af,
+ sx.conn_args.host = host;
+ sx.conn_args.host_af = host_af,
sx.port = port;
- sx.interface = interface;
+ sx.conn_args.interface = interface;
sx.helo_data = tf->helo_data;
- sx.tblock = addr->transport;
+ sx.conn_args.tblock = addr->transport;
sx.verify = TRUE;
tls_retry_connection:
if ( yield == DEFER
&& addr->basic_errno == ERRNO_TLSFAILURE
&& ob->tls_tempfail_tryclear
- && verify_check_given_host(&ob->hosts_require_tls, host) != OK
+ && verify_check_given_host(CUSS &ob->hosts_require_tls, host) != OK
)
{
log_write(0, LOG_MAIN,
The sync_responses() would need to be taught about it and we'd
need another return code filtering out to here.
- Avoid using a SIZE option on the MAIL for all randon-rcpt checks.
+ Avoid using a SIZE option on the MAIL for all random-rcpt checks.
*/
sx.avoid_option = OPTION_SIZE;
new_domain_record.random_result = ccache_accept;
yield = OK; /* Only usable verify result we can return */
done = TRUE;
+ *failure_ptr = US"random";
goto no_conn;
case FAIL: /* rejected: the preferred result */
new_domain_record.random_result = ccache_reject;
XXX We don't care about that for postmaster_full. Should we? */
if ((done =
- smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 &&
- smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
- '2', callout)))
+ smtp_write_command(&sx, SCMD_FLUSH, "RSET\r\n") >= 0 &&
+ smtp_read_response(&sx, sx.buffer, sizeof(sx.buffer), '2', callout)))
break;
HDEBUG(D_acl|D_v)
debug_printf_indent("problem after random/rset/mfrom; reopen conn\n");
random_local_part = NULL;
#ifdef SUPPORT_TLS
- tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
+ tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
- (void)close(sx.inblock.sock);
- sx.inblock.sock = sx.outblock.sock = -1;
+ (void)close(sx.cctx.sock);
+ sx.cctx.sock = -1;
#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
cancel_cutthrough_connection(TRUE, US"postmaster verify");
HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n");
- done = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0
- && smtp_read_response(&sx.inblock, sx.buffer,
- sizeof(sx.buffer), '2', callout);
+ done = smtp_write_command(&sx, SCMD_FLUSH, "RSET\r\n") >= 0
+ && smtp_read_response(&sx, sx.buffer, sizeof(sx.buffer), '2', callout);
if (done)
{
done = TRUE;
else
done = (options & vopt_callout_fullpm) != 0
- && smtp_write_command(&sx.outblock, SCMD_FLUSH,
+ && smtp_write_command(&sx, SCMD_FLUSH,
"RCPT TO:<postmaster>\r\n") >= 0
- && smtp_read_response(&sx.inblock, sx.buffer,
+ && smtp_read_response(&sx, sx.buffer,
sizeof(sx.buffer), '2', callout);
/* Sort out the cache record */
done = TRUE;
}
break;
+#endif
+#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
+ case ERRNO_REQUIRETLS:
+ addr->user_message = US"530 5.7.4 REQUIRETLS support required";
+ yield = FAIL;
+ done = TRUE;
+ break;
#endif
case ECONNREFUSED:
sx.send_quit = FALSE;
cutthrough.delivery= FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
}
+#ifndef DISABLE_DKIM
if (ob->dkim.dkim_domain)
{
cutthrough.delivery= FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
}
+#endif
+#ifdef EXPERIMENTAL_ARC
+ if (ob->arc_sign)
+ {
+ cutthrough.delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of ARC signing\n");
+ }
+#endif
}
if ( (cutthrough.delivery || options & vopt_callout_hold)
== vopt_callout_recipsender
&& !random_local_part
&& !pm_mailfrom
- && cutthrough.fd < 0
+ && cutthrough.cctx.sock < 0
&& !sx.lmtp
)
{
? "cutthrough delivery" : "potential further verifies and delivery");
cutthrough.callout_hold_only = !cutthrough.delivery;
- cutthrough.is_tls = tls_out.active >= 0;
- cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */
+ cutthrough.is_tls = tls_out.active.sock >= 0;
+ /* We assume no buffer in use in the outblock */
+ cutthrough.cctx = sx.cctx;
cutthrough.nrcpt = 1;
cutthrough.transport = addr->transport->name;
cutthrough.interface = interface;
cutthrough.host.address = string_copy(host->address);
store_pool = oldpool;
}
- cutthrough.addr = *addr; /* Save the address_item for later logging */
+
+ /* Save the address_item and parent chain for later logging */
+ cutthrough.addr = *addr;
cutthrough.addr.next = NULL;
cutthrough.addr.host_used = &cutthrough.host;
- if (addr->parent)
- *(cutthrough.addr.parent = store_get(sizeof(address_item))) =
- *addr->parent;
- ctblock.buffer = ctbuffer;
- ctblock.buffersize = sizeof(ctbuffer);
- ctblock.ptr = ctbuffer;
- /* ctblock.cmd_count = 0; ctblock.authenticating = FALSE; */
- ctblock.sock = cutthrough.fd;
+ for (address_item * caddr = &cutthrough.addr, * parent = addr->parent;
+ parent;
+ caddr = caddr->parent, parent = parent->parent)
+ *(caddr->parent = store_get(sizeof(address_item))) = *parent;
+
+ ctctx.outblock.buffer = ctbuffer;
+ ctctx.outblock.buffersize = sizeof(ctbuffer);
+ ctctx.outblock.ptr = ctbuffer;
+ /* ctctx.outblock.cmd_count = 0; ctctx.outblock.authenticating = FALSE; */
+ ctctx.outblock.cctx = &cutthrough.cctx;
}
else
{
cancel_cutthrough_connection(TRUE, US"not usable for cutthrough");
if (sx.send_quit)
{
- (void) smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n");
+ (void) smtp_write_command(&sx, SCMD_FLUSH, "QUIT\r\n");
/* Wait a short time for response, and discard it */
- smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
- '2', 1);
+ smtp_read_response(&sx, sx.buffer, sizeof(sx.buffer), '2', 1);
}
- if (sx.inblock.sock >= 0)
+ if (sx.cctx.sock >= 0)
{
#ifdef SUPPORT_TLS
- tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
+ if (sx.cctx.tls_ctx)
+ {
+ tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
+ sx.cctx.tls_ctx = NULL;
+ }
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
- (void)close(sx.inblock.sock);
- sx.inblock.sock = sx.outblock.sock = -1;
+ (void)close(sx.cctx.sock);
+ sx.cctx.sock = -1;
#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
#endif
one was requested and a recipient-verify wasn't subsequently done.
*/
int
-open_cutthrough_connection( address_item * addr )
+open_cutthrough_connection(address_item * addr)
{
address_item addr2;
int rc;
static BOOL
cutthrough_send(int n)
{
-if(cutthrough.fd < 0)
+if(cutthrough.cctx.sock < 0)
return TRUE;
if(
#ifdef SUPPORT_TLS
- tls_out.active == cutthrough.fd ? tls_write(FALSE, ctblock.buffer, n, FALSE) :
+ cutthrough.is_tls
+ ? tls_write(cutthrough.cctx.tls_ctx, ctctx.outblock.buffer, n, FALSE)
+ :
#endif
- send(cutthrough.fd, ctblock.buffer, n, 0) > 0
+ send(cutthrough.cctx.sock, ctctx.outblock.buffer, n, 0) > 0
)
{
transport_count += n;
- ctblock.ptr= ctblock.buffer;
+ ctctx.outblock.ptr= ctctx.outblock.buffer;
return TRUE;
}
{
while(n--)
{
- if(ctblock.ptr >= ctblock.buffer+ctblock.buffersize)
- if(!cutthrough_send(ctblock.buffersize))
+ if(ctctx.outblock.ptr >= ctctx.outblock.buffer+ctctx.outblock.buffersize)
+ if(!cutthrough_send(ctctx.outblock.buffersize))
return FALSE;
- *ctblock.ptr++ = *cp++;
+ *ctctx.outblock.ptr++ = *cp++;
}
return TRUE;
}
static BOOL
cutthrough_puts(uschar * cp, int n)
{
-if (cutthrough.fd < 0) return TRUE;
-if (_cutthrough_puts(cp, n)) return TRUE;
+if (cutthrough.cctx.sock < 0) return TRUE;
+if (_cutthrough_puts(cp, n)) return TRUE;
cancel_cutthrough_connection(TRUE, US"transmit failed");
return FALSE;
}
static BOOL
_cutthrough_flush_send(void)
{
-int n = ctblock.ptr - ctblock.buffer;
+int n = ctctx.outblock.ptr - ctctx.outblock.buffer;
if(n>0)
if(!cutthrough_send(n))
/* Get and check response from cutthrough target */
static uschar
-cutthrough_response(int fd, char expect, uschar ** copy, int timeout)
+cutthrough_response(client_conn_ctx * cctx, char expect, uschar ** copy, int timeout)
{
-smtp_inblock inblock;
+smtp_context sx = {0};
uschar inbuffer[4096];
uschar responsebuffer[4096];
-inblock.buffer = inbuffer;
-inblock.buffersize = sizeof(inbuffer);
-inblock.ptr = inbuffer;
-inblock.ptrend = inbuffer;
-inblock.sock = fd;
-/* this relies on (inblock.sock == tls_out.active) */
-if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, timeout))
+sx.inblock.buffer = inbuffer;
+sx.inblock.buffersize = sizeof(inbuffer);
+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");
if(copy)
BOOL
cutthrough_predata(void)
{
-if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
+if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
return FALSE;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> DATA\n");
cutthrough_flush_send();
/* Assume nothing buffered. If it was it gets ignored. */
-return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
+return cutthrough_response(&cutthrough.cctx, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
}
{
transport_ctx tctx;
-if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
+if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
return FALSE;
/* We share a routine with the mainline transport to handle header add/remove/rewrites,
*/
HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n");
-tctx.u.fd = cutthrough.fd;
+tctx.u.fd = cutthrough.cctx.sock;
tctx.tblock = cutthrough.addr.transport;
tctx.addr = &cutthrough.addr;
tctx.check_string = US".";
static void
close_cutthrough_connection(const uschar * why)
{
-int fd = cutthrough.fd;
+int fd = cutthrough.cctx.sock;
if(fd >= 0)
{
/* We could be sending this after a bunch of data, but that is ok as
the only way to cancel the transfer in dataphase is to drop the tcp
conn before the final dot.
*/
- ctblock.ptr = ctbuffer;
+ client_conn_ctx tmp_ctx = cutthrough.cctx;
+ ctctx.outblock.ptr = ctbuffer;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n");
_cutthrough_puts(US"QUIT\r\n", 6); /* avoid recursion */
_cutthrough_flush_send();
- cutthrough.fd = -1; /* avoid recursion via read timeout */
+ cutthrough.cctx.sock = -1; /* avoid recursion via read timeout */
cutthrough.nrcpt = 0; /* permit re-cutthrough on subsequent message */
/* Wait a short time for response, and discard it */
- cutthrough_response(fd, '2', NULL, 1);
+ cutthrough_response(&tmp_ctx, '2', NULL, 1);
#ifdef SUPPORT_TLS
- tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
+ if (cutthrough.is_tls)
+ {
+ tls_close(cutthrough.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
+ cutthrough.cctx.tls_ctx = NULL;
+ cutthrough.is_tls = FALSE;
+ }
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
(void)close(fd);
HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why);
}
-ctblock.ptr = ctbuffer;
+ctctx.outblock.ptr = ctbuffer;
}
void
void
release_cutthrough_connection(const uschar * why)
{
-if (cutthrough.fd < 0) return;
+if (cutthrough.cctx.sock < 0) return;
HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why);
-cutthrough.fd = -1;
+cutthrough.cctx.sock = -1;
+cutthrough.cctx.tls_ctx = NULL;
cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
}
cutthrough_finaldot(void)
{
uschar res;
-address_item * addr;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> .\n");
/* Assume data finshed with new-line */
)
return cutthrough.addr.message;
-res = cutthrough_response(cutthrough.fd, '2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
-for (addr = &cutthrough.addr; addr; addr = addr->next)
+res = cutthrough_response(&cutthrough.cctx, '2', &cutthrough.addr.message,
+ CUTTHROUGH_DATA_TIMEOUT);
+for (address_item * addr = &cutthrough.addr; addr; addr = addr->next)
{
addr->message = cutthrough.addr.message;
switch(res)
*/
int
-verify_address(address_item *vaddr, FILE *f, int options, int callout,
- int callout_overall, int callout_connect, uschar *se_mailfrom,
+verify_address(address_item * vaddr, FILE * fp, int options, int callout,
+ int callout_overall, int callout_connect, uschar * se_mailfrom,
uschar *pm_mailfrom, BOOL *routed)
{
BOOL allok = TRUE;
-BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0);
+BOOL full_info = fp ? debug_selector != 0 : FALSE;
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 :
+ f.address_test_mode? v_none :
options & vopt_is_recipient? v_recipient : v_sender;
address_item *addr_list;
address_item *addr_new = NULL;
if (parse_find_at(address) == NULL)
{
- if ((options & vopt_qualify) == 0)
+ if (!(options & vopt_qualify))
{
- if (f != NULL)
- respond_printf(f, "%sA domain is required for \"%s\"%s\n",
+ if (fp)
+ respond_printf(fp, "%sA domain is required for \"%s\"%s\n",
ko_prefix, address, cr);
*failure_ptr = US"qualify";
return FAIL;
DEBUG(D_verify)
{
debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- debug_printf("%s %s\n", address_test_mode? "Testing" : "Verifying", address);
+ debug_printf("%s %s\n", f.address_test_mode? "Testing" : "Verifying", address);
}
/* Rewrite and report on it. Clear the domain and local part caches - these
may have been set by domains and local part tests during an ACL. */
-if (global_rewrite_rules != NULL)
+if (global_rewrite_rules)
{
uschar *old = address;
address = rewrite_address(address, options & vopt_is_recipient, FALSE,
global_rewrite_rules, rewrite_existflags);
if (address != old)
{
- for (i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->localpart_cache[i] = 0;
- for (i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->domain_cache[i] = 0;
- if (f != NULL && !expn) fprintf(f, "Address rewritten as: %s\n", address);
+ for (int i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->localpart_cache[i] = 0;
+ for (int i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->domain_cache[i] = 0;
+ if (fp && !expn) fprintf(fp, "Address rewritten as: %s\n", address);
}
}
/* If this is the real sender address, we must update sender_address at
this point, because it may be referred to in the routers. */
-if ((options & (vopt_fake_sender|vopt_is_recipient)) == 0)
+if (!(options & (vopt_fake_sender|vopt_is_recipient)))
sender_address = address;
/* If the address was rewritten to <> no verification can be done, and we have
to return OK. This rewriting is permitted only for sender addresses; for other
addresses, such rewriting fails. */
-if (address[0] == 0) return OK;
+if (!address[0]) return OK;
/* 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
if (testflag(addr, af_pfr))
{
allok = FALSE;
- if (f != NULL)
+ if (fp)
{
BOOL allow;
if (addr->address[0] == '>')
{
allow = testflag(addr, af_allow_reply);
- fprintf(f, "%s -> mail %s", addr->parent->address, addr->address + 1);
+ fprintf(fp, "%s -> mail %s", addr->parent->address, addr->address + 1);
}
else
{
- allow = (addr->address[0] == '|')?
- testflag(addr, af_allow_pipe) : testflag(addr, af_allow_file);
- fprintf(f, "%s -> %s", addr->parent->address, addr->address);
+ allow = addr->address[0] == '|'
+ ? testflag(addr, af_allow_pipe) : testflag(addr, af_allow_file);
+ fprintf(fp, "%s -> %s", addr->parent->address, addr->address);
}
if (addr->basic_errno == ERRNO_BADTRANSPORT)
- fprintf(f, "\n*** Error in setting up pipe, file, or autoreply:\n"
+ fprintf(fp, "\n*** Error in setting up pipe, file, or autoreply:\n"
"%s\n", addr->message);
else if (allow)
- fprintf(f, "\n transport = %s\n", addr->transport->name);
+ fprintf(fp, "\n transport = %s\n", addr->transport->name);
else
- fprintf(f, " *** forbidden ***\n");
+ fprintf(fp, " *** forbidden ***\n");
}
continue;
}
else
{
int flags;
- host_item *host, *nexthost;
host_build_hostlist(&host_list, s, tf.hosts_randomize);
/* Just ignore failures to find a host address. If we don't manage
if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
- for (host = host_list; host; host = nexthost)
+ for (host_item * host = host_list, * nexthost; host; host = nexthost)
{
nexthost = host->next;
if (tf.gethostbyname ||
(void)host_find_byname(host, NULL, flags, NULL, TRUE);
else
{
- dnssec_domains * dnssec_domains = NULL;
+ const dnssec_domains * dsp = NULL;
if (Ustrcmp(tp->driver_name, "smtp") == 0)
{
smtp_transport_options_block * ob =
(smtp_transport_options_block *) tp->options_block;
- dnssec_domains = &ob->dnssec;
+ dsp = &ob->dnssec;
}
(void) host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
- dnssec_domains, NULL, NULL);
+ dsp, NULL, NULL);
}
}
}
if (host_list)
{
HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
- if (host_checking && !host_checking_callout)
+ if (host_checking && !f.host_checking_callout)
{
HDEBUG(D_verify)
debug_printf("... callout omitted by default when host testing\n"
#endif
rc = do_callout(addr, host_list, &tf, callout, callout_overall,
callout_connect, options, se_mailfrom, pm_mailfrom);
+#ifdef SUPPORT_TLS
+ deliver_set_expansions(NULL);
+#endif
}
}
else
{
HDEBUG(D_verify) debug_printf("Cannot do callout: neither router nor "
- "transport provided a host list\n");
+ "transport provided a host list, or transport is not smtp\n");
}
}
}
if (rc == FAIL)
{
allok = FALSE;
- if (f)
+ if (fp)
{
address_item *p = addr->parent;
- respond_printf(f, "%s%s %s", ko_prefix,
+ respond_printf(fp, "%s%s %s", ko_prefix,
full_info ? addr->address : address,
- address_test_mode ? "is undeliverable" : "failed to verify");
- if (!expn && admin_user)
+ f.address_test_mode ? "is undeliverable" : "failed to verify");
+ if (!expn && f.admin_user)
{
if (addr->basic_errno > 0)
- respond_printf(f, ": %s", strerror(addr->basic_errno));
+ respond_printf(fp, ": %s", strerror(addr->basic_errno));
if (addr->message)
- respond_printf(f, ": %s", addr->message);
+ respond_printf(fp, ": %s", addr->message);
}
/* Show parents iff doing full info */
if (full_info) while (p)
{
- respond_printf(f, "%s\n <-- %s", cr, p->address);
+ respond_printf(fp, "%s\n <-- %s", cr, p->address);
p = p->parent;
}
- respond_printf(f, "%s\n", cr);
+ respond_printf(fp, "%s\n", cr);
}
cancel_cutthrough_connection(TRUE, US"routing hard fail");
else if (rc == DEFER)
{
allok = FALSE;
- if (f)
+ if (fp)
{
address_item *p = addr->parent;
- respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
+ respond_printf(fp, "%s%s cannot be resolved at this time", ko_prefix,
full_info? addr->address : address);
- if (!expn && admin_user)
+ if (!expn && f.admin_user)
{
if (addr->basic_errno > 0)
- respond_printf(f, ": %s", strerror(addr->basic_errno));
+ respond_printf(fp, ": %s", strerror(addr->basic_errno));
if (addr->message)
- respond_printf(f, ": %s", addr->message);
+ respond_printf(fp, ": %s", addr->message);
else if (addr->basic_errno <= 0)
- respond_printf(f, ": unknown error");
+ respond_printf(fp, ": unknown error");
}
/* Show parents iff doing full info */
if (full_info) while (p)
{
- respond_printf(f, "%s\n <-- %s", cr, p->address);
+ respond_printf(fp, "%s\n <-- %s", cr, p->address);
p = p->parent;
}
- respond_printf(f, "%s\n", cr);
+ respond_printf(fp, "%s\n", cr);
}
cancel_cutthrough_connection(TRUE, US"routing soft fail");
if (!addr_new)
if (!addr_local && !addr_remote)
- respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
+ respond_printf(fp, "250 mail to <%s> is discarded\r\n", address);
else
- respond_printf(f, "250 <%s>\r\n", address);
+ respond_printf(fp, "250 <%s>\r\n", address);
else do
{
address_item *addr2 = addr_new;
addr_new = addr2->next;
if (!addr_new) ok_prefix = US"250 ";
- respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
+ respond_printf(fp, "%s<%s>\r\n", ok_prefix, addr2->address);
} while (addr_new);
yield = OK;
goto out;
) )
)
{
- if (f) fprintf(f, "%s %s\n",
- address, address_test_mode ? "is deliverable" : "verified");
+ if (fp) fprintf(fp, "%s %s\n",
+ address, f.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 */
} /* Loop for generated addresses */
/* Display the full results of the successful routing, including any generated
-addresses. Control gets here only when full_info is set, which requires f not
+addresses. Control gets here only when full_info is set, which requires fp not
to be NULL, and this occurs only when a top-level verify is called with the
debugging switch on.
if (allok && !addr_local && !addr_remote)
{
- fprintf(f, "mail to %s is discarded\n", address);
+ fprintf(fp, "mail to %s is discarded\n", address);
goto out;
}
while (addr_list)
{
address_item *addr = addr_list;
- address_item *p = addr->parent;
transport_instance * tp = addr->transport;
addr_list = addr->next;
- fprintf(f, "%s", CS addr->address);
+ fprintf(fp, "%s", CS addr->address);
#ifdef EXPERIMENTAL_SRS
if(addr->prop.srs_sender)
- fprintf(f, " [srs = %s]", addr->prop.srs_sender);
+ fprintf(fp, " [srs = %s]", addr->prop.srs_sender);
#endif
/* If the address is a duplicate, show something about it. */
{
tree_node *tnode;
if ((tnode = tree_search(tree_duplicates, addr->unique)))
- fprintf(f, " [duplicate, would not be delivered]");
+ fprintf(fp, " [duplicate, would not be delivered]");
else tree_add_duplicate(addr->unique, addr);
}
/* Now show its parents */
- for (p = addr->parent; p; p = p->parent)
- fprintf(f, "\n <-- %s", p->address);
- fprintf(f, "\n ");
+ for (address_item * p = addr->parent; p; p = p->parent)
+ fprintf(fp, "\n <-- %s", p->address);
+ fprintf(fp, "\n ");
/* Show router, and transport */
- fprintf(f, "router = %s, transport = %s\n",
+ fprintf(fp, "router = %s, transport = %s\n",
addr->router->name, tp ? tp->name : US"unset");
/* Show any hosts that are set up by a router unless the transport
if (addr->host_list && tp && !tp->overrides_hosts)
{
- host_item *h;
int maxlen = 0;
int maxaddlen = 0;
- for (h = addr->host_list; h; h = h->next)
+ for (host_item * h = addr->host_list; h; h = h->next)
{ /* get max lengths of host names, addrs */
int len = Ustrlen(h->name);
if (len > maxlen) maxlen = len;
len = h->address ? Ustrlen(h->address) : 7;
if (len > maxaddlen) maxaddlen = len;
}
- for (h = addr->host_list; h; h = h->next)
+ for (host_item * h = addr->host_list; h; h = h->next)
{
- fprintf(f, " host %-*s ", maxlen, h->name);
+ fprintf(fp, " host %-*s ", maxlen, h->name);
if (h->address)
- fprintf(f, "[%s%-*c", h->address, maxaddlen+1 - Ustrlen(h->address), ']');
+ fprintf(fp, "[%s%-*c", h->address, maxaddlen+1 - Ustrlen(h->address), ']');
else if (tp->info->local)
- fprintf(f, " %-*s ", maxaddlen, ""); /* Omit [unknown] for local */
+ fprintf(fp, " %-*s ", maxaddlen, ""); /* Omit [unknown] for local */
else
- fprintf(f, "[%s%-*c", "unknown", maxaddlen+1 - 7, ']');
+ fprintf(fp, "[%s%-*c", "unknown", maxaddlen+1 - 7, ']');
- if (h->mx >= 0) fprintf(f, " MX=%d", h->mx);
- if (h->port != PORT_NONE) fprintf(f, " port=%d", h->port);
- if (running_in_test_harness && h->dnssec == DS_YES) fputs(" AD", f);
- if (h->status == hstatus_unusable) fputs(" ** unusable **", f);
- fputc('\n', f);
+ if (h->mx >= 0) fprintf(fp, " MX=%d", h->mx);
+ if (h->port != PORT_NONE) fprintf(fp, " port=%d", h->port);
+ if (f.running_in_test_harness && h->dnssec == DS_YES) fputs(" AD", fp);
+ if (h->status == hstatus_unusable) fputs(" ** unusable **", fp);
+ fputc('\n', fp);
}
}
}
int
verify_check_headers(uschar **msgptr)
{
-header_line *h;
uschar *colon, *s;
int yield = OK;
-for (h = header_list; h && yield == OK; h = h->next)
+for (header_line * h = header_list; h && yield == OK; h = h->next)
{
if (h->type != htype_from &&
h->type != htype_reply_to &&
/* Loop for multiple addresses in the header, enabling group syntax. Note
that we have to reset this after the header has been scanned. */
- parse_allow_group = TRUE;
+ f.parse_allow_group = TRUE;
while (*s)
{
{
if (h->type == htype_from || h->type == htype_sender)
{
- if (!allow_unqualified_sender) recipient = NULL;
+ if (!f.allow_unqualified_sender) recipient = NULL;
}
else
{
- if (!allow_unqualified_recipient) recipient = NULL;
+ if (!f.allow_unqualified_recipient) recipient = NULL;
}
if (recipient == NULL) errmess = US"unqualified address not permitted";
}
while (isspace(*s)) s++;
} /* Next address */
- parse_allow_group = FALSE;
- parse_found_group = FALSE;
+ f.parse_allow_group = FALSE;
+ f.parse_found_group = FALSE;
} /* Next header unless yield has been set FALSE */
return yield;
int
verify_check_header_names_ascii(uschar **msgptr)
{
-header_line *h;
-uschar *colon, *s;
+uschar *colon;
-for (h = header_list; h; h = h->next)
+for (header_line * h = header_list; h; h = h->next)
{
colon = Ustrchr(h->text, ':');
- for(s = h->text; s < colon; s++)
+ for(uschar * s = h->text; s < colon; s++)
if ((*s < 33) || (*s > 126))
{
*msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
int
verify_check_notblind(void)
{
-int i;
-for (i = 0; i < recipients_count; i++)
+for (int i = 0; i < recipients_count; i++)
{
- header_line *h;
BOOL found = FALSE;
uschar *address = recipients_list[i].address;
- for (h = header_list; !found && h != NULL; h = h->next)
+ for (header_line * h = header_list; !found && h; h = h->next)
{
uschar *colon, *s;
/* Loop for multiple addresses in the header, enabling group syntax. Note
that we have to reset this after the header has been scanned. */
- parse_allow_group = TRUE;
+ f.parse_allow_group = TRUE;
- while (*s != 0)
+ while (*s)
{
uschar *ss = parse_find_address_end(s, FALSE);
uschar *recipient,*errmess;
while (isspace(*s)) s++;
} /* Next address */
- parse_allow_group = FALSE;
- parse_found_group = FALSE;
+ f.parse_allow_group = FALSE;
+ f.parse_found_group = FALSE;
} /* Next header (if found is false) */
if (!found) return FAIL;
address_item *
verify_checked_sender(uschar *sender)
{
-address_item *addr;
-for (addr = sender_verified_list; addr != NULL; addr = addr->next)
- if (Ustrcmp(sender, addr->address) == 0) break;
-return addr;
+for (address_item * addr = sender_verified_list; addr; addr = addr->next)
+ if (Ustrcmp(sender, addr->address) == 0) return addr;
+return NULL;
}
static int header_types[] = { htype_sender, htype_reply_to, htype_from };
BOOL done = FALSE;
int yield = FAIL;
-int i;
-for (i = 0; i < 3 && !done; i++)
- {
- header_line *h;
- for (h = header_list; h != NULL && !done; h = h->next)
+for (int i = 0; i < 3 && !done; i++)
+ for (header_line * h = header_list; h != NULL && !done; h = h->next)
{
int terminator, new_ok;
uschar *s, *ss, *endname;
/* Scan the addresses in the header, enabling group syntax. Note that we
have to reset this after the header has been scanned. */
- parse_allow_group = TRUE;
+ f.parse_allow_group = TRUE;
while (*s != 0)
{
s = ss;
} /* Next address */
- parse_allow_group = FALSE;
- parse_found_group = FALSE;
+ f.parse_allow_group = FALSE;
+ f.parse_found_group = FALSE;
} /* Next header, unless done */
- } /* Next header type unless done */
+ /* Next header type unless done */
if (yield == FAIL && *log_msgptr == NULL)
*log_msgptr = US"there is no valid sender in any header line";
void
verify_get_ident(int port)
{
-int sock, host_af, qlen;
+client_conn_ctx ident_conn_ctx = {0};
+int host_af, qlen;
int received_sender_port, received_interface_port, n;
uschar *p;
blob early_data;
address, the incoming interface address will also be IPv6. */
host_af = Ustrchr(sender_host_address, ':') == NULL ? AF_INET : AF_INET6;
-if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return;
+if ((ident_conn_ctx.sock = ip_socket(SOCK_STREAM, host_af)) < 0) return;
-if (ip_bind(sock, host_af, interface_address, 0) < 0)
+if (ip_bind(ident_conn_ctx.sock, host_af, interface_address, 0) < 0)
{
DEBUG(D_ident) debug_printf("bind socket for ident failed: %s\n",
strerror(errno));
early_data.data = buffer;
early_data.len = qlen;
-if (ip_connect(sock, host_af, sender_host_address, port,
+/*XXX we trust that the query is idempotent */
+if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port,
rfc1413_query_timeout, &early_data) < 0)
{
if (errno == ETIMEDOUT && LOGGING(ident_timeout))
int size = sizeof(buffer) - (p - buffer);
if (size <= 0) goto END_OFF; /* Buffer filled without seeing \n. */
- count = ip_recv(sock, p, size, rfc1413_query_timeout);
+ count = ip_recv(&ident_conn_ctx, p, size, rfc1413_query_timeout);
if (count <= 0) goto END_OFF; /* Read error or EOF */
/* Scan what we just read, to see if we have reached the terminating \r\n. Be
DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident);
END_OFF:
-(void)close(sock);
+(void)close(ident_conn_ctx.sock);
return;
}
}
else if (Ustrcmp(ss, "@[]") == 0)
{
- ip_address_item *ip;
- for (ip = host_find_interfaces(); ip != NULL; ip = ip->next)
+ for (ip_address_item * ip = host_find_interfaces(); ip; ip = ip->next)
if (Ustrcmp(ip->address, cb->host_address) == 0) return OK;
return FAIL;
}
course slashes may be present in lookups, but not preceded only by digits and
dots). */
-for (t = ss; isdigit(*t) || *t == '.'; t++);
+for (t = ss; isdigit(*t) || *t == '.'; ) t++;
if (*t == 0 || (*t == '/' && t != ss))
{
*error = US"malformed IPv4 address or address mask";
if (mlen == 0 && t == ss+3) mlen = -1; /* No mask supplied */
iplookup = (*t++ == '-');
}
-else t = ss;
+else
+ t = ss;
/* Do the IP address lookup if that is indeed what we have */
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;
+ if (valueptr) *valueptr = result;
+ return result ? OK : f.search_find_defer ? DEFER: FAIL;
}
/* The pattern is not an IP address or network reference of any kind. That is,
rc = host_find_byname(&h, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, FALSE);
if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL)
{
- host_item *hh;
- for (hh = &h; hh != NULL; hh = hh->next)
- {
+ for (host_item * hh = &h; hh; hh = hh->next)
if (host_is_in_net(hh->address, cb->host_address, 0)) return OK;
- }
return FAIL;
}
if (rc == HOST_FIND_AGAIN) return DEFER;
* Check the given host item matches a list *
*************************************************/
int
-verify_check_given_host(uschar **listptr, host_item *host)
+verify_check_given_host(const uschar **listptr, const host_item *host)
{
-return verify_check_this_host(CUSS listptr, NULL, host->name, host->address, NULL);
+return verify_check_this_host(listptr, NULL, host->name, host->address, NULL);
}
/*************************************************
if (host_aton(address, bin) == 1)
{
- int i;
int x = bin[0];
- for (i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++)
{
sprintf(CS bptr, "%d.", x & 255);
while (*bptr) bptr++;
#if HAVE_IPV6
else
- {
- int i, j;
- for (j = 3; j >= 0; j--)
+ for (int j = 3; j >= 0; j--)
{
int x = bin[j];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
sprintf(CS bptr, "%x.", x & 15);
while (*bptr) bptr++;
x >>= 4;
}
}
- }
#endif
/* Remove trailing period -- this is needed so that both arbitrary
/* If the lookup succeeded, cache the RHS address. The code allows for
more than one address - this was for complete generality and the possible
- use of A6 records. However, A6 records have been reduced to experimental
- status (August 2001) and may die out. So they may never get used at all,
- let alone in dnsbl records. However, leave the code here, just in case.
+ use of A6 records. However, A6 records are no longer supported. Leave the code
+ here, just in case.
Quite apart from one A6 RR generating multiple addresses, there are DNS
lists that return more than one A record, so we must handle multiple
if (cb->rc == DNS_SUCCEED)
{
- dns_record *rr;
- dns_address **addrp = &(cb->rhs);
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr;
+ dns_address ** addrp = &(cb->rhs);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
if (rr->type == T_A)
{
{
cb->text_set = TRUE;
if (dns_basic_lookup(&dnsa, query, T_TXT) == DNS_SUCCEED)
- {
- dns_record *rr;
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr;
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- if (rr->type == T_TXT) break;
- if (rr)
- {
- int len = (rr->data)[0];
- if (len > 511) len = 127;
- store_pool = POOL_PERM;
- cb->text = string_sprintf("%.*s", len, CUS (rr->data+1));
- store_pool = old_pool;
- }
- }
+ if (rr->type == T_TXT)
+ {
+ int len = (rr->data)[0];
+ if (len > 511) len = 127;
+ store_pool = POOL_PERM;
+ cb->text = string_sprintf("%.*s", len, CUS (rr->data+1));
+ store_pool = old_pool;
+ break;
+ }
}
dnslist_value = addlist;
int defer_return = FAIL;
const uschar *list = *listptr;
uschar *domain;
-uschar *s;
uschar buffer[1024];
uschar revadd[128]; /* Long enough for IPv6 address */
actually causing an error here, because that would no doubt hold up incoming
mail. Instead, I'll just log it. */
- for (s = domain; *s != 0; s++)
- {
+ for (uschar * s = domain; *s; s++)
if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
{
log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
"strange characters - is this right?", domain);
break;
}
- }
/* Check the alternate domain if present */
- if (domain_txt != domain) for (s = domain_txt; *s != 0; s++)
- {
+ if (domain_txt != domain) for (uschar * s = domain_txt; *s; s++)
if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
{
log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
"strange characters - is this right?", domain_txt);
break;
}
- }
/* If there is no key string, construct the query by adding the domain name
onto the inverted host address, and perform a single DNS lookup. */
- if (key == NULL)
+ if (!key)
{
if (where == ACL_WHERE_NOTSMTP_START || where == ACL_WHERE_NOTSMTP)
{