9225fafe1958f6401d4c01bc932da0849a1213b4
[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 #ifdef old
504 g = string_cat(g, US"Routers:");
505 /*XXX these run off the static list as we want them before the conf is read */
506 /*XXX lookup_show_supported is in exim.c and just works off the #defines, with hardoded strings */
507 for (router_info * rr = routers_available_oldarray; rr->drinfo.driver_name[0]; rr++)
508         g = string_fmt_append(g, " %s", rr->drinfo.driver_name);
509 return string_cat(g, US"\n");
510 #else
511
512 uschar * b = US""               /* static-build router names */
513 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
514   " accept"
515 #endif
516 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
517   " dnslookup"
518 #endif
519 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
520   " ipliteral"
521 #endif
522 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
523   " iplookup"
524 #endif
525 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
526   " manualroute"
527 #endif
528 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
529   " redirect"
530 #endif
531 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
532   " queryprogram"
533 #endif
534   ;
535
536 uschar * d = US""               /* dynamic-module router names */
537 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
538   " accept"
539 #endif
540 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
541   " dnslookup"
542 #endif
543 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
544   " ipliteral"
545 #endif
546 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
547   " iplookup"
548 #endif
549 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
550   " manualroute"
551 #endif
552 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
553   " redirect"
554 #endif
555 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
556   " queryprogram"
557 #endif
558   ;
559
560 if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
561 if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
562 return g;
563 #endif  /*!old*/
564 }
565
566 gstring *
567 transport_show_supported(gstring * g)
568 {
569 g = string_cat(g, US"Transports:");
570 #ifdef TRANSPORT_APPENDFILE
571   g = string_cat(g, US" appendfile");
572   #ifdef SUPPORT_MAILDIR
573     g = string_cat(g, US"/maildir");    /* damn these subclasses */
574   #endif
575   #ifdef SUPPORT_MAILSTORE
576     g = string_cat(g, US"/mailstore");
577   #endif
578   #ifdef SUPPORT_MBX
579     g = string_cat(g, US"/mbx");
580   #endif
581 #endif
582 #ifdef TRANSPORT_AUTOREPLY
583   g = string_cat(g, US" autoreply");
584 #endif
585 #ifdef TRANSPORT_LMTP
586   g = string_cat(g, US" lmtp");
587 #endif
588 #ifdef TRANSPORT_PIPE
589   g = string_cat(g, US" pipe");
590 #endif
591 #ifdef EXPERIMENTAL_QUEUEFILE
592   g = string_cat(g, US" queuefile");
593 #endif
594 #ifdef TRANSPORT_SMTP
595   g = string_cat(g, US" smtp");
596 #endif
597 return string_cat(g, US"\n");
598 }
599
600
601
602 struct lookupmodulestr
603 {
604   void *dl;
605   struct lookup_module_info *info;
606   struct lookupmodulestr *next;
607 };
608
609 static struct lookupmodulestr *lookupmodules = NULL;
610
611 static void
612 addlookupmodule(void *dl, struct lookup_module_info *info)
613 {
614 struct lookupmodulestr * p =
615   store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
616
617 p->dl = dl;
618 p->info = info;
619 p->next = lookupmodules;
620 lookupmodules = p;
621 lookup_list_count += info->lookupcount;
622 }
623
624 /* only valid after lookup_list and lookup_list_count are assigned */
625 static void
626 add_lookup_to_list(lookup_info *info)
627 {
628 /* need to add the lookup to lookup_list, sorted */
629 int pos = 0;
630
631 /* strategy is to go through the list until we find
632 either an empty spot or a name that is higher.
633 this can't fail because we have enough space. */
634
635 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
636   pos++;
637
638 if (lookup_list[pos])
639   {
640   /* need to insert it, so move all the other items up
641   (last slot is still empty, of course) */
642
643   memmove(&lookup_list[pos+1], &lookup_list[pos],
644           sizeof(lookup_info *) * (lookup_list_count-pos-1));
645   }
646 lookup_list[pos] = info;
647 }
648
649
650 /* These need to be at file level for old versions of gcc (2.95.2 reported),
651 which give parse errors on an extern in function scope.  Each entry needs
652 to also be invoked in init_lookup_list() below  */
653
654 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
655 extern lookup_module_info cdb_lookup_module_info;
656 #endif
657 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
658 extern lookup_module_info dbmdb_lookup_module_info;
659 #endif
660 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
661 extern lookup_module_info dnsdb_lookup_module_info;
662 #endif
663 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
664 extern lookup_module_info dsearch_lookup_module_info;
665 #endif
666 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
667 extern lookup_module_info ibase_lookup_module_info;
668 #endif
669 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
670 extern lookup_module_info json_lookup_module_info;
671 #endif
672 #if defined(LOOKUP_LDAP)
673 extern lookup_module_info ldap_lookup_module_info;
674 #endif
675 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
676 extern lookup_module_info lsearch_lookup_module_info;
677 #endif
678 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
679 extern lookup_module_info mysql_lookup_module_info;
680 #endif
681 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
682 extern lookup_module_info nis_lookup_module_info;
683 #endif
684 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
685 extern lookup_module_info nisplus_lookup_module_info;
686 #endif
687 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
688 extern lookup_module_info oracle_lookup_module_info;
689 #endif
690 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
691 extern lookup_module_info passwd_lookup_module_info;
692 #endif
693 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
694 extern lookup_module_info pgsql_lookup_module_info;
695 #endif
696 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
697 extern lookup_module_info redis_lookup_module_info;
698 #endif
699 #if defined(LOOKUP_LMDB)
700 extern lookup_module_info lmdb_lookup_module_info;
701 #endif
702 #if defined(SUPPORT_SPF)
703 extern lookup_module_info spf_lookup_module_info;
704 #endif
705 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
706 extern lookup_module_info sqlite_lookup_module_info;
707 #endif
708 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
709 extern lookup_module_info testdb_lookup_module_info;
710 #endif
711 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
712 extern lookup_module_info whoson_lookup_module_info;
713 #endif
714
715 extern lookup_module_info readsock_lookup_module_info;
716
717
718 void
719 init_lookup_list(void)
720 {
721 #ifdef LOOKUP_MODULE_DIR
722 DIR *dd;
723 struct dirent *ent;
724 int countmodules = 0;
725 int moduleerrors = 0;
726 #endif
727 static BOOL lookup_list_init_done = FALSE;
728 rmark reset_point;
729
730 if (lookup_list_init_done)
731   return;
732 reset_point = store_mark();
733 lookup_list_init_done = TRUE;
734
735 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
736 addlookupmodule(NULL, &cdb_lookup_module_info);
737 #endif
738
739 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
740 addlookupmodule(NULL, &dbmdb_lookup_module_info);
741 #endif
742
743 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
744 addlookupmodule(NULL, &dnsdb_lookup_module_info);
745 #endif
746
747 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
748 addlookupmodule(NULL, &dsearch_lookup_module_info);
749 #endif
750
751 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
752 addlookupmodule(NULL, &ibase_lookup_module_info);
753 #endif
754
755 #ifdef LOOKUP_LDAP
756 addlookupmodule(NULL, &ldap_lookup_module_info);
757 #endif
758
759 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
760 addlookupmodule(NULL, &json_lookup_module_info);
761 #endif
762
763 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
764 addlookupmodule(NULL, &lsearch_lookup_module_info);
765 #endif
766
767 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
768 addlookupmodule(NULL, &mysql_lookup_module_info);
769 #endif
770
771 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
772 addlookupmodule(NULL, &nis_lookup_module_info);
773 #endif
774
775 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
776 addlookupmodule(NULL, &nisplus_lookup_module_info);
777 #endif
778
779 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
780 addlookupmodule(NULL, &oracle_lookup_module_info);
781 #endif
782
783 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
784 addlookupmodule(NULL, &passwd_lookup_module_info);
785 #endif
786
787 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
788 addlookupmodule(NULL, &pgsql_lookup_module_info);
789 #endif
790
791 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
792 addlookupmodule(NULL, &redis_lookup_module_info);
793 #endif
794
795 #ifdef LOOKUP_LMDB
796 addlookupmodule(NULL, &lmdb_lookup_module_info);
797 #endif
798
799 #ifdef SUPPORT_SPF
800 addlookupmodule(NULL, &spf_lookup_module_info);
801 #endif
802
803 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
804 addlookupmodule(NULL, &sqlite_lookup_module_info);
805 #endif
806
807 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
808 addlookupmodule(NULL, &testdb_lookup_module_info);
809 #endif
810
811 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
812 addlookupmodule(NULL, &whoson_lookup_module_info);
813 #endif
814
815 /* This is a custom expansion, and not available as either
816 a list-syntax lookup or a lookup expansion. However, it is
817 implemented by a lookup module. */
818
819 addlookupmodule(NULL, &readsock_lookup_module_info);
820
821 #ifdef LOOKUP_MODULE_DIR
822 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
823   {
824   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
825   log_write(0, LOG_MAIN|LOG_PANIC,
826           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
827   }
828 else
829   {
830   const pcre2_code * regex_islookupmod = regex_must_compile(
831     US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
832
833   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
834   while ((ent = readdir(dd)))
835     {
836     char * name = ent->d_name;
837     int len = (int)strlen(name);
838     if (regex_match(regex_islookupmod, US name, len, NULL))
839       {
840       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
841       void *dl;
842       struct lookup_module_info *info;
843       const char *errormsg;
844
845       /* SRH: am I being paranoid here or what? */
846       if (pathnamelen > big_buffer_size)
847         {
848         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
849         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
850         continue;
851         }
852
853       /* SRH: snprintf here? */
854       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
855
856       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
857         {
858         errormsg = dlerror();
859         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
860         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
861         moduleerrors++;
862         continue;
863         }
864
865       /* FreeBSD nsdispatch() can trigger dlerror() errors about
866       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
867       state before calling dlsym(), so that any error afterwards only comes
868       from dlsym().  */
869
870       errormsg = dlerror();
871
872       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
873       if ((errormsg = dlerror()))
874         {
875         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
876         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
877         dlclose(dl);
878         moduleerrors++;
879         continue;
880         }
881       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
882         {
883         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
884         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
885         dlclose(dl);
886         moduleerrors++;
887         continue;
888         }
889
890       addlookupmodule(dl, info);
891       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
892       countmodules++;
893       }
894     }
895   store_free((void*)regex_islookupmod);
896   closedir(dd);
897   }
898
899 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
900 #endif
901
902 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
903
904 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
905 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
906
907 /* now add all lookups to the real list */
908 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
909   for (int j = 0; j < p->info->lookupcount; j++)
910     add_lookup_to_list(p->info->lookups[j]);
911 store_reset(reset_point);
912 /* just to be sure */
913 lookupmodules = NULL;
914 }
915
916 #endif  /*!MACRO_PREDEF*/
917 /* End of drtables.c */