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 *
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * http://www.apache.org/licenses/LICENSE-2.0
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl *
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 */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/*
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * util_ldap.c: LDAP things
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco *
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
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#include "httpd.h"
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#include "http_config.h"
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#include "http_core.h"
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#include "http_log.h"
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#include "http_protocol.h"
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#include "http_request.h"
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#include "util_ldap.h"
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#include "util_ldap_cache.h"
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#include <apr_strings.h>
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#if APR_HAVE_UNISTD_H
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco#include <unistd.h>
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco#endif
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#if !APR_HAS_LDAP
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#error mod_ldap requires APR-util to have LDAP support built in
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#endif
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#ifdef AP_NEED_SET_MUTEX_PERMS
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#include "unixd.h"
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#endif
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
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.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#ifndef APR_LDAP_SIZELIMIT
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco#define APR_LDAP_SIZELIMIT -1
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescomodule AP_MODULE_DECLARE_DATA ldap_module;
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco
6e121321775373fe11161d23c541437456df19b4Adrián Riesco#define LDAP_CACHE_LOCK() do { \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (st->util_ldap_cache_lock) \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_global_mutex_lock(st->util_ldap_cache_lock); \
6e121321775373fe11161d23c541437456df19b4Adrián Riesco} while (0)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#define LDAP_CACHE_UNLOCK() do { \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (st->util_ldap_cache_lock) \
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_global_mutex_unlock(st->util_ldap_cache_lock); \
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco} while (0)
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic void util_ldap_strdup (char **str, const char *newstr)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco{
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (*str) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco free(*str);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco *str = NULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (newstr) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco *str = strdup(newstr);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/*
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Status Handler
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * --------------
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 *
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * <Location /ldap-status>
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * SetHandler ldap-status
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco * </Location>
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco *
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic int util_ldap_handler(request_rec *r)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco{
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_state_t *st = (util_ldap_state_t *)
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco &ldap_module);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco r->allowed |= (1 << M_GET);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (r->method_number != M_GET)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return DECLINED;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (strcmp(r->handler, "ldap-status")) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return DECLINED;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_set_content_type(r, "text/html");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (r->header_only)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return OK;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_rputs(DOCTYPE_HTML_3_2
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
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ald_cache_display(r, st);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco return OK;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ------------------------------------------------------------------ */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
6e121321775373fe11161d23c541437456df19b4Adrián Riesco
6e121321775373fe11161d23c541437456df19b4Adriá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 Riesco */
6e121321775373fe11161d23c541437456df19b4Adrián Riescostatic void uldap_connection_close(util_ldap_connection_t *ldc)
6e121321775373fe11161d23c541437456df19b4Adrián Riesco{
6e121321775373fe11161d23c541437456df19b4Adrián Riesco
6e121321775373fe11161d23c541437456df19b4Adrián Riesco /*
6e121321775373fe11161d23c541437456df19b4Adrián Riesco * QUESTION:
6e121321775373fe11161d23c541437456df19b4Adrián Riesco *
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 *
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 */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* mark our connection as available for reuse */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#if APR_HAS_THREADS
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_unlock(ldc->lock);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco/*
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 Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic apr_status_t uldap_connection_unbind(void *param)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco{
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco util_ldap_connection_t *ldc = param;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (ldc) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (ldc->ldap) {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ldap_unbind_s(ldc->ldap);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->ldap = NULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->bound = 0;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return APR_SUCCESS;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/*
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Clean up an LDAP connection by unbinding and unlocking the connection.
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic apr_status_t uldap_connection_cleanup(void *param)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco{
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco util_ldap_connection_t *ldc = param;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (ldc) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* unbind and disconnect from the LDAP server */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco uldap_connection_unbind(ldc);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* free the username and password */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (ldc->bindpw) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco free((void*)ldc->bindpw);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (ldc->binddn) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco free((void*)ldc->binddn);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* unlock this entry */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco uldap_connection_close(ldc);
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco return APR_SUCCESS;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
ab9c6be005cb2af851307b7968c2baa16a76d6b1Adrián Riesco
5eb747ed1f9cb3d902d4277badfc2a42f9f98b0cAdrián Riescostatic int uldap_connection_init(request_rec *r,
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco util_ldap_connection_t *ldc )
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco{
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco int rc = 0, ldap_option = 0;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco int version = LDAP_VERSION3;
3f8cdebaede9921402318d525b57a9af8f9279d3Adrián Riesco apr_ldap_err_t *result = NULL;
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco struct timeval timeOut = {10,0}; /* 10 second connection timeout */
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco util_ldap_state_t *st =
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco &ldap_module);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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.
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco */
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco apr_ldap_init(r->pool, &(ldc->ldap),
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->host,
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco APR_LDAP_SSL == ldc->secure ? LDAPS_PORT : LDAP_PORT,
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco APR_LDAP_NONE,
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco &(result));
0f593bb6e3f0bc82abf3d6d3c76ef222a43d0476Adrián Riesco
0f593bb6e3f0bc82abf3d6d3c76ef222a43d0476Adrián Riesco
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco if (result != NULL && result->rc) {
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco ldc->reason = result->reason;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if (NULL == ldc->ldap)
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco {
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco ldc->bound = 0;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if (NULL == ldc->reason) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->reason = "LDAP: ldap initialization failed";
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco }
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco else {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ldc->reason = result->reason;
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco }
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco return(result->rc);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* always default to LDAP V3 */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* set client certificates */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (!apr_is_empty_array(ldc->client_certs)) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldc->client_certs, &(result));
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (LDAP_SUCCESS != result->rc) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco uldap_connection_unbind( ldc );
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldc->reason = result->reason;
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco return(result->rc);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* switch on SSL/TLS */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (APR_LDAP_NONE != ldc->secure) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco apr_ldap_set_option(r->pool, ldc->ldap,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco APR_LDAP_OPT_TLS, &ldc->secure, &(result));
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (LDAP_SUCCESS != result->rc) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco uldap_connection_unbind( ldc );
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldc->reason = result->reason;
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco return(result->rc);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* Set the alias dereferencing option */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldap_option = ldc->deref;
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco/*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco#ifdef APR_LDAP_OPT_VERIFY_CERT
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco apr_ldap_set_option(r->pool, ldc->ldap,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco APR_LDAP_OPT_VERIFY_CERT, &(st->verify_svr_cert), &(result));
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco#else
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco#if defined(LDAPSSL_VERIFY_SERVER)
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (st->verify_svr_cert) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco else {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco }
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco#elif defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
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 if (st->verify_svr_cert) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco int i = LDAP_OPT_X_TLS_DEMAND;
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco else {
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco int i = LDAP_OPT_X_TLS_NEVER;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco#endif
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco#endif
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco#ifdef LDAP_OPT_NETWORK_TIMEOUT
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if (st->connectionTimeout > 0) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco timeOut.tv_sec = st->connectionTimeout;
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco }
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if (st->connectionTimeout >= 0) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT,
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco (void *)&timeOut, &(result));
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if (APR_SUCCESS != rc) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco "LDAP: Could not set the connection timeout");
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco#endif
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco return(rc);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco}
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco/*
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 *
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco * Returns LDAP_SUCCESS on success; and an error code on failure
0be63c5d4b5e66cc600a0003081ae2bf85be9615Adrián Riesco */
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riescostatic int uldap_connection_open(request_rec *r,
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco util_ldap_connection_t *ldc)
0be63c5d4b5e66cc600a0003081ae2bf85be9615Adrián Riesco{
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco int rc = 0;
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco int failures = 0;
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco /* sanity check for NULL */
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco if (!ldc) {
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco return -1;
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco }
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco /* If the connection is already bound, return
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco */
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco if (ldc->bound)
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco {
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ldc->reason = "LDAP: connection open successful (already bound)";
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco return LDAP_SUCCESS;
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco /* create the ldap session handle
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco */
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco if (NULL == ldc->ldap)
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco {
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco rc = uldap_connection_init( r, ldc );
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco if (LDAP_SUCCESS != rc)
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco return rc;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
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.
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco *
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 */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco for (failures=0; failures<10; failures++)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco rc = ldap_simple_bind_s(ldc->ldap,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (char *)ldc->binddn,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (char *)ldc->bindpw);
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if (LDAP_SERVER_DOWN != rc) {
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco break;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco } else if (failures == 5) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* attempt to init the connection once again */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco uldap_connection_unbind( ldc );
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco rc = uldap_connection_init( r, ldc );
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco if (LDAP_SUCCESS != rc)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco break;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* free the handle if there was an error
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (LDAP_SUCCESS != rc)
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco uldap_connection_unbind(ldc);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "LDAP: ldap_simple_bind_s() failed";
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco else {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->bound = 1;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "LDAP: connection open successful";
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return(rc);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco}
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco/*
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Compare client certificate arrays.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco *
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Returns 1 on compare failure, 0 otherwise.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic int compare_client_certs(apr_array_header_t *srcs,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco apr_array_header_t *dests)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco{
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco int i = 0;
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco struct apr_ldap_opt_tls_cert_t *src, *dest;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* arrays both NULL? if so, then equal */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (srcs == NULL && dests == NULL) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return 0;
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
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 return 1;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
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 for (i = 0; i < srcs->nelts; i++) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (strcmp(src[i].path, dest[i].path) ||
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco strcmp(src[i].password, dest[i].password) ||
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco src[i].type != dest[i].type) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return 1;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* if we got here, the cert arrays were identical */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return 0;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco}
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco/*
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Find an existing ldap connection struct that matches the
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * provided ldap connection parameters.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco *
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 */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescostatic util_ldap_connection_t *
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco uldap_connection_find(request_rec *r,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco const char *host, int port,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco const char *binddn, const char *bindpw,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco deref_options deref, int secure)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco{
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco int secureflag = secure;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco util_ldap_state_t *st =
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco &ldap_module);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco#if APR_HAS_THREADS
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* mutex lock this function */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco apr_thread_mutex_lock(st->mutex);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco#endif
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (secure < APR_LDAP_NONE) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco secureflag = st->secure;
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco }
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* Search for an exact connection match in the list that is not
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * being used.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco for (l=st->connections,p=NULL; l; l=l->next) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#if APR_HAS_THREADS
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco#endif
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if ( (l->port == port) && (strcmp(l->host, host) == 0)
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco && ((!l->binddn && !binddn) || (l->binddn && binddn
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco && !strcmp(l->binddn, binddn)))
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco && !strcmp(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 {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco break;
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco }
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco#if APR_HAS_THREADS
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 */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco apr_thread_mutex_unlock(l->lock);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco p = l;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco }
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* If nothing found, search again, but we don't care about the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * binddn and bindpw this time.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if (!l) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco for (l=st->connections,p=NULL; l; l=l->next) {
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco#if APR_HAS_THREADS
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco#endif
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 {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* the bind credentials have changed */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->bound = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->binddn), binddn);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->bindpw), bindpw);
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco break;
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco }
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco#if APR_HAS_THREADS
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.
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco apr_thread_mutex_unlock(l->lock);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco p = l;
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* artificially disable cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* l = NULL; */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* If no connection what found after the second search, we
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * must create one.
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (!l) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /*
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 */
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 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "util_ldap: Failed to create memory pool");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#if APR_HAS_THREADS
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_unlock(st->mutex);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco return NULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#if APR_HAS_THREADS
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_lock(l->lock);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->bound = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->host = apr_pstrdup(st->pool, host);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->port = port;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->deref = deref;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->binddn), binddn);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_strdup((char**)&(l->bindpw), bindpw);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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 */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco l->secure = secureflag;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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 if (p) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco p->next = l;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco st->connections = l;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#if APR_HAS_THREADS
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_thread_mutex_unlock(st->mutex);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco#endif
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return l;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ------------------------------------------------------------------ */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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 *
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * The lock for the ldap cache should already be acquired.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riescostatic int uldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *url, const char *dn,
6f6549c13f912de12345850e4eb248ec358c1b43Adrián Riesco const char *reqdn, int compare_dn_on_server)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco{
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int result = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_url_node_t *curl;
6f6549c13f912de12345850e4eb248ec358c1b43Adrián Riesco util_url_node_t curnode;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_dn_compare_node_t *node;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_dn_compare_node_t newnode;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int failures = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAPMessage *res, *entry;
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco char *searchdn;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_state_t *st = (util_ldap_state_t *)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco &ldap_module);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* get cache entry (or create one) */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_LOCK();
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco curnode.url = url;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (curl == NULL) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco curl = util_ald_create_caches(st, url);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_UNLOCK();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* a simple compare? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (!compare_dn_on_server) {
3b1e33dd8d2de8301d7a31860dd1819bd3752718Adrián Riesco /* unlock this read lock */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (strcmp(dn, reqdn)) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison FALSE (direct strcmp())";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return LDAP_COMPARE_FALSE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison TRUE (direct strcmp())";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return LDAP_COMPARE_TRUE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (curl) {
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* no - it's a server side compare */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco LDAP_CACHE_LOCK();
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* is it in the compare cache? */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco newnode.reqdn = (char *)reqdn;
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if (node != NULL) {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* If it's in the cache, it's good */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* unlock this read lock */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_UNLOCK();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison TRUE (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return LDAP_COMPARE_TRUE;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco }
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* unlock this read lock */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco LDAP_CACHE_UNLOCK();
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco }
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riescostart_over:
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if (failures++ > 10) {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* too many failures */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco return result;
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco }
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
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 return result;
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco }
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
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 "(objectclass=*)", NULL, 1,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res))
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco == LDAP_SERVER_DOWN)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison ldap_search_ext_s() "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "failed with server down";
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco uldap_connection_unbind(ldc);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco goto start_over;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (result != LDAP_SUCCESS) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* search for reqdn failed - no match */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison ldap_search_ext_s() failed";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return result;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco entry = ldap_first_entry(ldc->ldap, res);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco searchdn = ldap_get_dn(ldc->ldap, entry);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldap_msgfree(res);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (strcmp(dn, searchdn) != 0) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* compare unsuccessful */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison FALSE (checked on server)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco result = LDAP_COMPARE_FALSE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (curl) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* compare successful - add to the compare cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_LOCK();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco newnode.reqdn = (char *)reqdn;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco newnode.dn = (char *)dn;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ( (node == NULL)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco || (strcmp(reqdn, node->reqdn) != 0)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco || (strcmp(dn, node->dn) != 0))
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ald_cache_insert(curl->dn_compare_cache, &newnode);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_UNLOCK();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "DN Comparison TRUE (checked on server)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco result = LDAP_COMPARE_TRUE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldap_memfree(searchdn);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return result;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/*
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 Riesco *
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riescostatic int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco const char *url, const char *dn,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *attrib, const char *value)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco{
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int result = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_url_node_t *curl;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_url_node_t curnode;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_compare_node_t *compare_nodep;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_compare_node_t the_compare_node;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_time_t curtime = 0; /* silence gcc -Wall */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco int failures = 0;
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco util_ldap_state_t *st = (util_ldap_state_t *)
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco ap_get_module_config(r->server->module_config,
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco &ldap_module);
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* get cache entry (or create one) */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_LOCK();
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco curnode.url = url;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (curl == NULL) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco curl = util_ald_create_caches(st, url);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_UNLOCK();
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (curl) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* make a comparison to the cache */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_LOCK();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco curtime = apr_time_now();
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco the_compare_node.dn = (char *)dn;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco the_compare_node.attrib = (char *)attrib;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco the_compare_node.value = (char *)value;
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco the_compare_node.result = 0;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco the_compare_node.sgl_processed = 0;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco the_compare_node.subgroupList = NULL;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco &the_compare_node);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (compare_nodep != NULL) {
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 }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ...and it is good */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (LDAP_COMPARE_TRUE == compare_nodep->result) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "Comparison true (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else if (LDAP_COMPARE_FALSE == compare_nodep->result) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "Comparison false (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
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 }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "Comparison undefined (cached)";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* record the result code to return with the reason... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco result = compare_nodep->result;
6f6549c13f912de12345850e4eb248ec358c1b43Adrián Riesco /* and unlock this read lock */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco LDAP_CACHE_UNLOCK();
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco return result;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* unlock this read lock */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco LDAP_CACHE_UNLOCK();
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescostart_over:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (failures++ > 10) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* too many failures */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return result;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* connect failed */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco return result;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if ((result = ldap_compare_s(ldc->ldap,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (char *)dn,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (char *)attrib,
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco (char *)value))
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco == LDAP_SERVER_DOWN) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* connection failed - try again */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "ldap_compare_s() failed with server down";
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco uldap_connection_unbind(ldc);
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco goto start_over;
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco }
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->reason = "Comparison complete";
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if ((LDAP_COMPARE_TRUE == result) ||
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco (LDAP_COMPARE_FALSE == result) ||
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco (LDAP_NO_SUCH_ATTRIBUTE == result)) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if (curl) {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco /* compare completed; caching result */
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco LDAP_CACHE_LOCK();
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco the_compare_node.lastcompare = curtime;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco the_compare_node.result = result;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco the_compare_node.sgl_processed = 0;
6e121321775373fe11161d23c541437456df19b4Adrián Riesco the_compare_node.subgroupList = NULL;
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* If the node doesn't exist then insert it, otherwise just update
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * it with the last results
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco &the_compare_node);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if ( (compare_nodep == NULL)
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))
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco void *junk;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco junk = util_ald_cache_insert(curl->compare_cache, &the_compare_node);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if(junk == NULL) {
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] cache_compare: Cache insertion failure.", getpid());
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco else {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco compare_nodep->lastcompare = curtime;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco compare_nodep->result = result;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco LDAP_CACHE_UNLOCK();
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if (LDAP_COMPARE_TRUE == result) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ldc->reason = "Comparison true (adding to cache)";
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco return LDAP_COMPARE_TRUE;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco else if (LDAP_COMPARE_FALSE == result) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "Comparison false (adding to cache)";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return LDAP_COMPARE_FALSE;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco else {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "Comparison no such attribute (adding to cache)";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return LDAP_NO_SUCH_ATTRIBUTE;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco }
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco return result;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco}
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic util_compare_subgroup_t* uldap_get_subgroups(request_rec *r, util_ldap_connection_t *ldc,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco const char *url, const char *dn,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco char **subgroupAttrs, apr_array_header_t *subgroupclasses) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco int failures = 0;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco int result = LDAP_COMPARE_FALSE;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco util_compare_subgroup_t *res = NULL;
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco LDAPMessage *sga_res, *entry;
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 *));
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (!subgroupAttrs) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return res;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco }
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riescostart_over:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* 3.B. The cache didn't have any subgrouplist yet. Go check for subgroups. */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (failures++ > 10) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* too many failures */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco return res;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco }
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* connect failed */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return res;
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco }
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* try to do the search */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco result = ldap_search_ext_s(ldc->ldap, (char *)dn, LDAP_SCOPE_BASE,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (char *)"cn=*", subgroupAttrs, 0,
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &sga_res);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (result == LDAP_SERVER_DOWN) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ldc->reason = "ldap_search_ext_s() for subgroups failed with server down";
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco uldap_connection_unbind(ldc);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco goto start_over;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco }
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (result != LDAP_SUCCESS) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldc->reason = "ldap_search_ext_s() for subgroups failed";
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco return res;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco entry = ldap_first_entry(ldc->ldap, sga_res);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /*
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco * Get values for the provided sub-group attributes.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (subgroupAttrs) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int indx = 0, tmp_sgcIndex;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco while (subgroupAttrs[indx]) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco char **values;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco int val_index = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Get *all* matching "member" values from this group. */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco values = ldap_get_values(ldc->ldap, entry, subgroupAttrs[indx]);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (values) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco val_index = 0;
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /*
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.
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco while (values[val_index]) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Check if this entry really is a group. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco tmp_sgcIndex = 0;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco result = LDAP_COMPARE_FALSE;
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",
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco sgc_ents[tmp_sgcIndex].name);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco if (result != LDAP_COMPARE_TRUE) {
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco tmp_sgcIndex++;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco }
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco /* It's a group, so add it to the array. */
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco if (result == LDAP_COMPARE_TRUE) {
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco char **newgrp = (char **) apr_array_push(subgroups);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco *newgrp = apr_pstrdup(r->pool, values[val_index]);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco val_index++;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldap_value_free(values);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco indx++;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ldap_msgfree(sga_res);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (subgroups->nelts > 0) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* We need to fill in tmp_local_subgroups using the data from LDAP */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int sgindex;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco char **group;
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 }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco res->len = sgindex;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return res;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco}
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/*
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
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco *
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * DON'T CALL THIS UNLESS YOU CALLED uldap_cache_compare FIRST!!!!!
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /*
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 Riesco */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic int uldap_cache_check_subgroups(request_rec *r, util_ldap_connection_t *ldc,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *url, const char *dn,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *attrib, const char *value,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco char **subgroupAttrs, apr_array_header_t *subgroupclasses,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int cur_subgroup_depth, int max_subgroup_depth)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco{
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco int result = LDAP_COMPARE_FALSE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_url_node_t *curl;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_url_node_t curnode;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_compare_node_t *compare_nodep;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_compare_node_t the_compare_node;
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
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco util_ldap_state_t *st = (util_ldap_state_t *)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_get_module_config(r->server->module_config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco &ldap_module);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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 */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (cur_subgroup_depth >= max_subgroup_depth) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return LDAP_COMPARE_FALSE;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
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);
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if (result != LDAP_COMPARE_TRUE) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco base_sgcIndex++;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco }
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (result != LDAP_COMPARE_TRUE) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ldc->reason = "DN failed group verification.";
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return result;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco }
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* 2. Find previously created cache entry and check if there is already a subgrouplist. */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco LDAP_CACHE_LOCK();
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco curnode.url = url;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode);
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco LDAP_CACHE_UNLOCK();
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco if (curl && curl->compare_cache) {
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* make a comparison to the cache */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco LDAP_CACHE_LOCK();
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.dn = (char *)dn;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.attrib = (char *)"objectClass";
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.result = 0;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.sgl_processed = 0;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco the_compare_node.subgroupList = NULL;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
6e121321775373fe11161d23c541437456df19b4Adrián Riesco
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco if (compare_nodep != NULL) {
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 */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco int i;
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 }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco LDAP_CACHE_UNLOCK();
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco else {
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.";
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco return LDAP_COMPARE_FALSE;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco }
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco result = LDAP_COMPARE_FALSE;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco
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 if (!tmp_local_sgl) {
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 }
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco lcl_sgl_processedFlag = 1;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* Find the generic group cache entry and add the sgl we just retrieved. */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco LDAP_CACHE_LOCK();
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.dn = (char *)dn;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.attrib = (char *)"objectClass";
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.result = 0;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.sgl_processed = 0;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco the_compare_node.subgroupList = NULL;
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco if (compare_nodep == NULL) {
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco /* Didn't find it. This shouldn't happen since we just called uldap_cache_compare. */
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco LDAP_CACHE_UNLOCK();
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco ldc->reason = "check_subgroups failed to find the cache entry to add sub-group list to.";
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco return LDAP_COMPARE_FALSE;
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco }
205d9bc0182b3e68e480c44806565362df2fcdcaAdrián Riesco /*
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 */
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco compare_nodep->sgl_processed = 1;
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco if (tmp_local_sgl) {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco compare_nodep->subgroupList = util_ald_sgl_dup(curl->compare_cache, tmp_local_sgl);
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco }
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco else {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco /* We didn't find a single subgroup, next time save us from looking */
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco compare_nodep->subgroupList = NULL;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco LDAP_CACHE_UNLOCK();
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco
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 result = LDAP_COMPARE_FALSE;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco if (!tmp_local_sgl) {
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco return result;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco while ((result != LDAP_COMPARE_TRUE) && (sgindex < tmp_local_sgl->len)) {
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco const char *group = NULL;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco group = tmp_local_sgl->subgroupDNs[sgindex];
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 if (result == LDAP_COMPARE_TRUE) {
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 }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco else {
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,
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco value, subgroupAttrs, subgroupclasses,
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco cur_subgroup_depth+1, max_subgroup_depth);
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco sgindex++;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco }
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco return result;
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco}
c6a4f949f2a9da476c80399fb061020937255f87Adrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riescostatic int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco const char *url, const char *basedn,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco int scope, char **attrs, const char *filter,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco const char *bindpw, const char **binddn,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco const char ***retvals)
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco{
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco const char **vals = NULL;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco int numvals = 0;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco int result = 0;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco LDAPMessage *res, *entry;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco char *dn;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco int count;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco int failures = 0;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_url_node_t *curl; /* Cached URL node */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_url_node_t curnode;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_search_node_t *search_nodep; /* Cached search node */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_search_node_t the_search_node;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco apr_time_t curtime;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco util_ldap_state_t *st =
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco &ldap_module);
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* Get the cache node for this url */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco LDAP_CACHE_LOCK();
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco curnode.url = url;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco &curnode);
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if (curl == NULL) {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco curl = util_ald_create_caches(st, url);
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco }
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco LDAP_CACHE_UNLOCK();
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if (curl) {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco LDAP_CACHE_LOCK();
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco the_search_node.username = filter;
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco search_nodep = util_ald_cache_fetch(curl->search_cache,
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco &the_search_node);
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if (search_nodep != NULL) {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* found entry in search cache... */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco curtime = apr_time_now();
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /*
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 */
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
0f35e410ce3d3202f6769e9d139ad26d1de69b8eAdrián Riesco /* ...but entry is too old */
util_ald_cache_remove(curl->search_cache, search_nodep);
}
else if ( (search_nodep->bindpw)
&& (search_nodep->bindpw[0] != '\0')
&& (strcmp(search_nodep->bindpw, bindpw) == 0))
{
/* ...and entry is valid */
*binddn = apr_pstrdup(r->pool, search_nodep->dn);
if (attrs) {
int i = 0, k = 0;
while (attrs[k++]);
*retvals = apr_pcalloc(r->pool, sizeof(char *) * k);
while (search_nodep->vals[i]) {
(*retvals)[i] = apr_pstrdup(r->pool, search_nodep->vals[i]);
i++;
}
}
LDAP_CACHE_UNLOCK();
ldc->reason = "Authentication successful (cached)";
return LDAP_SUCCESS;
}
}
/* unlock this read lock */
LDAP_CACHE_UNLOCK();
}
/*
* At this point, there is no valid cached search, so lets do the search.
*/
/*
* If LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
*/
start_over:
if (failures++ > 10) {
return result;
}
if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
return result;
}
/* try do the search */
if ((result = ldap_search_ext_s(ldc->ldap,
(char *)basedn, scope,
(char *)filter, attrs, 0,
NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res))
== LDAP_SERVER_DOWN)
{
ldc->reason = "ldap_search_ext_s() for user failed with server down";
uldap_connection_unbind(ldc);
goto start_over;
}
/* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
if (result != LDAP_SUCCESS) {
ldc->reason = "ldap_search_ext_s() for user failed";
return result;
}
/*
* We should have found exactly one entry; to find a different
* number is an error.
*/
count = ldap_count_entries(ldc->ldap, res);
if (count != 1)
{
if (count == 0 )
ldc->reason = "User not found";
else
ldc->reason = "User is not unique (search found two "
"or more matches)";
ldap_msgfree(res);
return LDAP_NO_SUCH_OBJECT;
}
entry = ldap_first_entry(ldc->ldap, res);
/* Grab the dn, copy it into the pool, and free it again */
dn = ldap_get_dn(ldc->ldap, entry);
*binddn = apr_pstrdup(r->pool, dn);
ldap_memfree(dn);
/*
* A bind to the server with an empty password always succeeds, so
* we check to ensure that the password is not empty. This implies
* that users who actually do have empty passwords will never be
* able to authenticate with this module. I don't see this as a big
* problem.
*/
if (!bindpw || strlen(bindpw) <= 0) {
ldap_msgfree(res);
ldc->reason = "Empty password not allowed";
return LDAP_INVALID_CREDENTIALS;
}
/*
* Attempt to bind with the retrieved dn and the password. If the bind
* fails, it means that the password is wrong (the dn obviously
* exists, since we just retrieved it)
*/
if ((result = ldap_simple_bind_s(ldc->ldap,
(char *)*binddn,
(char *)bindpw)) == LDAP_SERVER_DOWN) {
ldc->reason = "ldap_simple_bind_s() to check user credentials "
"failed with server down";
ldap_msgfree(res);
uldap_connection_unbind(ldc);
goto start_over;
}
/* failure? if so - return */
if (result != LDAP_SUCCESS) {
ldc->reason = "ldap_simple_bind_s() to check user credentials failed";
ldap_msgfree(res);
uldap_connection_unbind(ldc);
return result;
}
else {
/*
* We have just bound the connection to a different user and password
* combination, which might be reused unintentionally next time this
* connection is used from the connection pool. To ensure no confusion,
* we mark the connection as unbound.
*/
ldc->bound = 0;
}
/*
* Get values for the provided attributes.
*/
if (attrs) {
int k = 0;
int i = 0;
while (attrs[k++]);
vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
numvals = k;
while (attrs[i]) {
char **values;
int j = 0;
char *str = NULL;
/* get values */
values = ldap_get_values(ldc->ldap, entry, attrs[i]);
while (values && values[j]) {
str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL)
: apr_pstrdup(r->pool, values[j]);
j++;
}
ldap_value_free(values);
vals[i] = str;
i++;
}
*retvals = vals;
}
/*
* 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();
}
ldap_msgfree(res);
ldc->reason = "Authentication successful";
return LDAP_SUCCESS;
}
/*
* This function will return the DN of the entry matching userid.
* It is used to get the DN in case some other module than mod_auth_ldap
* has authenticated the user.
* The function is basically a copy of uldap_cache_checkuserid
* with password checking removed.
*/
static int uldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc,
const char *url, const char *basedn,
int scope, char **attrs, const char *filter,
const char **binddn, const char ***retvals)
{
const char **vals = NULL;
int numvals = 0;
int result = 0;
LDAPMessage *res, *entry;
char *dn;
int count;
int failures = 0;
util_url_node_t *curl; /* Cached URL node */
util_url_node_t curnode;
util_search_node_t *search_nodep; /* Cached search node */
util_search_node_t the_search_node;
apr_time_t curtime;
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
&ldap_module);
/* Get the cache node for this url */
LDAP_CACHE_LOCK();
curnode.url = url;
curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache,
&curnode);
if (curl == NULL) {
curl = util_ald_create_caches(st, url);
}
LDAP_CACHE_UNLOCK();
if (curl) {
LDAP_CACHE_LOCK();
the_search_node.username = filter;
search_nodep = util_ald_cache_fetch(curl->search_cache,
&the_search_node);
if (search_nodep != NULL) {
/* found entry in search cache... */
curtime = apr_time_now();
/*
* Remove this item from the cache if its expired.
*/
if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
/* ...but entry is too old */
util_ald_cache_remove(curl->search_cache, search_nodep);
}
else {
/* ...and entry is valid */
*binddn = apr_pstrdup(r->pool, search_nodep->dn);
if (attrs) {
int i = 0, k = 0;
while (attrs[k++]);
*retvals = apr_pcalloc(r->pool, sizeof(char *) * k);
while (search_nodep->vals[i]) {
(*retvals)[i] = apr_pstrdup(r->pool, search_nodep->vals[i]);
i++;
}
}
LDAP_CACHE_UNLOCK();
ldc->reason = "Search successful (cached)";
return LDAP_SUCCESS;
}
}
/* unlock this read lock */
LDAP_CACHE_UNLOCK();
}
/*
* At this point, there is no valid cached search, so lets do the search.
*/
/*
* If LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
*/
start_over:
if (failures++ > 10) {
return result;
}
if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) {
return result;
}
/* try do the search */
if ((result = ldap_search_ext_s(ldc->ldap,
(char *)basedn, scope,
(char *)filter, attrs, 0,
NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res))
== LDAP_SERVER_DOWN)
{
ldc->reason = "ldap_search_ext_s() for user failed with server down";
uldap_connection_unbind(ldc);
goto start_over;
}
/* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
if (result != LDAP_SUCCESS) {
ldc->reason = "ldap_search_ext_s() for user failed";
return result;
}
/*
* We should have found exactly one entry; to find a different
* number is an error.
*/
count = ldap_count_entries(ldc->ldap, res);
if (count != 1)
{
if (count == 0 )
ldc->reason = "User not found";
else
ldc->reason = "User is not unique (search found two "
"or more matches)";
ldap_msgfree(res);
return LDAP_NO_SUCH_OBJECT;
}
entry = ldap_first_entry(ldc->ldap, res);
/* Grab the dn, copy it into the pool, and free it again */
dn = ldap_get_dn(ldc->ldap, entry);
*binddn = apr_pstrdup(r->pool, dn);
ldap_memfree(dn);
/*
* Get values for the provided attributes.
*/
if (attrs) {
int k = 0;
int i = 0;
while (attrs[k++]);
vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
numvals = k;
while (attrs[i]) {
char **values;
int j = 0;
char *str = NULL;
/* get values */
values = ldap_get_values(ldc->ldap, entry, attrs[i]);
while (values && values[j]) {
str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL)
: apr_pstrdup(r->pool, values[j]);
j++;
}
ldap_value_free(values);
vals[i] = str;
i++;
}
*retvals = vals;
}
/*
* 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 = NULL;
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);
}
/*
* Don't update lastbind on entries with bindpw because
* we haven't verified that password. It's OK to update
* the entry if there is no password in it.
*/
else if (!search_nodep->bindpw) {
/* Cache entry is valid, update lastbind */
search_nodep->lastbind = the_search_node.lastbind;
}
LDAP_CACHE_UNLOCK();
}
ldap_msgfree(res);
ldc->reason = "Search successful";
return LDAP_SUCCESS;
}
/*
* Reports if ssl support is enabled
*
* 1 = enabled, 0 = not enabled
*/
static int uldap_ssl_supported(request_rec *r)
{
util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
r->server->module_config, &ldap_module);
return(st->ssl_supported);
}
/* ---------------------------------------- */
/* config directives */
static const char *util_ldap_set_cache_bytes(cmd_parms *cmd, void *dummy,
const char *bytes)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
st->cache_bytes = atol(bytes);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap cache: Setting shared memory "
" cache size to %" APR_SIZE_T_FMT " bytes.",
getpid(), st->cache_bytes);
return NULL;
}
static const char *util_ldap_set_cache_file(cmd_parms *cmd, void *dummy,
const char *file)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (file) {
st->cache_file = ap_server_root_relative(st->pool, file);
}
else {
st->cache_file = NULL;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"LDAP cache: Setting shared memory cache file to %s bytes.",
st->cache_file);
return NULL;
}
static const char *util_ldap_set_cache_ttl(cmd_parms *cmd, void *dummy,
const char *ttl)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
st->search_cache_ttl = atol(ttl) * 1000000;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap cache: Setting cache TTL to %ld microseconds.",
getpid(), st->search_cache_ttl);
return NULL;
}
static const char *util_ldap_set_cache_entries(cmd_parms *cmd, void *dummy,
const char *size)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
st->search_cache_size = atol(size);
if (st->search_cache_size < 0) {
st->search_cache_size = 0;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap cache: Setting search cache size to %ld entries.",
getpid(), st->search_cache_size);
return NULL;
}
static const char *util_ldap_set_opcache_ttl(cmd_parms *cmd, void *dummy,
const char *ttl)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
st->compare_cache_ttl = atol(ttl) * 1000000;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap cache: Setting operation cache TTL to %ld microseconds.",
getpid(), st->compare_cache_ttl);
return NULL;
}
static const char *util_ldap_set_opcache_entries(cmd_parms *cmd, void *dummy,
const char *size)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
st->compare_cache_size = atol(size);
if (st->compare_cache_size < 0) {
st->compare_cache_size = 0;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap cache: Setting operation cache size to %ld "
"entries.", getpid(), st->compare_cache_size);
return NULL;
}
/**
* Parse the certificate type.
*
* The type can be one of the following:
* CA_DER, CA_BASE64, CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64,
* CERT_KEY3_DB, CERT_NICKNAME, KEY_DER, KEY_BASE64
*
* If no matches are found, APR_LDAP_CA_TYPE_UNKNOWN is returned.
*/
static int util_ldap_parse_cert_type(const char *type)
{
/* Authority file in binary DER format */
if (0 == strcasecmp("CA_DER", type)) {
return APR_LDAP_CA_TYPE_DER;
}
/* Authority file in Base64 format */
else if (0 == strcasecmp("CA_BASE64", type)) {
return APR_LDAP_CA_TYPE_BASE64;
}
/* Netscape certificate database file/directory */
else if (0 == strcasecmp("CA_CERT7_DB", type)) {
return APR_LDAP_CA_TYPE_CERT7_DB;
}
/* Netscape secmod file/directory */
else if (0 == strcasecmp("CA_SECMOD", type)) {
return APR_LDAP_CA_TYPE_SECMOD;
}
/* Client cert file in DER format */
else if (0 == strcasecmp("CERT_DER", type)) {
return APR_LDAP_CERT_TYPE_DER;
}
/* Client cert file in Base64 format */
else if (0 == strcasecmp("CERT_BASE64", type)) {
return APR_LDAP_CERT_TYPE_BASE64;
}
/* Client cert file in PKCS#12 format */
else if (0 == strcasecmp("CERT_PFX", type)) {
return APR_LDAP_CERT_TYPE_PFX;
}
/* Netscape client cert database file/directory */
else if (0 == strcasecmp("CERT_KEY3_DB", type)) {
return APR_LDAP_CERT_TYPE_KEY3_DB;
}
/* Netscape client cert nickname */
else if (0 == strcasecmp("CERT_NICKNAME", type)) {
return APR_LDAP_CERT_TYPE_NICKNAME;
}
/* Client cert key file in DER format */
else if (0 == strcasecmp("KEY_DER", type)) {
return APR_LDAP_KEY_TYPE_DER;
}
/* Client cert key file in Base64 format */
else if (0 == strcasecmp("KEY_BASE64", type)) {
return APR_LDAP_KEY_TYPE_BASE64;
}
/* Client cert key file in PKCS#12 format */
else if (0 == strcasecmp("KEY_PFX", type)) {
return APR_LDAP_KEY_TYPE_PFX;
}
else {
return APR_LDAP_CA_TYPE_UNKNOWN;
}
}
/**
* Set LDAPTrustedGlobalCert.
*
* This directive takes either two or three arguments:
* - certificate type
* - certificate file / directory / nickname
* - certificate password (optional)
*
* This directive may only be used globally.
*/
static const char *util_ldap_set_trusted_global_cert(cmd_parms *cmd,
void *dummy,
const char *type,
const char *file,
const char *password)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
apr_finfo_t finfo;
apr_status_t rv;
int cert_type = 0;
apr_ldap_opt_tls_cert_t *cert;
if (err != NULL) {
return err;
}
/* handle the certificate type */
if (type) {
cert_type = util_ldap_parse_cert_type(type);
if (APR_LDAP_CA_TYPE_UNKNOWN == cert_type) {
return apr_psprintf(cmd->pool, "The certificate type %s is "
"not recognised. It should be one "
"of CA_DER, CA_BASE64, CA_CERT7_DB, "
"CA_SECMOD, CERT_DER, CERT_BASE64, "
"CERT_KEY3_DB, CERT_NICKNAME, "
"KEY_DER, KEY_BASE64", type);
}
}
else {
return "Certificate type was not specified.";
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"LDAP: SSL trusted global cert - %s (type %s)",
file, type);
/* add the certificate to the global array */
cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(st->global_certs);
cert->type = cert_type;
cert->path = file;
cert->password = password;
/* if file is a file or path, fix the path */
if (cert_type != APR_LDAP_CA_TYPE_UNKNOWN &&
cert_type != APR_LDAP_CERT_TYPE_NICKNAME) {
cert->path = ap_server_root_relative(cmd->pool, file);
if (cert->path &&
((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool))
!= APR_SUCCESS))
{
ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
"LDAP: Could not open SSL trusted certificate "
"authority file - %s",
cert->path == NULL ? file : cert->path);
return "Invalid global certificate file path";
}
}
return(NULL);
}
/**
* Set LDAPTrustedClientCert.
*
* This directive takes either two or three arguments:
* - certificate type
* - certificate file / directory / nickname
* - certificate password (optional)
*/
static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd,
void *config,
const char *type,
const char *file,
const char *password)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
apr_finfo_t finfo;
apr_status_t rv;
int cert_type = 0;
apr_ldap_opt_tls_cert_t *cert;
/* handle the certificate type */
if (type) {
cert_type = util_ldap_parse_cert_type(type);
if (APR_LDAP_CA_TYPE_UNKNOWN == cert_type) {
return apr_psprintf(cmd->pool, "The certificate type \"%s\" is "
"not recognised. It should be one "
"of CERT_DER, CERT_BASE64, "
"CERT_NICKNAME, CERT_PFX,"
"KEY_DER, KEY_BASE64, KEY_PFX",
type);
}
else if (APR_LDAP_CA_TYPE_DER == cert_type ||
APR_LDAP_CA_TYPE_BASE64 == cert_type ||
APR_LDAP_CA_TYPE_CERT7_DB == cert_type ||
APR_LDAP_CA_TYPE_SECMOD == cert_type ||
APR_LDAP_CERT_TYPE_PFX == cert_type ||
APR_LDAP_CERT_TYPE_KEY3_DB == cert_type) {
return apr_psprintf(cmd->pool, "The certificate type \"%s\" is "
"only valid within a "
"LDAPTrustedGlobalCert directive. "
"Only CERT_DER, CERT_BASE64, "
"CERT_NICKNAME, KEY_DER, and "
"KEY_BASE64 may be used.", type);
}
}
else {
return "Certificate type was not specified.";
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"LDAP: SSL trusted client cert - %s (type %s)",
file, type);
/* add the certificate to the global array */
cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(st->global_certs);
cert->type = cert_type;
cert->path = file;
cert->password = password;
/* if file is a file or path, fix the path */
if (cert_type != APR_LDAP_CA_TYPE_UNKNOWN &&
cert_type != APR_LDAP_CERT_TYPE_NICKNAME) {
cert->path = ap_server_root_relative(cmd->pool, file);
if (cert->path &&
((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool))
!= APR_SUCCESS))
{
ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
"LDAP: Could not open SSL client certificate "
"file - %s",
cert->path == NULL ? file : cert->path);
return "Invalid client certificate file path";
}
}
return(NULL);
}
/**
* Set LDAPTrustedMode.
*
* This directive sets what encryption mode to use on a connection:
* - None (No encryption)
* - SSL (SSL encryption)
* - STARTTLS (TLS encryption)
*/
static const char *util_ldap_set_trusted_mode(cmd_parms *cmd, void *dummy,
const char *mode)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"LDAP: SSL trusted mode - %s",
mode);
if (0 == strcasecmp("NONE", mode)) {
st->secure = APR_LDAP_NONE;
}
else if (0 == strcasecmp("SSL", mode)) {
st->secure = APR_LDAP_SSL;
}
else if ( (0 == strcasecmp("TLS", mode))
|| (0 == strcasecmp("STARTTLS", mode))) {
st->secure = APR_LDAP_STARTTLS;
}
else {
return "Invalid LDAPTrustedMode setting: must be one of NONE, "
"SSL, or TLS/STARTTLS";
}
st->secure_set = 1;
return(NULL);
}
static const char *util_ldap_set_verify_srv_cert(cmd_parms *cmd,
void *dummy,
int mode)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"LDAP: SSL verify server certificate - %s",
mode?"TRUE":"FALSE");
st->verify_svr_cert = mode;
return(NULL);
}
static const char *util_ldap_set_connection_timeout(cmd_parms *cmd,
void *dummy,
const char *ttl)
{
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
&ldap_module);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
#ifdef LDAP_OPT_NETWORK_TIMEOUT
st->connectionTimeout = atol(ttl);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"[%" APR_PID_T_FMT "] ldap connection: Setting connection timeout to "
"%ld seconds.", getpid(), st->connectionTimeout);
#else
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server,
"LDAP: Connection timout option not supported by the "
"LDAP SDK in use." );
#endif
return NULL;
}
static void *util_ldap_create_config(apr_pool_t *p, server_rec *s)
{
util_ldap_state_t *st =
(util_ldap_state_t *)apr_pcalloc(p, sizeof(util_ldap_state_t));
/* Create a per vhost pool for mod_ldap to use, serialized with
* st->mutex (also one per vhost). both are replicated by fork(),
* no shared memory managed by either.
*/
apr_pool_create(&st->pool, p);
#if APR_HAS_THREADS
apr_thread_mutex_create(&st->mutex, APR_THREAD_MUTEX_DEFAULT, st->pool);
#endif
st->cache_bytes = 100000;
st->search_cache_ttl = 600000000;
st->search_cache_size = 1024;
st->compare_cache_ttl = 600000000;
st->compare_cache_size = 1024;
st->connections = NULL;
st->ssl_supported = 0;
st->global_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t));
st->client_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t));
st->secure = APR_LDAP_NONE;
st->secure_set = 0;
st->connectionTimeout = 10;
st->verify_svr_cert = 1;
return st;
}
static void *util_ldap_merge_config(apr_pool_t *p, void *basev,
void *overridesv)
{
util_ldap_state_t *st = apr_pcalloc(p, sizeof(util_ldap_state_t));
util_ldap_state_t *base = (util_ldap_state_t *) basev;
util_ldap_state_t *overrides = (util_ldap_state_t *) overridesv;
st->pool = overrides->pool;
#if APR_HAS_THREADS
st->mutex = overrides->mutex;
#endif
/* The cache settings can not be modified in a
virtual host since all server use the same
shared memory cache. */
st->cache_bytes = base->cache_bytes;
st->search_cache_ttl = base->search_cache_ttl;
st->search_cache_size = base->search_cache_size;
st->compare_cache_ttl = base->compare_cache_ttl;
st->compare_cache_size = base->compare_cache_size;
st->util_ldap_cache_lock = base->util_ldap_cache_lock;
st->connections = NULL;
st->ssl_supported = 0;
st->global_certs = apr_array_append(p, base->global_certs,
overrides->global_certs);
st->client_certs = apr_array_append(p, base->client_certs,
overrides->client_certs);
st->secure = (overrides->secure_set == 0) ? base->secure
: overrides->secure;
/* These LDAP connection settings can not be overwritten in
a virtual host. Once set in the base server, they must
remain the same. None of the LDAP SDKs seem to be able
to handle setting the verify_svr_cert flag on a
per-connection basis. The OpenLDAP client appears to be
able to handle the connection timeout per-connection
but the Novell SDK cannot. Allowing the timeout to
be set by each vhost is of little value so rather than
trying to make special expections for one LDAP SDK, GLOBAL_ONLY
is being enforced on this setting as well. */
st->connectionTimeout = base->connectionTimeout;
st->verify_svr_cert = base->verify_svr_cert;
return st;
}
static apr_status_t util_ldap_cleanup_module(void *data)
{
server_rec *s = data;
util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
s->module_config, &ldap_module);
if (st->ssl_supported) {
apr_ldap_ssl_deinit();
}
return APR_SUCCESS;
}
static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
apr_status_t result;
server_rec *s_vhost;
util_ldap_state_t *st_vhost;
util_ldap_state_t *st = (util_ldap_state_t *)
ap_get_module_config(s->module_config,
&ldap_module);
void *data;
const char *userdata_key = "util_ldap_init";
apr_ldap_err_t *result_err = NULL;
int rc;
/* util_ldap_post_config() will be called twice. Don't bother
* going through all of the initialization on the first call
* because it will just be thrown away.*/
apr_pool_userdata_get(&data, userdata_key, s->process->pool);
if (!data) {
apr_pool_userdata_set((const void *)1, userdata_key,
apr_pool_cleanup_null, s->process->pool);
#if APR_HAS_SHARED_MEMORY
/* If the cache file already exists then delete it. Otherwise we are
* going to run into problems creating the shared memory. */
if (st->cache_file) {
char *lck_file = apr_pstrcat(ptemp, st->cache_file, ".lck",
NULL);
apr_file_remove(lck_file, ptemp);
}
#endif
return OK;
}
#if APR_HAS_SHARED_MEMORY
/* initializing cache if shared memory size is not zero and we already
* don't have shm address
*/
if (!st->cache_shm && st->cache_bytes > 0) {
#endif
result = util_ldap_cache_init(p, st);
if (result != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, result, s,
"LDAP cache: could not create shared memory segment");
return DONE;
}
#if APR_HAS_SHARED_MEMORY
if (st->cache_file) {
st->lock_file = apr_pstrcat(st->pool, st->cache_file, ".lck",
NULL);
}
#endif
result = apr_global_mutex_create(&st->util_ldap_cache_lock,
st->lock_file, APR_LOCK_DEFAULT,
st->pool);
if (result != APR_SUCCESS) {
return result;
}
#ifdef AP_NEED_SET_MUTEX_PERMS
result = unixd_set_global_mutex_perms(st->util_ldap_cache_lock);
if (result != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, result, s,
"LDAP cache: failed to set mutex permissions");
return result;
}
#endif
/* merge config in all vhost */
s_vhost = s->next;
while (s_vhost) {
st_vhost = (util_ldap_state_t *)
ap_get_module_config(s_vhost->module_config,
&ldap_module);
#if APR_HAS_SHARED_MEMORY
st_vhost->cache_shm = st->cache_shm;
st_vhost->cache_rmm = st->cache_rmm;
st_vhost->cache_file = st->cache_file;
ap_log_error(APLOG_MARK, APLOG_DEBUG, result, s,
"LDAP merging Shared Cache conf: shm=0x%pp rmm=0x%pp "
"for VHOST: %s", st->cache_shm, st->cache_rmm,
s_vhost->server_hostname);
#endif
st_vhost->lock_file = st->lock_file;
s_vhost = s_vhost->next;
}
#if APR_HAS_SHARED_MEMORY
}
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"LDAP cache: LDAPSharedCacheSize is zero, disabling "
"shared memory cache");
}
#endif
/* log the LDAP SDK used
*/
{
apr_ldap_err_t *result = NULL;
apr_ldap_info(p, &(result));
if (result != NULL) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "%s", result->reason);
}
}
apr_pool_cleanup_register(p, s, util_ldap_cleanup_module,
util_ldap_cleanup_module);
/*
* Initialize SSL support, and log the result for the benefit of the admin.
*
* If SSL is not supported it is not necessarily an error, as the
* application may not want to use it.
*/
rc = apr_ldap_ssl_init(p,
NULL,
0,
&(result_err));
if (APR_SUCCESS == rc) {
rc = apr_ldap_set_option(ptemp, NULL, APR_LDAP_OPT_TLS_CERT,
(void *)st->global_certs, &(result_err));
}
if (APR_SUCCESS == rc) {
st->ssl_supported = 1;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
"LDAP: SSL support available" );
}
else {
st->ssl_supported = 0;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
"LDAP: SSL support unavailable%s%s",
result_err ? ": " : "",
result_err ? result_err->reason : "");
}
return(OK);
}
static void util_ldap_child_init(apr_pool_t *p, server_rec *s)
{
apr_status_t sts;
util_ldap_state_t *st = ap_get_module_config(s->module_config,
&ldap_module);
if (!st->util_ldap_cache_lock) return;
sts = apr_global_mutex_child_init(&st->util_ldap_cache_lock,
st->lock_file, p);
if (sts != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, sts, s,
"Failed to initialise global mutex %s in child process %"
APR_PID_T_FMT ".",
st->lock_file, getpid());
}
}
static const command_rec util_ldap_cmds[] = {
AP_INIT_TAKE1("LDAPSharedCacheSize", util_ldap_set_cache_bytes,
NULL, RSRC_CONF,
"Set the size of the shared memory cache (in bytes). Use "
"0 to disable the shared memory cache. (default: 100000)"),
AP_INIT_TAKE1("LDAPSharedCacheFile", util_ldap_set_cache_file,
NULL, RSRC_CONF,
"Set the file name for the shared memory cache."),
AP_INIT_TAKE1("LDAPCacheEntries", util_ldap_set_cache_entries,
NULL, RSRC_CONF,
"Set the maximum number of entries that are possible in the "
"LDAP search cache. Use 0 for no limit. "
"-1 disables the cache. (default: 1024)"),
AP_INIT_TAKE1("LDAPCacheTTL", util_ldap_set_cache_ttl,
NULL, RSRC_CONF,
"Set the maximum time (in seconds) that an item can be "
"cached in the LDAP search cache. Use 0 for no limit. "
"(default 600)"),
AP_INIT_TAKE1("LDAPOpCacheEntries", util_ldap_set_opcache_entries,
NULL, RSRC_CONF,
"Set the maximum number of entries that are possible "
"in the LDAP compare cache. Use 0 for no limit. "
"Use -1 to disable the cache. (default: 1024)"),
AP_INIT_TAKE1("LDAPOpCacheTTL", util_ldap_set_opcache_ttl,
NULL, RSRC_CONF,
"Set the maximum time (in seconds) that an item is cached "
"in the LDAP operation cache. Use 0 for no limit. "
"(default: 600)"),
AP_INIT_TAKE23("LDAPTrustedGlobalCert", util_ldap_set_trusted_global_cert,
NULL, RSRC_CONF,
"Takes three args; the file and/or directory containing "
"the trusted CA certificates (and global client certs "
"for Netware) used to validate the LDAP server. Second "
"arg is the cert type for the first arg, one of CA_DER, "
"CA_BASE64, CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64, "
"CERT_KEY3_DB, CERT_NICKNAME, KEY_DER, or KEY_BASE64. "
"Third arg is an optional passphrase if applicable."),
AP_INIT_TAKE23("LDAPTrustedClientCert", util_ldap_set_trusted_client_cert,
NULL, RSRC_CONF,
"Takes three args; the file and/or directory containing "
"the client certificate, or certificate ID used to "
"validate this LDAP client. Second arg is the cert type "
"for the first arg, one of CA_DER, CA_BASE64, CA_CERT7_DB, "
"CA_SECMOD, CERT_DER, CERT_BASE64, CERT_KEY3_DB, "
"CERT_NICKNAME, KEY_DER, or KEY_BASE64. Third arg is an "
"optional passphrase if applicable."),
AP_INIT_TAKE1("LDAPTrustedMode", util_ldap_set_trusted_mode,
NULL, RSRC_CONF,
"Specify the type of security that should be applied to "
"an LDAP connection. One of; NONE, SSL or STARTTLS."),
AP_INIT_FLAG("LDAPVerifyServerCert", util_ldap_set_verify_srv_cert,
NULL, RSRC_CONF,
"Set to 'ON' requires that the server certificate be verified "
"before a secure LDAP connection can be establish. Default 'ON'"),
AP_INIT_TAKE1("LDAPConnectionTimeout", util_ldap_set_connection_timeout,
NULL, RSRC_CONF,
"Specify the LDAP socket connection timeout in seconds "
"(default: 10)"),
{NULL}
};
static void util_ldap_register_hooks(apr_pool_t *p)
{
APR_REGISTER_OPTIONAL_FN(uldap_connection_open);
APR_REGISTER_OPTIONAL_FN(uldap_connection_close);
APR_REGISTER_OPTIONAL_FN(uldap_connection_unbind);
APR_REGISTER_OPTIONAL_FN(uldap_connection_cleanup);
APR_REGISTER_OPTIONAL_FN(uldap_connection_find);
APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn);
APR_REGISTER_OPTIONAL_FN(uldap_cache_compare);
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid);
APR_REGISTER_OPTIONAL_FN(uldap_cache_getuserdn);
APR_REGISTER_OPTIONAL_FN(uldap_ssl_supported);
APR_REGISTER_OPTIONAL_FN(uldap_cache_check_subgroups);
ap_hook_post_config(util_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(util_ldap_child_init, NULL, NULL, APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA ldap_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create dir config */
NULL, /* merge dir config */
util_ldap_create_config, /* create server config */
util_ldap_merge_config, /* merge server config */
util_ldap_cmds, /* command table */
util_ldap_register_hooks, /* set up request processing hooks */
};