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 =
567 store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
571 p->next = lookupmodules;
573 lookup_list_count += info->lookupcount;
576 /* only valid after lookup_list and lookup_list_count are assigned */
578 add_lookup_to_list(lookup_info *info)
580 /* need to add the lookup to lookup_list, sorted */
583 /* strategy is to go through the list until we find
584 either an empty spot or a name that is higher.
585 this can't fail because we have enough space. */
587 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
590 if (lookup_list[pos])
592 /* need to insert it, so move all the other items up
593 (last slot is still empty, of course) */
595 memmove(&lookup_list[pos+1], &lookup_list[pos],
596 sizeof(lookup_info *) * (lookup_list_count-pos-1));
598 lookup_list[pos] = info;
602 /* These need to be at file level for old versions of gcc (2.95.2 reported),
603 which give parse errors on an extern in function scope. Each entry needs
604 to also be invoked in init_lookup_list() below */
606 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
607 extern lookup_module_info cdb_lookup_module_info;
609 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
610 extern lookup_module_info dbmdb_lookup_module_info;
612 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
613 extern lookup_module_info dnsdb_lookup_module_info;
615 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
616 extern lookup_module_info dsearch_lookup_module_info;
618 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
619 extern lookup_module_info ibase_lookup_module_info;
621 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
622 extern lookup_module_info json_lookup_module_info;
624 #if defined(LOOKUP_LDAP)
625 extern lookup_module_info ldap_lookup_module_info;
627 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
628 extern lookup_module_info lsearch_lookup_module_info;
630 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
631 extern lookup_module_info mysql_lookup_module_info;
633 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
634 extern lookup_module_info nis_lookup_module_info;
636 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
637 extern lookup_module_info nisplus_lookup_module_info;
639 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
640 extern lookup_module_info oracle_lookup_module_info;
642 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
643 extern lookup_module_info passwd_lookup_module_info;
645 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
646 extern lookup_module_info pgsql_lookup_module_info;
648 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
649 extern lookup_module_info redis_lookup_module_info;
651 #if defined(LOOKUP_LMDB)
652 extern lookup_module_info lmdb_lookup_module_info;
654 #if defined(SUPPORT_SPF)
655 extern lookup_module_info spf_lookup_module_info;
657 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
658 extern lookup_module_info sqlite_lookup_module_info;
660 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
661 extern lookup_module_info testdb_lookup_module_info;
663 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
664 extern lookup_module_info whoson_lookup_module_info;
667 extern lookup_module_info readsock_lookup_module_info;
671 init_lookup_list(void)
673 #ifdef LOOKUP_MODULE_DIR
676 int countmodules = 0;
677 int moduleerrors = 0;
679 static BOOL lookup_list_init_done = FALSE;
682 if (lookup_list_init_done)
684 reset_point = store_mark();
685 lookup_list_init_done = TRUE;
687 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
688 addlookupmodule(NULL, &cdb_lookup_module_info);
691 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
692 addlookupmodule(NULL, &dbmdb_lookup_module_info);
695 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
696 addlookupmodule(NULL, &dnsdb_lookup_module_info);
699 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
700 addlookupmodule(NULL, &dsearch_lookup_module_info);
703 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
704 addlookupmodule(NULL, &ibase_lookup_module_info);
708 addlookupmodule(NULL, &ldap_lookup_module_info);
711 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
712 addlookupmodule(NULL, &json_lookup_module_info);
715 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
716 addlookupmodule(NULL, &lsearch_lookup_module_info);
719 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
720 addlookupmodule(NULL, &mysql_lookup_module_info);
723 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
724 addlookupmodule(NULL, &nis_lookup_module_info);
727 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
728 addlookupmodule(NULL, &nisplus_lookup_module_info);
731 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
732 addlookupmodule(NULL, &oracle_lookup_module_info);
735 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
736 addlookupmodule(NULL, &passwd_lookup_module_info);
739 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
740 addlookupmodule(NULL, &pgsql_lookup_module_info);
743 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
744 addlookupmodule(NULL, &redis_lookup_module_info);
748 addlookupmodule(NULL, &lmdb_lookup_module_info);
752 addlookupmodule(NULL, &spf_lookup_module_info);
755 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
756 addlookupmodule(NULL, &sqlite_lookup_module_info);
759 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
760 addlookupmodule(NULL, &testdb_lookup_module_info);
763 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
764 addlookupmodule(NULL, &whoson_lookup_module_info);
767 addlookupmodule(NULL, &readsock_lookup_module_info);
769 #ifdef LOOKUP_MODULE_DIR
770 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
772 DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
773 log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
777 const pcre2_code * regex_islookupmod = regex_must_compile(
778 US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
780 DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
781 while ((ent = readdir(dd)))
783 char * name = ent->d_name;
784 int len = (int)strlen(name);
785 if (regex_match(regex_islookupmod, US name, len, NULL))
787 int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
789 struct lookup_module_info *info;
790 const char *errormsg;
792 /* SRH: am I being paranoid here or what? */
793 if (pathnamelen > big_buffer_size)
795 fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
796 log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
800 /* SRH: snprintf here? */
801 sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
803 if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
805 errormsg = dlerror();
806 fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
807 log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
812 /* FreeBSD nsdispatch() can trigger dlerror() errors about
813 _nss_cache_cycle_prevention_function; we need to clear the dlerror()
814 state before calling dlsym(), so that any error afterwards only comes
817 errormsg = dlerror();
819 info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
820 if ((errormsg = dlerror()))
822 fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
823 log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
828 if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
830 fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
831 log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
837 addlookupmodule(dl, info);
838 DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
842 store_free((void*)regex_islookupmod);
846 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
849 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
851 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
852 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
854 /* now add all lookups to the real list */
855 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
856 for (int j = 0; j < p->info->lookupcount; j++)
857 add_lookup_to_list(p->info->lookups[j]);
858 store_reset(reset_point);
859 /* just to be sure */
860 lookupmodules = NULL;
863 #endif /*!MACRO_PREDEF*/
864 /* End of drtables.c */