This item inserts &"raw"& header lines. It is described with the &%header%&
expansion item in section &<<SECTexpansionitems>>& above.
-.vitem "&*${run{*&<&'command'&>&*&~*&<&'args'&>&*}{*&<&'string1'&>&*}&&&
+.vitem "&*${run <&'options'&> {*&<&'command&~arg&~list'&>&*}{*&<&'string1'&>&*}&&&
{*&<&'string2'&>&*}}*&"
.cindex "expansion" "running a command"
.cindex "&%run%& expansion item"
-The command and its arguments are first expanded as one string. The string is
-split apart into individual arguments by spaces, and then the command is run
+This item runs an external command, as a subprocess.
+.new
+One option is supported after the word &'run'&, comma-separated.
+
+If the option &'preexpand'& is not used,
+the command string is split into individual arguments by spaces
+and then each argument is expanded.
+Then the command is run
in a separate process, but under the same uid and gid. As in other command
executions from Exim, a shell is not used by default. If the command requires
a shell, you must explicitly code it.
+The command name may not be tainted, but the remaining arguments can be.
+If the option &'preexpand'& is used,
+.wen
+the command and its arguments are first expanded as one string. The result is
+split apart into individual arguments by spaces, and then the command is run
+as above.
Since the arguments are split by spaces, when there is a variable expansion
which has an empty result, it will cause the situation that the argument will
simply be omitted when the program is actually executed by Exim. If the
around the command arguments. A possible guard against this is to wrap the
variable in the &%sg%& operator to change any quote marks to some other
character.
+.new
+Neither the command nor any argument may be tainted.
+.wen
The standard input for the command exists, but is empty. The standard output
and standard error are set to the same file descriptor.
resulted in the library waiting for the peer's Close. If that was never
sent we waited forever. Fix by tracking send calls.
+JH/24 The ${run} expansion item now expands its command string elements after
+ splitting. Previously it was before; the new ordering makes handling
+ zero-length arguments simpler. The old ordering can be obtained by
+ appending a new option "preexpand", after a comma, to the "run".
+
+JH/25 Taint-check exec arguments for transport-initiated external processes.
+ Previously, tainted values could be used. This affects "pipe", "lmtp" and
+ "queryprogram" transport, transport-filter, and ETRN commands.
+ The ${run} expansion is also affected: in "preexpand" mode no part of
+ the command line may be tainted, in default mode the executable name
+ may not be tainted.
+
Exim version 4.95
-----------------
if (is_tainted(argv[0]))
{
log_write(0, LOG_MAIN | LOG_PANIC, "Attempt to exec tainted path: '%s'", argv[0]);
+ errno = EPERM;
return (pid_t)(-1);
}
{
ok = transport_set_up_command(&transport_filter_argv,
tp->filter_command,
- TRUE, PANIC, addr, US"transport filter", NULL);
+ TRUE, PANIC, addr, FALSE, US"transport filter", NULL);
transport_filter_timeout = tp->filter_timeout;
}
else transport_filter_argv = NULL;
{
FILE * f;
const uschar * arg, ** argv;
+ BOOL late_expand = TRUE;
if ((expand_forbid & RDO_RUN) != 0)
{
goto EXPAND_FAILED;
}
+ /* Handle options to the "run" */
+
+ while (*s == ',')
+ {
+ if (Ustrncmp(++s, "preexpand", 9) == 0)
+ { late_expand = FALSE; s += 9; }
+ else
+ {
+ const uschar * t = s;
+ while (isalpha(*++t)) ;
+ expand_string_message = string_sprintf("bad option '%.*s' for run",
+ (int)(t-s), s);
+ goto EXPAND_FAILED;
+ }
+ }
Uskip_whitespace(&s);
+
if (*s != '{') /*}*/
{
expand_string_message = US"missing '{' for command arg of run";
goto EXPAND_FAILED_CURLY; /*"}*/
}
- if (!(arg = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
- goto EXPAND_FAILED;
- Uskip_whitespace(&s);
+ s++;
+
+ if (late_expand) /* this is the default case */
+ {
+ int n = Ustrcspn(s, "}");
+ arg = skipping ? NULL : string_copyn(s, n);
+ s += n;
+ }
+ else
+ {
+ if (!(arg = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
+ goto EXPAND_FAILED;
+ Uskip_whitespace(&s);
+ }
/*{*/
if (*s++ != '}')
{ /*{*/
if (!transport_set_up_command(&argv, /* anchor for arg list */
arg, /* raw command */
- FALSE, /* don't expand the arguments */
- 0, /* not relevant when... */
- NULL, /* no transporting address */
- US"${run} expansion", /* for error messages */
- &expand_string_message)) /* where to put error message */
+ late_expand, /* expand args if not already done */
+ 0, /* not relevant when... */
+ NULL, /* no transporting address */
+ late_expand, /* allow tainted args, when expand-after-split */
+ US"${run} expansion", /* for error messages */
+ &expand_string_message)) /* where to put error message */
goto EXPAND_FAILED;
/* Create the child process, making it a group leader. */
);
extern uschar *transport_rcpt_address(address_item *, BOOL);
extern BOOL transport_set_up_command(const uschar ***, const uschar *,
- BOOL, int, address_item *, const uschar *, uschar **);
+ BOOL, int, address_item *, BOOL, const uschar *, uschar **);
extern void transport_update_waiting(host_item *, uschar *);
extern BOOL transport_write_block(transport_ctx *, uschar *, int, BOOL);
extern void transport_write_reset(int);
TRUE, /* expand the arguments */
0, /* not relevant when... */
NULL, /* no transporting address */
+ FALSE, /* args must be untainted */
US"queryprogram router", /* for error messages */
&addr->message)) /* where to put error message */
return DEFER;
etrn_command = smtp_etrn_command;
deliver_domain = smtp_cmd_data;
rc = transport_set_up_command(&argv, smtp_etrn_command, TRUE, 0, NULL,
- US"ETRN processing", &error);
+ FALSE, US"ETRN processing", &error);
deliver_domain = NULL;
if (!rc)
{
+/* Enforce all args untainted, for consistency with a router-sourced pipe
+command, where (because the whole line is passed as one to the tpt) a
+tainted arg taints the executable name. It's unclear also that letting an
+attacker supply command arguments is wise. */
+
+static BOOL
+arg_is_tainted(const uschar * s, int argn, address_item * addr,
+ const uschar * etext, uschar ** errptr)
+{
+if (is_tainted(s))
+ {
+ uschar * msg = string_sprintf("Tainted arg %d for %s command: '%s'",
+ argn, etext, s);
+ if (addr)
+ {
+ addr->transport_return = FAIL;
+ addr->message = msg;
+ }
+ else *errptr = msg;
+ return TRUE;
+ }
+return FALSE;
+}
+
+
/*************************************************
* Set up direct (non-shell) command *
*************************************************/
expand_failed error value to set if expansion fails; not relevant if
addr == NULL
addr chain of addresses, or NULL
+ allow_tainted_args as it says; used for ${run}
etext text for use in error messages
errptr where to put error message if addr is NULL;
otherwise it is put in the first address
BOOL
transport_set_up_command(const uschar *** argvptr, const uschar * cmd,
- BOOL expand_arguments, int expand_failed, address_item *addr,
- const uschar * etext, uschar ** errptr)
+ BOOL expand_arguments, int expand_failed, address_item * addr,
+ BOOL allow_tainted_args, const uschar * etext, uschar ** errptr)
{
const uschar ** argv, * s;
int address_count = 0, argcount = 0, max_args;
for (address_item * ad = addr; ad; ad = ad->next)
{
+ /* $pipe_addresses is spefically not checked for taint, because there is
+ a testcase (321) depending on it. It's unclear if the exact thing being
+ done really needs to be legitimate, though I suspect it reflects an
+ actual use-case that showed up a bug.
+ This is a hole in the taint-pretection, mitigated only in that
+ shell-syntax metachars cannot be injected via this route. */
+
+ DEBUG(D_transport) if (is_tainted(ad->address))
+ debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address);
+
argv[i++] = ad->address;
argcount++;
}
for (int address_pipe_i = 0;
address_pipe_argv[address_pipe_i];
address_pipe_i++, argcount++)
- argv[i++] = address_pipe_argv[address_pipe_i];
+ {
+ uschar * s = address_pipe_argv[address_pipe_i];
+ if (arg_is_tainted(s, i, addr, etext, errptr)) return FALSE;
+ argv[i++] = s;
+ }
/* Subtract one since we replace $address_pipe */
argcount--;
else *errptr = msg;
return FALSE;
}
+
+ if ( f.running_in_test_harness && is_tainted(expanded_arg)
+ && Ustrcmp(etext, "queryprogram router") == 0)
+ { /* hack, would be good to not need it */
+ DEBUG(D_transport)
+ debug_printf("SPECIFIC TESTSUITE EXEMPTION: tainted arg '%s'\n",
+ expanded_arg);
+ }
+ else if ( !allow_tainted_args
+ && arg_is_tainted(expanded_arg, i, addr, etext, errptr))
+ return FALSE;
argv[i] = expanded_arg;
}
}
{
debug_printf("direct command after expansion:\n");
for (int i = 0; argv[i]; i++)
- debug_printf(" argv[%d] = %s\n", i, string_printing(argv[i]));
+ {
+ debug_printf(" argv[%d] = '%s'\n", i, string_printing(argv[i]));
+ debug_print_taint(argv[i]);
+ }
}
}
{
DEBUG(D_transport) debug_printf("using command %s\n", ob->cmd);
sprintf(CS buffer, "%.50s transport", tblock->name);
- if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist, buffer,
- NULL))
+ if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist, FALSE,
+ buffer, NULL))
return FALSE;
/* If the -N option is set, can't do any more. Presume all has gone well. */
is in the addresses). */
if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail,
- addr, string_sprintf("%.50s transport", tname), NULL))
+ addr, FALSE, string_sprintf("%.50s transport", tname), NULL))
return FALSE;
/* Point to the set-up arguments. */
for (address_item * ad = addr; ad; ad = ad->next)
{
+ DEBUG(D_transport) if (is_tainted(ad->address))
+ debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address);
+
/*XXX string_append_listele() ? */
if (ad != addr) g = string_catn(g, US" ", 1);
g = string_cat(g, ad->address);
}
if (is_tainted(cmd))
{
+ DEBUG(D_transport) debug_printf("cmd '%s' is tainted\n", cmd);
addr->message = string_sprintf("Tainted '%s' (command "
"for %s transport) not permitted", cmd, tblock->name);
addr->transport_return = PANIC;
yield ERROR. */
if (!transport_set_up_command(&transport_filter_argv,
- tblock->filter_command, TRUE, DEFER, addrlist,
+ tblock->filter_command, TRUE, DEFER, addrlist, FALSE,
string_sprintf("%.50s transport filter", tblock->name), NULL))
{
set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+# The map/match here detaints the $recipients
+#
if $recipients contains pipe then
- pipe "DIR/aux-fixed/showenv $recipients"
+ pipe "DIR/aux-fixed/showenv \
+ \"${map {<, $recipients} \
+ {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}\""
endif
+
if error_message then finish endif
if $received_protocol is not scanned-ok then
- pipe "DIR/aux-fixed/resubmit $sender_address $recipients DIR/ CALLER"
+ pipe "DIR/aux-fixed/resubmit \
+ \"${if match_address {$sender_address}{CALLER@test.ex} {$value}}\" \
+ \"${map {<, $recipients} \
+ {${if match_address {$item} {userx@test.ex : usery@test.ex : userz@test.ex} { $value}}}}\" \
+ DIR/ CALLER"
endif
-# Exim filter (system filter for test 444)
+# Exim filter (system filter for test 0383)
if error_message then finish endif
if foranyaddress $h_to: ($thisaddress matches "^(alice)") then
+ pipe "DIR/aux-fixed/showenv \"${if match_address {$thisaddress}{alice@test.ex}{$value}}\" $1"
+ finish
+endif
+
+if foranyaddress $h_to: ($thisaddress matches "^(marny)") then
pipe "DIR/aux-fixed/showenv $thisaddress $1"
finish
endif
mmdf_localuser:
driver = accept
local_part_prefix = mmdf-
+ local_parts = userx
transport = mmdf_local_delivery
filtered_localuser:
driver = accept
local_part_prefix = filter-
+ local_parts = userx
transport = filtered_local_delivery
bsmtp_localuser:
local_delivery:
driver = pipe
check_string = "From "
- command = /bin/sh -c 'cat >>DIR/test-mail/$local_part'
+ command = /bin/sh -c 'cat >>DIR/test-mail/$local_part_data'
escape_string = ">From "
user = CALLER
current_directory = /
bsmtp_local_delivery:
driver = pipe
use_bsmtp
- command = /bin/sh -c 'cat >>DIR/test-mail/$local_part'
+ command = /bin/sh -c 'cat >>DIR/test-mail/$local_part_data'
delivery_date_add
envelope_to_add
return_path_add
filtered_local_delivery:
driver = pipe
- command = /bin/sh -c 'cat >>DIR/test-mail/$local_part'
+ command = /bin/sh -c 'cat >>DIR/test-mail/$local_part_data'
delivery_date_add
envelope_to_add
return_path_add
mmdf_local_delivery:
driver = pipe
check_string = "\1\1\1\1\n"
- command = /bin/sh -c 'cat >>DIR/test-mail/$local_part'
+ command = /bin/sh -c 'cat >>DIR/test-mail/$local_part_data'
escape_string = "\1\1\1\1 \n"
message_prefix = "\1\1\1\1\n"
message_suffix = "\1\1\1\1\n"
pipe:
driver = pipe
- command = /bin/sh -c "echo $local_part $domain >DIR/test-mail/$local_part"
+ command = /bin/sh -c "echo $local_part_data $domain_data >DIR/test-mail/$local_part_data"
user = CALLER
piperet:
driver = pipe
batch_max = 100
- command = DIR/aux-fixed/TESTNUM.ret $h_ret:
+ command = DIR/aux-fixed/TESTNUM.ret "${if inlist {$h_ret:} {75:99} {$value}}"
return_fail_output
user = CALLER
pipe:
driver = pipe
- command = /non/exist/command -f <$sender_address> -d $pipe_addresses
+ command = /non/exist/command -f \
+ "<${if match_local_part {$sender_address}{CALLER@test.ex}{$value}}>" \
+ -d $pipe_addresses
message_prefix =
message_suffix =
check_string =
t1:
driver = pipe
- command = /bin/sh -c 'exit $local_part'
+ command = /bin/sh -c 'exit "${if inlist {$local_part}{0:10:45}{$value}}"'
user = CALLER
temp_errors = 45 : 56
t2:
driver = pipe
- command = /bin/sh -c 'exit $local_part'
+ command = /bin/sh -c 'exit "${if inlist {$local_part}{0:10:45}{$value}}"'
user = CALLER
temp_errors = *
qualify_domain = test.ex
system_filter = DIR/aux-var/TESTNUM.F
system_filter_pipe_transport = t1
-
+log_selector = +received_recipients
# ----- Routers -----
begin routers
-r2:
+r0:
driver = redirect
local_part_prefix = pipe-
local_part_suffix = =*
caseful_local_part = true
data = |${substr_1:$local_part_suffix}
- pipe_transport = t2
+ pipe_transport = t0
+
+r1:
+ driver = redirect
+ local_parts = rtr_user
+ data = |echo $local_part
+ pipe_transport = t0
+
+r2:
+ driver = redirect
+ local_parts = tpt_user
+ data = |unused_word
+ pipe_transport = t1
+ errors_to = ""
# ----- Transports -----
begin transports
-t2:
+t0:
+ driver = pipe
+ user = CALLER
+
+t1:
driver = pipe
+ force_command
+ command = echo $local_part
user = CALLER
- batch_max = 10
# End
smartuser:
driver = accept
retry_use_local_part
+ address_data = ${if inlist {$h_script:}{01:02:03:04:05:06:07:08:09:10} {$value}}
transport = lmtp
lmtp:
driver = lmtp
batch_max = 100
- command = DIR/bin/mtpscript DIR/aux-fixed/TESTNUM.script.$h_script: +DIR/spool/log/mainlog
+ command = DIR/bin/mtpscript DIR/aux-fixed/TESTNUM.script.$address_data +DIR/spool/log/mainlog
timeout = 1s
user = EXIMUSER
ignore_quota = IGNORE_QUOTA
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaX-0005vi-00 original recipients ignored (system filter)
-1999-03-02 09:44:33 10HmaX-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $recipients <system-filter> T=address_pipe: return message generated
+1999-03-02 09:44:33 10HmaX-0005vi-00 ** |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}" <system-filter> T=address_pipe: return message generated
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> R=user T=local_delivery
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaZ-0005vi-00 original recipients ignored (system filter)
-1999-03-02 09:44:33 10HmaZ-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $recipients <system-filter> T=address_pipe: return message generated
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}" <system-filter> T=address_pipe: return message generated
1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
1999-03-02 09:44:33 10HmbA-0005vi-00 => CALLER <CALLER@test.ex> R=user T=local_delivery
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=scanned-ok S=sss id=E10HmaX-0005vi-00@the.local.host.name
1999-03-02 09:44:33 10HmaY-0005vi-00 => userx <userx@test.ex> R=all T=appendfile
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaX-0005vi-00 => |TESTSUITE/aux-fixed/resubmit $sender_address $recipients TESTSUITE/ CALLER <system-filter> T=pipe
+1999-03-02 09:44:33 10HmaX-0005vi-00 => |TESTSUITE/aux-fixed/resubmit "${if match_address {$sender_address}{CALLER@test.ex} {$value}}" "${map {<, $recipients} {${if match_address {$item} {userx@test.ex : usery@test.ex : userz@test.ex} { $value}}}}" TESTSUITE/ CALLER <system-filter> T=pipe
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaZ-0005vi-00 original recipients ignored (system filter)
1999-03-02 09:44:33 10HmbA-0005vi-00 => usery <usery@test.ex> R=all T=appendfile
1999-03-02 09:44:33 10HmbA-0005vi-00 => userz <userz@test.ex> R=all T=appendfile
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => |TESTSUITE/aux-fixed/resubmit $sender_address $recipients TESTSUITE/ CALLER <system-filter> T=pipe
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => |TESTSUITE/aux-fixed/resubmit "${if match_address {$sender_address}{CALLER@test.ex} {$value}}" "${map {<, $recipients} {${if match_address {$item} {userx@test.ex : usery@test.ex : userz@test.ex} { $value}}}}" TESTSUITE/ CALLER <system-filter> T=pipe
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss for alice
1999-03-02 09:44:33 10HmaX-0005vi-00 original recipients ignored (system filter)
-1999-03-02 09:44:33 10HmaX-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $thisaddress $1 <system-filter> T=t1: return message generated
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 ** |TESTSUITE/aux-fixed/showenv "${if match_address {$thisaddress}{alice@test.ex}{$value}}" $1 <system-filter> T=t1: return message generated
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> R=r1 T=t2
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss for marny
1999-03-02 09:44:33 10HmaZ-0005vi-00 original recipients ignored (system filter)
-1999-03-02 09:44:33 10HmaZ-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $1 <system-filter> T=t1: return message generated
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $thisaddress $1 <system-filter> T=t1: Tainted arg 1 for t1 transport command: 'marny@test.ex'
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbA-0005vi-00 => CALLER <CALLER@test.ex> R=r1 T=t2
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmbB-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $thisaddress $1 <redking@test.ex> R=r0 T=t1: return message generated
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss for jabberwocky
+1999-03-02 09:44:33 10HmbB-0005vi-00 original recipients ignored (system filter)
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $1 <system-filter> T=t1: return message generated
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbC-0005vi-00 => CALLER <CALLER@test.ex> R=r1 T=t2
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss for redking
+1999-03-02 09:44:33 10HmbD-0005vi-00 ** |TESTSUITE/aux-fixed/showenv $thisaddress $1 <redking@test.ex> R=r0 T=t1: return message generated
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= <> R=10HmbD-0005vi-00 U=EXIMUSER P=local S=sss for CALLER@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 => CALLER <CALLER@test.ex> R=r1 T=t2
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r2 T=t2 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t2 transport) not permitted
+1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r0 T=t0 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t0 transport) not permitted
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 == |echo rtr_user <rtr_user@test.ex> R=r1 T=t0 defer (0): Tainted 'echo rtr_user' (command for t0 transport) not permitted
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** |unused_word <tpt_user@test.ex> R=r2 T=t1: Tainted arg 1 for t1 transport command: 'tpt_user'
+1999-03-02 09:44:33 10HmaZ-0005vi-00 |unused_word <tpt_user@test.ex>: error ignored
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
- pipe to |TESTSUITE/aux-fixed/showenv $recipients
+ pipe to |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}"
generated by system-filter
The following text was generated during the delivery attempt:
------- pipe to |TESTSUITE/aux-fixed/showenv $recipients
+------ pipe to |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}"
generated by system-filter ------
Test pipe script
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
- pipe to |TESTSUITE/aux-fixed/showenv $recipients
+ pipe to |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}"
generated by system-filter
The following text was generated during the delivery attempt:
------- pipe to |TESTSUITE/aux-fixed/showenv $recipients
+------ pipe to |TESTSUITE/aux-fixed/showenv "${map {<, $recipients} {${if match_address {$item} {pipe@test.ex : another@test.ex : a-third@test.ex} {$value}}}}"
generated by system-filter ------
Test pipe script
Running as: CALLER
------------------
Args:
- pipe@test.ex, another@test.ex, a-third@test.ex
+ pipe@test.ex,another@test.ex,a-third@test.ex
----------current-----------
/
----------env-----------
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
- pipe to |TESTSUITE/aux-fixed/showenv $thisaddress $1
+ pipe to |TESTSUITE/aux-fixed/showenv "${if match_address {$thisaddress}{alice@test.ex}{$value}}" $1
generated by system-filter
The following text was generated during the delivery attempt:
------- pipe to |TESTSUITE/aux-fixed/showenv $thisaddress $1
+------ pipe to |TESTSUITE/aux-fixed/showenv "${if match_address {$thisaddress}{alice@test.ex}{$value}}" $1
generated by system-filter ------
Test pipe script
This message was created automatically by mail delivery software.
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+ pipe to |TESTSUITE/aux-fixed/showenv $thisaddress $1
+ generated by system-filter
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/delivery-status
+
+Reporting-MTA: dns; myhost.test.ex
+
+Action: failed
+Final-Recipient: rfc822;system-filter
+Status: 5.0.0
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/rfc822
+
+Return-path: <CALLER@test.ex>
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaZ-0005vi-00
+ for marny@test.ex;
+ Tue, 2 Mar 1999 09:44:33 +0000
+To: marny@test.ex
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+ id 10HmbC-0005vi-00
+ for CALLER@test.ex;
+ Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: system-filter
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@test.ex>
+To: CALLER@test.ex
+References: <E10HmbB-0005vi-00@myhost.test.ex>
+Content-Type: multipart/report; report-type=delivery-status; boundary=NNNNNNNNNN-eximdsn-MMMMMMMMMM
+MIME-Version: 1.0
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <E10HmbC-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: text/plain; charset=us-ascii
+
+This message was created automatically by mail delivery software.
+
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
LOCAL_PART_SUFFIX=
LOGNAME=system-filter
ME=
-MESSAGE_ID=10HmaZ-0005vi-00
+MESSAGE_ID=10HmbB-0005vi-00
PATH=/bin:/usr/bin
QUALIFY_DOMAIN=test.ex
RECIPIENT=system-filter@test.ex
>From CALLER@test.ex Tue Mar 02 09:44:33 1999
Received: from CALLER by myhost.test.ex with local (Exim x.yz)
(envelope-from <CALLER@test.ex>)
- id 10HmaZ-0005vi-00
+ id 10HmbB-0005vi-00
for jabberwocky@test.ex;
Tue, 2 Mar 1999 09:44:33 +0000
To: jabberwocky@test.ex
-Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
From: CALLER_NAME <CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
Return-path: <CALLER@test.ex>
Received: from CALLER by myhost.test.ex with local (Exim x.yz)
(envelope-from <CALLER@test.ex>)
- id 10HmaZ-0005vi-00
+ id 10HmbB-0005vi-00
for jabberwocky@test.ex;
Tue, 2 Mar 1999 09:44:33 +0000
To: jabberwocky@test.ex
-Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
From: CALLER_NAME <CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
From MAILER-DAEMON Tue Mar 02 09:44:33 1999
Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
- id 10HmbC-0005vi-00
+ id 10HmbE-0005vi-00
for CALLER@test.ex;
Tue, 2 Mar 1999 09:44:33 +0000
X-Failed-Recipients: redking@test.ex
Auto-Submitted: auto-replied
From: Mail Delivery System <Mailer-Daemon@test.ex>
To: CALLER@test.ex
-References: <E10HmbB-0005vi-00@myhost.test.ex>
+References: <E10HmbD-0005vi-00@myhost.test.ex>
Content-Type: multipart/report; report-type=delivery-status; boundary=NNNNNNNNNN-eximdsn-MMMMMMMMMM
MIME-Version: 1.0
Subject: Mail delivery failed: returning message to sender
-Message-Id: <E10HmbC-0005vi-00@myhost.test.ex>
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
--NNNNNNNNNN-eximdsn-MMMMMMMMMM
LOCAL_PART_SUFFIX=
LOGNAME=redking
ME=
-MESSAGE_ID=10HmbB-0005vi-00
+MESSAGE_ID=10HmbD-0005vi-00
PATH=/bin:/usr/bin
QUALIFY_DOMAIN=test.ex
RECIPIENT=redking@test.ex
>From CALLER@test.ex Tue Mar 02 09:44:33 1999
Received: from CALLER by myhost.test.ex with local (Exim x.yz)
(envelope-from <CALLER@test.ex>)
- id 10HmbB-0005vi-00
+ id 10HmbD-0005vi-00
for redking@test.ex;
Tue, 2 Mar 1999 09:44:33 +0000
To: redking@test.ex
-Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
From: CALLER_NAME <CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
Return-path: <CALLER@test.ex>
Received: from CALLER by myhost.test.ex with local (Exim x.yz)
(envelope-from <CALLER@test.ex>)
- id 10HmbB-0005vi-00
+ id 10HmbD-0005vi-00
for redking@test.ex;
Tue, 2 Mar 1999 09:44:33 +0000
To: redking@test.ex
-Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
From: CALLER_NAME <CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
+++ /dev/null
-1999-03-02 09:44:33 Received from CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r2 T=t2 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t2 transport) not permitted
-1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r2 T=t2 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t2 transport) not permitted
+1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r0 T=t0 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t0 transport) not permitted
+1999-03-02 09:44:33 10HmaY-0005vi-00 == |echo rtr_user <rtr_user@test.ex> R=r1 T=t0 defer (0): Tainted 'echo rtr_user' (command for t0 transport) not permitted
rc=$runrc
${if eq{1}{2}{${run{/non/exist}}}{1!=2}}
rc=$runrc
+${run,preexpand {DIR/aux-fixed/0002.runfile 0}}
+rc=$runrc
# PRVS
exim -odi alice
To: alice@test.ex
****
+exim -odi marny
+To: marny@test.ex
+****
exim -odi jabberwocky
To: jabberwocky@test.ex
****
exim -odi pipe-userx=DIR/bin/iefbr14@test.ex
A test message.
****
+#
+exim -odi rtr_user@test.ex
+This one has an ok executable but tainted arg, pipecmd set by router
+****
+exim -odi tpt_user@test.ex
+This one has an ok executable but tainted arg, pipecmd set by transport
+****
+#
+no_msglog_check
direct command:
argv[0] = '/bin/cat'
direct command after expansion:
- argv[0] = /bin/cat
+ argv[0] = '/bin/cat'
appendfile transport entered
appendfile: mode=600 notify_comsat=0 quota=0 warning=0
file=TESTSUITE/test-mail/userx format=unix
direct command:
argv[0] = '${if={1}{1}{}{}}'
direct command after expansion:
- argv[0] =
+ argv[0] = ''
appendfile transport entered
appendfile: mode=600 notify_comsat=0 quota=0 warning=0
file=TESTSUITE/test-mail/userx format=unix
-1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r2 T=t2 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t2 transport) not permitted
+1999-03-02 09:44:33 10HmaX-0005vi-00 == |TESTSUITE/bin/iefbr14 <pipe-userx=TESTSUITE/bin/iefbr14@test.ex> R=r0 T=t0 defer (0): Tainted 'TESTSUITE/bin/iefbr14' (command for t0 transport) not permitted
+1999-03-02 09:44:33 10HmaY-0005vi-00 == |echo rtr_user <rtr_user@test.ex> R=r1 T=t0 defer (0): Tainted 'echo rtr_user' (command for t0 transport) not permitted
> >><<
> rc=0
> 1!=2
+> rc=0
+> abcd
+1234
+
> rc=0
>
> # PRVS