* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Functions concerned with routing, and the list of generic router options. */
/* Build a host list if fallback hosts is set. */
- host_build_hostlist(&(r->fallback_hostlist), r->fallback_hosts, FALSE);
+ {
+ int old_pool = store_pool;
+ store_pool = POOL_PERM;
+ host_build_hostlist(&r->fallback_hostlist, r->fallback_hosts, FALSE);
+ store_pool = old_pool;
+ }
/* Check redirect_router and pass_router are valid */
BOOL ugid_set = FALSE;
const uschar *listptr;
uschar *check;
-uschar buffer[1024];
if (!s) return OK;
-DEBUG(D_route) debug_printf("checking require_files\n");
+DEBUG(D_route|D_expand) debug_printf("checking require_files\n");
listptr = s;
-while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
+while ((check = string_nextinlist(&listptr, &sep, NULL, 0)))
{
int rc;
int eacces_code = 0;
/* Empty items are just skipped */
- if (*ss == 0) continue;
+ if (!*ss) continue;
/* If there are no slashes in the string, we have a user name or uid, with
optional group/gid. */
/* If there's a comma, temporarily terminate the user name/number
at that point. Then set the uid. */
- if (comma != NULL) *comma = 0;
+ if (comma) *comma = 0;
ok = route_finduser(ss, &pw, &uid);
- if (comma != NULL) *comma = ',';
+ if (comma) *comma = ',';
if (!ok)
{
/* If there was no comma, the gid is that associated with the user. */
- if (comma == NULL)
- {
- if (pw != NULL) gid = pw->pw_gid; else
+ if (!comma)
+ if (pw)
+ gid = pw->pw_gid;
+ else
{
*perror = string_sprintf("group missing after numerical uid %d for "
"require_files", (int)uid);
goto RETURN_DEFER;
}
- }
else
- {
if (!route_findgroup(comma + 1, &gid))
{
*perror = string_sprintf("group \"%s\" for require_files not found\n",
comma + 1);
goto RETURN_DEFER;
}
- }
/* Note that we have values set, and proceed to next item */
*/
static BOOL
-check_router_conditions(router_instance *r, address_item *addr, int verify,
- struct passwd **pw, uschar **perror)
+check_router_conditions(router_instance * r, address_item * addr, int verify,
+ struct passwd ** pw, uschar ** perror)
{
int rc;
-uschar *check_local_part;
-unsigned int *localpart_cache;
+uschar * check_local_part;
+unsigned int * localpart_cache;
/* Reset variables to hold a home directory and data from lookup of a domain or
local part, and ensure search_find_defer is unset, in case there aren't any
required. Also, we only use the match cache for local parts that have not had
a prefix or suffix stripped. */
+check_local_part = string_copy(addr->cc_local_part);
if (!addr->prefix && !addr->suffix)
- {
localpart_cache = addr->localpart_cache;
- check_local_part = addr->cc_local_part;
- }
else
{
localpart_cache = NULL;
- check_local_part = string_copy(addr->cc_local_part);
if (addr->prefix)
check_local_part += Ustrlen(addr->prefix);
if (addr->suffix)
could mean different things for different options, which would be extremely
confusing. */
+GET_OPTION("router_home_directory");
if (r->router_home_directory)
{
uschar * router_home = expand_string(r->router_home_directory);
if (r->condition)
{
- DEBUG(D_route) debug_printf("checking \"condition\" \"%.80s\"...\n", r->condition);
+ DEBUG(D_route|D_expand)
+ debug_printf("checking \"condition\" \"%.80s\"...\n", r->condition);
if (!expand_check_condition(r->condition, r->name, US"router"))
{
if (f.search_find_defer)
tree_node ** root = (tree_node **) &addr->prop.variables;
int sep = ';';
+GET_OPTION("set");
if (!varlist) return OK;
/* Walk the varlist, creating variables */
/* Expand "more" if necessary; DEFER => an expansion failed */
+ GET_OPTION("more");
yield = exp_bool(addr, US"router", r->name, D_route,
US"more", r->more, r->expand_more, &more);
if (yield != OK) return yield;
{
addr->message = string_sprintf("expansion of \"%s\" failed "
"in %s router: %s", ele, r->name, expand_string_message);
- return DEFER;
+ /* Caller will replace that for logging, if a DB lookup, to avoid exposing
+ passwords */
+ DEBUG(D_route) debug_printf("%s\n", addr->message);
+ if (!f.search_find_defer)
+ return f.search_find_defer ? DEFER : FAIL;
}
if (!(node = tree_search(*root, name)))
{ /* name should never be tainted */
- node = store_get(sizeof(tree_node) + Ustrlen(name), FALSE);
+ node = store_get(sizeof(tree_node) + Ustrlen(name), GET_UNTAINTED);
Ustrcpy(node->name, name);
(void)tree_insertnode(root, node);
}
{
int yield = OK;
BOOL unseen;
-router_instance *r, *nextr;
-const uschar *old_domain = addr->domain;
+router_instance * r, * nextr;
+const uschar * old_domain = addr->domain;
HDEBUG(D_route)
{
for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
{
- uschar *error;
- struct passwd *pw = NULL;
+ uschar * error;
+ struct passwd * pw = NULL;
struct passwd pwcopy;
BOOL loop_detected = FALSE;
BOOL more;
addr->prefix_v = string_copyn(addr->local_part, vlen);
}
else
- addr->prefix = string_copyn_taint(addr->local_part, plen, FALSE);
+ addr->prefix = string_copyn_taint(addr->local_part, plen, GET_UNTAINTED);
addr->local_part += plen;
DEBUG(D_route) debug_printf("stripped prefix %s\n", addr->prefix);
}
int lplen = Ustrlen(addr->local_part) - slen;
addr->suffix = vlen
? addr->local_part + lplen
- : string_copy_taint(addr->local_part + lplen, slen);
+ : string_copy_taint(addr->local_part + lplen, GET_UNTAINTED);
addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen;
addr->local_part = string_copyn(addr->local_part, lplen);
DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
the local part sorted. */
router_name = r->name;
+ driver_srcfile = r->srcfile;
+ driver_srcline = r->srcline;
deliver_set_expansions(addr);
/* For convenience, the pre-router checks are in a separate function, which
if ((rc = check_router_conditions(r, addr, verify, &pw, &error)) != OK)
{
- router_name = NULL;
+ driver_srcfile = router_name = NULL; driver_srcline = 0;
if (rc == SKIP) continue;
addr->message = error;
yield = rc;
router traversal. On the addr string they are held as a variable tree, so
as to maintain the post-expansion taints separate. */
- switch (set_router_vars(addr, r))
+ switch (rc = set_router_vars(addr, r))
{
case OK: break;
case PASS: continue; /* with next router */
- default: goto ROUTE_EXIT;
+ default: yield = rc; goto ROUTE_EXIT;
}
/* Finally, expand the address_data field in the router. Forced failure
if (r->address_data)
{
- DEBUG(D_route) debug_printf("processing address_data\n");
+ DEBUG(D_route|D_expand) debug_printf("processing address_data\n");
if (!(deliver_address_data = expand_string(r->address_data)))
{
if (f.expand_string_forcedfail)
/* Expand "more" if necessary; DEFER => an expansion failed */
+ GET_OPTION("more");
yield = exp_bool(addr, US"router", r->name, D_route,
US"more", r->more, r->expand_more, &more);
if (yield != OK) goto ROUTE_EXIT;
{
DEBUG(D_route)
debug_printf("\"more\"=false: skipping remaining routers\n");
- router_name = NULL;
+ driver_srcfile = router_name = NULL; driver_srcline = 0;
r = NULL;
break;
}
yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
addr_new, addr_succeed);
- router_name = NULL;
+ driver_srcfile = router_name = NULL; driver_srcline = 0;
if (yield == FAIL)
{
{
/* Expand "more" if necessary */
+ GET_OPTION("more");
yield = exp_bool(addr, US"router", r->name, D_route,
US"more", r->more, r->expand_more, &more);
if (yield != OK) goto ROUTE_EXIT;
HDEBUG(D_route) debug_printf("no more routers\n");
if (!addr->message)
{
- uschar *message = US"Unrouteable address";
- if (addr->router && addr->router->cannot_route_message)
+ uschar * message = US"Unrouteable address";
+ if (addr->router)
{
- uschar *expmessage = expand_string(addr->router->cannot_route_message);
- if (!expmessage)
- {
- if (!f.expand_string_forcedfail)
- log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
- "cannot_route_message in %s router: %s", addr->router->name,
- expand_string_message);
- }
- else message = expmessage;
+ uschar * s = addr->router->cannot_route_message;
+ GET_OPTION("cannot_route_message");
+ if (s)
+ {
+ if ((s = expand_string(s)))
+ message = s;
+ else
+ if (!f.expand_string_forcedfail)
+ log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
+ "cannot_route_message in %s router: %s", addr->router->name,
+ expand_string_message);
+ }
}
addr->user_message = addr->message = message;
}
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
+GET_OPTION("translate_ip_address");
if (r->translate_ip_address)
{
int rc;
/* See if this is an unseen routing; first expand the option if necessary.
DEFER can be given if the expansion fails */
+GET_OPTION("unseen");
yield = exp_bool(addr, US"router", r->name, D_route,
US"unseen", r->unseen, r->expand_unseen, &unseen);
if (yield != OK) goto ROUTE_EXIT;
addr->message = expand_hide_passwords(addr->message);
deliver_set_expansions(NULL);
-router_name = NULL;
+driver_srcfile = router_name = NULL; driver_srcline = 0;
f.disable_logging = FALSE;
return yield;
}
+
+
+/* For error messages, a string describing the config location associated
+with current processing. NULL if we are not in a router. */
+/* Name only, for now */
+
+uschar *
+router_current_name(void)
+{
+if (!router_name) return NULL;
+return string_sprintf(" (router %s, %s %d)", router_name, driver_srcfile, driver_srcline);
+}
+
#endif /*!MACRO_PREDEF*/
/* End of route.c */