* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim maintainers 2020 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "../exim.h"
+
+#ifdef TRANSPORT_PIPE /* Remainder of file */
#include "pipe.h"
#ifdef HAVE_SETCLASSRESOURCES
/* Default private options block for the pipe transport. */
pipe_transport_options_block pipe_transport_option_defaults = {
- NULL, /* cmd */
- NULL, /* allow_commands */
- NULL, /* environment */
- US"/bin:/usr/bin", /* path */
- NULL, /* message_prefix (reset in init if not bsmtp) */
- NULL, /* message_suffix (ditto) */
- US mac_expanded_string(EX_TEMPFAIL) ":" /* temp_errors */
- mac_expanded_string(EX_CANTCREAT),
- NULL, /* check_string */
- NULL, /* escape_string */
- 022, /* umask */
- 20480, /* max_output */
- 60*60, /* timeout */
- 0, /* options */
- FALSE, /* force_command */
- FALSE, /* freeze_exec_fail */
- FALSE, /* freeze_signal */
- FALSE, /* ignore_status */
- FALSE, /* permit_coredump */
- FALSE, /* restrict_to_path */
- FALSE, /* timeout_defer */
- FALSE, /* use_shell */
- FALSE, /* use_bsmtp */
- FALSE, /* use_classresources */
- FALSE /* use_crlf */
+ .path = US"/bin:/usr/bin",
+ .temp_errors = US mac_expanded_string(EX_TEMPFAIL) ":"
+ mac_expanded_string(EX_CANTCREAT),
+ .umask = 022,
+ .max_output = 20480,
+ .timeout = 60*60,
+ /* all others null/zero/false */
};
driver options. Only one of body_only and headers_only can be set. */
ob->options |=
- (tblock->body_only? topt_no_headers : 0) |
- (tblock->headers_only? topt_no_body : 0) |
- (tblock->return_path_add? topt_add_return_path : 0) |
- (tblock->delivery_date_add? topt_add_delivery_date : 0) |
- (tblock->envelope_to_add? topt_add_envelope_to : 0) |
- (ob->use_crlf? topt_use_crlf : 0);
+ (tblock->body_only ? topt_no_headers : 0)
+ | (tblock->headers_only ? topt_no_body : 0)
+ | (tblock->return_path_add ? topt_add_return_path : 0)
+ | (tblock->delivery_date_add ? topt_add_delivery_date : 0)
+ | (tblock->envelope_to_add ? topt_add_envelope_to : 0)
+ | (ob->use_crlf ? topt_use_crlf : 0);
}
*/
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, const 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, 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. */
/* If allow_commands is set, see if the command is in the permitted list. */
+GET_OPTION("allow_commands");
if (ob->allow_commands)
{
int sep = 0;
if (argv[0][0] != '/')
{
int sep = 0;
- uschar *p;
- const uschar *listptr = expand_string(ob->path);
+ uschar * p;
- while ((p = string_nextinlist(&listptr, &sep, NULL, 0)))
+ GET_OPTION("path");
+ for (const uschar * listptr = expand_string(ob->path);
+ p = string_nextinlist(&listptr, &sep, NULL, 0); )
{
struct stat statbuf;
sprintf(CS big_buffer, "%.256s/%.256s", p, argv[0]);
*/
static BOOL
-set_up_shell_command(const uschar ***argvptr, uschar *cmd,
- BOOL expand_arguments, int expand_fail, address_item *addr, uschar *tname)
+set_up_shell_command(const uschar *** argvptr, const uschar * cmd,
+ BOOL expand_arguments, int expand_fail, address_item * addr, uschar * tname)
{
const uschar **argv;
-*argvptr = argv = store_get((4)*sizeof(uschar *), FALSE);
+*argvptr = argv = store_get((4)*sizeof(uschar *), GET_UNTAINTED);
argv[0] = US"/bin/sh";
argv[1] = US"-c";
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);
}
g = string_cat(g, q);
- argv[2] = (cmd = string_from_gstring(g)) ? expand_string(cmd) : NULL;
+ argv[2] = (cmd = string_from_gstring(g)) ? expand_cstring(cmd) : NULL;
}
else
- argv[2] = expand_string(cmd);
+ argv[2] = expand_cstring(cmd);
f.enable_dollar_recipients = FALSE;
int timeout = ob->timeout;
BOOL written_ok = FALSE;
BOOL expand_arguments;
-const uschar **argv;
-uschar *envp[50];
-const uschar *envlist = ob->environment;
-uschar *cmd, *ss;
-uschar *eol = ob->use_crlf ? US"\r\n" : US"\n";
+const uschar ** argv;
+uschar * envp[50];
+const uschar * envlist = ob->environment;
+const uschar * cmd;
+uschar * ss;
+uschar * eol = ob->use_crlf ? US"\r\n" : US"\n";
transport_ctx tctx = {
.tblock = tblock,
.addr = addr,
{
/* Enables expansion of $address_pipe into separate arguments */
setflag(addr, af_force_command);
+ GET_OPTION("commsnd");
cmd = ob->cmd;
expand_arguments = TRUE;
expand_fail = PANIC;
else
{
cmd = addr->local_part + 1;
- while (isspace(*cmd)) cmd++;
+ Uskip_whitespace(&cmd);
expand_arguments = testflag(addr, af_expand_pipe);
expand_fail = FAIL;
}
else
{
+ GET_OPTION("commsnd");
cmd = ob->cmd;
expand_arguments = TRUE;
expand_fail = PANIC;
}
/* If no command has been supplied, we are in trouble.
- * We also check for an empty string since it may be
- * coming from addr->local_part[0] == '|'
- */
+We also check for an empty string since it may be
+coming from addr->local_part[0] == '|' */
if (!cmd || !*cmd)
{
tblock->name);
return FALSE;
}
-
-{ uschar *m;
-if ((m = is_tainted2(cmd, 0, "Tainted '%s' (command "
- "for %s transport) not permitted", cmd, tblock->name)))
+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;
- addr->message = m;
return FALSE;
}
-}
/* When a pipe is set up by a filter file, there may be values for $thisaddress
and numerical the variables in existence. These are passed in
envp[envcount++] = string_sprintf("SENDER=%s", sender_address);
envp[envcount++] = US"SHELL=/bin/sh";
-if (addr->host_list != NULL)
+if (addr->host_list)
envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name);
-if (f.timestamps_utc) envp[envcount++] = US"TZ=UTC";
-else if (timezone_string != NULL && timezone_string[0] != 0)
+if (f.timestamps_utc)
+ envp[envcount++] = US"TZ=UTC";
+else if (timezone_string && timezone_string[0])
envp[envcount++] = string_sprintf("TZ=%s", timezone_string);
/* Add any requested items */
+GET_OPTION("environment");
if (envlist)
if (!(envlist = expand_cstring(envlist)))
{
/* First write any configured prefix information */
+GET_OPTION("message_prefix");
if (ob->message_prefix)
{
- uschar *prefix = expand_string(ob->message_prefix);
+ uschar * prefix = expand_string(ob->message_prefix);
if (!prefix)
{
addr->transport_return = f.search_find_defer? DEFER : PANIC;
/* Now any configured suffix */
+GET_OPTION("message_suffix");
if (ob->message_suffix)
{
- uschar *suffix = expand_string(ob->message_suffix);
+ uschar * suffix = expand_string(ob->message_suffix);
if (!suffix)
{
addr->transport_return = f.search_find_defer? DEFER : PANIC;
}
#endif /*!MACRO_PREDEF*/
+#endif /*TRASPORT_PIPE*/
/* End of transport/pipe.c */