JH/33 Fix free for live variable $value created by a ${run ...} expansion.
Although not seen, this could have resulted in a SIGSEGV.
+JH/34 Bug 3013: Fix use of $recipients within arguments for ${run...}.
+ In 4.96 this would expand to empty.
+
Exim version 4.96
-----------------
{
ok = transport_set_up_command(&transport_filter_argv,
tp->filter_command,
- TRUE, PANIC, addr, FALSE, US"transport filter", NULL);
+ TSUC_EXPAND_ARGS, PANIC, addr, 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;
+ unsigned late_expand = TSUC_EXPAND_ARGS | TSUC_ALLOW_TAINTED_ARGS | TSUC_ALLOW_RECIPIENTS;
uschar * save_value = lookup_value;
int yesno;
while (*s == ',')
if (Ustrncmp(++s, "preexpand", 9) == 0)
- { late_expand = FALSE; s += 9; }
+ { late_expand = 0; s += 9; }
else
{
const uschar * t = s;
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;
);
extern uschar *transport_rcpt_address(address_item *, BOOL);
extern BOOL transport_set_up_command(const uschar ***, const uschar *,
- BOOL, int, address_item *, BOOL, const uschar *, uschar **);
+ unsigned, int, address_item *, 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);
#define QL_MSGID_ONLY 3
#define QL_UNSORTED 8
+/* Flags for transport_set_up_command() */
+#define TSUC_EXPAND_ARGS BIT(0)
+#define TSUC_ALLOW_TAINTED_ARGS BIT(1)
+#define TSUC_ALLOW_RECIPIENTS BIT(2)
+
/* End of macros.h */
if (!transport_set_up_command(&argvptr, /* anchor for arg list */
ob->command, /* raw command */
- TRUE, /* expand the arguments */
+ TSUC_EXPAND_ARGS, /* arguments expanded but must not be tainted */
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;
BOOL rc;
etrn_command = smtp_etrn_command;
deliver_domain = smtp_cmd_data;
- rc = transport_set_up_command(&argv, smtp_etrn_command, TRUE, 0, NULL,
- FALSE, US"ETRN processing", &error);
+ rc = transport_set_up_command(&argv, smtp_etrn_command, TSUC_EXPAND_ARGS, 0, NULL,
+ US"ETRN processing", &error);
deliver_domain = NULL;
if (!rc)
{
/* This function is called when a command line is to be parsed and executed
directly, without the use of /bin/sh. It is called by the pipe transport,
-the queryprogram router, and also from the main delivery code when setting up a
+the queryprogram router, for any ${run } expansion,
+and also from the main delivery code when setting up a
transport filter process. The code for ETRN also makes use of this; in that
case, no addresses are passed.
Arguments:
argvptr pointer to anchor for argv vector
cmd points to the command string (modified IN PLACE)
- expand_arguments true if expansion is to occur
+ flags bits for expand-args, allow taint, allow $recipients
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,
- BOOL allow_tainted_args, const uschar * etext, uschar ** errptr)
+ unsigned flags, int expand_failed, address_item * addr,
+ const uschar * etext, uschar ** errptr)
{
const uschar ** argv, * s;
int address_count = 0, argcount = 0, max_args;
debug_printf(" argv[%d] = '%s'\n", i, string_printing(argv[i]));
}
-if (expand_arguments)
+if (flags & TSUC_EXPAND_ARGS)
{
- BOOL allow_dollar_recipients = addr && addr->parent
- && Ustrcmp(addr->parent->address, "system-filter") == 0;
+ BOOL allow_dollar_recipients = (flags & TSUC_ALLOW_RECIPIENTS)
+ || (addr && addr->parent && Ustrcmp(addr->parent->address, "system-filter") == 0); /*XXX could we check this at caller? */
for (int i = 0; argv[i]; i++)
{
debug_printf("SPECIFIC TESTSUITE EXEMPTION: tainted arg '%s'\n",
expanded_arg);
}
- else if ( !allow_tainted_args
+ else if ( !(flags & TSUC_ALLOW_TAINTED_ARGS)
&& arg_is_tainted(expanded_arg, i, addr, etext, errptr))
return FALSE;
argv[i] = expanded_arg;
{
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, FALSE,
- buffer, NULL))
+ if (!transport_set_up_command(&argv, ob->cmd, TSUC_EXPAND_ARGS, PANIC,
+ addrlist, buffer, NULL))
return FALSE;
/* If the -N option is set, can't do any more. Presume all has gone well. */
*/
static BOOL
-set_up_direct_command(const uschar ***argvptr, uschar *cmd,
- BOOL expand_arguments, int expand_fail, address_item *addr, uschar *tname,
- pipe_transport_options_block *ob)
+set_up_direct_command(const uschar *** argvptr, uschar * cmd,
+ BOOL expand_arguments, int expand_fail, address_item * addr, uschar * tname,
+ pipe_transport_options_block * ob)
{
BOOL permitted = FALSE;
const uschar **argv;
the items if necessary. If it fails, this function fails (error information
is in the addresses). */
-if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail,
- addr, FALSE, string_sprintf("%.50s transport", tname), NULL))
+if (!transport_set_up_command(argvptr, cmd,
+ expand_arguments ? TSUC_EXPAND_ARGS : 0,
+ expand_fail, addr, string_sprintf("%.50s transport", tname), NULL))
return FALSE;
/* Point to the set-up arguments. */
yield ERROR. */
if (!transport_set_up_command(&transport_filter_argv,
- tblock->filter_command, TRUE, DEFER, addrlist, FALSE,
+ tblock->filter_command, TSUC_EXPAND_ARGS, DEFER, addrlist,
string_sprintf("%.50s transport filter", tblock->name), NULL))
{
set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
1999-03-02 09:44:33 10HmaX-000000005vi-0000 $recipients: "CALLER@the.local.host.name"
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 run-wrapped $recipients: "\n"
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 run-wrapped $recipients: "CALLER@the.local.host.name\n"
1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= someone@some.domain U=CALLER P=local-smtp S=sss
1999-03-02 09:44:33 10HmaX-000000005vi-0000 => CALLER <CALLER@the.local.host.name> R=localuser T=local_delivery
1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed