util_ldap.c revision 40a1aee60a66f7c8dbd0835fdd4f09334e12fc15
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl/* Licensed to the Apache Software Foundation (ASF) under one or more
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * contributor license agreements. See the NOTICE file distributed with
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * this work for additional information regarding copyright ownership.
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * The ASF licenses this file to You under the Apache License, Version 2.0
98890889ffb2e8f6f722b00e265a211f13b5a861Corneliu-Claudiu Prodescu * (the "License"); you may not use this file except in compliance with
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * the License. You may obtain a copy of the License at
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * Unless required by applicable law or agreed to in writing, software
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * distributed under the License is distributed on an "AS IS" BASIS,
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * See the License for the specific language governing permissions and
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * limitations under the License.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * util_ldap.c: LDAP things
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Original code from auth_ldap module for Apache v1.3:
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Copyright 1998, 1999 Enbridge Pipelines Inc.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Copyright 1999-2001 Dave Carrigan
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#error mod_ldap requires APR-util to have LDAP support built in
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco/* Default define for ldap functions that need a SIZELIMIT but
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * do not have the define
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco * XXX This should be removed once a supporting #define is
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * released through APR-Util.
6e121321775373fe11161d23c541437456df19b4Adrián Riesco#define LDAP_CACHE_LOCK() do { \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_global_mutex_lock(st->util_ldap_cache_lock); \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_global_mutex_unlock(st->util_ldap_cache_lock); \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic void util_ldap_strdup (char **str, const char *newstr)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Status Handler
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * --------------
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * This handler generates a status page about the current performance of
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the LDAP cache. It is enabled as follows:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * <Location /ldap-status>
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * SetHandler ldap-status
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco * </Location>
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "<html><head><title>LDAP Cache Information</title></head>\n", r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information"
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "</h1>\n", r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ------------------------------------------------------------------ */
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * Closes an LDAP connection by unlocking it. The next time
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * uldap_connection_find() is called this connection will be
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * available for reuse.
6e121321775373fe11161d23c541437456df19b4Adrián Riescostatic void uldap_connection_close(util_ldap_connection_t *ldc)
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * Is it safe leaving bound connections floating around between the
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * different modules? Keeping the user bound is a performance boost,
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * but it is also a potential security problem - maybe.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * For now we unbind the user when we finish with a connection, but
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * we don't have to...
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* mark our connection as available for reuse */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Destroys an LDAP connection by unbinding and closing the connection to
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the LDAP server. It is used to bring the connection back to a known
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * state after an error, and during pool cleanup.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic apr_status_t uldap_connection_unbind(void *param)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Clean up an LDAP connection by unbinding and unlocking the connection.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic apr_status_t uldap_connection_cleanup(void *param)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* unbind and disconnect from the LDAP server */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* free the username and password */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* unlock this entry */
5eb747ed1f9cb3d902d4277badfc2a42f9f98b0cAdrián Riescostatic int uldap_connection_init(request_rec *r,
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco struct timeval timeOut = {10,0}; /* 10 second connection timeout */
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* Since the host will include a port if the default port is not used,
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco * always specify the default ports for the port parameter. This will
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco * allow a host string that contains multiple hosts the ability to mix
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco * some hosts with ports and some without. All hosts which do not
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco * specify a port will use the default port.
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco APR_LDAP_SSL == ldc->secure ? LDAPS_PORT : LDAP_PORT,
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->reason = "LDAP: ldap initialization failed";
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* always default to LDAP V3 */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* set client certificates */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* switch on SSL/TLS */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* Set the alias dereferencing option */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco/*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco APR_LDAP_OPT_VERIFY_CERT, &(st->verify_svr_cert), &(result));
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* This is not a per-connection setting so just pass NULL for the
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco Ldap connection handle */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT,
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco "LDAP: Could not set the connection timeout");
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco * Connect to the LDAP server and binds. Does not connect if already
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco * Returns LDAP_SUCCESS on success; and an error code on failure
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riescostatic int uldap_connection_open(request_rec *r,
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco /* sanity check for NULL */
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco /* If the connection is already bound, return
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ldc->reason = "LDAP: connection open successful (already bound)";
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco /* create the ldap session handle
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* loop trying to bind up to 10 times if LDAP_SERVER_DOWN error is
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * returned. Break out of the loop on Success or any other error.
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * NOTE: Looping is probably not a great idea. If the server isn't
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * responding the chances it will respond after a few tries are poor.
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * However, the original code looped and it only happens on
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco * the error condition.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* attempt to init the connection once again */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* free the handle if there was an error
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "LDAP: ldap_simple_bind_s() failed";
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "LDAP: connection open successful";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Compare client certificate arrays.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Returns 1 on compare failure, 0 otherwise.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic int compare_client_certs(apr_array_header_t *srcs,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* arrays both NULL? if so, then equal */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* arrays different length or either NULL? If so, then not equal */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (srcs == NULL || dests == NULL || srcs->nelts != dests->nelts) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* run an actual comparison */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco src = (struct apr_ldap_opt_tls_cert_t *)srcs->elts;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco dest = (struct apr_ldap_opt_tls_cert_t *)dests->elts;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* if we got here, the cert arrays were identical */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Find an existing ldap connection struct that matches the
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * provided ldap connection parameters.
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco * If not found in the cache, a new ldc structure will be allocated
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * from st->pool and returned to the caller. If found in the cache,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * a pointer to the existing ldc structure will be returned.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* mutex lock this function */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* Search for an exact connection match in the list that is not
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * being used.
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco for (l=st->connections,p=NULL; l; l=l->next) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if ( (l->port == port) && (strcmp(l->host, host) == 0)
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco && ((!l->binddn && !binddn) || (l->binddn && binddn
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco && (l->deref == deref) && (l->secure == secureflag)
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco && !compare_client_certs(st->client_certs, l->client_certs))
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco /* If this connection didn't match the criteria, then we
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco * need to unlock the mutex so it is available to be reused.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* If nothing found, search again, but we don't care about the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * binddn and bindpw this time.
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco for (l=st->connections,p=NULL; l; l=l->next) {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((l->port == port) && (strcmp(l->host, host) == 0) &&
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (l->deref == deref) && (l->secure == secureflag) &&
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco !compare_client_certs(st->client_certs, l->client_certs))
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* the bind credentials have changed */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->binddn), binddn);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->bindpw), bindpw);
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco /* If this connection didn't match the criteria, then we
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco * need to unlock the mutex so it is available to be reused.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* artificially disable cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* l = NULL; */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* If no connection what found after the second search, we
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * must create one.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Add the new connection entry to the linked list. Note that we
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * don't actually establish an LDAP connection yet; that happens
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the first time authentication is requested.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* create the details to the pool in st */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco l = apr_pcalloc(st->pool, sizeof(util_ldap_connection_t));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (apr_pool_create(&l->pool, st->pool) != APR_SUCCESS) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "util_ldap: Failed to create memory pool");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->binddn), binddn);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->bindpw), bindpw);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* The security mode after parsing the URL will always be either
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * APR_LDAP_NONE (ldap://) or APR_LDAP_SSL (ldaps://).
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * If the security setting is NONE, override it to the security
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * setting optionally supplied by the admin using LDAPTrustedMode
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* save away a copy of the client cert list that is presently valid */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->client_certs = apr_array_copy_hdr(l->pool, st->client_certs);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ------------------------------------------------------------------ */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Compares two DNs to see if they're equal. The only way to do this correctly
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * is to search for the dn and then do ldap_get_dn() on the result. This should
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * match the initial dn, since it would have been also retrieved with
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * ldap_get_dn(). This is expensive, so if the configuration value
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * compare_dn_on_server is false, just does an ordinary strcmp.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * The lock for the ldap cache should already be acquired.
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riescostatic int uldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* get cache entry (or create one) */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* a simple compare? */
3b1e33dd8d2de8301d7a31860dd1819bd3752718Adrián Riesco /* unlock this read lock */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison FALSE (direct strcmp())";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison TRUE (direct strcmp())";
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* no - it's a server side compare */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* is it in the compare cache? */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* If it's in the cache, it's good */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* unlock this read lock */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* unlock this read lock */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* too many failures */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* make a server connection */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* connect to server failed */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* search for reqdn */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if ((result = ldap_search_ext_s(ldc->ldap, (char *)reqdn, LDAP_SCOPE_BASE,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison ldap_search_ext_s() "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "failed with server down";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* search for reqdn failed - no match */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison ldap_search_ext_s() failed";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* compare unsuccessful */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison FALSE (checked on server)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* compare successful - add to the compare cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ald_cache_insert(curl->dn_compare_cache, &newnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison TRUE (checked on server)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Does an generic ldap_compare operation. It accepts a cache that it will use
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco * to lookup the compare in the cache. We cache two kinds of compares
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco * (require group compares) and (require user compares). Each compare has a different
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco * cache node: require group includes the DN; require user does not because the
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco * require user cache is owned by the
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riescostatic int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_time_t curtime = 0; /* silence gcc -Wall */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* get cache entry (or create one) */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* make a comparison to the cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache,
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco /* found it... */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (curtime - compare_nodep->lastcompare > st->compare_cache_ttl) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* ...but it is too old */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco util_ald_cache_remove(curl->compare_cache, compare_nodep);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ...and it is good */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (LDAP_COMPARE_TRUE == compare_nodep->result) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else if (LDAP_COMPARE_FALSE == compare_nodep->result) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "Comparison no such attribute (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "Comparison undefined (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* record the result code to return with the reason... */
6f6549c13f912de12345850e4eb248ec358c1b43Adrián Riesco /* and unlock this read lock */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* unlock this read lock */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* too many failures */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* connect failed */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* connection failed - try again */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "ldap_compare_s() failed with server down";
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco /* compare completed; caching result */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* If the node doesn't exist then insert it, otherwise just update
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * it with the last results
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco || (strcmp(the_compare_node.dn, compare_nodep->dn) != 0)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco || (strcmp(the_compare_node.attrib,compare_nodep->attrib) != 0)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco || (strcmp(the_compare_node.value, compare_nodep->value) != 0))
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco junk = util_ald_cache_insert(curl->compare_cache, &the_compare_node);
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] cache_compare: Cache insertion failure.", getpid());
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "Comparison true (adding to cache)";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "Comparison false (adding to cache)";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "Comparison no such attribute (adding to cache)";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic util_compare_subgroup_t* uldap_get_subgroups(request_rec *r, util_ldap_connection_t *ldc,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco char **subgroupAttrs, apr_array_header_t *subgroupclasses) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco struct mod_auth_ldap_groupattr_entry_t *sgc_ents = (struct mod_auth_ldap_groupattr_entry_t *) subgroupclasses->elts;
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco apr_array_header_t *subgroups = apr_array_make(r->pool, 20, sizeof(char *));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* 3.B. The cache didn't have any subgrouplist yet. Go check for subgroups. */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* too many failures */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* connect failed */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* try to do the search */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco result = ldap_search_ext_s(ldc->ldap, (char *)dn, LDAP_SCOPE_BASE,
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &sga_res);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ldc->reason = "ldap_search_ext_s() for subgroups failed with server down";
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "ldap_search_ext_s() for subgroups failed";
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * Get values for the provided sub-group attributes.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Get *all* matching "member" values from this group. */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco values = ldap_get_values(ldc->ldap, entry, subgroupAttrs[indx]);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Now we are going to pare the subgroup members of this group to *just*
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * the subgroups, add them to the compare_nodep, and then proceed to check
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco * the new level of subgroups.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Check if this entry really is a group. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco while ((tmp_sgcIndex < subgroupclasses->nelts) && (result != LDAP_COMPARE_TRUE)) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco result = uldap_cache_compare(r, ldc, url, values[val_index], "objectClass",
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco /* It's a group, so add it to the array. */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco char **newgrp = (char **) apr_array_push(subgroups);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco *newgrp = apr_pstrdup(r->pool, values[val_index]);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* We need to fill in tmp_local_subgroups using the data from LDAP */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco res = apr_pcalloc(r->pool, sizeof(util_compare_subgroup_t));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco res->subgroupDNs = apr_pcalloc(r->pool, sizeof(char *) * (subgroups->nelts));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco for (sgindex = 0; (group = apr_array_pop(subgroups)); sgindex++) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco res->subgroupDNs[sgindex] = apr_pstrdup(r->pool, *group);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Does a recursive lookup operation to try to find a user within (cached) nested
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * groups. It accepts a cache that it will use to lookup previous compare attempts.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * We cache two kinds of compares (require group compares) and (require user
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * compares). Each compare has a different cache node: require group includes the DN;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * require user does not because the require user cache is owned by the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * DON'T CALL THIS UNLESS YOU CALLED uldap_cache_compare FIRST!!!!!
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 1. Call uldap_cache_compare for each subgroupclass value to check the generic,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * user-agnostic, cached group entry. This will create a new generic cache entry if there
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * wasn't one. If nothing returns LDAP_COMPARE_TRUE skip to step 5 since we have no groups.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 2. Lock The cache and get the generic cache entry.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 3. Check if there is already a subgrouplist in this generic group's cache entry.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * A. If there is, go to step 4.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * B. If there isn't:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * i) Use ldap_search to get the full list
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * of subgroup "members" (which may include non-group "members").
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * ii) Use uldap_cache_compare to strip the list down to just groups.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * iii) Lock and add this stripped down list to the cache of the generic group.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 4. Loop through the sgl and call uldap_cache_compare (using the user info) for each
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * subgroup to see if the subgroup contains the user and to get the subgroups added to the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * cache (with user-afinity, if they aren't already there).
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * A. If the user is in the subgroup, then we'll be returning LDAP_COMPARE_TRUE.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * B. if the user isn't in the subgroup (LDAP_COMPARE_FALSE via uldap_cache_compare) then
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * recursively call this function to get the sub-subgroups added...
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 5. Cleanup local allocations.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 6. Return the final result.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic int uldap_cache_check_subgroups(request_rec *r, util_ldap_connection_t *ldc,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco char **subgroupAttrs, apr_array_header_t *subgroupclasses,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int cur_subgroup_depth, int max_subgroup_depth)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_compare_subgroup_t *tmp_local_sgl = NULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int lcl_sgl_processedFlag = 0, failures = 0, sgindex = 0, base_sgcIndex = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco struct mod_auth_ldap_groupattr_entry_t *sgc_ents = (struct mod_auth_ldap_groupattr_entry_t *) subgroupclasses->elts;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Stop looking at deeper levels of nested groups if we have reached the max.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Since we already checked the top-level group in uldap_cache_compare, we don't
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * need to check it again here - so if max_subgroup_depth is set to 0, we won't
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * check it (i.e. that is why we check < rather than <=).
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * We'll be calling uldap_cache_compare from here to check if the user is in the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * next level before we recurse into that next level looking for more subgroups.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (cur_subgroup_depth >= max_subgroup_depth) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* 1. Check the "groupiness" of the specified basedn. Stopping at the first TRUE return. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco while ((base_sgcIndex < subgroupclasses->nelts) && (result != LDAP_COMPARE_TRUE)) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco result = uldap_cache_compare(r, ldc, url, dn, "objectClass", sgc_ents[base_sgcIndex].name);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "DN failed group verification.";
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* 2. Find previously created cache entry and check if there is already a subgrouplist. */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* make a comparison to the cache */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.attrib = (char *)"objectClass";
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name;
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* Found the generic group entry... but the user isn't in this group or we wouldn't be here. */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco lcl_sgl_processedFlag = compare_nodep->sgl_processed;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco if(compare_nodep->sgl_processed && compare_nodep->subgroupList) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* Make a local copy of the subgroup list */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco tmp_local_sgl = apr_pcalloc(r->pool, sizeof(util_compare_subgroup_t));
ebdb7b09e2ad2bb780d84c127d72c30dfcfb87b2Adrián Riesco tmp_local_sgl->len = compare_nodep->subgroupList->len;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco tmp_local_sgl->subgroupDNs = apr_pcalloc(r->pool, sizeof(char *) * compare_nodep->subgroupList->len);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco for (i = 0; i < compare_nodep->subgroupList->len; i++) {
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco tmp_local_sgl->subgroupDNs[i] = apr_pstrdup(r->pool, compare_nodep->subgroupList->subgroupDNs[i]);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* If we get here, something is wrong. Caches should have been created and
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco this group entry should be found in the cache. */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco ldc->reason = "check_subgroups failed to find any caches.";
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco if ((lcl_sgl_processedFlag == 0) && (!tmp_local_sgl)) {
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco /* No Cached SGL, retrieve from LDAP */
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] util_ldap: no cached SGL for %s, retrieving from LDAP" , getpid(), dn);
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco tmp_local_sgl = uldap_get_subgroups(r, ldc, url, dn, subgroupAttrs, subgroupclasses);
b3a8ae62887130fd41b91bf2ea1fd66360bd3c29Adrián Riesco /* No SGL aailable via LDAP either */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] util_ldap: no subgroups for %s" , getpid(), dn);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* Find the generic group cache entry and add the sgl we just retrieved. */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.attrib = (char *)"objectClass";
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco /* Didn't find it. This shouldn't happen since we just called uldap_cache_compare. */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->reason = "check_subgroups failed to find the cache entry to add sub-group list to.";
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco * overwrite SGL if it was previously updated between the last
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco * two times we looked at the cache
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco compare_nodep->subgroupList = util_ald_sgl_dup(curl->compare_cache, tmp_local_sgl);
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco /* We didn't find a single subgroup, next time save us from looking */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco /* tmp_local_sgl has either been created, or copied out of the cache */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco /* If tmp_local_sgl is NULL, there are no subgroups to process and we'll return false */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco while ((result != LDAP_COMPARE_TRUE) && (sgindex < tmp_local_sgl->len)) {
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco /* 4. Now loop through the subgroupList and call uldap_cache_compare to check for the user. */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco result = uldap_cache_compare(r, ldc, url, group, attrib, value);
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco /* 4.A. We found the user in the subgroup. Return LDAP_COMPARE_TRUE. */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] util_ldap:"
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco " Found user %s in a subgroup (%s) at level %d of %d.",
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco getpid(), r->user, group, cur_subgroup_depth+1, max_subgroup_depth);
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco /* 4.B. We didn't find the user in this subgroup, so recurse into it and keep looking. */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] util_ldap:"
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco " user %s not found in subgroup (%s) at level %d of %d.",
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco getpid(), r->user, group, cur_subgroup_depth+1, max_subgroup_depth);
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco result = uldap_cache_check_subgroups(r, ldc, url, group, attrib,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riescostatic int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco const char ***retvals)
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_search_node_t *search_nodep; /* Cached search node */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* Get the cache node for this url */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco search_nodep = util_ald_cache_fetch(curl->search_cache,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* found entry in search cache... */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * Remove this item from the cache if its expired. If the sent
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * password doesn't match the storepassword, the entry will
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * be removed and readded later if the credentials pass
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * authentication.
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* ...but entry is too old */
if (attrs) {
while (attrs[k++]);
return LDAP_SUCCESS;
return result;
return result;
== LDAP_SERVER_DOWN)
goto start_over;
return result;
if (count == 0 )
return LDAP_NO_SUCH_OBJECT;
return LDAP_INVALID_CREDENTIALS;
(char *)*binddn,
goto start_over;
return result;
if (attrs) {
while (attrs[k++]);
numvals = k;
while (attrs[i]) {
char **values;
if (curl) {
return LDAP_SUCCESS;
int numvals = 0;
int result = 0;
char *dn;
int count;
int failures = 0;
&ldap_module);
&curnode);
if (curl) {
if (attrs) {
while (attrs[k++]);
return LDAP_SUCCESS;
return result;
return result;
== LDAP_SERVER_DOWN)
goto start_over;
return result;
if (count == 0 )
return LDAP_NO_SUCH_OBJECT;
if (attrs) {
while (attrs[k++]);
numvals = k;
while (attrs[i]) {
char **values;
if (curl) {
return LDAP_SUCCESS;
const char *bytes)
&ldap_module);
return err;
return NULL;
const char *file)
&ldap_module);
return err;
if (file) {
return NULL;
const char *ttl)
&ldap_module);
return err;
return NULL;
const char *size)
&ldap_module);
return err;
return NULL;
const char *ttl)
&ldap_module);
return err;
return NULL;
const char *size)
&ldap_module);
return err;
return NULL;
return APR_LDAP_CA_TYPE_DER;
return APR_LDAP_CA_TYPE_BASE64;
return APR_LDAP_CA_TYPE_CERT7_DB;
return APR_LDAP_CA_TYPE_SECMOD;
return APR_LDAP_CERT_TYPE_DER;
return APR_LDAP_CERT_TYPE_BASE64;
return APR_LDAP_CERT_TYPE_PFX;
return APR_LDAP_CERT_TYPE_KEY3_DB;
return APR_LDAP_CERT_TYPE_NICKNAME;
return APR_LDAP_KEY_TYPE_DER;
return APR_LDAP_KEY_TYPE_BASE64;
return APR_LDAP_KEY_TYPE_PFX;
return APR_LDAP_CA_TYPE_UNKNOWN;
void *dummy,
const char *type,
const char *file,
const char *password)
&ldap_module);
int cert_type = 0;
return err;
if (type) {
!= APR_SUCCESS))
return(NULL);
void *config,
const char *type,
const char *file,
const char *password)
&ldap_module);
int cert_type = 0;
if (type) {
type);
!= APR_SUCCESS))
return(NULL);
const char *mode)
&ldap_module);
mode);
return(NULL);
void *dummy,
int mode)
&ldap_module);
return err;
return(NULL);
void *dummy,
const char *ttl)
&ldap_module);
return err;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
return NULL;
#if APR_HAS_THREADS
return st;
void *overridesv)
#if APR_HAS_THREADS
return st;
return APR_SUCCESS;
&ldap_module);
void *data;
int rc;
if (!data) {
NULL);
return OK;
return DONE;
NULL);
return result;
#ifdef AP_NEED_SET_MUTEX_PERMS
return result;
while (s_vhost) {
&ldap_module);
NULL,
&(result_err));
return(OK);
&ldap_module);
{NULL}