Mailing List Archive

POC: updated ldapi:// support for mod_ldap
Hi all,

This is a patch for httpd that adds support for ldapi:// URLs to mod_ldap and friends.

It depends on a patch for apr-util posted to the dev@apr list.

Regards,
Graham



Index: include/util_ldap.h
===================================================================
--- include/util_ldap.h (revision 1909117)
+++ include/util_ldap.h (working copy)
@@ -45,6 +45,10 @@
/* this whole thing disappears if LDAP is not enabled */
#if APR_HAS_LDAP

+#ifndef APR_HAS_LDAP_INITIALIZE
+#define APR_HAS_LDAP_INITIALIZE 0
+#endif
+
#if defined(LDAP_UNAVAILABLE) || APR_HAS_MICROSOFT_LDAPSDK
#define AP_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN \
||(s) == LDAP_UNAVAILABLE)
@@ -126,8 +130,8 @@
const char *reason; /* Reason for an error failure */

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 */
+ 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 */

int ChaseReferrals; /* [on|off] (default = AP_LDAP_CHASEREFERRALS_ON)*/
int ReferralHopLimit; /* # of referral hops to follow (default = AP_LDAP_DEFAULT_HOPLIMIT) */
@@ -136,6 +140,12 @@
int must_rebind; /* The connection was last bound with other then binddn/bindpw */
request_rec *r; /* request_rec used to find this util_ldap_connection_t */
apr_time_t last_backend_conn; /* the approximate time of the last backend LDAP request */
+
+#if APR_HAS_LDAP_INITIALIZE
+ apr_ldap_err_t result; /* result of prior operations on this connection */
+ const char *url; /* URL of the LDAP server (or space separated list) */
+ apr_ldap_t *ld;
+#endif
} util_ldap_connection_t;

typedef struct util_ldap_config_t {
@@ -241,6 +251,7 @@
* @fn util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
* const char *binddn, const char *bindpw, deref_options deref,
* int netscapessl, int starttls)
+ * @deprecated Replaced by uldap_connection_find_ex()
*/
APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find,(request_rec *r, const char *host, int port,
const char *binddn, const char *bindpw, deref_options deref,
@@ -247,6 +258,26 @@
int secure));

/**
+ * Find a connection in a list of connections
+ * @param r The request record
+ * @param url The URL to connect to (multiple URLs space separated)
+ * @param binddn The DN to bind with
+ * @param bindpw The password to bind with
+ * @param deref The dereferencing behavior
+ * @param secure use SSL on the connection
+ * @tip Once a connection is found and returned, a lock will be acquired to
+ * lock that particular connection, so that another thread does not try and
+ * use this connection while it is busy. Once you are finished with a connection,
+ * apr_ldap_connection_close() must be called to release this connection.
+ * @fn util_ldap_connection_t *util_ldap_connection_find_ex(request_rec *r, const char *url,
+ * const char *binddn, const char *bindpw, deref_options deref,
+ * int netscapessl, int starttls)
+ */
+APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find_ex,(request_rec *r, const char *url,
+ const char *binddn, const char *bindpw, deref_options deref,
+ int secure));
+
+/**
* Compare two DNs for sameness
* @param r The request record
* @param ldc The LDAP connection being used.
Index: modules/aaa/mod_authnz_ldap.c
===================================================================
--- modules/aaa/mod_authnz_ldap.c (revision 1909117)
+++ modules/aaa/mod_authnz_ldap.c (working copy)
@@ -104,7 +104,7 @@
module AP_MODULE_DECLARE_DATA authnz_ldap_module;

static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
-static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
+static APR_OPTIONAL_FN_TYPE(uldap_connection_find_ex) *util_ldap_connection_find_ex;
static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
static APR_OPTIONAL_FN_TYPE(uldap_cache_check_subgroups) *util_ldap_cache_check_subgroups;
@@ -453,9 +453,7 @@
bindpw = req->password;
}

- return util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ return util_ldap_connection_find_ex(r, sec->url, binddn, bindpw, sec->deref, sec->secure);
}
/*
* Authentication Phase
@@ -527,7 +525,7 @@
}

/* There is a good AuthLDAPURL, right? */
- if (sec->host) {
+ if (sec->url) {
const char *binddn = sec->binddn;
const char *bindpw = sec->bindpw;
if (sec->initial_bind_as_user) {
@@ -535,13 +533,13 @@
binddn = ldap_determine_binddn(r, user);
}

- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ ldc = util_ldap_connection_find_ex(r, sec->url,
+ binddn, bindpw,
+ sec->deref, sec->secure);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01690)
- "auth_ldap authenticate: no sec->host - weird...?");
+ "auth_ldap authenticate: no sec->url - weird...?");
return AUTH_GENERAL_ERROR;
}

@@ -1436,13 +1434,14 @@
* host and port.
*/
static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
- void *config,
- const char *url,
- const char *mode)
+ void *config,
+ const char *url,
+ const char *mode)
{
- int rc;
+ int rc, i;
apr_ldap_url_desc_t *urld;
apr_ldap_err_t *result;
+ const char *end = url;

authn_ldap_config_t *sec = config;

@@ -1450,8 +1449,18 @@
if (rc != APR_SUCCESS) {
return result->reason;
}
- sec->url = apr_pstrdup(cmd->pool, url);

+ /* isolate the host/port part of the URL */
+ for (i = 0; end && i < 3; i++) {
+ end = strchr((char *)end + 1, '/');
+ }
+ if (end) {
+ sec->url = apr_pstrndup(cmd->pool, url, end - url);
+ }
+ else {
+ sec->url = apr_pstrdup(cmd->pool, url);
+ }
+
/* Set all the values, or at least some sane defaults */
if (sec->host) {
sec->host = apr_pstrcat(cmd->pool, urld->lud_host, " ", sec->host, NULL);
@@ -1528,9 +1537,10 @@
sec->have_ldap_url = 1;

ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, cmd->server,
- "auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, "
+ "auth_ldap url parse: `%s', Url: %s, Host: %s, Port: %d, DN: %s, "
"attrib: %s, scope: %s, filter: %s, connection mode: %s",
url,
+ sec->url,
urld->lud_host,
urld->lud_port,
urld->lud_dn,
@@ -1921,13 +1931,13 @@

static void ImportULDAPOptFn(void)
{
- util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
- util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
- util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
- util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
- util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
- util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
- util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
+ util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
+ util_ldap_connection_find_ex = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find_ex);
+ util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
+ util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
+ util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
+ util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
+ util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
util_ldap_cache_check_subgroups = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_check_subgroups);
}

Index: modules/ldap/util_ldap.c
===================================================================
--- modules/ldap/util_ldap.c (revision 1909117)
+++ modules/ldap/util_ldap.c (working copy)
@@ -285,6 +285,25 @@
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
&ldap_module);
int have_client_certs = !apr_is_empty_array(ldc->client_certs);
+
+#if APR_HAS_LDAP_INITIALIZE
+
+ apr_ldap_initialize(ldc->pool, ldc->url, &(ldc->ld), &(ldc->result));
+
+ if (ldc->ld) {
+ apr_ldap_opt_t opt;
+
+ apr_ldap_get_option_ex(ldc->ld, APR_LDAP_OPT_HANDLE, &opt, &(ldc->result));
+
+ ldc->ldap = opt.handle;
+ }
+
+ result = &ldc->result;
+
+#else
+
+ /* remove after apr-util v1.7 */
+
#if !APR_HAS_SOLARIS_LDAPSDK
/*
* Normally we enable SSL/TLS with apr_ldap_set_option(), except
@@ -322,7 +341,9 @@
return(APR_EGENERAL);
}

- if (result->rc) {
+#endif
+
+ if (result && result->rc) {
ldc->reason = result->reason;
ldc->bound = 0;
return result->rc;
@@ -697,19 +718,12 @@
}


-/*
- * Find an existing ldap connection struct that matches the
- * provided ldap connection parameters.
- *
- * If not found in the cache, a new ldc structure will be allocated
- * from st->pool and returned to the caller. If found in the cache,
- * a pointer to the existing ldc structure will be returned.
- */
static util_ldap_connection_t *
- uldap_connection_find(request_rec *r,
- const char *host, int port,
- const char *binddn, const char *bindpw,
- deref_options deref, int secure)
+ connection_find(request_rec *r,
+ const char *url,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
{
struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
int secureflag = secure;
@@ -737,12 +751,16 @@
#if APR_HAS_THREADS
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
#endif
- if ( (l->port == port) && (strcmp(l->host, host) == 0)
- && ((!l->binddn && !binddn) || (l->binddn && binddn
- && !strcmp(l->binddn, binddn)))
- && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw
- && !strcmp(l->bindpw, bindpw)))
- && (l->deref == deref) && (l->secure == secureflag)
+ if ( (l->port == port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(l->host, host)))
+ && ((!binddn && !l->binddn) || (binddn && l->binddn
+ && !strcmp(binddn, l->binddn)))
+ && ((!bindpw && !l->bindpw) || (bindpw && l->bindpw
+ && !strcmp(bindpw, l->bindpw)))
+ && (deref == l->deref) && (secureflag == l->secure)
&& !compare_client_certs(dc->client_certs, l->client_certs))
{
if (st->connection_pool_ttl > 0) {
@@ -779,9 +797,13 @@
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {

#endif
- if ((l->port == port) && (strcmp(l->host, host) == 0) &&
- (l->deref == deref) && (l->secure == secureflag) &&
- !compare_client_certs(dc->client_certs, l->client_certs))
+ if ((port == l->port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(host, l->host)))
+ && (deref == l->deref) && (secureflag == l->secure)
+ && !compare_client_certs(dc->client_certs, l->client_certs))
{
if (st->connection_pool_ttl > 0) {
if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) {
@@ -849,6 +871,7 @@
apr_thread_mutex_lock(l->lock);
#endif
l->bound = 0;
+ l->url = apr_pstrdup(l->pool, url);
l->host = apr_pstrdup(l->pool, host);
l->port = port;
l->deref = deref;
@@ -897,6 +920,42 @@
return l;
}

+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ *
+ * Deprecated: replaced by uldap_connection_find_ex()
+ */
+static util_ldap_connection_t *
+ uldap_connection_find(request_rec *r,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, NULL, host, port, binddn, bindpw, deref, secure);
+}
+
+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ */
+static util_ldap_connection_t *
+ uldap_connection_find_ex(request_rec *r,
+ const char *url,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, url, NULL, 0, binddn, bindpw, deref, secure);
+}
+
/* ------------------------------------------------------------------ */

/*
@@ -3216,6 +3275,7 @@
APR_REGISTER_OPTIONAL_FN(uldap_connection_close);
APR_REGISTER_OPTIONAL_FN(uldap_connection_unbind);
APR_REGISTER_OPTIONAL_FN(uldap_connection_find);
+ APR_REGISTER_OPTIONAL_FN(uldap_connection_find_ex);
APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn);
APR_REGISTER_OPTIONAL_FN(uldap_cache_compare);
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid);
Re: POC: updated ldapi:// support for mod_ldap [ In reply to ]
On 18 Apr 2023, at 13:47, Graham Leggett <minfrin@sharp.fm> wrote:

> This is a patch for httpd that adds support for ldapi:// URLs to mod_ldap and friends.
>
> It depends on a patch for apr-util posted to the dev@apr list.

This patch adds limited support for SASL binds. Depends on updated POC patch at the dev@apr list.

Right now only EXTERNAL is supported, as the supporting structure for passing other SASL parameters isn't yet there. Further work to follow.

You can now do this:

<If "%{SSL_CLIENT_VERIFY} == 'SUCCESS' || %{SSL_CLIENT_VERIFY} == 'GENEROUS'">

SSLUserName SSL_CLIENT_CERT_RFC4523_CEA

LDAPBindMechanism EXTERNAL
AuthLDAPURL ldapi://%2frun%2fslapd-seawitch.socket/dc=xxx,dc=xx,dc=xx?uid,inetSubscriberAccountId?sub?inetSubscriberAccountId=*
require ldap-group cn=https://xxx.xxx.xx.xx/xxx,ou=xxx,ou=xxx,dc=xxx,dc=xx,dc=xx

</If>

Regards,
Graham




Index: include/util_ldap.h
===================================================================
--- include/util_ldap.h (revision 1909117)
+++ include/util_ldap.h (working copy)
@@ -45,6 +45,10 @@
/* this whole thing disappears if LDAP is not enabled */
#if APR_HAS_LDAP

+#ifndef APR_HAS_LDAP_INITIALIZE
+#define APR_HAS_LDAP_INITIALIZE 0
+#endif
+
#if defined(LDAP_UNAVAILABLE) || APR_HAS_MICROSOFT_LDAPSDK
#define AP_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN \
||(s) == LDAP_UNAVAILABLE)
@@ -126,8 +130,8 @@
const char *reason; /* Reason for an error failure */

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 */
+ 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 */

int ChaseReferrals; /* [on|off] (default = AP_LDAP_CHASEREFERRALS_ON)*/
int ReferralHopLimit; /* # of referral hops to follow (default = AP_LDAP_DEFAULT_HOPLIMIT) */
@@ -136,6 +140,14 @@
int must_rebind; /* The connection was last bound with other then binddn/bindpw */
request_rec *r; /* request_rec used to find this util_ldap_connection_t */
apr_time_t last_backend_conn; /* the approximate time of the last backend LDAP request */
+
+#if APR_HAS_LDAP_INITIALIZE
+ apr_pool_t *init_pool; /* Pool from which this connection is initialised */
+ apu_err_t result; /* result of prior operations on this connection */
+ const char *url; /* URL of the LDAP server (or space separated list) */
+ apr_ldap_t *ld;
+ const char *mech; /* SASL bind mechanism */
+#endif
} util_ldap_connection_t;

typedef struct util_ldap_config_t {
@@ -142,6 +154,13 @@
int ChaseReferrals;
int ReferralHopLimit;
apr_array_header_t *client_certs; /* Client certificates */
+ const char *mech; /* SASL mechanism */
+ unsigned int inherit:1;
+ unsigned int inherit_set:1;
+ unsigned int mech_set:1;
+ unsigned int client_certs_set:1;
+ unsigned int ReferralHopLimit_set:1;
+ unsigned int ChaseReferrals_set:1;
} util_ldap_config_t;

/* LDAP cache state information */
@@ -241,6 +260,7 @@
* @fn util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
* const char *binddn, const char *bindpw, deref_options deref,
* int netscapessl, int starttls)
+ * @deprecated Replaced by uldap_connection_find_ex()
*/
APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find,(request_rec *r, const char *host, int port,
const char *binddn, const char *bindpw, deref_options deref,
@@ -247,6 +267,26 @@
int secure));

/**
+ * Find a connection in a list of connections
+ * @param r The request record
+ * @param url The URL to connect to (multiple URLs space separated)
+ * @param binddn The DN to bind with
+ * @param bindpw The password to bind with
+ * @param deref The dereferencing behavior
+ * @param secure use SSL on the connection
+ * @tip Once a connection is found and returned, a lock will be acquired to
+ * lock that particular connection, so that another thread does not try and
+ * use this connection while it is busy. Once you are finished with a connection,
+ * apr_ldap_connection_close() must be called to release this connection.
+ * @fn util_ldap_connection_t *util_ldap_connection_find_ex(request_rec *r, const char *url,
+ * const char *binddn, const char *bindpw, deref_options deref,
+ * int netscapessl, int starttls)
+ */
+APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find_ex,(request_rec *r, const char *url,
+ const char *binddn, const char *bindpw, deref_options deref,
+ int secure));
+
+/**
* Compare two DNs for sameness
* @param r The request record
* @param ldc The LDAP connection being used.
Index: modules/aaa/mod_authnz_ldap.c
===================================================================
--- modules/aaa/mod_authnz_ldap.c (revision 1909117)
+++ modules/aaa/mod_authnz_ldap.c (working copy)
@@ -104,7 +104,7 @@
module AP_MODULE_DECLARE_DATA authnz_ldap_module;

static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
-static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
+static APR_OPTIONAL_FN_TYPE(uldap_connection_find_ex) *util_ldap_connection_find_ex;
static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
static APR_OPTIONAL_FN_TYPE(uldap_cache_check_subgroups) *util_ldap_cache_check_subgroups;
@@ -453,9 +453,7 @@
bindpw = req->password;
}

- return util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ return util_ldap_connection_find_ex(r, sec->url, binddn, bindpw, sec->deref, sec->secure);
}
/*
* Authentication Phase
@@ -527,7 +525,7 @@
}

/* There is a good AuthLDAPURL, right? */
- if (sec->host) {
+ if (sec->url) {
const char *binddn = sec->binddn;
const char *bindpw = sec->bindpw;
if (sec->initial_bind_as_user) {
@@ -535,13 +533,13 @@
binddn = ldap_determine_binddn(r, user);
}

- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ ldc = util_ldap_connection_find_ex(r, sec->url,
+ binddn, bindpw,
+ sec->deref, sec->secure);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01690)
- "auth_ldap authenticate: no sec->host - weird...?");
+ "auth_ldap authenticate: no sec->url - weird...?");
return AUTH_GENERAL_ERROR;
}

@@ -1436,13 +1434,14 @@
* host and port.
*/
static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
- void *config,
- const char *url,
- const char *mode)
+ void *config,
+ const char *url,
+ const char *mode)
{
- int rc;
+ int rc, i;
apr_ldap_url_desc_t *urld;
apr_ldap_err_t *result;
+ const char *end = url;

authn_ldap_config_t *sec = config;

@@ -1450,8 +1449,18 @@
if (rc != APR_SUCCESS) {
return result->reason;
}
- sec->url = apr_pstrdup(cmd->pool, url);

+ /* isolate the host/port part of the URL */
+ for (i = 0; end && i < 3; i++) {
+ end = strchr((char *)end + 1, '/');
+ }
+ if (end) {
+ sec->url = apr_pstrndup(cmd->pool, url, end - url);
+ }
+ else {
+ sec->url = apr_pstrdup(cmd->pool, url);
+ }
+
/* Set all the values, or at least some sane defaults */
if (sec->host) {
sec->host = apr_pstrcat(cmd->pool, urld->lud_host, " ", sec->host, NULL);
@@ -1528,9 +1537,10 @@
sec->have_ldap_url = 1;

ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, cmd->server,
- "auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, "
+ "auth_ldap url parse: `%s', Url: %s, Host: %s, Port: %d, DN: %s, "
"attrib: %s, scope: %s, filter: %s, connection mode: %s",
url,
+ sec->url,
urld->lud_host,
urld->lud_port,
urld->lud_dn,
@@ -1921,13 +1931,13 @@

static void ImportULDAPOptFn(void)
{
- util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
- util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
- util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
- util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
- util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
- util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
- util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
+ util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
+ util_ldap_connection_find_ex = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find_ex);
+ util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
+ util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
+ util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
+ util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
+ util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
util_ldap_cache_check_subgroups = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_check_subgroups);
}

Index: modules/ldap/util_ldap.c
===================================================================
--- modules/ldap/util_ldap.c (revision 1909117)
+++ modules/ldap/util_ldap.c (working copy)
@@ -199,9 +199,19 @@
if (ldc->r) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc);
}
+#if !APR_HAS_LDAP_INITIALIZE
ldap_unbind_s(ldc->ldap);
+#endif
ldc->ldap = NULL;
}
+
+#if APR_HAS_LDAP_INITIALIZE
+ if (ldc->ld) {
+ apr_pool_clear(ldc->init_pool);
+ ldc->ld = NULL;
+ }
+#endif
+
ldc->bound = 0;

/* forget the rebind info for this conn */
@@ -285,6 +295,27 @@
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
&ldap_module);
int have_client_certs = !apr_is_empty_array(ldc->client_certs);
+
+#if APR_HAS_LDAP_INITIALIZE
+
+ apr_ldap_initialize(ldc->init_pool, ldc->url, &(ldc->ld), &(ldc->result));
+
+ if (ldc->ld) {
+ apr_ldap_opt_t opt;
+
+ apr_ldap_get_option_ex(ldc->ld, APR_LDAP_OPT_HANDLE, &opt, &(ldc->result));
+
+ ldc->ldap = opt.handle;
+ }
+
+ result = (apr_ldap_err_t *)&ldc->result;
+
+#else
+
+ /* remove after apr-util v1.7 */
+
+ apr_ldap_err_t *result = NULL;
+
#if !APR_HAS_SOLARIS_LDAPSDK
/*
* Normally we enable SSL/TLS with apr_ldap_set_option(), except
@@ -322,7 +353,9 @@
return(APR_EGENERAL);
}

- if (result->rc) {
+#endif
+
+ if (result && result->rc) {
ldc->reason = result->reason;
ldc->bound = 0;
return result->rc;
@@ -508,6 +541,7 @@
return LDAP_OTHER;
}

+
/*
* Replacement function for ldap_simple_bind_s() with a timeout.
* To do this in a portable way, we have to use ldap_simple_bind() and
@@ -546,6 +580,15 @@
return rc;
}

+
+#if APR_HAS_LDAP_INITIALIZE
+static apr_status_t bind_interact(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx)
+{
+ return APR_SUCCESS;
+}
+#endif
+
+
/*
* Connect to the LDAP server and binds. Does not connect if already
* connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
@@ -559,6 +602,10 @@
int failures = 0;
int new_connection = 0;
util_ldap_state_t *st;
+#if APR_HAS_LDAP_INITIALIZE
+ apr_status_t status = APR_SUCCESS;
+ apu_err_t result = { 0 };
+#endif

/* sanity check for NULL */
if (!ldc) {
@@ -601,10 +648,126 @@
* the error condition.
*/

+#if APR_HAS_LDAP_INITIALIZE
+
while (failures <= st->retries) {
if (failures > 0 && st->retry_delay > 0) {
apr_sleep(st->retry_delay);
}
+
+ apr_ldap_message_t *msg = NULL;
+
+ do {
+// FIXME: pass pwd
+ status = apr_ldap_bind(ldc->ld, NULL, ldc->mech, bind_interact, NULL,
+ apr_time_from_sec(st->opTimeout ?
+ st->opTimeout->tv_sec : -1), &msg, &result);
+
+ if (APR_SUCCESS == status) {
+ break;
+ }
+ else if (APR_INCOMPLETE == status) {
+ /* keep going */
+ }
+ else {
+ break;
+ }
+
+ status = apr_ldap_result(msg, apr_time_from_sec(st->opTimeout ?
+ st->opTimeout->tv_sec : -1), &result);
+
+ if (APR_SUCCESS == status) {
+ /* no more messages */
+ break;
+ }
+ else if (APR_INCOMPLETE == status) {
+ /* keep going */
+ }
+ else {
+ break;
+ }
+
+ } while (APR_INCOMPLETE == status);
+
+ if (APR_SUCCESS != status) {
+ failures++;
+ }
+
+ if (APR_STATUS_IS_EDOWN(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "LDAP bind failed with server down "
+ "(try %d)", failures);
+ }
+ else if (APR_STATUS_IS_ETIMEDOUT(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01284)
+ "LDAP bind timed out on %s "
+ "connection, dropped by firewall?",
+ new_connection ? "new" : "reused");
+ }
+ else if (APR_STATUS_IS_AUTH_UNKNOWN(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, %s not supported for this user (auth unknown)",
+ new_connection ? "new" : "reused", ldc->mech);
+ break;
+ }
+ else if (APR_STATUS_IS_PROXY_AUTH(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, proxy auth failed for this user",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INAPPROPRIATE_AUTH(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, type of authentication not valid for this user (inappropriate auth)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INVALID_CREDENTIALS(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, invalid credentials for this user (wrong password?)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INSUFFICIENT_ACCESS(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, user does not have permission to bind (unsufficient access)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else {
+ /* Other errors not retryable */
+ break;
+ }
+
+ }
+
+ /* free the handle if there was an error
+ */
+ if (APR_SUCCESS != status)
+ {
+ uldap_connection_unbind(ldc);
+ ldc->reason = "LDAP: bind failed";
+ }
+ else {
+ ldc->bound = 1;
+ ldc->must_rebind = 0;
+ ldc->reason = "LDAP: connection open successful";
+ }
+
+ return(result.rc);
+
+#else
+
+ while (failures <= st->retries) {
+ if (failures > 0 && st->retry_delay > 0) {
+ apr_sleep(st->retry_delay);
+ }
+
rc = uldap_simple_bind(ldc, (char *)ldc->binddn, (char *)ldc->bindpw,
st->opTimeout);

@@ -637,6 +800,7 @@
break;
}
}
+
}

/* free the handle if there was an error
@@ -653,6 +817,7 @@
}

return(rc);
+#endif
}


@@ -697,19 +862,12 @@
}


-/*
- * Find an existing ldap connection struct that matches the
- * provided ldap connection parameters.
- *
- * If not found in the cache, a new ldc structure will be allocated
- * from st->pool and returned to the caller. If found in the cache,
- * a pointer to the existing ldc structure will be returned.
- */
static util_ldap_connection_t *
- uldap_connection_find(request_rec *r,
- const char *host, int port,
- const char *binddn, const char *bindpw,
- deref_options deref, int secure)
+ connection_find(request_rec *r,
+ const char *url,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
{
struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
int secureflag = secure;
@@ -737,13 +895,19 @@
#if APR_HAS_THREADS
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
#endif
- if ( (l->port == port) && (strcmp(l->host, host) == 0)
- && ((!l->binddn && !binddn) || (l->binddn && binddn
- && !strcmp(l->binddn, binddn)))
- && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw
- && !strcmp(l->bindpw, bindpw)))
- && (l->deref == deref) && (l->secure == secureflag)
- && !compare_client_certs(dc->client_certs, l->client_certs))
+ if ( (l->port == port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(l->host, host)))
+ && ((!binddn && !l->binddn) || (binddn && l->binddn
+ && !strcmp(binddn, l->binddn)))
+ && ((!bindpw && !l->bindpw) || (bindpw && l->bindpw
+ && !strcmp(bindpw, l->bindpw)))
+ && (deref == l->deref) && (secureflag == l->secure)
+ && !compare_client_certs(dc->client_certs, l->client_certs)
+ && ((!dc->mech && !l->mech) || (dc->mech && l->mech
+ && !strcmp(dc->mech, l->mech))) )
{
if (st->connection_pool_ttl > 0) {
if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) {
@@ -779,9 +943,15 @@
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {

#endif
- if ((l->port == port) && (strcmp(l->host, host) == 0) &&
- (l->deref == deref) && (l->secure == secureflag) &&
- !compare_client_certs(dc->client_certs, l->client_certs))
+ if ((port == l->port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(host, l->host)))
+ && (deref == l->deref) && (secureflag == l->secure)
+ && !compare_client_certs(dc->client_certs, l->client_certs)
+ && ((!dc->mech && !l->mech) || (dc->mech && l->mech
+ && !strcmp(dc->mech, l->mech))) )
{
if (st->connection_pool_ttl > 0) {
if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) {
@@ -849,6 +1019,7 @@
apr_thread_mutex_lock(l->lock);
#endif
l->bound = 0;
+ l->url = apr_pstrdup(l->pool, url);
l->host = apr_pstrdup(l->pool, host);
l->port = port;
l->deref = deref;
@@ -882,6 +1053,20 @@
apr_pool_tag(l->rebind_pool, "util_ldap_rebind");
}

+#if APR_HAS_LDAP_INITIALIZE
+ if (apr_pool_create(&(l->init_pool), l->pool) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01286)
+ "util_ldap: Failed to create memory pool");
+#if APR_HAS_THREADS
+ apr_thread_mutex_unlock(st->mutex);
+#endif
+ return NULL;
+ }
+ apr_pool_tag(l->init_pool, "util_ldap_init");
+
+ l->mech = dc->mech;
+#endif
+
if (p) {
p->next = l;
}
@@ -897,6 +1082,42 @@
return l;
}

+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ *
+ * Deprecated: replaced by uldap_connection_find_ex()
+ */
+static util_ldap_connection_t *
+ uldap_connection_find(request_rec *r,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, NULL, host, port, binddn, bindpw, deref, secure);
+}
+
+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ */
+static util_ldap_connection_t *
+ uldap_connection_find_ex(request_rec *r,
+ const char *url,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, url, NULL, 0, binddn, bindpw, deref, secure);
+}
+
/* ------------------------------------------------------------------ */

/*
@@ -2525,6 +2746,8 @@

}

+ dc->client_certs_set = 1;
+
return(NULL);
}

@@ -2643,6 +2866,8 @@
return "LDAPReferrals must be 'on', 'off', or 'default'";
}

+ dc->ChaseReferrals_set = 1;
+
return(NULL);
}

@@ -2684,9 +2909,33 @@
"LDAP: Limit chased referrals to maximum of %d hops.",
dc->ReferralHopLimit);

+ dc->ReferralHopLimit_set = 1;
+
return NULL;
}

+static const char *util_ldap_set_bind_mechanism(cmd_parms *cmd,
+ void *config,
+ const char *mech)
+{
+ util_ldap_config_t *dc = config;
+
+ dc->mech = mech;
+ dc->mech_set = 1;
+
+ return NULL;
+}
+
+static const char *util_ldap_set_inherit(cmd_parms *parms, void *config, int flag)
+{
+ util_ldap_config_t *dc = config;
+
+ dc->inherit = flag;
+ dc->inherit_set = 1;
+
+ return NULL;
+}
+
static void *util_ldap_create_dir_config(apr_pool_t *p, char *d)
{
util_ldap_config_t *dc =
@@ -2697,9 +2946,51 @@
dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_ON;
dc->ReferralHopLimit = AP_LDAP_HOPLIMIT_UNSET;

+ dc->inherit = 0;
+ dc->inherit_set = 0;
+
return dc;
}

+static void *util_ldap_merge_dir_config(apr_pool_t *p, void *basev,
+ void *overridesv)
+{
+ util_ldap_config_t *dc = apr_pcalloc(p, sizeof(util_ldap_config_t));
+ util_ldap_config_t *base = (util_ldap_config_t *) basev;
+ util_ldap_config_t *overrides = (util_ldap_config_t *) overridesv;
+
+ dc->inherit = (overrides->inherit_set == 0) ? base->inherit : overrides->inherit;
+ dc->inherit_set = overrides->inherit_set || base->inherit_set;
+
+ if (dc->inherit) {
+
+ dc->client_certs = (overrides->client_certs_set == 0) ? base->client_certs :
+ overrides->client_certs;
+ dc->client_certs_set = overrides->client_certs_set || base->client_certs_set;
+
+ dc->ChaseReferrals = (overrides->ChaseReferrals_set == 0) ? base->ChaseReferrals :
+ overrides->ChaseReferrals;
+ dc->ChaseReferrals_set = overrides->ChaseReferrals_set || base->ChaseReferrals_set;
+
+ dc->ReferralHopLimit = (overrides->ReferralHopLimit_set == 0) ? base->ReferralHopLimit :
+ overrides->ReferralHopLimit;
+ dc->ReferralHopLimit_set = overrides->ReferralHopLimit_set || base->ReferralHopLimit_set;
+
+ dc->mech = (overrides->mech_set == 0) ? base->mech :
+ overrides->mech;
+ dc->mech_set = overrides->mech_set || base->mech_set;
+
+ }
+ else {
+ dc->client_certs = overrides->client_certs;
+ dc->ChaseReferrals = overrides->ChaseReferrals;
+ dc->ReferralHopLimit = overrides->ReferralHopLimit;
+ dc->mech = overrides->mech;
+ }
+
+ return dc;
+}
+
static const char *util_ldap_set_op_timeout(cmd_parms *cmd,
void *dummy,
const char *val)
@@ -3184,6 +3475,10 @@
"Limit the number of referral hops that LDAP can follow. "
"(Integer value, Consult LDAP SDK documentation for applicability and defaults"),

+ AP_INIT_TAKE1("LDAPBindMechanism", util_ldap_set_bind_mechanism,
+ NULL, OR_AUTHCFG,
+ "Set the SASL bind mechanism."),
+
AP_INIT_TAKE1("LDAPLibraryDebug", util_ldap_set_debug_level,
NULL, RSRC_CONF,
"Enable debugging in LDAP SDK (Default: off, values: SDK specific"),
@@ -3206,6 +3501,8 @@
"Specify the delay between retries of a failed LDAP operation "
"(0 = no delay). Default: 0"),

+ AP_INIT_FLAG("LDAPInherit", util_ldap_set_inherit, NULL, OR_AUTHCFG,
+ "on if this server should inherit all LDAP directives defined in the main server"),

{NULL}
};
@@ -3216,6 +3513,7 @@
APR_REGISTER_OPTIONAL_FN(uldap_connection_close);
APR_REGISTER_OPTIONAL_FN(uldap_connection_unbind);
APR_REGISTER_OPTIONAL_FN(uldap_connection_find);
+ APR_REGISTER_OPTIONAL_FN(uldap_connection_find_ex);
APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn);
APR_REGISTER_OPTIONAL_FN(uldap_cache_compare);
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid);
@@ -3232,7 +3530,7 @@
AP_DECLARE_MODULE(ldap) = {
STANDARD20_MODULE_STUFF,
util_ldap_create_dir_config, /* create dir config */
- NULL, /* merge dir config */
+ util_ldap_merge_dir_config, /* merge dir config */
util_ldap_create_config, /* create server config */
util_ldap_merge_config, /* merge server config */
util_ldap_cmds, /* command table */
Re: POC: updated ldapi:// support for mod_ldap [ In reply to ]
On 22 Apr 2023, at 20:17, Graham Leggett via dev <dev@httpd.apache.org> wrote:

> This patch adds limited support for SASL binds. Depends on updated POC patch at the dev@apr list.

Updated patch that handles authname and pass for SASL.

<If "%{SSL_CLIENT_VERIFY} == 'SUCCESS' || %{SSL_CLIENT_VERIFY} == 'GENEROUS'">

SSLUserName SSL_CLIENT_CERT_RFC4523_CEA

LDAPBind mechanism EXTERNAL
AuthLDAPURL ldapi://%2frun%2fslapd-seawitch.socket/dc=xxx,dc=xx,dc=xx?uid,inetSubscriberAccountId?sub?inetSubscriberAccountId=*
require ldap-group cn=https://xxx.xxx.xx.xx/xxx,ou=xxx,ou=xxx,dc=xxx,dc=xx,dc=xx

</If>

Regards,
Graham




Index: include/util_ldap.h
===================================================================
--- include/util_ldap.h (revision 1909117)
+++ include/util_ldap.h (working copy)
@@ -45,6 +45,10 @@
/* this whole thing disappears if LDAP is not enabled */
#if APR_HAS_LDAP

+#ifndef APR_HAS_LDAP_INITIALIZE
+#define APR_HAS_LDAP_INITIALIZE 0
+#endif
+
#if defined(LDAP_UNAVAILABLE) || APR_HAS_MICROSOFT_LDAPSDK
#define AP_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN \
||(s) == LDAP_UNAVAILABLE)
@@ -126,8 +130,8 @@
const char *reason; /* Reason for an error failure */

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 */
+ 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 */

int ChaseReferrals; /* [on|off] (default = AP_LDAP_CHASEREFERRALS_ON)*/
int ReferralHopLimit; /* # of referral hops to follow (default = AP_LDAP_DEFAULT_HOPLIMIT) */
@@ -136,12 +140,39 @@
int must_rebind; /* The connection was last bound with other then binddn/bindpw */
request_rec *r; /* request_rec used to find this util_ldap_connection_t */
apr_time_t last_backend_conn; /* the approximate time of the last backend LDAP request */
+
+#if APR_HAS_LDAP_INITIALIZE
+ apr_pool_t *init_pool; /* Pool from which this connection is initialised */
+ apu_err_t result; /* result of prior operations on this connection */
+ const char *url; /* URL of the LDAP server (or space separated list) */
+ apr_ldap_t *ld;
+ const char *mech; /* SASL bind mechanism */
+ const char *realm; /* SASL realm for the authentication attempt */
+ const char *user; /* SASL username to use for proxy authorization */
+ const char *authname; /* SASL username to authenticate */
+ const char *pass; /* SASL password for the provided username */
+#endif
} util_ldap_connection_t;

typedef struct util_ldap_config_t {
int ChaseReferrals;
int ReferralHopLimit;
- apr_array_header_t *client_certs; /* Client certificates */
+ apr_array_header_t *client_certs; /* Client certificates */
+ const char *mech; /* SASL mechanism */
+ const char *realm; /* SASL realm for the authentication attempt */
+ const char *user; /* SASL username to use for proxy authorization */
+ const char *authname; /* SASL username to authenticate */
+ const char *pass; /* SASL password for the provided username */
+ unsigned int inherit:1;
+ unsigned int inherit_set:1;
+ unsigned int client_certs_set:1;
+ unsigned int ReferralHopLimit_set:1;
+ unsigned int ChaseReferrals_set:1;
+ unsigned int mech_set:1;
+ unsigned int realm_set:1;
+ unsigned int user_set:1;
+ unsigned int authname_set:1;
+ unsigned int pass_set:1;
} util_ldap_config_t;

/* LDAP cache state information */
@@ -241,6 +272,7 @@
* @fn util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
* const char *binddn, const char *bindpw, deref_options deref,
* int netscapessl, int starttls)
+ * @deprecated Replaced by uldap_connection_find_ex()
*/
APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find,(request_rec *r, const char *host, int port,
const char *binddn, const char *bindpw, deref_options deref,
@@ -247,6 +279,26 @@
int secure));

/**
+ * Find a connection in a list of connections
+ * @param r The request record
+ * @param url The URL to connect to (multiple URLs space separated)
+ * @param binddn The DN to bind with
+ * @param bindpw The password to bind with
+ * @param deref The dereferencing behavior
+ * @param secure use SSL on the connection
+ * @tip Once a connection is found and returned, a lock will be acquired to
+ * lock that particular connection, so that another thread does not try and
+ * use this connection while it is busy. Once you are finished with a connection,
+ * apr_ldap_connection_close() must be called to release this connection.
+ * @fn util_ldap_connection_t *util_ldap_connection_find_ex(request_rec *r, const char *url,
+ * const char *binddn, const char *bindpw, deref_options deref,
+ * int netscapessl, int starttls)
+ */
+APR_DECLARE_OPTIONAL_FN(util_ldap_connection_t *,uldap_connection_find_ex,(request_rec *r, const char *url,
+ const char *binddn, const char *bindpw, deref_options deref,
+ int secure));
+
+/**
* Compare two DNs for sameness
* @param r The request record
* @param ldc The LDAP connection being used.
Index: modules/aaa/mod_authnz_ldap.c
===================================================================
--- modules/aaa/mod_authnz_ldap.c (revision 1909117)
+++ modules/aaa/mod_authnz_ldap.c (working copy)
@@ -104,7 +104,7 @@
module AP_MODULE_DECLARE_DATA authnz_ldap_module;

static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;
-static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;
+static APR_OPTIONAL_FN_TYPE(uldap_connection_find_ex) *util_ldap_connection_find_ex;
static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;
static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;
static APR_OPTIONAL_FN_TYPE(uldap_cache_check_subgroups) *util_ldap_cache_check_subgroups;
@@ -453,9 +453,7 @@
bindpw = req->password;
}

- return util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ return util_ldap_connection_find_ex(r, sec->url, binddn, bindpw, sec->deref, sec->secure);
}
/*
* Authentication Phase
@@ -527,7 +525,7 @@
}

/* There is a good AuthLDAPURL, right? */
- if (sec->host) {
+ if (sec->url) {
const char *binddn = sec->binddn;
const char *bindpw = sec->bindpw;
if (sec->initial_bind_as_user) {
@@ -535,13 +533,13 @@
binddn = ldap_determine_binddn(r, user);
}

- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- binddn, bindpw,
- sec->deref, sec->secure);
+ ldc = util_ldap_connection_find_ex(r, sec->url,
+ binddn, bindpw,
+ sec->deref, sec->secure);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01690)
- "auth_ldap authenticate: no sec->host - weird...?");
+ "auth_ldap authenticate: no sec->url - weird...?");
return AUTH_GENERAL_ERROR;
}

@@ -1436,13 +1434,14 @@
* host and port.
*/
static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
- void *config,
- const char *url,
- const char *mode)
+ void *config,
+ const char *url,
+ const char *mode)
{
- int rc;
+ int rc, i;
apr_ldap_url_desc_t *urld;
apr_ldap_err_t *result;
+ const char *end = url;

authn_ldap_config_t *sec = config;

@@ -1450,8 +1449,18 @@
if (rc != APR_SUCCESS) {
return result->reason;
}
- sec->url = apr_pstrdup(cmd->pool, url);

+ /* isolate the host/port part of the URL */
+ for (i = 0; end && i < 3; i++) {
+ end = strchr((char *)end + 1, '/');
+ }
+ if (end) {
+ sec->url = apr_pstrndup(cmd->pool, url, end - url);
+ }
+ else {
+ sec->url = apr_pstrdup(cmd->pool, url);
+ }
+
/* Set all the values, or at least some sane defaults */
if (sec->host) {
sec->host = apr_pstrcat(cmd->pool, urld->lud_host, " ", sec->host, NULL);
@@ -1528,9 +1537,10 @@
sec->have_ldap_url = 1;

ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, cmd->server,
- "auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, "
+ "auth_ldap url parse: `%s', Url: %s, Host: %s, Port: %d, DN: %s, "
"attrib: %s, scope: %s, filter: %s, connection mode: %s",
url,
+ sec->url,
urld->lud_host,
urld->lud_port,
urld->lud_dn,
@@ -1921,13 +1931,13 @@

static void ImportULDAPOptFn(void)
{
- util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
- util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find);
- util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
- util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
- util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
- util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
- util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
+ util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
+ util_ldap_connection_find_ex = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find_ex);
+ util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn);
+ util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare);
+ util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid);
+ util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn);
+ util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported);
util_ldap_cache_check_subgroups = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_check_subgroups);
}

Index: modules/ldap/util_ldap.c
===================================================================
--- modules/ldap/util_ldap.c (revision 1909117)
+++ modules/ldap/util_ldap.c (working copy)
@@ -199,9 +199,19 @@
if (ldc->r) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc);
}
+#if !APR_HAS_LDAP_INITIALIZE
ldap_unbind_s(ldc->ldap);
+#endif
ldc->ldap = NULL;
}
+
+#if APR_HAS_LDAP_INITIALIZE
+ if (ldc->ld) {
+ apr_pool_clear(ldc->init_pool);
+ ldc->ld = NULL;
+ }
+#endif
+
ldc->bound = 0;

/* forget the rebind info for this conn */
@@ -285,6 +295,27 @@
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
&ldap_module);
int have_client_certs = !apr_is_empty_array(ldc->client_certs);
+
+#if APR_HAS_LDAP_INITIALIZE
+
+ apr_ldap_initialize(ldc->init_pool, ldc->url, &(ldc->ld), &(ldc->result));
+
+ if (ldc->ld) {
+ apr_ldap_opt_t opt;
+
+ apr_ldap_get_option_ex(ldc->ld, APR_LDAP_OPT_HANDLE, &opt, &(ldc->result));
+
+ ldc->ldap = opt.handle;
+ }
+
+ result = (apr_ldap_err_t *)&ldc->result;
+
+#else
+
+ /* remove after apr-util v1.7 */
+
+ apr_ldap_err_t *result = NULL;
+
#if !APR_HAS_SOLARIS_LDAPSDK
/*
* Normally we enable SSL/TLS with apr_ldap_set_option(), except
@@ -322,7 +353,9 @@
return(APR_EGENERAL);
}

- if (result->rc) {
+#endif
+
+ if (result && result->rc) {
ldc->reason = result->reason;
ldc->bound = 0;
return result->rc;
@@ -508,6 +541,7 @@
return LDAP_OTHER;
}

+
/*
* Replacement function for ldap_simple_bind_s() with a timeout.
* To do this in a portable way, we have to use ldap_simple_bind() and
@@ -546,6 +580,58 @@
return rc;
}

+
+#if APR_HAS_LDAP_INITIALIZE
+static apr_status_t bind_interact(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx)
+{
+ util_ldap_connection_t *ldc = ctx;
+
+ switch (interact->id) {
+ case APR_LDAP_INTERACT_GETREALM:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP bind realm %s: %s", ldc->realm ? "set to" : "left unset",
+ ldc->realm ? ldc->realm : "");
+ interact->result = ldc->realm;
+ interact->len = interact->result ? strlen(interact->result) : 0;
+ break;
+ case APR_LDAP_INTERACT_USER:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP bind user %s: %s", ldc->user ? "set to" : "left unset",
+ ldc->user ? ldc->user : "");
+ interact->result = ldc->user;
+ interact->len = interact->result ? strlen(interact->result) : 0;
+ break;
+ case APR_LDAP_INTERACT_AUTHNAME:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP bind authname %s: %s", ldc->authname ? "set to" : "left unset",
+ ldc->authname ? ldc->authname : "");
+ interact->result = ldc->authname;
+ interact->len = interact->result ? strlen(interact->result) : 0;
+ break;
+ case APR_LDAP_INTERACT_PASS:
+ if (ldc->binddn && ldc->bindpw) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP simple bind pass %s", ldc->bindpw ? "set" : "left unset");
+ interact->result = ldc->bindpw;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP bind pass %s", ldc->pass ? "set" : "left unset");
+ interact->result = ldc->pass;
+ }
+ interact->len = interact->result ? strlen(interact->result) : 0;
+ break;
+ default:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ldc->r, APLOGNO()
+ "LDAP bind id %d with prompt '%s' unrecognised", interact->id, interact->prompt);
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+#endif
+
+
/*
* Connect to the LDAP server and binds. Does not connect if already
* connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
@@ -559,6 +645,10 @@
int failures = 0;
int new_connection = 0;
util_ldap_state_t *st;
+#if APR_HAS_LDAP_INITIALIZE
+ apr_status_t status = APR_SUCCESS;
+ apu_err_t result = { 0 };
+#endif

/* sanity check for NULL */
if (!ldc) {
@@ -601,10 +691,130 @@
* the error condition.
*/

+#if APR_HAS_LDAP_INITIALIZE
+
while (failures <= st->retries) {
if (failures > 0 && st->retry_delay > 0) {
apr_sleep(st->retry_delay);
}
+
+ apr_ldap_message_t *msg = NULL;
+
+ do {
+
+ /* If a distinguished name is supplied, we've been asked for a simple bind.
+ * If the distinguished name is unset, we perform a sasl bind.
+ */
+
+ status = apr_ldap_bind(ldc->ld, ldc->binddn, ldc->mech, bind_interact, ldc,
+ apr_time_from_sec(st->opTimeout ?
+ st->opTimeout->tv_sec : -1), &msg, &result);
+
+ if (APR_SUCCESS == status) {
+ break;
+ }
+ else if (APR_INCOMPLETE == status) {
+ /* keep going */
+ }
+ else {
+ break;
+ }
+
+ status = apr_ldap_result(msg, apr_time_from_sec(st->opTimeout ?
+ st->opTimeout->tv_sec : -1), &result);
+
+ if (APR_SUCCESS == status) {
+ /* no more messages */
+ break;
+ }
+ else if (APR_INCOMPLETE == status) {
+ /* keep going */
+ }
+ else {
+ break;
+ }
+
+ } while (APR_INCOMPLETE == status);
+
+ if (APR_SUCCESS != status) {
+ failures++;
+ }
+
+ if (APR_STATUS_IS_EDOWN(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "LDAP bind failed with server down "
+ "(try %d)", failures);
+ }
+ else if (APR_STATUS_IS_ETIMEDOUT(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01284)
+ "LDAP bind timed out on %s "
+ "connection, dropped by firewall?",
+ new_connection ? "new" : "reused");
+ }
+ else if (APR_STATUS_IS_AUTH_UNKNOWN(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, %s not supported for this user (auth unknown)",
+ new_connection ? "new" : "reused", ldc->mech);
+ break;
+ }
+ else if (APR_STATUS_IS_PROXY_AUTH(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, proxy auth failed for this user",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INAPPROPRIATE_AUTH(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, type of authentication not valid for this user (inappropriate auth)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INVALID_CREDENTIALS(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, invalid credentials for this user (wrong password?)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else if (APR_STATUS_IS_INSUFFICIENT_ACCESS(status)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+ "LDAP bind failed on %s "
+ "connection, user does not have permission to bind (unsufficient access)",
+ new_connection ? "new" : "reused");
+ break;
+ }
+ else {
+ /* Other errors not retryable */
+ break;
+ }
+
+ }
+
+ /* free the handle if there was an error
+ */
+ if (APR_SUCCESS != status)
+ {
+ uldap_connection_unbind(ldc);
+ ldc->reason = "LDAP: bind failed";
+ }
+ else {
+ ldc->bound = 1;
+ ldc->must_rebind = 0;
+ ldc->reason = "LDAP: connection open successful";
+ }
+
+ return(result.rc);
+
+#else
+
+ while (failures <= st->retries) {
+ if (failures > 0 && st->retry_delay > 0) {
+ apr_sleep(st->retry_delay);
+ }
+
rc = uldap_simple_bind(ldc, (char *)ldc->binddn, (char *)ldc->bindpw,
st->opTimeout);

@@ -637,6 +847,7 @@
break;
}
}
+
}

/* free the handle if there was an error
@@ -653,6 +864,7 @@
}

return(rc);
+#endif
}


@@ -697,19 +909,12 @@
}


-/*
- * Find an existing ldap connection struct that matches the
- * provided ldap connection parameters.
- *
- * If not found in the cache, a new ldc structure will be allocated
- * from st->pool and returned to the caller. If found in the cache,
- * a pointer to the existing ldc structure will be returned.
- */
static util_ldap_connection_t *
- uldap_connection_find(request_rec *r,
- const char *host, int port,
- const char *binddn, const char *bindpw,
- deref_options deref, int secure)
+ connection_find(request_rec *r,
+ const char *url,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
{
struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
int secureflag = secure;
@@ -737,13 +942,27 @@
#if APR_HAS_THREADS
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {
#endif
- if ( (l->port == port) && (strcmp(l->host, host) == 0)
- && ((!l->binddn && !binddn) || (l->binddn && binddn
- && !strcmp(l->binddn, binddn)))
- && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw
- && !strcmp(l->bindpw, bindpw)))
- && (l->deref == deref) && (l->secure == secureflag)
- && !compare_client_certs(dc->client_certs, l->client_certs))
+ if ( (l->port == port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(l->host, host)))
+ && ((!binddn && !l->binddn) || (binddn && l->binddn
+ && !strcmp(binddn, l->binddn)))
+ && ((!bindpw && !l->bindpw) || (bindpw && l->bindpw
+ && !strcmp(bindpw, l->bindpw)))
+ && (deref == l->deref) && (secureflag == l->secure)
+ && !compare_client_certs(dc->client_certs, l->client_certs)
+ && ((!dc->mech && !l->mech) || (dc->mech && l->mech
+ && !strcmp(dc->mech, l->mech)))
+ && ((!dc->realm && !l->realm) || (dc->realm && l->realm
+ && !strcmp(dc->realm, l->realm)))
+ && ((!dc->user && !l->user) || (dc->user && l->user
+ && !strcmp(dc->user, l->user)))
+ && ((!dc->authname && !l->authname) || (dc->authname && l->authname
+ && !strcmp(dc->authname, l->authname)))
+ && ((!dc->pass && !l->pass) || (dc->pass && l->pass
+ && !strcmp(dc->pass, l->pass))) )
{
if (st->connection_pool_ttl > 0) {
if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) {
@@ -779,9 +998,23 @@
if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {

#endif
- if ((l->port == port) && (strcmp(l->host, host) == 0) &&
- (l->deref == deref) && (l->secure == secureflag) &&
- !compare_client_certs(dc->client_certs, l->client_certs))
+ if ((port == l->port)
+ && ((!url && !l->url) || (url && l->url
+ && !strcmp(url, l->url)))
+ && ((!host && !l->host) || (host && l->host
+ && !strcmp(host, l->host)))
+ && (deref == l->deref) && (secureflag == l->secure)
+ && !compare_client_certs(dc->client_certs, l->client_certs)
+ && ((!dc->mech && !l->mech) || (dc->mech && l->mech
+ && !strcmp(dc->mech, l->mech)))
+ && ((!dc->realm && !l->realm) || (dc->realm && l->realm
+ && !strcmp(dc->realm, l->realm)))
+ && ((!dc->user && !l->user) || (dc->user && l->user
+ && !strcmp(dc->user, l->user)))
+ && ((!dc->authname && !l->authname) || (dc->authname && l->authname
+ && !strcmp(dc->authname, l->authname)))
+ && ((!dc->pass && !l->pass) || (dc->pass && l->pass
+ && !strcmp(dc->pass, l->pass))) )
{
if (st->connection_pool_ttl > 0) {
if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) {
@@ -849,6 +1082,7 @@
apr_thread_mutex_lock(l->lock);
#endif
l->bound = 0;
+ l->url = apr_pstrdup(l->pool, url);
l->host = apr_pstrdup(l->pool, host);
l->port = port;
l->deref = deref;
@@ -882,6 +1116,24 @@
apr_pool_tag(l->rebind_pool, "util_ldap_rebind");
}

+#if APR_HAS_LDAP_INITIALIZE
+ if (apr_pool_create(&(l->init_pool), l->pool) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01286)
+ "util_ldap: Failed to create memory pool");
+#if APR_HAS_THREADS
+ apr_thread_mutex_unlock(st->mutex);
+#endif
+ return NULL;
+ }
+ apr_pool_tag(l->init_pool, "util_ldap_init");
+
+ l->mech = dc->mech;
+ l->realm = dc->realm;
+ l->user = dc->user;
+ l->authname = dc->authname;
+ l->pass = dc->pass;
+#endif
+
if (p) {
p->next = l;
}
@@ -897,6 +1149,42 @@
return l;
}

+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ *
+ * Deprecated: replaced by uldap_connection_find_ex()
+ */
+static util_ldap_connection_t *
+ uldap_connection_find(request_rec *r,
+ const char *host, int port,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, NULL, host, port, binddn, bindpw, deref, secure);
+}
+
+/*
+ * Find an existing ldap connection struct that matches the
+ * provided ldap connection parameters.
+ *
+ * If not found in the cache, a new ldc structure will be allocated
+ * from st->pool and returned to the caller. If found in the cache,
+ * a pointer to the existing ldc structure will be returned.
+ */
+static util_ldap_connection_t *
+ uldap_connection_find_ex(request_rec *r,
+ const char *url,
+ const char *binddn, const char *bindpw,
+ deref_options deref, int secure)
+{
+ return connection_find(r, url, NULL, 0, binddn, bindpw, deref, secure);
+}
+
/* ------------------------------------------------------------------ */

/*
@@ -2525,6 +2813,8 @@

}

+ dc->client_certs_set = 1;
+
return(NULL);
}

@@ -2643,6 +2933,8 @@
return "LDAPReferrals must be 'on', 'off', or 'default'";
}

+ dc->ChaseReferrals_set = 1;
+
return(NULL);
}

@@ -2684,9 +2976,61 @@
"LDAP: Limit chased referrals to maximum of %d hops.",
dc->ReferralHopLimit);

+ dc->ReferralHopLimit_set = 1;
+
return NULL;
}

+static const char *util_ldap_set_bind(cmd_parms *cmd,
+ void *config,
+ const char *prompt, const char *value)
+{
+ util_ldap_config_t *dc = config;
+ char c;
+
+ if (!prompt || !value) {
+ return "LDAPBind takes two parameters";
+ }
+
+ c = prompt[0];
+
+ if (c == 'm' && !strcmp(prompt, "mechanism")) {
+ dc->mech = value;
+ dc->mech_set = 1;
+ }
+ else if (c == 'r' && !strcmp(prompt, "realm")) {
+ dc->realm = value;
+ dc->realm_set = 1;
+ }
+ else if (c == 'a' && !strcmp(prompt, "authname")) {
+ dc->authname = value;
+ dc->authname_set = 1;
+ }
+ else if (c == 'u' && !strcmp(prompt, "user")) {
+ dc->user = value;
+ dc->user_set = 1;
+ }
+ else if (c == 'p' && !strcmp(prompt, "pass")) {
+ dc->pass = value;
+ dc->pass_set = 1;
+ }
+ else {
+ return "LDAPBind parameter must be one of 'mechanism', 'realm', 'authname', 'user', 'pass'";
+ }
+
+ return NULL;
+}
+
+static const char *util_ldap_set_inherit(cmd_parms *parms, void *config, int flag)
+{
+ util_ldap_config_t *dc = config;
+
+ dc->inherit = flag;
+ dc->inherit_set = 1;
+
+ return NULL;
+}
+
static void *util_ldap_create_dir_config(apr_pool_t *p, char *d)
{
util_ldap_config_t *dc =
@@ -2697,9 +3041,65 @@
dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_ON;
dc->ReferralHopLimit = AP_LDAP_HOPLIMIT_UNSET;

+ dc->inherit = 0;
+ dc->inherit_set = 0;
+
return dc;
}

+static void *util_ldap_merge_dir_config(apr_pool_t *p, void *basev,
+ void *overridesv)
+{
+ util_ldap_config_t *dc = apr_pcalloc(p, sizeof(util_ldap_config_t));
+ util_ldap_config_t *base = (util_ldap_config_t *) basev;
+ util_ldap_config_t *overrides = (util_ldap_config_t *) overridesv;
+
+ dc->inherit = (overrides->inherit_set == 0) ? base->inherit : overrides->inherit;
+ dc->inherit_set = overrides->inherit_set || base->inherit_set;
+
+ if (dc->inherit) {
+
+ dc->client_certs = (overrides->client_certs_set == 0) ? base->client_certs :
+ overrides->client_certs;
+ dc->client_certs_set = overrides->client_certs_set || base->client_certs_set;
+
+ dc->ChaseReferrals = (overrides->ChaseReferrals_set == 0) ? base->ChaseReferrals :
+ overrides->ChaseReferrals;
+ dc->ChaseReferrals_set = overrides->ChaseReferrals_set || base->ChaseReferrals_set;
+
+ dc->ReferralHopLimit = (overrides->ReferralHopLimit_set == 0) ? base->ReferralHopLimit :
+ overrides->ReferralHopLimit;
+ dc->ReferralHopLimit_set = overrides->ReferralHopLimit_set || base->ReferralHopLimit_set;
+
+ dc->mech = (overrides->mech_set == 0) ? base->mech : overrides->mech;
+ dc->mech_set = overrides->mech_set || base->mech_set;
+
+ dc->realm = (overrides->realm_set == 0) ? base->realm : overrides->realm;
+ dc->realm_set = overrides->realm_set || base->realm_set;
+
+ dc->user = (overrides->user_set == 0) ? base->user : overrides->user;
+ dc->user_set = overrides->user_set || base->user_set;
+
+ dc->authname = (overrides->authname_set == 0) ? base->authname : overrides->authname;
+ dc->authname_set = overrides->authname_set || base->authname_set;
+
+ dc->pass = (overrides->pass_set == 0) ? base->pass : overrides->pass;
+ dc->pass_set = overrides->pass_set || base->pass_set;
+ }
+ else {
+ dc->client_certs = overrides->client_certs;
+ dc->ChaseReferrals = overrides->ChaseReferrals;
+ dc->ReferralHopLimit = overrides->ReferralHopLimit;
+ dc->mech = overrides->mech;
+ dc->realm = overrides->realm;
+ dc->user = overrides->user;
+ dc->authname = overrides->authname;
+ dc->pass = overrides->pass;
+ }
+
+ return dc;
+}
+
static const char *util_ldap_set_op_timeout(cmd_parms *cmd,
void *dummy,
const char *val)
@@ -3184,6 +3584,10 @@
"Limit the number of referral hops that LDAP can follow. "
"(Integer value, Consult LDAP SDK documentation for applicability and defaults"),

+ AP_INIT_TAKE2("LDAPBind", util_ldap_set_bind,
+ NULL, OR_AUTHCFG,
+ "Set the SASL bind parameters. One of 'mechanism', 'user', 'authname', 'pass'"),
+
AP_INIT_TAKE1("LDAPLibraryDebug", util_ldap_set_debug_level,
NULL, RSRC_CONF,
"Enable debugging in LDAP SDK (Default: off, values: SDK specific"),
@@ -3206,6 +3610,8 @@
"Specify the delay between retries of a failed LDAP operation "
"(0 = no delay). Default: 0"),

+ AP_INIT_FLAG("LDAPInherit", util_ldap_set_inherit, NULL, OR_AUTHCFG,
+ "on if this server should inherit all LDAP directives defined in the main server"),

{NULL}
};
@@ -3216,6 +3622,7 @@
APR_REGISTER_OPTIONAL_FN(uldap_connection_close);
APR_REGISTER_OPTIONAL_FN(uldap_connection_unbind);
APR_REGISTER_OPTIONAL_FN(uldap_connection_find);
+ APR_REGISTER_OPTIONAL_FN(uldap_connection_find_ex);
APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn);
APR_REGISTER_OPTIONAL_FN(uldap_cache_compare);
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid);
@@ -3232,7 +3639,7 @@
AP_DECLARE_MODULE(ldap) = {
STANDARD20_MODULE_STUFF,
util_ldap_create_dir_config, /* create dir config */
- NULL, /* merge dir config */
+ util_ldap_merge_dir_config, /* merge dir config */
util_ldap_create_config, /* create server config */
util_ldap_merge_config, /* merge server config */
util_ldap_cmds, /* command table */