* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions concerned with routing, and the list of generic router options. */
(void *)offsetof(router_instance, domains) },
{ "driver", opt_stringptr|opt_public,
(void *)offsetof(router_instance, driver_name) },
+ { "dsn_lasthop", opt_bool|opt_public,
+ (void *)offsetof(router_instance, dsn_lasthop) },
{ "errors_to", opt_stringptr|opt_public,
(void *)(offsetof(router_instance, errors_to)) },
{ "expn", opt_bool|opt_public,
if (r->pass_router_name != NULL)
set_router(r, r->pass_router_name, &(r->pass_router), TRUE);
+
+ DEBUG(D_route) {
+ if (r->dsn_lasthop == FALSE)
+ debug_printf("DSN: %s propagating DSN\n", r->name);
+ else
+ debug_printf("DSN: %s lasthop set\n", r->name);
+ }
}
}
*/
int
-route_check_prefix(uschar *local_part, uschar *prefixes)
+route_check_prefix(const uschar *local_part, const uschar *prefixes)
{
int sep = 0;
uschar *prefix;
-uschar *listptr = prefixes;
+const uschar *listptr = prefixes;
uschar prebuf[64];
while ((prefix = string_nextinlist(&listptr, &sep, prebuf, sizeof(prebuf)))
int plen = Ustrlen(prefix);
if (prefix[0] == '*')
{
- uschar *p;
+ const uschar *p;
prefix++;
for (p = local_part + Ustrlen(local_part) - (--plen);
p >= local_part; p--)
*/
int
-route_check_suffix(uschar *local_part, uschar *suffixes)
+route_check_suffix(const uschar *local_part, const uschar *suffixes)
{
int sep = 0;
int alen = Ustrlen(local_part);
uschar *suffix;
-uschar *listptr = suffixes;
+const uschar *listptr = suffixes;
uschar sufbuf[64];
while ((suffix = string_nextinlist(&listptr, &sep, sufbuf, sizeof(sufbuf)))
int slen = Ustrlen(suffix);
if (suffix[slen-1] == '*')
{
- uschar *p, *pend;
+ const uschar *p, *pend;
pend = local_part + alen - (--slen) + 1;
for (p = local_part; p < pend; p++)
if (strncmpic(suffix, p, slen) == 0) return alen - (p - local_part);
*/
static int
-route_check_dls(uschar *rname, uschar *type, uschar *list, tree_node
- **anchorptr, unsigned int *cache_bits, int listtype, uschar *domloc,
- uschar **ldata, BOOL caseless, uschar **perror)
+route_check_dls(uschar *rname, uschar *type, const uschar *list,
+ tree_node **anchorptr, unsigned int *cache_bits, int listtype,
+ const uschar *domloc, const uschar **ldata, BOOL caseless, uschar **perror)
{
int rc;
{
uschar *address = (sender_address == NULL)? US"" : sender_address;
rc = match_address_list(address, TRUE, TRUE, &list, cache_bits, -1, 0,
- &sender_data);
+ CUSS &sender_data);
}
switch(rc)
SKIP otherwise
*/
-int
-check_files(uschar *s, uschar **perror)
+static int
+check_files(const uschar *s, uschar **perror)
{
int sep = 0; /* List has default separators */
uid_t uid = 0; /* For picky compilers */
gid_t gid = 0; /* For picky compilers */
BOOL ugid_set = FALSE;
-uschar *check, *listptr;
+const uschar *listptr;
+uschar *check;
uschar buffer[1024];
if (s == NULL) return OK;
DEBUG(D_route) debug_printf("checking require_files\n");
listptr = s;
-while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer)))
- != NULL)
+while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
{
int rc;
int eacces_code = 0;
/* Skip this router if there's a domain mismatch. */
if ((rc = route_check_dls(r->name, US"domains", r->domains, &domainlist_anchor,
- addr->domain_cache, TRUE, addr->domain, &deliver_domain_data, MCL_DOMAIN,
- perror)) != OK)
+ addr->domain_cache, TRUE, addr->domain, CUSS &deliver_domain_data,
+ MCL_DOMAIN, perror)) != OK)
return rc;
/* Skip this router if there's a local part mismatch. We want to pass over the
if ((rc = route_check_dls(r->name, US"local_parts", r->local_parts,
&localpartlist_anchor, localpart_cache, MCL_LOCALPART,
- check_local_part, &deliver_localpart_data, !r->caseful_local_part,
- perror)) != OK)
+ check_local_part, CUSS &deliver_localpart_data,
+ !r->caseful_local_part, perror)) != OK)
return rc;
/* If the check_local_user option is set, check that the local_part is the
static uschar lastshell[128];
BOOL
-route_finduser(uschar *s, struct passwd **pw, uid_t *return_uid)
+route_finduser(const uschar *s, struct passwd **pw, uid_t *return_uid)
{
BOOL cache_set = (Ustrcmp(lastname, s) == 0);
-/*************************************************
-* Sort out "more" or "unseen" *
-*************************************************/
-
-/* These values are usually fixed boolean values, but they are permitted to be
-expanded strings.
-
-Arguments:
- addr address being routed
- rname the router name
- oname the option name
- bvalue the router's boolean value
- svalue the router's string value
- rvalue where to put the returned value
-
-Returns: OK value placed in rvalue
- DEFER expansion failed
-*/
-
-static int
-exp_bool(address_item *addr, uschar *rname, uschar *oname, BOOL bvalue,
- uschar *svalue, BOOL *rvalue)
-{
-uschar *expanded;
-if (svalue == NULL) { *rvalue = bvalue; return OK; }
-
-expanded = expand_string(svalue);
-if (expanded == NULL)
- {
- if (expand_string_forcedfail)
- {
- DEBUG(D_route) debug_printf("expansion of \"%s\" forced failure\n", oname);
- *rvalue = bvalue;
- return OK;
- }
- addr->message = string_sprintf("failed to expand \"%s\" in %s router: %s",
- oname, rname, expand_string_message);
- DEBUG(D_route) debug_printf("%s\n", addr->message);
- return DEFER;
- }
-
-DEBUG(D_route) debug_printf("expansion of \"%s\" yields \"%s\"\n", oname,
- expanded);
-
-if (strcmpic(expanded, US"true") == 0 || strcmpic(expanded, US"yes") == 0)
- *rvalue = TRUE;
-else if (strcmpic(expanded, US"false") == 0 || strcmpic(expanded, US"no") == 0)
- *rvalue = FALSE;
-else
- {
- addr->message = string_sprintf("\"%s\" is not a valid value for the "
- "\"%s\" option in the %s router", expanded, oname, rname);
- return DEFER;
- }
-
-return OK;
-}
-
-
-
-
/*************************************************
* Handle an unseen routing *
*************************************************/
copyflag(new, addr, af_propagate);
new->p.address_data = addr->p.address_data;
+new->dsn_flags = addr->dsn_flags;
+new->dsn_orcpt = addr->dsn_orcpt;
/* As it has turned out, we haven't set headers_add or headers_remove for the
int yield = OK;
BOOL unseen;
router_instance *r, *nextr;
-uschar *old_domain = addr->domain;
+const uschar *old_domain = addr->domain;
HDEBUG(D_route)
{
/* Set the expansion variables now that we have the affixes and the case of
the local part sorted. */
+ router_name = r->name;
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;
if (rc == SKIP) continue;
addr->message = error;
yield = rc;
/* Expand "more" if necessary; DEFER => an expansion failed */
- yield = exp_bool(addr, r->name, US"more", r->more, r->expand_more,
- &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;
if (!more)
{
DEBUG(D_route)
debug_printf("\"more\"=false: skipping remaining routers\n");
+ router_name = NULL;
r = NULL;
break;
}
/* Run the router, and handle the consequences. */
+/* ... but let us check on DSN before. If this should be the last hop for DSN
+ set flag
+*/
+ if ((r->dsn_lasthop == TRUE) && ((addr->dsn_flags & rf_dsnlasthop) == 0))
+ {
+ addr->dsn_flags |= rf_dsnlasthop;
+ HDEBUG(D_route) debug_printf("DSN: last hop for %s\n", addr->address);
+ }
+
HDEBUG(D_route) debug_printf("calling %s router\n", r->name);
yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
addr_new, addr_succeed);
+ router_name = NULL;
+
if (yield == FAIL)
{
HDEBUG(D_route) debug_printf("%s router forced address failure\n", r->name);
{
/* Expand "more" if necessary */
- yield = exp_bool(addr, r->name, US"more", r->more, r->expand_more, &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;
if (!more)
/* See if this is an unseen routing; first expand the option if necessary.
DEFER can be given if the expansion fails */
-yield = exp_bool(addr, r->name, US"unseen", r->unseen, r->expand_unseen,
- &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;
/* Debugging output recording a successful routing */
if (h->mx >= 0) debug_printf(" MX=%d", h->mx);
else if (h->mx != MX_NONE) debug_printf(" rgroup=%d", h->mx);
if (h->port != PORT_NONE) debug_printf(" port=%d", h->port);
+ if (h->dnssec != DS_UNK) debug_printf(" dnssec=%s", h->dnssec==DS_YES ? "yes" : "no");
debug_printf("\n");
}
}
(
Ustrstr(addr->message, "mysql") != NULL ||
Ustrstr(addr->message, "pgsql") != NULL ||
+#ifdef EXPERIMENTAL_REDIS
+ Ustrstr(addr->message, "redis") != NULL ||
+#endif
Ustrstr(addr->message, "sqlite") != NULL ||
Ustrstr(addr->message, "ldap:") != NULL ||
Ustrstr(addr->message, "ldapdn:") != NULL ||
}
deliver_set_expansions(NULL);
+router_name = NULL;
disable_logging = FALSE;
return yield;
}