diff -ru httpd-2.4.29.orig/modules/ldap/util_ldap.c httpd-2.4.29/modules/ldap/util_ldap.c --- httpd-2.4.29.orig/modules/ldap/util_ldap.c 2015-09-08 13:10:16.000000000 +0200 +++ httpd-2.4.29/modules/ldap/util_ldap.c 2017-12-19 15:55:30.927918515 +0100 @@ -1642,6 +1642,58 @@ return result; } +/* + * Takes care of inserting a search/bind result into the cache. + */ +static void uldap_cache_search(util_ldap_state_t *st, util_url_node_t * curl, + const char *filter, const char **binddn, + const char *bindpw, const char **vals, + int numvals, int negative) { + util_search_node_t *search_nodep; /* Cached search node */ + util_search_node_t the_search_node; + const char* user = binddn == NULL ? "" : *binddn; + + // TODO: only cache negative if requested. + + if (curl) { + LDAP_CACHE_LOCK(); + the_search_node.username = filter; + the_search_node.dn = user; + the_search_node.bindpw = bindpw; + the_search_node.lastbind = apr_time_now(); + the_search_node.vals = vals; + the_search_node.numvals = numvals; + the_search_node.negative = negative; + + /* Search again to make sure that another thread didn't ready insert + * this node into the cache before we got here. If it does exist then + * update the lastbind + */ + search_nodep = util_ald_cache_fetch(curl->search_cache, + &the_search_node); + if ((search_nodep == NULL) || + (strcmp(user, search_nodep->dn) != 0)) { + + /* Nothing in cache, insert new entry */ + util_ald_cache_insert(curl->search_cache, &the_search_node); + } + else if ((!search_nodep->bindpw) || + (strcmp(bindpw, search_nodep->bindpw) != 0) || (search_nodep->negative != negative)) { + + /* Entry in cache is invalid, remove it and insert new one */ + util_ald_cache_remove(curl->search_cache, search_nodep); + util_ald_cache_insert(curl->search_cache, &the_search_node); + } + else { + /* Cache entry is valid, update lastbind */ + search_nodep->lastbind = the_search_node.lastbind; + } + LDAP_CACHE_UNLOCK(); + } + +} + + static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *basedn, @@ -1700,6 +1752,11 @@ && (search_nodep->bindpw[0] != '\0') && (strcmp(search_nodep->bindpw, bindpw) == 0)) { + if(search_nodep->negative != 0) { + LDAP_CACHE_UNLOCK(); + ldc->reason = "Authentication skipped (negative cached)"; + return LDAP_NO_SUCH_OBJECT; + } /* ...and entry is valid */ *binddn = apr_pstrdup(r->pool, search_nodep->dn); if (attrs) { @@ -1780,6 +1837,10 @@ else ldc->reason = "User is not unique (search found two " "or more matches)"; + /* + * potentially cache the negative result. + */ + uldap_cache_search(st, curl, filter, NULL, bindpw, NULL, 0, 1); ldap_msgfree(res); return LDAP_NO_SUCH_OBJECT; } @@ -1829,6 +1890,10 @@ /* failure? if so - return */ if (result != LDAP_SUCCESS) { ldc->reason = "ldap_simple_bind() to check user credentials failed"; + /* + * potentially cache the negative result. + */ + uldap_cache_search(st, curl, filter, binddn, bindpw, NULL, 0, 1); ldap_msgfree(res); uldap_connection_unbind(ldc); return result; @@ -1873,40 +1938,7 @@ /* * Add the new username to the search cache. */ - if (curl) { - LDAP_CACHE_LOCK(); - the_search_node.username = filter; - the_search_node.dn = *binddn; - the_search_node.bindpw = bindpw; - the_search_node.lastbind = apr_time_now(); - the_search_node.vals = vals; - the_search_node.numvals = numvals; - - /* Search again to make sure that another thread didn't ready insert - * this node into the cache before we got here. If it does exist then - * update the lastbind - */ - search_nodep = util_ald_cache_fetch(curl->search_cache, - &the_search_node); - if ((search_nodep == NULL) || - (strcmp(*binddn, search_nodep->dn) != 0)) { - - /* Nothing in cache, insert new entry */ - util_ald_cache_insert(curl->search_cache, &the_search_node); - } - else if ((!search_nodep->bindpw) || - (strcmp(bindpw, search_nodep->bindpw) != 0)) { - - /* Entry in cache is invalid, remove it and insert new one */ - util_ald_cache_remove(curl->search_cache, search_nodep); - util_ald_cache_insert(curl->search_cache, &the_search_node); - } - else { - /* Cache entry is valid, update lastbind */ - search_nodep->lastbind = the_search_node.lastbind; - } - LDAP_CACHE_UNLOCK(); - } + uldap_cache_search(st, curl, filter, binddn, bindpw, vals, numvals, 0); ldap_msgfree(res); ldc->reason = "Authentication successful"; diff -ru httpd-2.4.29.orig/modules/ldap/util_ldap_cache.c httpd-2.4.29/modules/ldap/util_ldap_cache.c --- httpd-2.4.29.orig/modules/ldap/util_ldap_cache.c 2015-10-06 14:36:36.000000000 +0200 +++ httpd-2.4.29/modules/ldap/util_ldap_cache.c 2017-12-18 10:00:05.106189774 +0100 @@ -190,6 +190,7 @@ newnode->bindpw = NULL; } newnode->lastbind = node->lastbind; + newnode->negative = node->negative; } return (void *)newnode; @@ -227,10 +228,12 @@ "%s" "%s" "%s" + "%s" "", node->username, node->dn, - date_str); + date_str, + node->negative ? "Yes" : "No"); } /* ------------------------------------------------------------------ */ diff -ru httpd-2.4.29.orig/modules/ldap/util_ldap_cache.h httpd-2.4.29/modules/ldap/util_ldap_cache.h --- httpd-2.4.29.orig/modules/ldap/util_ldap_cache.h 2011-09-23 20:08:42.000000000 +0200 +++ httpd-2.4.29/modules/ldap/util_ldap_cache.h 2017-12-14 15:02:36.082073056 +0100 @@ -117,6 +117,7 @@ apr_time_t lastbind; /* Time of last successful bind */ const char **vals; /* Values of queried attributes */ int numvals; /* Number of queried attributes */ + int negative; /* negative cache */ } util_search_node_t; /* diff -ru httpd-2.4.29.orig/modules/ldap/util_ldap_cache_mgr.c httpd-2.4.29/modules/ldap/util_ldap_cache_mgr.c --- httpd-2.4.29.orig/modules/ldap/util_ldap_cache_mgr.c 2016-08-25 14:48:18.000000000 +0200 +++ httpd-2.4.29/modules/ldap/util_ldap_cache_mgr.c 2017-12-18 09:58:38.177937852 +0100 @@ -769,6 +769,7 @@ "LDAP Filter" "User Name" "Last Bind" + "Negative" "\n", r ); if (n) {