800d9e4db4e22e840b01c336a9c2c122cac604e5
[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   .driver_name =        US"accept",
273   .options =            accept_router_options,
274   .options_count =      &accept_router_options_count,
275   .options_block =      &accept_router_option_defaults,
276   .options_len =        sizeof(accept_router_options_block),
277   .init =               accept_router_init,
278   .code =               accept_router_entry,
279   .tidyup =             NULL,     /* no tidyup entry */
280   .ri_flags =           ri_yestransport
281   },
282 #endif
283 #ifdef ROUTER_DNSLOOKUP
284   {
285   .driver_name =        US"dnslookup",
286   .options =            dnslookup_router_options,
287   .options_count =      &dnslookup_router_options_count,
288   .options_block =      &dnslookup_router_option_defaults,
289   .options_len =        sizeof(dnslookup_router_options_block),
290   .init =               dnslookup_router_init,
291   .code =               dnslookup_router_entry,
292   .tidyup =             NULL,     /* no tidyup entry */
293   .ri_flags =           ri_yestransport
294   },
295 #endif
296 #ifdef ROUTER_IPLITERAL
297   {
298   .driver_name =        US"ipliteral",
299   .options =            ipliteral_router_options,
300   .options_count =      &ipliteral_router_options_count,
301   .options_block =      &ipliteral_router_option_defaults,
302   .options_len =        sizeof(ipliteral_router_options_block),
303   .init =               ipliteral_router_init,
304   .code =               ipliteral_router_entry,
305   .tidyup =             NULL,     /* no tidyup entry */
306   .ri_flags =           ri_yestransport
307   },
308 #endif
309 #ifdef ROUTER_IPLOOKUP
310   {
311   .driver_name =        US"iplookup",
312   .options =            iplookup_router_options,
313   .options_count =      &iplookup_router_options_count,
314   .options_block =      &iplookup_router_option_defaults,
315   .options_len =        sizeof(iplookup_router_options_block),
316   .init =               iplookup_router_init,
317   .code =               iplookup_router_entry,
318   .tidyup =             NULL,     /* no tidyup entry */
319   .ri_flags =           ri_notransport
320   },
321 #endif
322 #ifdef ROUTER_MANUALROUTE
323   {
324   .driver_name =        US"manualroute",
325   .options =            manualroute_router_options,
326   .options_count =      &manualroute_router_options_count,
327   .options_block =      &manualroute_router_option_defaults,
328   .options_len =        sizeof(manualroute_router_options_block),
329   .init =               manualroute_router_init,
330   .code =               manualroute_router_entry,
331   .tidyup =             NULL,     /* no tidyup entry */
332   .ri_flags =           0
333   },
334 #endif
335 #ifdef ROUTER_QUERYPROGRAM
336   {
337   .driver_name =        US"queryprogram",
338   .options =            queryprogram_router_options,
339   .options_count =      &queryprogram_router_options_count,
340   .options_block =      &queryprogram_router_option_defaults,
341   .options_len =        sizeof(queryprogram_router_options_block),
342   .init =               queryprogram_router_init,
343   .code =               queryprogram_router_entry,
344   .tidyup =             NULL,     /* no tidyup entry */
345   .ri_flags =           0
346   },
347 #endif
348 #ifdef ROUTER_REDIRECT
349   {
350   .driver_name =        US"redirect",
351   .options =            redirect_router_options,
352   .options_count =      &redirect_router_options_count,
353   .options_block =      &redirect_router_option_defaults,
354   .options_len =        sizeof(redirect_router_options_block),
355   .init =               redirect_router_init,
356   .code =               redirect_router_entry,
357   .tidyup =             NULL,     /* no tidyup entry */
358   .ri_flags =           ri_notransport
359   },
360 #endif
361   { US"" }
362 };
363
364
365
366 transport_info transports_available[] = {
367 #ifdef TRANSPORT_APPENDFILE
368   {
369   .driver_name =        US"appendfile",
370   .options =            appendfile_transport_options,
371   .options_count =      &appendfile_transport_options_count,
372   .options_block =      &appendfile_transport_option_defaults,       /* private options defaults */
373   .options_len =        sizeof(appendfile_transport_options_block),
374   .init =               appendfile_transport_init,
375   .code =               appendfile_transport_entry,
376   .tidyup =             NULL,
377   .closedown =          NULL,
378   .local =              TRUE
379   },
380 #endif
381 #ifdef TRANSPORT_AUTOREPLY
382   {
383   .driver_name =        US"autoreply",
384   .options =            autoreply_transport_options,
385   .options_count =      &autoreply_transport_options_count,
386   .options_block =      &autoreply_transport_option_defaults,
387   .options_len =        sizeof(autoreply_transport_options_block),
388   .init =               autoreply_transport_init,
389   .code =               autoreply_transport_entry,
390   .tidyup =             NULL,
391   .closedown =          NULL,
392   .local =              TRUE
393   },
394 #endif
395 #ifdef TRANSPORT_LMTP
396   {
397   .driver_name =        US"lmtp",
398   .options =            lmtp_transport_options,
399   .options_count =      &lmtp_transport_options_count,
400   .options_block =      &lmtp_transport_option_defaults,
401   .options_len =        sizeof(lmtp_transport_options_block),
402   .init =               lmtp_transport_init,
403   .code =               lmtp_transport_entry,
404   .tidyup =             NULL,
405   .closedown =          NULL,
406   .local =              TRUE
407   },
408 #endif
409 #ifdef TRANSPORT_PIPE
410   {
411   .driver_name =        US"pipe",
412   .options =            pipe_transport_options,
413   .options_count =      &pipe_transport_options_count,
414   .options_block =      &pipe_transport_option_defaults,
415   .options_len =        sizeof(pipe_transport_options_block),
416   .init =               pipe_transport_init,
417   .code =               pipe_transport_entry,
418   .tidyup =             NULL,
419   .closedown =          NULL,
420   .local =              TRUE
421   },
422 #endif
423 #ifdef EXPERIMENTAL_QUEUEFILE
424   {
425   .driver_name =        US"queuefile",
426   .options =            queuefile_transport_options,
427   .options_count =      &queuefile_transport_options_count,
428   .options_block =      &queuefile_transport_option_defaults,
429   .options_len =        sizeof(queuefile_transport_options_block),
430   .init =               queuefile_transport_init,
431   .code =               queuefile_transport_entry,
432   .tidyup =             NULL,
433   .closedown =          NULL,
434   .local =              TRUE
435   },
436 #endif
437 #ifdef TRANSPORT_SMTP
438   {
439   .driver_name =        US"smtp",
440   .options =            smtp_transport_options,
441   .options_count =      &smtp_transport_options_count,
442   .options_block =      &smtp_transport_option_defaults,
443   .options_len =        sizeof(smtp_transport_options_block),
444   .init =               smtp_transport_init,
445   .code =               smtp_transport_entry,
446   .tidyup =             NULL,
447   .closedown =          smtp_transport_closedown,
448   .local =              FALSE
449   },
450 #endif
451   { US"" }
452 };
453
454 #ifndef MACRO_PREDEF
455
456 gstring *
457 auth_show_supported(gstring * g)
458 {
459 g = string_cat(g, US"Authenticators:");
460 for (auth_info * ai = auths_available; ai->driver_name[0]; ai++)
461         g = string_fmt_append(g, " %s", ai->driver_name);
462 return string_cat(g, US"\n");
463 }
464
465 gstring *
466 route_show_supported(gstring * g)
467 {
468 g = string_cat(g, US"Routers:");
469 for (router_info * rr = routers_available; rr->driver_name[0]; rr++)
470         g = string_fmt_append(g, " %s", rr->driver_name);
471 return string_cat(g, US"\n");
472 }
473
474 gstring *
475 transport_show_supported(gstring * g)
476 {
477 g = string_cat(g, US"Transports:");
478 #ifdef TRANSPORT_APPENDFILE
479   g = string_cat(g, US" appendfile");
480   #ifdef SUPPORT_MAILDIR
481     g = string_cat(g, US"/maildir");    /* damn these subclasses */
482   #endif
483   #ifdef SUPPORT_MAILSTORE
484     g = string_cat(g, US"/mailstore");
485   #endif
486   #ifdef SUPPORT_MBX
487     g = string_cat(g, US"/mbx");
488   #endif
489 #endif
490 #ifdef TRANSPORT_AUTOREPLY
491   g = string_cat(g, US" autoreply");
492 #endif
493 #ifdef TRANSPORT_LMTP
494   g = string_cat(g, US" lmtp");
495 #endif
496 #ifdef TRANSPORT_PIPE
497   g = string_cat(g, US" pipe");
498 #endif
499 #ifdef EXPERIMENTAL_QUEUEFILE
500   g = string_cat(g, US" queuefile");
501 #endif
502 #ifdef TRANSPORT_SMTP
503   g = string_cat(g, US" smtp");
504 #endif
505 return string_cat(g, US"\n");
506 }
507
508
509
510 struct lookupmodulestr
511 {
512   void *dl;
513   struct lookup_module_info *info;
514   struct lookupmodulestr *next;
515 };
516
517 static struct lookupmodulestr *lookupmodules = NULL;
518
519 static void
520 addlookupmodule(void *dl, struct lookup_module_info *info)
521 {
522 struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
523
524 p->dl = dl;
525 p->info = info;
526 p->next = lookupmodules;
527 lookupmodules = p;
528 lookup_list_count += info->lookupcount;
529 }
530
531 /* only valid after lookup_list and lookup_list_count are assigned */
532 static void
533 add_lookup_to_list(lookup_info *info)
534 {
535 /* need to add the lookup to lookup_list, sorted */
536 int pos = 0;
537
538 /* strategy is to go through the list until we find
539 either an empty spot or a name that is higher.
540 this can't fail because we have enough space. */
541
542 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
543   pos++;
544
545 if (lookup_list[pos])
546   {
547   /* need to insert it, so move all the other items up
548   (last slot is still empty, of course) */
549
550   memmove(&lookup_list[pos+1], &lookup_list[pos],
551           sizeof(lookup_info *) * (lookup_list_count-pos-1));
552   }
553 lookup_list[pos] = info;
554 }
555
556
557 /* These need to be at file level for old versions of gcc (2.95.2 reported),
558  * which give parse errors on an extern in function scope.  Each entry needs
559  * to also be invoked in init_lookup_list() below  */
560
561 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
562 extern lookup_module_info cdb_lookup_module_info;
563 #endif
564 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
565 extern lookup_module_info dbmdb_lookup_module_info;
566 #endif
567 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
568 extern lookup_module_info dnsdb_lookup_module_info;
569 #endif
570 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
571 extern lookup_module_info dsearch_lookup_module_info;
572 #endif
573 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
574 extern lookup_module_info ibase_lookup_module_info;
575 #endif
576 #if defined(LOOKUP_JSON)
577 extern lookup_module_info json_lookup_module_info;
578 #endif
579 #if defined(LOOKUP_LDAP)
580 extern lookup_module_info ldap_lookup_module_info;
581 #endif
582 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
583 extern lookup_module_info lsearch_lookup_module_info;
584 #endif
585 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
586 extern lookup_module_info mysql_lookup_module_info;
587 #endif
588 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
589 extern lookup_module_info nis_lookup_module_info;
590 #endif
591 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
592 extern lookup_module_info nisplus_lookup_module_info;
593 #endif
594 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
595 extern lookup_module_info oracle_lookup_module_info;
596 #endif
597 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
598 extern lookup_module_info passwd_lookup_module_info;
599 #endif
600 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
601 extern lookup_module_info pgsql_lookup_module_info;
602 #endif
603 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
604 extern lookup_module_info redis_lookup_module_info;
605 #endif
606 #if defined(LOOKUP_LMDB)
607 extern lookup_module_info lmdb_lookup_module_info;
608 #endif
609 #if defined(SUPPORT_SPF)
610 extern lookup_module_info spf_lookup_module_info;
611 #endif
612 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
613 extern lookup_module_info sqlite_lookup_module_info;
614 #endif
615 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
616 extern lookup_module_info testdb_lookup_module_info;
617 #endif
618 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
619 extern lookup_module_info whoson_lookup_module_info;
620 #endif
621
622 extern lookup_module_info readsock_lookup_module_info;
623
624
625 void
626 init_lookup_list(void)
627 {
628 #ifdef LOOKUP_MODULE_DIR
629 DIR *dd;
630 struct dirent *ent;
631 int countmodules = 0;
632 int moduleerrors = 0;
633 #endif
634 static BOOL lookup_list_init_done = FALSE;
635 rmark reset_point;
636
637 if (lookup_list_init_done)
638   return;
639 reset_point = store_mark();
640 lookup_list_init_done = TRUE;
641
642 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
643 addlookupmodule(NULL, &cdb_lookup_module_info);
644 #endif
645
646 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
647 addlookupmodule(NULL, &dbmdb_lookup_module_info);
648 #endif
649
650 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
651 addlookupmodule(NULL, &dnsdb_lookup_module_info);
652 #endif
653
654 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
655 addlookupmodule(NULL, &dsearch_lookup_module_info);
656 #endif
657
658 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
659 addlookupmodule(NULL, &ibase_lookup_module_info);
660 #endif
661
662 #ifdef LOOKUP_LDAP
663 addlookupmodule(NULL, &ldap_lookup_module_info);
664 #endif
665
666 #ifdef LOOKUP_JSON
667 addlookupmodule(NULL, &json_lookup_module_info);
668 #endif
669
670 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
671 addlookupmodule(NULL, &lsearch_lookup_module_info);
672 #endif
673
674 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
675 addlookupmodule(NULL, &mysql_lookup_module_info);
676 #endif
677
678 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
679 addlookupmodule(NULL, &nis_lookup_module_info);
680 #endif
681
682 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
683 addlookupmodule(NULL, &nisplus_lookup_module_info);
684 #endif
685
686 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
687 addlookupmodule(NULL, &oracle_lookup_module_info);
688 #endif
689
690 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
691 addlookupmodule(NULL, &passwd_lookup_module_info);
692 #endif
693
694 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
695 addlookupmodule(NULL, &pgsql_lookup_module_info);
696 #endif
697
698 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
699 addlookupmodule(NULL, &redis_lookup_module_info);
700 #endif
701
702 #ifdef LOOKUP_LMDB
703 addlookupmodule(NULL, &lmdb_lookup_module_info);
704 #endif
705
706 #ifdef SUPPORT_SPF
707 addlookupmodule(NULL, &spf_lookup_module_info);
708 #endif
709
710 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
711 addlookupmodule(NULL, &sqlite_lookup_module_info);
712 #endif
713
714 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
715 addlookupmodule(NULL, &testdb_lookup_module_info);
716 #endif
717
718 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
719 addlookupmodule(NULL, &whoson_lookup_module_info);
720 #endif
721
722 addlookupmodule(NULL, &readsock_lookup_module_info);
723
724 #ifdef LOOKUP_MODULE_DIR
725 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
726   {
727   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
728   log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
729   }
730 else
731   {
732   const pcre2_code * regex_islookupmod = regex_must_compile(
733     US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
734
735   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
736   while ((ent = readdir(dd)))
737     {
738     char * name = ent->d_name;
739     int len = (int)strlen(name);
740     if (regex_match(regex_islookupmod, US name, len, NULL))
741       {
742       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
743       void *dl;
744       struct lookup_module_info *info;
745       const char *errormsg;
746
747       /* SRH: am I being paranoid here or what? */
748       if (pathnamelen > big_buffer_size)
749         {
750         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
751         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
752         continue;
753         }
754
755       /* SRH: snprintf here? */
756       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
757
758       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
759         {
760         errormsg = dlerror();
761         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
762         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
763         moduleerrors++;
764         continue;
765         }
766
767       /* FreeBSD nsdispatch() can trigger dlerror() errors about
768       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
769       state before calling dlsym(), so that any error afterwards only comes
770       from dlsym().  */
771
772       errormsg = dlerror();
773
774       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
775       if ((errormsg = dlerror()))
776         {
777         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
778         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
779         dlclose(dl);
780         moduleerrors++;
781         continue;
782         }
783       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
784         {
785         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
786         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
787         dlclose(dl);
788         moduleerrors++;
789         continue;
790         }
791
792       addlookupmodule(dl, info);
793       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
794       countmodules++;
795       }
796     }
797   store_free((void*)regex_islookupmod);
798   closedir(dd);
799   }
800
801 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
802 #endif
803
804 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
805
806 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
807 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
808
809 /* now add all lookups to the real list */
810 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
811   for (int j = 0; j < p->info->lookupcount; j++)
812     add_lookup_to_list(p->info->lookups[j]);
813 store_reset(reset_point);
814 /* just to be sure */
815 lookupmodules = NULL;
816 }
817
818 #endif  /*!MACRO_PREDEF*/
819 /* End of drtables.c */