Lookups: ret=key option
[exim.git] / src / src / search.c
index 2a60fc78a046c6702179df3840ed038ccdcdd3e4..94a58897f787da0115b9d6ef225f27de6b1083f5 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* A set of functions to search databases in various formats. An open
@@ -188,7 +189,7 @@ if ((t = Ustrchr(t, ',')))
   *opts = string_copy(t+1);
   }
 else
-  * opts = NULL;
+  *opts = NULL;
 
 /* Check for the individual search type. Only those that are actually in the
 binary are valid. For query-style types, "partial" and default types are
@@ -239,12 +240,10 @@ Returns:     nothing
 static void
 tidyup_subtree(tree_node *t)
 {
-search_cache *c = (search_cache *)(t->data.ptr);
-if (t->left != NULL) tidyup_subtree(t->left);
-if (t->right != NULL) tidyup_subtree(t->right);
-if (c != NULL &&
-    c->handle != NULL &&
-    lookup_list[c->search_type]->close != NULL)
+search_cache * c = (search_cache *)(t->data.ptr);
+if (t->left)  tidyup_subtree(t->left);
+if (t->right) tidyup_subtree(t->right);
+if (c && c->handle && lookup_list[c->search_type]->close)
   lookup_list[c->search_type]->close(c->handle);
 }
 
@@ -522,7 +521,8 @@ else
   DEBUG(D_lookup)
     {
     if (t)
-      debug_printf_indent("cached data found but either wrong opts or dated; ");
+      debug_printf_indent("cached data found but %s; ",
+       e->expiry && e->expiry <= time(NULL) ? "out-of-date" : "wrong opts");
     debug_printf_indent("%s lookup required for %s%s%s\n",
       filename ? US"file" : US"database",
       keystring,
@@ -545,25 +545,20 @@ else
 
   else if (do_cache)
     {
-    int len = keylength + 1;
-
-    if (t)     /* Previous, out-of-date cache entry.  Update with the */
-      {        /* new result and forget the old one */
-      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
-      e->opts = opts;
-      e->data.ptr = data;
-      }
-    else
+    if (!t)    /* No existing entry.  Create new one. */
       {
+      int len = keylength + 1;
       e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, is_tainted(keystring));
-      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
-      e->opts = opts;
-      e->data.ptr = data;
       t = (tree_node *)(e+1);
       memcpy(t->name, keystring, len);
       t->data.ptr = e;
       tree_insertnode(&c->item_cache, t);
       }
+      /* Else previous, out-of-date cache entry.  Update with the */
+      /* new result and forget the old one */
+    e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
+    e->opts = opts ? string_copy(opts) : NULL;
+    e->data.ptr = data;
     }
 
   /* If caching was disabled, empty the cache tree. We just set the cache
@@ -572,7 +567,7 @@ else
   else
     {
     DEBUG(D_lookup) debug_printf_indent("lookup forced cache cleanup\n");
-    c->item_cache = NULL;
+    c->item_cache = NULL;      /* forget all lookups on this connection */
     }
   }
 
@@ -720,7 +715,7 @@ else if (partial >= 0)
   /* The key in its entirety did not match a wild entry; try chopping off
   leading components. */
 
-  if (yield == NULL)
+  if (!yield)
     {
     int dotcount = 0;
     uschar *keystring3 = keystring2 + affixlen;
@@ -844,6 +839,19 @@ if (set_null_wild && expand_setup && *expand_setup >= 0)
   expand_nlength[*expand_setup] = Ustrlen(keystring);
   }
 
+/* If we have a result, check the options to see if the key was wanted rather
+than the result.  Return a de-tainted version of the key on the grounds that
+it have been validated by the lookup. */
+
+if (yield && opts)
+  {
+  int sep = ',';
+  uschar * ele;
+  while ((ele = string_nextinlist(&opts, &sep, NULL, 0)))
+    if (Ustrcmp(ele, "ret=key") == 0)
+      { yield = string_copy_taint(keystring, FALSE); break; }
+  }
+
 return yield;
 }