Move from table to tree for lookups
[exim.git] / src / src / drtables.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
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 tree_node * lookups_tree = NULL;
23 unsigned lookup_list_count = 0;
24
25 /* Lists of information about which drivers are included in the exim binary. */
26
27 auth_info * auths_available= NULL;
28 router_info * routers_available = NULL;
29 transport_info * transports_available = NULL;
30
31
32
33 #ifndef MACRO_PREDEF
34
35 gstring *
36 auth_show_supported(gstring * g)
37 {
38 uschar * b = US""               /* static-build authenticatornames */
39 #if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5!=2
40   " cram_md5"
41 #endif
42 #if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL!=2
43   " cyrus_sasl"
44 #endif
45 #if defined(AUTH_DOVECOT) && AUTH_DOVECOT!=2
46   " dovecot"
47 #endif
48 #if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL!=2
49   " external"
50 #endif
51 #if defined(AUTH_GSASL) && AUTH_GSASL!=2
52   " gsasl"
53 #endif
54 #if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI!=2
55   " heimdal_gssapi"
56 #endif
57 #if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT!=2
58   " plaintext"
59 #endif
60 #if defined(AUTH_SPA) && AUTH_SPA!=2
61   " spa"
62 #endif
63 #if defined(AUTH_TLS) && AUTH_TLS!=2
64   " tls"
65 #endif
66   ;
67
68 uschar * d = US""               /* dynamic-module authenticator names */
69 #if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5==2
70   " cram_md5"
71 #endif
72 #if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL==2
73   " cyrus_sasl"
74 #endif
75 #if defined(AUTH_DOVECOT) && AUTH_DOVECOT==2
76   " dovecot"
77 #endif
78 #if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL==2
79   " external"
80 #endif
81 #if defined(AUTH_GSASL) && AUTH_GSASL==2
82   " gsasl"
83 #endif
84 #if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI==2
85   " heimdal_gssapi"
86 #endif
87 #if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT==2
88   " plaintext"
89 #endif
90 #if defined(AUTH_SPA) && AUTH_SPA==2
91   " spa"
92 #endif
93 #if defined(AUTH_TLS) && AUTH_TLS==2
94   " tls"
95 #endif
96   ;
97
98 if (*b) g = string_fmt_append(g, "Authenticators (built-in):%s\n", b);
99 if (*d) g = string_fmt_append(g, "Authenticators (dynamic): %s\n", d);
100 return g;
101 }
102
103 gstring *
104 route_show_supported(gstring * g)
105 {
106 uschar * b = US""               /* static-build router names */
107 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
108   " accept"
109 #endif
110 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
111   " dnslookup"
112 #endif
113 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
114   " ipliteral"
115 #endif
116 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
117   " iplookup"
118 #endif
119 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
120   " manualroute"
121 #endif
122 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
123   " redirect"
124 #endif
125 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
126   " queryprogram"
127 #endif
128   ;
129
130 uschar * d = US""               /* dynamic-module router names */
131 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
132   " accept"
133 #endif
134 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
135   " dnslookup"
136 #endif
137 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
138   " ipliteral"
139 #endif
140 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
141   " iplookup"
142 #endif
143 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
144   " manualroute"
145 #endif
146 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
147   " redirect"
148 #endif
149 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
150   " queryprogram"
151 #endif
152   ;
153
154 if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
155 if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
156 return g;
157 }
158
159 gstring *
160 transport_show_supported(gstring * g)
161 {
162 uschar * b = US""               /* static-build transportnames */
163 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
164   " appendfile"
165 # ifdef SUPPORT_MAILDIR
166     "/maildir"
167 # endif
168 # ifdef SUPPORT_MAILSTORE
169     "/mailstore"
170 # endif
171 # ifdef SUPPORT_MBX
172     "/mbx"
173 # endif
174 #endif
175 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
176   " autoreply"
177 #endif
178 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
179   " lmtp"
180 #endif
181 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
182   " pipe"
183 #endif
184 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
185   " queuefile"
186 #endif
187 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
188   " smtp"
189 #endif
190   ;
191
192 uschar * d = US""               /* dynamic-module transportnames */
193 #if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
194   " appendfile"
195 # ifdef SUPPORT_MAILDIR
196     "/maildir"
197 # endif
198 # ifdef SUPPORT_MAILSTORE
199     "/mailstore"
200 # endif
201 # ifdef SUPPORT_MBX
202     "/mbx"
203 # endif
204 #endif
205 #if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
206   " autoreply"
207 #endif
208 #if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
209   " lmtp"
210 #endif
211 #if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
212   " pipe"
213 #endif
214 #if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
215   " queuefile"
216 #endif
217 #if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
218   " smtp"
219 #endif
220   ;
221
222 if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
223 if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
224 return g;
225 }
226
227
228
229 static void
230 add_lookup_to_tree(lookup_info * li)
231 {
232 tree_node * new = store_get_perm(sizeof(tree_node) + Ustrlen(li->name),
233                                                         GET_UNTAINTED);
234 new->data.ptr = (void *)li;
235 Ustrcpy(new->name, li->name);
236 if (tree_insertnode(&lookups_tree, new))
237   li->acq_num = lookup_list_count++;
238 else
239   log_write(0, LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name);
240 }
241
242
243 /* Add all the lookup types provided by the module */
244 static void
245 addlookupmodule(const struct lookup_module_info * lmi)
246 {
247 for (int j = 0; j < lmi->lookupcount; j++)
248   add_lookup_to_tree(lmi->lookups[j]);
249 }
250
251
252
253 static unsigned hunt_acq;
254
255 static void
256 acq_cb(uschar * name, uschar * ptr, void * ctx)
257 {
258 lookup_info * li = (lookup_info *)ptr;
259 if (li->acq_num == hunt_acq) *(lookup_info **)ctx = li;
260 }
261
262 /*XXX many of the calls here could instead use a name on the quoted-pool */
263 const lookup_info *
264 lookup_with_acq_num(unsigned k)
265 {
266 const lookup_info * li = NULL;
267 hunt_acq = k;
268 tree_walk(lookups_tree, acq_cb, &li);
269 return li;
270 }
271
272
273
274 /* These need to be at file level for old versions of gcc (2.95.2 reported),
275 which give parse errors on an extern in function scope.  Each entry needs
276 to also be invoked in init_lookup_list() below  */
277
278 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
279 extern lookup_module_info cdb_lookup_module_info;
280 #endif
281 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
282 extern lookup_module_info dbmdb_lookup_module_info;
283 #endif
284 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
285 extern lookup_module_info dnsdb_lookup_module_info;
286 #endif
287 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
288 extern lookup_module_info dsearch_lookup_module_info;
289 #endif
290 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
291 extern lookup_module_info ibase_lookup_module_info;
292 #endif
293 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
294 extern lookup_module_info json_lookup_module_info;
295 #endif
296 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
297 extern lookup_module_info ldap_lookup_module_info;
298 #endif
299 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
300 extern lookup_module_info lsearch_lookup_module_info;
301 #endif
302 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
303 extern lookup_module_info mysql_lookup_module_info;
304 #endif
305 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
306 extern lookup_module_info nis_lookup_module_info;
307 #endif
308 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
309 extern lookup_module_info nisplus_lookup_module_info;
310 #endif
311 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
312 extern lookup_module_info oracle_lookup_module_info;
313 #endif
314 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
315 extern lookup_module_info passwd_lookup_module_info;
316 #endif
317 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
318 extern lookup_module_info pgsql_lookup_module_info;
319 #endif
320 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
321 extern lookup_module_info redis_lookup_module_info;
322 #endif
323 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
324 extern lookup_module_info lmdb_lookup_module_info;
325 #endif
326 #if defined(SUPPORT_SPF)
327 extern lookup_module_info spf_lookup_module_info;
328 #endif
329 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
330 extern lookup_module_info sqlite_lookup_module_info;
331 #endif
332 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
333 extern lookup_module_info testdb_lookup_module_info;
334 #endif
335 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
336 extern lookup_module_info whoson_lookup_module_info;
337 #endif
338
339 extern lookup_module_info readsock_lookup_module_info;
340
341
342 void
343 init_lookup_list(void)
344 {
345 #ifdef LOOKUP_MODULE_DIR
346 DIR * dd;
347 struct dirent * ent;
348 int countmodules = 0;
349 int moduleerrors = 0;
350 #endif
351 static BOOL lookup_list_init_done = FALSE;
352
353 if (lookup_list_init_done)
354   return;
355 lookup_list_init_done = TRUE;
356
357 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
358 addlookupmodule(&cdb_lookup_module_info);
359 #endif
360
361 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
362 addlookupmodule(&dbmdb_lookup_module_info);
363 #endif
364
365 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
366 addlookupmodule(&dnsdb_lookup_module_info);
367 #endif
368
369 #if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
370 addlookupmodule(&dsearch_lookup_module_info);
371 #endif
372
373 #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
374 addlookupmodule(&ibase_lookup_module_info);
375 #endif
376
377 #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
378 addlookupmodule(&ldap_lookup_module_info);
379 #endif
380
381 #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
382 addlookupmodule(&json_lookup_module_info);
383 #endif
384
385 #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
386 addlookupmodule(&lsearch_lookup_module_info);
387 #endif
388
389 #if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
390 addlookupmodule(&mysql_lookup_module_info);
391 #endif
392
393 #if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
394 addlookupmodule(&nis_lookup_module_info);
395 #endif
396
397 #if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
398 addlookupmodule(&nisplus_lookup_module_info);
399 #endif
400
401 #if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
402 addlookupmodule(&oracle_lookup_module_info);
403 #endif
404
405 #if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
406 addlookupmodule(&passwd_lookup_module_info);
407 #endif
408
409 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
410 addlookupmodule(&pgsql_lookup_module_info);
411 #endif
412
413 #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
414 addlookupmodule(&redis_lookup_module_info);
415 #endif
416
417 #if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2
418 addlookupmodule(&lmdb_lookup_module_info);
419 #endif
420
421 #ifdef SUPPORT_SPF
422 addlookupmodule(&spf_lookup_module_info);
423 #endif
424
425 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
426 addlookupmodule(&sqlite_lookup_module_info);
427 #endif
428
429 #if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
430 addlookupmodule(&testdb_lookup_module_info);
431 #endif
432
433 #if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
434 addlookupmodule(&whoson_lookup_module_info);
435 #endif
436
437 /* This is a custom expansion, and not available as either
438 a list-syntax lookup or a lookup expansion. However, it is
439 implemented by a lookup module. */
440
441 addlookupmodule(&readsock_lookup_module_info);
442
443 #ifdef LOOKUP_MODULE_DIR
444 if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
445   {
446   DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
447   log_write(0, LOG_MAIN|LOG_PANIC,
448           "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
449   }
450 else
451   {
452   const pcre2_code * regex_islookupmod = regex_must_compile(
453     US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
454
455   DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
456   while ((ent = readdir(dd)))
457     {
458     char * name = ent->d_name;
459     int len = (int)strlen(name);
460     if (regex_match(regex_islookupmod, US name, len, NULL))
461       {
462       int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
463       void *dl;
464       struct lookup_module_info *info;
465       const char *errormsg;
466
467       /* SRH: am I being paranoid here or what? */
468       if (pathnamelen > big_buffer_size)
469         {
470         fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
471         log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
472         continue;
473         }
474
475       /* SRH: snprintf here? */
476       sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);
477
478       if (!(dl = dlopen(CS big_buffer, RTLD_NOW)))
479         {
480         errormsg = dlerror();
481         fprintf(stderr, "Error loading %s: %s\n", name, errormsg);
482         log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormsg);
483         moduleerrors++;
484         continue;
485         }
486
487       /* FreeBSD nsdispatch() can trigger dlerror() errors about
488       _nss_cache_cycle_prevention_function; we need to clear the dlerror()
489       state before calling dlsym(), so that any error afterwards only comes
490       from dlsym().  */
491
492       errormsg = dlerror();
493
494       info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
495       if ((errormsg = dlerror()))
496         {
497         fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
498         log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
499         dlclose(dl);
500         moduleerrors++;
501         continue;
502         }
503       if (info->magic != LOOKUP_MODULE_INFO_MAGIC)
504         {
505         fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
506         log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
507         dlclose(dl);
508         moduleerrors++;
509         continue;
510         }
511
512       addlookupmodule(info);
513       DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
514       countmodules++;
515       }
516     }
517   store_free((void*)regex_islookupmod);
518   closedir(dd);
519   }
520
521 DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
522 #endif
523
524 DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);
525
526 }
527
528 #endif  /*!MACRO_PREDEF*/
529 /* End of drtables.c */