9ed55e29a02c9bc64dad53d6f2801865eae81e3a
[exim.git] / src / src / drtables.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
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 */
9
10
11 #include "exim.h"
12
13 #include <string.h>
14
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. */
19
20
21 //lookup_info **lookup_list;
22 tree_node * lookups_tree = NULL;
23 unsigned lookup_list_count = 0;
24
25 /* Lists of information about which drivers are included in the exim binary. */
26
27 auth_info * auths_available= NULL;
28 router_info * routers_available = NULL;
29 transport_info * transports_available = NULL;
30
31
32
33 #ifndef MACRO_PREDEF
34
35 gstring *
36 auth_show_supported(gstring * g)
37 {
38 uschar * b = US""               /* static-build authenticatornames */
39 #if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5!=2
40   " cram_md5"
41 #endif
42 #if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL!=2
43   " cyrus_sasl"
44 #endif
45 #if defined(AUTH_DOVECOT) && AUTH_DOVECOT!=2
46   " dovecot"
47 #endif
48 #if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL!=2
49   " external"
50 #endif
51 #if defined(AUTH_GSASL) && AUTH_GSASL!=2
52   " gsasl"
53 #endif
54 #if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI!=2
55   " heimdal_gssapi"
56 #endif
57 #if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT!=2
58   " plaintext"
59 #endif
60 #if defined(AUTH_SPA) && AUTH_SPA!=2
61   " spa"
62 #endif
63 #if defined(AUTH_TLS) && AUTH_TLS!=2
64   " tls"
65 #endif
66   ;
67
68 uschar * d = US""               /* dynamic-module authenticator names */
69 #if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5==2
70   " cram_md5"
71 #endif
72 #if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL==2
73   " cyrus_sasl"
74 #endif
75 #if defined(AUTH_DOVECOT) && AUTH_DOVECOT==2
76   " dovecot"
77 #endif
78 #if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL==2
79   " external"
80 #endif
81 #if defined(AUTH_GSASL) && AUTH_GSASL==2
82   " gsasl"
83 #endif
84 #if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI==2
85   " heimdal_gssapi"
86 #endif
87 #if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT==2
88   " plaintext"
89 #endif
90 #if defined(AUTH_SPA) && AUTH_SPA==2
91   " spa"
92 #endif
93 #if defined(AUTH_TLS) && AUTH_TLS==2
94   " tls"
95 #endif
96   ;
97
98 if (*b) g = string_fmt_append(g, "Authenticators (built-in):%s\n", b);
99 if (*d) g = string_fmt_append(g, "Authenticators (dynamic): %s\n", d);
100 return g;
101 }
102
103 gstring *
104 route_show_supported(gstring * g)
105 {
106 uschar * b = US""               /* static-build router names */
107 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
108   " accept"
109 #endif
110 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
111   " dnslookup"
112 #endif
113 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
114   " ipliteral"
115 #endif
116 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
117   " iplookup"
118 #endif
119 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
120   " manualroute"
121 #endif
122 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
123   " redirect"
124 #endif
125 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
126   " queryprogram"
127 #endif
128   ;
129
130 uschar * d = US""               /* dynamic-module router names */
131 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
132   " accept"
133 #endif
134 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
135   " dnslookup"
136 #endif
137 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
138   " ipliteral"
139 #endif
140 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
141   " iplookup"
142 #endif
143 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
144   " manualroute"
145 #endif
146 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
147   " redirect"
148 #endif
149 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
150   " queryprogram"
151 #endif
152   ;
153
154 if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
155 if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
156 return g;
157 }
158
159 gstring *
160 transport_show_supported(gstring * g)
161 {
162 uschar * b = US""               /* static-build transportnames */
163 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
164   " appendfile"
165 # ifdef SUPPORT_MAILDIR
166     "/maildir"
167 # endif
168 # ifdef SUPPORT_MAILSTORE
169     "/mailstore"
170 # endif
171 # ifdef SUPPORT_MBX
172     "/mbx"
173 # endif
174 #endif
175 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
176   " autoreply"
177 #endif
178 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
179   " lmtp"
180 #endif
181 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
182   " pipe"
183 #endif
184 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
185   " queuefile"
186 #endif
187 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
188   " smtp"
189 #endif
190   ;
191
192 uschar * d = US""               /* dynamic-module transportnames */
193 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
194   " appendfile"
195 # ifdef SUPPORT_MAILDIR
196     "/maildir"
197 # endif
198 # ifdef SUPPORT_MAILSTORE
199     "/mailstore"
200 # endif
201 # ifdef SUPPORT_MBX
202     "/mbx"
203 # endif
204 #endif
205 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
206   " autoreply"
207 #endif
208 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
209   " lmtp"
210 #endif
211 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
212   " pipe"
213 #endif
214 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
215   " queuefile"
216 #endif
217 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
218   " smtp"
219 #endif
220   ;
221
222 if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
223 if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
224 return g;
225 }
226
227
228
229 static void
230 add_lookup_to_tree(lookup_info * li)
231 {
232 tree_node * new = store_get_perm(sizeof(tree_node) + Ustrlen(li->name),
233                                                         GET_UNTAINTED);
234 new->data.ptr = (void *)li;
235 Ustrcpy(new->name, li->name);
236 if (tree_insertnode(&lookups_tree, new))
237   li->acq_num = lookup_list_count++;
238 else
239   log_write(0, LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name);
240 }
241
242
243 /* Add all the lookup types provided by the module */
244 static void
245 addlookupmodule(const struct lookup_module_info * lmi)
246 {
247 for (int j = 0; j < lmi->lookupcount; j++)
248   add_lookup_to_tree(lmi->lookups[j]);
249 }
250
251
252
253 /* Hunt for the lookup with the given acquisition number */
254
255 static unsigned hunt_acq;
256
257 static void
258 acq_cb(uschar * name, uschar * ptr, void * ctx)
259 {
260 lookup_info * li = (lookup_info *)ptr;
261 if (li->acq_num == hunt_acq) *(lookup_info **)ctx = li;
262 }
263
264 const lookup_info *
265 lookup_with_acq_num(unsigned k)
266 {
267 const lookup_info * li = NULL;
268 hunt_acq = k;
269 tree_walk(lookups_tree, acq_cb, &li);
270 return li;
271 }
272
273
274
275 /* These need to be at file level for old versions of gcc (2.95.2 reported),
276 which give parse errors on an extern in function scope.  Each entry needs
277 to also be invoked in init_lookup_list() below  */
278
279 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
280 extern lookup_module_info cdb_lookup_module_info;
281 #endif
282 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
283 extern lookup_module_info dbmdb_lookup_module_info;
284 #endif
285 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
286 extern lookup_module_info dnsdb_lookup_module_info;
287 #endif
288 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
289 extern lookup_module_info dsearch_lookup_module_info;
290 #endif
291 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
292 extern lookup_module_info ibase_lookup_module_info;
293 #endif
294 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
295 extern lookup_module_info json_lookup_module_info;
296 #endif
297 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
298 extern lookup_module_info ldap_lookup_module_info;
299 #endif
300 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
301 extern lookup_module_info lsearch_lookup_module_info;
302 #endif
303 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
304 extern lookup_module_info mysql_lookup_module_info;
305 #endif
306 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
307 extern lookup_module_info nis_lookup_module_info;
308 #endif
309 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
310 extern lookup_module_info nisplus_lookup_module_info;
311 #endif
312 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
313 extern lookup_module_info oracle_lookup_module_info;
314 #endif
315 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
316 extern lookup_module_info passwd_lookup_module_info;
317 #endif
318 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
319 extern lookup_module_info pgsql_lookup_module_info;
320 #endif
321 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
322 extern lookup_module_info redis_lookup_module_info;
323 #endif
324 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
325 extern lookup_module_info lmdb_lookup_module_info;
326 #endif
327 #if defined(SUPPORT_SPF)
328 extern lookup_module_info spf_lookup_module_info;       /* see below */
329 #endif
330 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
331 extern lookup_module_info sqlite_lookup_module_info;
332 #endif
333 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
334 extern lookup_module_info testdb_lookup_module_info;
335 #endif
336 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
337 extern lookup_module_info whoson_lookup_module_info;
338 #endif
339
340 extern lookup_module_info readsock_lookup_module_info;
341
342
343 #ifdef LOOKUP_MODULE_DIR
344 static void *
345 mod_open(const uschar * name, const uschar * class, uschar ** errstr)
346 {
347 const uschar * path = string_sprintf(
348   LOOKUP_MODULE_DIR "/%s_%s." DYNLIB_FN_EXT, name, class);
349 void * dl;
350 if (!(dl = dlopen(CS path, RTLD_NOW)))
351   {
352   if (errstr)
353     *errstr = string_sprintf("Error loading %s: %s", name, dlerror());
354   else
355     (void) dlerror();           /* clear out error state */
356   return NULL;
357   }
358
359 /* FreeBSD nsdispatch() can trigger dlerror() errors about
360 _nss_cache_cycle_prevention_function; we need to clear the dlerror()
361 state before calling dlsym(), so that any error afterwards only comes
362 from dlsym().  */
363
364 (void) dlerror();
365 return dl;
366 }
367
368
369 /* Try to load a lookup module with the given name.
370
371 Arguments:
372     name                name of the lookup
373     errstr              if not NULL, place "open fail" error message here
374
375 Return: boolean success
376 */
377
378 static BOOL
379 lookup_mod_load(const uschar * name, uschar ** errstr)
380 {
381 void * dl;
382 struct lookup_module_info * info;
383 const char * errormsg;
384
385 if (!(dl = mod_open(name, US"lookup", errstr)))
386   return FALSE;
387
388 info = (struct lookup_module_info *) dlsym(dl, "_lookup_module_info");
389 if ((errormsg = dlerror()))
390   {
391   fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
392   log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)", name, errormsg);
393   dlclose(dl);
394   return FALSE;
395   }
396 if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
397   {
398   fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
399   log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim", name);
400   dlclose(dl);
401   return FALSE;
402   }
403
404 addlookupmodule(info);
405 DEBUG(D_lookup) debug_printf_indent("Loaded \"%s\" (%d lookup type%s)\n",
406                                     name, info->lookupcount,
407                                     info->lookupcount > 1 ? "s" : "");
408 return TRUE;
409 }
410
411
412 /* Try to load a lookup module, assuming the module name is the same
413 as the lookup type name.  This will only work for single-method modules.
414 Other have to be always-load (see the RE in init_lookup_list() below).
415 */
416
417 BOOL
418 lookup_one_mod_load(const uschar * name, uschar ** errstr)
419 {
420 if (!lookup_mod_load(name, errstr)) return FALSE;
421 /*XXX notify daemon? */
422 return TRUE;
423 }
424
425 #endif  /*LOOKUP_MODULE_DIR*/
426
427
428
429 misc_module_info * misc_module_list = NULL;
430
431 static void
432 misc_mod_add(misc_module_info * mi)
433 {
434 if (mi->init) mi->init(mi);
435 DEBUG(D_any) if (mi->lib_vers_report)
436   debug_printf_indent("%Y", mi->lib_vers_report(NULL));
437
438 mi->next = misc_module_list;
439 misc_module_list = mi;
440 }
441
442
443 #ifdef LOOKUP_MODULE_DIR
444
445 /* Load a "misc" module, and add to list */
446
447 static misc_module_info *
448 misc_mod_load(const uschar * name, uschar ** errstr)
449 {
450 void * dl;
451 struct misc_module_info * mi;
452 const char * errormsg;
453
454 DEBUG(D_any) debug_printf_indent("loading module '%s'\n", name);
455 if (!(dl = mod_open(name, US"miscmod", errstr)))
456   return NULL;
457
458 mi = (struct misc_module_info *) dlsym(dl,
459                                     CS string_sprintf("%s_module_info", name));
460 if ((errormsg = dlerror()))
461   {
462   fprintf(stderr, "%s does not appear to be a '%s' module (%s)\n",
463           name, name, errormsg);
464   log_write(0, LOG_MAIN|LOG_PANIC,
465     "%s does not contain the expected module info symbol (%s)", name, errormsg);
466   dlclose(dl);
467   return NULL;
468   }
469 if (mi->dyn_magic != MISC_MODULE_MAGIC)
470   {
471   fprintf(stderr, "Module %s is not compatible with this version of Exim\n", name);
472   log_write(0, LOG_MAIN|LOG_PANIC, "Module %s is not compatible with this version of Exim", name);
473   dlclose(dl);
474   return FALSE;
475   }
476
477 DEBUG(D_lookup) debug_printf_indent("Loaded \"%s\"\n", name);
478 misc_mod_add(mi);
479 return mi;
480 }
481
482 #endif  /*LOOKUP_MODULE_DIR*/
483
484
485 /* Find a "misc" module by name, if loaded.
486 For now use a linear search down a linked list.  If the number of
487 modules gets large, we might consider a tree.
488 */
489
490 misc_module_info *
491 misc_mod_findonly(const uschar * name)
492 {
493 for (misc_module_info * mi = misc_module_list; mi; mi = mi->next)
494   if (Ustrcmp(name, mi->name) == 0)
495     return mi;
496 return NULL;
497 }
498
499 /* Find a "misc" module, possibly already loaded, by name. */
500
501 misc_module_info *
502 misc_mod_find(const uschar * name, uschar ** errstr)
503 {
504 misc_module_info * mi;
505 if ((mi = misc_mod_findonly(name))) return mi;
506 #ifdef LOOKUP_MODULE_DIR
507 return misc_mod_load(name, errstr);
508 #else
509 return NULL;
510 #endif  /*LOOKUP_MODULE_DIR*/
511 }
512
513
514 /* For any "misc" module having a connection-init routine, call it. */
515
516 int
517 misc_mod_conn_init(const uschar * sender_helo_name,
518   const uschar * sender_host_address)
519 {
520 for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
521   if (mi->conn_init)
522     if ((mi->conn_init) (sender_helo_name, sender_host_address) != OK)
523       return FAIL;
524 return OK;
525 }
526
527 /* Ditto, smtp-reset */
528
529 void
530 misc_mod_smtp_reset(void)
531 {
532 for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
533   if (mi->smtp_reset)
534     (mi->smtp_reset)();
535 }
536
537 /* Ditto, msg-init */
538
539 int
540 misc_mod_msg_init(void)
541 {
542 for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
543   if (mi->msg_init)
544     if ((mi->msg_init)() != OK)
545       return FAIL;
546 return OK;
547 }
548
549
550
551
552
553 void
554 init_lookup_list(void)
555 {
556 #ifdef LOOKUP_MODULE_DIR
557 DIR * dd;
558 int countmodules = 0;
559 #endif
560 static BOOL lookup_list_init_done = FALSE;
561
562 if (lookup_list_init_done)
563   return;
564 lookup_list_init_done = TRUE;
565
566 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
567 addlookupmodule(&cdb_lookup_module_info);
568 #endif
569
570 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
571 addlookupmodule(&dbmdb_lookup_module_info);
572 #endif
573
574 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
575 addlookupmodule(&dnsdb_lookup_module_info);
576 #endif
577
578 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
579 addlookupmodule(&dsearch_lookup_module_info);
580 #endif
581
582 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
583 addlookupmodule(&ibase_lookup_module_info);
584 #endif
585
586 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
587 addlookupmodule(&ldap_lookup_module_info);
588 #endif
589
590 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
591 addlookupmodule(&json_lookup_module_info);
592 #endif
593
594 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
595 addlookupmodule(&lsearch_lookup_module_info);
596 #endif
597
598 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
599 addlookupmodule(&mysql_lookup_module_info);
600 #endif
601
602 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
603 addlookupmodule(&nis_lookup_module_info);
604 #endif
605
606 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
607 addlookupmodule(&nisplus_lookup_module_info);
608 #endif
609
610 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
611 addlookupmodule(&oracle_lookup_module_info);
612 #endif
613
614 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
615 addlookupmodule(&passwd_lookup_module_info);
616 #endif
617
618 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
619 addlookupmodule(&pgsql_lookup_module_info);
620 #endif
621
622 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
623 addlookupmodule(&redis_lookup_module_info);
624 #endif
625
626 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
627 addlookupmodule(&lmdb_lookup_module_info);
628 #endif
629
630 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
631 addlookupmodule(&sqlite_lookup_module_info);
632 #endif
633
634 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
635 addlookupmodule(&testdb_lookup_module_info);
636 #endif
637
638 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
639 addlookupmodule(&whoson_lookup_module_info);
640 #endif
641
642 /* This is provided by the spf "misc" module, and the lookup aspect is always
643 linked statically whether or not the "misc" module (and hence libspf2) is
644 dynamic-load. */
645
646 #if defined(SUPPORT_SPF)
647 addlookupmodule(&spf_lookup_module_info);
648 #endif
649
650 /* This is a custom expansion, and not available as either
651 a list-syntax lookup or a lookup expansion. However, it is
652 implemented by a lookup module. */
653
654 addlookupmodule(&readsock_lookup_module_info);
655
656 DEBUG(D_lookup) debug_printf("Total %d built-in lookups\n", lookup_list_count);
657
658
659 #ifdef LOOKUP_MODULE_DIR
660 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
661   {
662   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
663   log_write(0, LOG_MAIN|LOG_PANIC,
664           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
665   }
666 else
667   {
668   /* Look specifically for modules we know offer several lookup types and
669   load them now, since we cannot load-on-first-use. */
670
671   struct dirent * ent;
672   const pcre2_code * regex_islookupmod = regex_must_compile(
673     US"(lsearch|ldap|nis)_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
674
675   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
676   while ((ent = readdir(dd)))
677     {
678     char * name = ent->d_name;
679     int len = (int)strlen(name);
680     if (regex_match_and_setup(regex_islookupmod, US name, 0, 0))
681       {
682       uschar * errstr;
683       if (lookup_mod_load(expand_nstring[1], &errstr))
684         countmodules++;
685       else
686         {
687         fprintf(stderr, "%s\n", errstr);
688         log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr);
689         }
690       }
691     }
692   closedir(dd);
693   }
694
695 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
696 #endif
697 }
698
699
700 #if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
701 extern misc_module_info dmarc_module_info;
702 #endif
703 #if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
704 extern misc_module_info spf_module_info;
705 #endif
706
707 void
708 init_misc_mod_list(void)
709 {
710 static BOOL onetime = FALSE;
711 if (onetime) return;
712
713 #if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
714 /* dmarc depends on spf so this add must go first, for the dmarc-static case */
715 misc_mod_add(&spf_module_info);
716 #endif
717 #if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
718 misc_mod_add(&dmarc_module_info);
719 #endif
720
721 onetime = TRUE;
722 }
723
724
725 #endif  /*!MACRO_PREDEF*/
726 /* End of drtables.c */