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