You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2023/12/02 09:52:54 UTC
svn commit: r1914282 - /httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch
Author: minfrin
Date: Sat Dec 2 09:52:54 2023
New Revision: 1914282
URL: http://svn.apache.org/viewvc?rev=1914282&view=rev
Log:
Update proposal with r1914281.
Added:
httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch
Added: httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch
URL: http://svn.apache.org/viewvc/httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch?rev=1914282&view=auto
==============================================================================
--- httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch (added)
+++ httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch Sat Dec 2 09:52:54 2023
@@ -0,0 +1,631 @@
+Index: changes-entries/ldap-search.txt
+===================================================================
+--- changes-entries/ldap-search.txt (nonexistent)
++++ changes-entries/ldap-search.txt (working copy)
+@@ -0,0 +1,12 @@
++ *) Add the ldap-search option to mod_authnz_ldap, allowing authorization
++ to be based on arbitrary expressions that do not include the username.
++ Make sure that when ldap searches are too long, we explicitly log the
++ error. [Graham Leggett]
++
++
++ *) Add the ldap-search option to mod_authnz_ldap, allowing authorization
++ to be based on arbitrary expressions that do not include the username.
++ Make sure that when ldap searches are too long, we explicitly log the
++ error. [Graham Leggett]
++
++
+Index: docs/manual/expr.xml
+===================================================================
+--- docs/manual/expr.xml (revision 1914280)
++++ docs/manual/expr.xml (working copy)
+@@ -61,6 +61,7 @@
+ <seealso><a href="mod/mod_authnz_ldap.html#reqdn">Require ldap-dn</a></seealso>
+ <seealso><a href="mod/mod_authnz_ldap.html#reqattribute">Require ldap-attribute</a></seealso>
+ <seealso><a href="mod/mod_authnz_ldap.html#reqfilter">Require ldap-filter</a></seealso>
++<seealso><a href="mod/mod_authnz_ldap.html#reqsearch">Require ldap-search</a></seealso>
+ <seealso><a href="mod/mod_authz_dbd.html#reqgroup">Require dbd-group</a></seealso>
+ <seealso><a href="mod/mod_authz_dbm.html#reqgroup">Require dbm-group</a></seealso>
+ <seealso><a href="mod/mod_authz_groupfile.html#reqgroup">Require group</a></seealso>
+Index: docs/manual/mod/mod_authnz_ldap.xml
+===================================================================
+--- docs/manual/mod/mod_authnz_ldap.xml (revision 1914280)
++++ docs/manual/mod/mod_authnz_ldap.xml (working copy)
+@@ -89,6 +89,7 @@
+ <li><a href="#reqdn">Require ldap-dn</a></li>
+ <li><a href="#reqattribute">Require ldap-attribute</a></li>
+ <li><a href="#reqfilter">Require ldap-filter</a></li>
++ <li><a href="#reqsearch">Require ldap-search</a></li>
+ </ul>
+ </li>
+
+@@ -234,6 +235,11 @@
+ directive, and the search filter successfully finds a single user
+ object that matches the dn of the authenticated user.</li>
+
++ <li>Grant access if there is a <a href="#reqsearch">
++ <code>Require ldap-search</code></a>
++ directive, and the search filter successfully returns a single
++ matching object with any distinguished name.</li>
++
+ <li>otherwise, deny or decline access</li>
+ </ul>
+
+@@ -531,8 +537,30 @@
+
+ </section>
+
++<section id="reqsearch"><title>Require ldap-search</title>
++
++ <p>The <code>Require ldap-search</code> directive allows the
++ administrator to grant access based on a generic LDAP search filter using an
++ <a href="../expr.html">expression</a>. If there is exactly one match to the search filter,
++ regardless of the distinguished name, access is granted.</p>
++
++ <p>The following directive would grant access to URLs that match the given objects in the
++ LDAP server:</p>
++
++<highlight language="config">
++<LocationMatch ^/dav/(?<SITENAME>[^/]+)/>
++Require ldap-search (cn=%{ldap:%{unescape:%{env:MATCH_SITENAME}} Website)
++</LocationMatch>
++</highlight>
++
++ <p>Note: care must be taken to ensure that any expressions are properly escaped to guard
++ against LDAP injection. The <strong>ldap</strong> function can be used as per the example
++ above.</p>
++
+ </section>
+
++</section>
++
+ <section id="examples"><title>Examples</title>
+
+ <ul>
+Index: modules/aaa/mod_authnz_ldap.c
+===================================================================
+--- modules/aaa/mod_authnz_ldap.c (revision 1914280)
++++ modules/aaa/mod_authnz_ldap.c (working copy)
+@@ -84,10 +84,10 @@
+ } authn_ldap_config_t;
+
+ typedef struct {
+- char *dn; /* The saved dn from a successful search */
+- char *user; /* The username provided by the client */
++ const char *dn; /* The saved dn from a successful search */
++ const char *user; /* The username provided by the client */
+ const char **vals; /* The additional values pulled during the DN search*/
+- char *password; /* if this module successfully authenticates, the basic auth password, else null */
++ const char *password; /* if this module successfully authenticates, the basic auth password, else null */
+ } authn_ldap_request_t;
+
+ enum auth_ldap_phase {
+@@ -192,11 +192,8 @@
+
+ /*
+ * Build the search filter, or at least as much of the search filter that
+- * will fit in the buffer. We don't worry about the buffer not being able
+- * to hold the entire filter. If the buffer wasn't big enough to hold the
+- * filter, ldap_search_s will complain, but the only situation where this
+- * is likely to happen is if the client sent a really, really long
+- * username, most likely as part of an attack.
++ * will fit in the buffer, and return APR_EGENERAL if it won't fit, otherwise
++ * APR_SUCCESS.
+ *
+ * The search filter consists of the filter provided with the URL,
+ * combined with a filter made up of the attribute provided with the URL,
+@@ -209,32 +206,25 @@
+ * search filter will be (&(posixid=*)(uid=userj)).
+ */
+ #define FILTER_LENGTH MAX_STRING_LEN
+-static void authn_ldap_build_filter(char *filtbuf,
++static apr_status_t authn_ldap_build_filter(char filtbuf[FILTER_LENGTH],
+ request_rec *r,
+- const char* sent_user,
+- const char* sent_filter,
++ const char *user,
++ const char *filter,
+ authn_ldap_config_t *sec)
+ {
+- char *p, *q, *filtbuf_end;
+- char *user, *filter;
++ char *q;
++ const char *p, *filtbuf_end;
+ apr_xlate_t *convset = NULL;
+ apr_size_t inbytes;
+ apr_size_t outbytes;
+ char *outbuf;
+- int nofilter = 0;
++ int nofilter = 0, len;
++ apr_status_t rv = APR_SUCCESS;
+
+- if (sent_user != NULL) {
+- user = apr_pstrdup (r->pool, sent_user);
++ if (!filter) {
++ filter = sec->filter;
+ }
+- else
+- return;
+
+- if (sent_filter != NULL) {
+- filter = apr_pstrdup (r->pool, sent_filter);
+- }
+- else
+- filter = sec->filter;
+-
+ if (charset_conversions) {
+ convset = get_conv_set(r);
+ }
+@@ -246,7 +236,7 @@
+
+ /* Convert the user name to UTF-8. This is only valid for LDAP v3 */
+ if (apr_xlate_conv_buffer(convset, user, &inbytes, outbuf, &outbytes) == APR_SUCCESS) {
+- user = apr_pstrdup(r->pool, outbuf);
++ user = outbuf;
+ }
+ }
+
+@@ -255,11 +245,11 @@
+ * config-supplied portions.
+ */
+
+- if ((nofilter = (filter && !strcasecmp(filter, "none")))) {
+- apr_snprintf(filtbuf, FILTER_LENGTH, "(%s=", sec->attribute);
++ if ((nofilter = (!filter || !*filter || !strcasecmp(filter, "none")))) {
++ len = apr_snprintf(filtbuf, FILTER_LENGTH, "(%s=", sec->attribute);
+ }
+ else {
+- apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute);
++ len = apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute);
+ }
+
+ /*
+@@ -267,12 +257,13 @@
+ * LDAP filter metachars are escaped.
+ */
+ filtbuf_end = filtbuf + FILTER_LENGTH - 1;
++ for (p = user, q = filtbuf + len; *p; ) {
++ if (strchr("*()\\", *p) != NULL) {
+ #if APR_HAS_MICROSOFT_LDAPSDK
+- for (p = user, q=filtbuf + strlen(filtbuf);
+- *p && q < filtbuf_end; ) {
+- if (strchr("*()\\", *p) != NULL) {
+- if ( q + 3 >= filtbuf_end)
+- break; /* Don't write part of escape sequence if we can't write all of it */
++ if (q + 3 >= filtbuf_end) { /* accounts for final \0 */
++ rv = APR_EGENERAL;
++ goto out;
++ }
+ *q++ = '\\';
+ switch ( *p++ )
+ {
+@@ -292,23 +283,24 @@
+ *q++ = '5';
+ *q++ = 'c';
+ break;
+- }
+- }
+- else
+- *q++ = *p++;
+- }
++ }
+ #else
+- for (p = user, q=filtbuf + strlen(filtbuf);
+- *p && q < filtbuf_end; *q++ = *p++) {
+- if (strchr("*()\\", *p) != NULL) {
++ if (q + 2 >= filtbuf_end) { /* accounts for final \0 */
++ rv = APR_EGENERAL;
++ goto out;
++ }
+ *q++ = '\\';
+- if (q >= filtbuf_end) {
+- break;
++ *q++ = *p++;
++#endif
++ }
++ else {
++ if (q + 1 >= filtbuf_end) { /* accounts for final \0 */
++ rv = APR_EGENERAL;
++ goto out;
+ }
++ *q++ = *p++;
+ }
+ }
+-#endif
+- *q = '\0';
+
+ /*
+ * Append the closing parens of the filter, unless doing so would
+@@ -316,14 +308,24 @@
+ */
+
+ if (nofilter) {
+- if (q + 1 <= filtbuf_end)
+- strcat(filtbuf, ")");
++ if (q + 1 >= filtbuf_end) { /* accounts for final \0 */
++ rv = APR_EGENERAL;
++ goto out;
++ }
++ *q++ = ')';
+ }
+ else {
+- if (q + 2 <= filtbuf_end)
+- strcat(filtbuf, "))");
++ if (q + 2 >= filtbuf_end) { /* accounts for final \0 */
++ rv = APR_EGENERAL;
++ goto out;
++ }
++ *q++ = ')';
++ *q++ = ')';
+ }
+
++out:
++ *q = '\0';
++ return rv;
+ }
+
+ static void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d)
+@@ -371,15 +373,12 @@
+ return APR_SUCCESS;
+ }
+
+-static int set_request_vars(request_rec *r, enum auth_ldap_phase phase) {
++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;
+- 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 **vals = req->vals;
+
+ prefix = (phase == LDAP_AUTHN) ? AUTHN_PREFIX : sec->authz_prefix;
+ prefix_len = strlen(prefix);
+@@ -441,8 +440,8 @@
+ authn_ldap_config_t *sec =
+ (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module);
+
+- char *binddn = sec->binddn;
+- char *bindpw = sec->bindpw;
++ 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 &&
+@@ -549,7 +548,13 @@
+ "auth_ldap authenticate: using URL %s", sec->url);
+
+ /* build the username filter */
+- authn_ldap_build_filter(filtbuf, r, user, NULL, sec);
++ if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, user, NULL, sec)) {
++ 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);
++ return AUTH_GENERAL_ERROR;
++ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "auth_ldap authenticate: final authn filter is %s", filtbuf);
+@@ -606,15 +611,15 @@
+ }
+
+ /* mark the user and DN */
+- req->dn = apr_pstrdup(r->pool, dn);
+- req->user = apr_pstrdup(r->pool, user);
+- req->password = apr_pstrdup(r->pool, password);
++ req->dn = dn;
++ req->user = user;
++ req->password = password;
+ if (sec->user_is_dn) {
+- r->user = req->dn;
++ r->user = (char *)req->dn;
+ }
+
+ /* add environment variables */
+- remote_user_attribute_set = set_request_vars(r, LDAP_AUTHN);
++ remote_user_attribute_set = set_request_vars(r, LDAP_AUTHN, req->vals);
+
+ /* sanity check */
+ if (sec->remote_user_attribute && !remote_user_attribute_set) {
+@@ -696,7 +701,12 @@
+ sizeof(authn_ldap_request_t));
+
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
++ 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,
+@@ -710,7 +720,7 @@
+ }
+
+ ap_set_module_config(r->request_config, &authnz_ldap_module, req);
+- req->dn = apr_pstrdup(r->pool, dn);
++ req->dn = dn;
+ req->user = r->user;
+
+ }
+@@ -740,7 +750,7 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01703)
+ "auth_ldap authorize: require user: authorization "
+ "successful");
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ default: {
+@@ -762,7 +772,7 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01705)
+ "auth_ldap authorize: "
+ "require user: authorization successful");
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ default: {
+@@ -880,7 +890,12 @@
+ req = (authn_ldap_request_t *)apr_pcalloc(r->pool,
+ sizeof(authn_ldap_request_t));
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
++ 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,
+@@ -894,7 +909,7 @@
+ }
+
+ ap_set_module_config(r->request_config, &authnz_ldap_module, req);
+- req->dn = apr_pstrdup(r->pool, dn);
++ req->dn = dn;
+ req->user = r->user;
+ }
+
+@@ -949,7 +964,7 @@
+ "[%s][%d - %s]",
+ ent[i].name, ldc->reason, result,
+ ldap_err2string(result));
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ else {
+@@ -988,7 +1003,7 @@
+ "(attribute %s) [%s][%d - %s]",
+ ent[i].name, ldc->reason, result,
+ ldap_err2string(result));
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ else {
+@@ -1069,7 +1084,12 @@
+ req = (authn_ldap_request_t *)apr_pcalloc(r->pool,
+ sizeof(authn_ldap_request_t));
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
++ 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;
++ }
+
+ /* Search for the user DN */
+ result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
+@@ -1083,7 +1103,7 @@
+ }
+
+ ap_set_module_config(r->request_config, &authnz_ldap_module, req);
+- req->dn = apr_pstrdup(r->pool, dn);
++ req->dn = dn;
+ req->user = r->user;
+ }
+
+@@ -1110,7 +1130,7 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01726)
+ "auth_ldap authorize: "
+ "require dn: authorization successful");
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ default: {
+@@ -1191,7 +1211,12 @@
+ req = (authn_ldap_request_t *)apr_pcalloc(r->pool,
+ sizeof(authn_ldap_request_t));
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
++ 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;
++ }
+
+ /* Search for the user DN */
+ result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
+@@ -1205,7 +1230,7 @@
+ }
+
+ ap_set_module_config(r->request_config, &authnz_ldap_module, req);
+- req->dn = apr_pstrdup(r->pool, dn);
++ req->dn = dn;
+ req->user = r->user;
+ }
+
+@@ -1239,7 +1264,7 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01735)
+ "auth_ldap authorize: "
+ "require attribute: authorization successful");
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ default: {
+@@ -1319,7 +1344,12 @@
+ req = (authn_ldap_request_t *)apr_pcalloc(r->pool,
+ sizeof(authn_ldap_request_t));
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
++ 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;
++ }
+
+ /* Search for the user DN */
+ result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
+@@ -1333,7 +1363,7 @@
+ }
+
+ ap_set_module_config(r->request_config, &authnz_ldap_module, req);
+- req->dn = apr_pstrdup(r->pool, dn);
++ req->dn = dn;
+ req->user = r->user;
+ }
+
+@@ -1359,7 +1389,12 @@
+ "auth_ldap authorize: checking filter %s", t);
+
+ /* Build the username filter */
+- authn_ldap_build_filter(filtbuf, r, req->user, t, sec);
++ if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, req->user, t, sec)) {
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02628)
++ "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,
+@@ -1384,7 +1419,7 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01745)
+ "auth_ldap authorize: require ldap-filter: "
+ "authorization successful");
+- set_request_vars(r, LDAP_AUTHZ);
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
+ return AUTHZ_GRANTED;
+ }
+ case LDAP_FILTER_ERROR: {
+@@ -1411,6 +1446,83 @@
+ return AUTHZ_DENIED;
+ }
+
++static authz_status ldapsearch_check_authorization(request_rec *r,
++ const char *require_args,
++ const void *parsed_require_args)
++{
++ int result = 0;
++ 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 *err = NULL;
++ const ap_expr_info_t *expr = parsed_require_args;
++ const char *require;
++ const char *t;
++ const char *dn = NULL;
++
++ if (!sec->have_ldap_url) {
++ 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)
++ "auth_ldap authorize: no sec->host - weird...?");
++ return AUTHZ_DENIED;
++ }
++
++ require = ap_expr_str_exec(r, expr, &err);
++ if (err) {
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02629)
++ "auth_ldap authorize: require ldap-search: Can't "
++ "evaluate require expression: %s", err);
++ return AUTHZ_DENIED;
++ }
++
++ t = require;
++
++ if (t[0]) {
++
++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02630)
++ "auth_ldap authorize: checking filter %s", t);
++
++ /* Search for the user DN */
++ result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
++ sec->scope, sec->attributes, t, &dn, &(req->vals));
++
++ /* Make sure that the filtered search returned a single dn */
++ if (result == LDAP_SUCCESS && dn) {
++ req->dn = dn;
++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02631)
++ "auth_ldap authorize: require ldap-search: "
++ "authorization successful");
++ set_request_vars(r, LDAP_AUTHZ, req->vals);
++ return AUTHZ_GRANTED;
++ }
++ else {
++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02632)
++ "auth_ldap authorize: require ldap-search: "
++ "%s authorization failed [%s][%s]",
++ t, ldc->reason, ldap_err2string(result));
++ }
++ }
++
++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02633)
++ "auth_ldap authorize search: authorization denied for "
++ "to %s", r->uri);
++
++ return AUTHZ_DENIED;
++}
++
+ static const char *ldap_parse_config(cmd_parms *cmd, const char *require_line,
+ const void **parsed_require_line)
+ {
+@@ -1919,6 +2031,12 @@
+ &ldap_parse_config,
+ };
+
++static const authz_provider authz_ldapsearch_provider =
++{
++ &ldapsearch_check_authorization,
++ &ldap_parse_config,
++};
++
+ static void ImportULDAPOptFn(void)
+ {
+ util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close);
+@@ -1959,6 +2077,10 @@
+ AUTHZ_PROVIDER_VERSION,
+ &authz_ldapfilter_provider,
+ AP_AUTH_INTERNAL_PER_CONF);
++ ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ldap-search",
++ AUTHZ_PROVIDER_VERSION,
++ &authz_ldapsearch_provider,
++ AP_AUTH_INTERNAL_PER_CONF);
+
+ ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE);
+