diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index d5b8b80c4f7..5e9d611fc89 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -88,6 +88,7 @@ typedef struct { const char *user; /* The username provided by the client */ const char **vals; /* The additional values pulled during the DN search*/ const char *password; /* if this module successfully authenticates, the basic auth password, else null */ + apr_pool_t *ldc_pool; /* a short-lived pool to trigger cleanups on any acquired LDCs */ } authn_ldap_request_t; enum auth_ldap_phase { @@ -115,7 +116,6 @@ static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported; static apr_hash_t *charset_conversions = NULL; static char *to_charset = NULL; /* UTF-8 identifier derived from the charset.conv file */ - /* Derive a code page ID give a language name or ID */ static char* derive_codepage_from_lang (apr_pool_t *p, char *language) { @@ -369,11 +369,13 @@ static void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d) static apr_status_t authnz_ldap_cleanup_connection_close(void *param) { util_ldap_connection_t *ldc = param; + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, ldc->r, "Release ldc %pp", ldc); util_ldap_connection_close(ldc); return APR_SUCCESS; } -static int set_request_vars(request_rec *r, enum auth_ldap_phase phase, const char **vals) { +static int set_request_vars(request_rec *r, enum auth_ldap_phase phase, const char **vals) +{ char *prefix = NULL; int prefix_len; int remote_user_attribute_set = 0; @@ -408,7 +410,8 @@ static int set_request_vars(request_rec *r, enum auth_ldap_phase phase, const ch return remote_user_attribute_set; } -static const char *ldap_determine_binddn(request_rec *r, const char *user) { +static const char *ldap_determine_binddn(request_rec *r, const char *user) +{ authn_ldap_config_t *sec = (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); const char *result = user; @@ -431,31 +434,74 @@ static const char *ldap_determine_binddn(request_rec *r, const char *user) { } -/* Some LDAP servers restrict who can search or compare, and the hard-coded ID - * might be good for the DN lookup but not for later operations. +/** + * Some LDAP servers restrict who can search or compare, and the hard-coded ID + * might be good for the DN lookup but not for later operations. + * Requires the per-request config be set to ensure the connection is cleaned up */ -static util_ldap_connection_t *get_connection_for_authz(request_rec *r, enum auth_ldap_optype type) { +static util_ldap_connection_t *get_connection_for_authz(request_rec *r, enum auth_ldap_optype type) +{ authn_ldap_request_t *req = (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); authn_ldap_config_t *sec = (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); + util_ldap_connection_t *ldc = NULL; const char *binddn = sec->binddn; const char *bindpw = sec->bindpw; - /* If the per-request config isn't set, we didn't authenticate this user, and leave the default credentials */ - if (req && req->password && + if (!req) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02659) + "module error: get_connection_for_authz without " + "per-request config"); + return NULL; + } + + /* If the password isn't set in the per-request config, we didn't + * authenticate this user, and leave the default credentials */ + if (req->password && ((type == LDAP_SEARCH && sec->search_as_user) || (type == LDAP_COMPARE && sec->compare_as_user) || - (type == LDAP_COMPARE_AND_SEARCH && sec->compare_as_user && sec->search_as_user))){ + (type == LDAP_COMPARE_AND_SEARCH && sec->compare_as_user && sec->search_as_user))) { binddn = req->dn; bindpw = req->password; } - return util_ldap_connection_find(r, sec->host, sec->port, + ldc = util_ldap_connection_find(r, sec->host, sec->port, binddn, bindpw, sec->deref, sec->secure); + + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "Obtain ldc %pp for authz", ldc); + apr_pool_cleanup_register(req->ldc_pool, ldc, + authnz_ldap_cleanup_connection_close, + apr_pool_cleanup_null); + return ldc; +} + + +static authn_ldap_request_t* build_request_config(request_rec *r) +{ + authn_ldap_request_t *req = + (authn_ldap_request_t *)apr_pcalloc(r->pool, sizeof(authn_ldap_request_t)); + ap_set_module_config(r->request_config, &authnz_ldap_module, req); + apr_pool_create(&(req->ldc_pool), r->pool); + apr_pool_tag(req->ldc_pool, "authn_ldap_req_ldc"); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01740) + "ldap authorize: Creating LDAP req structure"); + return req; } + +static void release_ldc(request_rec *r, util_ldap_connection_t *ldc) +{ + authn_ldap_request_t *req = + (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); + + if (req) { + apr_pool_cleanup_kill(req->ldc_pool, ldc, authnz_ldap_cleanup_connection_close); + } + authnz_ldap_cleanup_connection_close(ldc); +} + /* * Authentication Phase * -------------------- @@ -474,14 +520,12 @@ static authn_status authn_ldap_check_password(request_rec *r, const char *user, (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); util_ldap_connection_t *ldc = NULL; + authn_ldap_request_t *req = NULL; int result = 0; int remote_user_attribute_set = 0; const char *dn = NULL; const char *utfpassword; - authn_ldap_request_t *req = - (authn_ldap_request_t *)apr_pcalloc(r->pool, sizeof(authn_ldap_request_t)); - ap_set_module_config(r->request_config, &authnz_ldap_module, req); /* if (!sec->enabled) { @@ -534,6 +578,7 @@ static authn_status authn_ldap_check_password(request_rec *r, const char *user, binddn = ldap_determine_binddn(r, user); } + req = build_request_config(r); ldc = util_ldap_connection_find(r, sec->host, sec->port, binddn, bindpw, sec->deref, sec->secure); @@ -552,7 +597,7 @@ static authn_status authn_ldap_check_password(request_rec *r, const char *user, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02622) "auth_ldap authenticate: ldap filter too long (>%d): %s", FILTER_LENGTH, filtbuf); - util_ldap_connection_close(ldc); + release_ldc(r, ldc); return AUTH_GENERAL_ERROR; } @@ -566,7 +611,7 @@ static authn_status authn_ldap_check_password(request_rec *r, const char *user, result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope, sec->attributes, filtbuf, utfpassword, &dn, &(req->vals)); - util_ldap_connection_close(ldc); + release_ldc(r, ldc); /* handle bind failure */ if (result != LDAP_SUCCESS) { @@ -638,6 +683,56 @@ static authn_status authn_ldap_check_password(request_rec *r, const char *user, return AUTH_GRANTED; } +static authz_status get_dn_for_nonldap_authn(request_rec *r, util_ldap_connection_t *ldc) +{ + apr_status_t result = APR_SUCCESS; + char filtbuf[FILTER_LENGTH]; + authn_ldap_request_t *req = + (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); + authn_ldap_config_t *sec = + (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); + const char *dn = NULL; + int remote_user_attribute_set = 0; + + /* Build the username filter */ + if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02623) + "auth_ldap authorize: ldap filter too long (>%d): %s", + FILTER_LENGTH, filtbuf); + return AUTHZ_DENIED; + } + + /* Search for the user DN */ + result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, + sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); + + /* Search failed, log error and return failure */ + if (result != LDAP_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01701) + "auth_ldap authorise: User DN not found, %s", ldc->reason); + return AUTHZ_DENIED; + } + + req->dn = dn; + req->user = r->user; + + /* add environment variables */ + remote_user_attribute_set = set_request_vars(r, LDAP_AUTHN, req->vals); + + /* sanity check */ + if (sec->remote_user_attribute && !remote_user_attribute_set) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10450) + "auth_ldap non-ldap authenticate: " + "REMOTE_USER was to be set with attribute '%s', " + "but this attribute was not requested for in the " + "LDAP query for the user. REMOTE_USER will fall " + "back to username or DN as appropriate.", + sec->remote_user_attribute); + } + + return AUTHZ_GRANTED; +} + static authz_status ldapuser_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args) @@ -657,8 +752,6 @@ static authz_status ldapuser_check_authorization(request_rec *r, const char *t; char *w; - char filtbuf[FILTER_LENGTH]; - const char *dn = NULL; if (!r->user) { return AUTHZ_DENIED_NO_USER; @@ -668,13 +761,7 @@ static authz_status ldapuser_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_COMPARE); - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { + if (!sec->host) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01698) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; @@ -685,47 +772,23 @@ static authz_status ldapuser_check_authorization(request_rec *r, * the req structure needed for authorization needs to be created * and populated with the userid and DN of the account in LDAP */ - - - if (!strlen(r->user)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01699) - "ldap authorize: Userid is blank, AuthType=%s", - r->ap_auth_type); - } - - if(!req) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01700) - "ldap authorize: Creating LDAP req structure"); - - req = (authn_ldap_request_t *)apr_pcalloc(r->pool, - sizeof(authn_ldap_request_t)); - - /* Build the username filter */ - if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02623) - "auth_ldap authorize: ldap filter too long (>%d): %s", - FILTER_LENGTH, filtbuf); - return AUTHZ_DENIED; + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_COMPARE); + if (!req->dn) { + authz_status rv; + if (!*r->user) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01699) + "ldap authorize: Userid is blank, AuthType=%s", + r->ap_auth_type); } - - /* Search for the user DN */ - result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, - sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); - - /* Search failed, log error and return failure */ - if(result != LDAP_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01701) - "auth_ldap authorise: User DN not found, %s", ldc->reason); - return AUTHZ_DENIED; + rv = get_dn_for_nonldap_authn(r, ldc); + if (rv != AUTHZ_GRANTED) { + return rv; } - - ap_set_module_config(r->request_config, &authnz_ldap_module, req); - req->dn = dn; - req->user = r->user; - } - - if (req->dn == NULL || strlen(req->dn) == 0) { + if (req->dn == NULL || !*req->dn) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01702) "auth_ldap authorize: require user: user's DN has not " "been defined; failing authorization"); @@ -810,8 +873,6 @@ static authz_status ldapgroup_check_authorization(request_rec *r, const char *t; - char filtbuf[FILTER_LENGTH]; - const char *dn = NULL; struct mod_auth_ldap_groupattr_entry_t *ent; int i; @@ -823,18 +884,34 @@ static authz_status ldapgroup_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_COMPARE); /* for the top-level group only */ - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { + if (!sec->host) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01708) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; } + /* + * If we have been authenticated by some other module than mod_authnz_ldap, + * the req structure needed for authorization needs to be created + * and populated with the userid and DN of the account in LDAP + */ + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_COMPARE); + if (!req->dn) { + authz_status rv; + if (!*r->user) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10490) + "ldap authorize: Userid is blank, AuthType=%s", + r->ap_auth_type); + } + rv = get_dn_for_nonldap_authn(r, ldc); + if (rv != AUTHZ_GRANTED) { + return rv; + } + } + /* * If there are no elements in the group attribute array, the default should be * member and uniquemember; populate the array now. @@ -877,46 +954,17 @@ static authz_status ldapgroup_check_authorization(request_rec *r, * and populated with the userid and DN of the account in LDAP */ - if (!strlen(r->user)) { + if (!*r->user) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01709) "ldap authorize: Userid is blank, AuthType=%s", r->ap_auth_type); } - if(!req) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01710) - "ldap authorize: Creating LDAP req structure"); - - req = (authn_ldap_request_t *)apr_pcalloc(r->pool, - sizeof(authn_ldap_request_t)); - /* Build the username filter */ - if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02624) - "auth_ldap authorize: ldap filter too long (>%d): %s", - FILTER_LENGTH, filtbuf); - return AUTHZ_DENIED; - } - - /* Search for the user DN */ - result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, - sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); - - /* Search failed, log error and return failure */ - if(result != LDAP_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01711) - "auth_ldap authorise: User DN not found, %s", ldc->reason); - return AUTHZ_DENIED; - } - - ap_set_module_config(r->request_config, &authnz_ldap_module, req); - req->dn = dn; - req->user = r->user; - } - + ent = (struct mod_auth_ldap_groupattr_entry_t *) sec->groupattr->elts; if (sec->group_attrib_is_dn) { - if (req->dn == NULL || strlen(req->dn) == 0) { + if (req->dn == NULL || !*req->dn) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01712) "auth_ldap authorize: require group: user's DN has " "not been defined; failing authorization for user %s", @@ -925,7 +973,7 @@ static authz_status ldapgroup_check_authorization(request_rec *r, } } else { - if (req->user == NULL || strlen(req->user) == 0) { + if (req->user == NULL || !*req->user) { /* We weren't called in the authentication phase, so we didn't have a * chance to set the user field. Do so now. */ req->user = r->user; @@ -976,21 +1024,18 @@ static authz_status ldapgroup_check_authorization(request_rec *r, } } - for (i = 0; i < sec->groupattr->nelts; i++) { - /* nested groups need searches and compares, so grab a new handle */ - authnz_ldap_cleanup_connection_close(ldc); - apr_pool_cleanup_kill(r->pool, ldc,authnz_ldap_cleanup_connection_close); - + /* nested groups need searches and compares, so grab a new handle */ + if (sec->groupattr->nelts > 0) { + release_ldc(r, ldc); ldc = get_connection_for_authz(r, LDAP_COMPARE_AND_SEARCH); - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01716) - "auth_ldap authorise: require group \"%s\": " - "failed [%s][%d - %s], checking sub-groups", - t, ldc->reason, result, ldap_err2string(result)); + "auth_ldap authorise: require group \"%s\": " + "failed [%s][%d - %s], checking sub-groups", + t, ldc->reason, result, ldap_err2string(result)); + } + + for (i = 0; i < sec->groupattr->nelts; i++) { result = util_ldap_cache_check_subgroups(r, ldc, sec->url, t, ent[i].name, sec->group_attrib_is_dn ? req->dn : req->user, sec->sgAttributes[0] ? sec->sgAttributes : default_attributes, @@ -1042,9 +1087,6 @@ static authz_status ldapdn_check_authorization(request_rec *r, const char *t; - char filtbuf[FILTER_LENGTH]; - const char *dn = NULL; - if (!r->user) { return AUTHZ_DENIED_NO_USER; } @@ -1053,13 +1095,7 @@ static authz_status ldapdn_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_SEARCH); /* _comparedn is a searche */ - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { + if (!sec->host) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01721) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; @@ -1070,41 +1106,21 @@ static authz_status ldapdn_check_authorization(request_rec *r, * the req structure needed for authorization needs to be created * and populated with the userid and DN of the account in LDAP */ - - if (!strlen(r->user)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01722) - "ldap authorize: Userid is blank, AuthType=%s", - r->ap_auth_type); - } - - if(!req) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01723) - "ldap authorize: Creating LDAP req structure"); - - req = (authn_ldap_request_t *)apr_pcalloc(r->pool, - sizeof(authn_ldap_request_t)); - /* Build the username filter */ - if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02625) - "auth_ldap authorize: ldap filter too long (>%d): %s", - FILTER_LENGTH, filtbuf); - return AUTHZ_DENIED; + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_SEARCH); /* comparedn is a search */ + if (!req->dn) { + authz_status rv; + if (!*r->user) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01722) + "ldap authorize: Userid is blank, AuthType=%s", + r->ap_auth_type); } - - /* Search for the user DN */ - result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, - sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); - - /* Search failed, log error and return failure */ - if(result != LDAP_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01724) - "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason); - return AUTHZ_DENIED; + rv = get_dn_for_nonldap_authn(r, ldc); + if (rv != AUTHZ_GRANTED) { + return rv; } - - ap_set_module_config(r->request_config, &authnz_ldap_module, req); - req->dn = dn; - req->user = r->user; } require = ap_expr_str_exec(r, expr, &err); @@ -1117,7 +1133,7 @@ static authz_status ldapdn_check_authorization(request_rec *r, t = require; - if (req->dn == NULL || strlen(req->dn) == 0) { + if (req->dn == NULL || !*req->dn) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01725) "auth_ldap authorize: require dn: user's DN has not " "been defined; failing authorization"); @@ -1169,9 +1185,6 @@ static authz_status ldapattribute_check_authorization(request_rec *r, const char *t; char *w, *value; - char filtbuf[FILTER_LENGTH]; - const char *dn = NULL; - if (!r->user) { return AUTHZ_DENIED_NO_USER; } @@ -1180,13 +1193,7 @@ static authz_status ldapattribute_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_COMPARE); - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { + if (!sec->host) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01729) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; @@ -1197,44 +1204,23 @@ static authz_status ldapattribute_check_authorization(request_rec *r, * the req structure needed for authorization needs to be created * and populated with the userid and DN of the account in LDAP */ - - if (!strlen(r->user)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01730) - "ldap authorize: Userid is blank, AuthType=%s", - r->ap_auth_type); - } - - if(!req) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01731) - "ldap authorize: Creating LDAP req structure"); - - req = (authn_ldap_request_t *)apr_pcalloc(r->pool, - sizeof(authn_ldap_request_t)); - /* Build the username filter */ - if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02626) - "auth_ldap authorize: ldap filter too long (>%d): %s", - FILTER_LENGTH, filtbuf); - return AUTHZ_DENIED; + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_COMPARE); + if (!req->dn) { + authz_status rv; + if (!*r->user) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01730) + "ldap authorize: Userid is blank, AuthType=%s", + r->ap_auth_type); } - - /* Search for the user DN */ - result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, - sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); - - /* Search failed, log error and return failure */ - if(result != LDAP_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01732) - "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason); - return AUTHZ_DENIED; + rv = get_dn_for_nonldap_authn(r, ldc); + if (rv != AUTHZ_GRANTED) { + return rv; } - - ap_set_module_config(r->request_config, &authnz_ldap_module, req); - req->dn = dn; - req->user = r->user; } - - if (req->dn == NULL || strlen(req->dn) == 0) { + if (req->dn == NULL || !*req->dn) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01733) "auth_ldap authorize: require ldap-attribute: user's DN " "has not been defined; failing authorization"); @@ -1313,13 +1299,7 @@ static authz_status ldapfilter_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_SEARCH); - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { + if (!sec->host) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01738) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; @@ -1330,44 +1310,23 @@ static authz_status ldapfilter_check_authorization(request_rec *r, * the req structure needed for authorization needs to be created * and populated with the userid and DN of the account in LDAP */ - - if (!strlen(r->user)) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01739) - "ldap authorize: Userid is blank, AuthType=%s", - r->ap_auth_type); - } - - if(!req) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01740) - "ldap authorize: Creating LDAP req structure"); - - req = (authn_ldap_request_t *)apr_pcalloc(r->pool, - sizeof(authn_ldap_request_t)); - /* Build the username filter */ - if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02627) - "auth_ldap authorize: ldap filter too long (>%d): %s", - FILTER_LENGTH, filtbuf); - return AUTHZ_DENIED; + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_SEARCH); + if (!req->dn) { + authz_status rv; + if (!*r->user) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01739) + "ldap authorize: Userid is blank, AuthType=%s", + r->ap_auth_type); } - - /* Search for the user DN */ - result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, - sec->scope, sec->attributes, filtbuf, &dn, &(req->vals)); - - /* Search failed, log error and return failure */ - if(result != LDAP_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01741) - "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason); - return AUTHZ_DENIED; + rv = get_dn_for_nonldap_authn(r, ldc); + if (rv != AUTHZ_GRANTED) { + return rv; } - - ap_set_module_config(r->request_config, &authnz_ldap_module, req); - req->dn = dn; - req->user = r->user; } - - if (req->dn == NULL || strlen(req->dn) == 0) { + if (req->dn == NULL || !*req->dn) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01742) "auth_ldap authorize: require ldap-filter: user's DN " "has not been defined; failing authorization"); @@ -1406,8 +1365,7 @@ static authz_status ldapfilter_check_authorization(request_rec *r, "auth_ldap authorize: checking dn match %s", dn); if (sec->compare_as_user) { /* ldap-filter is the only authz that requires a search and a compare */ - apr_pool_cleanup_kill(r->pool, ldc, authnz_ldap_cleanup_connection_close); - authnz_ldap_cleanup_connection_close(ldc); + release_ldc(r, ldc); ldc = get_connection_for_authz(r, LDAP_COMPARE); } result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn, @@ -1468,18 +1426,22 @@ static authz_status ldapsearch_check_authorization(request_rec *r, return AUTHZ_DENIED; } - if (sec->host) { - ldc = get_connection_for_authz(r, LDAP_SEARCH); - apr_pool_cleanup_register(r->pool, ldc, - authnz_ldap_cleanup_connection_close, - apr_pool_cleanup_null); - } - else { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02636) + if (!sec->host) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10486) "auth_ldap authorize: no sec->host - weird...?"); return AUTHZ_DENIED; } + /* + * If we have been authenticated by some other module than mod_auth_ldap, + * the req structure needed for authorization needs to be created + * and populated with the userid and DN of the account in LDAP + */ + if (!req) { + req = build_request_config(r); + } + ldc = get_connection_for_authz(r, LDAP_SEARCH); + require = ap_expr_str_exec(r, expr, &err); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02629) @@ -1681,8 +1643,7 @@ static const char *mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const c static const char *mod_auth_ldap_add_subgroup_attribute(cmd_parms *cmd, void *config, const char *arg) { - int i = 0; - + int i; authn_ldap_config_t *sec = config; for (i = 0; sec->sgAttributes[i]; i++) { @@ -2049,6 +2010,20 @@ static void ImportULDAPOptFn(void) util_ldap_cache_check_subgroups = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_check_subgroups); } + +/** Cleanup LDAP connections before EOR. Note, if the authorization is unsuccessful, + * this will not run, but EOR is unlikely to be delayed as in a successful request. + */ +static apr_status_t authnz_ldap_fixups(request_rec *r) +{ + authn_ldap_request_t *req = + (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); + if (req && req->ldc_pool) { + apr_pool_destroy(req->ldc_pool); + } + return OK; +} + static void register_hooks(apr_pool_t *p) { /* Register authn provider */ @@ -2083,6 +2058,7 @@ static void register_hooks(apr_pool_t *p) AP_AUTH_INTERNAL_PER_CONF); ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_fixups(authnz_ldap_fixups,NULL,NULL,APR_HOOK_MIDDLE); ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE); } diff --git a/test/pytest_suite/t/conf/extra.conf.in b/test/pytest_suite/t/conf/extra.conf.in index b327cccfca9..19101e4c542 100644 --- a/test/pytest_suite/t/conf/extra.conf.in +++ b/test/pytest_suite/t/conf/extra.conf.in @@ -881,6 +881,7 @@ LimitRequestFields 32 Alias /modules/ldap/simple @DocumentRoot@ Alias /modules/ldap/group @DocumentRoot@ Alias /modules/ldap/refer @DocumentRoot@ + Alias /modules/ldap/search @DocumentRoot@ # Simple user lookup @@ -913,6 +914,14 @@ LimitRequestFields 32 AuthBasicProvider ldap Require ldap-group cn=Subgroup,ou=dept,dc=example,dc=com + # ldap-search + + AuthLDAPURL "ldap://localhost:8389/dc=example,dc=com?uid" + AuthLDAPBindDN "cn=httpd,dc=example,dc=com" + AuthLDAPBindPassword mod_authnz_ldap + Require ldap-search cn=Subgroup + + ## diff --git a/test/pytest_suite/tests/t/modules/test_ldap.py b/test/pytest_suite/tests/t/modules/test_ldap.py index 242291fa6a5..c7159ed5572 100644 --- a/test/pytest_suite/tests/t/modules/test_ldap.py +++ b/test/pytest_suite/tests/t/modules/test_ldap.py @@ -26,6 +26,7 @@ ("/modules/ldap/group/", "delta", "Delta", 200), ("/modules/ldap/refer/", "alpha", "Alpha", 401), ("/modules/ldap/refer/", "beta", "Beta", 200), + ("/modules/ldap/search/", "unchecked", "unchecked", 200), ]