* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim maintainers 2020 - 2022 */
+/* Copyright (c) The Exim maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* 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
/* Dummy values */
pipe_transport_options_block pipe_transport_option_defaults = {0};
-void pipe_transport_init(transport_instance *tblock) {}
+void pipe_transport_init(driver_instance *tblock) {}
BOOL pipe_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
#else /*!MACRO_PREDEF*/
pipe_transport_setup(transport_instance *tblock, address_item *addrlist,
transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg)
{
-pipe_transport_options_block *ob =
- (pipe_transport_options_block *)(tblock->options_block);
+pipe_transport_options_block * ob = tblock->drinst.options_block;
#ifdef HAVE_SETCLASSRESOURCES
if (ob->use_classresources)
to be set up. */
void
-pipe_transport_init(transport_instance *tblock)
+pipe_transport_init(driver_instance * t)
{
-pipe_transport_options_block *ob =
- (pipe_transport_options_block *)(tblock->options_block);
+transport_instance * tblock = (transport_instance *)t;
+const uschar * trname = t->name;
+pipe_transport_options_block * ob = t->options_block;
/* Set up the setup entry point, to be called in the privileged state */
tblock->expand_uid != NULL || tblock->expand_gid != NULL))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"both pipe_as_creator and an explicit uid/gid are set for the %s "
- "transport", tblock->name);
+ "transport", trname);
/* If a fixed uid field is set, then a gid field must also be set. */
if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "user set without group for the %s transport", tblock->name);
+ "user set without group for the %s transport", trname);
/* Temp_errors must consist only of digits and colons, but there can be
spaces round the colons, so allow them too. */
if (ob->temp_errors[p] != 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"temp_errors must be a list of numbers or an asterisk for the %s "
- "transport", tblock->name);
+ "transport", trname);
}
/* Only one of return_output/return_fail_output or log_output/log_fail_output
if (tblock->return_output && tblock->return_fail_output)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"both return_output and return_fail_output set for %s transport",
- tblock->name);
+ trname);
if (tblock->log_output && tblock->log_fail_output)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"both log_output and log_fail_output set for the %s transport",
- tblock->name);
+ trname);
/* If batch SMTP is set, force the check and escape strings, and arrange that
headers are also escaped. */
if (ob->restrict_to_path && ob->use_shell)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"both restrict_to_path and use_shell set for %s transport",
- tblock->name);
+ trname);
/* The allow_commands and use_shell options are incompatible */
if (ob->allow_commands && ob->use_shell)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"both allow_commands and use_shell set for %s transport",
- tblock->name);
+ trname);
/* Set up the bitwise options for transport_write_message from the various
driver options. Only one of body_only and headers_only can be set. */
*/
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,
+ const uschar * tname, pipe_transport_options_block * ob)
{
BOOL permitted = FALSE;
const uschar **argv;
/* 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,
+ const uschar * tname)
{
const uschar **argv;
}
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;
transport_instance *tblock, /* data for this instantiation */
address_item *addr) /* address(es) we are working on */
{
+pipe_transport_options_block * ob = tblock->drinst.options_block;
+const uschar * trname = tblock->drinst.name;
pid_t pid, outpid;
int fd_in, fd_out, rc;
-int envcount = 0;
-int envsep = 0;
-int expand_fail;
-pipe_transport_options_block *ob =
- (pipe_transport_options_block *)(tblock->options_block);
-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";
+int envcount = 0, envsep = 0, expand_fail, timeout = ob->timeout;
+BOOL written_ok = FALSE, expand_arguments;
+const uschar ** argv;
+uschar * envp[50];
+const uschar * envlist = ob->environment, * cmd;
+uschar * ss;
+uschar * eol = ob->use_crlf ? US"\r\n" : US"\n";
transport_ctx tctx = {
.tblock = tblock,
.addr = addr,
ob->options | topt_not_socket /* set at initialization time */
};
-DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name);
+DEBUG(D_transport) debug_printf("%s transport entered\n", trname);
/* Set up for the good case */
{
/* 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;
{
addr->transport_return = DEFER;
addr->message = string_sprintf("no command specified for %s transport",
- tblock->name);
+ trname);
return FALSE;
}
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);
+ "for %s transport) not permitted", cmd, trname);
addr->transport_return = PANIC;
return FALSE;
}
if (ob->use_shell)
{
if (!set_up_shell_command(&argv, cmd, expand_arguments, expand_fail, addr,
- tblock->name)) return FALSE;
+ trname)) return FALSE;
}
else if (!set_up_direct_command(&argv, cmd, expand_arguments, expand_fail, addr,
- tblock->name, ob)) return FALSE;
+ trname, ob)) return FALSE;
expand_nmax = -1; /* Reset */
filter_thisaddress = NULL;
/* Add any requested items */
+GET_OPTION("environment");
if (envlist)
if (!(envlist = expand_cstring(envlist)))
{
addr->transport_return = DEFER;
addr->message = string_sprintf("failed to expand string \"%s\" "
- "for %s transport: %s", ob->environment, tblock->name,
+ "for %s transport: %s", ob->environment, trname,
expand_string_message);
return FALSE;
}
addr->transport_return = DEFER;
addr->basic_errno = E2BIG;
addr->message = string_sprintf("too many environment settings for "
- "%s transport", tblock->name);
+ "%s transport", trname);
return FALSE;
}
envp[envcount++] = string_copy(ss);
{
DEBUG(D_transport)
debug_printf("*** delivery by %s transport bypassed by -N option",
- tblock->name);
+ trname);
return FALSE;
}
{
addr->transport_return = DEFER;
addr->message = string_sprintf(
- "Failed to create child process for %s transport: %s", tblock->name,
+ "Failed to create child process for %s transport: %s", trname,
strerror(errno));
return FALSE;
}
addr->transport_return = DEFER;
addr->message = string_sprintf(
"Failed to create process for handling output in %s transport",
- tblock->name);
+ trname);
(void)close(fd_in);
(void)close(fd_out);
return FALSE;
/* 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;
addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
- "transport) failed: %s", ob->message_prefix, tblock->name,
+ "transport) failed: %s", ob->message_prefix, trname,
expand_string_message);
return FALSE;
}
/* 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;
addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
- "transport) failed: %s", ob->message_suffix, tblock->name,
+ "transport) failed: %s", ob->message_suffix, trname,
expand_string_message);
return FALSE;
}
{
addr->transport_return = PANIC;
addr->message = string_sprintf("Wait() failed for child process of %s "
- "transport: %s%s", tblock->name, strerror(errno), tmsg);
+ "transport: %s%s", trname, strerror(errno), tmsg);
}
/* Since the transport_filter timed out we assume it has sent the child process
addr->transport_return = DEFER;
addr->special_action = SPECIAL_FREEZE;
addr->message = string_sprintf("Child process of %s transport (running "
- "command \"%s\") was terminated by signal %d (%s)%s", tblock->name, cmd,
+ "command \"%s\") was terminated by signal %d (%s)%s", trname, cmd,
-rc, os_strsignal(-rc), tmsg);
}
else if (!ob->ignore_status)
{
addr->transport_return = FAIL;
addr->message = string_sprintf("Child process of %s transport (running "
- "command \"%s\") was terminated by signal %d (%s)%s", tblock->name, cmd,
+ "command \"%s\") was terminated by signal %d (%s)%s", trname, cmd,
-rc, os_strsignal(-rc), tmsg);
}
}
doesn't have to be brilliantly efficient - it is an error situation. */
addr->message = string_sprintf("Child process of %s transport returned "
- "%d", tblock->name, rc);
+ "%d", trname, rc);
g = string_cat(NULL, addr->message);
/* If the return code is > 128, it often means that a shell command
while (wait(&rc) >= 0);
-DEBUG(D_transport) debug_printf("%s transport yielded %d\n", tblock->name,
+DEBUG(D_transport) debug_printf("%s transport yielded %d\n", trname,
addr->transport_return);
/* If there has been a problem, the message in addr->message contains details
return FALSE;
}
+
+
+
+# ifdef DYNLOOKUP
+# define pipe_transport_info _transport_info
+# endif
+
+transport_info pipe_transport_info = {
+.drinfo = {
+ .driver_name = US"pipe",
+ .options = pipe_transport_options,
+ .options_count = &pipe_transport_options_count,
+ .options_block = &pipe_transport_option_defaults,
+ .options_len = sizeof(pipe_transport_options_block),
+ .init = pipe_transport_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = TRANSPORT_MAGIC,
+# endif
+ },
+.code = pipe_transport_entry,
+.tidyup = NULL,
+.closedown = NULL,
+.local = TRUE
+};
+
#endif /*!MACRO_PREDEF*/
+#endif /*TRASPORT_PIPE*/
/* End of transport/pipe.c */