You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by bn...@apache.org on 2004/11/10 17:35:24 UTC
cvs commit: httpd-2.0/modules/experimental NWGNUutilldap util_ldap.c util_ldap.def
bnicholes 2004/11/10 08:35:24
Modified: . Tag: APACHE_2_0_BRANCH CHANGES STATUS
include Tag: APACHE_2_0_BRANCH util_ldap.h
modules/experimental Tag: APACHE_2_0_BRANCH NWGNUutilldap
util_ldap.c util_ldap.def
Log:
Implement the util_ldap_cache_getuserdn() API so that the ldap authorization only modules have access to the util_ldap user cache without having to require ldap authentication as well. [PR 31898]
Submitted by: Jari Ahonen [jah progress.com]
Reviewed by: bnicholes, wrowe, jim
Revision Changes Path
No revision
No revision
1.988.2.379 +5 -0 httpd-2.0/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/httpd-2.0/CHANGES,v
retrieving revision 1.988.2.378
retrieving revision 1.988.2.379
diff -u -r1.988.2.378 -r1.988.2.379
--- CHANGES 10 Nov 2004 12:18:50 -0000 1.988.2.378
+++ CHANGES 10 Nov 2004 16:35:20 -0000 1.988.2.379
@@ -1,5 +1,10 @@
Changes with Apache 2.0.53
+ *) Util_ldap: Implemented the util_ldap_cache_getuserdn() API so that
+ ldap authorization only modules have access to the util_ldap
+ user cache without having to require ldap authentication as well.
+ [PR 31898] [Jari Ahonen jah progress.com, Brad Nicholes]
+
*) SECURITY: CAN-2004-0942 (cve.mitre.org)
Fix for memory consumption DoS in handling of MIME folded request
headers. [Joe Orton]
1.751.2.1146 +1 -8 httpd-2.0/STATUS
Index: STATUS
===================================================================
RCS file: /home/cvs/httpd-2.0/STATUS,v
retrieving revision 1.751.2.1145
retrieving revision 1.751.2.1146
diff -u -r1.751.2.1145 -r1.751.2.1146
--- STATUS 10 Nov 2004 13:11:39 -0000 1.751.2.1145
+++ STATUS 10 Nov 2004 16:35:21 -0000 1.751.2.1146
@@ -75,13 +75,6 @@
[ please place file names and revisions from HEAD here, so it is easy to
identify exactly what the proposed changes are! ]
- *) util_ldap: Add the util_ldap_cache_getuserdn() API to allow
- non-LDAP authentication modules the ability to use the util_ldap
- cache for authorization purposes only rather than authentication.
- PR #31898
- http://www.apache.org/~bnicholes/apache_2.0_getuserdn.patch
- +1:bnicholes, wrowe, jim
-
*) mod_authnz_ldap: Added the directive "Requires ldap-attribute" that
allows the module to only authorize a user if the attribute value
specified matches the value of the user object. PR 31913
No revision
No revision
1.9.2.10 +21 -0 httpd-2.0/include/util_ldap.h
Index: util_ldap.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/util_ldap.h,v
retrieving revision 1.9.2.9
retrieving revision 1.9.2.10
diff -u -r1.9.2.9 -r1.9.2.10
--- util_ldap.h 4 Aug 2004 21:04:16 -0000 1.9.2.9
+++ util_ldap.h 10 Nov 2004 16:35:23 -0000 1.9.2.10
@@ -260,6 +260,27 @@
const char *filter, const char *bindpw, const char **binddn, const char ***retvals);
/**
+ * Retrieves the LDAP DN of the user without the need to know user password
+ * @param r The request record
+ * @param ldc The LDAP connection being used.
+ * @param url The URL of the LDAP connection - used for deciding which cache to use.
+ * @param basedn The Base DN to search for the user in.
+ * @param scope LDAP scope of the search.
+ * @param attrs LDAP attributes to return in search.
+ * @param filter The user to search for in the form of an LDAP filter. This filter must return
+ * exactly one user for the check to be successful.
+ * @param binddn The DN of the user will be returned in this variable.
+ * @param retvals The values corresponding to the attributes requested in the attrs array.
+ * @tip The filter supplied will be searched for. A single entry matching the search is returned.
+ * @deffunc int util_ldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc,
+ * char *url, const char *basedn, int scope, char **attrs,
+ * char *filter, char **binddn, char ***retvals)
+ */
+LDAP_DECLARE(int) util_ldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc,
+ const char *url, const char *basedn, int scope, char **attrs,
+ const char *filter, const char **binddn, const char ***retvals);
+
+/**
* Checks if SSL support is available in mod_ldap
* @deffunc int util_ldap_ssl_supported(request_rec *r)
*/
No revision
No revision
1.6.2.4 +1 -0 httpd-2.0/modules/experimental/Attic/NWGNUutilldap
Index: NWGNUutilldap
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/experimental/Attic/NWGNUutilldap,v
retrieving revision 1.6.2.3
retrieving revision 1.6.2.4
diff -u -r1.6.2.3 -r1.6.2.4
--- NWGNUutilldap 21 May 2004 22:42:56 -0000 1.6.2.3
+++ NWGNUutilldap 10 Nov 2004 16:35:23 -0000 1.6.2.4
@@ -226,6 +226,7 @@
util_ldap_connection_unbind \
util_ldap_connection_cleanup \
util_ldap_cache_checkuserid \
+ util_ldap_cache_getuserdn \
util_ldap_cache_compare \
util_ldap_cache_comparedn \
util_ldap_ssl_supported \
1.6.2.26 +198 -10 httpd-2.0/modules/experimental/Attic/util_ldap.c
Index: util_ldap.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/experimental/Attic/util_ldap.c,v
retrieving revision 1.6.2.25
retrieving revision 1.6.2.26
diff -u -r1.6.2.25 -r1.6.2.26
--- util_ldap.c 23 Oct 2004 13:47:05 -0000 1.6.2.25
+++ util_ldap.c 10 Nov 2004 16:35:23 -0000 1.6.2.26
@@ -776,24 +776,24 @@
LDAP_CACHE_LOCK();
the_search_node.username = filter;
search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
- if (search_nodep != NULL && search_nodep->bindpw) {
+ if (search_nodep != NULL) {
/* found entry in search cache... */
curtime = apr_time_now();
/*
- * Remove this item from the cache if its expired, or if the
- * sent password doesn't match the storepassword.
+ * Remove this item from the cache if its expired.
+ * If the sent password doesn't match the stored password,
+ * the entry will be removed and readded later if the
+ * credentials pass authentication.
*/
if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
/* ...but entry is too old */
util_ald_cache_remove(curl->search_cache, search_nodep);
}
- else if (strcmp(search_nodep->bindpw, bindpw) != 0) {
- /* ...but cached password doesn't match sent password */
- util_ald_cache_remove(curl->search_cache, search_nodep);
- }
- else {
+ else if ((search_nodep->bindpw) &&
+ (search_nodep->bindpw[0] != '\0') &&
+ (strcmp(search_nodep->bindpw, bindpw) == 0)) {
/* ...and entry is valid */
*binddn = search_nodep->dn;
*retvals = search_nodep->vals;
@@ -866,7 +866,7 @@
* able to authenticate with this module. I don't see this as a big
* problem.
*/
- if (strlen(bindpw) <= 0) {
+ if (!bindpw || strlen(bindpw) <= 0) {
ldap_msgfree(res);
ldc->reason = "Empty password not allowed";
return LDAP_INVALID_CREDENTIALS;
@@ -943,11 +943,20 @@
into the cache before we got here. If it does exist then update the lastbind */
search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
if ((search_nodep == NULL) ||
- (strcmp(*binddn, search_nodep->dn) != 0) || (strcmp(bindpw, search_nodep->bindpw) != 0)) {
+ (strcmp(*binddn, search_nodep->dn) != 0)) {
+ /* Nothing in cache, insert new entry */
+ util_ald_cache_insert(curl->search_cache, &the_search_node);
+ }
+ else if ((!search_nodep->bindpw) ||
+ (strcmp(bindpw, search_nodep->bindpw) != 0)) {
+
+ /* Entry in cache is invalid, remove it and insert new one */
+ util_ald_cache_remove(curl->search_cache, search_nodep);
util_ald_cache_insert(curl->search_cache, &the_search_node);
}
else {
+ /* Cache entry is valid, update lastbind */
search_nodep->lastbind = the_search_node.lastbind;
}
LDAP_CACHE_UNLOCK();
@@ -958,6 +967,185 @@
return LDAP_SUCCESS;
}
+/*
+ * This function will return the DN of the entry matching userid.
+ * It is used to get the DN in case some other module than mod_auth_ldap
+ * has authenticated the user.
+ * The function is basically a copy of util_ldap_cache_checkuserid
+ * with password checking removed.
+ */
+LDAP_DECLARE(int) util_ldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc,
+ const char *url, const char *basedn, int scope, char **attrs,
+ const char *filter, const char **binddn,
+ const char ***retvals)
+{
+ const char **vals = NULL;
+ int result = 0;
+ LDAPMessage *res, *entry;
+ char *dn;
+ int count;
+ int failures = 0;
+ util_url_node_t *curl; /* Cached URL node */
+ util_url_node_t curnode;
+ util_search_node_t *search_nodep; /* Cached search node */
+ util_search_node_t the_search_node;
+ apr_time_t curtime;
+
+ util_ldap_state_t *st =
+ (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
+ &ldap_module);
+
+ /* Get the cache node for this url */
+ LDAP_CACHE_LOCK();
+ curnode.url = url;
+ curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache, &curnode);
+ if (curl == NULL) {
+ curl = util_ald_create_caches(st, url);
+ }
+ LDAP_CACHE_UNLOCK();
+
+ if (curl) {
+ LDAP_CACHE_LOCK();
+ the_search_node.username = filter;
+ search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
+ if (search_nodep != NULL) {
+
+ /* found entry in search cache... */
+ curtime = apr_time_now();
+
+ /*
+ * Remove this item from the cache if its expired.
+ */
+ if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
+ /* ...but entry is too old */
+ util_ald_cache_remove(curl->search_cache, search_nodep);
+ }
+ else {
+ /* ...and entry is valid */
+ *binddn = search_nodep->dn;
+ *retvals = search_nodep->vals;
+ LDAP_CACHE_UNLOCK();
+ ldc->reason = "Search successful (cached)";
+ return LDAP_SUCCESS;
+ }
+ }
+ /* unlock this read lock */
+ LDAP_CACHE_UNLOCK();
+ }
+
+ /*
+ * At this point, there is no valid cached search, so lets do the search.
+ */
+
+ /*
+ * If any LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
+ */
+start_over:
+ if (failures++ > 10) {
+ return result;
+ }
+ if (LDAP_SUCCESS != (result = util_ldap_connection_open(r, ldc))) {
+ return result;
+ }
+
+ /* try do the search */
+ if ((result = ldap_search_ext_s(ldc->ldap,
+ const_cast(basedn), scope,
+ const_cast(filter), attrs, 0,
+ NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
+ ldc->reason = "ldap_search_ext_s() for user failed with server down";
+ goto start_over;
+ }
+
+ /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
+ if (result != LDAP_SUCCESS) {
+ ldc->reason = "ldap_search_ext_s() for user failed";
+ return result;
+ }
+
+ /*
+ * We should have found exactly one entry; to find a different
+ * number is an error.
+ */
+ count = ldap_count_entries(ldc->ldap, res);
+ if (count != 1)
+ {
+ if (count == 0 )
+ ldc->reason = "User not found";
+ else
+ ldc->reason = "User is not unique (search found two or more matches)";
+ ldap_msgfree(res);
+ return LDAP_NO_SUCH_OBJECT;
+ }
+
+ entry = ldap_first_entry(ldc->ldap, res);
+
+ /* Grab the dn, copy it into the pool, and free it again */
+ dn = ldap_get_dn(ldc->ldap, entry);
+ *binddn = apr_pstrdup(r->pool, dn);
+ ldap_memfree(dn);
+
+ /*
+ * Get values for the provided attributes.
+ */
+ if (attrs) {
+ int k = 0;
+ int i = 0;
+ while (attrs[k++]);
+ vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
+ while (attrs[i]) {
+ char **values;
+ int j = 0;
+ char *str = NULL;
+ /* get values */
+ values = ldap_get_values(ldc->ldap, entry, attrs[i]);
+ while (values && values[j]) {
+ str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL) : apr_pstrdup(r->pool, values[j]);
+ j++;
+ }
+ ldap_value_free(values);
+ vals[i] = str;
+ i++;
+ }
+ *retvals = vals;
+ }
+
+ /*
+ * Add the new username to the search cache.
+ */
+ if (curl) {
+ LDAP_CACHE_LOCK();
+ the_search_node.username = filter;
+ the_search_node.dn = *binddn;
+ the_search_node.bindpw = NULL;
+ the_search_node.lastbind = apr_time_now();
+ the_search_node.vals = vals;
+
+ /* Search again to make sure that another thread didn't ready insert this node
+ into the cache before we got here. If it does exist then update the lastbind */
+ search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
+ if ((search_nodep == NULL) ||
+ (strcmp(*binddn, search_nodep->dn) != 0)) {
+
+ /* Nothing in cache, insert new entry */
+ util_ald_cache_insert(curl->search_cache, &the_search_node);
+ }
+ /*
+ * Don't update lastbind on entries with bindpw because
+ * we haven't verified that password. It's OK to update
+ * the entry if there is no password in it.
+ */
+ else if (!search_nodep->bindpw) {
+ /* Cache entry is valid, update lastbind */
+ search_nodep->lastbind = the_search_node.lastbind;
+ }
+ LDAP_CACHE_UNLOCK();
+ }
+ ldap_msgfree(res);
+
+ ldc->reason = "Search successful";
+ return LDAP_SUCCESS;
+}
/*
* Reports if ssl support is enabled
1.1.2.1 +1 -0 httpd-2.0/modules/experimental/Attic/util_ldap.def
Index: util_ldap.def
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/experimental/Attic/util_ldap.def,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -u -r1.1 -r1.1.2.1
--- util_ldap.def 8 Feb 2002 18:31:32 -0000 1.1
+++ util_ldap.def 10 Nov 2004 16:35:23 -0000 1.1.2.1
@@ -2,5 +2,6 @@
EXPORT util_ldap_connection_find
EXPORT util_ldap_connection_close
EXPORT util_ldap_cache_checkuserid
+EXPORT util_ldap_cache_getuserdn
EXPORT util_ldap_cache_compare
EXPORT util_ldap_cache_comparedn