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