Hi all, Here is another snapshot of the library that incorporates LDAP into apr-util.
This patch is big, but it's an incorporation of a body of new code which works as a unit. The build should work correctly both with the default configuration (LDAP not included) to the configuration --with-ldap. Please test this for me to be sure. The header file apr_ldap.h incorporates some high level access to a number of LDAP functions, like opening connections, checking userids, and comparing users. Access is also possible to any of the ldap-*() routines within the LDAP SDK. The source code is half a vastly modified version of Dave Carrigan's auth_ldap module, published under the ASF licence. The other half takes the form of mod_auth_ldap, which is being posted separately to the new-httpd list. Currently the code works for me (Linux/PPC) - would be keen to see what other people's experiences are. It still needs a lot of work - but at this point feedback will be valuable. Comments...? The files are: include/apr_ldap.h.in include/private/apu_ldap_cache.h ldap/apr_ldap.c ldap/apr_ldap_cache.c ldap/apr_ldap_cache_mgr.c ldap/apr_ldap_compat.c ldap/Makefile.in Regards, Graham -- ----------------------------------------- [EMAIL PROTECTED] "There's a moon over Bourbon Street tonight..."
diff -r -u /home/minfrin/src/apache/pristine/apr-util/Makefile.in apr-util/Makefile.in --- /home/minfrin/src/apache/pristine/apr-util/Makefile.in Thu Aug 2 00:48:19 2001 +++ apr-util/Makefile.in Thu Aug 2 01:10:48 2001 @@ -11,7 +11,7 @@ # bring in rules.mk for standard functionality @INCLUDE_RULES@ -SUBDIRS = buckets crypto dbm encoding hooks uri xml misc +SUBDIRS = buckets crypto dbm encoding hooks ldap uri xml misc CLEAN_SUBDIRS = . test CLEAN_TARGETS = $(TARGET_EXPORTS) Only in apr-util: Makefile.in.orig diff -r -u /home/minfrin/src/apache/pristine/apr-util/build/apu-conf.m4 apr-util/build/apu-conf.m4 --- /home/minfrin/src/apache/pristine/apr-util/build/apu-conf.m4 Thu Aug 2 00:48:21 2001 +++ apr-util/build/apu-conf.m4 Wed Aug 8 23:00:41 2001 @@ -413,3 +413,78 @@ APR_ADDTO(APRUTIL_EXPORT_LIBS, [$expat_libs]) dnl ### export the Expat includes? ]) + + +dnl +dnl Find a particular LDAP library +dnl +AC_DEFUN(APU_FIND_LDAPLIB,[ + if test ${apu_has_ldap} != "define"; then + ldaplib=$1 + extralib=$2 + unset ac_cv_lib_${ldaplib}_ldap_init + AC_CHECK_LIB(${ldaplib}, ldap_init, + [ +dnl APR_ADDTO(CPPFLAGS,[-DAPU_HAS_LDAP]) + APR_ADDTO(LIBS,[-l${ldaplib} ${extralib}]) + APR_ADDTO(APRUTIL_EXPORT_LIBS,[-l${ldaplib} ${extralib}]) + AC_CHECK_LIB(${ldaplib}, ldapssl_install_routines, apu_has_ldap_netscape_ssl="define", , ${extralib}) + AC_CHECK_LIB(${ldaplib}, ldap_start_tls_s, apu_has_ldap_starttls="define", , ${extralib}) + apu_has_ldap="define"; + ], , ${extralib}) + fi +]) + + +dnl +dnl APU_FIND_LDAP: figure out where LDAP is located +dnl +AC_DEFUN(APU_FIND_LDAP,[ + +echo $ac_n "${nl}checking for ldap support...${nl}" + +AC_ARG_WITH(ldap-include, --with-ldap-include=path path to ldap include files with trailing slash) +AC_ARG_WITH(ldap-lib, --with-ldap-lib=path path to ldap lib file) +AC_ARG_WITH(ldap, --with-ldap=library ldap library to use, + [ + if test -n "$with_ldap_include"; then + APR_ADDTO(CPPFLAGS, [-I$with_ldap_include]) + fi + if test -n "$with_ldap_lib"; then + APR_ADDTO(LDFLAGS, [-L$with_ldap_lib]) + fi + + apu_has_ldap="undef"; + apu_has_ldap_netscape_ssl="undef" + apu_has_ldap_starttls="undef" + + LIBLDAP="$withval" + if test "$LIBLDAP" = "yes"; then +dnl The iPlanet C SDK 5.0 is as yet untested... + APU_FIND_LDAPLIB("ldap50", "-lnspr4 -lplc4 -lplds4 -liutil50 -llber50 -lldif50 -lnss3 -lprldap50 -lssl3 -lssldap50") + APU_FIND_LDAPLIB("ldapssl41", "-lnspr3 -lplc3 -lplds3") + APU_FIND_LDAPLIB("ldapssl40") + APU_FIND_LDAPLIB("ldapssl30") + APU_FIND_LDAPLIB("ldapssl20") + APU_FIND_LDAPLIB("ldap", "-llber") + else + APU_FIND_LDAPLIB($LDAPLIB) + fi + + test ${apu_has_ldap} != "define" && AC_MSG_ERROR(could not find an LDAP library) + AC_CHECK_LIB(lber, ber_init) + + AC_CHECK_HEADERS(ldap.h, ldap_h=["#include <ldap.h>"]) + AC_CHECK_HEADERS(lber.h, lber_h=["#include <lber.h>"]) + AC_CHECK_HEADERS(ldap_ssl.h, ldap_ssl_h=["#include <ldap_ssl.h>"]) + +AC_SUBST(apu_has_ldap_netscape_ssl) +AC_SUBST(apu_has_ldap_starttls) +AC_SUBST(ldap_h) +AC_SUBST(lber_h) +AC_SUBST(ldap_ssl_h) +AC_SUBST(apu_has_ldap) + + ]) + +]) diff -r -u /home/minfrin/src/apache/pristine/apr-util/configure.in apr-util/configure.in --- /home/minfrin/src/apache/pristine/apr-util/configure.in Thu Aug 2 00:48:20 2001 +++ apr-util/configure.in Wed Aug 8 22:38:32 2001 @@ -50,6 +50,7 @@ dnl 3. Find Expat dnl APU_FIND_APR +APU_FIND_LDAP APU_CHECK_DBM APU_FIND_EXPAT @@ -104,10 +105,11 @@ dnl dnl everthing is done. -MAKEFILES="Makefile buckets/Makefile crypto/Makefile dbm/Makefile dbm/sdbm/Makefile encoding/Makefile hooks/Makefile uri/Makefile xml/Makefile misc/Makefile $test_Makefile" +MAKEFILES="Makefile buckets/Makefile crypto/Makefile dbm/Makefile dbm/sdbm/Makefile encoding/Makefile hooks/Makefile ldap/Makefile uri/Makefile xml/Makefile misc/Makefile $test_Makefile" AC_OUTPUT([ export_vars.sh include/private/apu_select_dbm.h + include/apr_ldap.h include/apu.h $MAKEFILES ]) Only in apr-util/include: apr_ldap.h.in Only in apr-util/include/private: apu_ldap_cache.h Only in apr-util: ldap
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /* * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h */ #ifndef APU_LDAP_H #define APU_LDAP_H /* * This switches LDAP support on or off. */ /* this will be defined if LDAP support was compiled into apr-util */ [EMAIL PROTECTED]@ APU_HAS_LDAP /* this whole thing disappears if LDAP is not enabled */ #ifdef APU_HAS_LDAP /* LDAP secure capabilities */ [EMAIL PROTECTED]@ APU_HAS_LDAP_NETSCAPE_SSL [EMAIL PROTECTED]@ APU_HAS_LDAP_STARTTLS /* LDAP header files */ @ldap_h@ @lber_h@ @ldap_ssl_h@ /* APR header files */ #include <apr_lock.h> #include <apr_tables.h> #include <apr_time.h> /* * LDAP Compatibility */ #if LDAP_VERSION_MAX <= 2 int ldap_search_ext_s(LDAP *ldap, char *base, int scope, char *filter, char **attrs, int attrsonly, void *servertrls, void *clientctrls, void *timeout, int sizelimit, LDAPMessage **res); void ldap_memfree(void *p); /* The const_cast is used to get around the fact that some of the LDAPv2 prototypes * have non-const parameters, while the same ones in LDAPv3 are const. If compiling * with LDAPv2, the const_cast casts away the constness, but won't under LDAPv3 */ #define const_cast(x) ((char *)(x)) #else #define const_cast(x) (x) #endif /* LDAP_VERSION_MAX */ /* Define some errors that are mysteriously gone from OpenLDAP 2.x */ #ifndef LDAP_URL_ERR_NOTLDAP #define LDAP_URL_ERR_NOTLDAP LDAP_URL_ERR_BADSCHEME #endif #ifndef LDAP_URL_ERR_NODN #define LDAP_URL_ERR_NODN LDAP_URL_ERR_BADURL #endif /* * LDAP Connections */ /* Values that the deref member can have */ typedef enum { never=LDAP_DEREF_NEVER, searching=LDAP_DEREF_SEARCHING, finding=LDAP_DEREF_FINDING, always=LDAP_DEREF_ALWAYS } deref_options; /* Structure representing an LDAP connection */ typedef struct apr_ldap_connection_t { LDAP *ldap; apr_lock_t *lock; /* Lock to indicate this connection is in use */ int bound; /* Flag to indicate whether this connection is bound yet */ const char *host; /* Name of the LDAP server (or space separated list) */ int port; /* Port of the LDAP server */ deref_options deref; /* how to handle alias dereferening */ const char *binddn; /* DN to bind to server (can be NULL) */ const char *bindpw; /* Password to bind to server (can be NULL) */ int netscapessl; /* True if use Netscape SSL connection */ const char *certtdb; /* Path to Netscape CA database */ int starttls; /* True if StartTLS is enabled */ int withtls; /* True if StartTLS on this connection */ const char *reason; /* Reason for an error failure */ struct apr_ldap_connection_t *next; } apr_ldap_connection_t; /* LDAP cache state information */ typedef struct apr_ldap_state_t { apr_pool_t *pool; /* pool from which this state is allocated */ apr_lock_t *mutex; /* mutex lock for the connection list */ long search_cache_ttl; /* TTL for search cache */ long search_cache_size; /* Size of search cache */ long compare_cache_ttl; /* TTL for compare cache */ long compare_cache_size; /* Size of compare cache */ struct apr_ldap_connection_t *connections; #ifdef APU_HAS_LDAP_NETSCAPE_SSL int have_certdb; #endif } apr_ldap_state_t; /** * Open a connection to an LDAP server * @param ldc A structure containing the expanded details of the server * to connect to. The handle to the LDAP connection is returned * as ldc->ldap. * @tip This function connects to the LDAP server and binds. It does not * connect if already connected (ldc->ldap != NULL). Does not bind * if already bound. * @return If successful LDAP_SUCCESS is returned. * @deffunc int apr_ldap_connection_open(apr_ldap_connection_t *ldc) */ int apr_ldap_connection_open(apr_ldap_connection_t *ldc); /** * Close a connection to an LDAP server * @param ldc A structure containing the expanded details of the server that was connected. * @tip This function unbinds from the LDAP server, and clears ldc->ldap. * It is possible to rebind to this server again using the same ldc * structure, using apr_ldap_open_connection(). * @deffunc apr_ldap_close_connection(apr_ldap_connection_t *ldc) */ void apr_ldap_connection_close(apr_ldap_connection_t *ldc); /** * Find a connection in a list of connections * @param new A structure containing the details of the connection to search * for in the linked list. If the connection is not found in the linked * list, it will be added to the linked list. * @param st A structure containing the LDAP library state. The connection linked * list is stored within this structure. If a new connection is created * in the linked list, it is allocated from the pool within st->pool. * @tip Once a connection is found and returned, the "in use" flag will be set 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 mark this connection as no * longer "in use". * @deffunc apr_ldap_connection_t *apr_ldap_connection_find(apr_ldap_state_t *st, const char *host, int port, * const char *binddn, const char *bindpw, deref_options deref, * int netscapessl, int starttls) */ apr_ldap_connection_t *apr_ldap_connection_find(apr_ldap_state_t *st, const char *host, int port, const char *binddn, const char *bindpw, deref_options deref, int netscapessl, int starttls); /** * Compare two DNs for sameness * @param st A structure containing the LDAP library state. * @param ldc The LDAP connection being used. * @param url The URL of the LDAP connection - used for deciding which cache to use. * @param dn The first DN to compare. * @param reqdn The DN to compare the first DN to. * @param compare_dn_on_server Flag to determine whether the DNs should be checked using * LDAP calls or with a direct string comparision. A direct * string comparison is faster, but not as accurate - false * negative comparisons are possible. * @tip Two DNs can be equal and still fail a string comparison. Eg "dc=example,dc=com" * and "dc=example, dc=com". Use the compare_dn_on_server unless there are serious * performance issues. * @deffunc int apr_ldap_cache_comparedn(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, * const char *url, const char *dn, const char *reqdn, * int compare_dn_on_server) */ int apr_ldap_cache_comparedn(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *dn, const char *reqdn, int compare_dn_on_server); /** * A generic LDAP compare function * @param st A structure containing the LDAP library state. * @param ldc The LDAP connection being used. * @param url The URL of the LDAP connection - used for deciding which cache to use. * @param dn The DN of the object in which we do the compare. * @param attrib The attribute within the object we are comparing for. * @param value The value of the attribute we are trying to compare for. * @tip Use this function to determine whether an attribute/value pair exists within an * object. Typically this would be used to determine LDAP group membership. * @deffunc int apr_ldap_cache_compare(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, * const char *url, const char *dn, const char *attrib, const char *value) */ int apr_ldap_cache_compare(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *dn, const char *attrib, const char *value); /** * Checks a username/password combination by binding to the LDAP server * @param st A structure containing the LDAP library state. * @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 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 bindpw The user password to bind as. * @param binddn The DN of the user will be returned in this variable. * @tip The filter supplied will be searched for. If a single entry is returned, an attempt * is made to bind as that user. If this bind succeeds, the user is not validated. * @deffunc int apr_ldap_cache_checkuserid(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, char *url, const char *basedn, int scope, char *filter, char *bindpw, char **binddn) */ int apr_ldap_cache_checkuserid(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *basedn, int scope, const char *filter, const char *bindpw, const char **binddn); /* from apr_ldap_cache.c */ /** * Init the LDAP cache * @param p The pool to use to initialise the cache * @deffunc void apr_ldap_cache_init(apr_pool_t *p) */ void apr_ldap_cache_init(apr_pool_t *p); #endif /* APU_HAS_LDAP */ #endif /* APU_LDAP_H */
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ #ifndef APU_LDAP_CACHE_H #define APU_LDAP_CACHE_H /* * This switches LDAP support on or off. */ /* this whole thing disappears if LDAP is not enabled */ #ifdef APU_HAS_LDAP /* * LDAP Cache Manager */ #ifdef APU_HAS_LDAP_SHARED_CACHE #include <apr_shmem.h> #endif typedef struct apr_cache_node_t { void *payload; /* Pointer to the payload */ time_t add_time; /* Time node was added to cache */ struct apr_cache_node_t *next; } apr_cache_node_t; typedef struct apr_ald_cache_t { unsigned long size; /* Size of cache array */ unsigned long maxentries; /* Maximum number of cache entries */ unsigned long numentries; /* Current number of cache entries */ unsigned long fullmark; /* Used to keep track of when cache becomes 3/4 full */ time_t marktime; /* Time that the cache became 3/4 full */ unsigned long (*hash)(void *); /* Func to hash the payload */ int (*compare)(void *, void *); /* Func to compare two payloads */ void * (*copy)(void *); /* Func to alloc mem and copy payload to new mem */ void (*free)(void *); /* Func to free mem used by the payload */ apr_cache_node_t **nodes; unsigned long numpurges; /* No. of times the cache has been purged */ double avg_purgetime; /* Average time to purge the cache */ time_t last_purge; /* Time of the last purge */ unsigned long npurged; /* Number of elements purged in last purge. This is not obvious: it won't be 3/4 the size of the cache if there were a lot of expired entries. */ unsigned long fetches; /* Number of fetches */ unsigned long hits; /* Number of cache hits */ unsigned long inserts; /* Number of inserts */ unsigned long removes; /* Number of removes */ } apr_ald_cache_t; /*#define EXTERN */ #ifdef APU_HAS_LDAP_SHARED_CACHE EXTERN AP_MM *apr_ldap_mm; #endif /*EXTERN apr_ald_cache_t *apr_ldap_cache;*/ apr_ald_cache_t *apr_ldap_cache; apr_lock_t *apr_ldap_cache_lock; #ifndef WIN32 #define ALD_MM_FILE_MODE ( S_IRUSR|S_IWUSR ) #else #define ALD_MM_FILE_MODE ( _S_IREAD|_S_IWRITE ) #endif /* * LDAP Cache */ /* * Maintain a cache of LDAP URLs that the server handles. Each node in * the cache contains the search cache for that URL, and a compare cache * for the URL. The compare cash is populated when doing require group * compares. */ typedef struct apr_url_node_t { const char *url; apr_ald_cache_t *search_cache; apr_ald_cache_t *compare_cache; apr_ald_cache_t *dn_compare_cache; } apr_url_node_t; /* * We cache every successful search and bind operation, using the username * as the key. Each node in the cache contains the returned DN, plus the * password used to bind. */ typedef struct apr_search_node_t { const char *username; /* Cache key */ const char *dn; /* DN returned from search */ const char *bindpw; /* The most recently used bind password; NULL if the bind failed */ apr_time_t lastbind; /* Time of last successful bind */ } apr_search_node_t; /* * We cache every successful compare operation, using the DN, attrib, and * value as the key. */ typedef struct apr_compare_node_t { const char *dn; /* DN, attrib and value combine to be the key */ const char *attrib; const char *value; apr_time_t lastcompare; } apr_compare_node_t; /* * We cache every successful compare dn operation, using the dn in the require * statement and the dn fetched based on the client-provided username. */ typedef struct apr_dn_compare_node_t { const char *reqdn; /* The DN in the require dn statement */ const char *dn; /* The DN found in the search */ } apr_dn_compare_node_t; /* * Function prototypes for LDAP cache */ /* apr_ldap_cache.c */ unsigned long apr_ldap_url_node_hash(void *n); int apr_ldap_url_node_compare(void *a, void *b); void *apr_ldap_url_node_copy(void *c); void apr_ldap_url_node_free(void *n); unsigned long apr_ldap_search_node_hash(void *n); int apr_ldap_search_node_compare(void *a, void *b); void *apr_ldap_search_node_copy(void *c); void apr_ldap_search_node_free(void *n); unsigned long apr_ldap_compare_node_hash(void *n); int apr_ldap_compare_node_compare(void *a, void *b); void *apr_ldap_compare_node_copy(void *c); void apr_ldap_compare_node_free(void *n); unsigned long apr_ldap_dn_compare_node_hash(void *n); int apr_ldap_dn_compare_node_compare(void *a, void *b); void *apr_ldap_dn_compare_node_copy(void *c); void apr_ldap_dn_compare_node_free(void *n); /* apr_ldap_cache_mgr.c */ void apr_ald_free(const void *ptr); void *apr_ald_alloc(int size); const char *apr_ald_strdup(const char *s); unsigned long apr_ald_hash_string(int nstr, ...); void apr_ald_cache_purge(apr_ald_cache_t *cache); apr_url_node_t *apr_ald_create_caches(apr_ldap_state_t *s, const char *url); apr_ald_cache_t *apr_ald_create_cache(unsigned long maxentries, unsigned long (*hashfunc)(void *), int (*comparefunc)(void *, void *), void * (*copyfunc)(void *), void (*freefunc)(void *)); void apr_ald_destroy_cache(apr_ald_cache_t *cache); void *apr_ald_cache_fetch(apr_ald_cache_t *cache, void *payload); void apr_ald_cache_insert(apr_ald_cache_t *cache, void *payload); void apr_ald_cache_remove(apr_ald_cache_t *cache, void *payload); void apr_ald_cache_display_stats(apr_pool_t *p, apr_ald_cache_t *cache, char *name, char **stats); #endif /* APU_HAS_LDAP */ #endif /* APU_LDAP_CACHE_H */
[EMAIL PROTECTED]@ INCLUDES=-I$(top_builddir)/include -I$(top_builddir)/../apr/include TARGETS = apr_ldap.lo apr_ldap_cache.lo apr_ldap_cache_mgr.lo apr_ldap_compat.lo # bring in rules.mk for standard functionality @INCLUDE_RULES@
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /* * apr_ldap.c: LDAP things * * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan */ #include <apr_ldap.h> #include <private/apu_ldap_cache.h> #include <apr_lock.h> #include <apr_strings.h> #ifdef APU_HAS_LDAP /* * Closes an LDAP connection by unbinding. Sets the boundas value for the * http connection config record and clears the bound dn string in the * global connection record. The next time apr_ldap_connection_open() is * called, the connection will be recreated. * * If the log parameter is set, adds a debug entry to the log that the * server was down and it's reconnecting. * */ void apr_ldap_connection_close(apr_ldap_connection_t *ldc) { /* * QUESTION: * * Is it safe leaving bound connections floating around between the * different modules? Keeping the user bound is a performance boost, * but it is also a potential security problem - maybe. * * For now we unbind the user when we finish with a connection, but * we don't have to... */ /* unbinding from the LDAP server */ if (ldc->ldap) { ldap_unbind_s(ldc->ldap); ldc->bound = 0; } /* mark our connection as available for reuse */ apr_lock_release(ldc->lock); } /* * 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. * * Returns LDAP_SUCCESS on success; and an error code on failure * XXX FIXME: Make these APR error codes, not LDAP error codes * */ int apr_ldap_connection_open(apr_ldap_connection_t *ldc) { int result = 0; int failures = 0; start_over: if (failures++ > 10) { /* too many failures - leave */ return result; } if (!ldc->ldap) { ldc->bound = 0; /* opening connection to LDAP server */ if ((ldc->ldap = ldap_init(ldc->host, ldc->port)) == NULL) { /* couldn't connect */ /* XXX FIXME: when ldap_init returns NULL, the real error * message is a system error in errno. This should be * changed when LDAP errors become APR errors to automatically * return the relevant APR system error where appropriate */ ldc->reason = "ldap_init() failed"; return -1; } /* Set the alias dereferencing option */ #if LDAP_VERSION_MAX == 2 ldc->ldap->ld_deref = ldc->deref; #else result = ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &(ldc->deref)); if (result != LDAP_SUCCESS) { /* setting LDAP dereference option failed */ /* we ignore this error */ } #endif /* LDAP_VERSION_MAX */ #ifdef APU_HAS_LDAP_NETSCAPE_SSL if (ldc->netscapessl) { if (!ldc->certdb) { /* secure LDAP requested, but no CA cert defined */ ldc->reason = "secure LDAP requested, but no CA cert defined"; return -1; } else { result = ldapssl_install_routines(ldc->ldap); if (result != LDAP_SUCCESS) { /* SSL initialisation failed */ ldc->reason = "ldapssl_install_routines() failed"; return result; } result = ldap_set_option(ldc->ldap, LDAP_OPT_SSL, LDAP_OPT_ON); if (result != LDAP_SUCCESS) { /* SSL option failed */ ldc->reason = "ldap_set_option() failed trying to set LDAP_OPT_SSL"; return result; } } } #endif /* APU_HAS_LDAP_NETSCAPE_SSL */ #ifdef APU_HAS_LDAP_STARTTLS if (ldc->starttls) { int version = LDAP_VERSION3; /* Also we have to set the connection to use protocol version 3, * since we're using TLS. */ if ((result = ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_SUCCESS) { /* setting LDAP version failed - ignore error */ } /* * In apr_ldap_connection_find, we compare ldc->withtls to * sec->starttls to see if we have a cache match. On the off * chance that apache's config processing rotines set starttls to * some other true value besides 1, we set it to 1 here to ensure * that the comparison succeeds. */ ldc->starttls = 1; result = ldap_start_tls_s(ldc->ldap, NULL, NULL); if (result != LDAP_SUCCESS) { /* start TLS failed */ ldc->withtls = 0; ldc->reason = "ldap_start_tls_s() failed"; return result; } ldc->withtls = 1; } else { ldc->withtls = 0; } #endif /* APU_HAS_LDAP_STARTTLS */ } /* * At this point the LDAP connection is guaranteed alive. If bound says * that we're bound already, we can just return. */ if (ldc->bound) { ldc->reason = "LDAP connection open successful (already bound)"; return LDAP_SUCCESS; } /* * Now bind with the username/password provided by the * configuration. It will be an anonymous bind if no u/p was * provided. */ if ((result = ldap_simple_bind_s(ldc->ldap, ldc->binddn, ldc->bindpw)) == LDAP_SERVER_DOWN) { /* couldn't connect - try again */ ldc->reason = "ldap_simple_bind_s() failed with server down"; goto start_over; } if (result != LDAP_SUCCESS) { /* LDAP fatal error occured */ ldc->reason = "ldap_simple_bind_s() failed"; return result; } /* note how we are bound */ ldc->bound = 1; ldc->reason = "LDAP connection open successful"; return LDAP_SUCCESS; } /* * 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. */ apr_ldap_connection_t *apr_ldap_connection_find(apr_ldap_state_t *st, const char *host, int port, const char *binddn, const char *bindpw, deref_options deref, int netscapessl, int starttls) { struct apr_ldap_connection_t *l, *p; /* To traverse the linked list */ /* mutex lock this function */ if (!st->mutex) { apr_lock_create(&st->mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, st->pool); } apr_lock_acquire(st->mutex); /* Search for an exact connection match in the list that is not * being used. */ for (l=st->connections,p=NULL; l; l=l->next) { if ( (APR_SUCCESS == apr_lock_tryacquire(l->lock)) && 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 #ifdef APU_HAS_LDAP_NETSCAPE_SSL && l->netscapessl == netscapessl #endif #ifdef APU_HAS_LDAP_STARTTLS && l->withtls == starttls #endif ) break; p = l; } /* If nothing found, search again, but we don't care about the * binddn and bindpw this time. */ if (!l) { for (l=st->connections,p=NULL; l; l=l->next) { if ( (APR_SUCCESS == apr_lock_tryacquire(l->lock)) && l->port == port && strcmp(l->host, host) == 0 && l->deref == deref #ifdef APU_HAS_LDAP_NETSCAPE_SSL && l->netscapessl == netscapessl #endif #ifdef APU_HAS_LDAP_STARTTLS && l->withtls == starttls #endif ) { /* the bind credentials have changed */ l->bound = 0; l->binddn = apr_pstrdup(st->pool, binddn); l->bindpw = apr_pstrdup(st->pool, bindpw); break; } p = l; } } /* artificially disable cache */ l = NULL; /* If no connection what found after the second search, we * must create one. */ if (!l) { /* * Add the new connection entry to the linked list. Note that we * don't actually establish an LDAP connection yet; that happens * the first time authentication is requested. */ /* create the details to the pool in st */ l = apr_pcalloc(st->pool, sizeof(apr_ldap_connection_t)); apr_lock_create(&l->lock, APR_MUTEX, APR_INTRAPROCESS, NULL, st->pool); apr_lock_acquire(l->lock); l->bound = 0; l->host = apr_pstrdup(st->pool, host); l->port = port; l->deref = deref; l->binddn = apr_pstrdup(st->pool, binddn); l->bindpw = apr_pstrdup(st->pool, bindpw); l->netscapessl = netscapessl; l->starttls = starttls; l->withtls = 0; if (p) { p->next = l; } else { st->connections = l; } } apr_lock_release(st->mutex); return l; } /* ------------------------------------------------------------------ */ /* * Compares two DNs to see if they're equal. The only way to do this correctly is to * search for the dn and then do ldap_get_dn() on the result. This should match the * initial dn, since it would have been also retrieved with ldap_get_dn(). This is * expensive, so if the configuration value compare_dn_on_server is * false, just does an ordinary strcmp. * * The lock for the ldap cache should already be acquired. */ int apr_ldap_cache_comparedn(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *dn, const char *reqdn, int compare_dn_on_server) { int result = 0; apr_url_node_t *curl; apr_url_node_t curnode; apr_dn_compare_node_t *node; apr_dn_compare_node_t newnode; int failures = 0; LDAPMessage *res, *entry; char *searchdn; /* read lock this function */ if (!apr_ldap_cache_lock) { apr_lock_create(&apr_ldap_cache_lock, APR_READWRITE, APR_INTRAPROCESS, NULL, st->pool); } /* get cache entry (or create one) */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_WRITER); curnode.url = url; curl = apr_ald_cache_fetch(apr_ldap_cache, &curnode); if (curl == NULL) { curl = apr_ald_create_caches(st, url); } apr_lock_release(apr_ldap_cache_lock); /* a simple compare? */ if (!compare_dn_on_server) { /* unlock this read lock */ if (strcmp(dn, reqdn)) { ldc->reason = "DN Comparison FALSE (direct strcmp())"; return LDAP_COMPARE_FALSE; } else { ldc->reason = "DN Comparison TRUE (direct strcmp())"; return LDAP_COMPARE_TRUE; } } /* no - it's a server side compare */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_READER); /* is it in the compare cache? */ newnode.reqdn = (char *)reqdn; node = apr_ald_cache_fetch(curl->dn_compare_cache, &newnode); if (node != NULL) { /* If it's in the cache, it's good */ /* unlock this read lock */ apr_lock_release(apr_ldap_cache_lock); ldc->reason = "DN Comparison TRUE (cached)"; return LDAP_COMPARE_TRUE; } /* unlock this read lock */ apr_lock_release(apr_ldap_cache_lock); start_over: if (failures++ > 10) { /* too many failures */ return result; } /* make a server connection */ if (LDAP_SUCCESS != (result = apr_ldap_connection_open(ldc))) { /* connect to server failed */ return result; } /* search for reqdn */ if ((result = ldap_search_ext_s(ldc->ldap, const_cast(reqdn), LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 1, NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) { apr_ldap_connection_close(ldc); ldc->reason = "DN Comparison ldap_search_ext_s() failed with server down"; goto start_over; } if (result != LDAP_SUCCESS) { /* search for reqdn failed - no match */ ldc->reason = "DN Comparison ldap_search_ext_s() failed"; return result; } entry = ldap_first_entry(ldc->ldap, res); searchdn = ldap_get_dn(ldc->ldap, entry); ldap_msgfree(res); if (strcmp(dn, searchdn) != 0) { /* compare unsuccessful */ ldc->reason = "DN Comparison FALSE (checked on server)"; result = LDAP_COMPARE_FALSE; } else { /* compare successful - add to the compare cache */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_READER); newnode.reqdn = (char *)reqdn; newnode.dn = (char *)dn; apr_ald_cache_insert(curl->dn_compare_cache, &newnode); apr_lock_release(apr_ldap_cache_lock); ldc->reason = "DN Comparison TRUE (checked on server)"; result = LDAP_COMPARE_TRUE; } ldap_memfree(searchdn); return result; } /* * Does an generic ldap_compare operation. It accepts a cache that it will use * to lookup the compare in the cache. We cache two kinds of compares * (require group compares) and (require user compares). Each compare has a different * cache node: require group includes the DN; require user does not because the * require user cache is owned by the * */ int apr_ldap_cache_compare(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *dn, const char *attrib, const char *value) { int result = 0; apr_url_node_t *curl; apr_url_node_t curnode; apr_compare_node_t *compare_nodep; apr_compare_node_t the_compare_node; apr_time_t curtime; int failures = 0; /* read lock this function */ if (!apr_ldap_cache_lock) { apr_lock_create(&apr_ldap_cache_lock, APR_READWRITE, APR_INTRAPROCESS, NULL, st->pool); } /* get cache entry (or create one) */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_WRITER); curnode.url = url; curl = apr_ald_cache_fetch(apr_ldap_cache, &curnode); if (curl == NULL) { curl = apr_ald_create_caches(st, url); } apr_lock_release(apr_ldap_cache_lock); /* make a comparison to the cache */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_READER); curtime = apr_time_now(); the_compare_node.dn = (char *)dn; the_compare_node.attrib = (char *)attrib; the_compare_node.value = (char *)value; compare_nodep = apr_ald_cache_fetch(curl->compare_cache, &the_compare_node); if (compare_nodep != NULL) { /* found it... */ if (curtime - compare_nodep->lastcompare > st->compare_cache_ttl) { /* ...but it is too old */ apr_ald_cache_remove(curl->compare_cache, compare_nodep); } else { /* ...and it is good */ /* unlock this read lock */ apr_lock_release(apr_ldap_cache_lock); ldc->reason = "Comparison successful (cached)"; return LDAP_COMPARE_TRUE; } } /* unlock this read lock */ apr_lock_release(apr_ldap_cache_lock); start_over: if (failures++ > 10) { /* too many failures */ return result; } if (LDAP_SUCCESS != (result = apr_ldap_connection_open(ldc))) { /* connect failed */ return result; } if ((result = ldap_compare_s(ldc->ldap, const_cast(dn), const_cast(attrib), const_cast(value))) == LDAP_SERVER_DOWN) { /* connection failed - try again */ apr_ldap_connection_close(ldc); ldc->reason = "ldap_compare_s() failed with server down"; goto start_over; } if (result == LDAP_COMPARE_TRUE) { /* compare succeeded; caching result */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_WRITER); the_compare_node.lastcompare = curtime; apr_ald_cache_insert(curl->compare_cache, &the_compare_node); apr_lock_release(apr_ldap_cache_lock); } ldc->reason = "Comparison complete"; return result; } int apr_ldap_cache_checkuserid(apr_ldap_state_t *st, apr_ldap_connection_t *ldc, const char *url, const char *basedn, int scope, const char *filter, const char *bindpw, const char **binddn) { int result = 0; LDAPMessage *res, *entry; char *dn; int count; int failures = 0; apr_url_node_t *curl; /* Cached URL node */ apr_url_node_t curnode; apr_search_node_t *search_nodep; /* Cached search node */ apr_search_node_t the_search_node; apr_time_t curtime; /* read lock this function */ if (!apr_ldap_cache_lock) { apr_lock_create(&apr_ldap_cache_lock, APR_READWRITE, APR_INTRAPROCESS, NULL, st->pool); } /* Get the cache node for this url */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_WRITER); curnode.url = url; curl = (apr_url_node_t *)apr_ald_cache_fetch(apr_ldap_cache, &curnode); if (curl == NULL) { curl = apr_ald_create_caches(st, url); } apr_lock_release(apr_ldap_cache_lock); apr_lock_acquire_rw(apr_ldap_cache_lock, APR_READER); the_search_node.username = filter; search_nodep = apr_ald_cache_fetch(curl->search_cache, &the_search_node); if (search_nodep != NULL && search_nodep->bindpw) { /* 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. */ if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) { /* ...but entry is too old */ apr_ald_cache_remove(curl->search_cache, search_nodep); } else if (strcmp(search_nodep->bindpw, bindpw) != 0) { /* ...but cached password doesn't match sent password */ apr_ald_cache_remove(curl->search_cache, search_nodep); } else { /* ...and entry is valid */ *binddn = search_nodep->dn; apr_lock_release(apr_ldap_cache_lock); ldc->reason = "Authentication successful (cached)"; return LDAP_SUCCESS; } } /* unlock this read lock */ apr_lock_release(apr_ldap_cache_lock); /* * 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 = apr_ldap_connection_open(ldc))) { return result; } /* try do the search */ if ((result = ldap_search_ext_s(ldc->ldap, basedn, scope, filter, NULL, 1, 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) { ldap_msgfree(res); ldc->reason = "User is not unique (search found two or more matches)"; 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(st->pool, dn); ldap_memfree(dn); /* * A bind to the server with an empty password always succeeds, so * we check to ensure that the password is not empty. This implies * that users who actually do have empty passwords will never be * able to authenticate with this module. I don't see this as a big * problem. */ if (strlen(bindpw) <= 0) { ldap_msgfree(res); ldc->reason = "Empty password not allowed"; return LDAP_INVALID_CREDENTIALS; } /* * Attempt to bind with the retrieved dn and the password. If the bind * fails, it means that the password is wrong (the dn obviously * exists, since we just retrieved it) */ if ((result = ldap_simple_bind_s(ldc->ldap, *binddn, bindpw)) == LDAP_SERVER_DOWN) { ldc->reason = "ldap_simple_bind_s() to check user credentials failed with server down"; goto start_over; } /* failure? if so - return */ if (result != LDAP_SUCCESS) { ldc->reason = "ldap_simple_bind_s() to check user credentials failed"; return result; } ldap_msgfree(res); /* * Add the new username to the search cache. */ apr_lock_acquire_rw(apr_ldap_cache_lock, APR_WRITER); the_search_node.username = filter; the_search_node.dn = *binddn; the_search_node.bindpw = bindpw; the_search_node.lastbind = apr_time_now(); apr_ald_cache_insert(curl->search_cache, &the_search_node); apr_lock_release(apr_ldap_cache_lock); ldc->reason = "Authentication successful"; return LDAP_SUCCESS; } #endif /* APU_HAS_LDAP */
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /* * apr_ldap_cache.c: LDAP cache things * * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan */ #include <apr_ldap.h> #include <private/apu_ldap_cache.h> #ifdef APU_HAS_LDAP /* ------------------------------------------------------------------ */ unsigned long apr_ldap_url_node_hash(void *n) { apr_url_node_t *node = (apr_url_node_t *)n; return apr_ald_hash_string(1, node->url); } int apr_ldap_url_node_compare(void *a, void *b) { apr_url_node_t *na = (apr_url_node_t *)a; apr_url_node_t *nb = (apr_url_node_t *)b; return(strcmp(na->url, nb->url) == 0); } void *apr_ldap_url_node_copy(void *c) { apr_url_node_t *n = (apr_url_node_t *)c; apr_url_node_t *node = (apr_url_node_t *)apr_ald_alloc(sizeof(apr_url_node_t)); node->url = apr_ald_strdup(n->url); node->search_cache = n->search_cache; node->compare_cache = n->compare_cache; node->dn_compare_cache = n->dn_compare_cache; return node; } void apr_ldap_url_node_free(void *n) { apr_url_node_t *node = (apr_url_node_t *)n; apr_ald_free(node->url); apr_ald_destroy_cache(node->search_cache); apr_ald_destroy_cache(node->compare_cache); apr_ald_destroy_cache(node->dn_compare_cache); apr_ald_free(node); } /* ------------------------------------------------------------------ */ /* Cache functions for search nodes */ unsigned long apr_ldap_search_node_hash(void *n) { apr_search_node_t *node = (apr_search_node_t *)n; return apr_ald_hash_string(1, ((apr_search_node_t *)(node))->username); } int apr_ldap_search_node_compare(void *a, void *b) { return(strcmp(((apr_search_node_t *)a)->username, ((apr_search_node_t *)b)->username) == 0); } void *apr_ldap_search_node_copy(void *c) { apr_search_node_t *node = (apr_search_node_t *)c; apr_search_node_t *newnode = apr_ald_alloc(sizeof(apr_search_node_t)); newnode->username = apr_ald_strdup(node->username); newnode->dn = apr_ald_strdup(node->dn); newnode->bindpw = apr_ald_strdup(node->bindpw); newnode->lastbind = node->lastbind; return (void *)newnode; } void apr_ldap_search_node_free(void *n) { apr_search_node_t *node = (apr_search_node_t *)n; apr_ald_free(node->username); apr_ald_free(node->dn); apr_ald_free(node->bindpw); apr_ald_free(node); } /* ------------------------------------------------------------------ */ unsigned long apr_ldap_compare_node_hash(void *n) { apr_compare_node_t *node = (apr_compare_node_t *)n; return apr_ald_hash_string(3, node->dn, node->attrib, node->value); } int apr_ldap_compare_node_compare(void *a, void *b) { apr_compare_node_t *na = (apr_compare_node_t *)a; apr_compare_node_t *nb = (apr_compare_node_t *)b; return (strcmp(na->dn, nb->dn) == 0 && strcmp(na->attrib, nb->attrib) == 0 && strcmp(na->value, nb->value) == 0); } void *apr_ldap_compare_node_copy(void *c) { apr_compare_node_t *n = (apr_compare_node_t *)c; apr_compare_node_t *node = (apr_compare_node_t *)apr_ald_alloc(sizeof(apr_compare_node_t)); node->dn = apr_ald_strdup(n->dn); node->attrib = apr_ald_strdup(n->attrib); node->value = apr_ald_strdup(n->value); node->lastcompare = n->lastcompare; return node; } void apr_ldap_compare_node_free(void *n) { apr_compare_node_t *node = (apr_compare_node_t *)n; apr_ald_free(node->dn); apr_ald_free(node->attrib); apr_ald_free(node->value); apr_ald_free(node); } /* ------------------------------------------------------------------ */ unsigned long apr_ldap_dn_compare_node_hash(void *n) { return apr_ald_hash_string(1, ((apr_dn_compare_node_t *)n)->reqdn); } int apr_ldap_dn_compare_node_compare(void *a, void *b) { return (strcmp(((apr_dn_compare_node_t *)a)->reqdn, ((apr_dn_compare_node_t *)b)->reqdn) == 0); } void *apr_ldap_dn_compare_node_copy(void *c) { apr_dn_compare_node_t *n = (apr_dn_compare_node_t *)c; apr_dn_compare_node_t *node = (apr_dn_compare_node_t *)apr_ald_alloc(sizeof(apr_dn_compare_node_t)); node->reqdn = apr_ald_strdup(n->reqdn); node->dn = apr_ald_strdup(n->dn); return node; } void apr_ldap_dn_compare_node_free(void *n) { apr_dn_compare_node_t *node = (apr_dn_compare_node_t *)n; apr_ald_free(node->reqdn); apr_ald_free(node->dn); apr_ald_free(node); } /* ------------------------------------------------------------------ */ apr_status_t apr_ldap_cache_child_kill(void *data); apr_status_t apr_ldap_cache_module_kill(void *data); apr_status_t apr_ldap_cache_module_kill(void *data) { #ifdef APU_HAS_LDAP_SHARED_CACHE if (apr_ldap_mm != NULL) { apr_mm_destroy(apr_ldap_mm); apr_ldap_mm = NULL; } #endif return APR_SUCCESS; } apr_status_t apr_ldap_cache_child_kill(void *data) { /* Nothing to do */ return APR_SUCCESS; } void apr_ldap_cache_init(apr_pool_t *p) { apr_pool_cleanup_register(p, NULL, apr_ldap_cache_module_kill, apr_ldap_cache_child_kill); #ifdef APU_HAS_LDAP_SHARED_CACHE if (apr_mm_useable()) { extern AP_MM *apr_ldap_mm; apr_ldap_mm = apr_mm_create(0, "/tmp/ldap_cache"); if (apr_ldap_mm != NULL) { apr_mm_permission(apr_ldap_mm, ALD_MM_FILE_MODE, ap_user_id, -1); } } #endif apr_ldap_cache = apr_ald_create_cache(50, apr_ldap_url_node_hash, apr_ldap_url_node_compare, apr_ldap_url_node_copy, apr_ldap_url_node_free); } #endif /* APU_HAS_LDAP */
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /* * apr_ldap_cache_mgr.c: LDAP cache manager things * * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan */ #include <apr_ldap.h> #include <private/apu_ldap_cache.h> #include <apr_strings.h> #ifdef APU_HAS_LDAP /* only here until strdup is gone */ #include <string.h> /* here till malloc is gone */ #include <stdlib.h> static const int primes[] = { 11, 19, 37, 73, 109, 163, 251, 367, 557, 823, 1237, 1861, 2777, 4177, 6247, 9371, 14057, 21089, 31627, 47431, 71143, 106721, 160073, 240101, 360163, 540217, 810343, 1215497, 1823231, 2734867, 4102283, 6153409, 9230113, 13845163, 0 }; void apr_ald_free(const void *ptr) { #ifdef APU_HAS_LDAP_SHARED_CACHE if (auth_ldap_mm != NULL) { apr_mm_free(apr_ldap_mm, ptr); } else { free((void *)ptr); } #else free((void *)ptr); #endif } void *apr_ald_alloc(int size) { #ifdef APU_HAS_LDAP_SHARED_CACHE if (apr_ldap_mm != NULL) { return (void *)apr_mm_malloc(apr_ldap_mm, size); } else { return (void *)malloc(size); } #else return (void *)malloc(size); #endif } const char *apr_ald_strdup(const char *s) { #ifdef APU_HAS_LDAP_SHARED_CACHE if (apr_ldap_mm != NULL) { return apr_mm_strdup(apr_ldap_mm, s); } else { return strdup(s); } #else return strdup(s); #endif } /* * Computes the hash on a set of strings. The first argument is the number * of strings to hash, the rest of the args are strings. * Algorithm taken from glibc. */ unsigned long apr_ald_hash_string(int nstr, ...) { int i; va_list args; unsigned long h=0, g; char *str, *p; va_start(args, nstr); for (i=0; i < nstr; ++i) { str = va_arg(args, char *); for (p = str; *p; ++p) { h = ( h << 4 ) + *p; if ( ( g = h & 0xf0000000 ) ) { h = h ^ (g >> 24); h = h ^ g; } } } va_end(args); return h; } /* Purges a cache that has gotten full. We keep track of the time that we added the entry that made the cache 3/4 full, then delete all entries that were added before that time. It's pretty simplistic, but time to purge is only O(n), which is more important. */ void apr_ald_cache_purge(apr_ald_cache_t *cache) { int i; apr_cache_node_t *p, *q; apr_time_t t; cache->last_purge = apr_time_now(); cache->npurged = 0; cache->numpurges++; for (i=0; i < cache->size; ++i) { p = cache->nodes[i]; while (p != NULL) { if (p->add_time < cache->marktime) { q = p->next; (*cache->free)(p->payload); apr_ald_free(p); cache->numentries--; cache->npurged++; p = q; } else { p = p->next; } } } t = apr_time_now(); cache->avg_purgetime = ((t - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) / cache->numpurges; } /* * create caches */ apr_url_node_t *apr_ald_create_caches(apr_ldap_state_t *st, const char *url) { apr_url_node_t *curl; /* inserting URL into URL cache */ curl = (apr_url_node_t *)apr_pcalloc(st->pool, sizeof(apr_url_node_t)); curl->url = url; curl->search_cache = apr_ald_create_cache(st->search_cache_size, apr_ldap_search_node_hash, apr_ldap_search_node_compare, apr_ldap_search_node_copy, apr_ldap_search_node_free); curl->compare_cache = apr_ald_create_cache(st->compare_cache_size, apr_ldap_compare_node_hash, apr_ldap_compare_node_compare, apr_ldap_compare_node_copy, apr_ldap_compare_node_free); curl->dn_compare_cache = apr_ald_create_cache(st->compare_cache_size, apr_ldap_dn_compare_node_hash, apr_ldap_dn_compare_node_compare, apr_ldap_dn_compare_node_copy, apr_ldap_dn_compare_node_free); apr_ald_cache_insert(apr_ldap_cache, curl); return curl; } apr_ald_cache_t *apr_ald_create_cache(unsigned long maxentries, unsigned long (*hashfunc)(void *), int (*comparefunc)(void *, void *), void * (*copyfunc)(void *), void (*freefunc)(void *)) { apr_ald_cache_t *cache; int i; if (maxentries <= 0) return NULL; cache = (apr_ald_cache_t *)apr_ald_alloc(sizeof(apr_ald_cache_t)); if (cache == NULL) return NULL; cache->maxentries = maxentries; cache->numentries = 0; cache->size = maxentries / 3; if (cache->size < 64) cache->size = 64; for (i = 0; primes[i] && primes[i] < cache->size; ++i) ; cache->size = primes[i]? primes[i] : primes[i-1]; cache->nodes = (apr_cache_node_t **)apr_ald_alloc(cache->size * sizeof(apr_cache_node_t *)); for (i=0; i < cache->size; ++i) cache->nodes[i] = NULL; cache->hash = hashfunc; cache->compare = comparefunc; cache->copy = copyfunc; cache->free = freefunc; cache->fullmark = cache->maxentries / 4 * 3; cache->marktime = 0; cache->avg_purgetime = 0.0; cache->numpurges = 0; cache->last_purge = 0; cache->npurged = 0; cache->fetches = 0; cache->hits = 0; cache->inserts = 0; cache->removes = 0; return cache; } void apr_ald_destroy_cache(apr_ald_cache_t *cache) { int i; apr_cache_node_t *p, *q; if (cache == NULL) return; for (i = 0; i < cache->size; ++i) { p = cache->nodes[i]; q = NULL; while (p != NULL) { q = p->next; (*cache->free)(p->payload); apr_ald_free(p); p = q; } } apr_ald_free(cache->nodes); } void *apr_ald_cache_fetch(apr_ald_cache_t *cache, void *payload) { int hashval; apr_cache_node_t *p; if (cache == NULL) return NULL; cache->fetches++; hashval = (*cache->hash)(payload) % cache->size; for (p = cache->nodes[hashval]; p && !(*cache->compare)(p->payload, payload); p = p->next) ; if (p != NULL) { cache->hits++; return p->payload; } else { return NULL; } } /* * Insert an item into the cache. * *** Does not catch duplicates!!! *** */ void apr_ald_cache_insert(apr_ald_cache_t *cache, void *payload) { int hashval; apr_cache_node_t *node; if (cache == NULL || payload == NULL) return; cache->inserts++; hashval = (*cache->hash)(payload) % cache->size; node = (apr_cache_node_t *)apr_ald_alloc(sizeof(apr_cache_node_t)); node->add_time = apr_time_now(); node->payload = (*cache->copy)(payload); node->next = cache->nodes[hashval]; cache->nodes[hashval] = node; if (++cache->numentries == cache->fullmark) cache->marktime=apr_time_now(); if (cache->numentries >= cache->maxentries) apr_ald_cache_purge(cache); } void apr_ald_cache_remove(apr_ald_cache_t *cache, void *payload) { int hashval; apr_cache_node_t *p, *q; if (cache == NULL) return; cache->removes++; hashval = (*cache->hash)(payload) % cache->size; for (p = cache->nodes[hashval], q=NULL; p && !(*cache->compare)(p->payload, payload); p = p->next) { q = p; } /* If p is null, it means that we couldn't find the node, so just return */ if (p == NULL) return; if (q == NULL) { /* We found the node, and it's the first in the list */ cache->nodes[hashval] = p->next; } else { /* We found the node and it's not the first in the list */ q->next = p->next; } (*cache->free)(p->payload); apr_ald_free(p); cache->numentries--; } void apr_ald_cache_display_stats(apr_pool_t *p, apr_ald_cache_t *cache, char *name, char **stats) { int i; int totchainlen = 0; int nchains = 0; double chainlen; apr_cache_node_t *n; char *buf; if (cache == NULL) return; for (i=0; i < cache->size; ++i) { if (cache->nodes[i] != NULL) { nchains++; for (n = cache->nodes[i]; n != NULL; n = n->next) totchainlen++; } } chainlen = nchains? (double)totchainlen / (double)nchains : 0; buf = apr_psprintf(p, "<tr valign='top'>" "<td nowrap>%s</td>" "<td align='right' nowrap>%lu (%.0f%% full)</td>" "<td align='right'>%.1f</td>" "<td align='right'>%lu/%lu</td>" "<td align='right'>%.0f%%</td>" "<td align='right'>%lu/%lu</td>", name, cache->numentries, (double)cache->numentries / (double)cache->maxentries * 100.0, chainlen, cache->hits, cache->fetches, (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0), cache->inserts, cache->removes); if (cache->numpurges) { char str_ctime[APR_CTIME_LEN]; apr_ctime(str_ctime, cache->last_purge); buf = apr_psprintf(p, "%s" "<td align='right'>%lu</td>\n" "<td align='right' nowrap>%s</td>\n", buf, cache->numpurges, str_ctime); } else { buf = apr_psprintf(p, "%s<td colspan='2' align='center'>(none)</td>\n", buf); } buf = apr_psprintf(p, "%s<td align='right'>%.2g</td>\n</tr>", buf, cache->avg_purgetime); *stats = buf; } #endif /* APU_HAS_LDAP */
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /* * apr_ldap_compat.c: LDAP v2/v3 compatibility things * * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan */ #include <apr_ldap.h> #include <private/apu_ldap_cache.h> #ifdef APR_HAVE_LDAP /* * Compatibility for LDAPv2 libraries. Differences between LDAPv2 and * LDAPv3, as they affect this module * * LDAPv3 uses ldap_search_ext_s; LDAPv2 uses only basic ldap_search_s * * LDAPv3 uses ldap_memfree; LDAPv2 just uses free(). * * In this section, we just implement the LDAPv3 SDK functions that are * missing in LDAPv2. * */ #if LDAP_VERSION_MAX == 2 /* * LDAPv2 doesn't support extended search. Since auth_ldap doesn't use * it anyway, we just translate the extended search into a normal search. */ int ldap_search_ext_s(LDAP *ldap, char *base, int scope, char *filter, char **attrs, int attrsonly, void *servertrls, void *clientctrls, void *timeout, int sizelimit, LDAPMessage **res) { return ldap_search_s(ldap, base, scope, filter, attrs, attrsonly, res); } void ldap_memfree(void *p) { free(p); } #endif /* if LDAP_VERSION_MAX */ #endif /* APR_HAVE_LDAP */
smime.p7s
Description: S/MIME Cryptographic Signature