0f64728b467ed89a1d296e857961f8629795bcb1
[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 /*XXX delete */
234 #ifdef ROUTER_DNSLOOKUP
235 # include "routers/dnslookup.h"
236 #endif
237
238 #ifdef ROUTER_MANUALROUTE
239 # include "routers/manualroute.h"
240 #endif
241
242 #ifdef ROUTER_IPLITERAL
243 # include "routers/ipliteral.h"
244 #endif
245
246 #ifdef ROUTER_IPLOOKUP
247 # include "routers/iplookup.h"
248 #endif
249
250 #ifdef ROUTER_QUERYPROGRAM
251 # include "routers/queryprogram.h"
252 #endif
253
254 #ifdef ROUTER_REDIRECT
255 # include "routers/redirect.h"
256 #endif
257
258 #ifdef TRANSPORT_APPENDFILE
259 # include "transports/appendfile.h"
260 #endif
261
262 #ifdef TRANSPORT_AUTOREPLY
263 # include "transports/autoreply.h"
264 #endif
265
266 #ifdef TRANSPORT_LMTP
267 # include "transports/lmtp.h"
268 #endif
269
270 #ifdef TRANSPORT_PIPE
271 # include "transports/pipe.h"
272 #endif
273
274 #ifdef EXPERIMENTAL_QUEUEFILE
275 # include "transports/queuefile.h"
276 #endif
277
278 #ifdef TRANSPORT_SMTP
279 # include "transports/smtp.h"
280 #endif
281
282
283 router_info * routers_available_newlist = NULL;
284
285 /* Now set up the structures, terminated by an entry with a null name. */
286
287 router_info routers_available_oldarray[] = {
288   { .drinfo = { .driver_name = US"" }}
289 };
290
291
292
293 transport_info * transports_available_newlist = NULL;
294 transport_info transports_available_oldarray[] = {
295 #ifdef TRANSPORT_APPENDFILE
296   {
297   .drinfo = {
298     .driver_name =      US"appendfile",
299     .options =          appendfile_transport_options,
300     .options_count =    &appendfile_transport_options_count,
301     .options_block =    &appendfile_transport_option_defaults,       /* private options defaults */
302     .options_len =      sizeof(appendfile_transport_options_block),
303     .init =             appendfile_transport_init,
304     },
305   .code =               appendfile_transport_entry,
306   .tidyup =             NULL,
307   .closedown =          NULL,
308   .local =              TRUE
309   },
310 #endif
311 #ifdef TRANSPORT_AUTOREPLY
312   {
313   .drinfo = {
314     .driver_name =      US"autoreply",
315     .options =          autoreply_transport_options,
316     .options_count =    &autoreply_transport_options_count,
317     .options_block =    &autoreply_transport_option_defaults,
318     .options_len =      sizeof(autoreply_transport_options_block),
319     .init =             autoreply_transport_init,
320     },
321   .code =               autoreply_transport_entry,
322   .tidyup =             NULL,
323   .closedown =          NULL,
324   .local =              TRUE
325   },
326 #endif
327 #ifdef TRANSPORT_LMTP
328   {
329   .drinfo = {
330     .driver_name =      US"lmtp",
331     .options =          lmtp_transport_options,
332     .options_count =    &lmtp_transport_options_count,
333     .options_block =    &lmtp_transport_option_defaults,
334     .options_len =      sizeof(lmtp_transport_options_block),
335     .init =             lmtp_transport_init,
336     },
337   .code =               lmtp_transport_entry,
338   .tidyup =             NULL,
339   .closedown =          NULL,
340   .local =              TRUE
341   },
342 #endif
343 #ifdef TRANSPORT_PIPE
344   {
345   .drinfo = {
346     .driver_name =      US"pipe",
347     .options =          pipe_transport_options,
348     .options_count =    &pipe_transport_options_count,
349     .options_block =    &pipe_transport_option_defaults,
350     .options_len =      sizeof(pipe_transport_options_block),
351     .init =             pipe_transport_init,
352     },
353   .code =               pipe_transport_entry,
354   .tidyup =             NULL,
355   .closedown =          NULL,
356   .local =              TRUE
357   },
358 #endif
359 #ifdef EXPERIMENTAL_QUEUEFILE
360   {
361   .drinfo = {
362     .driver_name =      US"queuefile",
363     .options =          queuefile_transport_options,
364     .options_count =    &queuefile_transport_options_count,
365     .options_block =    &queuefile_transport_option_defaults,
366     .options_len =      sizeof(queuefile_transport_options_block),
367     .init =             queuefile_transport_init,
368     },
369   .code =               queuefile_transport_entry,
370   .tidyup =             NULL,
371   .closedown =          NULL,
372   .local =              TRUE
373   },
374 #endif
375 #ifdef TRANSPORT_SMTP
376   {
377   .drinfo = {
378     .driver_name =      US"smtp",
379     .options =          smtp_transport_options,
380     .options_count =    &smtp_transport_options_count,
381     .options_block =    &smtp_transport_option_defaults,
382     .options_len =      sizeof(smtp_transport_options_block),
383     .init =             smtp_transport_init,
384     },
385   .code =               smtp_transport_entry,
386   .tidyup =             NULL,
387   .closedown =          smtp_transport_closedown,
388   .local =              FALSE
389   },
390 #endif
391   { .drinfo = { .driver_name = US"" }}
392 };
393
394 #ifndef MACRO_PREDEF
395
396 gstring *
397 auth_show_supported(gstring * g)
398 {
399 g = string_cat(g, US"Authenticators:");
400 /*XXX these run off the static list as we want them before the conf is read */
401 /*XXX Could possibly check for dyn flag + file presence */
402 for (auth_info * ai = auths_available_oldarray; ai->drinfo.driver_name[0]; ai++)
403         g = string_fmt_append(g, " %s", ai->drinfo.driver_name);
404 return string_cat(g, US"\n");
405 }
406
407 gstring *
408 route_show_supported(gstring * g)
409 {
410 #ifdef old
411 g = string_cat(g, US"Routers:");
412 /*XXX these run off the static list as we want them before the conf is read */
413 /*XXX lookup_show_supported is in exim.c and just works off the #defines, with hardoded strings */
414 for (router_info * rr = routers_available_oldarray; rr->drinfo.driver_name[0]; rr++)
415         g = string_fmt_append(g, " %s", rr->drinfo.driver_name);
416 return string_cat(g, US"\n");
417 #else
418
419 uschar * b = US""               /* static-build router names */
420 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
421   " accept"
422 #endif
423 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
424   " dnslookup"
425 #endif
426 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
427   " ipliteral"
428 #endif
429 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
430   " iplookup"
431 #endif
432 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
433   " manualroute"
434 #endif
435 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
436   " redirect"
437 #endif
438 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
439   " queryprogram"
440 #endif
441   ;
442
443 uschar * d = US""               /* dynamic-module router names */
444 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
445   " accept"
446 #endif
447 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
448   " dnslookup"
449 #endif
450 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
451   " ipliteral"
452 #endif
453 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
454   " iplookup"
455 #endif
456 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
457   " manualroute"
458 #endif
459 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
460   " redirect"
461 #endif
462 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
463   " queryprogram"
464 #endif
465   ;
466
467 if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
468 if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
469 return g;
470 #endif  /*!old*/
471 }
472
473 gstring *
474 transport_show_supported(gstring * g)
475 {
476 g = string_cat(g, US"Transports:");
477 #ifdef TRANSPORT_APPENDFILE
478   g = string_cat(g, US" appendfile");
479   #ifdef SUPPORT_MAILDIR
480     g = string_cat(g, US"/maildir");    /* damn these subclasses */
481   #endif
482   #ifdef SUPPORT_MAILSTORE
483     g = string_cat(g, US"/mailstore");
484   #endif
485   #ifdef SUPPORT_MBX
486     g = string_cat(g, US"/mbx");
487   #endif
488 #endif
489 #ifdef TRANSPORT_AUTOREPLY
490   g = string_cat(g, US" autoreply");
491 #endif
492 #ifdef TRANSPORT_LMTP
493   g = string_cat(g, US" lmtp");
494 #endif
495 #ifdef TRANSPORT_PIPE
496   g = string_cat(g, US" pipe");
497 #endif
498 #ifdef EXPERIMENTAL_QUEUEFILE
499   g = string_cat(g, US" queuefile");
500 #endif
501 #ifdef TRANSPORT_SMTP
502   g = string_cat(g, US" smtp");
503 #endif
504 return string_cat(g, US"\n");
505 }
506
507
508
509 struct lookupmodulestr
510 {
511   void *dl;
512   struct lookup_module_info *info;
513   struct lookupmodulestr *next;
514 };
515
516 static struct lookupmodulestr *lookupmodules = NULL;
517
518 static void
519 addlookupmodule(void *dl, struct lookup_module_info *info)
520 {
521 struct lookupmodulestr * p =
522   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) && LOOKUP_JSON!=2
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 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
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 /* This is a custom expansion, and not available as either
723 a list-syntax lookup or a lookup expansion. However, it is
724 implemented by a lookup module. */
725
726 addlookupmodule(NULL, &readsock_lookup_module_info);
727
728 #ifdef LOOKUP_MODULE_DIR
729 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
730   {
731   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
732   log_write(0, LOG_MAIN|LOG_PANIC,
733           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
734   }
735 else
736   {
737   const pcre2_code * regex_islookupmod = regex_must_compile(
738     US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
739
740   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
741   while ((ent = readdir(dd)))
742     {
743     char * name = ent->d_name;
744     int len = (int)strlen(name);
745     if (regex_match(regex_islookupmod, US name, len, NULL))
746       {
747       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
748       void *dl;
749       struct lookup_module_info *info;
750       const char *errormsg;
751
752       /* SRH: am I being paranoid here or what? */
753       if (pathnamelen > big_buffer_size)
754         {
755         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
756         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
757         continue;
758         }
759
760       /* SRH: snprintf here? */
761       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
762
763       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
764         {
765         errormsg = dlerror();
766         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
767         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
768         moduleerrors++;
769         continue;
770         }
771
772       /* FreeBSD nsdispatch() can trigger dlerror() errors about
773       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
774       state before calling dlsym(), so that any error afterwards only comes
775       from dlsym().  */
776
777       errormsg = dlerror();
778
779       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
780       if ((errormsg = dlerror()))
781         {
782         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
783         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
784         dlclose(dl);
785         moduleerrors++;
786         continue;
787         }
788       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
789         {
790         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
791         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
792         dlclose(dl);
793         moduleerrors++;
794         continue;
795         }
796
797       addlookupmodule(dl, info);
798       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
799       countmodules++;
800       }
801     }
802   store_free((void*)regex_islookupmod);
803   closedir(dd);
804   }
805
806 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
807 #endif
808
809 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
810
811 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
812 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
813
814 /* now add all lookups to the real list */
815 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
816   for (int j = 0; j < p->info->lookupcount; j++)
817     add_lookup_to_list(p->info->lookups[j]);
818 store_reset(reset_point);
819 /* just to be sure */
820 lookupmodules = NULL;
821 }
822
823 #endif  /*!MACRO_PREDEF*/
824 /* End of drtables.c */