Callouts: r-verify option to use transport-defined mailfrom master
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 17 Dec 2024 18:42:13 +0000 (18:42 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 17 Dec 2024 21:18:26 +0000 (21:18 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/acl.c
src/src/macros.h
src/src/verify.c

index 1cf4562d2ac2aec13e726ab1b868041b0e7bb09e..31aafa4beeda259ffb6f0942d035637d7fbc5001 100644 (file)
@@ -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
index 91e1aacf6542126a855a18149d365848f73997e4..9df91b9cdae0d87f128bf7fff8ec850f66dcb1c9 100644 (file)
@@ -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
 ------------
index 2e7dc2929272aef44ea25aa20aba091491553de1..6b00b5677ea467e80834437c50fbf88d5418677a 100644 (file)
@@ -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;
index 3ac9315c579f352557e6fcdfc2aa4b701f7af85f..d2ae5692181020c6597a028d92c0dc67f865cc5d 100644 (file)
@@ -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
index c69dc193d2102d46f2edb5ec592bb6b2bcb60b5b..b48d17ee5b6c40b0d4e3e7a86921e2ec26336046 100644 (file)
@@ -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