Taint: When a non-wildcarded localpart affix is matched in a router,
[exim.git] / src / src / route.c
index 8b43613ce9a477fbc0a40a6a701da151258695f3..7538b75659d6528c1e27297ed5130e1f2b8ae1fb 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with routing, and the list of generic router options. */
@@ -736,7 +737,7 @@ while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
     otherwise. Save the old state for resetting on the wait. */
 
     oldsignal = signal(SIGCHLD, SIG_DFL);
-    pid = fork();
+    pid = exim_fork(US"require-files");
 
     /* If fork() fails, reinstate the original error and behave as if
     this block of code were not present. This is the same behaviour as happens
@@ -759,9 +760,9 @@ while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
       exim_setugid(uid, gid, TRUE,
         string_sprintf("require_files check, file=%s", ss));
       if (route_check_access(ss, uid, gid, 4))
-       exim_underbar_exit(0);
+       exim_underbar_exit(EXIT_SUCCESS);
       DEBUG(D_route) debug_printf("route_check_access() failed\n");
-      exim_underbar_exit(1);
+      exim_underbar_exit(EXIT_FAILURE);
       }
 
     /* In the parent, wait for the child to finish */
@@ -958,7 +959,8 @@ if (r->check_local_user)
       r->name, addr->local_part);
     return SKIP;
     }
-  deliver_localpart_verified = string_copy(US (*pw)->pw_name);
+  addr->local_part_verified =
+    deliver_localpart_verified = string_copy(US (*pw)->pw_name);
   deliver_home = string_copy(US (*pw)->pw_dir);
   local_user_gid = (*pw)->pw_gid;
   local_user_uid = (*pw)->pw_uid;
@@ -972,22 +974,19 @@ confusing. */
 
 if (r->router_home_directory)
   {
-  uschar *router_home = expand_string(r->router_home_directory);
-  if (!router_home)
-    {
-    if (!f.expand_string_forcedfail)
-      {
-      *perror = string_sprintf("failed to expand \"%s\" for "
-        "router_home_directory: %s", r->router_home_directory,
-        expand_string_message);
-      return DEFER;
-      }
-    }
-  else
+  uschar * router_home = expand_string(r->router_home_directory);
+  if (router_home)
     {
     setflag(addr, af_home_expanded); /* Note set from router_home_directory */
     deliver_home = router_home;
     }
+  else if (!f.expand_string_forcedfail)
+    {
+    *perror = string_sprintf("failed to expand \"%s\" for "
+      "router_home_directory: %s", r->router_home_directory,
+      expand_string_message);
+    return DEFER;
+    }
   }
 
 /* Skip if the sender condition is not met. We leave this one till after the
@@ -1656,8 +1655,18 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
     int plen = route_check_prefix(addr->local_part, r->prefix, &vlen);
     if (plen > 0)
       {
-      addr->prefix = string_copyn(addr->local_part, plen);
-      if (vlen) addr->prefix_v = string_copyn(addr->local_part, vlen);
+      /* If the variable-part is zero-length then the prefix was not
+      wildcarded and we can detaint-copy it since it matches the
+      (non-expandable) router option.  Otherwise copy the (likely) tainted match
+      and the variable-part of the match from the local_part. */
+
+      if (vlen)
+       {
+       addr->prefix = string_copyn(addr->local_part, plen);
+       addr->prefix_v = string_copyn(addr->local_part, vlen);
+       }
+      else
+       addr->prefix = string_copyn_taint(addr->local_part, plen, FALSE);
       addr->local_part += plen;
       DEBUG(D_route) debug_printf("stripped prefix %s\n", addr->prefix);
       }
@@ -1678,7 +1687,9 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
     if (slen > 0)
       {
       int lplen = Ustrlen(addr->local_part) - slen;
-      addr->suffix = addr->local_part + lplen;
+      addr->suffix = vlen
+       ? addr->local_part + lplen
+       : string_copy_taint(addr->local_part + lplen, slen);
       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);
@@ -1695,7 +1706,6 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   the local part sorted. */
 
   router_name = r->name;
-  deliver_localpart_verified = NULL;
   deliver_set_expansions(addr);
 
   /* For convenience, the pre-router checks are in a separate function, which