Clean & integrate force_command.
authorPhil Pennock <pdp@exim.org>
Tue, 2 Apr 2013 01:24:14 +0000 (21:24 -0400)
committerPhil Pennock <pdp@exim.org>
Tue, 2 Apr 2013 01:24:14 +0000 (21:24 -0400)
Work by J. Nick Koston, for cPanel, Inc.

doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/ACKNOWLEDGMENTS
src/src/structs.h
src/src/transport.c
src/src/transports/pipe.c

index c3994a79cb194f6dbaaac270875440f4dc1e646c..4a9b3b9550fc0d8dce1f6537140463996bb0ed0e 100644 (file)
@@ -21712,11 +21712,14 @@ inserted in the argument list at that point &'as a separate argument'&. This
 avoids any problems with spaces or shell metacharacters, and is of use when a
 &(pipe)& transport is handling groups of addresses in a batch.
 
-If &(force_command)& is enabled on the transport, Special handling takes place
+If &%force_command%& is enabled on the transport, Special handling takes place
 for an argument that consists of precisely the text &`$address_pipe`&.  It
-is handled much like &`$pipe_addresses`& above.  It is expanded and each
+is handled similarly to &$pipe_addresses$& above.  It is expanded and each
 argument is inserted in the argument list at that point
-&'as a separate argument'&.
+&'as a separate argument'&.  The &`$address_pipe`& item does not need to be
+the only item in the argument; in fact, if it were then &%force_command%&
+should behave as a no-op.  Rather, it should be used to adjust the command
+run while preserving the argument vector separation.
 
 After splitting up into arguments and expansion, the resulting command is run
 in a subprocess directly from the transport, &'not'& under a shell. The
@@ -21883,6 +21886,10 @@ command = /usr/bin/remote_exec myhost -- $address_pipe
 force_command
 .endd
 
+Note that &$address_pipe$& is handled specially in &%command%& when
+&%force_command%& is set, expanding out to the original argument vector as
+separate items, similarly to a Unix shell &`"$@"`& construct.
+
 .option ignore_status pipe boolean false
 If this option is true, the status returned by the subprocess that is set up to
 run the command is ignored, and Exim behaves as if zero had been returned.
index abaee5659d0b674c3242a3d0b3c68a31dbc29add..bfef5556d7f87e9fe6b23c4a8af2c68c5b1486d3 100644 (file)
@@ -185,6 +185,9 @@ PP/19 Renamed DNSSEC-enabling option to "dns_dnssec_ok", to make it
       clearer that Exim is using the DO (DNSSEC OK) EDNS0 resolver flag,
       not performing validation itself.
 
+PP/20 Added force_command boolean option to pipe transport.
+      Patch from Nick Koston, of cPanel Inc.
+
 
 Exim version 4.80.1
 -------------------
index ab8589e53896871d58da2efae3b3b0a8bf9ea884..e349fc855302c1525f8087d59b4288dd6d9a9b21 100644 (file)
@@ -130,6 +130,10 @@ Version 4.82
 18. If built with EXPERIMENTAL_PRDR, per-recipient data responses per a
     proposed extension to SMTP from Eric Hall.
 
+19. The pipe transport has gained the force_command option, to allow
+    decorating commands from user .forward pipe aliases with prefix
+    wrappers, for instance.
+
 
 Version 4.80
 ------------
index fa692bfb175a7cea1ec61cf0aa4e4ec9297a56c4..cb5f35eb6af94e32d385e656a02916614c4f34a7 100644 (file)
@@ -235,6 +235,7 @@ forbid_include                       boolean         false         redirect
 forbid_pipe                          boolean         false         redirect          4.00
 forbid_sieve_filter                  boolean         false         redirect          4.44
 forbid_smtp_code                     boolean         false         redirect          4.63
+force_command                        boolean         false         pipe              4.82
 freeze_exec_fail                     boolean         false         pipe              1.89
 freeze_signal                        boolean         false         pipe              4.75
 freeze_tell                          boolean         false         main              4.00 replaces freeze_tell_mailmaster
index ed005b3f851fa8b717de96bbd32640e2a5d3521c..4474de32240ae0026f21ffcc6035c2262f95b92a 100644 (file)
@@ -405,6 +405,7 @@ John Horne                Patch adding $av_failed
                           Pointed out ClamAV ExtendedDetectionInfo compat issue
 Regid Ichira              Documentation fixes
 Andreas M. Kirchwitz      Let /dev/null have normal permissions (4.73 fallout)
+J. Nick Koston            Patch adding force_command pipe transport option
 Roberto Lima              Patch letting exicyclog rotate paniclog
 Todd Lyons                Patch handling TAB in MAIL arguments
 Christof Meerwald         Provided insight & suggested patch for GnuTLS update
index 1105bb718691ff30f1272b1eae8b6a5200face93..53aa2106b7834d2095160b066416b20bcc94e497 100644 (file)
@@ -482,11 +482,10 @@ typedef struct address_item_propagated {
 #define af_cert_verified       0x01000000 /* delivered with verified TLS cert */
 #define af_pass_message        0x02000000 /* pass message in bounces */
 #define af_bad_reply           0x04000000 /* filter could not generate autoreply */
-#define af_force_command       0x08000000 /* force command */
-
 #ifdef EXPERIMENTAL_PRDR
 # define af_prdr_used          0x08000000 /* delivery used SMTP PRDR */
 #endif
+#define af_force_command       0x10000000 /* force_command in pipe transport */
 
 /* These flags must be propagated when a child is created */
 
index a112820fdceb5d18102a71cedd012596b2e5829f..7dd1afb85d828f26dad55785feca43fdd661b32b 100644 (file)
@@ -2002,10 +2002,9 @@ if (expand_arguments)
           argcount++;
       }
 
-        /* Subtract one since we replace $pipe_addresses */
-        argcount--;
-        i--;
-
+      /* Subtract one since we replace $pipe_addresses */
+      argcount--;
+      i--;
       }
 
       /* Handle special case of $address_pipe when af_force_command is set */
@@ -2023,8 +2022,7 @@ if (expand_arguments)
       address_pipe_max_args = max_args - argcount + 1;
 
       DEBUG(D_transport)
-        debug_printf("address_pipe_max_args=%d\n",
-          address_pipe_max_args);
+        debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args);
 
       /* We allocate an additional for (uschar *)0 */
       address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *));
@@ -2032,13 +2030,14 @@ if (expand_arguments)
       /* +1 because addr->local_part[0] == '|' since af_force_command is set */
       s = expand_string(addr->local_part + 1);
 
-      if (s == NULL || *s == '\0') {
-       addr->transport_return = FAIL;
-       addr->message = string_sprintf("Expansion of \"%s\" "
-          "from command \"%s\" in %s failed: %s",
-          (addr->local_part + 1), cmd, etext, expand_string_message);
+      if (s == NULL || *s == '\0')
+        {
+        addr->transport_return = FAIL;
+        addr->message = string_sprintf("Expansion of \"%s\" "
+           "from command \"%s\" in %s failed: %s",
+           (addr->local_part + 1), cmd, etext, expand_string_message);
         return FALSE;
-      }
+        }
 
       while (isspace(*s)) s++; /* strip leading space */
 
@@ -2073,9 +2072,9 @@ if (expand_arguments)
         return FALSE;
         }
 
-        /* address_pipe_argcount - 1
-         * because we are replacing $address_pipe in the argument list
-         * with the first thing it expands to */
+      /* address_pipe_argcount - 1
+       * because we are replacing $address_pipe in the argument list
+       * with the first thing it expands to */
       if (argcount + address_pipe_argcount - 1 > max_args)
         {
         addr->transport_return = FAIL;
@@ -2086,10 +2085,10 @@ if (expand_arguments)
 
       /* If we are not just able to replace the slot that contained
        * $address_pipe (address_pipe_argcount == 1)
-       * We have to move the existing argv by address_pipe_argcount
+       * We have to move the existing argv by address_pipe_argcount - 1
        * Visually if address_pipe_argcount == 2:
        * [argv 0][argv 1][argv 2($address_pipe)][argv 3][0]
-       * [argv 0][argv 1][XXXXXX][XXXXXX][old argv 3][0]
+       * [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0]
        */
       if (address_pipe_argcount > 1)
         memmove(
@@ -2104,17 +2103,17 @@ if (expand_arguments)
       /* Now we fill in the slots we just moved argv out of
        * [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0]
        */
-       for (address_pipe_i = 0;
-            address_pipe_argv[address_pipe_i] != (uschar *)0;
-            address_pipe_i++) {
-         argv[i++] = address_pipe_argv[address_pipe_i];
-         argcount++;
+      for (address_pipe_i = 0;
+           address_pipe_argv[address_pipe_i] != (uschar *)0;
+           address_pipe_i++)
+        {
+        argv[i++] = address_pipe_argv[address_pipe_i];
+        argcount++;
         }
 
-        /* Subtract one since we replace $address_pipe */
-        argcount--;
-        i--;
-
+      /* Subtract one since we replace $address_pipe */
+      argcount--;
+      i--;
       }
 
     /* Handle normal expansion string */
index 39a9d8b476cec313210b6eae0f110c56d180ec8c..54989410a4266442504e476c99ab78267630e30e 100644 (file)
@@ -572,17 +572,20 @@ options. */
 
 if (testflag(addr, af_pfr) && addr->local_part[0] == '|')
   {
-    if (ob->force_command) {
-     /* Enables expansion of $address_pipe into seperate arguments */
-     setflag(addr,af_force_command);
-     cmd = ob->cmd;
-     expand_arguments = TRUE;
-     expand_fail = PANIC;
-    } else {
-     cmd = addr->local_part + 1;
-     while (isspace(*cmd)) cmd++;
-     expand_arguments = testflag(addr, af_expand_pipe);
-     expand_fail = FAIL;
+  if (ob->force_command)
+    {
+    /* Enables expansion of $address_pipe into seperate arguments */
+    setflag(addr, af_force_command);
+    cmd = ob->cmd;
+    expand_arguments = TRUE;
+    expand_fail = PANIC;
+    }
+  else
+    {
+    cmd = addr->local_part + 1;
+    while (isspace(*cmd)) cmd++;
+    expand_arguments = testflag(addr, af_expand_pipe);
+    expand_fail = FAIL;
     }
   }
 else