From 700d22f3fc0cc559170e8085a1b799b61dceb738 Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Mon, 1 Apr 2013 21:24:14 -0400 Subject: [PATCH] Clean & integrate force_command. Work by J. Nick Koston, for cPanel, Inc. --- doc/doc-docbook/spec.xfpt | 13 +++++++--- doc/doc-txt/ChangeLog | 3 +++ doc/doc-txt/NewStuff | 4 +++ doc/doc-txt/OptionLists.txt | 1 + src/ACKNOWLEDGMENTS | 1 + src/src/structs.h | 3 +-- src/src/transport.c | 51 ++++++++++++++++++------------------- src/src/transports/pipe.c | 25 ++++++++++-------- 8 files changed, 59 insertions(+), 42 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index c3994a79c..4a9b3b955 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -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. diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index abaee5659..bfef5556d 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -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 ------------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index ab8589e53..e349fc855 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -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 ------------ diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt index fa692bfb1..cb5f35eb6 100644 --- a/doc/doc-txt/OptionLists.txt +++ b/doc/doc-txt/OptionLists.txt @@ -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 diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index ed005b3f8..4474de322 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -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 diff --git a/src/src/structs.h b/src/src/structs.h index 1105bb718..53aa2106b 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -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 */ diff --git a/src/src/transport.c b/src/src/transport.c index a112820fd..7dd1afb85 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -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 */ diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 39a9d8b47..54989410a 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -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 -- 2.25.1