1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2023 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
15 /* This module contains tables that define the lookup methods and drivers
16 that are actually included in the binary. Its contents are controlled by
17 various macros in config.h that ultimately come from Local/Makefile. They are
18 all described in src/EDITME. */
21 lookup_info **lookup_list;
22 int lookup_list_count = 0;
24 /* Table of information about all possible authentication mechanisms. All
25 entries are always present if any mechanism is declared, but the functions are
26 set to NULL for those that are not compiled into the binary. */
29 #include "auths/cram_md5.h"
32 #ifdef AUTH_CYRUS_SASL
33 #include "auths/cyrus_sasl.h"
37 #include "auths/dovecot.h"
41 #include "auths/external.h"
45 #include "auths/gsasl_exim.h"
48 #ifdef AUTH_HEIMDAL_GSSAPI
49 #include "auths/heimdal_gssapi.h"
53 #include "auths/plaintext.h"
57 #include "auths/spa.h"
61 #include "auths/tls.h"
64 auth_info auths_available[] = {
66 /* Checking by an expansion condition on plain text */
71 .driver_name = US"cram_md5", /* lookup name */
72 .options = auth_cram_md5_options,
73 .options_count = &auth_cram_md5_options_count,
74 .options_block = &auth_cram_md5_option_defaults,
75 .options_len = sizeof(auth_cram_md5_options_block),
76 .init = auth_cram_md5_init,
78 .servercode = auth_cram_md5_server,
79 .clientcode = auth_cram_md5_client,
80 .version_report = NULL,
81 .macros_create = NULL,
85 #ifdef AUTH_CYRUS_SASL
88 .driver_name = US"cyrus_sasl",
89 .options = auth_cyrus_sasl_options,
90 .options_count = &auth_cyrus_sasl_options_count,
91 .options_block = &auth_cyrus_sasl_option_defaults,
92 .options_len = sizeof(auth_cyrus_sasl_options_block),
93 .init = auth_cyrus_sasl_init,
95 .servercode = auth_cyrus_sasl_server,
97 .version_report = auth_cyrus_sasl_version_report,
98 .macros_create = NULL,
105 .driver_name = US"dovecot",
106 .options = auth_dovecot_options,
107 .options_count = &auth_dovecot_options_count,
108 .options_block = &auth_dovecot_option_defaults,
109 .options_len = sizeof(auth_dovecot_options_block),
110 .init = auth_dovecot_init,
112 .servercode = auth_dovecot_server,
114 .version_report = NULL,
115 .macros_create = NULL,
122 .driver_name = US"external",
123 .options = auth_external_options,
124 .options_count = &auth_external_options_count,
125 .options_block = &auth_external_option_defaults,
126 .options_len = sizeof(auth_external_options_block),
127 .init = auth_external_init,
129 .servercode = auth_external_server,
130 .clientcode = auth_external_client,
131 .version_report = NULL,
132 .macros_create = NULL,
139 .driver_name = US"gsasl",
140 .options = auth_gsasl_options,
141 .options_count = &auth_gsasl_options_count,
142 .options_block = &auth_gsasl_option_defaults,
143 .options_len = sizeof(auth_gsasl_options_block),
144 .init = auth_gsasl_init,
146 .servercode = auth_gsasl_server,
147 .clientcode = auth_gsasl_client,
148 .version_report = auth_gsasl_version_report,
149 .macros_create = auth_gsasl_macros,
153 #ifdef AUTH_HEIMDAL_GSSAPI
156 .driver_name = US"heimdal_gssapi",
157 .options = auth_heimdal_gssapi_options,
158 .options_count = &auth_heimdal_gssapi_options_count,
159 .options_block = &auth_heimdal_gssapi_option_defaults,
160 .options_len = sizeof(auth_heimdal_gssapi_options_block),
161 .init = auth_heimdal_gssapi_init,
163 .servercode = auth_heimdal_gssapi_server,
165 .version_report = auth_heimdal_gssapi_version_report,
166 .macros_create = NULL,
170 #ifdef AUTH_PLAINTEXT
173 .driver_name = US"plaintext",
174 .options = auth_plaintext_options,
175 .options_count = &auth_plaintext_options_count,
176 .options_block = &auth_plaintext_option_defaults,
177 .options_len = sizeof(auth_plaintext_options_block),
178 .init = auth_plaintext_init,
180 .servercode = auth_plaintext_server,
181 .clientcode = auth_plaintext_client,
182 .version_report = NULL,
183 .macros_create = NULL,
190 .driver_name = US"spa",
191 .options = auth_spa_options,
192 .options_count = &auth_spa_options_count,
193 .options_block = &auth_spa_option_defaults,
194 .options_len = sizeof(auth_spa_options_block),
195 .init = auth_spa_init,
197 .servercode = auth_spa_server,
198 .clientcode = auth_spa_client,
199 .version_report = NULL,
200 .macros_create = NULL,
207 .driver_name = US"tls",
208 .options = auth_tls_options,
209 .options_count = &auth_tls_options_count,
210 .options_block = &auth_tls_option_defaults,
211 .options_len = sizeof(auth_tls_options_block),
212 .init = auth_tls_init,
214 .servercode = auth_tls_server,
216 .version_report = NULL,
217 .macros_create = NULL,
221 { .drinfo = { .driver_name = US"" }} /* end marker */
225 /* Tables of information about which routers and transports are included in the
228 /* Pull in the necessary header files */
230 #include "routers/rf_functions.h"
233 # include "routers/accept.h"
236 #ifdef ROUTER_DNSLOOKUP
237 # include "routers/dnslookup.h"
240 #ifdef ROUTER_MANUALROUTE
241 # include "routers/manualroute.h"
244 #ifdef ROUTER_IPLITERAL
245 # include "routers/ipliteral.h"
248 #ifdef ROUTER_IPLOOKUP
249 # include "routers/iplookup.h"
252 #ifdef ROUTER_QUERYPROGRAM
253 # include "routers/queryprogram.h"
256 #ifdef ROUTER_REDIRECT
257 # include "routers/redirect.h"
260 #ifdef TRANSPORT_APPENDFILE
261 # include "transports/appendfile.h"
264 #ifdef TRANSPORT_AUTOREPLY
265 # include "transports/autoreply.h"
268 #ifdef TRANSPORT_LMTP
269 # include "transports/lmtp.h"
272 #ifdef TRANSPORT_PIPE
273 # include "transports/pipe.h"
276 #ifdef EXPERIMENTAL_QUEUEFILE
277 # include "transports/queuefile.h"
280 #ifdef TRANSPORT_SMTP
281 # include "transports/smtp.h"
285 /* Now set up the structures, terminated by an entry with a null name. */
287 router_info routers_available[] = {
291 .driver_name = US"accept",
292 .options = accept_router_options,
293 .options_count = &accept_router_options_count,
294 .options_block = &accept_router_option_defaults,
295 .options_len = sizeof(accept_router_options_block),
296 .init = accept_router_init,
298 .code = accept_router_entry,
299 .tidyup = NULL, /* no tidyup entry */
300 .ri_flags = ri_yestransport
303 #ifdef ROUTER_DNSLOOKUP
306 .driver_name = US"dnslookup",
307 .options = dnslookup_router_options,
308 .options_count = &dnslookup_router_options_count,
309 .options_block = &dnslookup_router_option_defaults,
310 .options_len = sizeof(dnslookup_router_options_block),
311 .init = dnslookup_router_init,
313 .code = dnslookup_router_entry,
314 .tidyup = NULL, /* no tidyup entry */
315 .ri_flags = ri_yestransport
318 #ifdef ROUTER_IPLITERAL
321 .driver_name = US"ipliteral",
322 .options = ipliteral_router_options,
323 .options_count = &ipliteral_router_options_count,
324 .options_block = &ipliteral_router_option_defaults,
325 .options_len = sizeof(ipliteral_router_options_block),
326 .init = ipliteral_router_init,
328 .code = ipliteral_router_entry,
329 .tidyup = NULL, /* no tidyup entry */
330 .ri_flags = ri_yestransport
333 #ifdef ROUTER_IPLOOKUP
336 .driver_name = US"iplookup",
337 .options = iplookup_router_options,
338 .options_count = &iplookup_router_options_count,
339 .options_block = &iplookup_router_option_defaults,
340 .options_len = sizeof(iplookup_router_options_block),
341 .init = iplookup_router_init,
343 .code = iplookup_router_entry,
344 .tidyup = NULL, /* no tidyup entry */
345 .ri_flags = ri_notransport
348 #ifdef ROUTER_MANUALROUTE
351 .driver_name = US"manualroute",
352 .options = manualroute_router_options,
353 .options_count = &manualroute_router_options_count,
354 .options_block = &manualroute_router_option_defaults,
355 .options_len = sizeof(manualroute_router_options_block),
356 .init = manualroute_router_init,
358 .code = manualroute_router_entry,
359 .tidyup = NULL, /* no tidyup entry */
363 #ifdef ROUTER_QUERYPROGRAM
366 .driver_name = US"queryprogram",
367 .options = queryprogram_router_options,
368 .options_count = &queryprogram_router_options_count,
369 .options_block = &queryprogram_router_option_defaults,
370 .options_len = sizeof(queryprogram_router_options_block),
371 .init = queryprogram_router_init,
373 .code = queryprogram_router_entry,
374 .tidyup = NULL, /* no tidyup entry */
378 #ifdef ROUTER_REDIRECT
381 .driver_name = US"redirect",
382 .options = redirect_router_options,
383 .options_count = &redirect_router_options_count,
384 .options_block = &redirect_router_option_defaults,
385 .options_len = sizeof(redirect_router_options_block),
386 .init = redirect_router_init,
388 .code = redirect_router_entry,
389 .tidyup = NULL, /* no tidyup entry */
390 .ri_flags = ri_notransport
393 { .drinfo = { .driver_name = US"" }}
398 transport_info transports_available[] = {
399 #ifdef TRANSPORT_APPENDFILE
402 .driver_name = US"appendfile",
403 .options = appendfile_transport_options,
404 .options_count = &appendfile_transport_options_count,
405 .options_block = &appendfile_transport_option_defaults, /* private options defaults */
406 .options_len = sizeof(appendfile_transport_options_block),
407 .init = appendfile_transport_init,
409 .code = appendfile_transport_entry,
415 #ifdef TRANSPORT_AUTOREPLY
418 .driver_name = US"autoreply",
419 .options = autoreply_transport_options,
420 .options_count = &autoreply_transport_options_count,
421 .options_block = &autoreply_transport_option_defaults,
422 .options_len = sizeof(autoreply_transport_options_block),
423 .init = autoreply_transport_init,
425 .code = autoreply_transport_entry,
431 #ifdef TRANSPORT_LMTP
434 .driver_name = US"lmtp",
435 .options = lmtp_transport_options,
436 .options_count = &lmtp_transport_options_count,
437 .options_block = &lmtp_transport_option_defaults,
438 .options_len = sizeof(lmtp_transport_options_block),
439 .init = lmtp_transport_init,
441 .code = lmtp_transport_entry,
447 #ifdef TRANSPORT_PIPE
450 .driver_name = US"pipe",
451 .options = pipe_transport_options,
452 .options_count = &pipe_transport_options_count,
453 .options_block = &pipe_transport_option_defaults,
454 .options_len = sizeof(pipe_transport_options_block),
455 .init = pipe_transport_init,
457 .code = pipe_transport_entry,
463 #ifdef EXPERIMENTAL_QUEUEFILE
466 .driver_name = US"queuefile",
467 .options = queuefile_transport_options,
468 .options_count = &queuefile_transport_options_count,
469 .options_block = &queuefile_transport_option_defaults,
470 .options_len = sizeof(queuefile_transport_options_block),
471 .init = queuefile_transport_init,
473 .code = queuefile_transport_entry,
479 #ifdef TRANSPORT_SMTP
482 .driver_name = US"smtp",
483 .options = smtp_transport_options,
484 .options_count = &smtp_transport_options_count,
485 .options_block = &smtp_transport_option_defaults,
486 .options_len = sizeof(smtp_transport_options_block),
487 .init = smtp_transport_init,
489 .code = smtp_transport_entry,
491 .closedown = smtp_transport_closedown,
495 { .drinfo = { .driver_name = US"" }}
501 auth_show_supported(gstring * g)
503 g = string_cat(g, US"Authenticators:");
504 for (auth_info * ai = auths_available; ai->drinfo.driver_name[0]; ai++)
505 g = string_fmt_append(g, " %s", ai->drinfo.driver_name);
506 return string_cat(g, US"\n");
510 route_show_supported(gstring * g)
512 g = string_cat(g, US"Routers:");
513 for (router_info * rr = routers_available; rr->drinfo.driver_name[0]; rr++)
514 g = string_fmt_append(g, " %s", rr->drinfo.driver_name);
515 return string_cat(g, US"\n");
519 transport_show_supported(gstring * g)
521 g = string_cat(g, US"Transports:");
522 #ifdef TRANSPORT_APPENDFILE
523 g = string_cat(g, US" appendfile");
524 #ifdef SUPPORT_MAILDIR
525 g = string_cat(g, US"/maildir"); /* damn these subclasses */
527 #ifdef SUPPORT_MAILSTORE
528 g = string_cat(g, US"/mailstore");
531 g = string_cat(g, US"/mbx");
534 #ifdef TRANSPORT_AUTOREPLY
535 g = string_cat(g, US" autoreply");
537 #ifdef TRANSPORT_LMTP
538 g = string_cat(g, US" lmtp");
540 #ifdef TRANSPORT_PIPE
541 g = string_cat(g, US" pipe");
543 #ifdef EXPERIMENTAL_QUEUEFILE
544 g = string_cat(g, US" queuefile");
546 #ifdef TRANSPORT_SMTP
547 g = string_cat(g, US" smtp");
549 return string_cat(g, US"\n");
554 struct lookupmodulestr
557 struct lookup_module_info *info;
558 struct lookupmodulestr *next;
561 static struct lookupmodulestr *lookupmodules = NULL;
564 addlookupmodule(void *dl, struct lookup_module_info *info)
566 struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
570 p->next = lookupmodules;
572 lookup_list_count += info->lookupcount;
575 /* only valid after lookup_list and lookup_list_count are assigned */
577 add_lookup_to_list(lookup_info *info)
579 /* need to add the lookup to lookup_list, sorted */
582 /* strategy is to go through the list until we find
583 either an empty spot or a name that is higher.
584 this can't fail because we have enough space. */
586 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
589 if (lookup_list[pos])
591 /* need to insert it, so move all the other items up
592 (last slot is still empty, of course) */
594 memmove(&lookup_list[pos+1], &lookup_list[pos],
595 sizeof(lookup_info *) * (lookup_list_count-pos-1));
597 lookup_list[pos] = info;
601 /* These need to be at file level for old versions of gcc (2.95.2 reported),
602 which give parse errors on an extern in function scope. Each entry needs
603 to also be invoked in init_lookup_list() below */
605 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
606 extern lookup_module_info cdb_lookup_module_info;
608 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
609 extern lookup_module_info dbmdb_lookup_module_info;
611 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
612 extern lookup_module_info dnsdb_lookup_module_info;
614 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
615 extern lookup_module_info dsearch_lookup_module_info;
617 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
618 extern lookup_module_info ibase_lookup_module_info;
620 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
621 extern lookup_module_info json_lookup_module_info;
623 #if defined(LOOKUP_LDAP)
624 extern lookup_module_info ldap_lookup_module_info;
626 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
627 extern lookup_module_info lsearch_lookup_module_info;
629 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
630 extern lookup_module_info mysql_lookup_module_info;
632 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
633 extern lookup_module_info nis_lookup_module_info;
635 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
636 extern lookup_module_info nisplus_lookup_module_info;
638 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
639 extern lookup_module_info oracle_lookup_module_info;
641 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
642 extern lookup_module_info passwd_lookup_module_info;
644 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
645 extern lookup_module_info pgsql_lookup_module_info;
647 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
648 extern lookup_module_info redis_lookup_module_info;
650 #if defined(LOOKUP_LMDB)
651 extern lookup_module_info lmdb_lookup_module_info;
653 #if defined(SUPPORT_SPF)
654 extern lookup_module_info spf_lookup_module_info;
656 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
657 extern lookup_module_info sqlite_lookup_module_info;
659 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
660 extern lookup_module_info testdb_lookup_module_info;
662 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
663 extern lookup_module_info whoson_lookup_module_info;
666 extern lookup_module_info readsock_lookup_module_info;
670 init_lookup_list(void)
672 #ifdef LOOKUP_MODULE_DIR
675 int countmodules = 0;
676 int moduleerrors = 0;
678 static BOOL lookup_list_init_done = FALSE;
681 if (lookup_list_init_done)
683 reset_point = store_mark();
684 lookup_list_init_done = TRUE;
686 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
687 addlookupmodule(NULL, &cdb_lookup_module_info);
690 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
691 addlookupmodule(NULL, &dbmdb_lookup_module_info);
694 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
695 addlookupmodule(NULL, &dnsdb_lookup_module_info);
698 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
699 addlookupmodule(NULL, &dsearch_lookup_module_info);
702 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
703 addlookupmodule(NULL, &ibase_lookup_module_info);
707 addlookupmodule(NULL, &ldap_lookup_module_info);
710 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
711 addlookupmodule(NULL, &json_lookup_module_info);
714 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
715 addlookupmodule(NULL, &lsearch_lookup_module_info);
718 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
719 addlookupmodule(NULL, &mysql_lookup_module_info);
722 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
723 addlookupmodule(NULL, &nis_lookup_module_info);
726 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
727 addlookupmodule(NULL, &nisplus_lookup_module_info);
730 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
731 addlookupmodule(NULL, &oracle_lookup_module_info);
734 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
735 addlookupmodule(NULL, &passwd_lookup_module_info);
738 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
739 addlookupmodule(NULL, &pgsql_lookup_module_info);
742 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
743 addlookupmodule(NULL, &redis_lookup_module_info);
747 addlookupmodule(NULL, &lmdb_lookup_module_info);
751 addlookupmodule(NULL, &spf_lookup_module_info);
754 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
755 addlookupmodule(NULL, &sqlite_lookup_module_info);
758 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
759 addlookupmodule(NULL, &testdb_lookup_module_info);
762 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
763 addlookupmodule(NULL, &whoson_lookup_module_info);
766 addlookupmodule(NULL, &readsock_lookup_module_info);
768 #ifdef LOOKUP_MODULE_DIR
769 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
771 DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
772 log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
776 const pcre2_code * regex_islookupmod = regex_must_compile(
777 US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
779 DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
780 while ((ent = readdir(dd)))
782 char * name = ent->d_name;
783 int len = (int)strlen(name);
784 if (regex_match(regex_islookupmod, US name, len, NULL))
786 int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
788 struct lookup_module_info *info;
789 const char *errormsg;
791 /* SRH: am I being paranoid here or what? */
792 if (pathnamelen > big_buffer_size)
794 fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
795 log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
799 /* SRH: snprintf here? */
800 sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
802 if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
804 errormsg = dlerror();
805 fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
806 log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
811 /* FreeBSD nsdispatch() can trigger dlerror() errors about
812 _nss_cache_cycle_prevention_function; we need to clear the dlerror()
813 state before calling dlsym(), so that any error afterwards only comes
816 errormsg = dlerror();
818 info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
819 if ((errormsg = dlerror()))
821 fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
822 log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
827 if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
829 fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
830 log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
836 addlookupmodule(dl, info);
837 DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
841 store_free((void*)regex_islookupmod);
845 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
848 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
850 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
851 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
853 /* now add all lookups to the real list */
854 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
855 for (int j = 0; j < p->info->lookupcount; j++)
856 add_lookup_to_list(p->info->lookups[j]);
857 store_reset(reset_point);
858 /* just to be sure */
859 lookupmodules = NULL;
862 #endif /*!MACRO_PREDEF*/
863 /* End of drtables.c */