424c6197c3f2dacdc02add170ea0714209d41a0f
[exim.git] / src / src / drtables.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
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 */
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 int lookup_list_count = 0;
23
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. */
27
28 #ifdef AUTH_CRAM_MD5
29 #include "auths/cram_md5.h"
30 #endif
31
32 #ifdef AUTH_CYRUS_SASL
33 #include "auths/cyrus_sasl.h"
34 #endif
35
36 #ifdef AUTH_DOVECOT
37 #include "auths/dovecot.h"
38 #endif
39
40 #ifdef AUTH_EXTERNAL
41 #include "auths/external.h"
42 #endif
43
44 #ifdef AUTH_GSASL
45 #include "auths/gsasl_exim.h"
46 #endif
47
48 #ifdef AUTH_HEIMDAL_GSSAPI
49 #include "auths/heimdal_gssapi.h"
50 #endif
51
52 #ifdef AUTH_PLAINTEXT
53 #include "auths/plaintext.h"
54 #endif
55
56 #ifdef AUTH_SPA
57 #include "auths/spa.h"
58 #endif
59
60 #ifdef AUTH_TLS
61 #include "auths/tls.h"
62 #endif
63
64 auth_info auths_available[] = {
65
66 /* Checking by an expansion condition on plain text */
67
68 #ifdef AUTH_CRAM_MD5
69   {
70   .drinfo = {
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,
77     },
78   .servercode =         auth_cram_md5_server,
79   .clientcode =         auth_cram_md5_client,
80   .version_report =     NULL,
81   .macros_create =      NULL,
82   },
83 #endif
84
85 #ifdef AUTH_CYRUS_SASL
86   {
87   .drinfo = {
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,
94     },
95   .servercode =         auth_cyrus_sasl_server,
96   .clientcode =         NULL,
97   .version_report =     auth_cyrus_sasl_version_report,
98   .macros_create =      NULL,
99   },
100 #endif
101
102 #ifdef AUTH_DOVECOT
103   {
104   .drinfo = {
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,
111     },
112   .servercode =         auth_dovecot_server,
113   .clientcode =         NULL,
114   .version_report =     NULL,
115   .macros_create =      NULL,
116   },
117 #endif
118
119 #ifdef AUTH_EXTERNAL
120   {
121   .drinfo = {
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,
128     },
129   .servercode =         auth_external_server,
130   .clientcode =         auth_external_client,
131   .version_report =     NULL,
132   .macros_create =      NULL,
133   },
134 #endif
135
136 #ifdef AUTH_GSASL
137   {
138   .drinfo = {
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,
145     },
146   .servercode =         auth_gsasl_server,
147   .clientcode =         auth_gsasl_client,
148   .version_report =     auth_gsasl_version_report,
149   .macros_create =      auth_gsasl_macros,
150   },
151 #endif
152
153 #ifdef AUTH_HEIMDAL_GSSAPI
154   {
155   .drinfo = {
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,
162     },
163   .servercode =         auth_heimdal_gssapi_server,
164   .clientcode =         NULL,
165   .version_report =     auth_heimdal_gssapi_version_report,
166   .macros_create =      NULL,
167   },
168 #endif
169
170 #ifdef AUTH_PLAINTEXT
171   {
172   .drinfo = {
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,
179     },
180   .servercode =         auth_plaintext_server,
181   .clientcode =         auth_plaintext_client,
182   .version_report =     NULL,
183   .macros_create =      NULL,
184   },
185 #endif
186
187 #ifdef AUTH_SPA
188   {
189   .drinfo = {
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,
196     },
197   .servercode =         auth_spa_server,
198   .clientcode =         auth_spa_client,
199   .version_report =     NULL,
200   .macros_create =      NULL,
201   },
202 #endif
203
204 #ifdef AUTH_TLS
205   {
206   .drinfo = {
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,
213     },
214   .servercode =         auth_tls_server,
215   .clientcode =         NULL,
216   .version_report =     NULL,
217   .macros_create =      NULL,
218   },
219 #endif
220
221   { .drinfo = { .driver_name = US"" }}          /* end marker */
222 };
223
224
225 /* Tables of information about which routers and transports are included in the
226 exim binary. */
227
228 /* Pull in the necessary header files */
229
230 #include "routers/rf_functions.h"
231
232 #ifdef ROUTER_ACCEPT
233 # include "routers/accept.h"
234 #endif
235
236 #ifdef ROUTER_DNSLOOKUP
237 # include "routers/dnslookup.h"
238 #endif
239
240 #ifdef ROUTER_MANUALROUTE
241 # include "routers/manualroute.h"
242 #endif
243
244 #ifdef ROUTER_IPLITERAL
245 # include "routers/ipliteral.h"
246 #endif
247
248 #ifdef ROUTER_IPLOOKUP
249 # include "routers/iplookup.h"
250 #endif
251
252 #ifdef ROUTER_QUERYPROGRAM
253 # include "routers/queryprogram.h"
254 #endif
255
256 #ifdef ROUTER_REDIRECT
257 # include "routers/redirect.h"
258 #endif
259
260 #ifdef TRANSPORT_APPENDFILE
261 # include "transports/appendfile.h"
262 #endif
263
264 #ifdef TRANSPORT_AUTOREPLY
265 # include "transports/autoreply.h"
266 #endif
267
268 #ifdef TRANSPORT_LMTP
269 # include "transports/lmtp.h"
270 #endif
271
272 #ifdef TRANSPORT_PIPE
273 # include "transports/pipe.h"
274 #endif
275
276 #ifdef EXPERIMENTAL_QUEUEFILE
277 # include "transports/queuefile.h"
278 #endif
279
280 #ifdef TRANSPORT_SMTP
281 # include "transports/smtp.h"
282 #endif
283
284
285 /* Now set up the structures, terminated by an entry with a null name. */
286
287 router_info routers_available[] = {
288 #ifdef ROUTER_ACCEPT
289   {
290   .drinfo = {
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,
297     },
298   .code =               accept_router_entry,
299   .tidyup =             NULL,     /* no tidyup entry */
300   .ri_flags =           ri_yestransport
301   },
302 #endif
303 #ifdef ROUTER_DNSLOOKUP
304   {
305   .drinfo = {
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,
312     },
313   .code =               dnslookup_router_entry,
314   .tidyup =             NULL,     /* no tidyup entry */
315   .ri_flags =           ri_yestransport
316   },
317 #endif
318 #ifdef ROUTER_IPLITERAL
319   {
320   .drinfo = {
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,
327     },
328   .code =               ipliteral_router_entry,
329   .tidyup =             NULL,     /* no tidyup entry */
330   .ri_flags =           ri_yestransport
331   },
332 #endif
333 #ifdef ROUTER_IPLOOKUP
334   {
335   .drinfo = {
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,
342     },
343   .code =               iplookup_router_entry,
344   .tidyup =             NULL,     /* no tidyup entry */
345   .ri_flags =           ri_notransport
346   },
347 #endif
348 #ifdef ROUTER_MANUALROUTE
349   {
350   .drinfo = {
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,
357     },
358   .code =               manualroute_router_entry,
359   .tidyup =             NULL,     /* no tidyup entry */
360   .ri_flags =           0
361   },
362 #endif
363 #ifdef ROUTER_QUERYPROGRAM
364   {
365   .drinfo = {
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,
372     },
373   .code =               queryprogram_router_entry,
374   .tidyup =             NULL,     /* no tidyup entry */
375   .ri_flags =           0
376   },
377 #endif
378 #ifdef ROUTER_REDIRECT
379   {
380   .drinfo = {
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,
387     },
388   .code =               redirect_router_entry,
389   .tidyup =             NULL,     /* no tidyup entry */
390   .ri_flags =           ri_notransport
391   },
392 #endif
393   { .drinfo = { .driver_name = US"" }}
394 };
395
396
397
398 transport_info transports_available[] = {
399 #ifdef TRANSPORT_APPENDFILE
400   {
401   .drinfo = {
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,
408     },
409   .code =               appendfile_transport_entry,
410   .tidyup =             NULL,
411   .closedown =          NULL,
412   .local =              TRUE
413   },
414 #endif
415 #ifdef TRANSPORT_AUTOREPLY
416   {
417   .drinfo = {
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,
424     },
425   .code =               autoreply_transport_entry,
426   .tidyup =             NULL,
427   .closedown =          NULL,
428   .local =              TRUE
429   },
430 #endif
431 #ifdef TRANSPORT_LMTP
432   {
433   .drinfo = {
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,
440     },
441   .code =               lmtp_transport_entry,
442   .tidyup =             NULL,
443   .closedown =          NULL,
444   .local =              TRUE
445   },
446 #endif
447 #ifdef TRANSPORT_PIPE
448   {
449   .drinfo = {
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,
456     },
457   .code =               pipe_transport_entry,
458   .tidyup =             NULL,
459   .closedown =          NULL,
460   .local =              TRUE
461   },
462 #endif
463 #ifdef EXPERIMENTAL_QUEUEFILE
464   {
465   .drinfo = {
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,
472     },
473   .code =               queuefile_transport_entry,
474   .tidyup =             NULL,
475   .closedown =          NULL,
476   .local =              TRUE
477   },
478 #endif
479 #ifdef TRANSPORT_SMTP
480   {
481   .drinfo = {
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,
488     },
489   .code =               smtp_transport_entry,
490   .tidyup =             NULL,
491   .closedown =          smtp_transport_closedown,
492   .local =              FALSE
493   },
494 #endif
495   { .drinfo = { .driver_name = US"" }}
496 };
497
498 #ifndef MACRO_PREDEF
499
500 gstring *
501 auth_show_supported(gstring * g)
502 {
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");
507 }
508
509 gstring *
510 route_show_supported(gstring * g)
511 {
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");
516 }
517
518 gstring *
519 transport_show_supported(gstring * g)
520 {
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 */
526   #endif
527   #ifdef SUPPORT_MAILSTORE
528     g = string_cat(g, US"/mailstore");
529   #endif
530   #ifdef SUPPORT_MBX
531     g = string_cat(g, US"/mbx");
532   #endif
533 #endif
534 #ifdef TRANSPORT_AUTOREPLY
535   g = string_cat(g, US" autoreply");
536 #endif
537 #ifdef TRANSPORT_LMTP
538   g = string_cat(g, US" lmtp");
539 #endif
540 #ifdef TRANSPORT_PIPE
541   g = string_cat(g, US" pipe");
542 #endif
543 #ifdef EXPERIMENTAL_QUEUEFILE
544   g = string_cat(g, US" queuefile");
545 #endif
546 #ifdef TRANSPORT_SMTP
547   g = string_cat(g, US" smtp");
548 #endif
549 return string_cat(g, US"\n");
550 }
551
552
553
554 struct lookupmodulestr
555 {
556   void *dl;
557   struct lookup_module_info *info;
558   struct lookupmodulestr *next;
559 };
560
561 static struct lookupmodulestr *lookupmodules = NULL;
562
563 static void
564 addlookupmodule(void *dl, struct lookup_module_info *info)
565 {
566 struct lookupmodulestr * p =
567   store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
568
569 p->dl = dl;
570 p->info = info;
571 p->next = lookupmodules;
572 lookupmodules = p;
573 lookup_list_count += info->lookupcount;
574 }
575
576 /* only valid after lookup_list and lookup_list_count are assigned */
577 static void
578 add_lookup_to_list(lookup_info *info)
579 {
580 /* need to add the lookup to lookup_list, sorted */
581 int pos = 0;
582
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. */
586
587 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
588   pos++;
589
590 if (lookup_list[pos])
591   {
592   /* need to insert it, so move all the other items up
593   (last slot is still empty, of course) */
594
595   memmove(&lookup_list[pos+1], &lookup_list[pos],
596           sizeof(lookup_info *) * (lookup_list_count-pos-1));
597   }
598 lookup_list[pos] = info;
599 }
600
601
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  */
605
606 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
607 extern lookup_module_info cdb_lookup_module_info;
608 #endif
609 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
610 extern lookup_module_info dbmdb_lookup_module_info;
611 #endif
612 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
613 extern lookup_module_info dnsdb_lookup_module_info;
614 #endif
615 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
616 extern lookup_module_info dsearch_lookup_module_info;
617 #endif
618 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
619 extern lookup_module_info ibase_lookup_module_info;
620 #endif
621 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
622 extern lookup_module_info json_lookup_module_info;
623 #endif
624 #if defined(LOOKUP_LDAP)
625 extern lookup_module_info ldap_lookup_module_info;
626 #endif
627 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
628 extern lookup_module_info lsearch_lookup_module_info;
629 #endif
630 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
631 extern lookup_module_info mysql_lookup_module_info;
632 #endif
633 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
634 extern lookup_module_info nis_lookup_module_info;
635 #endif
636 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
637 extern lookup_module_info nisplus_lookup_module_info;
638 #endif
639 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
640 extern lookup_module_info oracle_lookup_module_info;
641 #endif
642 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
643 extern lookup_module_info passwd_lookup_module_info;
644 #endif
645 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
646 extern lookup_module_info pgsql_lookup_module_info;
647 #endif
648 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
649 extern lookup_module_info redis_lookup_module_info;
650 #endif
651 #if defined(LOOKUP_LMDB)
652 extern lookup_module_info lmdb_lookup_module_info;
653 #endif
654 #if defined(SUPPORT_SPF)
655 extern lookup_module_info spf_lookup_module_info;
656 #endif
657 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
658 extern lookup_module_info sqlite_lookup_module_info;
659 #endif
660 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
661 extern lookup_module_info testdb_lookup_module_info;
662 #endif
663 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
664 extern lookup_module_info whoson_lookup_module_info;
665 #endif
666
667 extern lookup_module_info readsock_lookup_module_info;
668
669
670 void
671 init_lookup_list(void)
672 {
673 #ifdef LOOKUP_MODULE_DIR
674 DIR *dd;
675 struct dirent *ent;
676 int countmodules = 0;
677 int moduleerrors = 0;
678 #endif
679 static BOOL lookup_list_init_done = FALSE;
680 rmark reset_point;
681
682 if (lookup_list_init_done)
683   return;
684 reset_point = store_mark();
685 lookup_list_init_done = TRUE;
686
687 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
688 addlookupmodule(NULL, &cdb_lookup_module_info);
689 #endif
690
691 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
692 addlookupmodule(NULL, &dbmdb_lookup_module_info);
693 #endif
694
695 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
696 addlookupmodule(NULL, &dnsdb_lookup_module_info);
697 #endif
698
699 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
700 addlookupmodule(NULL, &dsearch_lookup_module_info);
701 #endif
702
703 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
704 addlookupmodule(NULL, &ibase_lookup_module_info);
705 #endif
706
707 #ifdef LOOKUP_LDAP
708 addlookupmodule(NULL, &ldap_lookup_module_info);
709 #endif
710
711 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
712 addlookupmodule(NULL, &json_lookup_module_info);
713 #endif
714
715 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
716 addlookupmodule(NULL, &lsearch_lookup_module_info);
717 #endif
718
719 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
720 addlookupmodule(NULL, &mysql_lookup_module_info);
721 #endif
722
723 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
724 addlookupmodule(NULL, &nis_lookup_module_info);
725 #endif
726
727 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
728 addlookupmodule(NULL, &nisplus_lookup_module_info);
729 #endif
730
731 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
732 addlookupmodule(NULL, &oracle_lookup_module_info);
733 #endif
734
735 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
736 addlookupmodule(NULL, &passwd_lookup_module_info);
737 #endif
738
739 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
740 addlookupmodule(NULL, &pgsql_lookup_module_info);
741 #endif
742
743 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
744 addlookupmodule(NULL, &redis_lookup_module_info);
745 #endif
746
747 #ifdef LOOKUP_LMDB
748 addlookupmodule(NULL, &lmdb_lookup_module_info);
749 #endif
750
751 #ifdef SUPPORT_SPF
752 addlookupmodule(NULL, &spf_lookup_module_info);
753 #endif
754
755 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
756 addlookupmodule(NULL, &sqlite_lookup_module_info);
757 #endif
758
759 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
760 addlookupmodule(NULL, &testdb_lookup_module_info);
761 #endif
762
763 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
764 addlookupmodule(NULL, &whoson_lookup_module_info);
765 #endif
766
767 addlookupmodule(NULL, &readsock_lookup_module_info);
768
769 #ifdef LOOKUP_MODULE_DIR
770 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
771   {
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);
774   }
775 else
776   {
777   const pcre2_code * regex_islookupmod = regex_must_compile(
778     US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
779
780   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
781   while ((ent = readdir(dd)))
782     {
783     char * name = ent->d_name;
784     int len = (int)strlen(name);
785     if (regex_match(regex_islookupmod, US name, len, NULL))
786       {
787       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
788       void *dl;
789       struct lookup_module_info *info;
790       const char *errormsg;
791
792       /* SRH: am I being paranoid here or what? */
793       if (pathnamelen > big_buffer_size)
794         {
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);
797         continue;
798         }
799
800       /* SRH: snprintf here? */
801       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
802
803       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
804         {
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);
808         moduleerrors++;
809         continue;
810         }
811
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
815       from dlsym().  */
816
817       errormsg = dlerror();
818
819       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
820       if ((errormsg = dlerror()))
821         {
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);
824         dlclose(dl);
825         moduleerrors++;
826         continue;
827         }
828       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
829         {
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);
832         dlclose(dl);
833         moduleerrors++;
834         continue;
835         }
836
837       addlookupmodule(dl, info);
838       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
839       countmodules++;
840       }
841     }
842   store_free((void*)regex_islookupmod);
843   closedir(dd);
844   }
845
846 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
847 #endif
848
849 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
850
851 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
852 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
853
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;
861 }
862
863 #endif  /*!MACRO_PREDEF*/
864 /* End of drtables.c */