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);