X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/42c7f0b4ea09d8971a19beeef743ec8981d4aacc..1ddb1855402d48ad735e46abaf0d662e45600ecd:/src/src/lookups/ldap.c diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 97ee188d2..415266358 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ /* Many thanks to Stuart Lynne for contributing the original code for this @@ -301,24 +302,18 @@ if (!lcp) than the host name + "ldaps:///" plus : and a port number, say 20 + the length of the host name. What we get should accommodate both, easily. */ - uschar *shost = (host == NULL)? US"" : host; - uschar *init_url = store_get(20 + 3 * Ustrlen(shost)); - uschar *init_ptr; + uschar * shost = host ? host : US""; + rmark reset_point = store_mark(); + gstring * g; /* Handle connection via Unix socket ("ldapi"). We build a basic LDAP URI to contain the path name, with slashes escaped as %2F. */ if (ldapi) { - int ch; - init_ptr = init_url + 8; - Ustrcpy(init_url, "ldapi://"); - while ((ch = *shost++)) - if (ch == '/') - { Ustrncpy(init_ptr, "%2F", 3); init_ptr += 3; } - else - *init_ptr++ = ch; - *init_ptr = 0; + g = string_catn(NULL, US"ldapi://", 8); + for (uschar ch; (ch = *shost); shost++) + g = ch == '/' ? string_catn(g, US"%2F", 3) : string_catn(g, shost, 1); } /* This is not an ldapi call. Just build a URI with the protocol type, host @@ -326,22 +321,22 @@ if (!lcp) else { - init_ptr = Ustrchr(ldap_url, '/'); - Ustrncpy(init_url, ldap_url, init_ptr - ldap_url); - init_ptr = init_url + (init_ptr - ldap_url); - sprintf(CS init_ptr, "//%s:%d/", shost, port); + uschar * init_ptr = Ustrchr(ldap_url, '/'); + g = string_catn(NULL, ldap_url, init_ptr - ldap_url); + g = string_fmt_append(g, "//%s:%d/", shost, port); } + string_from_gstring(g); /* Call ldap_initialize() and check the result */ - DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", init_url); - if ((rc = ldap_initialize(&ld, CS init_url)) != LDAP_SUCCESS) + DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", g->s); + if ((rc = ldap_initialize(&ld, CS g->s)) != LDAP_SUCCESS) { *errmsg = string_sprintf("ldap_initialize: (error %d) URL \"%s\"\n", - rc, init_url); + rc, g->s); goto RETURN_ERROR; } - store_reset(init_url); /* Might as well save memory when we can */ + store_reset(reset_point); /* Might as well save memory when we can */ /* ------------------------- Not OpenLDAP ---------------------- */ @@ -501,8 +496,8 @@ if (!lcp) /* Now add this connection to the chain of cached connections */ - lcp = store_get(sizeof(LDAP_CONNECTION)); - lcp->host = (host == NULL)? NULL : string_copy(host); + lcp = store_get(sizeof(LDAP_CONNECTION), FALSE); + lcp->host = host ? string_copy(host) : NULL; lcp->bound = FALSE; lcp->user = NULL; lcp->password = NULL; @@ -1004,7 +999,7 @@ if (search_type != SEARCH_LDAP_MULTIPLE && rescount > 1) if (rescount < 1) { - *errmsg = string_sprintf("LDAP search: no results"); + *errmsg = US"LDAP search: no results"; error_yield = FAIL; goto RETURN_ERROR_BREAK; } @@ -1096,9 +1091,7 @@ const uschar *p; uschar *user = NULL; uschar *password = NULL; uschar *local_servers = NULL; -uschar *server; const uschar *list; -uschar buffer[512]; while (isspace(*url)) url++; @@ -1110,7 +1103,7 @@ NAME has the value "ldap". */ while (strncmpic(url, US"ldap", 4) != 0) { const uschar *name = url; - while (*url != 0 && *url != '=') url++; + while (*url && *url != '=') url++; if (*url == '=') { int namelen; @@ -1156,6 +1149,7 @@ while (strncmpic(url, US"ldap", 4) != 0) else if (strcmpic(value, US"nofollow") == 0) referrals = LDAP_OPT_OFF; else { + *errmsg = US"LDAP option REFERRALS is not \"follow\" or \"nofollow\""; DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } @@ -1193,7 +1187,7 @@ result of ${quote_ldap_dn:...} quoting, which does apply URL quoting, because that is needed when the DN is used as a base DN in a query. Sigh. This is all far too complicated. */ -if (user != NULL) +if (user) { uschar *t = user; for (uschar * s = user; *s != 0; s++) @@ -1216,7 +1210,7 @@ if (user != NULL) DEBUG(D_lookup) debug_printf_indent("LDAP parameters: user=%s pass=%s size=%d time=%d connect=%d " "dereference=%d referrals=%s\n", user, password, sizelimit, timelimit, - tcplimit, dereference, (referrals == LDAP_OPT_ON)? "on" : "off"); + tcplimit, dereference, referrals == LDAP_OPT_ON ? "on" : "off"); /* If the request is just to check authentication, some credentials must be given. The password must not be empty because LDAP binds with an empty @@ -1224,12 +1218,12 @@ password are considered anonymous, and will succeed on most installations. */ if (search_type == SEARCH_LDAP_AUTH) { - if (user == NULL || password == NULL) + if (!user || !password) { *errmsg = US"ldapauth lookups must specify the username and password"; return DEFER; } - if (password[0] == 0) + if (!*password) { DEBUG(D_lookup) debug_printf_indent("Empty password: ldapauth returns FAIL\n"); return FAIL; @@ -1250,22 +1244,20 @@ if (Ustrncmp(p, "://", 3) != 0) /* No default servers, or URL contains a server name: just one attempt */ -if ((eldap_default_servers == NULL && local_servers == NULL) || p[3] != '/') - { +if (!eldap_default_servers && !local_servers || p[3] != '/') return perform_ldap_search(url, NULL, 0, search_type, res, errmsg, &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference, referrals); - } -/* Loop through the default servers until OK or FAIL. Use local_servers list - * if defined in the lookup, otherwise use the global default list */ -list = (local_servers == NULL) ? eldap_default_servers : local_servers; -while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) +/* Loop through the servers until OK or FAIL. Use local_servers list +if defined in the lookup, otherwise use the global default list */ + +list = local_servers ? local_servers : eldap_default_servers; +for (uschar * server; server = string_nextinlist(&list, &sep, NULL, 0); ) { - int rc; - int port = 0; + int rc, port = 0; uschar *colon = Ustrchr(server, ':'); - if (colon != NULL) + if (colon) { *colon = 0; port = Uatoi(colon+1); @@ -1290,38 +1282,33 @@ are handled by a common function, with a flag to differentiate between them. The handle and filename arguments are not used. */ static int -eldap_find(void *handle, uschar *filename, const uschar *ldap_url, int length, - uschar **result, uschar **errmsg, uint *do_cache) +eldap_find(void * handle, const uschar * filename, const uschar * ldap_url, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) { -/* Keep picky compilers happy */ -do_cache = do_cache; return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg)); } static int -eldapm_find(void *handle, uschar *filename, const uschar *ldap_url, int length, - uschar **result, uschar **errmsg, uint *do_cache) +eldapm_find(void * handle, const uschar * filename, const uschar * ldap_url, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) { -/* Keep picky compilers happy */ -do_cache = do_cache; return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg)); } static int -eldapdn_find(void *handle, uschar *filename, const uschar *ldap_url, int length, - uschar **result, uschar **errmsg, uint *do_cache) +eldapdn_find(void * handle, const uschar * filename, const uschar * ldap_url, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) { -/* Keep picky compilers happy */ -do_cache = do_cache; return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg)); } int -eldapauth_find(void *handle, uschar *filename, const uschar *ldap_url, int length, - uschar **result, uschar **errmsg, uint *do_cache) +eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url, + int length, uschar ** result, uschar ** errmsg, uint * do_cache) { -/* Keep picky compilers happy */ -do_cache = do_cache; return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg)); } @@ -1334,7 +1321,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg)); /* See local README for interface description. */ static void * -eldap_open(uschar *filename, uschar **errmsg) +eldap_open(const uschar * filename, uschar ** errmsg) { return (void *)(1); /* Just return something non-null */ } @@ -1351,16 +1338,13 @@ Make sure that eldap_dn does not refer to reclaimed or worse, freed store */ static void eldap_tidy(void) { -LDAP_CONNECTION *lcp = NULL; eldap_dn = NULL; -while ((lcp = ldap_connections) != NULL) +for (LDAP_CONNECTION *lcp; lcp = ldap_connections; ldap_connections = lcp->next) { - DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", lcp->host, - lcp->port); - if(lcp->bound == TRUE) - ldap_unbind(lcp->ld); - ldap_connections = lcp->next; + DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", + lcp->host, lcp->port); + if(lcp->bound) ldap_unbind(lcp->ld); } } @@ -1481,7 +1465,7 @@ if (count == 0) return s; /* Get sufficient store to hold the quoted string */ -t = quoted = store_get(len + count + 1); +t = quoted = store_get(len + count + 1, is_tainted(s)); /* Handle plain quote_ldap */ @@ -1536,7 +1520,7 @@ else { if (Ustrchr(LDAP_DN_QUOTE, c) != NULL) { - Ustrncpy(t, "%5C", 3); /* insert \ where needed */ + Ustrncpy(t, US"%5C", 3); /* insert \ where needed */ t += 3; /* fall through to check URL */ } if (Ustrchr(URL_NONQUOTE, c) == NULL) /* e.g. ] => %5D */ @@ -1553,7 +1537,7 @@ else while (*ss++ != 0) { - Ustrncpy(t, "%5C%20", 6); + Ustrncpy(t, US"%5C%20", 6); t += 6; } } @@ -1574,49 +1558,50 @@ return quoted; #include "../version.h" -void -ldap_version_report(FILE *f) +gstring * +ldap_version_report(gstring * g) { #ifdef DYNLOOKUP -fprintf(f, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR); +g = string_fmt_append(g, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR); #endif +return g; } static lookup_info ldap_lookup_info = { - US"ldap", /* lookup name */ - lookup_querystyle, /* query-style lookup */ - eldap_open, /* open function */ - NULL, /* check function */ - eldap_find, /* find function */ - NULL, /* no close function */ - eldap_tidy, /* tidy function */ - eldap_quote, /* quoting function */ - ldap_version_report /* version reporting */ + .name = US"ldap", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = eldap_open, /* open function */ + .check = NULL, /* check function */ + .find = eldap_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = eldap_tidy, /* tidy function */ + .quote = eldap_quote, /* quoting function */ + .version_report = ldap_version_report /* version reporting */ }; static lookup_info ldapdn_lookup_info = { - US"ldapdn", /* lookup name */ - lookup_querystyle, /* query-style lookup */ - eldap_open, /* sic */ /* open function */ - NULL, /* check function */ - eldapdn_find, /* find function */ - NULL, /* no close function */ - eldap_tidy, /* sic */ /* tidy function */ - eldap_quote, /* sic */ /* quoting function */ - NULL /* no version reporting (redundant) */ + .name = US"ldapdn", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = eldap_open, /* sic */ /* open function */ + .check = NULL, /* check function */ + .find = eldapdn_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) */ }; static lookup_info ldapm_lookup_info = { - US"ldapm", /* lookup name */ - lookup_querystyle, /* query-style lookup */ - eldap_open, /* sic */ /* open function */ - NULL, /* check function */ - eldapm_find, /* find function */ - NULL, /* no close function */ - eldap_tidy, /* sic */ /* tidy function */ - eldap_quote, /* sic */ /* quoting function */ - NULL /* no version reporting (redundant) */ + .name = US"ldapm", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = eldap_open, /* sic */ /* open function */ + .check = NULL, /* check function */ + .find = eldapm_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