026f2ff97b712b7d71b5a682747e155d57fffe56
[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
234 router_info * routers_available = NULL;
235 transport_info * transports_available = NULL;
236
237
238
239 #ifndef MACRO_PREDEF
240
241 gstring *
242 auth_show_supported(gstring * g)
243 {
244 g = string_cat(g, US"Authenticators:");
245 for (auth_info * ai = auths_available_oldarray; ai->drinfo.driver_name[0]; ai++)
246         g = string_fmt_append(g, " %s", ai->drinfo.driver_name);
247 return string_cat(g, US"\n");
248 }
249
250 gstring *
251 route_show_supported(gstring * g)
252 {
253 uschar * b = US""               /* static-build router names */
254 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
255   " accept"
256 #endif
257 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
258   " dnslookup"
259 #endif
260 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
261   " ipliteral"
262 #endif
263 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
264   " iplookup"
265 #endif
266 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
267   " manualroute"
268 #endif
269 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
270   " redirect"
271 #endif
272 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
273   " queryprogram"
274 #endif
275   ;
276
277 uschar * d = US""               /* dynamic-module router names */
278 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
279   " accept"
280 #endif
281 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
282   " dnslookup"
283 #endif
284 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
285   " ipliteral"
286 #endif
287 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
288   " iplookup"
289 #endif
290 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
291   " manualroute"
292 #endif
293 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
294   " redirect"
295 #endif
296 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
297   " queryprogram"
298 #endif
299   ;
300
301 if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
302 if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
303 return g;
304 }
305
306 gstring *
307 transport_show_supported(gstring * g)
308 {
309 uschar * b = US""               /* static-build transportnames */
310 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
311   " appendfile"
312 # ifdef SUPPORT_MAILDIR
313     "/maildir"
314 # endif
315 # ifdef SUPPORT_MAILSTORE
316     "/mailstore"
317 # endif
318 # ifdef SUPPORT_MBX
319     "/mbx"
320 # endif
321 #endif
322 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
323   " autoreply"
324 #endif
325 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
326   " lmtp"
327 #endif
328 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
329   " pipe"
330 #endif
331 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
332   " queuefile"
333 #endif
334 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
335   " smtp"
336 #endif
337   ;
338
339 uschar * d = US""               /* dynamic-module transportnames */
340 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
341   " appendfile"
342 # ifdef SUPPORT_MAILDIR
343     "/maildir"
344 # endif
345 # ifdef SUPPORT_MAILSTORE
346     "/mailstore"
347 # endif
348 # ifdef SUPPORT_MBX
349     "/mbx"
350 # endif
351 #endif
352 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
353   " autoreply"
354 #endif
355 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
356   " lmtp"
357 #endif
358 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
359   " pipe"
360 #endif
361 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
362   " queuefile"
363 #endif
364 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
365   " smtp"
366 #endif
367   ;
368
369 if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
370 if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
371 return g;
372 }
373
374
375
376 struct lookupmodulestr
377 {
378   void *dl;
379   struct lookup_module_info *info;
380   struct lookupmodulestr *next;
381 };
382
383 static struct lookupmodulestr *lookupmodules = NULL;
384
385 static void
386 addlookupmodule(void *dl, struct lookup_module_info *info)
387 {
388 struct lookupmodulestr * p =
389   store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
390
391 p->dl = dl;
392 p->info = info;
393 p->next = lookupmodules;
394 lookupmodules = p;
395 lookup_list_count += info->lookupcount;
396 }
397
398 /* only valid after lookup_list and lookup_list_count are assigned */
399 static void
400 add_lookup_to_list(lookup_info *info)
401 {
402 /* need to add the lookup to lookup_list, sorted */
403 int pos = 0;
404
405 /* strategy is to go through the list until we find
406 either an empty spot or a name that is higher.
407 this can't fail because we have enough space. */
408
409 while (lookup_list[pos] && (Ustrcmp(lookup_list[pos]->name, info->name) <= 0))
410   pos++;
411
412 if (lookup_list[pos])
413   {
414   /* need to insert it, so move all the other items up
415   (last slot is still empty, of course) */
416
417   memmove(&lookup_list[pos+1], &lookup_list[pos],
418           sizeof(lookup_info *) * (lookup_list_count-pos-1));
419   }
420 lookup_list[pos] = info;
421 }
422
423
424 /* These need to be at file level for old versions of gcc (2.95.2 reported),
425 which give parse errors on an extern in function scope.  Each entry needs
426 to also be invoked in init_lookup_list() below  */
427
428 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
429 extern lookup_module_info cdb_lookup_module_info;
430 #endif
431 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
432 extern lookup_module_info dbmdb_lookup_module_info;
433 #endif
434 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
435 extern lookup_module_info dnsdb_lookup_module_info;
436 #endif
437 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
438 extern lookup_module_info dsearch_lookup_module_info;
439 #endif
440 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
441 extern lookup_module_info ibase_lookup_module_info;
442 #endif
443 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
444 extern lookup_module_info json_lookup_module_info;
445 #endif
446 #if defined(LOOKUP_LDAP)
447 extern lookup_module_info ldap_lookup_module_info;
448 #endif
449 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
450 extern lookup_module_info lsearch_lookup_module_info;
451 #endif
452 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
453 extern lookup_module_info mysql_lookup_module_info;
454 #endif
455 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
456 extern lookup_module_info nis_lookup_module_info;
457 #endif
458 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
459 extern lookup_module_info nisplus_lookup_module_info;
460 #endif
461 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
462 extern lookup_module_info oracle_lookup_module_info;
463 #endif
464 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
465 extern lookup_module_info passwd_lookup_module_info;
466 #endif
467 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
468 extern lookup_module_info pgsql_lookup_module_info;
469 #endif
470 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
471 extern lookup_module_info redis_lookup_module_info;
472 #endif
473 #if defined(LOOKUP_LMDB)
474 extern lookup_module_info lmdb_lookup_module_info;
475 #endif
476 #if defined(SUPPORT_SPF)
477 extern lookup_module_info spf_lookup_module_info;
478 #endif
479 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
480 extern lookup_module_info sqlite_lookup_module_info;
481 #endif
482 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
483 extern lookup_module_info testdb_lookup_module_info;
484 #endif
485 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
486 extern lookup_module_info whoson_lookup_module_info;
487 #endif
488
489 extern lookup_module_info readsock_lookup_module_info;
490
491
492 void
493 init_lookup_list(void)
494 {
495 #ifdef LOOKUP_MODULE_DIR
496 DIR * dd;
497 struct dirent * ent;
498 int countmodules = 0;
499 int moduleerrors = 0;
500 #endif
501 static BOOL lookup_list_init_done = FALSE;
502 rmark reset_point;
503
504 if (lookup_list_init_done)
505   return;
506 reset_point = store_mark();
507 lookup_list_init_done = TRUE;
508
509 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
510 addlookupmodule(NULL, &cdb_lookup_module_info);
511 #endif
512
513 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
514 addlookupmodule(NULL, &dbmdb_lookup_module_info);
515 #endif
516
517 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
518 addlookupmodule(NULL, &dnsdb_lookup_module_info);
519 #endif
520
521 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
522 addlookupmodule(NULL, &dsearch_lookup_module_info);
523 #endif
524
525 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
526 addlookupmodule(NULL, &ibase_lookup_module_info);
527 #endif
528
529 #ifdef LOOKUP_LDAP
530 addlookupmodule(NULL, &ldap_lookup_module_info);
531 #endif
532
533 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
534 addlookupmodule(NULL, &json_lookup_module_info);
535 #endif
536
537 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
538 addlookupmodule(NULL, &lsearch_lookup_module_info);
539 #endif
540
541 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
542 addlookupmodule(NULL, &mysql_lookup_module_info);
543 #endif
544
545 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
546 addlookupmodule(NULL, &nis_lookup_module_info);
547 #endif
548
549 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
550 addlookupmodule(NULL, &nisplus_lookup_module_info);
551 #endif
552
553 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
554 addlookupmodule(NULL, &oracle_lookup_module_info);
555 #endif
556
557 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
558 addlookupmodule(NULL, &passwd_lookup_module_info);
559 #endif
560
561 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
562 addlookupmodule(NULL, &pgsql_lookup_module_info);
563 #endif
564
565 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
566 addlookupmodule(NULL, &redis_lookup_module_info);
567 #endif
568
569 #ifdef LOOKUP_LMDB
570 addlookupmodule(NULL, &lmdb_lookup_module_info);
571 #endif
572
573 #ifdef SUPPORT_SPF
574 addlookupmodule(NULL, &spf_lookup_module_info);
575 #endif
576
577 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
578 addlookupmodule(NULL, &sqlite_lookup_module_info);
579 #endif
580
581 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
582 addlookupmodule(NULL, &testdb_lookup_module_info);
583 #endif
584
585 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
586 addlookupmodule(NULL, &whoson_lookup_module_info);
587 #endif
588
589 /* This is a custom expansion, and not available as either
590 a list-syntax lookup or a lookup expansion. However, it is
591 implemented by a lookup module. */
592
593 addlookupmodule(NULL, &readsock_lookup_module_info);
594
595 #ifdef LOOKUP_MODULE_DIR
596 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
597   {
598   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
599   log_write(0, LOG_MAIN|LOG_PANIC,
600           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
601   }
602 else
603   {
604   const pcre2_code * regex_islookupmod = regex_must_compile(
605     US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
606
607   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
608   while ((ent = readdir(dd)))
609     {
610     char * name = ent->d_name;
611     int len = (int)strlen(name);
612     if (regex_match(regex_islookupmod, US name, len, NULL))
613       {
614       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
615       void *dl;
616       struct lookup_module_info *info;
617       const char *errormsg;
618
619       /* SRH: am I being paranoid here or what? */
620       if (pathnamelen > big_buffer_size)
621         {
622         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
623         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
624         continue;
625         }
626
627       /* SRH: snprintf here? */
628       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
629
630       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
631         {
632         errormsg = dlerror();
633         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
634         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
635         moduleerrors++;
636         continue;
637         }
638
639       /* FreeBSD nsdispatch() can trigger dlerror() errors about
640       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
641       state before calling dlsym(), so that any error afterwards only comes
642       from dlsym().  */
643
644       errormsg = dlerror();
645
646       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
647       if ((errormsg = dlerror()))
648         {
649         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
650         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
651         dlclose(dl);
652         moduleerrors++;
653         continue;
654         }
655       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
656         {
657         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
658         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
659         dlclose(dl);
660         moduleerrors++;
661         continue;
662         }
663
664       addlookupmodule(dl, info);
665       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
666       countmodules++;
667       }
668     }
669   store_free((void*)regex_islookupmod);
670   closedir(dd);
671   }
672
673 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
674 #endif
675
676 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
677
678 lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
679 memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);
680
681 /* now add all lookups to the real list */
682 for (struct lookupmodulestr * p = lookupmodules; p; p = p->next)
683   for (int j = 0; j < p->info->lookupcount; j++)
684     add_lookup_to_list(p->info->lookups[j]);
685 store_reset(reset_point);
686 /* just to be sure */
687 lookupmodules = NULL;
688 }
689
690 #endif  /*!MACRO_PREDEF*/
691 /* End of drtables.c */