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