common driver structs for auths
[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 = store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
567
568 p->dl = dl;
569 p->info = info;
570 p->next = lookupmodules;
571 lookupmodules = p;
572 lookup_list_count += info->lookupcount;
573 }
574
575 /* only valid after lookup_list and lookup_list_count are assigned */
576 static void
577 add_lookup_to_list(lookup_info *info)
578 {
579 /* need to add the lookup to lookup_list, sorted */
580 int pos = 0;
581
582 /* strategy is to go through the list until we find
583 either an empty spot or a name that is higher.
584 this can't fail because we have enough space. */
585
586 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
587   pos++;
588
589 if (lookup_list[pos])
590   {
591   /* need to insert it, so move all the other items up
592   (last slot is still empty, of course) */
593
594   memmove(&lookup_list[pos+1], &lookup_list[pos],
595           sizeof(lookup_info *) * (lookup_list_count-pos-1));
596   }
597 lookup_list[pos] = info;
598 }
599
600
601 /* These need to be at file level for old versions of gcc (2.95.2 reported),
602 which give parse errors on an extern in function scope.  Each entry needs
603 to also be invoked in init_lookup_list() below  */
604
605 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
606 extern lookup_module_info cdb_lookup_module_info;
607 #endif
608 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
609 extern lookup_module_info dbmdb_lookup_module_info;
610 #endif
611 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
612 extern lookup_module_info dnsdb_lookup_module_info;
613 #endif
614 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
615 extern lookup_module_info dsearch_lookup_module_info;
616 #endif
617 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
618 extern lookup_module_info ibase_lookup_module_info;
619 #endif
620 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
621 extern lookup_module_info json_lookup_module_info;
622 #endif
623 #if defined(LOOKUP_LDAP)
624 extern lookup_module_info ldap_lookup_module_info;
625 #endif
626 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
627 extern lookup_module_info lsearch_lookup_module_info;
628 #endif
629 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
630 extern lookup_module_info mysql_lookup_module_info;
631 #endif
632 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
633 extern lookup_module_info nis_lookup_module_info;
634 #endif
635 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
636 extern lookup_module_info nisplus_lookup_module_info;
637 #endif
638 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
639 extern lookup_module_info oracle_lookup_module_info;
640 #endif
641 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
642 extern lookup_module_info passwd_lookup_module_info;
643 #endif
644 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
645 extern lookup_module_info pgsql_lookup_module_info;
646 #endif
647 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
648 extern lookup_module_info redis_lookup_module_info;
649 #endif
650 #if defined(LOOKUP_LMDB)
651 extern lookup_module_info lmdb_lookup_module_info;
652 #endif
653 #if defined(SUPPORT_SPF)
654 extern lookup_module_info spf_lookup_module_info;
655 #endif
656 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
657 extern lookup_module_info sqlite_lookup_module_info;
658 #endif
659 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
660 extern lookup_module_info testdb_lookup_module_info;
661 #endif
662 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
663 extern lookup_module_info whoson_lookup_module_info;
664 #endif
665
666 extern lookup_module_info readsock_lookup_module_info;
667
668
669 void
670 init_lookup_list(void)
671 {
672 #ifdef LOOKUP_MODULE_DIR
673 DIR *dd;
674 struct dirent *ent;
675 int countmodules = 0;
676 int moduleerrors = 0;
677 #endif
678 static BOOL lookup_list_init_done = FALSE;
679 rmark reset_point;
680
681 if (lookup_list_init_done)
682   return;
683 reset_point = store_mark();
684 lookup_list_init_done = TRUE;
685
686 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
687 addlookupmodule(NULL, &cdb_lookup_module_info);
688 #endif
689
690 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
691 addlookupmodule(NULL, &dbmdb_lookup_module_info);
692 #endif
693
694 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
695 addlookupmodule(NULL, &dnsdb_lookup_module_info);
696 #endif
697
698 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
699 addlookupmodule(NULL, &dsearch_lookup_module_info);
700 #endif
701
702 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
703 addlookupmodule(NULL, &ibase_lookup_module_info);
704 #endif
705
706 #ifdef LOOKUP_LDAP
707 addlookupmodule(NULL, &ldap_lookup_module_info);
708 #endif
709
710 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
711 addlookupmodule(NULL, &json_lookup_module_info);
712 #endif
713
714 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
715 addlookupmodule(NULL, &lsearch_lookup_module_info);
716 #endif
717
718 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
719 addlookupmodule(NULL, &mysql_lookup_module_info);
720 #endif
721
722 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
723 addlookupmodule(NULL, &nis_lookup_module_info);
724 #endif
725
726 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
727 addlookupmodule(NULL, &nisplus_lookup_module_info);
728 #endif
729
730 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
731 addlookupmodule(NULL, &oracle_lookup_module_info);
732 #endif
733
734 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
735 addlookupmodule(NULL, &passwd_lookup_module_info);
736 #endif
737
738 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
739 addlookupmodule(NULL, &pgsql_lookup_module_info);
740 #endif
741
742 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
743 addlookupmodule(NULL, &redis_lookup_module_info);
744 #endif
745
746 #ifdef LOOKUP_LMDB
747 addlookupmodule(NULL, &lmdb_lookup_module_info);
748 #endif
749
750 #ifdef SUPPORT_SPF
751 addlookupmodule(NULL, &spf_lookup_module_info);
752 #endif
753
754 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
755 addlookupmodule(NULL, &sqlite_lookup_module_info);
756 #endif
757
758 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
759 addlookupmodule(NULL, &testdb_lookup_module_info);
760 #endif
761
762 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
763 addlookupmodule(NULL, &whoson_lookup_module_info);
764 #endif
765
766 addlookupmodule(NULL, &readsock_lookup_module_info);
767
768 #ifdef LOOKUP_MODULE_DIR
769 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
770   {
771   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
772   log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
773   }
774 else
775   {
776   const pcre2_code * regex_islookupmod = regex_must_compile(
777     US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
778
779   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
780   while ((ent = readdir(dd)))
781     {
782     char * name = ent->d_name;
783     int len = (int)strlen(name);
784     if (regex_match(regex_islookupmod, US name, len, NULL))
785       {
786       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
787       void *dl;
788       struct lookup_module_info *info;
789       const char *errormsg;
790
791       /* SRH: am I being paranoid here or what? */
792       if (pathnamelen > big_buffer_size)
793         {
794         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
795         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
796         continue;
797         }
798
799       /* SRH: snprintf here? */
800       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
801
802       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
803         {
804         errormsg = dlerror();
805         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
806         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
807         moduleerrors++;
808         continue;
809         }
810
811       /* FreeBSD nsdispatch() can trigger dlerror() errors about
812       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
813       state before calling dlsym(), so that any error afterwards only comes
814       from dlsym().  */
815
816       errormsg = dlerror();
817
818       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
819       if ((errormsg = dlerror()))
820         {
821         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
822         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
823         dlclose(dl);
824         moduleerrors++;
825         continue;
826         }
827       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
828         {
829         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
830         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
831         dlclose(dl);
832         moduleerrors++;
833         continue;
834         }
835
836       addlookupmodule(dl, info);
837       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
838       countmodules++;
839       }
840     }
841   store_free((void*)regex_islookupmod);
842   closedir(dd);
843   }
844
845 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
846 #endif
847
848 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
849
850 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
851 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
852
853 /* now add all lookups to the real list */
854 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
855   for (int j = 0; j < p->info->lookupcount; j++)
856     add_lookup_to_list(p->info->lookups[j]);
857 store_reset(reset_point);
858 /* just to be sure */
859 lookupmodules = NULL;
860 }
861
862 #endif  /*!MACRO_PREDEF*/
863 /* End of drtables.c */