diff options
author | Arno Töll <debian@toell.net> | 2012-01-08 22:53:17 +0100 |
---|---|---|
committer | Arno Töll <debian@toell.net> | 2012-01-08 22:53:17 +0100 |
commit | e072a2dd866b7cb9f14319b80326a4e7fd16fcdf (patch) | |
tree | a49dfc56d94a26011fe157835ff6cbe14edbd8a9 /modules/ldap | |
parent | 0890390c00801651d08d3794e13b31a5dabbf5ef (diff) | |
download | apache2-e072a2dd866b7cb9f14319b80326a4e7fd16fcdf.tar.gz |
Imported Upstream version 2.3.16-beta
Diffstat (limited to 'modules/ldap')
-rw-r--r-- | modules/ldap/NWGNUmakefile | 18 | ||||
-rw-r--r-- | modules/ldap/config.m4 | 19 | ||||
-rw-r--r-- | modules/ldap/mod_ldap.dep | 92 | ||||
-rw-r--r-- | modules/ldap/mod_ldap.dsp | 4 | ||||
-rw-r--r-- | modules/ldap/mod_ldap.mak | 371 | ||||
-rw-r--r-- | modules/ldap/util_ldap.c | 1488 | ||||
-rw-r--r-- | modules/ldap/util_ldap_cache.c | 70 | ||||
-rw-r--r-- | modules/ldap/util_ldap_cache.h | 50 | ||||
-rw-r--r-- | modules/ldap/util_ldap_cache_mgr.c | 85 |
9 files changed, 1414 insertions, 783 deletions
diff --git a/modules/ldap/NWGNUmakefile b/modules/ldap/NWGNUmakefile index aee46a34..ef830253 100644 --- a/modules/ldap/NWGNUmakefile +++ b/modules/ldap/NWGNUmakefile @@ -103,7 +103,7 @@ endif NLM_NAME = utilldap # -# This is used by the link '-desc ' directive. +# This is used by the link '-desc ' directive. # If left blank, NLM_NAME will be used. # NLM_DESCRIPTION = Apache $(VERSION_STR) LDAP Authentication Module @@ -115,7 +115,7 @@ NLM_DESCRIPTION = Apache $(VERSION_STR) LDAP Authentication Module NLM_THREAD_NAME = UtilLDAP Module # -# If this is specified, it will override VERSION value in +# If this is specified, it will override VERSION value in # $(AP_WORK)/build/NWGNUenvironment.inc # NLM_VERSION = @@ -147,11 +147,11 @@ NLM_CHECK_SYM = NLM_FLAGS = # -# If this is specified it will be linked in with the XDCData option in the def +# If this is specified it will be linked in with the XDCData option in the def # file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled # by setting APACHE_UNIPROC in the environment # -XDCDATA = +XDCDATA = # # If there is an NLM target, put it here @@ -199,7 +199,7 @@ FILES_nlm_modules = \ # If the nlm has a msg file, put it's path here # FILE_nlm_msg = - + # # If the nlm has a hlp file put it's path here # @@ -220,15 +220,15 @@ FILES_nlm_Ximports = \ @lldapsdk.imp \ @lldapssl.imp \ $(EOLIST) - -# + +# # Any symbols exported to here # FILES_nlm_exports = \ ldap_module \ $(EOLIST) -# +# # These are the OBJ files needed to create the LIB target above. # Paths must all use the '/' character # @@ -244,7 +244,7 @@ libs :: $(OBJDIR) $(TARGET_lib) nlms :: libs $(TARGET_nlm) # -# Updated this target to create necessary directories and copy files to the +# Updated this target to create necessary directories and copy files to the # correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) # install :: nlms FORCE diff --git a/modules/ldap/config.m4 b/modules/ldap/config.m4 index a598d250..3345bcd9 100644 --- a/modules/ldap/config.m4 +++ b/modules/ldap/config.m4 @@ -4,9 +4,22 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) APACHE_MODPATH_INIT(ldap) ldap_objects="util_ldap.lo util_ldap_cache.lo util_ldap_cache_mgr.lo" -APACHE_MODULE(ldap, LDAP caching and connection pooling services, $ldap_objects, , no, [ - MOD_LDAP_LDADD="`$apu_config --ldap-libs`" || MOD_LDAP_LDADD="" - AC_SUBST(MOD_LDAP_LDADD) +APACHE_MODULE(ldap, LDAP caching and connection pooling services, $ldap_objects, , most , [ + APACHE_CHECK_APR_HAS_LDAP + if test "$ac_cv_APR_HAS_LDAP" = "yes" ; then + if test -z "$apu_config" ; then + LDAP_LIBS="`$apr_config --ldap-libs`" + else + LDAP_LIBS="`$apu_config --ldap-libs`" + fi + APR_ADDTO(MOD_LDAP_LDADD, [$LDAP_LIBS]) + AC_SUBST(MOD_LDAP_LDADD) + else + AC_MSG_WARN([apr/apr-util is compiled without ldap support]) + enable_ldap=no + fi ]) +APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + APACHE_MODPATH_FINISH diff --git a/modules/ldap/mod_ldap.dep b/modules/ldap/mod_ldap.dep deleted file mode 100644 index 62ea880d..00000000 --- a/modules/ldap/mod_ldap.dep +++ /dev/null @@ -1,92 +0,0 @@ -# Microsoft Developer Studio Generated Dependency File, included by mod_ldap.mak - -..\..\build\win32\httpd.rc : \ - "..\..\include\ap_release.h"\ - - -.\util_ldap.c : \ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_regex.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\os.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_ldap.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_optional.h"\ - "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ - "..\..\srclib\apr-util\include\apr_rmm.h"\ - "..\..\srclib\apr-util\include\apr_uri.h"\ - "..\..\srclib\apr\include\apr_hash.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_poll.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_thread_rwlock.h"\ - ".\util_ldap_cache.h"\ - - -.\util_ldap_cache.c : \ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_regex.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\os.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_ldap.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_optional.h"\ - "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ - "..\..\srclib\apr-util\include\apr_rmm.h"\ - "..\..\srclib\apr-util\include\apr_uri.h"\ - "..\..\srclib\apr\include\apr_hash.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_poll.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_thread_rwlock.h"\ - ".\util_ldap_cache.h"\ - - -.\util_ldap_cache_mgr.c : \ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_regex.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_core.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\os.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\include\util_ldap.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_optional.h"\ - "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ - "..\..\srclib\apr-util\include\apr_rmm.h"\ - "..\..\srclib\apr-util\include\apr_uri.h"\ - "..\..\srclib\apr\include\apr_hash.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_poll.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - "..\..\srclib\apr\include\apr_thread_rwlock.h"\ - ".\util_ldap_cache.h"\ - diff --git a/modules/ldap/mod_ldap.dsp b/modules/ldap/mod_ldap.dsp index bacb8ce6..db087575 100644 --- a/modules/ldap/mod_ldap.dsp +++ b/modules/ldap/mod_ldap.dsp @@ -105,6 +105,10 @@ SOURCE=.\util_ldap.c # End Source File # Begin Source File +SOURCE=.\util_ldap.h +# End Source File +# Begin Source File + SOURCE=.\util_ldap_cache.c # End Source File # Begin Source File diff --git a/modules/ldap/mod_ldap.mak b/modules/ldap/mod_ldap.mak deleted file mode 100644 index 36bb0f63..00000000 --- a/modules/ldap/mod_ldap.mak +++ /dev/null @@ -1,371 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_ldap.dsp -!IF "$(CFG)" == "" -CFG=mod_ldap - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_ldap - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_ldap - Win32 Release" && "$(CFG)" != "mod_ldap - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_ldap.mak" CFG="mod_ldap - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_ldap - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_ldap - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_ldap - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_ldap.so" "$(DS_POSTBUILD_DEP)" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_ldap.so" "$(DS_POSTBUILD_DEP)" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_ldap.res" - -@erase "$(INTDIR)\mod_ldap_src.idb" - -@erase "$(INTDIR)\mod_ldap_src.pdb" - -@erase "$(INTDIR)\util_ldap.obj" - -@erase "$(INTDIR)\util_ldap_cache.obj" - -@erase "$(INTDIR)\util_ldap_cache_mgr.obj" - -@erase "$(OUTDIR)\mod_ldap.exp" - -@erase "$(OUTDIR)\mod_ldap.lib" - -@erase "$(OUTDIR)\mod_ldap.pdb" - -@erase "$(OUTDIR)\mod_ldap.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "LDAP_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_ldap_src" /FD /c - -.c{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_ldap.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_ldap.so" /d LONG_NAME="ldap_module for Apache" -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_ldap.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib wldap32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_ldap.pdb" /debug /out:"$(OUTDIR)\mod_ldap.so" /implib:"$(OUTDIR)\mod_ldap.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_ldap.so /opt:ref -LINK32_OBJS= \ - "$(INTDIR)\util_ldap.obj" \ - "$(INTDIR)\util_ldap_cache.obj" \ - "$(INTDIR)\util_ldap_cache_mgr.obj" \ - "$(INTDIR)\mod_ldap.res" \ - "..\..\srclib\apr\Release\libapr-1.lib" \ - "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ - "..\..\Release\libhttpd.lib" - -"$(OUTDIR)\mod_ldap.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -TargetPath=.\Release\mod_ldap.so -SOURCE="$(InputPath)" -PostBuild_Desc=Embed .manifest -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep - -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_ldap.so" - if exist .\Release\mod_ldap.so.manifest mt.exe -manifest .\Release\mod_ldap.so.manifest -outputresource:.\Release\mod_ldap.so;2 - echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" - -!ELSEIF "$(CFG)" == "mod_ldap - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_ldap.so" "$(DS_POSTBUILD_DEP)" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_ldap.so" "$(DS_POSTBUILD_DEP)" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_ldap.res" - -@erase "$(INTDIR)\mod_ldap_src.idb" - -@erase "$(INTDIR)\mod_ldap_src.pdb" - -@erase "$(INTDIR)\util_ldap.obj" - -@erase "$(INTDIR)\util_ldap_cache.obj" - -@erase "$(INTDIR)\util_ldap_cache_mgr.obj" - -@erase "$(OUTDIR)\mod_ldap.exp" - -@erase "$(OUTDIR)\mod_ldap.lib" - -@erase "$(OUTDIR)\mod_ldap.pdb" - -@erase "$(OUTDIR)\mod_ldap.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "LDAP_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_ldap_src" /FD /EHsc /c - -.c{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_ldap.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_ldap.so" /d LONG_NAME="ldap_module for Apache" -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_ldap.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib wldap32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_ldap.pdb" /debug /out:"$(OUTDIR)\mod_ldap.so" /implib:"$(OUTDIR)\mod_ldap.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_ldap.so -LINK32_OBJS= \ - "$(INTDIR)\util_ldap.obj" \ - "$(INTDIR)\util_ldap_cache.obj" \ - "$(INTDIR)\util_ldap_cache_mgr.obj" \ - "$(INTDIR)\mod_ldap.res" \ - "..\..\srclib\apr\Debug\libapr-1.lib" \ - "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ - "..\..\Debug\libhttpd.lib" - -"$(OUTDIR)\mod_ldap.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -TargetPath=.\Debug\mod_ldap.so -SOURCE="$(InputPath)" -PostBuild_Desc=Embed .manifest -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep - -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_ldap.so" - if exist .\Debug\mod_ldap.so.manifest mt.exe -manifest .\Debug\mod_ldap.so.manifest -outputresource:.\Debug\mod_ldap.so;2 - echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" - -!ENDIF - - -!IF "$(NO_EXTERNAL_DEPS)" != "1" -!IF EXISTS("mod_ldap.dep") -!INCLUDE "mod_ldap.dep" -!ELSE -!MESSAGE Warning: cannot find "mod_ldap.dep" -!ENDIF -!ENDIF - - -!IF "$(CFG)" == "mod_ldap - Win32 Release" || "$(CFG)" == "mod_ldap - Win32 Debug" - -!IF "$(CFG)" == "mod_ldap - Win32 Release" - -"libapr - Win32 Release" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" - cd "..\..\modules\ldap" - -"libapr - Win32 ReleaseCLEAN" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN - cd "..\..\modules\ldap" - -!ELSEIF "$(CFG)" == "mod_ldap - Win32 Debug" - -"libapr - Win32 Debug" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" - cd "..\..\modules\ldap" - -"libapr - Win32 DebugCLEAN" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN - cd "..\..\modules\ldap" - -!ENDIF - -!IF "$(CFG)" == "mod_ldap - Win32 Release" - -"libaprutil - Win32 Release" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" - cd "..\..\modules\ldap" - -"libaprutil - Win32 ReleaseCLEAN" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN - cd "..\..\modules\ldap" - -!ELSEIF "$(CFG)" == "mod_ldap - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\ldap" - -"libaprutil - Win32 DebugCLEAN" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN - cd "..\..\modules\ldap" - -!ENDIF - -!IF "$(CFG)" == "mod_ldap - Win32 Release" - -"libhttpd - Win32 Release" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" - cd ".\modules\ldap" - -"libhttpd - Win32 ReleaseCLEAN" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN - cd ".\modules\ldap" - -!ELSEIF "$(CFG)" == "mod_ldap - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" - cd ".\modules\ldap" - -"libhttpd - Win32 DebugCLEAN" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN - cd ".\modules\ldap" - -!ENDIF - -SOURCE=..\..\build\win32\httpd.rc - -!IF "$(CFG)" == "mod_ldap - Win32 Release" - - -"$(INTDIR)\mod_ldap.res" : $(SOURCE) "$(INTDIR)" - $(RSC) /l 0x409 /fo"$(INTDIR)\mod_ldap.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_ldap.so" /d LONG_NAME="ldap_module for Apache" $(SOURCE) - - -!ELSEIF "$(CFG)" == "mod_ldap - Win32 Debug" - - -"$(INTDIR)\mod_ldap.res" : $(SOURCE) "$(INTDIR)" - $(RSC) /l 0x409 /fo"$(INTDIR)\mod_ldap.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_ldap.so" /d LONG_NAME="ldap_module for Apache" $(SOURCE) - - -!ENDIF - -SOURCE=.\util_ldap.c - -"$(INTDIR)\util_ldap.obj" : $(SOURCE) "$(INTDIR)" - - -SOURCE=.\util_ldap_cache.c - -"$(INTDIR)\util_ldap_cache.obj" : $(SOURCE) "$(INTDIR)" - - -SOURCE=.\util_ldap_cache_mgr.c - -"$(INTDIR)\util_ldap_cache_mgr.obj" : $(SOURCE) "$(INTDIR)" - - - -!ENDIF - diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c index 08f21496..46840ad6 100644 --- a/modules/ldap/util_ldap.c +++ b/modules/ldap/util_ldap.c @@ -28,6 +28,7 @@ #include "http_log.h" #include "http_protocol.h" #include "http_request.h" +#include "util_mutex.h" #include "util_ldap.h" #include "util_ldap_cache.h" @@ -41,27 +42,37 @@ #error mod_ldap requires APR-util to have LDAP support built in #endif -#ifdef AP_NEED_SET_MUTEX_PERMS -#include "unixd.h" -#endif - - /* defines for certificate file types - */ -#define LDAP_CA_TYPE_UNKNOWN 0 -#define LDAP_CA_TYPE_DER 1 -#define LDAP_CA_TYPE_BASE64 2 -#define LDAP_CA_TYPE_CERT7_DB 3 - /* Default define for ldap functions that need a SIZELIMIT but * do not have the define - * XXX This should be removed once a supporting #define is + * XXX This should be removed once a supporting #define is * released through APR-Util. */ #ifndef APR_LDAP_SIZELIMIT #define APR_LDAP_SIZELIMIT -1 #endif +#ifdef LDAP_OPT_DEBUG_LEVEL +#define AP_LDAP_OPT_DEBUG LDAP_OPT_DEBUG_LEVEL +#else +#ifdef LDAP_OPT_DEBUG +#define AP_LDAP_OPT_DEBUG LDAP_OPT_DEBUG +#endif +#endif + +#define AP_LDAP_HOPLIMIT_UNSET -1 +#define AP_LDAP_CHASEREFERRALS_OFF 0 +#define AP_LDAP_CHASEREFERRALS_ON 1 + +#define AP_LDAP_CONNPOOL_DEFAULT -1 +#define AP_LDAP_CONNPOOL_INFINITE -2 + +#if !defined(LDAP_OPT_NETWORK_TIMEOUT) && defined(LDAP_OPT_CONNECT_TIMEOUT) +#define LDAP_OPT_NETWORK_TIMEOUT LDAP_OPT_CONNECT_TIMEOUT +#endif + module AP_MODULE_DECLARE_DATA ldap_module; +static const char *ldap_cache_mutex_type = "ldap-cache"; +static apr_status_t uldap_connection_unbind(void *param); #define LDAP_CACHE_LOCK() do { \ if (st->util_ldap_cache_lock) \ @@ -99,19 +110,22 @@ static void util_ldap_strdup (char **str, const char *newstr) */ static int util_ldap_handler(request_rec *r) { - util_ldap_state_t *st = (util_ldap_state_t *) - ap_get_module_config(r->server->module_config, - &ldap_module); + util_ldap_state_t *st; r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) + if (r->method_number != M_GET) { return DECLINED; + } if (strcmp(r->handler, "ldap-status")) { return DECLINED; } - r->content_type = "text/html; charset=ISO-8859-1"; + st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config, + &ldap_module); + + ap_set_content_type(r, "text/html; charset=ISO-8859-1"); + if (r->header_only) return OK; @@ -125,9 +139,9 @@ static int util_ldap_handler(request_rec *r) return OK; } -/* ------------------------------------------------------------------ */ +/* ------------------------------------------------------------------ */ /* * Closes an LDAP connection by unlocking it. The next time * uldap_connection_find() is called this connection will be @@ -136,29 +150,27 @@ static int util_ldap_handler(request_rec *r) static void uldap_connection_close(util_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... - */ - - /* mark our connection as available for reuse */ - + /* We leave bound LDAP connections floating around in our pool, + * but always check/fix the binddn/bindpw when we take them out + * of the pool + */ + if (!ldc->keep) { + uldap_connection_unbind(ldc); + } + else { + /* mark our connection as available for reuse */ + ldc->freed = apr_time_now(); #if APR_HAS_THREADS - apr_thread_mutex_unlock(ldc->lock); + apr_thread_mutex_unlock(ldc->lock); #endif + } } /* * Destroys an LDAP connection by unbinding and closing the connection to * the LDAP server. It is used to bring the connection back to a known - * state after an error, and during pool cleanup. + * state after an error. */ static apr_status_t uldap_connection_unbind(void *param) { @@ -170,54 +182,103 @@ static apr_status_t uldap_connection_unbind(void *param) ldc->ldap = NULL; } ldc->bound = 0; + + /* forget the rebind info for this conn */ + if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + apr_ldap_rebind_remove(ldc->ldap); + apr_pool_clear(ldc->rebind_pool); + } } return APR_SUCCESS; } - +/* not presently used, not part of the API */ +#if 0 /* - * Clean up an LDAP connection by unbinding and unlocking the connection. - * This function is registered with the pool cleanup function - causing - * the LDAP connections to be shut down cleanly on graceful restart. + * util_ldap_connection_remove frees all storage associated with the LDAP + * connection and removes it completely from the per-virtualhost list of + * connections + * + * The caller should hold the lock for this connection */ -static apr_status_t uldap_connection_cleanup(void *param) -{ - util_ldap_connection_t *ldc = param; +static apr_status_t util_ldap_connection_remove (void *param) { + util_ldap_connection_t *ldc = param, *l = NULL, *prev = NULL; + util_ldap_state_t *st; - if (ldc) { + if (!ldc) return APR_SUCCESS; - /* unbind and disconnect from the LDAP server */ - uldap_connection_unbind(ldc); + st = ldc->st; - /* free the username and password */ - if (ldc->bindpw) { - free((void*)ldc->bindpw); - } - if (ldc->binddn) { - free((void*)ldc->binddn); - } + uldap_connection_unbind(ldc); - /* unlock this entry */ - uldap_connection_close(ldc); +#if APR_HAS_THREADS + apr_thread_mutex_lock(st->mutex); +#endif + /* Remove ldc from the list */ + for (l=st->connections; l; l=l->next) { + if (l == ldc) { + if (prev) { + prev->next = l->next; + } + else { + st->connections = l->next; + } + break; + } + prev = l; } + if (ldc->bindpw) { + free((void*)ldc->bindpw); + } + if (ldc->binddn) { + free((void*)ldc->binddn); + } + +#if APR_HAS_THREADS + apr_thread_mutex_unlock(ldc->lock); + apr_thread_mutex_unlock(st->mutex); +#endif + + /* Destory the pool associated with this connection */ + + apr_pool_destroy(ldc->pool); + return APR_SUCCESS; } +#endif static int uldap_connection_init(request_rec *r, - util_ldap_connection_t *ldc ) + util_ldap_connection_t *ldc) { int rc = 0, ldap_option = 0; int version = LDAP_VERSION3; apr_ldap_err_t *result = NULL; #ifdef LDAP_OPT_NETWORK_TIMEOUT - struct timeval timeOut = {10,0}; /* 10 second connection timeout */ + struct timeval connectionTimeout = {0}; #endif util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module); + int have_client_certs = !apr_is_empty_array(ldc->client_certs); +#if !APR_HAS_SOLARIS_LDAPSDK + /* + * Normally we enable SSL/TLS with apr_ldap_set_option(), except + * with Solaris LDAP, where this is broken. + */ + int secure = APR_LDAP_NONE; +#else + /* + * With Solaris LDAP, we enable TSL via the secure argument + * to apr_ldap_init(). This requires a fix from apr-util >= 1.4.0. + * + * Just in case client certificates ever get supported, we + * handle those as with the other LDAP SDKs. + */ + int secure = have_client_certs ? APR_LDAP_NONE : ldc->secure; +#endif /* Since the host will include a port if the default port is not used, * always specify the default ports for the port parameter. This will @@ -228,9 +289,7 @@ static int uldap_connection_init(request_rec *r, apr_ldap_init(r->pool, &(ldc->ldap), ldc->host, APR_LDAP_SSL == ldc->secure ? LDAPS_PORT : LDAP_PORT, - APR_LDAP_NONE, - &(result)); - + secure, &(result)); if (NULL == result) { /* something really bad happened */ @@ -243,6 +302,8 @@ static int uldap_connection_init(request_rec *r, if (result->rc) { ldc->reason = result->reason; + ldc->bound = 0; + return result->rc; } if (NULL == ldc->ldap) @@ -257,11 +318,23 @@ static int uldap_connection_init(request_rec *r, return(result->rc); } + if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + /* Now that we have an ldap struct, add it to the referral list for rebinds. */ + rc = apr_ldap_rebind_add(ldc->rebind_pool, ldc->ldap, ldc->binddn, ldc->bindpw); + if (rc != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01277) + "LDAP: Unable to add rebind cross reference entry. Out of memory?"); + uldap_connection_unbind(ldc); + ldc->reason = "LDAP: Unable to add rebind cross reference entry."; + return(rc); + } + } + /* always default to LDAP V3 */ ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); /* set client certificates */ - if (!apr_is_empty_array(ldc->client_certs)) { + if (have_client_certs) { apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT, ldc->client_certs, &(result)); if (LDAP_SUCCESS != result->rc) { @@ -272,7 +345,12 @@ static int uldap_connection_init(request_rec *r, } /* switch on SSL/TLS */ - if (APR_LDAP_NONE != ldc->secure) { + if (APR_LDAP_NONE != ldc->secure +#if APR_HAS_SOLARIS_LDAPSDK + /* See comments near apr_ldap_init() above */ + && have_client_certs +#endif + ) { apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS, &ldc->secure, &(result)); if (LDAP_SUCCESS != result->rc) { @@ -286,10 +364,53 @@ static int uldap_connection_init(request_rec *r, ldap_option = ldc->deref; ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option); + if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + /* Set options for rebind and referrals. */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01278) + "LDAP: Setting referrals to %s.", + ((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ? "On" : "Off")); + apr_ldap_set_option(r->pool, ldc->ldap, + APR_LDAP_OPT_REFERRALS, + (void *)((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ? + LDAP_OPT_ON : LDAP_OPT_OFF), + &(result)); + if (result->rc != LDAP_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01279) + "Unable to set LDAP_OPT_REFERRALS option to %s: %d.", + ((ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) ? "On" : "Off"), + result->rc); + result->reason = "Unable to set LDAP_OPT_REFERRALS."; + ldc->reason = result->reason; + uldap_connection_unbind(ldc); + return(result->rc); + } + + if ((ldc->ReferralHopLimit != AP_LDAP_HOPLIMIT_UNSET) && ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + /* Referral hop limit - only if referrals are enabled and a hop limit is explicitly requested */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01280) + "Setting referral hop limit to %d.", + ldc->ReferralHopLimit); + apr_ldap_set_option(r->pool, ldc->ldap, + APR_LDAP_OPT_REFHOPLIMIT, + (void *)&ldc->ReferralHopLimit, + &(result)); + if (result->rc != LDAP_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01281) + "Unable to set LDAP_OPT_REFHOPLIMIT option to %d: %d.", + ldc->ReferralHopLimit, + result->rc); + result->reason = "Unable to set LDAP_OPT_REFHOPLIMIT."; + ldc->reason = result->reason; + uldap_connection_unbind(ldc); + return(result->rc); + } + } + } + /*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */ #ifdef APR_LDAP_OPT_VERIFY_CERT - apr_ldap_set_option(r->pool, ldc->ldap, - APR_LDAP_OPT_VERIFY_CERT, &(st->verify_svr_cert), &(result)); + apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_VERIFY_CERT, + &(st->verify_svr_cert), &(result)); #else #if defined(LDAPSSL_VERIFY_SERVER) if (st->verify_svr_cert) { @@ -314,22 +435,87 @@ static int uldap_connection_init(request_rec *r, #ifdef LDAP_OPT_NETWORK_TIMEOUT if (st->connectionTimeout > 0) { - timeOut.tv_sec = st->connectionTimeout; + connectionTimeout.tv_sec = st->connectionTimeout; } - if (st->connectionTimeout >= 0) { + if (connectionTimeout.tv_sec > 0) { rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT, - (void *)&timeOut, &(result)); + (void *)&connectionTimeout, &(result)); if (APR_SUCCESS != rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(01282) "LDAP: Could not set the connection timeout"); } } #endif +#ifdef LDAP_OPT_TIMEOUT + /* + * LDAP_OPT_TIMEOUT is not portable, but it influences all synchronous ldap + * function calls and not just ldap_search_ext_s(), which accepts a timeout + * parameter. + * XXX: It would be possible to simulate LDAP_OPT_TIMEOUT by replacing all + * XXX: synchronous ldap function calls with asynchronous calls and using + * XXX: ldap_result() with a timeout. + */ + if (st->opTimeout) { + rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_TIMEOUT, + st->opTimeout, &(result)); + if (APR_SUCCESS != rc) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(01283) + "LDAP: Could not set LDAP_OPT_TIMEOUT"); + } + } +#endif + return(rc); } +static int uldap_ld_errno(util_ldap_connection_t *ldc) +{ + int ldaprc; +#ifdef LDAP_OPT_ERROR_NUMBER + if (LDAP_SUCCESS == ldap_get_option(ldc->ldap, LDAP_OPT_ERROR_NUMBER, &ldaprc)) return ldaprc; +#endif +#ifdef LDAP_OPT_RESULT_CODE + if (LDAP_SUCCESS == ldap_get_option(ldc->ldap, LDAP_OPT_RESULT_CODE, &ldaprc)) return ldaprc; +#endif + return LDAP_OTHER; +} + +/* + * Replacement function for ldap_simple_bind_s() with a timeout. + * To do this in a portable way, we have to use ldap_simple_bind() and + * ldap_result(). + * + * Returns LDAP_SUCCESS on success; and an error code on failure + */ +static int uldap_simple_bind(util_ldap_connection_t *ldc, char *binddn, + char* bindpw, struct timeval *timeout) +{ + LDAPMessage *result; + int rc; + int msgid = ldap_simple_bind(ldc->ldap, binddn, bindpw); + if (msgid == -1) { + ldc->reason = "LDAP: ldap_simple_bind() failed"; + return uldap_ld_errno(ldc); + } + rc = ldap_result(ldc->ldap, msgid, 0, timeout, &result); + if (rc == -1) { + ldc->reason = "LDAP: ldap_simple_bind() result retrieval failed"; + /* -1 is LDAP_SERVER_DOWN in openldap, use something else */ + return uldap_ld_errno(ldc); + } + else if (rc == 0) { + ldc->reason = "LDAP: ldap_simple_bind() timed out"; + rc = LDAP_TIMEOUT; + } else if (ldap_parse_result(ldc->ldap, result, &rc, NULL, NULL, NULL, + NULL, 1) == -1) { + ldc->reason = "LDAP: ldap_simple_bind() parse result failed"; + return uldap_ld_errno(ldc); + } + return rc; +} + /* * 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. @@ -341,6 +527,8 @@ static int uldap_connection_open(request_rec *r, { int rc = 0; int failures = 0; + int new_connection = 0; + util_ldap_state_t *st; /* sanity check for NULL */ if (!ldc) { @@ -359,6 +547,7 @@ static int uldap_connection_open(request_rec *r, */ if (NULL == ldc->ldap) { + new_connection = 1; rc = uldap_connection_init( r, ldc ); if (LDAP_SUCCESS != rc) { @@ -367,38 +556,65 @@ static int uldap_connection_open(request_rec *r, } - /* loop trying to bind up to 10 times if LDAP_SERVER_DOWN error is - * returned. Break out of the loop on Success or any other error. + st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, + &ldap_module); + + /* loop trying to bind up to st->retries times if LDAP_SERVER_DOWN or LDAP_TIMEOUT + * are returned. Close the connection before the first retry, and then on every + * other retry. + * + * On Success or any other error, break out of the loop. * * NOTE: Looping is probably not a great idea. If the server isn't * responding the chances it will respond after a few tries are poor. * However, the original code looped and it only happens on * the error condition. - */ - for (failures=0; failures<10; failures++) - { - rc = ldap_simple_bind_s(ldc->ldap, - (char *)ldc->binddn, - (char *)ldc->bindpw); - if (!AP_LDAP_IS_SERVER_DOWN(rc)) { + */ + + while (failures <= st->retries) { + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + rc = uldap_simple_bind(ldc, (char *)ldc->binddn, (char *)ldc->bindpw, + st->opTimeout); + + if (rc == LDAP_SUCCESS) break; + + failures++; + + if (AP_LDAP_IS_SERVER_DOWN(rc)) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "ldap_simple_bind() failed with server down " + "(try %d)", failures); + } + else if (rc == LDAP_TIMEOUT) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01284) + "ldap_simple_bind() timed out on %s " + "connection, dropped by firewall?", + new_connection ? "new" : "reused"); + } + else { + /* Other errors not retryable */ break; - } else if (failures == 5) { - /* attempt to init the connection once again */ - uldap_connection_unbind( ldc ); - rc = uldap_connection_init( r, ldc ); - if (LDAP_SUCCESS != rc) - { - break; - } - } + } + + if (!(failures % 2)) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "attempt to re-init the connection"); + uldap_connection_unbind(ldc); + if (LDAP_SUCCESS != uldap_connection_init(r, ldc)) { + /* leave rc as the initial bind return code */ + break; + } + } } /* free the handle if there was an error */ if (LDAP_SUCCESS != rc) { - uldap_connection_unbind(ldc); - ldc->reason = "LDAP: ldap_simple_bind_s() failed"; + uldap_connection_unbind(ldc); + ldc->reason = "LDAP: ldap_simple_bind() failed"; } else { ldc->bound = 1; @@ -434,9 +650,12 @@ static int compare_client_certs(apr_array_header_t *srcs, src = (struct apr_ldap_opt_tls_cert_t *)srcs->elts; dest = (struct apr_ldap_opt_tls_cert_t *)dests->elts; for (i = 0; i < srcs->nelts; i++) { - if (strcmp(src[i].path, dest[i].path) || - strcmp(src[i].password, dest[i].password) || - src[i].type != dest[i].type) { + if ((strcmp(src[i].path, dest[i].path)) || + (src[i].type != dest[i].type) || + /* One is passwordless? If so, then not equal */ + ((src[i].password == NULL) ^ (dest[i].password == NULL)) || + (src[i].password != NULL && dest[i].password != NULL && + strcmp(src[i].password, dest[i].password))) { return 1; } } @@ -463,11 +682,13 @@ static util_ldap_connection_t * { struct util_ldap_connection_t *l, *p; /* To traverse the linked list */ int secureflag = secure; + apr_time_t now = apr_time_now(); util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module); - + util_ldap_config_t *dc = + (util_ldap_config_t *) ap_get_module_config(r->per_dir_config, &ldap_module); #if APR_HAS_THREADS /* mutex lock this function */ @@ -491,8 +712,17 @@ static util_ldap_connection_t * && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw))) && (l->deref == deref) && (l->secure == secureflag) - && !compare_client_certs(st->client_certs, l->client_certs)) + && !compare_client_certs(dc->client_certs, l->client_certs)) { + if (st->connection_pool_ttl > 0) { + if (l->bound && (now - l->freed) > st->connection_pool_ttl) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Removing LDAP connection last used %" APR_TIME_T_FMT " seconds ago", + (now - l->freed) / APR_USEC_PER_SEC); + uldap_connection_unbind(l); + /* Go ahead (by falling through) and use it, so we don't create more just to unbind some other old ones */ + } + } break; } #if APR_HAS_THREADS @@ -516,10 +746,12 @@ static util_ldap_connection_t * #endif if ((l->port == port) && (strcmp(l->host, host) == 0) && (l->deref == deref) && (l->secure == secureflag) && - !compare_client_certs(st->client_certs, l->client_certs)) + !compare_client_certs(dc->client_certs, l->client_certs)) { /* the bind credentials have changed */ - l->bound = 0; + /* no check for connection_pool_ttl, since we are unbinding any way */ + uldap_connection_unbind(l); + util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); break; @@ -538,37 +770,43 @@ static util_ldap_connection_t * /* artificially disable cache */ /* l = NULL; */ - /* If no connection what found after the second search, we + /* If no connection was 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(util_ldap_connection_t)); - if (apr_pool_create(&l->pool, st->pool) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, + apr_pool_t *newpool; + if (apr_pool_create(&newpool, NULL) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01285) "util_ldap: Failed to create memory pool"); #if APR_HAS_THREADS apr_thread_mutex_unlock(st->mutex); #endif return NULL; - } + + /* + * 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 of this connection in the new pool */ + l = apr_pcalloc(newpool, sizeof(util_ldap_connection_t)); + l->pool = newpool; + l->st = st; + #if APR_HAS_THREADS - apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool); + apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, l->pool); apr_thread_mutex_lock(l->lock); #endif l->bound = 0; - l->host = apr_pstrdup(st->pool, host); + l->host = apr_pstrdup(l->pool, host); l->port = port; l->deref = deref; util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); + l->ChaseReferrals = dc->ChaseReferrals; + l->ReferralHopLimit = dc->ReferralHopLimit; /* The security mode after parsing the URL will always be either * APR_LDAP_NONE (ldap://) or APR_LDAP_SSL (ldaps://). @@ -578,12 +816,21 @@ static util_ldap_connection_t * l->secure = secureflag; /* save away a copy of the client cert list that is presently valid */ - l->client_certs = apr_array_copy_hdr(l->pool, st->client_certs); + l->client_certs = apr_array_copy_hdr(l->pool, dc->client_certs); - /* add the cleanup to the pool */ - apr_pool_cleanup_register(l->pool, l, - uldap_connection_cleanup, - apr_pool_cleanup_null); + /* whether or not to keep this connection in the pool when it's returned */ + l->keep = (st->connection_pool_ttl == 0) ? 0 : 1; + + if (l->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + if (apr_pool_create(&(l->rebind_pool), l->pool) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01286) + "util_ldap: Failed to create memory pool"); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(st->mutex); +#endif + return NULL; + } + } if (p) { p->next = l; @@ -670,11 +917,14 @@ static int uldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc, } start_over: - if (failures++ > 10) { - /* too many failures */ + if (failures > st->retries) { return result; } + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + /* make a server connection */ if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { /* connect to server failed */ @@ -684,12 +934,24 @@ start_over: /* search for reqdn */ result = ldap_search_ext_s(ldc->ldap, (char *)reqdn, LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 1, - NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res); + NULL, NULL, st->opTimeout, APR_LDAP_SIZELIMIT, &res); if (AP_LDAP_IS_SERVER_DOWN(result)) { ldc->reason = "DN Comparison ldap_search_ext_s() " "failed with server down"; uldap_connection_unbind(ldc); + failures++; + goto start_over; + } + if (result == LDAP_TIMEOUT && failures == 0) { + /* + * we are reusing a connection that doesn't seem to be active anymore + * (firewall state drop?), let's try a new connection. + */ + ldc->reason = "DN Comparison ldap_search_ext_s() " + "failed with timeout"; + uldap_connection_unbind(ldc); + failures++; goto start_over; } if (result != LDAP_SUCCESS) { @@ -734,9 +996,9 @@ start_over: /* * 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 + * (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 * */ static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, @@ -773,6 +1035,8 @@ static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, the_compare_node.attrib = (char *)attrib; the_compare_node.value = (char *)value; the_compare_node.result = 0; + the_compare_node.sgl_processed = 0; + the_compare_node.subgroupList = NULL; compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node); @@ -785,24 +1049,24 @@ static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, } else { /* ...and it is good */ - /* unlock this read lock */ - LDAP_CACHE_UNLOCK(); if (LDAP_COMPARE_TRUE == compare_nodep->result) { ldc->reason = "Comparison true (cached)"; - return compare_nodep->result; } else if (LDAP_COMPARE_FALSE == compare_nodep->result) { ldc->reason = "Comparison false (cached)"; - return compare_nodep->result; } else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) { ldc->reason = "Comparison no such attribute (cached)"; - return compare_nodep->result; } else { ldc->reason = "Comparison undefined (cached)"; - return compare_nodep->result; } + + /* record the result code to return with the reason... */ + result = compare_nodep->result; + /* and unlock this read lock */ + LDAP_CACHE_UNLOCK(); + return result; } } /* unlock this read lock */ @@ -810,10 +1074,14 @@ static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, } start_over: - if (failures++ > 10) { - /* too many failures */ + if (failures > st->retries) { return result; } + + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { /* connect failed */ return result; @@ -823,10 +1091,21 @@ start_over: (char *)dn, (char *)attrib, (char *)value); - if (AP_LDAP_IS_SERVER_DOWN(result)) { + if (AP_LDAP_IS_SERVER_DOWN(result)) { /* connection failed - try again */ ldc->reason = "ldap_compare_s() failed with server down"; uldap_connection_unbind(ldc); + failures++; + goto start_over; + } + if (result == LDAP_TIMEOUT && failures == 0) { + /* + * we are reusing a connection that doesn't seem to be active anymore + * (firewall state drop?), let's try a new connection. + */ + ldc->reason = "ldap_compare_s() failed with timeout"; + uldap_connection_unbind(ldc); + failures++; goto start_over; } @@ -839,6 +1118,8 @@ start_over: LDAP_CACHE_LOCK(); the_compare_node.lastcompare = curtime; the_compare_node.result = result; + the_compare_node.sgl_processed = 0; + the_compare_node.subgroupList = NULL; /* If the node doesn't exist then insert it, otherwise just update * it with the last results @@ -850,7 +1131,14 @@ start_over: || (strcmp(the_compare_node.attrib,compare_nodep->attrib) != 0) || (strcmp(the_compare_node.value, compare_nodep->value) != 0)) { - util_ald_cache_insert(curl->compare_cache, &the_compare_node); + void *junk; + + junk = util_ald_cache_insert(curl->compare_cache, + &the_compare_node); + if (junk == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01287) + "cache_compare: Cache insertion failure."); + } } else { compare_nodep->lastcompare = curtime; @@ -874,6 +1162,430 @@ start_over: return result; } + +static util_compare_subgroup_t* uldap_get_subgroups(request_rec *r, + util_ldap_connection_t *ldc, + const char *url, + const char *dn, + char **subgroupAttrs, + apr_array_header_t *subgroupclasses) +{ + int failures = 0; + int result = LDAP_COMPARE_FALSE; + util_compare_subgroup_t *res = NULL; + LDAPMessage *sga_res, *entry; + struct mod_auth_ldap_groupattr_entry_t *sgc_ents; + apr_array_header_t *subgroups = apr_array_make(r->pool, 20, sizeof(char *)); + util_ldap_state_t *st = (util_ldap_state_t *) + ap_get_module_config(r->server->module_config, + &ldap_module); + + sgc_ents = (struct mod_auth_ldap_groupattr_entry_t *) subgroupclasses->elts; + + if (!subgroupAttrs) { + return res; + } + +start_over: + /* + * 3.B. The cache didn't have any subgrouplist yet. Go check for subgroups. + */ + if (failures > st->retries) { + return res; + } + + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + + + if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { + /* connect failed */ + return res; + } + + /* try to do the search */ + result = ldap_search_ext_s(ldc->ldap, (char *)dn, LDAP_SCOPE_BASE, + (char *)"cn=*", subgroupAttrs, 0, + NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &sga_res); + if (AP_LDAP_IS_SERVER_DOWN(result)) { + ldc->reason = "ldap_search_ext_s() for subgroups failed with server" + " down"; + uldap_connection_unbind(ldc); + failures++; + goto start_over; + } + if (result == LDAP_TIMEOUT && failures == 0) { + /* + * we are reusing a connection that doesn't seem to be active anymore + * (firewall state drop?), let's try a new connection. + */ + ldc->reason = "ldap_search_ext_s() for subgroups failed with timeout"; + uldap_connection_unbind(ldc); + failures++; + 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 subgroups failed"; + return res; + } + + entry = ldap_first_entry(ldc->ldap, sga_res); + + /* + * Get values for the provided sub-group attributes. + */ + if (subgroupAttrs) { + int indx = 0, tmp_sgcIndex; + + while (subgroupAttrs[indx]) { + char **values; + int val_index = 0; + + /* Get *all* matching "member" values from this group. */ + values = ldap_get_values(ldc->ldap, entry, subgroupAttrs[indx]); + + if (values) { + val_index = 0; + /* + * Now we are going to pare the subgroup members of this group + * to *just* the subgroups, add them to the compare_nodep, and + * then proceed to check the new level of subgroups. + */ + while (values[val_index]) { + /* Check if this entry really is a group. */ + tmp_sgcIndex = 0; + result = LDAP_COMPARE_FALSE; + while ((tmp_sgcIndex < subgroupclasses->nelts) + && (result != LDAP_COMPARE_TRUE)) { + result = uldap_cache_compare(r, ldc, url, + values[val_index], + "objectClass", + sgc_ents[tmp_sgcIndex].name + ); + + if (result != LDAP_COMPARE_TRUE) { + tmp_sgcIndex++; + } + } + /* It's a group, so add it to the array. */ + if (result == LDAP_COMPARE_TRUE) { + char **newgrp = (char **) apr_array_push(subgroups); + *newgrp = apr_pstrdup(r->pool, values[val_index]); + } + val_index++; + } + ldap_value_free(values); + } + indx++; + } + } + + ldap_msgfree(sga_res); + + if (subgroups->nelts > 0) { + /* We need to fill in tmp_local_subgroups using the data from LDAP */ + int sgindex; + char **group; + res = apr_pcalloc(r->pool, sizeof(util_compare_subgroup_t)); + res->subgroupDNs = apr_pcalloc(r->pool, + sizeof(char *) * (subgroups->nelts)); + for (sgindex = 0; (group = apr_array_pop(subgroups)); sgindex++) { + res->subgroupDNs[sgindex] = apr_pstrdup(r->pool, *group); + } + res->len = sgindex; + } + + return res; +} + + +/* + * Does a recursive lookup operation to try to find a user within (cached) + * nested groups. It accepts a cache that it will use to lookup previous + * compare attempts. 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 + * + * DON'T CALL THIS UNLESS YOU CALLED uldap_cache_compare FIRST!!!!! + * + * + * 1. Call uldap_cache_compare for each subgroupclass value to check the + * generic, user-agnostic, cached group entry. This will create a new generic + * cache entry if there + * wasn't one. If nothing returns LDAP_COMPARE_TRUE skip to step 5 since we + * have no groups. + * 2. Lock The cache and get the generic cache entry. + * 3. Check if there is already a subgrouplist in this generic group's cache + * entry. + * A. If there is, go to step 4. + * B. If there isn't: + * i) Use ldap_search to get the full list + * of subgroup "members" (which may include non-group "members"). + * ii) Use uldap_cache_compare to strip the list down to just groups. + * iii) Lock and add this stripped down list to the cache of the generic + * group. + * 4. Loop through the sgl and call uldap_cache_compare (using the user info) + * for each + * subgroup to see if the subgroup contains the user and to get the subgroups + * added to the + * cache (with user-afinity, if they aren't already there). + * A. If the user is in the subgroup, then we'll be returning + * LDAP_COMPARE_TRUE. + * B. if the user isn't in the subgroup (LDAP_COMPARE_FALSE via + * uldap_cache_compare) then recursively call this function to get the + * sub-subgroups added... + * 5. Cleanup local allocations. + * 6. Return the final result. + */ + +static int uldap_cache_check_subgroups(request_rec *r, + util_ldap_connection_t *ldc, + const char *url, const char *dn, + const char *attrib, const char *value, + char **subgroupAttrs, + apr_array_header_t *subgroupclasses, + int cur_subgroup_depth, + int max_subgroup_depth) +{ + int result = LDAP_COMPARE_FALSE; + util_url_node_t *curl; + util_url_node_t curnode; + util_compare_node_t *compare_nodep; + util_compare_node_t the_compare_node; + util_compare_subgroup_t *tmp_local_sgl = NULL; + int sgl_cached_empty = 0, sgindex = 0, base_sgcIndex = 0; + struct mod_auth_ldap_groupattr_entry_t *sgc_ents = + (struct mod_auth_ldap_groupattr_entry_t *) subgroupclasses->elts; + util_ldap_state_t *st = (util_ldap_state_t *) + ap_get_module_config(r->server->module_config, + &ldap_module); + + /* + * Stop looking at deeper levels of nested groups if we have reached the + * max. Since we already checked the top-level group in uldap_cache_compare, + * we don't need to check it again here - so if max_subgroup_depth is set + * to 0, we won't check it (i.e. that is why we check < rather than <=). + * We'll be calling uldap_cache_compare from here to check if the user is + * in the next level before we recurse into that next level looking for + * more subgroups. + */ + if (cur_subgroup_depth >= max_subgroup_depth) { + return LDAP_COMPARE_FALSE; + } + + /* + * 1. Check the "groupiness" of the specified basedn. Stopping at the first + * TRUE return. + */ + while ((base_sgcIndex < subgroupclasses->nelts) + && (result != LDAP_COMPARE_TRUE)) { + result = uldap_cache_compare(r, ldc, url, dn, "objectClass", + sgc_ents[base_sgcIndex].name); + if (result != LDAP_COMPARE_TRUE) { + base_sgcIndex++; + } + } + + if (result != LDAP_COMPARE_TRUE) { + ldc->reason = "DN failed group verification."; + return result; + } + + /* + * 2. Find previously created cache entry and check if there is already a + * subgrouplist. + */ + LDAP_CACHE_LOCK(); + curnode.url = url; + curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode); + LDAP_CACHE_UNLOCK(); + + if (curl && curl->compare_cache) { + /* make a comparison to the cache */ + LDAP_CACHE_LOCK(); + + the_compare_node.dn = (char *)dn; + the_compare_node.attrib = (char *)"objectClass"; + the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name; + the_compare_node.result = 0; + the_compare_node.sgl_processed = 0; + the_compare_node.subgroupList = NULL; + + compare_nodep = util_ald_cache_fetch(curl->compare_cache, + &the_compare_node); + + if (compare_nodep != NULL) { + /* + * Found the generic group entry... but the user isn't in this + * group or we wouldn't be here. + */ + if (compare_nodep->sgl_processed) { + if (compare_nodep->subgroupList) { + /* Make a local copy of the subgroup list */ + int i; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01288) + "Making local copy of SGL for " + "group (%s)(objectClass=%s) ", + dn, (char *)sgc_ents[base_sgcIndex].name); + tmp_local_sgl = apr_pcalloc(r->pool, + sizeof(util_compare_subgroup_t)); + tmp_local_sgl->len = compare_nodep->subgroupList->len; + tmp_local_sgl->subgroupDNs = + apr_pcalloc(r->pool, + sizeof(char *) * compare_nodep->subgroupList->len); + for (i = 0; i < compare_nodep->subgroupList->len; i++) { + tmp_local_sgl->subgroupDNs[i] = + apr_pstrdup(r->pool, + compare_nodep->subgroupList->subgroupDNs[i]); + } + } + else { + sgl_cached_empty = 1; + } + } + } + LDAP_CACHE_UNLOCK(); + } + + if (!tmp_local_sgl && !sgl_cached_empty) { + /* No Cached SGL, retrieve from LDAP */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01289) + "no cached SGL for %s, retrieving from LDAP", dn); + tmp_local_sgl = uldap_get_subgroups(r, ldc, url, dn, subgroupAttrs, + subgroupclasses); + if (!tmp_local_sgl) { + /* No SGL aailable via LDAP either */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01290) "no subgroups for %s", + dn); + } + + if (curl && curl->compare_cache) { + /* + * Find the generic group cache entry and add the sgl we just retrieved. + */ + LDAP_CACHE_LOCK(); + + the_compare_node.dn = (char *)dn; + the_compare_node.attrib = (char *)"objectClass"; + the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name; + the_compare_node.result = 0; + the_compare_node.sgl_processed = 0; + the_compare_node.subgroupList = NULL; + + compare_nodep = util_ald_cache_fetch(curl->compare_cache, + &the_compare_node); + + if (compare_nodep == NULL) { + /* + * The group entry we want to attach our SGL to doesn't exist. + * We only got here if we verified this DN was actually a group + * based on the objectClass, but we can't call the compare function + * while we already hold the cache lock -- only the insert. + */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01291) + "Cache entry for %s doesn't exist", dn); + the_compare_node.result = LDAP_COMPARE_TRUE; + util_ald_cache_insert(curl->compare_cache, &the_compare_node); + compare_nodep = util_ald_cache_fetch(curl->compare_cache, + &the_compare_node); + if (compare_nodep == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01292) + "util_ldap: Couldn't retrieve group entry " + "for %s from cache", + dn); + } + } + + /* + * We have a valid cache entry and a locally generated SGL. + * Attach the SGL to the cache entry + */ + if (compare_nodep && !compare_nodep->sgl_processed) { + if (!tmp_local_sgl) { + /* We looked up an SGL for a group and found it to be empty */ + if (compare_nodep->subgroupList == NULL) { + compare_nodep->sgl_processed = 1; + } + } + else { + util_compare_subgroup_t *sgl_copy = + util_ald_sgl_dup(curl->compare_cache, tmp_local_sgl); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01293) + "Copying local SGL of len %d for group %s into cache", + tmp_local_sgl->len, dn); + if (sgl_copy) { + if (compare_nodep->subgroupList) { + util_ald_sgl_free(curl->compare_cache, + &(compare_nodep->subgroupList)); + } + compare_nodep->subgroupList = sgl_copy; + compare_nodep->sgl_processed = 1; + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(01294) + "Copy of SGL failed to obtain shared memory, " + "couldn't update cache"); + } + } + } + LDAP_CACHE_UNLOCK(); + } + } + + /* + * tmp_local_sgl has either been created, or copied out of the cache + * If tmp_local_sgl is NULL, there are no subgroups to process and we'll + * return false + */ + result = LDAP_COMPARE_FALSE; + if (!tmp_local_sgl) { + return result; + } + + while ((result != LDAP_COMPARE_TRUE) && (sgindex < tmp_local_sgl->len)) { + const char *group = NULL; + group = tmp_local_sgl->subgroupDNs[sgindex]; + /* + * 4. Now loop through the subgroupList and call uldap_cache_compare + * to check for the user. + */ + result = uldap_cache_compare(r, ldc, url, group, attrib, value); + if (result == LDAP_COMPARE_TRUE) { + /* + * 4.A. We found the user in the subgroup. Return + * LDAP_COMPARE_TRUE. + */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01295) + "Found user %s in a subgroup (%s) at level %d of %d.", + r->user, group, cur_subgroup_depth+1, + max_subgroup_depth); + } + else { + /* + * 4.B. We didn't find the user in this subgroup, so recurse into + * it and keep looking. + */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01296) + "User %s not found in subgroup (%s) at level %d of " + "%d.", r->user, group, cur_subgroup_depth+1, + max_subgroup_depth); + result = uldap_cache_check_subgroups(r, ldc, url, group, attrib, + value, subgroupAttrs, + subgroupclasses, + cur_subgroup_depth+1, + max_subgroup_depth); + } + sgindex++; + } + + return result; +} + + static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *basedn, int scope, char **attrs, const char *filter, @@ -957,9 +1669,14 @@ static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, * If LDAP operation fails due to LDAP_SERVER_DOWN, control returns here. */ start_over: - if (failures++ > 10) { + if (failures > st->retries) { return result; } + + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { return result; } @@ -968,11 +1685,12 @@ start_over: result = ldap_search_ext_s(ldc->ldap, (char *)basedn, scope, (char *)filter, attrs, 0, - NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res); + NULL, NULL, st->opTimeout, APR_LDAP_SIZELIMIT, &res); if (AP_LDAP_IS_SERVER_DOWN(result)) { ldc->reason = "ldap_search_ext_s() for user failed with server down"; uldap_connection_unbind(ldc); + failures++; goto start_over; } @@ -1023,20 +1741,25 @@ start_over: * fails, it means that the password is wrong (the dn obviously * exists, since we just retrieved it) */ - result = ldap_simple_bind_s(ldc->ldap, - (char *)*binddn, - (char *)bindpw); - if (AP_LDAP_IS_SERVER_DOWN(result)) { - ldc->reason = "ldap_simple_bind_s() to check user credentials " - "failed with server down"; + result = uldap_simple_bind(ldc, (char *)*binddn, (char *)bindpw, + st->opTimeout); + if (AP_LDAP_IS_SERVER_DOWN(result) || + (result == LDAP_TIMEOUT && failures == 0)) { + if (AP_LDAP_IS_SERVER_DOWN(result)) + ldc->reason = "ldap_simple_bind() to check user credentials " + "failed with server down"; + else + ldc->reason = "ldap_simple_bind() to check user credentials " + "timed out"; ldap_msgfree(res); uldap_connection_unbind(ldc); + failures++; goto start_over; } /* failure? if so - return */ if (result != LDAP_SUCCESS) { - ldc->reason = "ldap_simple_bind_s() to check user credentials failed"; + ldc->reason = "ldap_simple_bind() to check user credentials failed"; ldap_msgfree(res); uldap_connection_unbind(ldc); return result; @@ -1204,9 +1927,14 @@ static int uldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc, * If LDAP operation fails due to LDAP_SERVER_DOWN, control returns here. */ start_over: - if (failures++ > 10) { + if (failures > st->retries) { return result; } + + if (failures > 0 && st->retry_delay > 0) { + apr_sleep(st->retry_delay); + } + if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { return result; } @@ -1215,11 +1943,12 @@ start_over: result = ldap_search_ext_s(ldc->ldap, (char *)basedn, scope, (char *)filter, attrs, 0, - NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res); + NULL, NULL, st->opTimeout, APR_LDAP_SIZELIMIT, &res); if (AP_LDAP_IS_SERVER_DOWN(result)) { ldc->reason = "ldap_search_ext_s() for user failed with server down"; uldap_connection_unbind(ldc); + failures++; goto start_over; } @@ -1353,10 +2082,10 @@ static const char *util_ldap_set_cache_bytes(cmd_parms *cmd, void *dummy, st->cache_bytes = atol(bytes); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap cache: Setting shared memory " - " cache size to %" APR_SIZE_T_FMT " bytes.", - getpid(), st->cache_bytes); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01297) + "ldap cache: Setting shared memory cache size to " + "%" APR_SIZE_T_FMT " bytes.", + st->cache_bytes); return NULL; } @@ -1380,7 +2109,7 @@ static const char *util_ldap_set_cache_file(cmd_parms *cmd, void *dummy, st->cache_file = NULL; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01298) "LDAP cache: Setting shared memory cache file to %s bytes.", st->cache_file); @@ -1401,9 +2130,9 @@ static const char *util_ldap_set_cache_ttl(cmd_parms *cmd, void *dummy, st->search_cache_ttl = atol(ttl) * 1000000; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap cache: Setting cache TTL to %ld microseconds.", - getpid(), st->search_cache_ttl); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01299) + "ldap cache: Setting cache TTL to %ld microseconds.", + st->search_cache_ttl); return NULL; } @@ -1425,9 +2154,9 @@ static const char *util_ldap_set_cache_entries(cmd_parms *cmd, void *dummy, st->search_cache_size = 0; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap cache: Setting search cache size to %ld entries.", - getpid(), st->search_cache_size); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01300) + "ldap cache: Setting search cache size to %ld entries.", + st->search_cache_size); return NULL; } @@ -1446,9 +2175,9 @@ static const char *util_ldap_set_opcache_ttl(cmd_parms *cmd, void *dummy, st->compare_cache_ttl = atol(ttl) * 1000000; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap cache: Setting operation cache TTL to %ld microseconds.", - getpid(), st->compare_cache_ttl); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01301) + "ldap cache: Setting operation cache TTL to %ld microseconds.", + st->compare_cache_ttl); return NULL; } @@ -1470,9 +2199,9 @@ static const char *util_ldap_set_opcache_entries(cmd_parms *cmd, void *dummy, st->compare_cache_size = 0; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap cache: Setting operation cache size to %ld " - "entries.", getpid(), st->compare_cache_size); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01302) + "ldap cache: Setting operation cache size to %ld entries.", + st->compare_cache_size); return NULL; } @@ -1601,7 +2330,7 @@ static const char *util_ldap_set_trusted_global_cert(cmd_parms *cmd, return "Certificate type was not specified."; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01303) "LDAP: SSL trusted global cert - %s (type %s)", file, type); @@ -1620,7 +2349,7 @@ static const char *util_ldap_set_trusted_global_cert(cmd_parms *cmd, ((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server, + ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server, APLOGNO(01304) "LDAP: Could not open SSL trusted certificate " "authority file - %s", cert->path == NULL ? file : cert->path); @@ -1646,9 +2375,7 @@ static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd, const char *file, const char *password) { - util_ldap_state_t *st = - (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, - &ldap_module); + util_ldap_config_t *dc = config; apr_finfo_t finfo; apr_status_t rv; int cert_type = 0; @@ -1660,21 +2387,21 @@ static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd, if (APR_LDAP_CA_TYPE_UNKNOWN == cert_type) { return apr_psprintf(cmd->pool, "The certificate type \"%s\" is " "not recognised. It should be one " - "of CERT_DER, CERT_BASE64, " - "CERT_NICKNAME, CERT_PFX," + "of CA_DER, CA_BASE64, " + "CERT_DER, CERT_BASE64, " + "CERT_NICKNAME, CERT_PFX, " "KEY_DER, KEY_BASE64, KEY_PFX", type); } - else if (APR_LDAP_CA_TYPE_DER == cert_type || - APR_LDAP_CA_TYPE_BASE64 == cert_type || - APR_LDAP_CA_TYPE_CERT7_DB == cert_type || + else if ( APR_LDAP_CA_TYPE_CERT7_DB == cert_type || APR_LDAP_CA_TYPE_SECMOD == cert_type || APR_LDAP_CERT_TYPE_PFX == cert_type || APR_LDAP_CERT_TYPE_KEY3_DB == cert_type) { return apr_psprintf(cmd->pool, "The certificate type \"%s\" is " "only valid within a " "LDAPTrustedGlobalCert directive. " - "Only CERT_DER, CERT_BASE64, " + "Only CA_DER, CA_BASE64, " + "CERT_DER, CERT_BASE64, " "CERT_NICKNAME, KEY_DER, and " "KEY_BASE64 may be used.", type); } @@ -1683,12 +2410,12 @@ static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd, return "Certificate type was not specified."; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01305) "LDAP: SSL trusted client cert - %s (type %s)", file, type); - /* add the certificate to the global array */ - cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(st->global_certs); + /* add the certificate to the client array */ + cert = (apr_ldap_opt_tls_cert_t *)apr_array_push(dc->client_certs); cert->type = cert_type; cert->path = file; cert->password = password; @@ -1702,7 +2429,7 @@ static const char *util_ldap_set_trusted_client_cert(cmd_parms *cmd, ((rv = apr_stat (&finfo, cert->path, APR_FINFO_MIN, cmd->pool)) != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server, + ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server, APLOGNO(01306) "LDAP: Could not open SSL client certificate " "file - %s", cert->path == NULL ? file : cert->path); @@ -1730,7 +2457,7 @@ static const char *util_ldap_set_trusted_mode(cmd_parms *cmd, void *dummy, (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, &ldap_module); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01307) "LDAP: SSL trusted mode - %s", mode); @@ -1766,7 +2493,7 @@ static const char *util_ldap_set_verify_srv_cert(cmd_parms *cmd, return err; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01308) "LDAP: SSL verify server certificate - %s", mode?"TRUE":"FALSE"); @@ -1794,12 +2521,12 @@ static const char *util_ldap_set_connection_timeout(cmd_parms *cmd, #ifdef LDAP_OPT_NETWORK_TIMEOUT st->connectionTimeout = atol(ttl); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "[%" APR_PID_T_FMT "] ldap connection: Setting connection timeout to " - "%ld seconds.", getpid(), st->connectionTimeout); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01309) + "ldap connection: Setting connection timeout to %ld seconds.", + st->connectionTimeout); #else - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, - "LDAP: Connection timout option not supported by the " + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(01310) + "LDAP: Connection timeout option not supported by the " "LDAP SDK in use." ); #endif @@ -1807,13 +2534,197 @@ static const char *util_ldap_set_connection_timeout(cmd_parms *cmd, } +static const char *util_ldap_set_chase_referrals(cmd_parms *cmd, + void *config, + int mode) +{ + util_ldap_config_t *dc = config; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01311) + "LDAP: Setting referral chasing %s", + (mode == AP_LDAP_CHASEREFERRALS_ON) ? "ON" : "OFF"); + + dc->ChaseReferrals = mode; + + return(NULL); +} + +static const char *util_ldap_set_debug_level(cmd_parms *cmd, + void *config, + const char *arg) { +#ifdef AP_LDAP_OPT_DEBUG + util_ldap_state_t *st = + (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, + &ldap_module); +#endif + + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + +#ifndef AP_LDAP_OPT_DEBUG + return "This directive is not supported with the currently linked LDAP library"; +#else + st->debug_level = atoi(arg); + return NULL; +#endif +} + +static const char *util_ldap_set_referral_hop_limit(cmd_parms *cmd, + void *config, + const char *hop_limit) +{ + util_ldap_config_t *dc = config; + + dc->ReferralHopLimit = atol(hop_limit); + + if (dc->ReferralHopLimit <= 0) { + return "LDAPReferralHopLimit must be greater than zero (Use 'LDAPReferrals Off' to disable referral chasing)"; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01312) + "LDAP: Limit chased referrals to maximum of %d hops.", + dc->ReferralHopLimit); + + return NULL; +} + +static void *util_ldap_create_dir_config(apr_pool_t *p, char *d) { + util_ldap_config_t *dc = + (util_ldap_config_t *) apr_pcalloc(p,sizeof(util_ldap_config_t)); + + /* defaults are AP_LDAP_CHASEREFERRALS_ON and AP_LDAP_DEFAULT_HOPLIMIT */ + dc->client_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t)); + dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_ON; + dc->ReferralHopLimit = AP_LDAP_HOPLIMIT_UNSET; + + return dc; +} + +static const char *util_ldap_set_op_timeout(cmd_parms *cmd, + void *dummy, + const char *val) +{ + long timeout; + char *endptr; + util_ldap_state_t *st = + (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, + &ldap_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + timeout = strtol(val, &endptr, 10); + if ((val == endptr) || (*endptr != '\0')) { + return "Timeout not numerical"; + } + if (timeout < 0) { + return "Timeout must be non-negative"; + } + + if (timeout) { + if (!st->opTimeout) { + st->opTimeout = apr_pcalloc(cmd->pool, sizeof(struct timeval)); + } + st->opTimeout->tv_sec = timeout; + } + else { + st->opTimeout = NULL; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01313) + "ldap connection: Setting op timeout to %ld seconds.", + timeout); + +#ifndef LDAP_OPT_TIMEOUT + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01314) + "LDAP: LDAP_OPT_TIMEOUT option not supported by the " + "LDAP library in use. Using LDAPTimeout value as search " + "timeout only." ); +#endif + + return NULL; +} + +static const char *util_ldap_set_conn_ttl(cmd_parms *cmd, + void *dummy, + const char *val) +{ + apr_interval_time_t timeout; + util_ldap_state_t *st = + (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, + &ldap_module); + + if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS) { + return "LDAPConnPoolTTL has wrong format"; + } + + if (timeout < 0) { + /* reserve -1 for default value */ + timeout = AP_LDAP_CONNPOOL_INFINITE; + } + st->connection_pool_ttl = timeout; + return NULL; +} +static const char *util_ldap_set_retry_delay(cmd_parms *cmd, + void *dummy, + const char *val) +{ + apr_interval_time_t timeout; + util_ldap_state_t *st = + (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, + &ldap_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS) { + return "LDAPRetryDelay has wrong format"; + } + + if (timeout < 0) { + return "LDAPRetryDelay must be >= 0"; + } + + st->retry_delay = timeout; + return NULL; +} + +static const char *util_ldap_set_retries(cmd_parms *cmd, + void *dummy, + const char *val) +{ + util_ldap_state_t *st = + (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, + &ldap_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + st->retries = atoi(val); + if (st->retries < 0) { + return "LDAPRetries must be >= 0"; + } + + return NULL; +} + static void *util_ldap_create_config(apr_pool_t *p, server_rec *s) { util_ldap_state_t *st = (util_ldap_state_t *)apr_pcalloc(p, sizeof(util_ldap_state_t)); - /* Create a per vhost pool for mod_ldap to use, serialized with - * st->mutex (also one per vhost) + /* Create a per vhost pool for mod_ldap to use, serialized with + * st->mutex (also one per vhost). both are replicated by fork(), + * no shared memory managed by either. */ apr_pool_create(&st->pool, p); #if APR_HAS_THREADS @@ -1828,11 +2739,15 @@ static void *util_ldap_create_config(apr_pool_t *p, server_rec *s) st->connections = NULL; st->ssl_supported = 0; st->global_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t)); - st->client_certs = apr_array_make(p, 10, sizeof(apr_ldap_opt_tls_cert_t)); st->secure = APR_LDAP_NONE; st->secure_set = 0; st->connectionTimeout = 10; + st->opTimeout = apr_pcalloc(p, sizeof(struct timeval)); + st->opTimeout->tv_sec = 60; st->verify_svr_cert = 1; + st->connection_pool_ttl = AP_LDAP_CONNPOOL_DEFAULT; /* no limit */ + st->retries = 3; + st->retry_delay = 0; /* no delay */ return st; } @@ -1852,7 +2767,7 @@ static void *util_ldap_merge_config(apr_pool_t *p, void *basev, st->mutex = overrides->mutex; #endif - /* The cache settings can not be modified in a + /* The cache settings can not be modified in a virtual host since all server use the same shared memory cache. */ st->cache_bytes = base->cache_bytes; @@ -1860,29 +2775,35 @@ static void *util_ldap_merge_config(apr_pool_t *p, void *basev, st->search_cache_size = base->search_cache_size; st->compare_cache_ttl = base->compare_cache_ttl; st->compare_cache_size = base->compare_cache_size; - st->util_ldap_cache_lock = base->util_ldap_cache_lock; + st->util_ldap_cache_lock = base->util_ldap_cache_lock; st->connections = NULL; - st->ssl_supported = 0; + st->ssl_supported = 0; /* not known until post-config and re-merged */ st->global_certs = apr_array_append(p, base->global_certs, overrides->global_certs); - st->client_certs = apr_array_append(p, base->client_certs, - overrides->client_certs); st->secure = (overrides->secure_set == 0) ? base->secure : overrides->secure; - /* These LDAP connection settings can not be overwritten in - a virtual host. Once set in the base server, they must + /* These LDAP connection settings can not be overwritten in + a virtual host. Once set in the base server, they must remain the same. None of the LDAP SDKs seem to be able - to handle setting the verify_svr_cert flag on a + to handle setting the verify_svr_cert flag on a per-connection basis. The OpenLDAP client appears to be able to handle the connection timeout per-connection but the Novell SDK cannot. Allowing the timeout to be set by each vhost is of little value so rather than - trying to make special expections for one LDAP SDK, GLOBAL_ONLY + trying to make special expections for one LDAP SDK, GLOBAL_ONLY is being enforced on this setting as well. */ st->connectionTimeout = base->connectionTimeout; + st->opTimeout = base->opTimeout; st->verify_svr_cert = base->verify_svr_cert; + st->debug_level = base->debug_level; + + st->connection_pool_ttl = (overrides->connection_pool_ttl == AP_LDAP_CONNPOOL_DEFAULT) ? + base->connection_pool_ttl : overrides->connection_pool_ttl; + + st->retries = base->retries; + st->retry_delay = base->retry_delay; return st; } @@ -1902,6 +2823,20 @@ static apr_status_t util_ldap_cleanup_module(void *data) } +static int util_ldap_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) +{ + apr_status_t result; + + result = ap_mutex_register(pconf, ldap_cache_mutex_type, NULL, + APR_LOCK_DEFAULT, 0); + if (result != APR_SUCCESS) { + return result; + } + + return OK; +} + static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { @@ -1913,23 +2848,21 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, ap_get_module_config(s->module_config, &ldap_module); - void *data; - const char *userdata_key = "util_ldap_init"; apr_ldap_err_t *result_err = NULL; int rc; /* util_ldap_post_config() will be called twice. Don't bother * going through all of the initialization on the first call * because it will just be thrown away.*/ - apr_pool_userdata_get(&data, userdata_key, s->process->pool); - if (!data) { - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, s->process->pool); + if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { #if APR_HAS_SHARED_MEMORY - /* If the cache file already exists then delete it. Otherwise we are - * going to run into problems creating the shared memory. */ - if (st->cache_file) { + /* + * If we are using shared memory caching and the cache file already + * exists then delete it. Otherwise we are going to run into problems + * creating the shared memory. + */ + if (st->cache_file && st->cache_bytes > 0) { char *lck_file = apr_pstrcat(ptemp, st->cache_file, ".lck", NULL); apr_file_remove(lck_file, ptemp); @@ -1939,42 +2872,24 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, } #if APR_HAS_SHARED_MEMORY - /* initializing cache if shared memory size is not zero and we already - * don't have shm address + /* + * initializing cache if we don't already have a shm address */ - if (!st->cache_shm && st->cache_bytes > 0) { + if (!st->cache_shm) { #endif result = util_ldap_cache_init(p, st); if (result != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, result, s, + ap_log_error(APLOG_MARK, APLOG_ERR, result, s, APLOGNO(01315) "LDAP cache: could not create shared memory segment"); return DONE; } - -#if APR_HAS_SHARED_MEMORY - if (st->cache_file) { - st->lock_file = apr_pstrcat(st->pool, st->cache_file, ".lck", - NULL); - } -#endif - - result = apr_global_mutex_create(&st->util_ldap_cache_lock, - st->lock_file, APR_LOCK_DEFAULT, - st->pool); + result = ap_global_mutex_create(&st->util_ldap_cache_lock, NULL, + ldap_cache_mutex_type, NULL, s, p, 0); if (result != APR_SUCCESS) { return result; } -#ifdef AP_NEED_SET_MUTEX_PERMS - result = unixd_set_global_mutex_perms(st->util_ldap_cache_lock); - if (result != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, result, s, - "LDAP cache: failed to set mutex permissions"); - return result; - } -#endif - /* merge config in all vhost */ s_vhost = s->next; while (s_vhost) { @@ -1987,18 +2902,17 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, st_vhost->cache_rmm = st->cache_rmm; st_vhost->cache_file = st->cache_file; st_vhost->util_ldap_cache = st->util_ldap_cache; - ap_log_error(APLOG_MARK, APLOG_DEBUG, result, s, + ap_log_error(APLOG_MARK, APLOG_DEBUG, result, s, APLOGNO(01316) "LDAP merging Shared Cache conf: shm=0x%pp rmm=0x%pp " "for VHOST: %s", st->cache_shm, st->cache_rmm, s_vhost->server_hostname); #endif - st_vhost->lock_file = st->lock_file; s_vhost = s_vhost->next; } #if APR_HAS_SHARED_MEMORY } else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01317) "LDAP cache: LDAPSharedCacheSize is zero, disabling " "shared memory cache"); } @@ -2010,7 +2924,7 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_ldap_err_t *result = NULL; apr_ldap_info(p, &(result)); if (result != NULL) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "%s", result->reason); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01318) "%s", result->reason); } } @@ -2034,17 +2948,42 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, if (APR_SUCCESS == rc) { st->ssl_supported = 1; - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01319) "LDAP: SSL support available" ); } else { st->ssl_supported = 0; - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01320) "LDAP: SSL support unavailable%s%s", result_err ? ": " : "", result_err ? result_err->reason : ""); } + /* ssl_supported is really a global setting */ + s_vhost = s->next; + while (s_vhost) { + st_vhost = (util_ldap_state_t *) + ap_get_module_config(s_vhost->module_config, + &ldap_module); + + st_vhost->ssl_supported = st->ssl_supported; + s_vhost = s_vhost->next; + } + + /* Initialize the rebind callback's cross reference list. */ + apr_ldap_rebind_init (p); + +#ifdef AP_LDAP_OPT_DEBUG + if (st->debug_level > 0) { + result = ldap_set_option(NULL, AP_LDAP_OPT_DEBUG, &st->debug_level); + if (result != LDAP_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01321) + "LDAP: Could not set the LDAP library debug level to %d:(%d) %s", + st->debug_level, result, ldap_err2string(result)); + } + } +#endif + return(OK); } @@ -2057,12 +2996,11 @@ static void util_ldap_child_init(apr_pool_t *p, server_rec *s) if (!st->util_ldap_cache_lock) return; sts = apr_global_mutex_child_init(&st->util_ldap_cache_lock, - st->lock_file, p); + apr_global_mutex_lockfile(st->util_ldap_cache_lock), p); if (sts != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, sts, s, - "Failed to initialise global mutex %s in child process %" - APR_PID_T_FMT ".", - st->lock_file, getpid()); + ap_log_error(APLOG_MARK, APLOG_CRIT, sts, s, APLOGNO(01322) + "Failed to initialise global mutex %s in child process", + ldap_cache_mutex_type); } } @@ -2070,7 +3008,7 @@ static const command_rec util_ldap_cmds[] = { AP_INIT_TAKE1("LDAPSharedCacheSize", util_ldap_set_cache_bytes, NULL, RSRC_CONF, "Set the size of the shared memory cache (in bytes). Use " - "0 to disable the shared memory cache. (default: 100000)"), + "0 to disable the shared memory cache. (default: 500000)"), AP_INIT_TAKE1("LDAPSharedCacheFile", util_ldap_set_cache_file, NULL, RSRC_CONF, @@ -2079,9 +3017,9 @@ static const command_rec util_ldap_cmds[] = { AP_INIT_TAKE1("LDAPCacheEntries", util_ldap_set_cache_entries, NULL, RSRC_CONF, "Set the maximum number of entries that are possible in the " - "LDAP search cache. Use 0 or -1 to disable the search cache " + "LDAP search cache. Use 0 or -1 to disable the search cache " "(default: 1024)"), - + AP_INIT_TAKE1("LDAPCacheTTL", util_ldap_set_cache_ttl, NULL, RSRC_CONF, "Set the maximum time (in seconds) that an item can be " @@ -2091,7 +3029,7 @@ static const command_rec util_ldap_cmds[] = { AP_INIT_TAKE1("LDAPOpCacheEntries", util_ldap_set_opcache_entries, NULL, RSRC_CONF, "Set the maximum number of entries that are possible " - "in the LDAP compare cache. Use 0 or -1 to disable the compare cache " + "in the LDAP compare cache. Use 0 or -1 to disable the compare cache " "(default: 1024)"), AP_INIT_TAKE1("LDAPOpCacheTTL", util_ldap_set_opcache_ttl, @@ -2102,23 +3040,25 @@ static const command_rec util_ldap_cmds[] = { AP_INIT_TAKE23("LDAPTrustedGlobalCert", util_ldap_set_trusted_global_cert, NULL, RSRC_CONF, - "Takes three args; the file and/or directory containing " - "the trusted CA certificates (and global client certs " - "for Netware) used to validate the LDAP server. Second " - "arg is the cert type for the first arg, one of CA_DER, " - "CA_BASE64, CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64, " - "CERT_KEY3_DB, CERT_NICKNAME, KEY_DER, or KEY_BASE64. " - "Third arg is an optional passphrase if applicable."), + "Takes three arguments; the first argument is the cert " + "type of the second argument, one of CA_DER, CA_BASE64, " + "CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64, CERT_KEY3_DB, " + "CERT_NICKNAME, KEY_DER, or KEY_BASE64. The second argument " + "specifes the file and/or directory containing the trusted CA " + "certificates (and global client certs for Netware) used to " + "validate the LDAP server. The third argument is an optional " + "passphrase if applicable."), AP_INIT_TAKE23("LDAPTrustedClientCert", util_ldap_set_trusted_client_cert, - NULL, RSRC_CONF, - "Takes three args; the file and/or directory containing " - "the client certificate, or certificate ID used to " - "validate this LDAP client. Second arg is the cert type " - "for the first arg, one of CA_DER, CA_BASE64, CA_CERT7_DB, " - "CA_SECMOD, CERT_DER, CERT_BASE64, CERT_KEY3_DB, " - "CERT_NICKNAME, KEY_DER, or KEY_BASE64. Third arg is an " - "optional passphrase if applicable."), + NULL, OR_AUTHCFG, + "Takes three arguments: the first argument is the certificate " + "type of the second argument, one of CA_DER, CA_BASE64, " + "CA_CERT7_DB, CA_SECMOD, CERT_DER, CERT_BASE64, CERT_KEY3_DB, " + "CERT_NICKNAME, KEY_DER, or KEY_BASE64. The second argument " + "specifies the file and/or directory containing the client " + "certificate, or certificate ID used to validate this LDAP " + "client. The third argument is an optional passphrase if " + "applicable."), AP_INIT_TAKE1("LDAPTrustedMode", util_ldap_set_trusted_mode, NULL, RSRC_CONF, @@ -2127,14 +3067,47 @@ static const command_rec util_ldap_cmds[] = { AP_INIT_FLAG("LDAPVerifyServerCert", util_ldap_set_verify_srv_cert, NULL, RSRC_CONF, - "Set to 'ON' requires that the server certificate be verified " - "before a secure LDAP connection can be establish. Default 'ON'"), + "Set to 'ON' requires that the server certificate be verified" + " before a secure LDAP connection can be establish. Default" + " 'ON'"), AP_INIT_TAKE1("LDAPConnectionTimeout", util_ldap_set_connection_timeout, NULL, RSRC_CONF, "Specify the LDAP socket connection timeout in seconds " "(default: 10)"), + AP_INIT_FLAG("LDAPReferrals", util_ldap_set_chase_referrals, + NULL, OR_AUTHCFG, + "Choose whether referrals are chased ['ON'|'OFF']. Default 'ON'"), + + AP_INIT_TAKE1("LDAPReferralHopLimit", util_ldap_set_referral_hop_limit, + NULL, OR_AUTHCFG, + "Limit the number of referral hops that LDAP can follow. " + "(Integer value, Consult LDAP SDK documentation for applicability and defaults"), + + AP_INIT_TAKE1("LDAPLibraryDebug", util_ldap_set_debug_level, + NULL, RSRC_CONF, + "Enable debugging in LDAP SDK (Default: off, values: SDK specific"), + + AP_INIT_TAKE1("LDAPTimeout", util_ldap_set_op_timeout, + NULL, RSRC_CONF, + "Specify the LDAP bind/search timeout in seconds " + "(0 = no limit). Default: 60"), + AP_INIT_TAKE1("LDAPConnectionPoolTTL", util_ldap_set_conn_ttl, + NULL, RSRC_CONF, + "Specify the maximum amount of time a bound connection can sit " + "idle and still be considered valid for reuse" + "(0 = no pool, -1 = no limit, n = time in seconds). Default: -1"), + AP_INIT_TAKE1("LDAPRetries", util_ldap_set_retries, + NULL, RSRC_CONF, + "Specify the number of times a failed LDAP operation should be retried " + "(0 = no retries). Default: 3"), + AP_INIT_TAKE1("LDAPRetryDelay", util_ldap_set_retry_delay, + NULL, RSRC_CONF, + "Specify the delay between retries of a failed LDAP operation " + "(0 = no delay). Default: 0"), + + {NULL} }; @@ -2143,22 +3116,23 @@ static void util_ldap_register_hooks(apr_pool_t *p) APR_REGISTER_OPTIONAL_FN(uldap_connection_open); APR_REGISTER_OPTIONAL_FN(uldap_connection_close); APR_REGISTER_OPTIONAL_FN(uldap_connection_unbind); - APR_REGISTER_OPTIONAL_FN(uldap_connection_cleanup); APR_REGISTER_OPTIONAL_FN(uldap_connection_find); APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn); APR_REGISTER_OPTIONAL_FN(uldap_cache_compare); APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid); APR_REGISTER_OPTIONAL_FN(uldap_cache_getuserdn); APR_REGISTER_OPTIONAL_FN(uldap_ssl_supported); + APR_REGISTER_OPTIONAL_FN(uldap_cache_check_subgroups); + ap_hook_pre_config(util_ldap_pre_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(util_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(util_ldap_child_init, NULL, NULL, APR_HOOK_MIDDLE); } -module AP_MODULE_DECLARE_DATA ldap_module = { +AP_DECLARE_MODULE(ldap) = { STANDARD20_MODULE_STUFF, - NULL, /* create dir config */ + util_ldap_create_dir_config, /* create dir config */ NULL, /* merge dir config */ util_ldap_create_config, /* create server config */ util_ldap_merge_config, /* merge server config */ diff --git a/modules/ldap/util_ldap_cache.c b/modules/ldap/util_ldap_cache.c index 7ae63be6..87642e11 100644 --- a/modules/ldap/util_ldap_cache.c +++ b/modules/ldap/util_ldap_cache.c @@ -79,7 +79,7 @@ void util_ldap_url_node_free(util_ald_cache_t *cache, void *n) void util_ldap_url_node_display(request_rec *r, util_ald_cache_t *cache, void *n) { util_url_node_t *node = n; - char date_str[APR_CTIME_LEN+1]; + char date_str[APR_CTIME_LEN]; const char *type_str; util_ald_cache_t *cache_node; int x; @@ -218,7 +218,7 @@ void util_ldap_search_node_free(util_ald_cache_t *cache, void *n) void util_ldap_search_node_display(request_rec *r, util_ald_cache_t *cache, void *n) { util_search_node_t *node = n; - char date_str[APR_CTIME_LEN+1]; + char date_str[APR_CTIME_LEN]; apr_ctime(date_str, node->lastbind); @@ -259,12 +259,14 @@ void *util_ldap_compare_node_copy(util_ald_cache_t *cache, void *c) if (node) { if (!(node->dn = util_ald_strdup(cache, n->dn)) || !(node->attrib = util_ald_strdup(cache, n->attrib)) || - !(node->value = util_ald_strdup(cache, n->value))) { + !(node->value = util_ald_strdup(cache, n->value)) || + ((n->subgroupList) && !(node->subgroupList = util_ald_sgl_dup(cache, n->subgroupList)))) { util_ldap_compare_node_free(cache, node); return NULL; } node->lastcompare = n->lastcompare; node->result = n->result; + node->sgl_processed = n->sgl_processed; return node; } else { @@ -275,6 +277,8 @@ void *util_ldap_compare_node_copy(util_ald_cache_t *cache, void *c) void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n) { util_compare_node_t *node = n; + + util_ald_sgl_free(cache, &(node->subgroupList)); util_ald_free(cache, node->dn); util_ald_free(cache, node->attrib); util_ald_free(cache, node->value); @@ -284,8 +288,10 @@ void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n) void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n) { util_compare_node_t *node = n; - char date_str[APR_CTIME_LEN+1]; + char date_str[APR_CTIME_LEN]; char *cmp_result; + char *sub_groups_val; + char *sub_groups_checked; apr_ctime(date_str, node->lastcompare); @@ -299,6 +305,20 @@ void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, voi cmp_result = apr_itoa(r->pool, node->result); } + if(node->subgroupList) { + sub_groups_val = "Yes"; + } + else { + sub_groups_val = "No"; + } + + if(node->sgl_processed) { + sub_groups_checked = "Yes"; + } + else { + sub_groups_checked = "No"; + } + ap_rprintf(r, "<tr valign='top'>" "<td nowrap>%s</td>" @@ -306,12 +326,16 @@ void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, voi "<td nowrap>%s</td>" "<td nowrap>%s</td>" "<td nowrap>%s</td>" + "<td nowrap>%s</td>" + "<td nowrap>%s</td>" "</tr>", node->dn, node->attrib, node->value, date_str, - cmp_result); + cmp_result, + sub_groups_val, + sub_groups_checked); } /* ------------------------------------------------------------------ */ @@ -396,27 +420,29 @@ apr_status_t util_ldap_cache_init(apr_pool_t *pool, util_ldap_state_t *st) apr_status_t result; apr_size_t size; - if (st->cache_file) { - /* Remove any existing shm segment with this name. */ - apr_shm_remove(st->cache_file, st->pool); - } + if (st->cache_bytes > 0) { + if (st->cache_file) { + /* Remove any existing shm segment with this name. */ + apr_shm_remove(st->cache_file, st->pool); + } - size = APR_ALIGN_DEFAULT(st->cache_bytes); + size = APR_ALIGN_DEFAULT(st->cache_bytes); - result = apr_shm_create(&st->cache_shm, size, st->cache_file, st->pool); - if (result != APR_SUCCESS) { - return result; - } + result = apr_shm_create(&st->cache_shm, size, st->cache_file, st->pool); + if (result != APR_SUCCESS) { + return result; + } - /* Determine the usable size of the shm segment. */ - size = apr_shm_size_get(st->cache_shm); + /* Determine the usable size of the shm segment. */ + size = apr_shm_size_get(st->cache_shm); - /* This will create a rmm "handler" to get into the shared memory area */ - result = apr_rmm_init(&st->cache_rmm, NULL, - apr_shm_baseaddr_get(st->cache_shm), size, - st->pool); - if (result != APR_SUCCESS) { - return result; + /* This will create a rmm "handler" to get into the shared memory area */ + result = apr_rmm_init(&st->cache_rmm, NULL, + apr_shm_baseaddr_get(st->cache_shm), size, + st->pool); + if (result != APR_SUCCESS) { + return result; + } } #endif diff --git a/modules/ldap/util_ldap_cache.h b/modules/ldap/util_ldap_cache.h index 0f67fc72..8cfae324 100644 --- a/modules/ldap/util_ldap_cache.h +++ b/modules/ldap/util_ldap_cache.h @@ -33,15 +33,15 @@ #include "util_ldap.h" typedef struct util_cache_node_t { - void *payload; /* Pointer to the payload */ - apr_time_t add_time; /* Time node was added to cache */ + void *payload; /* Pointer to the payload */ + apr_time_t add_time; /* Time node was added to cache */ struct util_cache_node_t *next; } util_cache_node_t; typedef struct util_ald_cache util_ald_cache_t; struct util_ald_cache { - unsigned long size; /* Size of cache array */ + 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 */ @@ -57,7 +57,7 @@ struct util_ald_cache { double avg_purgetime; /* Average time to purge the cache */ apr_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 + 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 */ @@ -97,30 +97,40 @@ typedef struct util_url_node_t { } util_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 + * When a group is found, subgroups are stored in the group's cache entry. + */ +typedef struct util_compare_subgroup_t { + const char **subgroupDNs; + int len; +} util_compare_subgroup_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 util_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 */ - const char **vals; /* Values of queried attributes */ + 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 */ + const char **vals; /* Values of queried attributes */ int numvals; /* Number of queried attributes */ } util_search_node_t; /* * We cache every successful compare operation, using the DN, attrib, and - * value as the key. + * value as the key. */ typedef struct util_compare_node_t { - const char *dn; /* DN, attrib and value combine to be the key */ - const char *attrib; + const char *dn; /* DN, attrib and value combine to be the key */ + const char *attrib; const char *value; apr_time_t lastcompare; int result; + int sgl_processed; /* 0 if no sgl processing yet. 1 if sgl has been processed (even if SGL is NULL). Saves repeat work on leaves. */ + struct util_compare_subgroup_t *subgroupList; } util_compare_node_t; /* @@ -128,8 +138,8 @@ typedef struct util_compare_node_t { * statement and the dn fetched based on the client-provided username. */ typedef struct util_dn_compare_node_t { - const char *reqdn; /* The DN in the require dn statement */ - const char *dn; /* The DN found in the search */ + const char *reqdn; /* The DN in the require dn statement */ + const char *dn; /* The DN found in the search */ } util_dn_compare_node_t; @@ -169,6 +179,8 @@ void util_ldap_dn_compare_node_display(request_rec *r, util_ald_cache_t *cache, void util_ald_free(util_ald_cache_t *cache, const void *ptr); void *util_ald_alloc(util_ald_cache_t *cache, unsigned long size); const char *util_ald_strdup(util_ald_cache_t *cache, const char *s); +util_compare_subgroup_t *util_ald_sgl_dup(util_ald_cache_t *cache, util_compare_subgroup_t *sgl); +void util_ald_sgl_free(util_ald_cache_t *cache, util_compare_subgroup_t **sgl); /* Cache managing function */ unsigned long util_ald_hash_string(int nstr, ...); @@ -176,12 +188,12 @@ void util_ald_cache_purge(util_ald_cache_t *cache); util_url_node_t *util_ald_create_caches(util_ldap_state_t *s, const char *url); util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st, long cache_size, - unsigned long (*hashfunc)(void *), + unsigned long (*hashfunc)(void *), int (*comparefunc)(void *, void *), void * (*copyfunc)(util_ald_cache_t *cache, void *), void (*freefunc)(util_ald_cache_t *cache, void *), void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *)); - + void util_ald_destroy_cache(util_ald_cache_t *cache); void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload); void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload); diff --git a/modules/ldap/util_ldap_cache_mgr.c b/modules/ldap/util_ldap_cache_mgr.c index b0283715..82675770 100644 --- a/modules/ldap/util_ldap_cache_mgr.c +++ b/modules/ldap/util_ldap_cache_mgr.c @@ -27,6 +27,8 @@ #include "util_ldap_cache.h" #include <apr_strings.h> +APLOG_USE_MODULE(ldap); + #if APR_HAS_LDAP /* only here until strdup is gone */ @@ -126,7 +128,8 @@ const char *util_ald_strdup(util_ald_cache_t *cache, const char *s) else { return NULL; } - } else { + } + else { /* Cache shm is not used */ return strdup(s); } @@ -135,6 +138,61 @@ const char *util_ald_strdup(util_ald_cache_t *cache, const char *s) #endif } +/* + * Duplicate a subgroupList from one compare entry to another. + * Returns: ptr to a new copy of the subgroupList or NULL if allocation failed. + */ +util_compare_subgroup_t *util_ald_sgl_dup(util_ald_cache_t *cache, util_compare_subgroup_t *sgl_in) +{ + int i = 0; + util_compare_subgroup_t *sgl_out = NULL; + + if (!sgl_in) { + return NULL; + } + + sgl_out = (util_compare_subgroup_t *) util_ald_alloc(cache, sizeof(util_compare_subgroup_t)); + if (sgl_out) { + sgl_out->subgroupDNs = util_ald_alloc(cache, sizeof(char *) * sgl_in->len); + if (sgl_out->subgroupDNs) { + for (i = 0; i < sgl_in->len; i++) { + sgl_out->subgroupDNs[i] = util_ald_strdup(cache, sgl_in->subgroupDNs[i]); + if (!sgl_out->subgroupDNs[i]) { + /* We ran out of SHM, delete the strings we allocated for the SGL */ + for (i = (i - 1); i >= 0; i--) { + util_ald_free(cache, sgl_out->subgroupDNs[i]); + } + util_ald_free(cache, sgl_out->subgroupDNs); + util_ald_free(cache, sgl_out); + sgl_out = NULL; + break; + } + } + /* We were able to allocate new strings for all the subgroups */ + if (sgl_out != NULL) { + sgl_out->len = sgl_in->len; + } + } + } + + return sgl_out; +} + +/* + * Delete an entire subgroupList. + */ +void util_ald_sgl_free(util_ald_cache_t *cache, util_compare_subgroup_t **sgl) +{ + int i = 0; + if (sgl == NULL || *sgl == NULL) { + return; + } + + for (i = 0; i < (*sgl)->len; i++) { + util_ald_free(cache, (*sgl)->subgroupDNs[i]); + } + util_ald_free(cache, *sgl); +} /* * Computes the hash on a set of strings. The first argument is the number @@ -273,16 +331,19 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st, { util_ald_cache_t *cache; unsigned long i; +#if APR_HAS_SHARED_MEMORY + apr_rmm_off_t block; +#endif if (cache_size <= 0) return NULL; #if APR_HAS_SHARED_MEMORY if (!st->cache_rmm) { - return NULL; + cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1); } else { - apr_rmm_off_t block = apr_rmm_calloc(st->cache_rmm, sizeof(util_ald_cache_t)); + block = apr_rmm_calloc(st->cache_rmm, sizeof(util_ald_cache_t)); cache = block ? (util_ald_cache_t *)apr_rmm_addr_get(st->cache_rmm, block) : NULL; } #else @@ -304,6 +365,7 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st, cache->nodes = (util_cache_node_t **)util_ald_alloc(cache, cache->size * sizeof(util_cache_node_t *)); if (!cache->nodes) { + /* This frees cache in the right way even if !APR_HAS_SHARED_MEMORY or !st->cache_rmm */ util_ald_free(cache, cache); return NULL; } @@ -365,9 +427,10 @@ void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload) cache->fetches++; hashval = (*cache->hash)(payload) % cache->size; + for (p = cache->nodes[hashval]; p && !(*cache->compare)(p->payload, payload); - p = p->next) ; + p = p->next) ; if (p != NULL) { cache->hits++; @@ -398,7 +461,7 @@ void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) util_ald_cache_purge(cache); if (cache->numentries >= cache->maxentries) { /* if the purge was not effective, we leave now to avoid an overflow */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01323) "Purge of LDAP cache failed"); return NULL; } @@ -411,7 +474,7 @@ void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) * XXX: The cache management should be rewritten to work * properly when LDAPSharedCacheSize is too small. */ - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01324) "LDAPSharedCacheSize is too small. Increase it or " "reduce LDAPCacheEntries/LDAPOpCacheEntries!"); if (cache->numentries < cache->fullmark) { @@ -426,7 +489,7 @@ void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) node = (util_cache_node_t *)util_ald_alloc(cache, sizeof(util_cache_node_t)); if (node == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01325) "Could not allocate memory for LDAP cache entry"); return NULL; } @@ -439,7 +502,7 @@ void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) * XXX: The cache management should be rewritten to work * properly when LDAPSharedCacheSize is too small. */ - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01326) "LDAPSharedCacheSize is too small. Increase it or " "reduce LDAPCacheEntries/LDAPOpCacheEntries!"); if (cache->numentries < cache->fullmark) { @@ -453,7 +516,7 @@ void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) util_ald_cache_purge(cache); tmp_payload = (*cache->copy)(cache, payload); if (tmp_payload == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01327) "Could not allocate memory for LDAP cache value"); util_ald_free(cache, node); return NULL; @@ -612,7 +675,7 @@ char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st) if (r->args && strlen(r->args)) { char cachetype[5], lint[2]; unsigned int id, off; - char date_str[APR_CTIME_LEN+1]; + char date_str[APR_CTIME_LEN]; if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) && (id < util_ldap_cache->size)) { @@ -725,6 +788,8 @@ char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st) "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>" "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>" + "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Sub-groups?</b></font></td>" + "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>S-G Checked?</b></font></td>" "</tr>\n", r ); if (n) { |