From: Jeremy Harris Date: Tue, 17 Dec 2024 18:42:13 +0000 (+0000) Subject: Callouts: r-verify option to use transport-defined mailfrom X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain?ds=sidebyside Callouts: r-verify option to use transport-defined mailfrom --- diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 1cf4562d2..31aafa4be 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -32218,7 +32218,7 @@ and data is copied from one to the other. An attempt to set this control for any recipient but the first for a mail will be quietly ignored. If a recipient-verify callout -(with use_sender) +(with use_sender or use_tpt_sender) connection is subsequently requested in the same ACL it is held open and used for any subsequent recipients and the data, @@ -32275,6 +32275,8 @@ The default value of &"orig"& uses the address given for envelope-from in the inbound (originating) connection. A value of &"transport"& permits the transport used for the outbound connection to modify the envelope-from, via its &*return_path*& option. +If the control is used on combination with a verify (as described above) +then the envelope-from options must match for the same connection to be used. .wen @@ -34236,7 +34238,11 @@ for the sender. This default is chosen because most hosts do not make use of the sender address when verifying a recipient. Using the same address means that a single cache entry can be used for each recipient. Some sites, however, do make use of the sender address when verifying. These are catered for by the -&%use_sender%& and &%use_postmaster%& options, described in the next section. +&%use_sender%&, +.new +&%use_tptsender%& +.wen +and &%use_postmaster%& options, described in the next section. If the response to the RCPT command is a 2&'xx'& code, the verification succeeds. If it is 5&'xx'&, the verification fails. For any other condition, @@ -34409,6 +34415,11 @@ need to use this option unless you know that the called hosts make use of the sender when checking recipients. If used indiscriminately, it reduces the usefulness of callout caching. +.vitem &*use_tptsender*& +This option is similar to &*use_sender*& above, +but additionally permits the replacement of the sender address +by the &*return_path*& option of the transport. + .vitem &*hold*& This option applies to recipient callouts only. For example: .code diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 91e1aacf6..9df91b9cd 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -30,7 +30,8 @@ Version 4.98 9. IPv6 address support for mysql and pgsql lookups - 10. Cutthrough deliveries can use an envelope-from specified by a transport. + 10. Cutthrough deliveries and recipient verifies can use an envelope-from + specified by a transport. Version 4.98 ------------ diff --git a/src/src/acl.c b/src/src/acl.c index 2e7dc2929..6b00b5677 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1711,9 +1711,10 @@ static verify_type_t verify_type_list[] = { enum { CALLOUT_DEFER_OK, CALLOUT_NOCACHE, CALLOUT_RANDOM, CALLOUT_USE_SENDER, - CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, CALLOUT_FULLPOSTMASTER, - CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, CALLOUT_MAXWAIT, CALLOUT_CONNECT, - CALLOUT_HOLD, CALLOUT_TIME /* TIME must be last */ + CALLOUT_USE_TPTSENDER, CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, + CALLOUT_FULLPOSTMASTER, CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, + CALLOUT_MAXWAIT, CALLOUT_CONNECT, CALLOUT_HOLD, + CALLOUT_TIME /* TIME must be last */ }; typedef struct { uschar * name; @@ -1728,7 +1729,8 @@ static callout_opt_t callout_opt_list[] = { { US"no_cache", CALLOUT_NOCACHE, vopt_callout_no_cache, FALSE, FALSE }, { US"random", CALLOUT_RANDOM, vopt_callout_random, FALSE, FALSE }, { US"use_sender", CALLOUT_USE_SENDER, vopt_callout_recipsender, FALSE, FALSE }, - { US"use_postmaster", CALLOUT_USE_POSTMASTER,vopt_callout_recippmaster, FALSE, FALSE }, + { US"use_tptsender", CALLOUT_USE_TPTSENDER, vopt_callout_r_tptsender, FALSE, FALSE }, + { US"use_postmaster", CALLOUT_USE_POSTMASTER,vopt_callout_r_pmaster, FALSE, FALSE }, { US"postmaster_mailfrom",CALLOUT_POSTMASTER_MAILFROM,0, TRUE, FALSE }, { US"postmaster", CALLOUT_POSTMASTER, 0, FALSE, FALSE }, { US"fullpostmaster", CALLOUT_FULLPOSTMASTER,vopt_callout_fullpm, FALSE, FALSE }, @@ -1802,31 +1804,22 @@ static int acl_verify(int where, address_item *addr, const uschar *arg, uschar **user_msgptr, uschar **log_msgptr, int *basic_errno) { -int sep = '/'; -int callout = -1; -int callout_overall = -1; -int callout_connect = -1; -int verify_options = 0; -int rc; -BOOL verify_header_sender = FALSE; -BOOL defer_ok = FALSE; -BOOL callout_defer_ok = FALSE; -BOOL no_details = FALSE; -BOOL success_on_redirect = FALSE; -BOOL quota = FALSE; +int sep = '/', callout = -1, callout_overall = -1, callout_connect = -1; +int verify_options = 0, rc; +BOOL verify_header_sender = FALSE, defer_ok = FALSE, callout_defer_ok = FALSE; +BOOL no_details = FALSE, success_on_redirect = FALSE, quota = FALSE; int quota_pos_cache = QUOTA_POS_DEFAULT, quota_neg_cache = QUOTA_NEG_DEFAULT; address_item * sender_vaddr = NULL; const uschar * verify_sender_address = NULL; -uschar * pm_mailfrom = NULL; -uschar * se_mailfrom = NULL; +uschar * pm_mailfrom = NULL, * se_mailfrom = NULL; /* Some of the verify items have slash-separated options; some do not. Diagnose an error if options are given for items that don't expect them. */ -uschar *slash = Ustrchr(arg, '/'); -const uschar *list = arg; -uschar *ss = string_nextinlist(&list, &sep, NULL, 0); +uschar * slash = Ustrchr(arg, '/'); +const uschar * list = arg; +uschar * ss = string_nextinlist(&list, &sep, NULL, 0); verify_type_t * vp; if (!ss) goto BAD_VERIFY; @@ -2113,13 +2106,22 @@ while ((ss = string_nextinlist(&list, &sep, NULL, 0))) } } -if ((verify_options & (vopt_callout_recipsender|vopt_callout_recippmaster)) == - (vopt_callout_recipsender|vopt_callout_recippmaster)) - { - *log_msgptr = US"only one of use_sender and use_postmaster can be set " - "for a recipient callout"; - return ERROR; - } + { + int ropts = verify_options & + (vopt_callout_recipsender|vopt_callout_r_tptsender|vopt_callout_r_pmaster); + if (ropts && verify_sender_address) + { + *log_msgptr = US"use_sender, use_tptsender or use_postmaster cannot be used" + "for a sender verify callout"; + return ERROR; + } + if ((ropts-1) & -ropts) /* more than one bit set */ + { + *log_msgptr = US"only one of use_sender, use_tptsender and use_postmaster" + " can be set for a recipient callout"; + return ERROR; + } + } /* Handle quota verification */ if (quota) @@ -2185,13 +2187,6 @@ callout handling, should ensure that this is not terribly inefficient. */ else if (verify_sender_address) { - if ((verify_options & (vopt_callout_recipsender|vopt_callout_recippmaster))) - { - *log_msgptr = US"use_sender or use_postmaster cannot be used for a " - "sender verify callout"; - return ERROR; - } - sender_vaddr = verify_checked_sender(verify_sender_address); if ( sender_vaddr /* Previously checked */ && callout <= 0) /* No callout needed this time */ @@ -3802,8 +3797,6 @@ for (; cb; cb = cb->next) } else if (Ustrncmp(pp, "sender=", 7) == 0) { -/*XXX rather raises the Q: should r-verify have a similar option? -Esp. given the callout hold options and upgrade to cutthrough... */ pp += 7; if (Ustrncmp(pp, "transport", 9) == 0) cutthrough.tpt_sender = TRUE; diff --git a/src/src/macros.h b/src/src/macros.h index 3ac9315c5..d2ae56921 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -741,7 +741,7 @@ enum { v_none, v_sender, v_recipient, v_expn }; #define vopt_callout_random 0x0020 /* during callout */ #define vopt_callout_no_cache 0x0040 /* disable callout cache */ #define vopt_callout_recipsender 0x0080 /* use real sender to verify recip */ -#define vopt_callout_recippmaster 0x0100 /* use postmaster to verify recip */ +#define vopt_callout_r_pmaster 0x0100 /* use postmaster to verify recip */ #define vopt_callout_r_tptsender 0x0200 /* use s from tpt to verify recip */ #define vopt_callout_hold 0x0400 /* lazy close connection */ #define vopt_success_on_redirect 0x0800 diff --git a/src/src/verify.c b/src/src/verify.c index c69dc193d..b48d17ee5 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -445,8 +445,6 @@ if (addr->transport == cutthrough.addr.transport) } break; /* host_list */ } -if (!done) - cancel_cutthrough_connection(TRUE, US"incompatible connection"); return done; } @@ -491,9 +489,9 @@ Arguments: vopt_callout_fullpm => if postmaster check, do full one vopt_callout_random => do the "random" thing vopt_callout_recipsender => use original sender addres - vopt_callout_recippmaster => use postmaster as sender -vopt_callout_r_tptsender => use sender as defined by transport - vopt_callout_hold => lazy close connection + 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 @@ -531,7 +529,7 @@ callout, because that may influence the result of the callout. */ if (options & vopt_is_recipient) if (options & ( vopt_callout_recipsender | vopt_callout_r_tptsender - | vopt_callout_recippmaster) + | vopt_callout_r_pmaster) ) { if (options & vopt_callout_recipsender) @@ -560,11 +558,9 @@ if (options & vopt_is_recipient) 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= */ - addr->return_path = from_address; /* for cutthrough logging */ - } } else { @@ -646,14 +642,19 @@ that conn for verification purposes (and later delivery also). Simplest 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_r_tptsender | 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. */ @@ -1141,7 +1142,7 @@ no_conn: && rcpt_count == 1 && done && yield == OK - && !(options & (vopt_callout_recippmaster | vopt_success_on_redirect)) + && !(options & (vopt_callout_r_pmaster| vopt_success_on_redirect)) && !random_local_part && !pm_mailfrom && cutthrough.cctx.sock < 0 @@ -1704,10 +1705,10 @@ Arguments: 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 transport + vopt_callout_r_tptsender => use sender as defined by tpt callout if > 0, specifies that callout is required, and gives timeout for individual commands