Debug: mark up space/nl in lookup results
[exim.git] / src / src / search.c
index bf709763c730ef68c8e487c59fb42ad40e07a6dd..168c25e6a028a50c78dd5bd3d50eb8cc43e5ea8d 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2015 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* A set of functions to search databases in various formats. An open
 database is represented by a void * value which is returned from a lookup-
@@ -589,35 +590,48 @@ else
   is either untainted or properly quoted for the lookup type.
 
   XXX Should we this move into lf_sqlperform() ?  The server-taint check is there.
+  Also it already knows about looking for a "servers" spec in the query string.
+  Passing search_type down that far is an issue.
   */
 
   if (  !filename && lookup_list[search_type]->quote
      && is_tainted(keystring) && !is_quoted_like(keystring, search_type))
     {
-    uschar * s = acl_current_verb();
-    if (!s) s = authenticator_current_name();  /* must be before transport */
-    if (!s) s = transport_current_name();      /* must be before router */
-    if (!s) s = router_current_name(); /* GCC ?: would be good, but not in clang */
-    if (!s) s = US"";
+    const uschar * ks = keystring;
+    uschar * loc = acl_current_verb();
+    if (!loc) loc = authenticator_current_name();      /* must be before transport */
+    if (!loc) loc = transport_current_name();          /* must be before router */
+    if (!loc) loc = router_current_name();             /* GCC ?: would be good, but not in clang */
+    if (!loc) loc = US"";
+
+    if (Ustrncmp(ks, "servers", 7) == 0)       /* Avoid logging server/password */
+      if ((ks = Ustrchr(keystring, ';')))
+       while (isspace(*++ks))
+         ;
+      else
+       ks = US"";
+
 #ifdef enforce_quote_protection_notyet
     search_error_message = string_sprintf(
       "tainted search query is not properly quoted%s: %s%s",
-      s, keystring);
+      loc, ks);
     f.search_find_defer = TRUE;
+    goto out;
 #else
-     {
-      int q = quoter_for_address(keystring);
-      /* If we're called from a transport, no privs to open the paniclog;
-      the logging punts to using stderr - and that seems to stop the debug
-      stream. */
-      log_write(0,
-       transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC,
-       "tainted search query is not properly quoted%s: %s", s, keystring);
-
-      DEBUG(D_lookup) debug_printf_indent("search_type %d (%s) quoting %d (%s)\n",
+    /* If we're called from a transport, no privs to open the paniclog;
+    the logging punts to using stderr - and that seems to stop the debug
+    stream. */
+    log_write(0,
+      transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC,
+      "tainted search query is not properly quoted%s: %s", loc, ks);
+
+    DEBUG(D_lookup)
+      {
+      int q = quoter_for_address(ks);
+      debug_printf_indent("search_type %d (%s) quoting %d (%s)\n",
        search_type, lookup_list[search_type]->name,
        q, is_real_quoter(q) ? lookup_list[q]->name : US"none");
-     }
+      }
 #endif
     }
 
@@ -668,10 +682,11 @@ pointer to NULL here, because we cannot release the store at this stage. */
     }
   }
 
+out:
 DEBUG(D_lookup)
   {
   if (data)
-    debug_printf_indent("lookup yielded: %s\n", data);
+    debug_printf_indent("lookup yielded: %W\n", data);
   else if (f.search_find_defer)
     debug_printf_indent("lookup deferred: %s\n", search_error_message);
   else debug_printf_indent("lookup failed\n");
@@ -811,7 +826,7 @@ just in case the original key is too long for the string_sprintf() buffer (it
 else if (partial >= 0)
   {
   int len = Ustrlen(keystring);
-  uschar *keystring2;
+  uschar * keystring2;
 
   /* Try with the affix on the front, except for a zero-length affix */
 
@@ -832,20 +847,20 @@ else if (partial >= 0)
   if (!yield)
     {
     int dotcount = 0;
-    uschar *keystring3 = keystring2 + affixlen;
-    uschar *s = keystring3;
-    while (*s != 0) if (*s++ == '.') dotcount++;
+    uschar * keystring3 = keystring2 + affixlen;
+
+    for(uschar * s = keystring3; *s; ) if (*s++ == '.') dotcount++;
 
     while (dotcount-- >= partial)
       {
-      while (*keystring3 != 0 && *keystring3 != '.') keystring3++;
+      while (*keystring3 && *keystring3 != '.') keystring3++;
 
       /* If we get right to the end of the string (which will be the last time
       through this loop), we've failed if the affix is null. Otherwise do one
       last lookup for the affix itself, but if it is longer than 1 character,
       remove the last character if it is ".". */
 
-      if (*keystring3 == 0)
+      if (!*keystring3)
         {
         if (affixlen < 1) break;
         if (affixlen > 1 && affix[affixlen-1] == '.') affixlen--;
@@ -866,7 +881,8 @@ else if (partial >= 0)
       if (yield)
         {
         /* First variable is the wild part; second is the fixed part. Take care
-        to get it right when keystring3 is just "*". */
+        to get it right when keystring3 is just "*".  Return a de-tainted version
+       of the fixed part, on the grounds it has been validated by the lookup. */
 
         if (expand_setup && *expand_setup >= 0)
           {
@@ -876,8 +892,10 @@ else if (partial >= 0)
           expand_nstring[*expand_setup] = keystring;
           expand_nlength[*expand_setup] = wildlength;
           *expand_setup += 1;
-          expand_nstring[*expand_setup] = keystring + wildlength + 1;
-          expand_nlength[*expand_setup] = (fixedlength < 0)? 0 : fixedlength;
+         if (fixedlength < 0) fixedlength = 0;
+          expand_nstring[*expand_setup] = string_copyn_taint(
+           keystring + wildlength + 1, fixedlength, GET_UNTAINTED);
+          expand_nlength[*expand_setup] = fixedlength;
           }
         break;
         }
@@ -895,10 +913,10 @@ is set to the string to the left of the @. */
 if (!yield  &&  starflags & SEARCH_STARAT)
   {
   uschar *atat = Ustrrchr(keystring, '@');
-  if (atat != NULL && atat > keystring)
+  if (atat && atat > keystring)
     {
     int savechar;
-    savechar = *(--atat);
+    savechar = *--atat;
     *atat = '*';
 
     DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat);
@@ -942,16 +960,19 @@ complete non-wild domain entry, or we matched a wild-carded entry without
 chopping off any of the domain components, set up the expansion variables
 (if required) so that the first one is empty, and the second one is the
 fixed part of the domain. The set_null_wild flag is set only when yield is not
-NULL. */
+NULL.  Return a de-tainted version of the fixed part, on the grounds it has been
+validated by the lookup. */
 
 if (set_null_wild && expand_setup && *expand_setup >= 0)
   {
+  int fixedlength = Ustrlen(keystring);
   *expand_setup += 1;
   expand_nstring[*expand_setup] = keystring;
   expand_nlength[*expand_setup] = 0;
   *expand_setup += 1;
-  expand_nstring[*expand_setup] = keystring;
-  expand_nlength[*expand_setup] = Ustrlen(keystring);
+  expand_nstring[*expand_setup] = string_copyn_taint(
+           keystring, fixedlength, GET_UNTAINTED);
+  expand_nlength[*expand_setup] = fixedlength;
   }
 
 /* If we have a result, check the options to see if the key was wanted rather
@@ -959,9 +980,15 @@ than the result.  Return a de-tainted version of the key on the grounds that
 it have been validated by the lookup. */
 
 if (yield && ret_key)
+  {
   yield = string_copy_taint(keystring, GET_UNTAINTED);
+  DEBUG(D_lookup)
+    debug_printf_indent("lookup yield replace by key: %s\n", yield);
+  }
 
 return yield;
 }
 
 /* End of search.c */
+/* vi: aw ai sw=2
+*/