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