X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Ftransports%2Fpipe.c;h=27422bd4275253faff52eec52ed1039d011d3382;hb=a06afb97d53eb100c7f1b5b00da746d071d52415;hp=a16a197a4cfa571dc4eb7d2ea034bf0cd0aa69b6;hpb=1d717e1c110562fd6bf28478c79f180cafeba776;p=exim.git diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index a16a197a4..27422bd42 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -21,72 +22,50 @@ with "*" are not settable by the user but are used by the option-reading software for alternative value types. Some options are stored in the transport instance block so as to be publicly visible; these are flagged with opt_public. */ +#define LOFF(field) OPT_OFF(pipe_transport_options_block, field) optionlist pipe_transport_options[] = { - { "allow_commands", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, allow_commands) }, + { "allow_commands", opt_stringptr, LOFF(allow_commands) }, { "batch_id", opt_stringptr | opt_public, - (void *)offsetof(transport_instance, batch_id) }, + OPT_OFF(transport_instance, batch_id) }, { "batch_max", opt_int | opt_public, - (void *)offsetof(transport_instance, batch_max) }, - { "check_string", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, check_string) }, - { "command", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, cmd) }, - { "environment", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, environment) }, - { "escape_string", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, escape_string) }, - { "force_command", opt_bool, - (void *)offsetof(pipe_transport_options_block, force_command) }, - { "freeze_exec_fail", opt_bool, - (void *)offsetof(pipe_transport_options_block, freeze_exec_fail) }, - { "freeze_signal", opt_bool, - (void *)offsetof(pipe_transport_options_block, freeze_signal) }, - { "ignore_status", opt_bool, - (void *)offsetof(pipe_transport_options_block, ignore_status) }, + OPT_OFF(transport_instance, batch_max) }, + { "check_string", opt_stringptr, LOFF(check_string) }, + { "command", opt_stringptr, LOFF(cmd) }, + { "environment", opt_stringptr, LOFF(environment) }, + { "escape_string", opt_stringptr, LOFF(escape_string) }, + { "force_command", opt_bool, LOFF(force_command) }, + { "freeze_exec_fail", opt_bool, LOFF(freeze_exec_fail) }, + { "freeze_signal", opt_bool, LOFF(freeze_signal) }, + { "ignore_status", opt_bool, LOFF(ignore_status) }, { "log_defer_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_defer_output) }, + OPT_OFF(transport_instance, log_defer_output) }, { "log_fail_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_fail_output) }, + OPT_OFF(transport_instance, log_fail_output) }, { "log_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_output) }, - { "max_output", opt_mkint, - (void *)offsetof(pipe_transport_options_block, max_output) }, - { "message_prefix", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, message_prefix) }, - { "message_suffix", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, message_suffix) }, - { "path", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, path) }, - { "permit_coredump", opt_bool, - (void *)offsetof(pipe_transport_options_block, permit_coredump) }, + OPT_OFF(transport_instance, log_output) }, + { "max_output", opt_mkint, LOFF(max_output) }, + { "message_prefix", opt_stringptr, LOFF(message_prefix) }, + { "message_suffix", opt_stringptr, LOFF(message_suffix) }, + { "path", opt_stringptr, LOFF(path) }, + { "permit_coredump", opt_bool, LOFF(permit_coredump) }, { "pipe_as_creator", opt_bool | opt_public, - (void *)offsetof(transport_instance, deliver_as_creator) }, - { "restrict_to_path", opt_bool, - (void *)offsetof(pipe_transport_options_block, restrict_to_path) }, + OPT_OFF(transport_instance, deliver_as_creator) }, + { "restrict_to_path", opt_bool, LOFF(restrict_to_path) }, { "return_fail_output",opt_bool | opt_public, - (void *)offsetof(transport_instance, return_fail_output) }, + OPT_OFF(transport_instance, return_fail_output) }, { "return_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, return_output) }, - { "temp_errors", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, temp_errors) }, - { "timeout", opt_time, - (void *)offsetof(pipe_transport_options_block, timeout) }, - { "timeout_defer", opt_bool, - (void *)offsetof(pipe_transport_options_block, timeout_defer) }, - { "umask", opt_octint, - (void *)offsetof(pipe_transport_options_block, umask) }, - { "use_bsmtp", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_bsmtp) }, + OPT_OFF(transport_instance, return_output) }, + { "temp_errors", opt_stringptr, LOFF(temp_errors) }, + { "timeout", opt_time, LOFF(timeout) }, + { "timeout_defer", opt_bool, LOFF(timeout_defer) }, + { "umask", opt_octint, LOFF(umask) }, + { "use_bsmtp", opt_bool, LOFF(use_bsmtp) }, #ifdef HAVE_SETCLASSRESOURCES - { "use_classresources", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_classresources) }, + { "use_classresources", opt_bool, LOFF(use_classresources) }, #endif - { "use_crlf", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_crlf) }, - { "use_shell", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_shell) }, + { "use_crlf", opt_bool, LOFF(use_crlf) }, + { "use_shell", opt_bool, LOFF(use_shell) }, }; /* Size of the options list. An extern variable has to be used so that its @@ -586,7 +565,6 @@ symbol. In other cases, the command is supplied as one of the pipe transport's options. */ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') - { if (ob->force_command) { /* Enables expansion of $address_pipe into separate arguments */ @@ -602,7 +580,6 @@ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') expand_arguments = testflag(addr, af_expand_pipe); expand_fail = FAIL; } - } else { cmd = ob->cmd; @@ -615,13 +592,20 @@ else * coming from addr->local_part[0] == '|' */ -if (cmd == NULL || *cmd == '\0') +if (!cmd || !*cmd) { addr->transport_return = DEFER; addr->message = string_sprintf("no command specified for %s transport", tblock->name); return FALSE; } +if (is_tainted(cmd)) + { + addr->message = string_sprintf("Tainted '%s' (command " + "for %s transport) not permitted", cmd, tblock->name); + addr->transport_return = PANIC; + 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 @@ -631,8 +615,8 @@ if (expand_arguments && addr->pipe_expandn) { uschar **ss = addr->pipe_expandn; expand_nmax = -1; - if (*ss != NULL) filter_thisaddress = *ss++; - while (*ss != NULL) + if (*ss) filter_thisaddress = *ss++; + while (*ss) { expand_nstring[++expand_nmax] = *ss; expand_nlength[expand_nmax] = Ustrlen(*ss++); @@ -685,7 +669,6 @@ else if (timezone_string != NULL && timezone_string[0] != 0) /* Add any requested items */ if (envlist) - { if (!(envlist = expand_cstring(envlist))) { addr->transport_return = DEFER; @@ -694,9 +677,8 @@ if (envlist) expand_string_message); return FALSE; } - } -while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size))) +while ((ss = string_nextinlist(&envlist, &envsep, NULL, 0))) { if (envcount > nelem(envp) - 2) { @@ -743,7 +725,8 @@ reading of the output pipe. */ uid/gid and current directory. Request that the new process be a process group leader, so we can kill it and all its children on a timeout. */ -if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0) +if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE, + US"pipe-tpt-cmd")) < 0) { addr->transport_return = DEFER; addr->message = string_sprintf( @@ -755,7 +738,7 @@ tctx.u.fd = fd_in; /* Now fork a process to handle the output that comes down the pipe. */ -if ((outpid = fork()) < 0) +if ((outpid = exim_fork(US"pipe-tpt-output")) < 0) { addr->basic_errno = errno; addr->transport_return = DEFER; @@ -831,10 +814,10 @@ transport_count = 0; /* First write any configured prefix information */ -if (ob->message_prefix != NULL) +if (ob->message_prefix) { uschar *prefix = expand_string(ob->message_prefix); - if (prefix == NULL) + if (!prefix) { addr->transport_return = f.search_find_defer? DEFER : PANIC; addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s " @@ -951,8 +934,8 @@ above timed out. */ if ((rc = child_close(pid, timeout)) != 0) { - uschar *tmsg = (addr->message == NULL)? US"" : - string_sprintf(" (preceded by %s)", addr->message); + uschar * tmsg = addr->message + ? string_sprintf(" (preceded by %s)", addr->message) : US""; /* The process did not complete in time; kill its process group and fail the delivery. It appears to be necessary to kill the output process too, as @@ -1058,7 +1041,7 @@ if ((rc = child_close(pid, timeout)) != 0) { /* Always handle execve() failure specially if requested to */ - if (ob->freeze_exec_fail && (rc == EX_EXECFAILED)) + if (ob->freeze_exec_fail && rc == EX_EXECFAILED) { addr->transport_return = DEFER; addr->special_action = SPECIAL_FREEZE; @@ -1106,7 +1089,7 @@ if ((rc = child_close(pid, timeout)) != 0) rc-128, os_strsignal(rc-128)) : US os_strexit(rc); - if (*ss != 0) + if (*ss) { g = string_catn(g, US" ", 1); g = string_cat (g, ss);