X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/322050c2d9e83d10f046da71aa2cd9cc5a355b0b..1ad6489edabbfce85ee7362370cee4b34739c234:/src/src/route.c diff --git a/src/src/route.c b/src/src/route.c index f80256e3e..09503044f 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/route.c,v 1.11 2006/10/09 14:36:25 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* 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. */ @@ -50,7 +48,7 @@ optionlist optionlist_routers[] = { (void *)(offsetof(router_instance, caseful_local_part)) }, { "check_local_user", opt_bool | opt_public, (void *)(offsetof(router_instance, check_local_user)) }, - { "condition", opt_stringptr|opt_public, + { "condition", opt_stringptr|opt_public|opt_rep_con, (void *)offsetof(router_instance, condition) }, { "debug_print", opt_stringptr | opt_public, (void *)offsetof(router_instance, debug_string) }, @@ -60,6 +58,8 @@ optionlist optionlist_routers[] = { (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, @@ -74,9 +74,9 @@ optionlist optionlist_routers[] = { (void *)offsetof(router_instance, fallback_hosts) }, { "group", opt_expand_gid | opt_public, (void *)(offsetof(router_instance, gid)) }, - { "headers_add", opt_stringptr|opt_public, + { "headers_add", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(router_instance, extra_headers) }, - { "headers_remove", opt_stringptr|opt_public, + { "headers_remove", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(router_instance, remove_headers) }, { "ignore_target_hosts",opt_stringptr|opt_public, (void *)offsetof(router_instance, ignore_target_hosts) }, @@ -272,6 +272,13 @@ for (r = routers; r != NULL; r = r->next) 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); + } } } @@ -825,6 +832,7 @@ check_router_conditions(router_instance *r, address_item *addr, int verify, { int rc; 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 @@ -885,12 +893,17 @@ if ((rc = route_check_dls(r->name, US"domains", r->domains, &domainlist_anchor, caseful local part, so that +caseful can restore it, even if this router is handling local parts caselessly. However, we can't just pass cc_local_part, because that doesn't have the prefix or suffix stripped. A bit of massaging is -required. */ +required. Also, we only use the match cache for local parts that have not had +a prefix or suffix stripped. */ if (addr->prefix == NULL && addr->suffix == NULL) + { + 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 != NULL) check_local_part += Ustrlen(addr->prefix); @@ -899,7 +912,7 @@ else } if ((rc = route_check_dls(r->name, US"local_parts", r->local_parts, - &localpartlist_anchor, addr->localpart_cache, MCL_LOCALPART, + &localpartlist_anchor, localpart_cache, MCL_LOCALPART, check_local_part, &deliver_localpart_data, !r->caseful_local_part, perror)) != OK) return rc; @@ -1288,67 +1301,6 @@ return yield; -/************************************************* -* 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 * *************************************************/ @@ -1408,6 +1360,8 @@ new->p.errors_address = parent->p.errors_address; 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 @@ -1629,6 +1583,7 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router; /* 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 @@ -1636,6 +1591,7 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router; if ((rc = check_router_conditions(r, addr, verify, &pw, &error)) != OK) { + router_name = NULL; if (rc == SKIP) continue; addr->message = error; yield = rc; @@ -1666,14 +1622,15 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router; /* 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; } @@ -1712,11 +1669,22 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router; /* 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); @@ -1762,7 +1730,8 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router; { /* 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) @@ -1902,8 +1871,8 @@ if (r->translate_ip_address != NULL) /* 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 */ @@ -1932,6 +1901,7 @@ DEBUG(D_route) 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"); } } @@ -1946,7 +1916,27 @@ if (unseen && r->next != NULL) /* Unset the address expansions, and return the final result. */ ROUTE_EXIT: +if (yield == DEFER) { + if ( + ((Ustrstr(addr->message, "failed to expand") != NULL) || (Ustrstr(addr->message, "expansion of ") != NULL)) && + ( + 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 || + Ustrstr(addr->message, "ldapm:") != NULL + ) + ) { + addr->message = string_sprintf("Temporary internal error"); + } +} + deliver_set_expansions(NULL); +router_name = NULL; disable_logging = FALSE; return yield; }