987846bac5c3a0b4cfd339d9fa8180d343fbf013
[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_newlist = NULL;
65 auth_info auths_available_oldarray[] = {
66
67 /* Checking by an expansion condition on plain text */
68
69 #ifdef AUTH_CRAM_MD5
70   {
71   .drinfo = {
72     .driver_name =      US"cram_md5",                   /* lookup name */
73     .options =          auth_cram_md5_options,
74     .options_count =    &auth_cram_md5_options_count,
75     .options_block =    &auth_cram_md5_option_defaults,
76     .options_len =      sizeof(auth_cram_md5_options_block),
77     .init =             auth_cram_md5_init,
78     },
79   .servercode =         auth_cram_md5_server,
80   .clientcode =         auth_cram_md5_client,
81   .version_report =     NULL,
82   .macros_create =      NULL,
83   },
84 #endif
85
86 #ifdef AUTH_CYRUS_SASL
87   {
88   .drinfo = {
89     .driver_name =      US"cyrus_sasl",
90     .options =          auth_cyrus_sasl_options,
91     .options_count =    &auth_cyrus_sasl_options_count,
92     .options_block =    &auth_cyrus_sasl_option_defaults,
93     .options_len =      sizeof(auth_cyrus_sasl_options_block),
94     .init =             auth_cyrus_sasl_init,
95     },
96   .servercode =         auth_cyrus_sasl_server,
97   .clientcode =         NULL,
98   .version_report =     auth_cyrus_sasl_version_report,
99   .macros_create =      NULL,
100   },
101 #endif
102
103 #ifdef AUTH_DOVECOT
104   {
105   .drinfo = {
106     .driver_name =      US"dovecot",
107     .options =          auth_dovecot_options,
108     .options_count =    &auth_dovecot_options_count,
109     .options_block =    &auth_dovecot_option_defaults,
110     .options_len =      sizeof(auth_dovecot_options_block),
111     .init =             auth_dovecot_init,
112     },
113   .servercode =         auth_dovecot_server,
114   .clientcode =         NULL,
115   .version_report =     NULL,
116   .macros_create =      NULL,
117   },
118 #endif
119
120 #ifdef AUTH_EXTERNAL
121   {
122   .drinfo = {
123     .driver_name =      US"external",
124     .options =          auth_external_options,
125     .options_count =    &auth_external_options_count,
126     .options_block =    &auth_external_option_defaults,
127     .options_len =      sizeof(auth_external_options_block),
128     .init =             auth_external_init,
129     },
130   .servercode =         auth_external_server,
131   .clientcode =         auth_external_client,
132   .version_report =     NULL,
133   .macros_create =      NULL,
134   },
135 #endif
136
137 #ifdef AUTH_GSASL
138   {
139   .drinfo = {
140     .driver_name =      US"gsasl",
141     .options =          auth_gsasl_options,
142     .options_count =    &auth_gsasl_options_count,
143     .options_block =    &auth_gsasl_option_defaults,
144     .options_len =      sizeof(auth_gsasl_options_block),
145     .init =             auth_gsasl_init,
146     },
147   .servercode =         auth_gsasl_server,
148   .clientcode =         auth_gsasl_client,
149   .version_report =     auth_gsasl_version_report,
150   .macros_create =      auth_gsasl_macros,
151   },
152 #endif
153
154 #ifdef AUTH_HEIMDAL_GSSAPI
155   {
156   .drinfo = {
157     .driver_name =      US"heimdal_gssapi",
158     .options =          auth_heimdal_gssapi_options,
159     .options_count =    &auth_heimdal_gssapi_options_count,
160     .options_block =    &auth_heimdal_gssapi_option_defaults,
161     .options_len =      sizeof(auth_heimdal_gssapi_options_block),
162     .init =             auth_heimdal_gssapi_init,
163     },
164   .servercode =         auth_heimdal_gssapi_server,
165   .clientcode =         NULL,
166   .version_report =     auth_heimdal_gssapi_version_report,
167   .macros_create =      NULL,
168   },
169 #endif
170
171 #ifdef AUTH_PLAINTEXT
172   {
173   .drinfo = {
174     .driver_name =      US"plaintext",
175     .options =          auth_plaintext_options,
176     .options_count =    &auth_plaintext_options_count,
177     .options_block =    &auth_plaintext_option_defaults,
178     .options_len =      sizeof(auth_plaintext_options_block),
179     .init =             auth_plaintext_init,
180     },
181   .servercode =         auth_plaintext_server,
182   .clientcode =         auth_plaintext_client,
183   .version_report =     NULL,
184   .macros_create =      NULL,
185   },
186 #endif
187
188 #ifdef AUTH_SPA
189   {
190   .drinfo = {
191     .driver_name =      US"spa",
192     .options =          auth_spa_options,
193     .options_count =    &auth_spa_options_count,
194     .options_block =    &auth_spa_option_defaults,
195     .options_len =      sizeof(auth_spa_options_block),
196     .init =             auth_spa_init,
197     },
198   .servercode =         auth_spa_server,
199   .clientcode =         auth_spa_client,
200   .version_report =     NULL,
201   .macros_create =      NULL,
202   },
203 #endif
204
205 #ifdef AUTH_TLS
206   {
207   .drinfo = {
208     .driver_name =      US"tls",
209     .options =          auth_tls_options,
210     .options_count =    &auth_tls_options_count,
211     .options_block =    &auth_tls_option_defaults,
212     .options_len =      sizeof(auth_tls_options_block),
213     .init =             auth_tls_init,
214     },
215   .servercode =         auth_tls_server,
216   .clientcode =         NULL,
217   .version_report =     NULL,
218   .macros_create =      NULL,
219   },
220 #endif
221
222   { .drinfo = { .driver_name = US"" }}          /* end marker */
223 };
224
225
226 /* Tables of information about which routers and transports are included in the
227 exim binary. */
228
229 /* Pull in the necessary header files */
230
231 #include "routers/rf_functions.h"
232
233 #ifdef ROUTER_ACCEPT
234 # include "routers/accept.h"
235 #endif
236
237 #ifdef ROUTER_DNSLOOKUP
238 # include "routers/dnslookup.h"
239 #endif
240
241 #ifdef ROUTER_MANUALROUTE
242 # include "routers/manualroute.h"
243 #endif
244
245 #ifdef ROUTER_IPLITERAL
246 # include "routers/ipliteral.h"
247 #endif
248
249 #ifdef ROUTER_IPLOOKUP
250 # include "routers/iplookup.h"
251 #endif
252
253 #ifdef ROUTER_QUERYPROGRAM
254 # include "routers/queryprogram.h"
255 #endif
256
257 #ifdef ROUTER_REDIRECT
258 # include "routers/redirect.h"
259 #endif
260
261 #ifdef TRANSPORT_APPENDFILE
262 # include "transports/appendfile.h"
263 #endif
264
265 #ifdef TRANSPORT_AUTOREPLY
266 # include "transports/autoreply.h"
267 #endif
268
269 #ifdef TRANSPORT_LMTP
270 # include "transports/lmtp.h"
271 #endif
272
273 #ifdef TRANSPORT_PIPE
274 # include "transports/pipe.h"
275 #endif
276
277 #ifdef EXPERIMENTAL_QUEUEFILE
278 # include "transports/queuefile.h"
279 #endif
280
281 #ifdef TRANSPORT_SMTP
282 # include "transports/smtp.h"
283 #endif
284
285
286 router_info * routers_available_newlist = NULL;
287
288 /* Now set up the structures, terminated by an entry with a null name. */
289
290 router_info routers_available_oldarray[] = {
291 #ifdef ROUTER_ACCEPT
292   {
293   .drinfo = {
294     .driver_name =      US"accept",
295     .options =          accept_router_options,
296     .options_count =    &accept_router_options_count,
297     .options_block =    &accept_router_option_defaults,
298     .options_len =      sizeof(accept_router_options_block),
299     .init =             accept_router_init,
300     },
301   .code =               accept_router_entry,
302   .tidyup =             NULL,     /* no tidyup entry */
303   .ri_flags =           ri_yestransport
304   },
305 #endif
306 #ifdef ROUTER_DNSLOOKUP
307   {
308   .drinfo = {
309     .driver_name =      US"dnslookup",
310     .options =          dnslookup_router_options,
311     .options_count =    &dnslookup_router_options_count,
312     .options_block =    &dnslookup_router_option_defaults,
313     .options_len =      sizeof(dnslookup_router_options_block),
314     .init =             dnslookup_router_init,
315     },
316   .code =               dnslookup_router_entry,
317   .tidyup =             NULL,     /* no tidyup entry */
318   .ri_flags =           ri_yestransport
319   },
320 #endif
321 #ifdef ROUTER_IPLITERAL
322   {
323   .drinfo = {
324     .driver_name =      US"ipliteral",
325     .options =          ipliteral_router_options,
326     .options_count =    &ipliteral_router_options_count,
327     .options_block =    &ipliteral_router_option_defaults,
328     .options_len =      sizeof(ipliteral_router_options_block),
329     .init =             ipliteral_router_init,
330     },
331   .code =               ipliteral_router_entry,
332   .tidyup =             NULL,     /* no tidyup entry */
333   .ri_flags =           ri_yestransport
334   },
335 #endif
336 #ifdef ROUTER_IPLOOKUP
337   {
338   .drinfo = {
339     .driver_name =      US"iplookup",
340     .options =          iplookup_router_options,
341     .options_count =    &iplookup_router_options_count,
342     .options_block =    &iplookup_router_option_defaults,
343     .options_len =      sizeof(iplookup_router_options_block),
344     .init =             iplookup_router_init,
345     },
346   .code =               iplookup_router_entry,
347   .tidyup =             NULL,     /* no tidyup entry */
348   .ri_flags =           ri_notransport
349   },
350 #endif
351 #ifdef ROUTER_MANUALROUTE
352   {
353   .drinfo = {
354     .driver_name =      US"manualroute",
355     .options =          manualroute_router_options,
356     .options_count =    &manualroute_router_options_count,
357     .options_block =    &manualroute_router_option_defaults,
358     .options_len =      sizeof(manualroute_router_options_block),
359     .init =             manualroute_router_init,
360     },
361   .code =               manualroute_router_entry,
362   .tidyup =             NULL,     /* no tidyup entry */
363   .ri_flags =           0
364   },
365 #endif
366 #ifdef ROUTER_REDIRECT
367   {
368   .drinfo = {
369     .driver_name =      US"redirect",
370     .options =          redirect_router_options,
371     .options_count =    &redirect_router_options_count,
372     .options_block =    &redirect_router_option_defaults,
373     .options_len =      sizeof(redirect_router_options_block),
374     .init =             redirect_router_init,
375     },
376   .code =               redirect_router_entry,
377   .tidyup =             NULL,     /* no tidyup entry */
378   .ri_flags =           ri_notransport
379   },
380 #endif
381   { .drinfo = { .driver_name = US"" }}
382 };
383
384
385
386 transport_info * transports_available_newlist = NULL;
387 transport_info transports_available_oldarray[] = {
388 #ifdef TRANSPORT_APPENDFILE
389   {
390   .drinfo = {
391     .driver_name =      US"appendfile",
392     .options =          appendfile_transport_options,
393     .options_count =    &appendfile_transport_options_count,
394     .options_block =    &appendfile_transport_option_defaults,       /* private options defaults */
395     .options_len =      sizeof(appendfile_transport_options_block),
396     .init =             appendfile_transport_init,
397     },
398   .code =               appendfile_transport_entry,
399   .tidyup =             NULL,
400   .closedown =          NULL,
401   .local =              TRUE
402   },
403 #endif
404 #ifdef TRANSPORT_AUTOREPLY
405   {
406   .drinfo = {
407     .driver_name =      US"autoreply",
408     .options =          autoreply_transport_options,
409     .options_count =    &autoreply_transport_options_count,
410     .options_block =    &autoreply_transport_option_defaults,
411     .options_len =      sizeof(autoreply_transport_options_block),
412     .init =             autoreply_transport_init,
413     },
414   .code =               autoreply_transport_entry,
415   .tidyup =             NULL,
416   .closedown =          NULL,
417   .local =              TRUE
418   },
419 #endif
420 #ifdef TRANSPORT_LMTP
421   {
422   .drinfo = {
423     .driver_name =      US"lmtp",
424     .options =          lmtp_transport_options,
425     .options_count =    &lmtp_transport_options_count,
426     .options_block =    &lmtp_transport_option_defaults,
427     .options_len =      sizeof(lmtp_transport_options_block),
428     .init =             lmtp_transport_init,
429     },
430   .code =               lmtp_transport_entry,
431   .tidyup =             NULL,
432   .closedown =          NULL,
433   .local =              TRUE
434   },
435 #endif
436 #ifdef TRANSPORT_PIPE
437   {
438   .drinfo = {
439     .driver_name =      US"pipe",
440     .options =          pipe_transport_options,
441     .options_count =    &pipe_transport_options_count,
442     .options_block =    &pipe_transport_option_defaults,
443     .options_len =      sizeof(pipe_transport_options_block),
444     .init =             pipe_transport_init,
445     },
446   .code =               pipe_transport_entry,
447   .tidyup =             NULL,
448   .closedown =          NULL,
449   .local =              TRUE
450   },
451 #endif
452 #ifdef EXPERIMENTAL_QUEUEFILE
453   {
454   .drinfo = {
455     .driver_name =      US"queuefile",
456     .options =          queuefile_transport_options,
457     .options_count =    &queuefile_transport_options_count,
458     .options_block =    &queuefile_transport_option_defaults,
459     .options_len =      sizeof(queuefile_transport_options_block),
460     .init =             queuefile_transport_init,
461     },
462   .code =               queuefile_transport_entry,
463   .tidyup =             NULL,
464   .closedown =          NULL,
465   .local =              TRUE
466   },
467 #endif
468 #ifdef TRANSPORT_SMTP
469   {
470   .drinfo = {
471     .driver_name =      US"smtp",
472     .options =          smtp_transport_options,
473     .options_count =    &smtp_transport_options_count,
474     .options_block =    &smtp_transport_option_defaults,
475     .options_len =      sizeof(smtp_transport_options_block),
476     .init =             smtp_transport_init,
477     },
478   .code =               smtp_transport_entry,
479   .tidyup =             NULL,
480   .closedown =          smtp_transport_closedown,
481   .local =              FALSE
482   },
483 #endif
484   { .drinfo = { .driver_name = US"" }}
485 };
486
487 #ifndef MACRO_PREDEF
488
489 gstring *
490 auth_show_supported(gstring * g)
491 {
492 g = string_cat(g, US"Authenticators:");
493 /*XXX these run off the static list as we want them before the conf is read */
494 /*XXX Could possibly check for dyn flag + file presence */
495 for (auth_info * ai = auths_available_oldarray; ai->drinfo.driver_name[0]; ai++)
496         g = string_fmt_append(g, " %s", ai->drinfo.driver_name);
497 return string_cat(g, US"\n");
498 }
499
500 gstring *
501 route_show_supported(gstring * g)
502 {
503 gstring * b = NULL, * d = NULL;
504
505 #ifdef old
506 g = string_cat(g, US"Routers:");
507 /*XXX these run off the static list as we want them before the conf is read */
508 /*XXX lookup_show_supported is in exim.c and just works off the #defines, with hardoded strings */
509 for (router_info * rr = routers_available_oldarray; rr->drinfo.driver_name[0]; rr++)
510         g = string_fmt_append(g, " %s", rr->drinfo.driver_name);
511 #else
512
513 #ifdef ROUTER_ACCEPT
514 # if ROUTER_ACCEPT!=2
515   b = string_cat(b, US" accept");
516 # else
517   d = string_cat(d, US" cdb");
518 # endif
519 #endif
520 #ifdef ROUTER_DNSLOOKUP
521 # if ROUTER_DNSLOOKUP!=2
522   b = string_cat(g, US" dnslookup");
523 # else
524   d = string_cat(g, US" dnslookup");
525 # endif
526 #endif
527 # ifdef ROUTER_IPLITERAL
528 # if ROUTER_IPLITERAL!=2
529   b = string_cat(g, US" ipliteral");
530 # else
531   d = string_cat(g, US" ipliteral");
532 # endif
533 #endif
534 #ifdef ROUTER_IPLOOKUP
535 # if ROUTER_IPLOOKUP!=2
536   b = string_cat(g, US" iplookup");
537 # else
538   d = string_cat(g, US" iplookup");
539 # endif
540 #endif
541 #ifdef ROUTER_MANUALROUTE
542 # if ROUTER_MANUALROUTE!=2
543   b = string_cat(g, US" manualroute");
544 # else
545   d = string_cat(g, US" manualroute");
546 # endif
547 #endif
548 #ifdef ROUTER_REDIRECT
549 # if ROUTER_REDIRECT!=2
550   b = string_cat(g, US" redirect");
551 # else
552   d = string_cat(g, US" redirect");
553 # endif
554 #endif
555 #ifdef ROUTER_QUERYPROGRAM
556 # if ROUTER_QUERYPROGRAM!=2
557   b = string_cat(g, US" queryprogram");
558 # else
559   d = string_cat(g, US" queryprogram");
560 # endif
561 #endif
562
563 if (b) g = string_fmt_append(g, "Routers (built-in):%Y\n", b);
564 if (d) g = string_fmt_append(g, "Routers (dynamic): %Y\n", d);
565 #endif
566 return string_cat(g, US"\n");
567 }
568
569 gstring *
570 transport_show_supported(gstring * g)
571 {
572 g = string_cat(g, US"Transports:");
573 #ifdef TRANSPORT_APPENDFILE
574   g = string_cat(g, US" appendfile");
575   #ifdef SUPPORT_MAILDIR
576     g = string_cat(g, US"/maildir");    /* damn these subclasses */
577   #endif
578   #ifdef SUPPORT_MAILSTORE
579     g = string_cat(g, US"/mailstore");
580   #endif
581   #ifdef SUPPORT_MBX
582     g = string_cat(g, US"/mbx");
583   #endif
584 #endif
585 #ifdef TRANSPORT_AUTOREPLY
586   g = string_cat(g, US" autoreply");
587 #endif
588 #ifdef TRANSPORT_LMTP
589   g = string_cat(g, US" lmtp");
590 #endif
591 #ifdef TRANSPORT_PIPE
592   g = string_cat(g, US" pipe");
593 #endif
594 #ifdef EXPERIMENTAL_QUEUEFILE
595   g = string_cat(g, US" queuefile");
596 #endif
597 #ifdef TRANSPORT_SMTP
598   g = string_cat(g, US" smtp");
599 #endif
600 return string_cat(g, US"\n");
601 }
602
603
604
605 struct lookupmodulestr
606 {
607   void *dl;
608   struct lookup_module_info *info;
609   struct lookupmodulestr *next;
610 };
611
612 static struct lookupmodulestr *lookupmodules = NULL;
613
614 static void
615 addlookupmodule(void *dl, struct lookup_module_info *info)
616 {
617 struct lookupmodulestr * p =
618   store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
619
620 p->dl = dl;
621 p->info = info;
622 p->next = lookupmodules;
623 lookupmodules = p;
624 lookup_list_count += info->lookupcount;
625 }
626
627 /* only valid after lookup_list and lookup_list_count are assigned */
628 static void
629 add_lookup_to_list(lookup_info *info)
630 {
631 /* need to add the lookup to lookup_list, sorted */
632 int pos = 0;
633
634 /* strategy is to go through the list until we find
635 either an empty spot or a name that is higher.
636 this can't fail because we have enough space. */
637
638 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
639   pos++;
640
641 if (lookup_list[pos])
642   {
643   /* need to insert it, so move all the other items up
644   (last slot is still empty, of course) */
645
646   memmove(&lookup_list[pos+1], &lookup_list[pos],
647           sizeof(lookup_info *) * (lookup_list_count-pos-1));
648   }
649 lookup_list[pos] = info;
650 }
651
652
653 /* These need to be at file level for old versions of gcc (2.95.2 reported),
654 which give parse errors on an extern in function scope.  Each entry needs
655 to also be invoked in init_lookup_list() below  */
656
657 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
658 extern lookup_module_info cdb_lookup_module_info;
659 #endif
660 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
661 extern lookup_module_info dbmdb_lookup_module_info;
662 #endif
663 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
664 extern lookup_module_info dnsdb_lookup_module_info;
665 #endif
666 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
667 extern lookup_module_info dsearch_lookup_module_info;
668 #endif
669 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
670 extern lookup_module_info ibase_lookup_module_info;
671 #endif
672 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
673 extern lookup_module_info json_lookup_module_info;
674 #endif
675 #if defined(LOOKUP_LDAP)
676 extern lookup_module_info ldap_lookup_module_info;
677 #endif
678 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
679 extern lookup_module_info lsearch_lookup_module_info;
680 #endif
681 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
682 extern lookup_module_info mysql_lookup_module_info;
683 #endif
684 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
685 extern lookup_module_info nis_lookup_module_info;
686 #endif
687 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
688 extern lookup_module_info nisplus_lookup_module_info;
689 #endif
690 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
691 extern lookup_module_info oracle_lookup_module_info;
692 #endif
693 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
694 extern lookup_module_info passwd_lookup_module_info;
695 #endif
696 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
697 extern lookup_module_info pgsql_lookup_module_info;
698 #endif
699 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
700 extern lookup_module_info redis_lookup_module_info;
701 #endif
702 #if defined(LOOKUP_LMDB)
703 extern lookup_module_info lmdb_lookup_module_info;
704 #endif
705 #if defined(SUPPORT_SPF)
706 extern lookup_module_info spf_lookup_module_info;
707 #endif
708 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
709 extern lookup_module_info sqlite_lookup_module_info;
710 #endif
711 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
712 extern lookup_module_info testdb_lookup_module_info;
713 #endif
714 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
715 extern lookup_module_info whoson_lookup_module_info;
716 #endif
717
718 extern lookup_module_info readsock_lookup_module_info;
719
720
721 void
722 init_lookup_list(void)
723 {
724 #ifdef LOOKUP_MODULE_DIR
725 DIR *dd;
726 struct dirent *ent;
727 int countmodules = 0;
728 int moduleerrors = 0;
729 #endif
730 static BOOL lookup_list_init_done = FALSE;
731 rmark reset_point;
732
733 if (lookup_list_init_done)
734   return;
735 reset_point = store_mark();
736 lookup_list_init_done = TRUE;
737
738 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
739 addlookupmodule(NULL, &cdb_lookup_module_info);
740 #endif
741
742 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
743 addlookupmodule(NULL, &dbmdb_lookup_module_info);
744 #endif
745
746 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
747 addlookupmodule(NULL, &dnsdb_lookup_module_info);
748 #endif
749
750 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
751 addlookupmodule(NULL, &dsearch_lookup_module_info);
752 #endif
753
754 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
755 addlookupmodule(NULL, &ibase_lookup_module_info);
756 #endif
757
758 #ifdef LOOKUP_LDAP
759 addlookupmodule(NULL, &ldap_lookup_module_info);
760 #endif
761
762 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
763 addlookupmodule(NULL, &json_lookup_module_info);
764 #endif
765
766 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
767 addlookupmodule(NULL, &lsearch_lookup_module_info);
768 #endif
769
770 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
771 addlookupmodule(NULL, &mysql_lookup_module_info);
772 #endif
773
774 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
775 addlookupmodule(NULL, &nis_lookup_module_info);
776 #endif
777
778 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
779 addlookupmodule(NULL, &nisplus_lookup_module_info);
780 #endif
781
782 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
783 addlookupmodule(NULL, &oracle_lookup_module_info);
784 #endif
785
786 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
787 addlookupmodule(NULL, &passwd_lookup_module_info);
788 #endif
789
790 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
791 addlookupmodule(NULL, &pgsql_lookup_module_info);
792 #endif
793
794 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
795 addlookupmodule(NULL, &redis_lookup_module_info);
796 #endif
797
798 #ifdef LOOKUP_LMDB
799 addlookupmodule(NULL, &lmdb_lookup_module_info);
800 #endif
801
802 #ifdef SUPPORT_SPF
803 addlookupmodule(NULL, &spf_lookup_module_info);
804 #endif
805
806 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
807 addlookupmodule(NULL, &sqlite_lookup_module_info);
808 #endif
809
810 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
811 addlookupmodule(NULL, &testdb_lookup_module_info);
812 #endif
813
814 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
815 addlookupmodule(NULL, &whoson_lookup_module_info);
816 #endif
817
818 /* This is a custom expansion, and not available as either
819 a list-syntax lookup or a lookup expansion. However, it is
820 implemented by a lookup module. */
821
822 addlookupmodule(NULL, &readsock_lookup_module_info);
823
824 #ifdef LOOKUP_MODULE_DIR
825 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
826   {
827   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
828   log_write(0, LOG_MAIN|LOG_PANIC,
829           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
830   }
831 else
832   {
833   const pcre2_code * regex_islookupmod = regex_must_compile(
834     US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
835
836   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
837   while ((ent = readdir(dd)))
838     {
839     char * name = ent->d_name;
840     int len = (int)strlen(name);
841     if (regex_match(regex_islookupmod, US name, len, NULL))
842       {
843       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
844       void *dl;
845       struct lookup_module_info *info;
846       const char *errormsg;
847
848       /* SRH: am I being paranoid here or what? */
849       if (pathnamelen > big_buffer_size)
850         {
851         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
852         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
853         continue;
854         }
855
856       /* SRH: snprintf here? */
857       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
858
859       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
860         {
861         errormsg = dlerror();
862         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
863         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
864         moduleerrors++;
865         continue;
866         }
867
868       /* FreeBSD nsdispatch() can trigger dlerror() errors about
869       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
870       state before calling dlsym(), so that any error afterwards only comes
871       from dlsym().  */
872
873       errormsg = dlerror();
874
875       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
876       if ((errormsg = dlerror()))
877         {
878         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
879         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
880         dlclose(dl);
881         moduleerrors++;
882         continue;
883         }
884       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
885         {
886         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
887         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
888         dlclose(dl);
889         moduleerrors++;
890         continue;
891         }
892
893       addlookupmodule(dl, info);
894       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
895       countmodules++;
896       }
897     }
898   store_free((void*)regex_islookupmod);
899   closedir(dd);
900   }
901
902 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
903 #endif
904
905 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
906
907 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
908 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
909
910 /* now add all lookups to the real list */
911 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
912   for (int j = 0; j < p->info->lookupcount; j++)
913     add_lookup_to_list(p->info->lookups[j]);
914 store_reset(reset_point);
915 /* just to be sure */
916 lookupmodules = NULL;
917 }
918
919 #endif  /*!MACRO_PREDEF*/
920 /* End of drtables.c */