Move from table to tree for lookups
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 23 Aug 2024 20:31:07 +0000 (21:31 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 24 Aug 2024 15:25:28 +0000 (16:25 +0100)
20 files changed:
src/src/acl.c
src/src/drtables.c
src/src/exim.c
src/src/expand.c
src/src/functions.h
src/src/globals.h
src/src/lookupapi.h
src/src/lookups/ldap.c
src/src/macros.h
src/src/match.c
src/src/search.c
src/src/spool_in.c
src/src/spool_out.c
src/src/store.c
src/src/structs.h
src/src/tree.c
src/src/verify.c
test/runtest
test/stderr/2610
test/stderr/2620

index 69777cf9c89610dd008b57565fdb73ea8513b8f1..3f1ff65cbd6377df37d21d4c9632421809fae4d1 100644 (file)
@@ -5017,7 +5017,11 @@ if (is_tainted(value))
   {
   int q = quoter_for_address(value);
   putc('-', f);
   {
   int q = quoter_for_address(value);
   putc('-', f);
-  if (is_real_quoter(q)) fprintf(f, "(%s)", lookup_list[q]->name);
+  if (is_real_quoter(q))
+    {
+    const lookup_info * li = lookup_with_acq_num(q);
+    fprintf(f, "(%s)", li ? li->name : US"???");
+    }
   }
 fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
 }
   }
 fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
 }
index 1d8e222e2d2e8efe9d6f6fda555cf408a56fe3c4..d25db887f160e3ad2302e71b7b86973d3dc66b6b 100644 (file)
@@ -18,8 +18,9 @@ various macros in config.h that ultimately come from Local/Makefile. They are
 all described in src/EDITME. */
 
 
 all described in src/EDITME. */
 
 
-lookup_info **lookup_list;
-int lookup_list_count = 0;
+//lookup_info **lookup_list;
+tree_node * lookups_tree = NULL;
+unsigned lookup_list_count = 0;
 
 /* Lists of information about which drivers are included in the exim binary. */
 
 
 /* Lists of information about which drivers are included in the exim binary. */
 
@@ -225,54 +226,51 @@ return g;
 
 
 
 
 
 
-struct lookupmodulestr
+static void
+add_lookup_to_tree(lookup_info * li)
 {
 {
-  void *dl;
-  struct lookup_module_info *info;
-  struct lookupmodulestr *next;
-};
+tree_node * new = store_get_perm(sizeof(tree_node) + Ustrlen(li->name),
+                                                       GET_UNTAINTED);
+new->data.ptr = (void *)li;
+Ustrcpy(new->name, li->name);
+if (tree_insertnode(&lookups_tree, new))
+  li->acq_num = lookup_list_count++;
+else
+  log_write(0, LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name);
+}
 
 
-static struct lookupmodulestr *lookupmodules = NULL;
 
 
+/* Add all the lookup types provided by the module */
 static void
 static void
-addlookupmodule(void *dl, struct lookup_module_info *info)
+addlookupmodule(const struct lookup_module_info * lmi)
 {
 {
-struct lookupmodulestr * p =
-  store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
-
-p->dl = dl;
-p->info = info;
-p->next = lookupmodules;
-lookupmodules = p;
-lookup_list_count += info->lookupcount;
+for (int j = 0; j < lmi->lookupcount; j++)
+  add_lookup_to_tree(lmi->lookups[j]);
 }
 
 }
 
-/* only valid after lookup_list and lookup_list_count are assigned */
-static void
-add_lookup_to_list(lookup_info *info)
-{
-/* need to add the lookup to lookup_list, sorted */
-int pos = 0;
 
 
-/* strategy is to go through the list until we find
-either an empty spot or a name that is higher.
-this can't fail because we have enough space. */
 
 
-while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
-  pos++;
+static unsigned hunt_acq;
 
 
-if (lookup_list[pos])
-  {
-  /* need to insert it, so move all the other items up
-  (last slot is still empty, of course) */
+static void
+acq_cb(uschar * name, uschar * ptr, void * ctx)
+{
+lookup_info * li = (lookup_info *)ptr;
+if (li->acq_num == hunt_acq) *(lookup_info **)ctx = li;
+}
 
 
-  memmove(&lookup_list[pos+1], &lookup_list[pos],
-         sizeof(lookup_info *) * (lookup_list_count-pos-1));
-  }
-lookup_list[pos] = info;
+/*XXX many of the calls here could instead use a name on the quoted-pool */
+const lookup_info *
+lookup_with_acq_num(unsigned k)
+{
+const lookup_info * li = NULL;
+hunt_acq = k;
+tree_walk(lookups_tree, acq_cb, &li);
+return li;
 }
 
 
 }
 
 
+
 /* These need to be at file level for old versions of gcc (2.95.2 reported),
 which give parse errors on an extern in function scope.  Each entry needs
 to also be invoked in init_lookup_list() below  */
 /* These need to be at file level for old versions of gcc (2.95.2 reported),
 which give parse errors on an extern in function scope.  Each entry needs
 to also be invoked in init_lookup_list() below  */
@@ -351,98 +349,96 @@ int countmodules = 0;
 int moduleerrors = 0;
 #endif
 static BOOL lookup_list_init_done = FALSE;
 int moduleerrors = 0;
 #endif
 static BOOL lookup_list_init_done = FALSE;
-rmark reset_point;
 
 if (lookup_list_init_done)
   return;
 
 if (lookup_list_init_done)
   return;
-reset_point = store_mark();
 lookup_list_init_done = TRUE;
 
 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
 lookup_list_init_done = TRUE;
 
 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
-addlookupmodule(NULL, &cdb_lookup_module_info);
+addlookupmodule(&cdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
 #endif
 
 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
-addlookupmodule(NULL, &dbmdb_lookup_module_info);
+addlookupmodule(&dbmdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
 #endif
 
 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
-addlookupmodule(NULL, &dnsdb_lookup_module_info);
+addlookupmodule(&dnsdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
 #endif
 
 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
-addlookupmodule(NULL, &dsearch_lookup_module_info);
+addlookupmodule(&dsearch_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
 #endif
 
 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
-addlookupmodule(NULL, &ibase_lookup_module_info);
+addlookupmodule(&ibase_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
 #endif
 
 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
-addlookupmodule(NULL, &ldap_lookup_module_info);
+addlookupmodule(&ldap_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
 #endif
 
 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
-addlookupmodule(NULL, &json_lookup_module_info);
+addlookupmodule(&json_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
 #endif
 
 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
-addlookupmodule(NULL, &lsearch_lookup_module_info);
+addlookupmodule(&lsearch_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
 #endif
 
 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
-addlookupmodule(NULL, &mysql_lookup_module_info);
+addlookupmodule(&mysql_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
 #endif
 
 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
-addlookupmodule(NULL, &nis_lookup_module_info);
+addlookupmodule(&nis_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
 #endif
 
 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
-addlookupmodule(NULL, &nisplus_lookup_module_info);
+addlookupmodule(&nisplus_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
 #endif
 
 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
-addlookupmodule(NULL, &oracle_lookup_module_info);
+addlookupmodule(&oracle_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
 #endif
 
 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
-addlookupmodule(NULL, &passwd_lookup_module_info);
+addlookupmodule(&passwd_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
 #endif
 
 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
-addlookupmodule(NULL, &pgsql_lookup_module_info);
+addlookupmodule(&pgsql_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
 #endif
 
 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
-addlookupmodule(NULL, &redis_lookup_module_info);
+addlookupmodule(&redis_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
 #endif
 
 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
-addlookupmodule(NULL, &lmdb_lookup_module_info);
+addlookupmodule(&lmdb_lookup_module_info);
 #endif
 
 #ifdef SUPPORT_SPF
 #endif
 
 #ifdef SUPPORT_SPF
-addlookupmodule(NULL, &spf_lookup_module_info);
+addlookupmodule(&spf_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
 #endif
 
 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
-addlookupmodule(NULL, &sqlite_lookup_module_info);
+addlookupmodule(&sqlite_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
 #endif
 
 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
-addlookupmodule(NULL, &testdb_lookup_module_info);
+addlookupmodule(&testdb_lookup_module_info);
 #endif
 
 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
 #endif
 
 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
-addlookupmodule(NULL, &whoson_lookup_module_info);
+addlookupmodule(&whoson_lookup_module_info);
 #endif
 
 /* This is a custom expansion, and not available as either
 a list-syntax lookup or a lookup expansion. However, it is
 implemented by a lookup module. */
 
 #endif
 
 /* This is a custom expansion, and not available as either
 a list-syntax lookup or a lookup expansion. However, it is
 implemented by a lookup module. */
 
-addlookupmodule(NULL, &readsock_lookup_module_info);
+addlookupmodule(&readsock_lookup_module_info);
 
 #ifdef LOOKUP_MODULE_DIR
 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
 
 #ifdef LOOKUP_MODULE_DIR
 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
@@ -513,7 +509,7 @@ else
        continue;
        }
 
        continue;
        }
 
-      addlookupmodule(dl, info);
+      addlookupmodule(info);
       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
       countmodules++;
       }
       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
       countmodules++;
       }
@@ -527,16 +523,6 @@ DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
 
 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
 
 
 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
 
-lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
-memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
-
-/* now add all lookups to the real list */
-for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
-  for (int j = 0; j < p->info->lookupcount; j++)
-    add_lookup_to_list(p->info->lookups[j]);
-store_reset(reset_point);
-/* just to be sure */
-lookupmodules = NULL;
 }
 
 #endif /*!MACRO_PREDEF*/
 }
 
 #endif /*!MACRO_PREDEF*/
index 3d0929592b3ca8f46b012f390ef6e0fce62a9da3..1a22c9af2528fcd358bba883254f441312e7b40c 100644 (file)
@@ -1183,6 +1183,17 @@ return g;
 }
 
 
 }
 
 
+static void
+lookup_version_report_cb(uschar * name, uschar * ptr, void * ctx)
+{
+const lookup_info * li = (lookup_info *)ptr;
+gstring ** gp = ctx;
+
+if (li->version_report)
+  *gp = li->version_report(*gp);
+}
+
+
 /* This function is called for -bV/--version and for -d to output the optional
 features of the current Exim binary.
 
 /* This function is called for -bV/--version and for -d to output the optional
 features of the current Exim binary.
 
@@ -1368,7 +1379,7 @@ DEBUG(D_any)
                gnu_get_libc_version());
 #endif
 
                gnu_get_libc_version());
 #endif
 
-g = show_db_version(g);
+  g = show_db_version(g);
 
 #ifndef DISABLE_TLS
   g = tls_version_report(g);
 
 #ifndef DISABLE_TLS
   g = tls_version_report(g);
@@ -1383,12 +1394,12 @@ g = show_db_version(g);
   g = spf_lib_version_report(g);
 #endif
 
   g = spf_lib_version_report(g);
 #endif
 
-show_string(is_stdout, g);
-g = NULL;
+  show_string(is_stdout, g);
+  g = NULL;
 
 
-for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next)
-  if (ai->version_report)
-    g = (*ai->version_report)(g);
+  for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next)
+    if (ai->version_report)
+      g = (*ai->version_report)(g);
 
   /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
   characters; unless it's an ancient version of PCRE in which case it
 
   /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
   characters; unless it's an ancient version of PCRE in which case it
@@ -1398,27 +1409,25 @@ for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next)
 #endif
 #define QUOTE(X) #X
 #define EXPAND_AND_QUOTE(X) QUOTE(X)
 #endif
 #define QUOTE(X) #X
 #define EXPAND_AND_QUOTE(X) QUOTE(X)
-  {
-  uschar buf[24];
-  pcre2_config(PCRE2_CONFIG_VERSION, buf);
-  g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
-              "                        Runtime: %s\n",
-          PCRE2_MAJOR, PCRE2_MINOR,
-          EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
-          buf);
-  }
+    {
+    uschar buf[24];
+    pcre2_config(PCRE2_CONFIG_VERSION, buf);
+    g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
+               "                        Runtime: %s\n",
+           PCRE2_MAJOR, PCRE2_MINOR,
+           EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
+           buf);
+    }
 #undef QUOTE
 #undef EXPAND_AND_QUOTE
 
 #undef QUOTE
 #undef EXPAND_AND_QUOTE
 
-show_string(is_stdout, g);
-g = NULL;
+  show_string(is_stdout, g);
+  g = NULL;
 
 
-init_lookup_list();
-for (int i = 0; i < lookup_list_count; i++)
-  if (lookup_list[i]->version_report)
-    g = lookup_list[i]->version_report(g);
-show_string(is_stdout, g);
-g = NULL;
+  init_lookup_list();
+  tree_walk(lookups_tree, lookup_version_report_cb, &g);
+  show_string(is_stdout, g);
+  g = NULL;
 
 #ifdef WHITELIST_D_MACROS
   g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
 
 #ifdef WHITELIST_D_MACROS
   g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
index e17c21788028ccd0cb695e16203d15b6172f39cd..08d72f213dd56938af10b6b609378f99a6ea677b 100644 (file)
@@ -2804,9 +2804,11 @@ switch(cond_type = identify_operator(&s, &opname))
     case ECOND_LDAPAUTH:
     #ifdef LOOKUP_LDAP
       {
     case ECOND_LDAPAUTH:
     #ifdef LOOKUP_LDAP
       {
-      int stype = search_findtype(US"ldapauth", 8), expand_setup = -1;
-      void * handle = search_open(NULL, stype, 0, NULL, NULL);
-      if (handle)
+      int expand_setup = -1;
+      const lookup_info * li = search_findtype(US"ldapauth", 8);
+      void * handle;
+
+      if (li && (handle = search_open(NULL, li, 0, NULL, NULL)))
        rc = search_find(handle, NULL, sub[0],
                        -1, NULL, 0, 0, &expand_setup, NULL)
          ? OK : f.search_find_defer ? DEFER : FAIL;
        rc = search_find(handle, NULL, sub[0],
                        -1, NULL, 0, 0, &expand_setup, NULL)
          ? OK : f.search_find_defer ? DEFER : FAIL;
@@ -5018,9 +5020,9 @@ while (*s)
 
     case EITEM_LOOKUP:
       {
 
     case EITEM_LOOKUP:
       {
-      int stype, partial, affixlen, starflags;
-      int expand_setup = 0;
-      int nameptr = 0;
+      int expand_setup = 0, nameptr = 0;
+      int partial, affixlen, starflags;
+      const lookup_info * li;
       uschar * key, * filename;
       const uschar * affix, * opts;
       uschar * save_lookup_value = lookup_value;
       uschar * key, * filename;
       const uschar * affix, * opts;
       uschar * save_lookup_value = lookup_value;
@@ -5073,8 +5075,8 @@ while (*s)
       /* Now check for the individual search type and any partial or default
       options. Only those types that are actually in the binary are valid. */
 
       /* Now check for the individual search type and any partial or default
       options. Only those types that are actually in the binary are valid. */
 
-      if ((stype = search_findtype_partial(name, &partial, &affix, &affixlen,
-         &starflags, &opts)) < 0)
+      if (!(li = search_findtype_partial(name, &partial, &affix, &affixlen,
+         &starflags, &opts)))
         {
         expand_string_message = search_error_message;
         goto EXPAND_FAILED;
         {
         expand_string_message = search_error_message;
         goto EXPAND_FAILED;
@@ -5083,7 +5085,7 @@ while (*s)
       /* Check that a key was provided for those lookup types that need it,
       and was not supplied for those that use the query style. */
 
       /* Check that a key was provided for those lookup types that need it,
       and was not supplied for those that use the query style. */
 
-      if (!mac_islookup(stype, lookup_querystyle|lookup_absfilequery))
+      if (!mac_islookup(li, lookup_querystyle|lookup_absfilequery))
         {
         if (!key)
           {
         {
         if (!key)
           {
@@ -5126,7 +5128,7 @@ while (*s)
       file types, the query (i.e. "key") starts with a file name. */
 
       if (!key)
       file types, the query (i.e. "key") starts with a file name. */
 
       if (!key)
-       key = search_args(stype, name, filename, &filename, opts);
+       key = search_args(li, name, filename, &filename, opts);
 
       /* If skipping, don't do the next bit - just lookup_value == NULL, as if
       the entry was not found. Note that there is no search_close() function.
 
       /* If skipping, don't do the next bit - just lookup_value == NULL, as if
       the entry was not found. Note that there is no search_close() function.
@@ -5145,7 +5147,7 @@ while (*s)
         lookup_value = NULL;
       else
         {
         lookup_value = NULL;
       else
         {
-        void * handle = search_open(filename, stype, 0, NULL, NULL);
+        void * handle = search_open(filename, li, 0, NULL, NULL);
         if (!handle)
           {
           expand_string_message = search_error_message;
         if (!handle)
           {
           expand_string_message = search_error_message;
@@ -5526,12 +5528,18 @@ while (*s)
 
       if (!(flags & ESI_SKIPPING))
         {
 
       if (!(flags & ESI_SKIPPING))
         {
-       int stype = search_findtype(US"readsock", 8);
+       const lookup_info * li = search_findtype(US"readsock", 8);
        gstring * g = NULL;
        void * handle;
        int expand_setup = -1;
        uschar * s;
 
        gstring * g = NULL;
        void * handle;
        int expand_setup = -1;
        uschar * s;
 
+       if (!li)
+         {
+         expand_string_message = search_error_message;
+         goto EXPAND_FAILED;
+         }
+
        /* If the reqstr is empty, flag that and set a dummy */
 
        if (!sub_arg[1][0])
        /* If the reqstr is empty, flag that and set a dummy */
 
        if (!sub_arg[1][0])
@@ -5569,7 +5577,7 @@ while (*s)
 
        /* Gat a (possibly cached) handle for the connection */
 
 
        /* Gat a (possibly cached) handle for the connection */
 
-       if (!(handle = search_open(sub_arg[0], stype, 0, NULL, NULL)))
+       if (!(handle = search_open(sub_arg[0], li, 0, NULL, NULL)))
          {
          if (*expand_string_message) goto EXPAND_FAILED;
          expand_string_message = search_error_message;
          {
          if (*expand_string_message) goto EXPAND_FAILED;
          expand_string_message = search_error_message;
@@ -7792,19 +7800,19 @@ NOT_ITEM: ;
 
        else
          {
 
        else
          {
-         int n;
+         const lookup_info * li;
          uschar * opt = Ustrchr(arg, '_');
 
          if (opt) *opt++ = 0;
 
          uschar * opt = Ustrchr(arg, '_');
 
          if (opt) *opt++ = 0;
 
-         if ((n = search_findtype(arg, Ustrlen(arg))) < 0)
+         if (!(li = search_findtype(arg, Ustrlen(arg))))
            {
            expand_string_message = search_error_message;
            goto EXPAND_FAILED;
            }
 
            {
            expand_string_message = search_error_message;
            goto EXPAND_FAILED;
            }
 
-         if (lookup_list[n]->quote)
-           sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n);
+         if (li->quote)
+           sub = (li->quote)(sub, opt, li->acq_num);
          else if (opt)
            sub = NULL;
 
          else if (opt)
            sub = NULL;
 
index 9ae51d05b6578823135e2e968aa799c38ba3704a..b97895b8a5d2fccb8c93016aec033b4b416c598e 100644 (file)
@@ -338,6 +338,8 @@ extern int     ipv6_nmtoa(int *, uschar *);
 extern const uschar *local_part_quote(const uschar *);
 extern int     log_open_as_exim(const uschar * const);
 extern void    log_close_all(void);
 extern const uschar *local_part_quote(const uschar *);
 extern int     log_open_as_exim(const uschar * const);
 extern void    log_close_all(void);
+extern const lookup_info * lookup_with_acq_num(unsigned);
+
 
 extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
 extern BOOL    macro_read_assignment(uschar *);
 
 extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
 extern BOOL    macro_read_assignment(uschar *);
@@ -490,13 +492,15 @@ extern gstring * route_show_supported(gstring *);
 extern void    route_tidyup(void);
 extern uschar *router_current_name(void);
 
 extern void    route_tidyup(void);
 extern uschar *router_current_name(void);
 
-extern uschar *search_args(int, uschar *, uschar *, uschar **, const uschar *);
+extern uschar *search_args(const lookup_info *, uschar *, uschar *, uschar **,
+               const uschar *);
 extern uschar *search_find(void *, const uschar *, const uschar *, int,
                 const uschar *, int, int, int *, const uschar *);
 extern uschar *search_find(void *, const uschar *, const uschar *, int,
                 const uschar *, int, int, int *, const uschar *);
-extern int     search_findtype(const uschar *, int);
-extern int     search_findtype_partial(const uschar *, int *, const uschar **, int *,
-                 int *, const uschar **);
-extern void   *search_open(const uschar *, int, int, uid_t *, gid_t *);
+extern const lookup_info * search_findtype(const uschar *, int);
+extern const lookup_info * search_findtype_partial(const uschar *, int *,
+               const uschar **, int *, int *, const uschar **);
+extern void   *search_open(const uschar *, const lookup_info *, int,
+               uid_t *, gid_t *);
 extern void    search_tidyup(void);
 extern BOOL    send_fd_over_socket(int, int);
 extern uschar *sender_helo_verified_boolstr(void);
 extern void    search_tidyup(void);
 extern BOOL    send_fd_over_socket(int, int);
 extern uschar *sender_helo_verified_boolstr(void);
index 9731b7b5851c98f8e04b4bbb0a338139d490dab6..a542a179f243964f1c14792f2a13da7c8827c749 100644 (file)
@@ -729,8 +729,8 @@ extern uschar *log_selector_string;    /* As supplied in the config */
 extern FILE   *log_stderr;             /* Copy of stderr for log use, or NULL */
 extern BOOL    log_timezone;           /* TRUE to include the timezone in log lines */
 extern uschar *login_sender_address;   /* The actual sender address */
 extern FILE   *log_stderr;             /* Copy of stderr for log use, or NULL */
 extern BOOL    log_timezone;           /* TRUE to include the timezone in log lines */
 extern uschar *login_sender_address;   /* The actual sender address */
-extern lookup_info **lookup_list;      /* Array of pointers to available lookups */
-extern int     lookup_list_count;      /* Number of entries in the list */
+extern tree_node *lookups_tree;        /* Tree of available lookups */
+extern unsigned lookup_list_count;     /* Number of entries in the list */
 extern uschar *lookup_dnssec_authenticated; /* AD status of dns lookup */
 extern int     lookup_open_max;        /* Max lookup files to cache */
 extern uschar *lookup_value;           /* Value looked up from file */
 extern uschar *lookup_dnssec_authenticated; /* AD status of dns lookup */
 extern int     lookup_open_max;        /* Max lookup files to cache */
 extern uschar *lookup_value;           /* Value looked up from file */
index 62c8c0524b50db9df6c371461179ed7ecd305a58..af7bd51f6b95b1d6f3c98dac578d948bcc87fc66 100644 (file)
@@ -19,6 +19,7 @@
 typedef struct lookup_info {
   uschar *name;                   /* e.g. "lsearch" */
   int type;                       /* query/singlekey/abs-file */
 typedef struct lookup_info {
   uschar *name;                   /* e.g. "lsearch" */
   int type;                       /* query/singlekey/abs-file */
+  unsigned acq_num;              /* acquisition number */
   void *(*open)(                  /* open function */
     const uschar *,               /* file name for those that have one */
     uschar **);                   /* for error message */
   void *(*open)(                  /* open function */
     const uschar *,               /* file name for those that have one */
     uschar **);                   /* for error message */
index bf1e63325888dbcecb61631099111cc9c899291b..ee4099419a3ccb503d0bc994c98b66017970aca3 100644 (file)
@@ -1408,7 +1408,7 @@ Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
              only "dn" is recognized
   s          the string to be quoted
   opt        additional option text or NULL if none
              only "dn" is recognized
-  idx       lookup type index
+  idx       quoter identification number
 
 Returns:     the processed string or NULL for a bad option
 */
 
 Returns:     the processed string or NULL for a bad option
 */
index 3ccbe3353030a6d2a82e7d1a6efb3337fae8ca68..3bfcf51d5e2a3d0b75303d86751dde688c7f8ca6 100644 (file)
@@ -102,7 +102,7 @@ don't make the file descriptors two-way. */
 
 /* A macro to simplify testing bits in lookup types */
 
 
 /* A macro to simplify testing bits in lookup types */
 
-#define mac_islookup(a,b) ((lookup_list[a]->type & (b)) != 0)
+#define mac_islookup(li,b) ((li)->type & (b))
 
 /* Debugging control */
 
 
 /* Debugging control */
 
index 4f4f2c777bb940c0eeb052645be53c97d233953d..0b3632f7e49a06983cdb26a5eb88ca39c4404167 100644 (file)
@@ -96,7 +96,8 @@ check_string(void * arg, const uschar * pattern, const uschar ** valueptr,
   uschar ** error)
 {
 const check_string_block * cb = arg;
   uschar ** error)
 {
 const check_string_block * cb = arg;
-int search_type, partial, affixlen, starflags;
+int partial, affixlen, starflags;
+const lookup_info * li;
 int expand_setup = cb->expand_setup;
 const uschar * affix, * opts;
 uschar *s;
 int expand_setup = cb->expand_setup;
 const uschar * affix, * opts;
 uschar *s;
@@ -268,11 +269,10 @@ if ((semicolon = Ustrchr(pattern, ';')) == NULL)
 the part of the string preceding the semicolon. */
 
 *semicolon = 0;
 the part of the string preceding the semicolon. */
 
 *semicolon = 0;
-search_type = search_findtype_partial(pattern, &partial, &affix, &affixlen,
+li = search_findtype_partial(pattern, &partial, &affix, &affixlen,
   &starflags, &opts);
 *semicolon = ';';
   &starflags, &opts);
 *semicolon = ';';
-if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
-  search_error_message);
+if (!li) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 
 /* Partial matching is not appropriate for certain lookups (e.g. when looking
 up user@domain for sender rejection). There's a flag to disable it. */
 
 /* Partial matching is not appropriate for certain lookups (e.g. when looking
 up user@domain for sender rejection). There's a flag to disable it. */
@@ -281,13 +281,13 @@ if (!(cb->flags & MCS_PARTIAL)) partial = -1;
 
 /* Set the parameters for the three different kinds of lookup. */
 
 
 /* Set the parameters for the three different kinds of lookup. */
 
-keyquery = search_args(search_type, s, semicolon+1, &filename, opts);
+keyquery = search_args(li, s, semicolon+1, &filename, opts);
 
 /* Now do the actual lookup; throw away the data returned unless it was asked
 for; partial matching is all handled inside search_find(). Note that there is
 no search_close() because of the caching arrangements. */
 
 
 /* Now do the actual lookup; throw away the data returned unless it was asked
 for; partial matching is all handled inside search_find(). Note that there is
 no search_close() because of the caching arrangements. */
 
-if (!(handle = search_open(filename, search_type, 0, NULL, NULL)))
+if (!(handle = search_open(filename, li, 0, NULL, NULL)))
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 result = search_find(handle, filename, keyquery, partial, affix, affixlen,
   starflags, &expand_setup, opts);
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 result = search_find(handle, filename, keyquery, partial, affix, affixlen,
   starflags, &expand_setup, opts);
index 1c501455eb2842f3c6caeadfc1613faeb4bec4ee..5078920f154b11448eb9c059fbc54c4b15c2cd59 100644 (file)
@@ -59,44 +59,25 @@ Arguments:
   name       lookup type name - not necessarily zero terminated (e.g. dbm*)
   len        length of the name
 
   name       lookup type name - not necessarily zero terminated (e.g. dbm*)
   len        length of the name
 
-Returns:     +ve => valid lookup name; value is offset in lookup_list
-             -ve => invalid name; message in search_error_message.
+Returns:     ptr to info struct for the lookup,
+            or NULL with message in search_error_message.
 */
 
 */
 
-int
+const lookup_info *
 search_findtype(const uschar * name, int len)
 {
 search_findtype(const uschar * name, int len)
 {
-for (int bot = 0, top = lookup_list_count; top > bot; )
-  {
-  int mid = (top + bot)/2;
-  int c = Ustrncmp(name, lookup_list[mid]->name, len);
-
-  /* If c == 0 we have matched the incoming name with the start of the search
-  type name. However, some search types are substrings of others (e.g. nis and
-  nisplus) so we need to check that the lengths are the same. The length of the
-  type name cannot be shorter (else c would not be 0); if it is not equal it
-  must be longer, and in that case, the incoming name comes before the name we
-  are testing. By leaving c == 0 when the lengths are different, and doing a
-  > 0 test below, this all falls out correctly. */
-
-  if (c == 0 && Ustrlen(lookup_list[mid]->name) == len)
-    {
-    if (lookup_list[mid]->find != NULL) return mid;
-    search_error_message  = string_sprintf("lookup type \"%.*s\" is not "
-      "available (not in the binary - check buildtime LOOKUP configuration)",
-      len, name);
-    return -1;
-    }
+const uschar * s = name[len] ? string_copyn(name, len) : name;
+tree_node * t = tree_search(lookups_tree, s);
 
 
-  if (c > 0) bot = mid + 1; else top = mid;
-  }
+if (t) return t->data.ptr;
 
 
-search_error_message = string_sprintf("unknown lookup type \"%.*s\"", len, name);
-return -1;
+search_error_message = string_sprintf("unknown lookup type \"%s\"", s);
+return NULL;
 }
 
 
 
 }
 
 
 
+
 /*************************************************
 *       Validate a full lookup type name         *
 *************************************************/
 /*************************************************
 *       Validate a full lookup type name         *
 *************************************************/
@@ -117,18 +98,17 @@ Arguments:
   starflags    where to put the SEARCH_STAR and SEARCH_STARAT flags
   opts        where to put the options
 
   starflags    where to put the SEARCH_STAR and SEARCH_STARAT flags
   opts        where to put the options
 
-Returns:     +ve => valid lookup name; value is offset in lookup_list
-             -ve => invalid name; message in search_error_message.
+Returns:     ptr to info struct for the lookup,
+            or NULL with message in search_error_message.
 */
 
 */
 
-int
+const lookup_info *
 search_findtype_partial(const uschar *name, int *ptypeptr, const uschar **ptypeaff,
   int *afflen, int *starflags, const uschar ** opts)
 {
 search_findtype_partial(const uschar *name, int *ptypeptr, const uschar **ptypeaff,
   int *afflen, int *starflags, const uschar ** opts)
 {
-int len, stype;
-int pv = -1;
-const uschar *ss = name;
-const uschar * t;
+const lookup_info * li;
+int pv = -1, len;
+const uschar * ss = name, * t;
 
 *starflags = 0;
 *ptypeaff = NULL;
 
 *starflags = 0;
 *ptypeaff = NULL;
@@ -165,7 +145,7 @@ if (Ustrncmp(name, "partial", 7) == 0)
     BAD_TYPE:
     search_error_message = string_sprintf("format error in lookup type \"%s\"",
       name);
     BAD_TYPE:
     search_error_message = string_sprintf("format error in lookup type \"%s\"",
       name);
-    return -1;
+    return NULL;
     }
   }
 
     }
   }
 
@@ -194,31 +174,31 @@ else
 binary are valid. For query-style types, "partial" and default types are
 erroneous. */
 
 binary are valid. For query-style types, "partial" and default types are
 erroneous. */
 
-stype = search_findtype(ss, len);
-if (stype >= 0 && mac_islookup(stype, lookup_querystyle))
+li = search_findtype(ss, len);
+if (li && mac_islookup(li, lookup_querystyle))
   {
   if (pv >= 0)
     {
     search_error_message = string_sprintf("\"partial\" is not permitted "
       "for lookup type \"%s\"", ss);
   {
   if (pv >= 0)
     {
     search_error_message = string_sprintf("\"partial\" is not permitted "
       "for lookup type \"%s\"", ss);
-    return -1;
+    return NULL;
     }
   if ((*starflags & (SEARCH_STAR|SEARCH_STARAT)) != 0)
     {
     search_error_message = string_sprintf("defaults using \"*\" or \"*@\" are "
       "not permitted for lookup type \"%s\"", ss);
     }
   if ((*starflags & (SEARCH_STAR|SEARCH_STARAT)) != 0)
     {
     search_error_message = string_sprintf("defaults using \"*\" or \"*@\" are "
       "not permitted for lookup type \"%s\"", ss);
-    return -1;
+    return NULL;
     }
   }
 
 *ptypeptr = pv;
     }
   }
 
 *ptypeptr = pv;
-return stype;
+return li;
 }
 
 
 /* Set the parameters for the three different kinds of lookup.
 Arguments:
 }
 
 
 /* Set the parameters for the three different kinds of lookup.
 Arguments:
search_type   the search-type code
li            the info block for the search type
  search                the search-type string
  query         argument for the search; filename or query
  fnamep                pointer to return filename
  search                the search-type string
  query         argument for the search; filename or query
  fnamep                pointer to return filename
@@ -227,11 +207,11 @@ Arguments:
 Return:        keyquery        the search-type (for single-key) or query (for query-type)
  */
 uschar *
 Return:        keyquery        the search-type (for single-key) or query (for query-type)
  */
 uschar *
-search_args(int search_type, uschar * search, uschar * query, uschar ** fnamep,
+search_args(const lookup_info * li, uschar * search, uschar * query, uschar ** fnamep,
   const uschar * opts)
 {
 Uskip_whitespace(&query);
   const uschar * opts)
 {
 Uskip_whitespace(&query);
-if (mac_islookup(search_type, lookup_absfilequery))
+if (mac_islookup(li, lookup_absfilequery))
   {                                    /* query-style but with file (sqlite) */
   int sep = ',';
 
   {                                    /* query-style but with file (sqlite) */
   int sep = ',';
 
@@ -255,7 +235,7 @@ if (mac_islookup(search_type, lookup_absfilequery))
     *fnamep = NULL;
   return query;                /* remainder after file skipped */
   }
     *fnamep = NULL;
   return query;                /* remainder after file skipped */
   }
-if (!mac_islookup(search_type, lookup_querystyle))
+if (!mac_islookup(li, lookup_querystyle))
   {                                    /* single-key */
   *fnamep = query;
   return search;       /* modifiers important so use "keyquery" for them */
   {                                    /* single-key */
   *fnamep = query;
   return search;       /* modifiers important so use "keyquery" for them */
@@ -288,11 +268,19 @@ Returns:     nothing
 static void
 tidyup_subtree(tree_node *t)
 {
 static void
 tidyup_subtree(tree_node *t)
 {
-search_cache * c = (search_cache *)(t->data.ptr);
+search_cache * c = (search_cache *)t->data.ptr;
 if (t->left)  tidyup_subtree(t->left);
 if (t->right) tidyup_subtree(t->right);
 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);
+if (c && c->handle && c->li->close)
+  c->li->close(c->handle);
+}
+
+
+static void
+tidy_cb(uschar * name, uschar * ptr, void * ctx)
+{
+lookup_info * li = (lookup_info *)ptr;
+if (li->tidy) (li->tidy)();
 }
 
 
 }
 
 
@@ -322,8 +310,7 @@ open_filecount = 0;
 
 /* Call the general tidyup entry for any drivers that have one. */
 
 
 /* Call the general tidyup entry for any drivers that have one. */
 
-for (int i = 0; i < lookup_list_count; i++) if (lookup_list[i]->tidy)
-  (lookup_list[i]->tidy)();
+tree_walk(lookups_tree, tidy_cb, NULL);
 
 if (search_reset_point) search_reset_point = store_reset(search_reset_point);
 store_pool = old_pool;
 
 if (search_reset_point) search_reset_point = store_reset(search_reset_point);
 store_pool = old_pool;
@@ -366,7 +353,7 @@ but is marked closed.
 Arguments:
   filename       the name of the file for single-key+file style lookups,
                  NULL for query-style lookups
 Arguments:
   filename       the name of the file for single-key+file style lookups,
                  NULL for query-style lookups
-  search_type    the type of search required
+  li            the info block for the type of search required
   modemask       if a real single file is used, this specifies mode bits that
                  must not be set; otherwise it is ignored
   owners         if a real single file is used, this specifies the possible
   modemask       if a real single file is used, this specifies mode bits that
                  must not be set; otherwise it is ignored
   owners         if a real single file is used, this specifies the possible
@@ -381,13 +368,12 @@ Returns:         an identifying handle for the open database;
 */
 
 void *
 */
 
 void *
-search_open(const uschar * filename, int search_type, int modemask,
+search_open(const uschar * filename, const lookup_info * li, int modemask,
   uid_t * owners, gid_t * owngroups)
 {
 void *handle;
 tree_node *t;
 search_cache *c;
   uid_t * owners, gid_t * owngroups)
 {
 void *handle;
 tree_node *t;
 search_cache *c;
-lookup_info *lk = lookup_list[search_type];
 uschar keybuffer[256];
 int old_pool = store_pool;
 
 uschar keybuffer[256];
 int old_pool = store_pool;
 
@@ -403,7 +389,7 @@ if (filename && is_tainted(filename))
 store_pool = POOL_SEARCH;
 if (!search_reset_point) search_reset_point = store_mark();
 
 store_pool = POOL_SEARCH;
 if (!search_reset_point) search_reset_point = store_mark();
 
-DEBUG(D_lookup) debug_printf_indent("search_open: %s \"%s\"\n", lk->name,
+DEBUG(D_lookup) debug_printf_indent("search_open: %s \"%s\"\n", li->name,
   filename ? filename : US"NULL");
 
 /* See if we already have this open for this type of search, and if so,
   filename ? filename : US"NULL");
 
 /* See if we already have this open for this type of search, and if so,
@@ -411,7 +397,7 @@ pass back the tree block as the handle. The key for the tree node is the search
 type plus '0' concatenated with the file name. There may be entries in the tree
 with closed files if a lot of files have been opened. */
 
 type plus '0' concatenated with the file name. There may be entries in the tree
 with closed files if a lot of files have been opened. */
 
-sprintf(CS keybuffer, "%c%.254s", search_type + '0',
+sprintf(CS keybuffer, "%c%.254s", li->acq_num+ '0',
   filename ? filename : US"");
 
 if ((t = tree_search(search_tree, keybuffer)))
   filename ? filename : US"");
 
 if ((t = tree_search(search_tree, keybuffer)))
@@ -431,7 +417,7 @@ this, if the search type is one that uses real files, check on the number that
 we are holding open in the cache. If the limit is reached, close the least
 recently used one. */
 
 we are holding open in the cache. If the limit is reached, close the least
 recently used one. */
 
-if (lk->type == lookup_absfile && open_filecount >= lookup_open_max)
+if (li->type == lookup_absfile && open_filecount >= lookup_open_max)
   if (!open_bot)
     log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find "
       "one to close");
   if (!open_bot)
     log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find "
       "one to close");
@@ -444,7 +430,7 @@ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max)
       ((search_cache *)(open_bot->data.ptr))->down = NULL;
     else
       open_top = NULL;
       ((search_cache *)(open_bot->data.ptr))->down = NULL;
     else
       open_top = NULL;
-    ((lookup_list[c->search_type])->close)(c->handle);
+    ((c->li)->close)(c->handle);
     c->handle = NULL;
     open_filecount--;
     }
     c->handle = NULL;
     open_filecount--;
     }
@@ -452,24 +438,24 @@ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max)
 /* If opening is successful, call the file-checking function if there is one,
 and if all is still well, enter the open database into the tree. */
 
 /* If opening is successful, call the file-checking function if there is one,
 and if all is still well, enter the open database into the tree. */
 
-if (!(handle = (lk->open)(filename, &search_error_message)))
+if (!(handle = (li->open)(filename, &search_error_message)))
   {
   store_pool = old_pool;
   return NULL;
   }
 
   {
   store_pool = old_pool;
   return NULL;
   }
 
-if (  lk->check
-   && !lk->check(handle, filename, modemask, owners, owngroups,
+if (  li->check
+   && !li->check(handle, filename, modemask, owners, owngroups,
         &search_error_message))
   {
         &search_error_message))
   {
-  lk->close(handle);
+  li->close(handle);
   store_pool = old_pool;
   return NULL;
   }
 
 /* If this is a search type that uses real files, keep count. */
 
   store_pool = old_pool;
   return NULL;
   }
 
 /* If this is a search type that uses real files, keep count. */
 
-if (lk->type == lookup_absfile) open_filecount++;
+if (li->type == lookup_absfile) open_filecount++;
 
 /* If we found a previously opened entry in the tree, re-use it; otherwise
 insert a new entry. On re-use, leave any cached lookup data and the lookup
 
 /* If we found a previously opened entry in the tree, re-use it; otherwise
 insert a new entry. On re-use, leave any cached lookup data and the lookup
@@ -486,7 +472,7 @@ if (!t)
 else c = t->data.ptr;
 
 c->handle = handle;
 else c = t->data.ptr;
 
 c->handle = handle;
-c->search_type = search_type;
+c->li = li;
 c->up = c->down = NULL;
 
 store_pool = old_pool;
 c->up = c->down = NULL;
 
 store_pool = old_pool;
@@ -525,9 +511,10 @@ internal_search_find(void * handle, const uschar * filename,
 {
 tree_node * t = (tree_node *)handle;
 search_cache * c = (search_cache *)(t->data.ptr);
 {
 tree_node * t = (tree_node *)handle;
 search_cache * c = (search_cache *)(t->data.ptr);
+const lookup_info * li = c->li;
 expiring_data * e = NULL;      /* compiler quietening */
 uschar * data = NULL;
 expiring_data * e = NULL;      /* compiler quietening */
 uschar * data = NULL;
-int search_type = t->name[0] - '0';
+int quoter_id = li->acq_num;
 int old_pool = store_pool;
 
 /* Lookups that return DEFER may not always set an error message. So that
 int old_pool = store_pool;
 
 /* Lookups that return DEFER may not always set an error message. So that
@@ -538,8 +525,7 @@ f.search_find_defer = FALSE;
 
 DEBUG(D_lookup) debug_printf_indent("internal_search_find: file=\"%s\"\n  "
   "type=%s key=\"%s\" opts=%s%s%s\n", filename,
 
 DEBUG(D_lookup) debug_printf_indent("internal_search_find: file=\"%s\"\n  "
   "type=%s key=\"%s\" opts=%s%s%s\n", filename,
-  lookup_list[search_type]->name, keystring,
-  opts ? "\"" : "", opts, opts ? "\"" : "");
+  li->name, keystring, opts ? "\"" : "", opts, opts ? "\"" : "");
 
 /* Insurance. If the keystring is empty, just fail. */
 
 
 /* Insurance. If the keystring is empty, just fail. */
 
@@ -591,11 +577,11 @@ else
 
   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.
 
   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.
+  Passing quoter_id down that far is an issue.
   */
 
   */
 
-  if (  !filename && lookup_list[search_type]->quote
-     && is_tainted(keystring) && !is_quoted_like(keystring, search_type))
+  if (  !filename && li->quote
+     && is_tainted(keystring) && !is_quoted_like(keystring, quoter_id))
     {
     const uschar * ks = keystring;
     uschar * loc = acl_current_verb();
     {
     const uschar * ks = keystring;
     uschar * loc = acl_current_verb();
@@ -628,9 +614,12 @@ else
     DEBUG(D_lookup)
       {
       int q = quoter_for_address(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");
+      const lookup_info * qli = lookup_with_acq_num(q);
+
+      debug_printf_indent("quoter_id %d (%s) quoting %d (%s)\n",
+       quoter_id, li->name,
+       q,
+       is_real_quoter(q) ? qli ? qli->name : US"???" : US"none");
       }
 #endif
     }
       }
 #endif
     }
@@ -639,7 +628,7 @@ else
   like FAIL, except that search_find_defer is set so the caller can
   distinguish if necessary. */
 
   like FAIL, except that search_find_defer is set so the caller can
   distinguish if necessary. */
 
-  if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
+  if (li->find(c->handle, filename, keystring, keylength,
          &data, &search_error_message, &do_cache, opts) == DEFER)
     f.search_find_defer = TRUE;
 
          &data, &search_error_message, &do_cache, opts) == DEFER)
     f.search_find_defer = TRUE;
 
@@ -768,33 +757,36 @@ if (opts)
 /* Arrange to put this database at the top of the LRU chain if it is a type
 that opens real files. */
 
 /* Arrange to put this database at the top of the LRU chain if it is a type
 that opens real files. */
 
-if (  open_top != (tree_node *)handle 
-   && lookup_list[t->name[0]-'0']->type == lookup_absfile)
+if (open_top != (tree_node *)handle)
   {
   {
-  search_cache *c = (search_cache *)(t->data.ptr);
-  tree_node *up = c->up;
-  tree_node *down = c->down;
+  const lookup_info * li = lookup_with_acq_num(t->name[0]-'0');
+  if (li && li->type == lookup_absfile)
+    {
+    search_cache *c = (search_cache *)(t->data.ptr);
+    tree_node *up = c->up;
+    tree_node *down = c->down;
 
 
-  /* Cut it out of the list. A newly opened file will a NULL up pointer.
-  Otherwise there will be a non-NULL up pointer, since we checked above that
-  this block isn't already at the top of the list. */
+    /* Cut it out of the list. A newly opened file will a NULL up pointer.
+    Otherwise there will be a non-NULL up pointer, since we checked above that
+    this block isn't already at the top of the list. */
 
 
-  if (up)
-    {
-    ((search_cache *)(up->data.ptr))->down = down;
-    if (down)
-      ((search_cache *)(down->data.ptr))->up = up;
-    else
-      open_bot = up;
-    }
+    if (up)
+      {
+      ((search_cache *)(up->data.ptr))->down = down;
+      if (down)
+       ((search_cache *)(down->data.ptr))->up = up;
+      else
+       open_bot = up;
+      }
 
 
-  /* Now put it at the head of the list. */
+    /* Now put it at the head of the list. */
 
 
-  c->up = NULL;
-  c->down = open_top;
-  if (!open_top) open_bot = t;
-  else ((search_cache *)(open_top->data.ptr))->up = t;
-  open_top = t;
+    c->up = NULL;
+    c->down = open_top;
+    if (!open_top) open_bot = t;
+    else ((search_cache *)(open_top->data.ptr))->up = t;
+    open_top = t;
+    }
   }
 
 DEBUG(D_lookup)
   }
 
 DEBUG(D_lookup)
index 4ee1455d06e614f1e5e35bba0102f296725abb6f..76b2f615b2fcebd661a73508ba989f24bbf0ea35 100644 (file)
@@ -518,15 +518,15 @@ for (;;)
     for (s = ++var; *s != ')'; ) s++;
 #ifndef COMPILE_UTILITY
       {
     for (s = ++var; *s != ')'; ) s++;
 #ifndef COMPILE_UTILITY
       {
-      int idx;
-      if ((idx = search_findtype(var, s - var)) < 0)
+      const lookup_info * li;
+      if (!(li= search_findtype(var, s - var)))
        {
        DEBUG(D_any)
          debug_printf("Unrecognised quoter %.*s\n", (int)(s - var), var+1);
        where = NULL;
        goto SPOOL_FORMAT_ERROR;
        }
        {
        DEBUG(D_any)
          debug_printf("Unrecognised quoter %.*s\n", (int)(s - var), var+1);
        where = NULL;
        goto SPOOL_FORMAT_ERROR;
        }
-      proto_mem = store_get_quoted(1, GET_TAINTED, idx);
+      proto_mem = store_get_quoted(1, GET_TAINTED, li->acq_num);
       }
 #endif  /* COMPILE_UTILITY */
     var = s + 1;
       }
 #endif  /* COMPILE_UTILITY */
     var = s + 1;
index 574aa167fc4b1b4cfa5135ea818c8770b1f75727..e1972aa4400d278227667ddb5679707fa3a079df 100644 (file)
@@ -126,7 +126,11 @@ if (is_tainted(val))
   {
   int q = quoter_for_address(val);
   putc('-', fp);
   {
   int q = quoter_for_address(val);
   putc('-', fp);
-  if (is_real_quoter(q)) fprintf(fp, "(%s)", lookup_list[q]->name);
+  if (is_real_quoter(q))
+    {
+    const lookup_info * li = lookup_with_acq_num(q);
+    fprintf(fp, "(%s)", li ? li->name : US"unknown!");
+    }
   }
 fprintf(fp, "%s %s\n", name, val);
 }
   }
 fprintf(fp, "%s %s\n", name, val);
 }
index 181e7fd6751296c8e2e9e8f2759608a13d188f28..09f812dfd824dec947b22d8a4e93bf0d1caec692 100644 (file)
@@ -651,8 +651,11 @@ BOOL
 is_quoted_like(const void * p, unsigned quoter)
 {
 int pq = quoter_for_address(p);
 is_quoted_like(const void * p, unsigned quoter)
 {
 int pq = quoter_for_address(p);
-BOOL y =
-  is_real_quoter(pq) && lookup_list[pq]->quote == lookup_list[quoter]->quote;
+const lookup_info * p_li = lookup_with_acq_num(pq);
+void * p_qfn = p_li ? p_li->quote : NULL;
+const lookup_info * q_li = lookup_with_acq_num(quoter);
+void * q_qfn = q_li ? q_li->quote : NULL;
+BOOL y = is_real_quoter(pq) && p_qfn == q_qfn;
 /* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
 return y;
 }
 /* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
 return y;
 }
@@ -1254,8 +1257,10 @@ DEBUG(D_memory)
  for (quoted_pooldesc * qp = quoted_pools; qp; i++, qp = qp->next)
    {
    pooldesc * pp = &qp->pool;
  for (quoted_pooldesc * qp = quoted_pools; qp; i++, qp = qp->next)
    {
    pooldesc * pp = &qp->pool;
+   const lookup_info* li = lookup_with_acq_num(qp->quoter);
    debug_printf("----Exit  pool Q%d max: %3d kB in %d blocks at order %u\ttainted quoted:%s\n",
    debug_printf("----Exit  pool Q%d max: %3d kB in %d blocks at order %u\ttainted quoted:%s\n",
-    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder, lookup_list[qp->quoter]->name);
+    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder,
+    li ? li->name : US"???");
    }
  }
 #endif
    }
  }
 #endif
@@ -1297,7 +1302,11 @@ debug_print_taint(const void * p)
 int q = quoter_for_address(p);
 if (!is_tainted(p)) return;
 debug_printf("(tainted");
 int q = quoter_for_address(p);
 if (!is_tainted(p)) return;
 debug_printf("(tainted");
-if (is_real_quoter(q)) debug_printf(", quoted:%s", lookup_list[q]->name);
+if (is_real_quoter(q))
+  {
+  const lookup_info * li = lookup_with_acq_num(q);
+  debug_printf(", quoted:%s", li ? li->name : US"???");
+  }
 debug_printf(")\n");
 }
 #endif
 debug_printf(")\n");
 }
 #endif
index ffcd8a5dfe9b1ce597f87e6962d38f55b7ea8882..702c7c72c8adf25f44f08d0cc6678699ac825be7 100644 (file)
@@ -742,7 +742,7 @@ to close. */
 
 typedef struct search_cache {
   void   *handle;                 /* lookup handle, or NULL if closed */
 
 typedef struct search_cache {
   void   *handle;                 /* lookup handle, or NULL if closed */
-  int search_type;                /* search type */
+  const lookup_info *li;         /* info struct for search type */
   tree_node *up;                  /* LRU up pointer */
   tree_node *down;                /* LRU down pointer */
   tree_node *item_cache;          /* tree of cached results */
   tree_node *up;                  /* LRU up pointer */
   tree_node *down;                /* LRU down pointer */
   tree_node *item_cache;          /* tree of cached results */
index 8f73a46aa65394037f0dc6f5a120a8fae4f70bf0..5cb44b01d822587983970659b8841d2665287998 100644 (file)
@@ -191,7 +191,7 @@ node->balance = 0;
 
 /* Deal with an empty tree */
 
 
 /* Deal with an empty tree */
 
-if (p == NULL)
+if (!p)
   {
   *treebase = node;
   return TRUE;
   {
   *treebase = node;
   return TRUE;
@@ -214,9 +214,9 @@ for (;;)
   /* Deal with climbing down the tree, exiting from the loop
   when we reach a leaf. */
 
   /* Deal with climbing down the tree, exiting from the loop
   when we reach a leaf. */
 
-  q = (c > 0)? &(p->right) : &(p->left);
+  q = c > 0 ? &p->right : &p->left;
   p = *q;
   p = *q;
-  if (p == NULL) break;
+  if (!p) break;
 
   /* Save the address of the pointer to the last node en route
   which has a non-zero balance factor. */
 
   /* Save the address of the pointer to the last node en route
   which has a non-zero balance factor. */
index 3f307122377b0d4e928ffe6cf01e8b001aec85a7..f936de50a761555fca95ab628f10d7e796371dc8 100644 (file)
@@ -3060,7 +3060,7 @@ else
 if (iplookup)
   {
   int insize;
 if (iplookup)
   {
   int insize;
-  int search_type;
+  const lookup_info * li;
   int incoming[4];
   void *handle;
   uschar *filename, *key, *result;
   int incoming[4];
   void *handle;
   uschar *filename, *key, *result;
@@ -3068,10 +3068,8 @@ if (iplookup)
 
   /* Find the search type */
 
 
   /* Find the search type */
 
-  search_type = search_findtype(t, endname - t);
-
-  if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
-    search_error_message);
+  if (!(li = search_findtype(t, endname - t)))
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 
   /* Adjust parameters for the type of lookup. For a query-style lookup, there
   is no file name, and the "key" is just the query. For query-style with a file
 
   /* Adjust parameters for the type of lookup. For a query-style lookup, there
   is no file name, and the "key" is just the query. For query-style with a file
@@ -3081,7 +3079,7 @@ if (iplookup)
   dot separators instead of colons, except when the lookup type is "iplsearch".
   */
 
   dot separators instead of colons, except when the lookup type is "iplsearch".
   */
 
-  if (mac_islookup(search_type, lookup_absfilequery))
+  if (mac_islookup(li, lookup_absfilequery))
     {
     filename = semicolon + 1;
     key = filename;
     {
     filename = semicolon + 1;
     key = filename;
@@ -3089,14 +3087,14 @@ if (iplookup)
     filename = string_copyn(filename, key - filename);
     Uskip_whitespace(&key);
     }
     filename = string_copyn(filename, key - filename);
     Uskip_whitespace(&key);
     }
-  else if (mac_islookup(search_type, lookup_querystyle))
+  else if (mac_islookup(li, lookup_querystyle))
     {
     filename = NULL;
     key = semicolon + 1;
     }
   else   /* Single-key style */
     {
     {
     filename = NULL;
     key = semicolon + 1;
     }
   else   /* Single-key style */
     {
-    int sep = (Ustrcmp(lookup_list[search_type]->name, "iplsearch") == 0)?
+    int sep = (Ustrcmp(li->name, "iplsearch") == 0)?
       ':' : '.';
     insize = host_aton(cb->host_address, incoming);
     host_mask(insize, incoming, mlen);
       ':' : '.';
     insize = host_aton(cb->host_address, incoming);
     host_mask(insize, incoming, mlen);
@@ -3108,7 +3106,7 @@ if (iplookup)
   /* Now do the actual lookup; note that there is no search_close() because
   of the caching arrangements. */
 
   /* Now do the actual lookup; note that there is no search_close() because
   of the caching arrangements. */
 
-  if (!(handle = search_open(filename, search_type, 0, NULL, NULL)))
+  if (!(handle = search_open(filename, li, 0, NULL, NULL)))
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 
   result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL, opts);
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
 
   result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL, opts);
@@ -3182,20 +3180,21 @@ on spec. */
 if ((semicolon = Ustrchr(ss, ';')))
   {
   const uschar * affix, * opts;
 if ((semicolon = Ustrchr(ss, ';')))
   {
   const uschar * affix, * opts;
-  int partial, affixlen, starflags, id;
+  int partial, affixlen, starflags;
+  const lookup_info * li;
 
   *semicolon = 0;
 
   *semicolon = 0;
-  id = search_findtype_partial(ss, &partial, &affix, &affixlen, &starflags,
+  li = search_findtype_partial(ss, &partial, &affix, &affixlen, &starflags,
          &opts);
   *semicolon=';';
 
          &opts);
   *semicolon=';';
 
-  if (id < 0)                           /* Unknown lookup type */
+  if (!li)                             /* Unknown lookup type */
     {
     log_write(0, LOG_MAIN|LOG_PANIC, "%s in host list item \"%s\"",
       search_error_message, ss);
     return DEFER;
     }
     {
     log_write(0, LOG_MAIN|LOG_PANIC, "%s in host list item \"%s\"",
       search_error_message, ss);
     return DEFER;
     }
-  isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
+  isquery = mac_islookup(li, lookup_querystyle|lookup_absfilequery);
   }
 
 if (isquery)
   }
 
 if (isquery)
index 0c9f2808b94432f4a3ab636107edf79236ceeb01..ab8371942d7ca1b17dcbaa5d6ff822272a69507c 100755 (executable)
@@ -1234,7 +1234,7 @@ RESET_AFTER_EXTRA_LINE_READ:
     # Lookups have a char which depends on the number of lookup types compiled in,
     # in stderr output.  Replace with a "0".  Recognising this while avoiding
     # other output is fragile; perhaps the debug output should be revised instead.
     # Lookups have a char which depends on the number of lookup types compiled in,
     # in stderr output.  Replace with a "0".  Recognising this while avoiding
     # other output is fragile; perhaps the debug output should be revised instead.
-    s%^\s+(:?closing )?\K[0-?]TESTSUITE/aux-fixed/%0TESTSUITE/aux-fixed/%g;
+    s%^\s+(?:closing )?\K[0-Z]TESTSUITE/aux-fixed/%0TESTSUITE/aux-fixed/%g;
 
     # drop gnutls version strings
     next if /GnuTLS compile-time version: \d+[\.\d]+$/;
 
     # drop gnutls version strings
     next if /GnuTLS compile-time version: \d+[\.\d]+$/;
@@ -1471,7 +1471,7 @@ RESET_AFTER_EXTRA_LINE_READ:
       }
 
     # Different builds will have different lookup types included
       }
 
     # Different builds will have different lookup types included
-    s/search_type \K\d+ \((\w+)\) quoting -1 \(none\)$/NN ($1) quoting -1 (none)/;
+    s/quoter_id \K\d+ \((\w+)\) quoting -1 \(none\)$/NN ($1) quoting -1 (none)/;
     # and different numbers of lookup types result in different type-code letters,
     # so convert them all to "0"
     s%(?<!lsearch)[^ ](?=TESTSUITE/aux-fixed/(?:0414.list[12]|0464.domains)$)%0%;
     # and different numbers of lookup types result in different type-code letters,
     # so convert them all to "0"
     s%(?<!lsearch)[^ ](?=TESTSUITE/aux-fixed/(?:0414.list[12]|0464.domains)$)%0%;
index 93c24bf58f9e8ed79445c221f484f46d655fe21c..0f62df1c0b4a612b0f957c1f643df5a621fd13cd 100644 (file)
@@ -381,7 +381,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235                                (tainted)
 01:01:01 p1235  LOG: MAIN PANIC
 01:01:01 p1235    tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 26): select name from them where id = 'c'
 01:01:01 p1235                                (tainted)
 01:01:01 p1235  LOG: MAIN PANIC
 01:01:01 p1235    tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 26): select name from them where id = 'c'
-01:01:01 p1235   search_type NN (mysql) quoting -1 (none)
+01:01:01 p1235   quoter_id NN (mysql) quoting -1 (none)
 01:01:01 p1235   MySQL query: "select name from them where id = 'c'" opts 'no_rd'
 01:01:01 p1235   MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
 01:01:01 p1235   MYSQL: no data found
 01:01:01 p1235   MySQL query: "select name from them where id = 'c'" opts 'no_rd'
 01:01:01 p1235   MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
 01:01:01 p1235   MYSQL: no data found
@@ -540,7 +540,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235                                (tainted)
 01:01:01 p1235  LOG: MAIN PANIC
 01:01:01 p1235    tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 39): select name from them where id = 'c'
 01:01:01 p1235                                (tainted)
 01:01:01 p1235  LOG: MAIN PANIC
 01:01:01 p1235    tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 39): select name from them where id = 'c'
-01:01:01 p1235   search_type NN (mysql) quoting -1 (none)
+01:01:01 p1235   quoter_id NN (mysql) quoting -1 (none)
 01:01:01 p1235   MySQL query: "servers=127.0.0.1::PORT_N; select name from them where id = 'c'" opts 'NULL'
 01:01:01 p1235  LOG: MAIN
 01:01:01 p1235    Exim configuration error in line 89 of TESTSUITE/test-config:
 01:01:01 p1235   MySQL query: "servers=127.0.0.1::PORT_N; select name from them where id = 'c'" opts 'NULL'
 01:01:01 p1235  LOG: MAIN
 01:01:01 p1235    Exim configuration error in line 89 of TESTSUITE/test-config:
@@ -846,7 +846,7 @@ processing address_data
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
search_type NN (mysql) quoting -1 (none)
quoter_id NN (mysql) quoting -1 (none)
  MySQL query: "select name from them where id='ph10' limit 1" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
  creating new cache entry
  MySQL query: "select name from them where id='ph10' limit 1" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
  creating new cache entry
@@ -890,7 +890,7 @@ appendfile transport entered
                               (tainted)
 LOG: MAIN
   tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
                               (tainted)
 LOG: MAIN
   tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
search_type NN (mysql) quoting -1 (none)
quoter_id NN (mysql) quoting -1 (none)
  MySQL query: "select id from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=PORT_N socket=NULL database=test user=root
  creating new cache entry
  MySQL query: "select id from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=PORT_N socket=NULL database=test user=root
  creating new cache entry
index 7193592a98ab1c92cac9f3791230167c779c6b17..f0538e83f195f6662ec301ae0aba248c04f5fd2f 100644 (file)
@@ -295,7 +295,7 @@ check set acl_m0 = ok:   ${lookup pgsql                    {select name from the
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
search_type NN (pgsql) quoting -1 (none)
quoter_id NN (pgsql) quoting -1 (none)
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  PGSQL: no data found
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  PGSQL: no data found
@@ -490,7 +490,7 @@ check set acl_m0 = ok:   ${lookup pgsql                    {select name from the
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
                               (tainted)
 LOG: MAIN PANIC
   tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
search_type NN (pgsql) quoting -1 (none)
quoter_id NN (pgsql) quoting -1 (none)
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  PGSQL: no data found
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  PGSQL: no data found