-/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.2 2005/01/04 10:00:44 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
int queryprogram_router_options_count =
sizeof(queryprogram_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+queryprogram_router_options_block queryprogram_router_option_defaults = {0};
+void queryprogram_router_init(router_instance *rblock) {}
+int queryprogram_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the queryprogram router. */
queryprogram_router_options_block queryprogram_router_option_defaults = {
{
while (generated != NULL)
{
+ BOOL ignore_error = addr->prop.ignore_error;
address_item *next = generated;
+
generated = next->next;
next->parent = addr;
- orflag(next, addr, af_propagate);
- next->p = *addr_prop;
+ next->prop = *addr_prop;
+ next->prop.ignore_error = next->prop.ignore_error || ignore_error;
next->start_router = rblock->redirect_router;
next->next = *addr_new;
*addr_new = next;
+ if (addr->child_count == USHRT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
+ "child addresses for <%s>", rblock->name, USHRT_MAX, addr->address);
addr->child_count++;
DEBUG(D_route)
router_instance *rblock, /* data for this instantiation */
address_item *addr, /* address we are working on */
struct passwd *pw, /* passwd entry after check_local_user */
- BOOL verify, /* TRUE when verifying */
+ int verify, /* v_none/v_recipient/v_sender/v_expn */
address_item **addr_local, /* add it to this if it's local */
address_item **addr_remote, /* add it to this if it's remote */
address_item **addr_new, /* put new addresses on here */
pid_t pid;
struct passwd *upw = NULL;
uschar buffer[1024];
-uschar **argvptr;
+const uschar **argvptr;
uschar *rword, *rdata, *s;
address_item_propagated addr_prop;
queryprogram_router_options_block *ob =
(queryprogram_router_options_block *)(rblock->options_block);
uschar *current_directory = ob->current_directory;
ugid_block ugid;
+uid_t curr_uid = getuid();
+gid_t curr_gid = getgid();
uid_t uid = ob->cmd_uid;
gid_t gid = ob->cmd_gid;
+uid_t *puid = &uid;
+gid_t *pgid = &gid;
DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
rblock->name, addr->address, addr->domain);
/* Set up the propagated data block with the current address_data and the
errors address and extra header stuff. */
+bzero(&addr_prop, sizeof(addr_prop));
addr_prop.address_data = deliver_address_data;
-rc = rf_get_errors_address(addr, rblock, verify, &(addr_prop.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr_prop.errors_address);
if (rc != OK) return rc;
-rc = rf_get_munge_headers(addr, rblock, &(addr_prop.extra_headers),
- &(addr_prop.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr_prop.extra_headers,
+ &addr_prop.remove_headers);
if (rc != OK) return rc;
+#ifdef EXPERIMENTAL_SRS
+addr_prop.srs_sender = NULL;
+#endif
+
/* Get the fixed or expanded uid under which the command is to run
(initialization ensures that one or the other is set). */
}
}
-DEBUG(D_route) debug_printf("uid=%ld gid=%ld current_directory=%s\n",
+DEBUG(D_route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n",
(long int)uid, (long int)gid, current_directory);
+/* If we are not running as root, we will not be able to change uid/gid. */
+
+if (curr_uid != root_uid && (uid != curr_uid || gid != curr_gid))
+ {
+ DEBUG(D_route)
+ {
+ debug_printf("not running as root: cannot change uid/gid\n");
+ debug_printf("subprocess will run with uid=%ld gid=%ld\n",
+ (long int)curr_uid, (long int)curr_gid);
+ }
+ puid = pgid = NULL;
+ }
+
+/* Set up the command to run */
+
if (!transport_set_up_command(&argvptr, /* anchor for arg list */
ob->command, /* raw command */
TRUE, /* expand the arguments */
/* Create the child process, making it a group leader. */
-pid = child_open_uid(argvptr, NULL, 0077, &uid, &gid, &fd_in, &fd_out,
+pid = child_open_uid(argvptr, NULL, 0077, puid, pgid, &fd_in, &fd_out,
current_directory, TRUE);
if (pid < 0)
/* Nothing is written to the standard input. */
-close(fd_in);
+(void)close(fd_in);
/* Wait for the process to finish, applying the timeout, and inspect its return
code. */
/* Read the pipe to get the command's output, and then close it. */
len = read(fd_out, buffer, sizeof(buffer) - 1);
-close(fd_out);
+(void)close(fd_out);
/* Failure to return any data is an error. */
RDO_REWRITE, /* rewrite generated addresses */
NULL, /* :include: directory not relevant */
NULL, /* sieve vacation directory not relevant */
+ NULL, /* sieve enotify mailto owner not relevant */
+ NULL, /* sieve useraddress not relevant */
+ NULL, /* sieve subaddress not relevant */
&ugid, /* uid/gid (but not set) */
&generated, /* where to hang the results */
&(addr->message), /* where to put messages */
if (strcmpic(rword, US"decline") == 0) return DECLINE;
if (strcmpic(rword, US"pass") == 0) return PASS;
addr->message = string_copy(rdata); /* data is a message */
- if (strcmpic(rword, US"fail") == 0) return FAIL;
+ if (strcmpic(rword, US"fail") == 0)
+ {
+ setflag(addr, af_pass_message);
+ return FAIL;
+ }
if (strcmpic(rword, US"freeze") == 0) addr->special_action = SPECIAL_FREEZE;
else if (strcmpic(rword, US"defer") != 0)
{
if (*s != 0)
{
- int lookup_type = lk_default;
+ int lookup_type = LK_DEFAULT;
uschar *ss = expand_string(US"${extract{lookup}{$value}}");
lookup_value = NULL;
if (*ss != 0)
{
- if (Ustrcmp(ss, "byname") == 0) lookup_type = lk_byname;
- else if (Ustrcmp(ss, "bydns") == 0) lookup_type = lk_bydns;
+ if (Ustrcmp(ss, "byname") == 0) lookup_type = LK_BYNAME;
+ else if (Ustrcmp(ss, "bydns") == 0) lookup_type = LK_BYDNS;
else
{
addr->message = string_sprintf("bad lookup type \"%s\" yielded by "
/* Put the errors address, extra headers, and address_data into this address */
-addr->p = addr_prop;
+addr->prop = addr_prop;
/* Queue the address for local or remote delivery. */
OK : DEFER;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/queryprogram.c */