* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
/* See the file NOTICE for conditions of use and distribution. */
(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,
20480, /* max_output */
60*60, /* timeout */
0, /* options */
+ FALSE, /* force_command */
FALSE, /* freeze_exec_fail */
FALSE, /* freeze_signal */
FALSE, /* ignore_status */
if (errno != ENOSYS && errno != ENOTSUP)
#endif
log_write(0, LOG_MAIN,
- "delivery setrlimit(RLIMIT_CORE, RLIMI_INFINITY) failed: %s",
+ "delivery setrlimit(RLIMIT_CORE, RLIM_INFINITY) failed: %s",
strerror(errno));
}
}
*/
static BOOL
-set_up_direct_command(uschar ***argvptr, uschar *cmd, BOOL expand_arguments,
- int expand_fail, address_item *addr, uschar *tname,
+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;
-uschar **argv;
+const uschar **argv;
uschar buffer[64];
/* Set up "transport <name>" to be put in any error messages, and then
if (ob->allow_commands != NULL)
{
int sep = 0;
- uschar *s, *p;
+ const uschar *s;
+ uschar *p;
uschar buffer[256];
- s = expand_string(ob->allow_commands);
- if (s == NULL)
+ if (!(s = expand_string(ob->allow_commands)))
{
addr->transport_return = DEFER;
addr->message = string_sprintf("failed to expand string \"%s\" "
return FALSE;
}
- while ((p = string_nextinlist(&s, &sep, buffer, sizeof(buffer))) != NULL)
- {
+ while ((p = string_nextinlist(&s, &sep, buffer, sizeof(buffer))))
if (Ustrcmp(p, argv[0]) == 0) { permitted = TRUE; break; }
- }
}
/* If permitted is TRUE it means the command was found in the allowed list, and
{
int sep = 0;
uschar *p;
- uschar *listptr = ob->path;
+ const uschar *listptr = ob->path;
uschar buffer[1024];
while ((p = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))) != NULL)
*/
static BOOL
-set_up_shell_command(uschar ***argvptr, uschar *cmd, BOOL expand_arguments,
- int expand_fail, address_item *addr, uschar *tname)
+set_up_shell_command(const uschar ***argvptr, uschar *cmd,
+ BOOL expand_arguments, int expand_fail, address_item *addr, uschar *tname)
{
-uschar **argv;
+const uschar **argv;
*argvptr = argv = store_get((4)*sizeof(uschar *));
for (ad = addr; ad != NULL; ad = ad->next)
{
- if (ad != addr) string_cat(s, &size, &offset, US" ", 1);
- string_cat(s, &size, &offset, ad->address, Ustrlen(ad->address));
+ /*XXX string_append_listele() ? */
+ if (ad != addr) s = string_catn(s, &size, &offset, US" ", 1);
+ s = string_cat(s, &size, &offset, ad->address);
}
- string_cat(s, &size, &offset, q, Ustrlen(q));
+ s = string_cat(s, &size, &offset, q);
s[offset] = 0;
}
int timeout = ob->timeout;
BOOL written_ok = FALSE;
BOOL expand_arguments;
-uschar **argv;
+const uschar **argv;
uschar *envp[50];
-uschar *envlist = ob->environment;
+const uschar *envlist = ob->environment;
uschar *cmd, *ss;
uschar *eol = (ob->use_crlf)? US"\r\n" : US"\n";
if (testflag(addr, af_pfr) && addr->local_part[0] == '|')
{
- cmd = addr->local_part + 1;
- while (isspace(*cmd)) cmd++;
- expand_arguments = testflag(addr, af_expand_pipe);
- expand_fail = FAIL;
+ if (ob->force_command)
+ {
+ /* Enables expansion of $address_pipe into seperate arguments */
+ setflag(addr, af_force_command);
+ cmd = ob->cmd;
+ expand_arguments = TRUE;
+ expand_fail = PANIC;
+ }
+ else
+ {
+ cmd = addr->local_part + 1;
+ while (isspace(*cmd)) cmd++;
+ expand_arguments = testflag(addr, af_expand_pipe);
+ expand_fail = FAIL;
+ }
}
else
{
expand_fail = PANIC;
}
-/* If no command has been supplied, we are in trouble. */
+/* 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] == '|'
+ */
-if (cmd == NULL)
+if (cmd == NULL || *cmd == '\0')
{
addr->transport_return = DEFER;
addr->message = string_sprintf("no command specified for %s transport",
/* Add any requested items */
-if (envlist != NULL)
+if (envlist)
{
- envlist = expand_string(envlist);
+ envlist = expand_cstring(envlist);
if (envlist == NULL)
{
addr->transport_return = DEFER;
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(argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0)
+if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0)
{
addr->transport_return = DEFER;
addr->message = string_sprintf(
while ((rc = read(fd_out, big_buffer, big_buffer_size)) > 0)
{
if (addr->return_file >= 0)
- write(addr->return_file, big_buffer, rc);
+ if(write(addr->return_file, big_buffer, rc) != rc)
+ DEBUG(D_transport) debug_printf("Problem writing to return_file\n");
count += rc;
if (count > ob->max_output)
{
- uschar *message = US"\n\n*** Too much output - remainder discarded ***\n";
DEBUG(D_transport) debug_printf("Too much output from pipe - killed\n");
if (addr->return_file >= 0)
- write(addr->return_file, message, Ustrlen(message));
+ {
+ uschar *message = US"\n\n*** Too much output - remainder discarded ***\n";
+ rc = Ustrlen(message);
+ if(write(addr->return_file, message, rc) != rc)
+ DEBUG(D_transport) debug_printf("Problem writing to return_file\n");
+ }
killpg(pid, SIGKILL);
break;
}
else
{
- uschar *s = ob->temp_errors;
+ const uschar *s = ob->temp_errors;
uschar *p;
uschar buffer[64];
int sep = 0;
addr->transport_return = FAIL;
- while ((p = string_nextinlist(&s,&sep,buffer,sizeof(buffer))) != NULL)
- {
+ while ((p = string_nextinlist(&s,&sep,buffer,sizeof(buffer))))
if (rc == Uatoi(p)) { addr->transport_return = DEFER; break; }
- }
}
/* Ensure the message contains the expanded command and arguments. This
if (*ss != 0)
{
- addr->message = string_cat(addr->message, &size, &ptr, US" ", 1);
- addr->message = string_cat(addr->message, &size, &ptr,
- ss, Ustrlen(ss));
+ addr->message = string_catn(addr->message, &size, &ptr, US" ", 1);
+ addr->message = string_cat (addr->message, &size, &ptr, ss);
}
/* Now add the command and arguments */
- addr->message = string_cat(addr->message, &size, &ptr,
+ addr->message = string_catn(addr->message, &size, &ptr,
US" from command:", 14);
for (i = 0; i < sizeof(argv)/sizeof(int *) && argv[i] != NULL; i++)
{
BOOL quote = FALSE;
- addr->message = string_cat(addr->message, &size, &ptr, US" ", 1);
+ addr->message = string_catn(addr->message, &size, &ptr, US" ", 1);
if (Ustrpbrk(argv[i], " \t") != NULL)
{
quote = TRUE;
- addr->message = string_cat(addr->message, &size, &ptr, US"\"", 1);
+ addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1);
}
- addr->message = string_cat(addr->message, &size, &ptr, argv[i],
- Ustrlen(argv[i]));
+ addr->message = string_cat(addr->message, &size, &ptr, argv[i]);
if (quote)
- addr->message = string_cat(addr->message, &size, &ptr, US"\"", 1);
+ addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1);
}
/* Add previous filter timeout message, if present. */
- if (*tmsg != 0)
- addr->message = string_cat(addr->message, &size, &ptr, tmsg,
- Ustrlen(tmsg));
+ if (*tmsg)
+ addr->message = string_cat(addr->message, &size, &ptr, tmsg);
addr->message[ptr] = 0; /* Ensure concatenated string terminated */
}