X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/0756eb3cb50d73a77b486e47528f7cb1bffdb299..c988f1f4faa9f679f79beddf3c14676c5dcb8e28:/src/src/lookups/ldap.c diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index aa2e7bfd8..c32038ba1 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */ +/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.7 2005/01/04 10:00:44 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2005 */ /* See the file NOTICE for conditions of use and distribution. */ /* Many thanks to Stuart Lynne for contributing the original code for this @@ -72,13 +72,6 @@ LDAP_LIB_OPENLDAP1 #endif -/* For libraries without TCP connect timeouts */ - -#ifndef LDAP_X_IO_TIMEOUT_NO_TIMEOUT -#define LDAP_X_IO_TIMEOUT_NO_TIMEOUT (-1) -#endif - - /* Four types of LDAP search are implemented */ #define SEARCH_LDAP_MULTIPLE 0 /* Get attributes from multiple entries */ @@ -136,7 +129,7 @@ Arguments: password password for authentication, or NULL sizelimit max number of entries returned, or 0 for no limit timelimit max time to wait, or 0 for no limit - tcplimit max time to connect, or NULL for OS default + tcplimit max time for network activity, e.g. connect, or 0 for OS default deference the dereference option, which is one of LDAP_DEREF_{NEVER,SEARCHING,FINDING,ALWAYS} @@ -174,7 +167,7 @@ uschar *matched = NULL; /* partially matched DN */ int attr_count = 0; int error_yield = DEFER; int msgid; -int rc; +int rc, ldap_rc, ldap_parse_rc; int port; int ptr = 0; int rescount = 0; @@ -278,6 +271,15 @@ for (lcp = ldap_connections; lcp != NULL; lcp = lcp->next) if (ldapi || port == lcp->port) break; } +/* Use this network timeout in any requests. */ + +if (tcplimit > 0) + { + timeout.tv_sec = tcplimit; + timeout.tv_usec = 0; + timeoutptr = &timeout; + } + /* If no cached connection found, we must open a connection to the server. If the server name is actually an absolute path, we set ldapi=TRUE above. This requests connection via a Unix socket. However, as far as I know, only OpenLDAP @@ -376,9 +378,25 @@ if (lcp == NULL) in Netscape SDK v4.1; I don't know about other libraries. */ #ifdef LDAP_X_OPT_CONNECT_TIMEOUT - ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&tcplimit); + if (tcplimit > 0) + { + int timeout1000 = tcplimit*1000; + ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&timeout1000); + } + else + { + int notimeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT; + ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)¬imeout); + } #endif + /* Set the TCP connect timeout. This works with OpenLDAP 2.2.14. */ + + #ifdef LDAP_OPT_NETWORK_TIMEOUT + if (tcplimit > 0) + ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)timeoutptr); + #endif + /* I could not get TLS to work until I set the version to 3. That version seems to be the default nowadays. The RFC is dated 1997, so I would hope that all the LDAP libraries support it. Therefore, if eldap_version hasn't @@ -457,23 +475,41 @@ if (!lcp->bound || { DEBUG(D_lookup) debug_printf("%sbinding with user=%s password=%s\n", (lcp->bound)? "re-" : "", user, password); - if ((rc = ldap_bind_s(lcp->ld, CS user, CS password, LDAP_AUTH_SIMPLE)) - != LDAP_SUCCESS) + if ((msgid = ldap_bind(lcp->ld, CS user, CS password, LDAP_AUTH_SIMPLE)) + == -1) { - /* Invalid credentials when just checking credentials returns FAIL. This - stops any further servers being tried. */ + *errmsg = string_sprintf("failed to bind the LDAP connection to server " + "%s%s - ldap_bind() returned -1", host, porttext); + goto RETURN_ERROR; + } - if (search_type == SEARCH_LDAP_AUTH && rc == LDAP_INVALID_CREDENTIALS) - { - DEBUG(D_lookup) - debug_printf("Invalid credentials: ldapauth returns FAIL\n"); - error_yield = FAIL; - goto RETURN_ERROR_NOMSG; - } + if ((rc = ldap_result( lcp->ld, msgid, 1, timeoutptr, &result )) <= 0) + { + *errmsg = string_sprintf("failed to bind the LDAP connection to server " + "%s%s - LDAP error: %s", host, porttext, + rc == -1 ? "result retrieval failed" : "timeout" ); + result = NULL; + goto RETURN_ERROR; + } + + rc = ldap_result2error( lcp->ld, result, 0 ); + + /* Invalid credentials when just checking credentials returns FAIL. This + stops any further servers being tried. */ + + if (search_type == SEARCH_LDAP_AUTH && rc == LDAP_INVALID_CREDENTIALS) + { + DEBUG(D_lookup) + debug_printf("Invalid credentials: ldapauth returns FAIL\n"); + error_yield = FAIL; + goto RETURN_ERROR_NOMSG; + } - /* Otherwise we have a problem that doesn't stop further servers from being - tried. */ + /* Otherwise we have a problem that doesn't stop further servers from being + tried. */ + if (rc != LDAP_SUCCESS) + { *errmsg = string_sprintf("failed to bind the LDAP connection to server " "%s%s - LDAP error %d: %s", host, porttext, rc, ldap_err2string(rc)); goto RETURN_ERROR; @@ -484,6 +520,9 @@ if (!lcp->bound || lcp->bound = TRUE; lcp->user = (user == NULL)? NULL : string_copy(user); lcp->password = (password == NULL)? NULL : string_copy(password); + + ldap_msgfree(result); + result = NULL; } /* If we are just checking credentials, return OK. */ @@ -521,20 +560,22 @@ msgid = ldap_search(lcp->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, if (msgid == -1) { - *errmsg = string_sprintf("ldap search initiation failed"); + #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2 + int err; + ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err); + *errmsg = string_sprintf("ldap_search failed: %d, %s", err, + ldap_err2string(err)); + + #else + *errmsg = string_sprintf("ldap_search failed"); + #endif + goto RETURN_ERROR; } /* Loop to pick up results as they come in, setting a timeout if one was given. */ -if (timelimit > 0) - { - timeout.tv_sec = timelimit; - timeout.tv_usec = 0; - timeoutptr = &timeout; - } - while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == LDAP_RES_SEARCH_ENTRY) { @@ -747,10 +788,10 @@ if (rc == -1 || result == NULL) } /* A return code that isn't -1 doesn't necessarily mean there were no problems -with the search. The message must be an LDAP_RES_SEARCH_RESULT or else it's -something we can't handle. */ +with the search. The message must be an LDAP_RES_SEARCH_RESULT or +LDAP_RES_SEARCH_REFERENCE or else it's something we can't handle. */ -if (rc != LDAP_RES_SEARCH_RESULT) +if (rc != LDAP_RES_SEARCH_RESULT && rc != LDAP_RES_SEARCH_REFERENCE) { *errmsg = string_sprintf("ldap_result returned unexpected code %d", rc); goto RETURN_ERROR; @@ -759,11 +800,16 @@ if (rc != LDAP_RES_SEARCH_RESULT) /* We have a result message from the server. This doesn't yet mean all is well. We need to parse the message to find out exactly what's happened. */ - #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2 - if (ldap_parse_result(lcp->ld, result, &rc, CSS &matched, CSS &error2, NULL, - NULL, 0) < 0) +#if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2 + ldap_rc = rc; + ldap_parse_rc = ldap_parse_result(lcp->ld, result, &rc, CSS &matched, + CSS &error2, NULL, NULL, 0); + DEBUG(D_lookup) debug_printf("ldap_parse_result: %d\n", ldap_parse_rc); + if (ldap_parse_rc < 0 && + (ldap_parse_rc != LDAP_NO_RESULTS_RETURNED || + ldap_rc != LDAP_RES_SEARCH_REFERENCE)) { - *errmsg = US"ldap_parse_result failed"; + *errmsg = string_sprintf("ldap_parse_result failed %d", ldap_parse_rc); goto RETURN_ERROR; } error1 = US ldap_err2string(rc); @@ -916,7 +962,7 @@ control_ldap_search(uschar *ldap_url, int search_type, uschar **res, BOOL defer_break = FALSE; int timelimit = LDAP_NO_LIMIT; int sizelimit = LDAP_NO_LIMIT; -int tcplimit = LDAP_X_IO_TIMEOUT_NO_TIMEOUT; +int tcplimit = 0; int dereference = LDAP_DEREF_NEVER; int sep = 0; uschar *url = ldap_url; @@ -949,7 +995,8 @@ while (strncmpic(url, US"ldap", 4) != 0) else if (strncmpic(name, US"PASS=", namelen) == 0) password = value; else if (strncmpic(name, US"SIZE=", namelen) == 0) sizelimit = Uatoi(value); else if (strncmpic(name, US"TIME=", namelen) == 0) timelimit = Uatoi(value); - else if (strncmpic(name, US"CONNECT=", namelen) == 0) tcplimit = Uatoi(value) * 1000; + else if (strncmpic(name, US"CONNECT=", namelen) == 0) tcplimit = Uatoi(value); + else if (strncmpic(name, US"NETTIME=", namelen) == 0) tcplimit = Uatoi(value); /* Don't know if all LDAP libraries have LDAP_OPT_DEREF */