Fix dnssec indication variable when used from smtp:commect event
[exim.git] / src / src / route.c
index cc0d63cb0281c4b10d1320401eac92e960adfd62..3834b836a2ca907e4324013250704c4839770de1 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/route.c,v 1.10 2006/07/17 09:21:00 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,10 @@ optionlist optionlist_routers[] = {
                  (void *)offsetof(router_instance, domains) },
   { "driver",             opt_stringptr|opt_public,
                  (void *)offsetof(router_instance, driver_name) },
+  #ifdef EXPERIMENTAL_DSN
+  { "dsn_lasthop",        opt_bool|opt_public,
+                 (void *)offsetof(router_instance, dsn_lasthop) },
+  #endif
   { "errors_to",          opt_stringptr|opt_public,
                  (void *)(offsetof(router_instance, errors_to)) },
   { "expn",               opt_bool|opt_public,
@@ -74,9 +76,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 +274,15 @@ 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);
+
+  #ifdef EXPERIMENTAL_DSN
+    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);
+      }
+  #endif
   }
 }
 
@@ -825,6 +836,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 +897,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 +916,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;
@@ -1408,6 +1425,10 @@ new->p.errors_address = parent->p.errors_address;
 
 copyflag(new, addr, af_propagate);
 new->p.address_data = addr->p.address_data;
+#ifdef EXPERIMENTAL_DSN
+new->dsn_flags = addr->dsn_flags;
+new->dsn_orcpt = addr->dsn_orcpt;
+#endif
 
 
 /* As it has turned out, we haven't set headers_add or headers_remove for the
@@ -1629,6 +1650,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 +1658,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;
@@ -1674,6 +1697,7 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router;
           {
           DEBUG(D_route)
             debug_printf("\"more\"=false: skipping remaining routers\n");
+         router_name = NULL;
           r = NULL;
           break;
           }
@@ -1712,11 +1736,24 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router;
 
   /* Run the router, and handle the consequences. */
 
+#ifdef EXPERIMENTAL_DSN
+/* ... 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);
+  }
+#endif
+
   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);
@@ -1884,7 +1921,7 @@ if (r->translate_ip_address != NULL)
     h->mx = MX_NONE;
 
     store_pool = POOL_PERM;
-    rc = host_find_byname(h, NULL, NULL, TRUE);
+    rc = host_find_byname(h, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, TRUE);
     store_pool = old_pool;
 
     if (rc == HOST_FIND_FAILED || rc == HOST_FIND_AGAIN)
@@ -1932,6 +1969,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 +1984,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;
 }