deliver_host_address = host->address;
deliver_host_port = host->port;
deliver_domain = addr->domain;
- transport_name = addr->transport->name;
+ transport_name = addr->transport->drinst.name;
host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
uschar * resp = NULL;
/* Match! Send the RCPT TO, set done from the response */
+
+ DEBUG(D_verify)
+ debug_printf("already-open verify connection matches recipient\n");
+
done =
smtp_write_command(&ctctx, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
transport_rcpt_address(addr,
}
break; /* host_list */
}
-if (!done)
- cancel_cutthrough_connection(TRUE, US"incompatible connection");
return done;
}
vopt_callout_no_cache => don't use callout cache
vopt_callout_fullpm => if postmaster check, do full one
vopt_callout_random => do the "random" thing
- vopt_callout_recipsender => use real sender for recipient
- vopt_callout_recippmaster => use postmaster for recipient
- vopt_callout_hold => lazy close connection
+ vopt_callout_recipsender => use original sender addres
+ vopt_callout_r_pmaster => use postmaster as sender
+ vopt_callout_r_tptsender => use sender defined by tpt
+ vopt_callout_hold => lazy close connection
se_mailfrom MAIL FROM address for sender verify; NULL => ""
pm_mailfrom if non-NULL, do the postmaster check with this sender
memset(&new_address_record, 0, sizeof(new_address_record));
/* For a recipient callout, the key used for the address cache record must
-include the sender address if we are using the real sender in the callout,
-because that may influence the result of the callout. */
+include the sender address if we are using anything but a blank sender in the
+callout, because that may influence the result of the callout. */
if (options & vopt_is_recipient)
- if (options & vopt_callout_recipsender)
- {
- from_address = sender_address;
- address_key = string_sprintf("%s/<%s>", addr->address, sender_address);
- if (cutthrough.delivery) options |= vopt_callout_no_cache;
- }
- else if (options & vopt_callout_recippmaster)
+ if (options & ( vopt_callout_recipsender
+ | vopt_callout_r_tptsender
+ | vopt_callout_r_pmaster)
+ )
{
- from_address = string_sprintf("postmaster@%s", qualify_domain_sender);
- address_key = string_sprintf("%s/<postmaster@%s>", addr->address,
- qualify_domain_sender);
+ if (options & vopt_callout_recipsender)
+ from_address = sender_address;
+ else if (options & vopt_callout_r_tptsender)
+ {
+ transport_instance * tp = addr->transport;
+ from_address = addr->prop.errors_address
+ ? addr->prop.errors_address : sender_address;
+ DEBUG(D_verify)
+ debug_printf(" return-path from routed addr: %s\n", from_address);
+
+ GET_OPTION("return_path");
+ if (tp->return_path)
+ {
+ uschar * new_return_path = expand_string(tp->return_path);
+ if (new_return_path)
+ from_address = new_return_path;
+ else if (!f.expand_string_forcedfail)
+ return DEFER;
+ DEBUG(D_verify)
+ debug_printf(" return-path from transport: %s\n", from_address);
+ }
+ }
+ else /* if (options & vopt_callout_recippmaster) */
+ from_address = string_sprintf("postmaster@%s", qualify_domain_sender);
+
+ address_key = string_sprintf("%s/<%s>", addr->address, from_address);
+ addr->return_path = from_address; /* for cutthrough logging */
+ if (cutthrough.delivery) /* cutthrough previously req. */
+ options |= vopt_callout_no_cache; /* in case called by verify= */
}
else
{
HDEBUG(D_verify) debug_printf("cannot callout via null transport\n");
}
-else if (Ustrcmp(addr->transport->driver_name, "smtp") != 0)
+else if (Ustrcmp(addr->transport->drinst.driver_name, "smtp") != 0)
log_write(0, LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp",
- addr->transport->name, addr->transport->driver_name);
+ addr->transport->drinst.name, addr->transport->drinst.driver_name);
else
{
- smtp_transport_options_block *ob =
- (smtp_transport_options_block *)addr->transport->options_block;
+ smtp_transport_options_block * ob = addr->transport->drinst.options_block;
smtp_context * sx = NULL;
/* The information wasn't available in the cache, so we have to do a real
coding means skipping this whole loop and doing the append separately. */
/* Can we re-use an open cutthrough connection? */
- if ( cutthrough.cctx.sock >= 0
- && (options & (vopt_callout_recipsender | vopt_callout_recippmaster))
- == vopt_callout_recipsender
- && !random_local_part
- && !pm_mailfrom
- )
- done = cutthrough_multi(addr, host_list, tf, &yield);
+
+ if (cutthrough.cctx.sock >= 0)
+ {
+ if ( !(options & vopt_callout_r_pmaster)
+ && !random_local_part
+ && !pm_mailfrom
+ && Ustrcmp(addr->return_path, cutthrough.addr.return_path) == 0
+ )
+ done = cutthrough_multi(addr, host_list, tf, &yield);
+
+ if (!done)
+ cancel_cutthrough_connection(TRUE, US"incompatible connection");
+ }
/* 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. */
deliver_host_address = host->address;
deliver_host_port = host->port;
deliver_domain = addr->domain;
- transport_name = addr->transport->name;
+ transport_name = addr->transport->drinst.name;
GET_OPTION("interface");
if ( !smtp_get_interface(tf->interface, host_af, addr, &interface,
sx->send_rset = TRUE;
sx->completed_addr = FALSE;
+/*XXX do not want to write a cache record for ATRN */
new_domain_record.result = old_domain_cache_result == ccache_reject_mfnull
? ccache_reject_mfnull : ccache_accept;
/* Main verify. For rcpt-verify use SIZE if we know it and we're not cacheing;
for sndr-verify never use it. */
- if (done)
+ if (done && !(options & vopt_atrn))
{
if (!(options & vopt_is_recipient && options & vopt_callout_no_cache))
sx->avoid_option = OPTION_SIZE;
&& rcpt_count == 1
&& done
&& yield == OK
- && (options & (vopt_callout_recipsender|vopt_callout_recippmaster|vopt_success_on_redirect))
- == vopt_callout_recipsender
+ && !(options & (vopt_callout_r_pmaster| vopt_success_on_redirect))
&& !random_local_part
&& !pm_mailfrom
&& cutthrough.cctx.sock < 0
/* We assume no buffer in use in the outblock */
cutthrough.cctx = sx->cctx;
cutthrough.nrcpt = 1;
- cutthrough.transport = addr->transport->name;
+ cutthrough.transport = addr->transport->drinst.name;
cutthrough.interface = interface;
cutthrough.snd_port = sending_port;
cutthrough.peer_options = smtp_peer_options;
else
{
/* Ensure no cutthrough on multiple verifies that were incompatible */
- if (options & vopt_callout_recipsender)
+ if (options & (vopt_callout_recipsender | vopt_callout_r_tptsender))
cancel_cutthrough_connection(TRUE, US"not usable for cutthrough");
if (sx->send_quit && sx->cctx.sock >= 0)
if (smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n") != -1)
/* Come here from within the cache-reading code on fast-track exit. */
END_CALLOUT:
-tls_modify_variables(&tls_in); /* return variables to inbound values */
+if (!(options & vopt_atrn))
+ tls_modify_variables(&tls_in); /* return variables to inbound values */
return yield;
}
one was requested and a recipient-verify wasn't subsequently done.
*/
int
-open_cutthrough_connection(address_item * addr)
+open_cutthrough_connection(address_item * addr, BOOL transport_sender)
{
address_item addr2;
-int rc;
+int vopt, 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_indent("----------- %s cutthrough setup ------------\n",
rcpt_count > 1 ? "more" : "start");
-rc = verify_address(&addr2, NULL,
- vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache,
- CUTTHROUGH_CMD_TIMEOUT, -1, -1,
+
+vopt = transport_sender
+ ? vopt_is_recipient | vopt_callout_r_tptsender | vopt_callout_no_cache
+ : vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache;
+
+rc = verify_address(&addr2, NULL, vopt, CUTTHROUGH_CMD_TIMEOUT, -1, -1,
NULL, NULL, NULL);
addr->message = addr2.message;
addr->user_message = addr2.user_message;
vopt_callout_fullpm => if postmaster check, do full one
vopt_callout_no_cache => don't use callout cache
- vopt_callout_random => do the "random" thing
- vopt_callout_recipsender => use real sender for recipient
+ vopt_callout_random => do the "random" thing
+ vopt_callout_recipsender => use real sender for recipient
vopt_callout_recippmaster => use postmaster for recipient
+ vopt_callout_r_tptsender => use sender as defined by tpt
callout if > 0, specifies that callout is required, and gives timeout
for individual commands
int verify_type = expn ? v_expn :
f.address_test_mode ? v_none :
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;
+address_item * addr_list, * addr_new = NULL, * addr_remote = NULL;
+address_item * addr_local = NULL, * addr_succeed = NULL;
uschar ** failure_ptr = options & vopt_is_recipient
? &recipient_verify_failure : &sender_verify_failure;
uschar * ko_prefix, * cr;
-const uschar * address = vaddr->address;
-const uschar * save_sender;
+const uschar * address = vaddr->address, * save_sender;
uschar null_sender[] = { 0 }; /* Ensure writeable memory */
/* Clear, just in case */
fprintf(fp, "\n*** Error in setting up pipe, file, or autoreply:\n"
"%s\n", addr->message);
else if (allow)
- fprintf(fp, "\n transport = %s\n", addr->transport->name);
+ fprintf(fp, "\n transport = %s\n", addr->transport->drinst.name);
else
fprintf(fp, " *** forbidden ***\n");
}
sending a message to this address. */
if ((tp = addr->transport))
- if (!tp->info->local)
+ {
+ transport_info * ti = tp->drinst.info;
+ if (!ti->local)
{
(void)(tp->setup)(tp, addr, &tf, 0, 0, NULL);
{
log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
"\"%s\" in %s transport for callout: %s", tf.hosts,
- tp->name, expand_string_message);
+ tp->drinst.name, expand_string_message);
}
else
{
else
{
const dnssec_domains * dsp = NULL;
- if (Ustrcmp(tp->driver_name, "smtp") == 0)
+ if (Ustrcmp(tp->drinst.driver_name, "smtp") == 0)
{
- smtp_transport_options_block * ob =
- (smtp_transport_options_block *) tp->options_block;
+ smtp_transport_options_block * ob = tp->drinst.options_block;
dsp = &ob->dnssec;
}
}
}
else if ( options & vopt_quota
- && Ustrcmp(tp->driver_name, "appendfile") == 0)
+ && Ustrcmp(tp->drinst.driver_name, "appendfile") == 0)
local_verify = TRUE;
+ }
/* 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)
{
- HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
+ HDEBUG(D_verify)
+ debug_printf("Attempting full verification using callout\n");
if (host_checking && !f.host_checking_callout)
{
HDEBUG(D_verify)
}
else
{
-#ifndef DISABLE_TLS
deliver_set_expansions(addr);
-#endif
rc = do_callout(addr, host_list, &tf, callout, callout_overall,
callout_connect, options, se_mailfrom, pm_mailfrom);
-#ifndef DISABLE_TLS
deliver_set_expansions(NULL);
-#endif
+
if ( options & vopt_is_recipient
&& rc == OK
/* set to "random", with OK, for an accepted random */
for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
while (addr_list)
{
- address_item *addr = addr_list;
+ address_item * addr = addr_list;
transport_instance * tp = addr->transport;
addr_list = addr->next;
/* Show router, and transport */
fprintf(fp, "router = %s, transport = %s\n",
- addr->router->drinst.name, tp ? tp->name : US"unset");
+ addr->router->drinst.name, tp ? tp->drinst.name : US"unset");
/* Show any hosts that are set up by a router unless the transport
is going to override them; fiddle a bit to get a nice format. */
if (addr->host_list && tp && !tp->overrides_hosts)
{
+ transport_info * ti = tp->drinst.info;
int maxlen = 0;
int maxaddlen = 0;
for (host_item * h = addr->host_list; h; h = h->next)
if (h->address)
fprintf(fp, "[%s%-*c", h->address, maxaddlen+1 - Ustrlen(h->address), ']');
- else if (tp->info->local)
+ else if (ti->local)
fprintf(fp, " %-*s ", maxaddlen, ""); /* Omit [unknown] for local */
else
fprintf(fp, "[%s%-*c", "unknown", maxaddlen+1 - 7, ']');
out:
verify_mode = NULL;
-tls_modify_variables(&tls_in); /* return variables to inbound values */
+if (!(options & vopt_atrn))
+ tls_modify_variables(&tls_in); /* return variables to inbound values */
return yield;
}
if (iplookup)
{
- int insize;
- int search_type;
- int incoming[4];
- void *handle;
- uschar *filename, *key, *result;
+ const lookup_info * li;
+ int incoming[4], insize;
+ void * handle;
+ uschar * filename, * key, * result;
uschar buffer[64];
/* Find the search type */
- search_type = search_findtype(t, endname - t);
-
- if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- search_error_message);
+ if (!(li = search_findtype(t, endname - t)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
/* Adjust parameters for the type of lookup. For a query-style lookup, there
is no file name, and the "key" is just the query. For query-style with a file
dot separators instead of colons, except when the lookup type is "iplsearch".
*/
- if (mac_islookup(search_type, lookup_absfilequery))
+ if (mac_islookup(li, lookup_absfilequery))
{
filename = semicolon + 1;
key = filename;
filename = string_copyn(filename, key - filename);
Uskip_whitespace(&key);
}
- else if (mac_islookup(search_type, lookup_querystyle))
+ else if (mac_islookup(li, lookup_querystyle))
{
filename = NULL;
key = semicolon + 1;
}
else /* Single-key style */
{
- int sep = (Ustrcmp(lookup_list[search_type]->name, "iplsearch") == 0)?
- ':' : '.';
+ int sep = Ustrcmp(li->name, "iplsearch") == 0 ? ':' : '.';
insize = host_aton(cb->host_address, incoming);
host_mask(insize, incoming, mlen);
- (void)host_nmtoa(insize, incoming, mlen, buffer, sep);
+ (void) host_nmtoa(insize, incoming, mlen, buffer, sep);
key = buffer;
filename = semicolon + 1;
}
/* Now do the actual lookup; note that there is no search_close() because
of the caching arrangements. */
- if (!(handle = search_open(filename, search_type, 0, NULL, NULL)))
+ if (!(handle = search_open(filename, li, 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, opts);
if ((semicolon = Ustrchr(ss, ';')))
{
const uschar * affix, * opts;
- int partial, affixlen, starflags, id;
+ int partial, affixlen, starflags;
+ const lookup_info * li;
*semicolon = 0;
- id = search_findtype_partial(ss, &partial, &affix, &affixlen, &starflags,
+ li = search_findtype_partial(ss, &partial, &affix, &affixlen, &starflags,
&opts);
*semicolon=';';
- if (id < 0) /* Unknown lookup type */
+ if (!li) /* Unknown lookup type */
{
log_write(0, LOG_MAIN|LOG_PANIC, "%s in host list item \"%s\"",
search_error_message, ss);
return DEFER;
}
- isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
+ isquery = mac_islookup(li, lookup_querystyle|lookup_absfilequery);
}
if (isquery)
if (!sender_host_name)
{
HDEBUG(D_host_lookup)
- debug_printf("sender host name required, to match against %s\n", ss);
+ debug_printf_indent("sender host name required, to match against %s\n", ss);
+ expand_level++;
if (host_lookup_failed || host_name_lookup() != OK)
{
+ expand_level--;
*error = string_sprintf("failed to find host name for %s",
sender_host_address);;
return ERROR;
}
+ expand_level--;
host_build_sender_fullhost();
}
}
DEBUG(D_verify) debug_printf_indent("verify_quota: len %d\n", len);
-write(1, msg, len);
+if (write(1, msg, len) != 0) ;
return;
}