util_ldap.c revision 7af19efc4667363f74d332a8d010b49e88d56fd5
2d2eda71267231c2526be701fe655db125852c1ffielding/* Licensed to the Apache Software Foundation (ASF) under one or more
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * contributor license agreements. See the NOTICE file distributed with
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * this work for additional information regarding copyright ownership.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * The ASF licenses this file to You under the Apache License, Version 2.0
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * (the "License"); you may not use this file except in compliance with
2d2eda71267231c2526be701fe655db125852c1ffielding * the License. You may obtain a copy of the License at
2d2eda71267231c2526be701fe655db125852c1ffielding * Unless required by applicable law or agreed to in writing, software
2d2eda71267231c2526be701fe655db125852c1ffielding * distributed under the License is distributed on an "AS IS" BASIS,
2d2eda71267231c2526be701fe655db125852c1ffielding * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2d2eda71267231c2526be701fe655db125852c1ffielding * See the License for the specific language governing permissions and
2d2eda71267231c2526be701fe655db125852c1ffielding * limitations under the License.
2d2eda71267231c2526be701fe655db125852c1ffielding * util_ldap.c: LDAP things
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Original code from auth_ldap module for Apache v1.3:
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Copyright 1998, 1999 Enbridge Pipelines Inc.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Copyright 1999-2001 Dave Carrigan
f062ed7bd262a37a909dd77ce5fc23b446818823fielding#error mod_ldap requires APR-util to have LDAP support built in
f062ed7bd262a37a909dd77ce5fc23b446818823fielding/* Default define for ldap functions that need a SIZELIMIT but
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * do not have the define
2d2eda71267231c2526be701fe655db125852c1ffielding * XXX This should be removed once a supporting #define is
2d2eda71267231c2526be701fe655db125852c1ffielding * released through APR-Util.
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic const char *ldap_cache_mutex_type = "ldap-cache";
2d2eda71267231c2526be701fe655db125852c1ffielding#define LDAP_CACHE_LOCK() do { \
61fd0cab072a05b855cbef9c585702401ac5ae29rbb} while (0)
2d2eda71267231c2526be701fe655db125852c1ffielding#define LDAP_CACHE_UNLOCK() do { \
2d2eda71267231c2526be701fe655db125852c1ffielding apr_global_mutex_unlock(st->util_ldap_cache_lock); \
61fd0cab072a05b855cbef9c585702401ac5ae29rbbstatic apr_status_t util_ldap_connection_remove (void *param);
61fd0cab072a05b855cbef9c585702401ac5ae29rbbstatic void util_ldap_strdup (char **str, const char *newstr)
2d2eda71267231c2526be701fe655db125852c1ffielding * Status Handler
2d2eda71267231c2526be701fe655db125852c1ffielding * --------------
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * This handler generates a status page about the current performance of
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * the LDAP cache. It is enabled as follows:
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * <Location /ldap-status>
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * SetHandler ldap-status
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * </Location>
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ap_set_content_type(r, "text/html; charset=ISO-8859-1");
2d2eda71267231c2526be701fe655db125852c1ffielding "<html><head><title>LDAP Cache Information</title></head>\n", r);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information"
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "</h1>\n", r);
4c3d3eaf42bd7757edb3721cb586f2ef2bcbf671stoddard/* ------------------------------------------------------------------ */
2d2eda71267231c2526be701fe655db125852c1ffielding * Closes an LDAP connection by unlocking it. The next time
2d2eda71267231c2526be701fe655db125852c1ffielding * uldap_connection_find() is called this connection will be
2d2eda71267231c2526be701fe655db125852c1ffielding * available for reuse.
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic void uldap_connection_close(util_ldap_connection_t *ldc)
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * QUESTION:
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * Is it safe leaving bound connections floating around between the
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * different modules? Keeping the user bound is a performance boost,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * but it is also a potential security problem - maybe.
2d2eda71267231c2526be701fe655db125852c1ffielding * For now we unbind the user when we finish with a connection, but
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * we don't have to...
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* mark our connection as available for reuse */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * Destroys an LDAP connection by unbinding and closing the connection to
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * the LDAP server. It is used to bring the connection back to a known
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * state after an error.
2d2eda71267231c2526be701fe655db125852c1ffielding * Clean up an LDAP connection by unbinding and unlocking the connection.
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * This cleanup does not remove the util_ldap_connection_t from the
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * per-virtualhost list of connections, does not remove the storage
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * for the util_ldap_connection_t or its data, and is NOT run automatically.
61fd0cab072a05b855cbef9c585702401ac5ae29rbbstatic apr_status_t uldap_connection_cleanup(void *param)
2d2eda71267231c2526be701fe655db125852c1ffielding /* Release the rebind info for this connection. No more referral rebinds required. */
2d2eda71267231c2526be701fe655db125852c1ffielding /* unbind and disconnect from the LDAP server */
2d2eda71267231c2526be701fe655db125852c1ffielding /* free the username and password */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* ldc->reason is allocated from r->pool */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* unlock this entry */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * util_ldap_connection_remove frees all storage associated with the LDAP
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * connection and removes it completely from the per-virtualhost list of
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * connections
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * The caller should hold the lock for this connection
61fd0cab072a05b855cbef9c585702401ac5ae29rbbstatic apr_status_t util_ldap_connection_remove (void *param) {
61fd0cab072a05b855cbef9c585702401ac5ae29rbb util_ldap_connection_t *ldc = param, *l = NULL, *prev = NULL;
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Remove ldc from the list */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (l == ldc) {
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Some unfortunate duplication between this method
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * and uldap_connection_cleanup()
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Destory the pool associated with this connection */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb struct timeval connectionTimeout = {10,0}; /* 10 second connection timeout */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Since the host will include a port if the default port is not used,
2d2eda71267231c2526be701fe655db125852c1ffielding * always specify the default ports for the port parameter. This will
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * allow a host string that contains multiple hosts the ability to mix
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * some hosts with ports and some without. All hosts which do not
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * specify a port will use the default port.
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* something really bad happened */
2d2eda71267231c2526be701fe655db125852c1ffielding /* Now that we have an ldap struct, add it to the referral list for rebinds. */
2d2eda71267231c2526be701fe655db125852c1ffielding rc = apr_ldap_rebind_add(ldc->pool, ldc->ldap, ldc->binddn, ldc->bindpw);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "LDAP: Unable to add rebind cross reference entry. Out of memory?");
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ldc->reason = "LDAP: Unable to add rebind cross reference entry.";
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* always default to LDAP V3 */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* set client certificates */
2d2eda71267231c2526be701fe655db125852c1ffielding apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* switch on SSL/TLS */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Set the alias dereferencing option */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Set options for rebind and referrals. */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "LDAP: Setting referrals to %s.",
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ? "On" : "Off"));
61fd0cab072a05b855cbef9c585702401ac5ae29rbb (void *)((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ?
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
2d2eda71267231c2526be701fe655db125852c1ffielding "Unable to set LDAP_OPT_REFERRALS option to %s: %d.",
2d2eda71267231c2526be701fe655db125852c1ffielding ((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ? "On" : "Off"),
61fd0cab072a05b855cbef9c585702401ac5ae29rbb if ((ldc->ReferralHopLimit != AP_LDAP_HOPLIMIT_UNSET) && ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) {
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* Referral hop limit - only if referrals are enabled and a hop limit is explicitly requested */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "Setting referral hop limit to %d.",
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "Unable to set LDAP_OPT_REFHOPLIMIT option to %d: %d.",
61fd0cab072a05b855cbef9c585702401ac5ae29rbb/*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_VERIFY_CERT,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* This is not a per-connection setting so just pass NULL for the
61fd0cab072a05b855cbef9c585702401ac5ae29rbb Ldap connection handle */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
2d2eda71267231c2526be701fe655db125852c1ffielding rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb "LDAP: Could not set the connection timeout");
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * LDAP_OPT_TIMEOUT is not portable, but it influences all synchronous ldap
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * function calls and not just ldap_search_ext_s(), which accepts a timeout
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * parameter.
2d2eda71267231c2526be701fe655db125852c1ffielding * XXX: It would be possible to simulate LDAP_OPT_TIMEOUT by replacing all
2d2eda71267231c2526be701fe655db125852c1ffielding * XXX: synchronous ldap function calls with asynchronous calls and using
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * XXX: ldap_result() with a timeout.
61fd0cab072a05b855cbef9c585702401ac5ae29rbb rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_TIMEOUT,
2d2eda71267231c2526be701fe655db125852c1ffielding "LDAP: Could not set LDAP_OPT_TIMEOUT");
344f3bc38dfccf6261d5bb8d689794cde113b3d6coar * Replacement function for ldap_simple_bind_s() with a timeout.
344f3bc38dfccf6261d5bb8d689794cde113b3d6coar * To do this in a portable way, we have to use ldap_simple_bind() and
fd0edaa8e3d4dd67d0604ccef2e96b071db96643fielding * ldap_result().
fd0edaa8e3d4dd67d0604ccef2e96b071db96643fielding * Returns LDAP_SUCCESS on success; and an error code on failure
fd0edaa8e3d4dd67d0604ccef2e96b071db96643fieldingstatic int uldap_simple_bind(util_ldap_connection_t *ldc, char *binddn,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb int msgid = ldap_simple_bind(ldc->ldap, binddn, bindpw);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* -1 is LDAP_SERVER_DOWN in openldap, use something else */
61fd0cab072a05b855cbef9c585702401ac5ae29rbb rc = ldap_result(ldc->ldap, msgid, 0, timeout, &result);
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ldc->reason = "LDAP: ldap_simple_bind() result retrieval failed";
61fd0cab072a05b855cbef9c585702401ac5ae29rbb /* -1 is LDAP_SERVER_DOWN in openldap, use something else */
36bb027ff0af9d285d15e9fac4fc956db6c33e94wrowe else if (rc == 0) {
61fd0cab072a05b855cbef9c585702401ac5ae29rbb } else if (ldap_parse_result(ldc->ldap, result, &rc, NULL, NULL, NULL,
61fd0cab072a05b855cbef9c585702401ac5ae29rbb ldc->reason = "LDAP: ldap_simple_bind() parse result failed";
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * Connect to the LDAP server and binds. Does not connect if already
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
61fd0cab072a05b855cbef9c585702401ac5ae29rbb * Returns LDAP_SUCCESS on success; and an error code on failure
if (!ldc) {
return LDAP_SUCCESS;
return rc;
&ldap_module);
return(rc);
static util_ldap_connection_t *
&ldap_module);
#if APR_HAS_THREADS
#if APR_HAS_THREADS
#if APR_HAS_THREADS
#if APR_HAS_THREADS
l->bound = 0;
#if APR_HAS_THREADS
#if APR_HAS_THREADS
return NULL;
#if APR_HAS_THREADS
l->bound = 0;
p->next = l;
#if APR_HAS_THREADS
int result = 0;
int failures = 0;
char *searchdn;
&ldap_module);
if (!compare_dn_on_server) {
return LDAP_COMPARE_FALSE;
return LDAP_COMPARE_TRUE;
if (curl) {
return LDAP_COMPARE_TRUE;
return result;
return result;
goto start_over;
goto start_over;
return result;
if (curl) {
return result;
int result = 0;
int failures = 0;
&ldap_module);
if (curl) {
return result;
return result;
return result;
(char *)dn,
(char *)attrib,
(char *)value);
goto start_over;
goto start_over;
if (curl) {
void *junk;
return LDAP_COMPARE_TRUE;
return LDAP_COMPARE_FALSE;
return LDAP_NO_SUCH_ATTRIBUTE;
return result;
const char *url,
const char *dn,
char **subgroupAttrs,
int failures = 0;
if (!subgroupAttrs) {
return res;
return res;
return res;
goto start_over;
goto start_over;
return res;
if (subgroupAttrs) {
char **values;
int val_index = 0;
if (values) {
val_index = 0;
tmp_sgcIndex = 0;
tmp_sgcIndex++;
val_index++;
indx++;
int sgindex;
char **group;
return res;
char **subgroupAttrs,
int cur_subgroup_depth,
int max_subgroup_depth)
&ldap_module);
return LDAP_COMPARE_FALSE;
return result;
sizeof(util_compare_subgroup_t));
if (!tmp_local_sgl) {
dn);
dn);
if (!tmp_local_sgl) {
if (sgl_copy) {
if (!tmp_local_sgl) {
return result;
sgindex++;
return result;
const char ***retvals)
int numvals = 0;
int result = 0;
char *dn;
int count;
int failures = 0;
&ldap_module);
&curnode);
if (curl) {
if (attrs) {
return LDAP_SUCCESS;
return result;
return result;
goto start_over;
return result;
if (count == 0 )
return LDAP_NO_SUCH_OBJECT;
return LDAP_INVALID_CREDENTIALS;
goto start_over;
return result;
if (attrs) {
while (attrs[k++]);
numvals = k;
while (attrs[i]) {
char **values;
if (curl) {
return LDAP_SUCCESS;
int numvals = 0;
int result = 0;
char *dn;
int count;
int failures = 0;
&ldap_module);
&curnode);
if (curl) {
if (attrs) {
return LDAP_SUCCESS;
return result;
return result;
goto start_over;
return result;
if (count == 0 )
return LDAP_NO_SUCH_OBJECT;
if (attrs) {
while (attrs[k++]);
numvals = k;
while (attrs[i]) {
char **values;
if (curl) {
return LDAP_SUCCESS;
const char *bytes)
&ldap_module);
return err;
return NULL;
const char *file)
&ldap_module);
return err;
if (file) {
return NULL;
const char *ttl)
&ldap_module);
return err;
return NULL;
const char *size)
&ldap_module);
return err;
return NULL;
const char *ttl)
&ldap_module);
return err;
return NULL;
const char *size)
&ldap_module);
return err;
return NULL;
return APR_LDAP_CA_TYPE_DER;
return APR_LDAP_CA_TYPE_BASE64;
return APR_LDAP_CA_TYPE_CERT7_DB;
return APR_LDAP_CA_TYPE_SECMOD;
return APR_LDAP_CERT_TYPE_DER;
return APR_LDAP_CERT_TYPE_BASE64;
return APR_LDAP_CERT_TYPE_PFX;
return APR_LDAP_CERT_TYPE_KEY3_DB;
return APR_LDAP_CERT_TYPE_NICKNAME;
return APR_LDAP_KEY_TYPE_DER;
return APR_LDAP_KEY_TYPE_BASE64;
return APR_LDAP_KEY_TYPE_PFX;
return APR_LDAP_CA_TYPE_UNKNOWN;
void *dummy,
const char *type,
const char *file,
const char *password)
&ldap_module);
int cert_type = 0;
return err;
if (type) {
!= APR_SUCCESS))
return(NULL);
void *config,
const char *type,
const char *file,
const char *password)
int cert_type = 0;
if (type) {
type);
!= APR_SUCCESS))
return(NULL);
const char *mode)
&ldap_module);
mode);
return(NULL);
void *dummy,
int mode)
&ldap_module);
return err;
return(NULL);
void *dummy,
const char *ttl)
#ifdef LDAP_OPT_NETWORK_TIMEOUT
&ldap_module);
return err;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
return NULL;
void *config,
int mode)
return(NULL);
void *config,
const char *arg) {
&ldap_module);
return err;
#ifndef AP_LDAP_OPT_DEBUG
return NULL;
void *config,
const char *hop_limit)
return "LDAPReferralHopLimit must be greater than zero (Use 'LDAPReferrals Off' to disable referral chasing)";
return NULL;
return dc;
void *dummy,
const char *val)
long timeout;
char *endptr;
&ldap_module);
return err;
if (timeout < 0) {
if (timeout) {
timeout);
#ifndef LDAP_OPT_TIMEOUT
return NULL;
#if APR_HAS_THREADS
return st;
void *overridesv)
#if APR_HAS_THREADS
return st;
return APR_SUCCESS;
APR_LOCK_DEFAULT, 0);
return result;
return OK;
&ldap_module);
int rc;
NULL);
return OK;
return DONE;
return result;
while (s_vhost) {
&ldap_module);
NULL,
&(result_err));
apr_ldap_rebind_init (p);
#ifdef AP_LDAP_OPT_DEBUG
return(OK);
&ldap_module);
{NULL}