From f4e5632d6075f79c3a5396ddea5873b522af18f0 Mon Sep 17 00:00:00 2001 From: "Paul J. Reder" Date: Wed, 23 Jan 2008 18:14:41 +0000 Subject: [PATCH] This adds Apache support (taking advantage of the new APR capability) for ldap rebind callback while chasing referrals. This allows direct searches on LDAP servers (in particular MS Active Directory 2003+) using referrals without the use of the global catalog. This addresses PRs 26538, 40268, and 42557 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@614605 13f79535-47bb-0310-9956-ffa450edef68 --- include/util_ldap.h | 8 +++ modules/ldap/util_ldap.c | 111 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 3 deletions(-) diff --git a/include/util_ldap.h b/include/util_ldap.h index ede0c82f94..1b48ca55fb 100644 --- a/include/util_ldap.h +++ b/include/util_ldap.h @@ -29,6 +29,7 @@ #include "apr_tables.h" #include "apr_time.h" #include "apr_ldap.h" +#include "apr_ldap_rebind.h" #if APR_HAS_MICROSOFT_LDAPSDK #define AP_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN \ @@ -112,12 +113,19 @@ typedef struct util_ldap_connection_t { apr_array_header_t *client_certs; /* Client certificates on this connection */ const char *reason; /* Reason for an error failure */ + int ChaseReferrals; /* [on|off] (on=1, off=0, default = On)*/ + int ReferralHopLimit; /* # of referral hops to follow (default = 5) */ struct util_ldap_connection_t *next; struct util_ldap_state_t *st; /* The LDAP vhost config this connection belongs to */ int keep; /* Will this connection be kept when it's unlocked */ } util_ldap_connection_t; +typedef struct util_ldap_config_t { + int ChaseReferrals; + int ReferralHopLimit; +} util_ldap_config_t; + /* LDAP cache state information */ typedef struct util_ldap_state_t { apr_pool_t *pool; /* pool from which this state is allocated */ diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c index 04cc1e4db6..234a133a25 100644 --- a/modules/ldap/util_ldap.c +++ b/modules/ldap/util_ldap.c @@ -187,6 +187,8 @@ static apr_status_t uldap_connection_cleanup(void *param) util_ldap_connection_t *ldc = param; if (ldc) { + /* Release the rebind info for this connection. No more referral rebinds required. */ + apr_ldap_rebind_remove(ldc->ldap); /* unbind and disconnect from the LDAP server */ uldap_connection_unbind(ldc); @@ -290,7 +292,6 @@ static int uldap_connection_init(request_rec *r, APR_LDAP_NONE, &(result)); - if (result != NULL && result->rc) { ldc->reason = result->reason; } @@ -307,6 +308,16 @@ static int uldap_connection_init(request_rec *r, return(result->rc); } + /* Now that we have an ldap struct, add it to the referral list for rebinds. */ + rc = apr_ldap_rebind_add(ldc->pool, ldc->ldap, ldc->binddn, ldc->bindpw); + if (rc != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "LDAP: Unable to add rebind cross reference entry. Out of memory?"); + uldap_connection_unbind(ldc); + ldc->reason = "LDAP: Unable to add rebind cross reference entry."; + return(rc); + } + /* always default to LDAP V3 */ ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); @@ -336,6 +347,44 @@ static int uldap_connection_init(request_rec *r, ldap_option = ldc->deref; ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option); + /* Set options for rebind and referrals. */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "LDAP: Setting referrals to %s.", + (ldc->ChaseReferrals ? "On" : "Off")); + apr_ldap_set_option(r->pool, ldc->ldap, + APR_LDAP_OPT_REFERRALS, + (void *)(ldc->ChaseReferrals ? LDAP_OPT_ON : LDAP_OPT_OFF), + &(result)); + if (result->rc != LDAP_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Unable to set LDAP_OPT_REFERRALS option to %s: %d.", + (ldc->ChaseReferrals ? "On" : "Off"), + result->rc); + result->reason = "Unable to set LDAP_OPT_REFERRALS."; + uldap_connection_unbind(ldc); + return(result->rc); + } + + if (ldc->ChaseReferrals) { + /* Referral hop limit - only if referrals are enabled */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Setting referral hop limit to %d.", + ldc->ReferralHopLimit); + apr_ldap_set_option(r->pool, ldc->ldap, + APR_LDAP_OPT_REFHOPLIMIT, + (void *)&ldc->ReferralHopLimit, + &(result)); + if (result->rc != LDAP_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Unable to set LDAP_OPT_REFHOPLIMIT option to %d: %d.", + ldc->ReferralHopLimit, + result->rc); + result->reason = "Unable to set LDAP_OPT_REFHOPLIMIT."; + uldap_connection_unbind(ldc); + return(result->rc); + } + } + /*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */ #ifdef APR_LDAP_OPT_VERIFY_CERT apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_VERIFY_CERT, @@ -517,7 +566,8 @@ static util_ldap_connection_t * util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module); - + util_ldap_config_t *dc = + (util_ldap_config_t *) ap_get_module_config(r->per_dir_config, &ldap_module); #if APR_HAS_THREADS /* mutex lock this function */ @@ -623,6 +673,8 @@ static util_ldap_connection_t * l->deref = deref; util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); + l->ChaseReferrals = dc->ChaseReferrals; + l->ReferralHopLimit = dc->ReferralHopLimit; /* The security mode after parsing the URL will always be either * APR_LDAP_NONE (ldap://) or APR_LDAP_SSL (ldaps://). @@ -2288,6 +2340,47 @@ static const char *util_ldap_set_connection_timeout(cmd_parms *cmd, } +static const char *util_ldap_set_chase_referrals(cmd_parms *cmd, + void *config, + int mode) +{ + util_ldap_config_t *dc = config; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + "LDAP: Setting refferal chasing %s", + mode?"ON":"OFF"); + + dc->ChaseReferrals = mode; + + return(NULL); +} + +static const char *util_ldap_set_referral_hop_limit(cmd_parms *cmd, + void *config, + const char *hop_limit) +{ + util_ldap_config_t *dc = config; + + dc->ReferralHopLimit = atol(hop_limit); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + "LDAP: Limit chased referrals to maximum of %d hops.", + dc->ReferralHopLimit); + + return NULL; +} + +static void *util_ldap_create_dir_config(apr_pool_t *p, char *d) { + util_ldap_config_t *dc = + (util_ldap_config_t *) apr_pcalloc(p,sizeof(util_ldap_config_t)); + + dc->ChaseReferrals = 1; /* default is to turn referral chasing on. */ + dc->ReferralHopLimit = 5; /* default is to chase a max of 5 hops. */ + + return dc; +} + + static void *util_ldap_create_config(apr_pool_t *p, server_rec *s) { util_ldap_state_t *st = @@ -2316,6 +2409,9 @@ static void *util_ldap_create_config(apr_pool_t *p, server_rec *s) st->connectionTimeout = 10; st->verify_svr_cert = 1; + /* Initialize the rebind callback's cross reference list. */ + apr_ldap_rebind_init (p); + return st; } @@ -2614,6 +2710,15 @@ static const command_rec util_ldap_cmds[] = { "Specify the LDAP socket connection timeout in seconds " "(default: 10)"), + AP_INIT_FLAG("LDAPReferrals", util_ldap_set_chase_referrals, + NULL, OR_AUTHCFG, + "Choose whether referrals are chased ['ON'|'OFF']. Default 'ON'"), + + AP_INIT_TAKE1("LDAPReferralHopLimit", util_ldap_set_referral_hop_limit, + NULL, OR_AUTHCFG, + "Limit the number of referral hops that LDAP can follow. " + "(Integer value, default=5)"), + {NULL} }; @@ -2638,7 +2743,7 @@ static void util_ldap_register_hooks(apr_pool_t *p) module AP_MODULE_DECLARE_DATA ldap_module = { STANDARD20_MODULE_STUFF, - NULL, /* create dir config */ + util_ldap_create_dir_config, /* create dir config */ NULL, /* merge dir config */ util_ldap_create_config, /* create server config */ util_ldap_merge_config, /* merge server config */ -- 2.40.0