From: Jeremy Harris Date: Sun, 18 Aug 2024 17:46:44 +0000 (+0100) Subject: ldap lookups build as dynamic module X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/419d8549aad98eb3438593873332661e6fb1845e?hp=747736dc83324875bd6339f97f492747a3ad7fe5 ldap lookups build as dynamic module --- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index a5a8bd5f3..9a34f8ac2 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -14,8 +14,9 @@ Version 4.98 3. Events smtp:fail:protocol and smtp:fail:syntax - 4. JSON lookup support, all the router and authenticator drivers, and all the - transport drivers except smtp, can now be built as loadable modules + 4. JSON and LDAP lookup support, all the router and authenticator drivers, + and all the transport drivers except smtp, can now be built as loadable + modules Version 4.98 ------------ diff --git a/src/scripts/lookups-Makefile b/src/scripts/lookups-Makefile index 8dcac585b..40cca603f 100755 --- a/src/scripts/lookups-Makefile +++ b/src/scripts/lookups-Makefile @@ -163,17 +163,12 @@ exec > "$target" sed -n "1,/$tag_marker/p" < "$input" for name_mod in \ - CDB DBM:dbmdb DNSDB DSEARCH IBASE JSON LMDB LSEARCH MYSQL NIS NISPLUS ORACLE \ - PASSWD PGSQL REDIS SQLITE TESTDB WHOSON + CDB DBM:dbmdb DNSDB DSEARCH IBASE JSON LMDB LDAP LSEARCH MYSQL NIS NISPLUS \ + ORACLE PASSWD PGSQL REDIS SQLITE TESTDB WHOSON do emit_module_rule $name_mod done -if want_at_all LDAP -then - OBJ="${OBJ} ldap.o" -fi - # Because the variable is EXPERIMENTAL_SPF and not LOOKUP_SPF we # always include spf.o and compile a dummy if EXPERIMENTAL_SPF is not # defined. diff --git a/src/src/EDITME b/src/src/EDITME index 3353a4239..aeba7704a 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -416,10 +416,8 @@ TRANSPORT_SMTP=yes # the dynamic library and not the exim binary will be linked against the # library. # -# NOTE: LDAP cannot be built as a module! -# JSON cannot (yet). -# Also, PASSWD, DBM and DNSDB can but there is little point since the accesses -# are always needed by the Exim core. +# PASSWD, DBM and DNSDB can be build as modules but there is little point since +# the accesses are always needed by the Exim core. # # For Redis you need to have hiredis installed on your system # (https://github.com/redis/hiredis). @@ -479,6 +477,7 @@ LOOKUP_DNSDB=yes # If you don't set any of these, Exim assumes the original University of # Michigan (OpenLDAP 1) library. +# For building as a modules, set LOOKUP_LDAP_INCLUDE and LOOKUP_LDAP_LIBS #------------------------------------------------------------------------------ # The PCRE2 library is required for Exim. There is no longer an embedded @@ -538,6 +537,7 @@ SUPPORT_DANE=yes # # LOOKUP_INCLUDE += -I/usr/local/include # LOOKUP_LIBS += -llmdb +# For dynamic-modules builds, use instead LOOKUP_LMDB_INCLUDE & LOOKUP_LMDB_LIBS #------------------------------------------------------------------------------ diff --git a/src/src/drtables.c b/src/src/drtables.c index c490e7f86..1d8e222e2 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -295,7 +295,7 @@ extern lookup_module_info ibase_lookup_module_info; #if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 extern lookup_module_info json_lookup_module_info; #endif -#if defined(LOOKUP_LDAP) +#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 extern lookup_module_info ldap_lookup_module_info; #endif #if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 @@ -322,7 +322,7 @@ extern lookup_module_info pgsql_lookup_module_info; #if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 extern lookup_module_info redis_lookup_module_info; #endif -#if defined(LOOKUP_LMDB) +#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2 extern lookup_module_info lmdb_lookup_module_info; #endif #if defined(SUPPORT_SPF) @@ -378,7 +378,7 @@ addlookupmodule(NULL, &dsearch_lookup_module_info); addlookupmodule(NULL, &ibase_lookup_module_info); #endif -#ifdef LOOKUP_LDAP +#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 addlookupmodule(NULL, &ldap_lookup_module_info); #endif @@ -418,7 +418,7 @@ addlookupmodule(NULL, &pgsql_lookup_module_info); addlookupmodule(NULL, &redis_lookup_module_info); #endif -#ifdef LOOKUP_LMDB +#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2 addlookupmodule(NULL, &lmdb_lookup_module_info); #endif diff --git a/src/src/exim.c b/src/src/exim.c index 66746e6bb..3d0929592 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1043,56 +1043,56 @@ lookup_show_supported(gstring * g) { gstring * b = NULL, * d = NULL; -#if defined(LOOKUP_LSEARCH) +#ifdef LOOKUP_LSEARCH # if LOOKUP_LSEARCH!=2 b = string_cat(b, US" lsearch wildlsearch nwildlsearch iplsearch"); # else d = string_cat(d, US" lsearch wildlsearch nwildlsearch iplsearch"); # endif #endif -#if defined(LOOKUP_CDB) +#ifdef LOOKUP_CDB # if LOOKUP_CDB!=2 b = string_cat(b, US" cdb"); # else d = string_cat(d, US" cdb"); # endif #endif -#if defined(LOOKUP_DBM) +#ifdef LOOKUP_DBM # if LOOKUP_DBM!=2 b = string_cat(b, US" dbm dbmjz dbmnz"); # else d = string_cat(d, US" dbm dbmjz dbmnz"); # endif #endif -#if defined(LOOKUP_DNSDB) +#ifdef LOOKUP_DNSDB # if LOOKUP_DNSDB!=2 b = string_cat(b, US" dnsdb"); # else d = string_cat(d, US" dnsdb"); # endif #endif -#if defined(LOOKUP_DSEARCH) +#ifdef LOOKUP_DSEARCH # if LOOKUP_DSEARCH!=2 b = string_cat(b, US" dsearch"); # else d = string_cat(d, US" dsearch"); # endif #endif -#if defined(LOOKUP_IBASE) +#ifdef LOOKUP_IBASE # if LOOKUP_IBASE!=2 b = string_cat(b, US" ibase"); # else d = string_cat(d, US" ibase"); # endif #endif -#if defined(LOOKUP_JSON) +#ifdef LOOKUP_JSON # if LOOKUP_JSON!=2 b = string_cat(b, US" json"); # else d = string_cat(d, US" json"); # endif #endif -#if defined(LOOKUP_LDAP) +#ifdef LOOKUP_LDAP # if LOOKUP_LDAP!=2 b = string_cat(b, US" ldap ldapdn ldapm"); # else @@ -1100,72 +1100,76 @@ gstring * b = NULL, * d = NULL; # endif #endif #ifdef LOOKUP_LMDB +# if LOOKUP_LMDB!=2 b = string_cat(b, US" lmdb"); +# else + d = string_cat(d, US" lmdb"); +# endif #endif -#if defined(LOOKUP_MYSQL) +#ifdef LOOKUP_MYSQL # if LOOKUP_MYSQL!=2 b = string_cat(b, US" mysql"); # else d = string_cat(d, US" mysql"); # endif #endif -#if defined(LOOKUP_NIS) +#ifdef LOOKUP_NIS # if LOOKUP_NIS!=2 b = string_cat(b, US" nis nis0"); # else d = string_cat(d, US" nis nis0"); # endif #endif -#if defined(LOOKUP_NISPLUS) +#ifdef LOOKUP_NISPLUS # if LOOKUP_NISPLUS!=2 b = string_cat(b, US" nisplus"); # else d = string_cat(d, US" nisplus"); # endif #endif -#if defined(LOOKUP_ORACLE) +#ifdef LOOKUP_ORACLE # if LOOKUP_ORACLE!=2 b = string_cat(b, US" oracle"); # else d = string_cat(d, US" oracle"); # endif #endif -#if defined(LOOKUP_PASSWD) +#ifdef LOOKUP_PASSWD # if LOOKUP_PASSWD!=2 b = string_cat(b, US" passwd"); # else d = string_cat(d, US" passwd"); # endif #endif -#if defined(LOOKUP_PGSQL) +#ifdef LOOKUP_PGSQL # if LOOKUP_PGSQL!=2 b = string_cat(b, US" pgsql"); # else d = string_cat(d, US" pgsql"); # endif #endif -#if defined(LOOKUP_REDIS) +#ifdef LOOKUP_REDIS # if LOOKUP_REDIS!=2 b = string_cat(b, US" redis"); # else d = string_cat(d, US" redis"); # endif #endif -#if defined(LOOKUP_SQLITE) +#ifdef LOOKUP_SQLITE # if LOOKUP_SQLITE!=2 b = string_cat(b, US" sqlite"); # else d = string_cat(d, US" sqlite"); # endif #endif -#if defined(LOOKUP_TESTDB) +#ifdef LOOKUP_TESTDB # if LOOKUP_TESTDB!=2 b = string_cat(b, US" testdb"); # else d = string_cat(d, US" testdb"); # endif #endif -#if defined(LOOKUP_WHOSON) +#ifdef LOOKUP_WHOSON # if LOOKUP_WHOSON!=2 b = string_cat(b, US" whoson"); # else diff --git a/src/src/expand.c b/src/src/expand.c index 2ed802fd4..d7b55831f 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -30,10 +30,6 @@ typedef unsigned esi_flags; # endif #endif /*!STAND_ALONE*/ -#ifdef LOOKUP_LDAP -# include "lookups/ldap.h" -#endif - #ifdef SUPPORT_CRYPTEQ # ifdef CRYPT_H # include @@ -2808,13 +2804,14 @@ switch(cond_type = identify_operator(&s, &opname)) case ECOND_LDAPAUTH: #ifdef LOOKUP_LDAP { - /* Just to keep the interface the same */ - BOOL do_cache; - int old_pool = store_pool; - store_pool = POOL_SEARCH; - rc = eldapauth_find((void *)(-1), NULL, sub[0], Ustrlen(sub[0]), NULL, - &expand_string_message, &do_cache); - store_pool = old_pool; + int stype = search_findtype(US"ldapauth", 8), expand_setup = -1; + void * handle = search_open(NULL, stype, 0, NULL, NULL); + if (handle) + rc= search_find(handle, NULL, sub[0], + -1, NULL, 0, 0, &expand_setup, NULL) + ? OK : f.search_find_defer ? DEFER : FAIL; + else + { expand_string_message = search_error_message; rc = FAIL; } } goto END_AUTH; #else diff --git a/src/src/functions.h b/src/src/functions.h index 3253043ae..9ae51d05b 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -491,7 +491,7 @@ extern void route_tidyup(void); extern uschar *router_current_name(void); extern uschar *search_args(int, uschar *, uschar *, uschar **, const uschar *); -extern uschar *search_find(void *, const uschar *, uschar *, int, +extern uschar *search_find(void *, const uschar *, const uschar *, int, const uschar *, int, int, int *, const uschar *); extern int search_findtype(const uschar *, int); extern int search_findtype_partial(const uschar *, int *, const uschar **, int *, diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 0c29b6c9a..8a142398e 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -101,7 +101,10 @@ and eldapm_find(), with a difference in the "search_type" argument. The case of eldapauth_find() is special in that all it does is do authentication, returning OK or FAIL as appropriate. This isn't used as a -lookup. Instead, it is called from expand.c as an expansion condition test. +lookup. Instead, it is called via the generic search interface from expand.c +as an expansion condition test. We take a non/NULL return string as OK/FAIL. +We do not advertise or document it as a general search method, +but probably could. The DN from a successful lookup is placed in $ldap_dn. This feature postdates the provision of the SEARCH_LDAP_DN facility for returning just the DN as the @@ -1305,7 +1308,8 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg)); int eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url, - int length, uschar ** result, uschar ** errmsg, uint * do_cache) + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) { return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg)); } @@ -1559,6 +1563,7 @@ gstring * ldap_version_report(gstring * g) { #ifdef DYNLOOKUP +/*XXX it would be nice to haul a version string for the underlying ldap library */ g = string_fmt_append(g, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR); #endif return g; @@ -1601,11 +1606,28 @@ static lookup_info ldapm_lookup_info = { .version_report = NULL /* no version reporting (redundant) */ }; +static lookup_info ldapauth_lookup_info = { + .name = US"ldapauth", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = eldap_open, /* sic */ /* open function */ + .check = NULL, /* check function */ + .find = eldapauth_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = eldap_tidy, /* sic */ /* tidy function */ + .quote = eldap_quote, /* sic */ /* quoting function */ + .version_report = NULL /* no version reporting (redundant) */ +}; + #ifdef DYNLOOKUP #define ldap_lookup_module_info _lookup_module_info #endif -static lookup_info *_lookup_list[] = { &ldap_lookup_info, &ldapdn_lookup_info, &ldapm_lookup_info }; -lookup_module_info ldap_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 }; +static lookup_info *_lookup_list[] = { + &ldap_lookup_info, + &ldapdn_lookup_info, + &ldapm_lookup_info, + &ldapauth_lookup_info, + }; +lookup_module_info ldap_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 4 }; /* End of lookups/ldap.c */ diff --git a/src/src/lookups/ldap.h b/src/src/lookups/ldap.h deleted file mode 100644 index 2ce62fc05..000000000 --- a/src/src/lookups/ldap.h +++ /dev/null @@ -1,14 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Copyright (c) University of Cambridge 1995 - 2015 */ -/* See the file NOTICE for conditions of use and distribution. */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* Header for eldapauth_find */ - -extern int eldapauth_find(void *, uschar *, const uschar *, int, uschar **, - uschar **, BOOL *); - -/* End of lookups/ldap.h */ diff --git a/src/src/search.c b/src/src/search.c index 6c28b390e..1c501455e 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -520,8 +520,8 @@ Returns: a pointer to a dynamic string containing the answer, */ static uschar * -internal_search_find(void * handle, const uschar * filename, uschar * keystring, - BOOL cache_rd, const uschar * opts) +internal_search_find(void * handle, const uschar * filename, + const uschar * keystring, BOOL cache_rd, const uschar * opts) { tree_node * t = (tree_node *)handle; search_cache * c = (search_cache *)(t->data.ptr); @@ -729,7 +729,7 @@ Returns: a pointer to a dynamic string containing the answer, */ uschar * -search_find(void * handle, const uschar * filename, uschar * keystring, +search_find(void * handle, const uschar * filename, const uschar * keystring, int partial, const uschar * affix, int affixlen, int starflags, int * expand_setup, const uschar * opts) { @@ -830,14 +830,16 @@ else if (partial >= 0) /* Try with the affix on the front, except for a zero-length affix */ - if (affixlen == 0) keystring2 = keystring; else + if (affixlen == 0) + keystring2 = string_copy(keystring); + else { keystring2 = store_get(len + affixlen + 1, is_tainted(keystring) || is_tainted(affix) ? GET_TAINTED : GET_UNTAINTED); Ustrncpy(keystring2, affix, affixlen); Ustrcpy(keystring2 + affixlen, keystring); DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2); - yield = internal_search_find(handle, filename, keystring2, cache_rd, opts); + yield = internal_search_find(handle, filename, CUS keystring2, cache_rd, opts); if (f.search_find_defer) return NULL; } @@ -875,7 +877,7 @@ else if (partial >= 0) } DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3); - yield = internal_search_find(handle, filename, keystring3, + yield = internal_search_find(handle, filename, CUS keystring3, cache_rd, opts); if (f.search_find_defer) return NULL; if (yield)