Re: POC: updated LDAP support for apr-util 1.7
"Graham Leggett via dev" <[email protected]>
| Newsgroups | gmane.comp.apache.apr.devel |
|---|---|
| Message-ID | <[email protected]> |
On 18 Apr 2023, at 13:26, Graham Leggett via dev <[email protected]> wrote: > The following patch adds ldapi:// (LDAP over unix domain socket) support to apr-util. It is part of a wider cleanup covering the following: > > - Add apr_ldap_t to hide the native LDAP type. > - Add apr_ldap_initialize() with URL support, allowing us to do ldapi://, including proper pool cleanups. > - Add apr_ldap_get_option_ex() and apr_ldap_set_option_ex() that use apr_ldap_t, and support all options used by httpd. > - Options passed to apr_ldap_get_option_ex() / apr_ldap_set_option_ex() are a strongly typed union rather than the native void pointers, the assumption being the union is extensible in future. > > In theory this extends but does not break our ABI and is safe to go into apr-util 1.7, if this isn’t the case please tell me so I can fix it. Update to the POC. In addition to the above, the following is added: - apr_ldap_bind() that currently maps to ldap_sasl_interactive_bind <https://serverfault.com/questions/936658/ldap-sasl-interactive-bind-s-cant-contact-ldap-server-1>(), supporting async requests. Timeout is now a proper parameter so that platform specific weirdness can be handled. - apr_ldap_result() that maps to ldap_result(). - updated test/testldap demonstrating a SASL bind. Still to be done: - ldap_simple_bind() support. Will be emulated inside apr_ldap_bind(). Regards, Graham — Index: CHANGES =================================================================== --- CHANGES (revision 1909133) +++ CHANGES (working copy) @@ -1,6 +1,11 @@ -*- coding: utf-8 -*- Changes with APR-util 1.7.0 + *) apr_ldap: Add apr_ldap_t type. Add apr_ldap_initialize() with + URL and ldapi:// support. Add apr_ldap_get_option_ex() and + apr_ldap_set_option_ex() with support for the apr_ldap_t type. + [Graham Leggett] + *) apr_crypto_openssl: Compatibility with OpenSSL 3. [Yann Ylavic] *) configure: Fix configure for compilers which don't accept implicit Index: aprutil.dep =================================================================== --- aprutil.dep (revision 1909133) +++ aprutil.dep (working copy) @@ -234,6 +234,7 @@ ".\include\apr_ldap.h"\ ".\include\apr_ldap_init.h"\ ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ ".\include\apr_ldap_rebind.h"\ ".\include\apr_ldap_url.h"\ ".\include\apu.h"\ @@ -245,6 +246,7 @@ ".\include\apr_ldap.h"\ ".\include\apr_ldap_init.h"\ ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ ".\include\apr_ldap_rebind.h"\ ".\include\apr_ldap_url.h"\ ".\include\apu.h"\ @@ -251,10 +253,22 @@ ".\include\private\apu_config.h"\ +.\ldap\apr_ldap_bind.c : \ + ".\include\apr_ldap.h"\ + ".\include\apr_ldap_init.h"\ + ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ + ".\include\apr_ldap_rebind.h"\ + ".\include\apr_ldap_url.h"\ + ".\include\apu.h"\ + ".\include\private\apu_config.h"\ + + .\ldap\apr_ldap_rebind.c : \ ".\include\apr_ldap.h"\ ".\include\apr_ldap_init.h"\ ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ ".\include\apr_ldap_rebind.h"\ ".\include\apr_ldap_url.h"\ ".\include\apu.h"\ @@ -265,6 +279,7 @@ ".\include\apr_ldap.h"\ ".\include\apr_ldap_init.h"\ ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ ".\include\apr_ldap_rebind.h"\ ".\include\apr_ldap_url.h"\ ".\include\apu.h"\ @@ -277,6 +292,7 @@ ".\include\apr_ldap.h"\ ".\include\apr_ldap_init.h"\ ".\include\apr_ldap_option.h"\ + ".\include\apr_ldap_bind.h"\ ".\include\apr_ldap_rebind.h"\ ".\include\apr_ldap_url.h"\ ".\include\apu.h"\ Index: aprutil.dsp =================================================================== --- aprutil.dsp (revision 1909133) +++ aprutil.dsp (working copy) @@ -313,6 +313,10 @@ SOURCE=.\ldap\apr_ldap_option.c # End Source File +# Begin Source File + +SOURCE=.\ldap\apr_ldap_bind.c +# End Source File # Begin Source File SOURCE=.\ldap\apr_ldap_rebind.c Index: aprutil.mak =================================================================== --- aprutil.mak (revision 1909133) +++ aprutil.mak (working copy) @@ -86,6 +86,7 @@ -@erase "$(INTDIR)\apr_hooks.obj" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_stub.obj" -@erase "$(INTDIR)\apr_ldap_url.obj" @@ -198,6 +199,7 @@ "$(INTDIR)\apr_hooks.obj" \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap_stub.obj" \ "$(INTDIR)\apr_ldap_url.obj" \ @@ -278,6 +280,7 @@ -@erase "$(INTDIR)\apr_hooks.obj" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_stub.obj" -@erase "$(INTDIR)\apr_ldap_url.obj" @@ -395,6 +398,7 @@ "$(INTDIR)\apr_hooks.obj" \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap_stub.obj" \ "$(INTDIR)\apr_ldap_url.obj" \ @@ -475,6 +479,7 @@ -@erase "$(INTDIR)\apr_hooks.obj" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_stub.obj" -@erase "$(INTDIR)\apr_ldap_url.obj" @@ -592,6 +597,7 @@ "$(INTDIR)\apr_hooks.obj" \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap_stub.obj" \ "$(INTDIR)\apr_ldap_url.obj" \ @@ -672,6 +678,7 @@ -@erase "$(INTDIR)\apr_hooks.obj" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_stub.obj" -@erase "$(INTDIR)\apr_ldap_url.obj" @@ -789,6 +796,7 @@ "$(INTDIR)\apr_hooks.obj" \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap_stub.obj" \ "$(INTDIR)\apr_ldap_url.obj" \ @@ -1051,6 +1059,12 @@ $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=.\ldap\apr_ldap_bind.c + +"$(INTDIR)\apr_ldap_bind.obj" : $(SOURCE) "$(INTDIR)" ".\include\apu.h" ".\include\private\apu_config.h" ".\include\apr_ldap.h" + $(CPP) $(CPP_PROJ) $(SOURCE) + + SOURCE=.\ldap\apr_ldap_rebind.c "$(INTDIR)\apr_ldap_rebind.obj" : $(SOURCE) "$(INTDIR)" ".\include\apu.h" ".\include\private\apu_config.h" ".\include\apr_ldap.h" Index: build/apu-conf.m4 =================================================================== --- build/apu-conf.m4 (revision 1909133) +++ build/apu-conf.m4 (working copy) @@ -63,6 +63,8 @@ AC_CHECK_LIB(${ldaplib}, ldap_init, [ LDADD_ldap_found="-l${ldaplib} ${extralib}" + AC_CHECK_LIB(${ldaplib}, ldap_initialize, apu_has_ldap_initialize="1", , ${extralib}) + AC_CHECK_LIB(${ldaplib}, ldap_sasl_interactive_bind, apu_has_ldap_sasl_interactive_bind="1", , ${extralib}) AC_CHECK_LIB(${ldaplib}, ldapssl_client_init, apu_has_ldapssl_client_init="1", , ${extralib}) AC_CHECK_LIB(${ldaplib}, ldapssl_client_deinit, apu_has_ldapssl_client_deinit="1", , ${extralib}) AC_CHECK_LIB(${ldaplib}, ldapssl_add_trusted_cert, apu_has_ldapssl_add_trusted_cert="1", , ${extralib}) @@ -84,6 +86,8 @@ echo $ac_n "${nl}checking for ldap support..." apu_has_ldap="0"; +apu_has_ldap_initialize="0" +apu_has_ldap_sasl_interactive_bind="0" apu_has_ldapssl_client_init="0" apu_has_ldapssl_client_deinit="0" apu_has_ldapssl_add_trusted_cert="0" @@ -274,9 +278,13 @@ LIBS="$save_libs" fi +AC_CHECK_HEADERS([sasl.h sasl/sasl.h]) + AC_SUBST(ldap_h) AC_SUBST(lber_h) AC_SUBST(ldap_ssl_h) +AC_SUBST(apu_has_ldap_initialize) +AC_SUBST(apu_has_ldap_sasl_interactive_bind) AC_SUBST(apu_has_ldapssl_client_init) AC_SUBST(apu_has_ldapssl_client_deinit) AC_SUBST(apu_has_ldapssl_add_trusted_cert) Index: build.conf =================================================================== --- build.conf (revision 1909133) +++ build.conf (working copy) @@ -102,6 +102,7 @@ [ldap] paths = ldap/apr_ldap_init.c ldap/apr_ldap_option.c + ldap/apr_ldap_bind.c ldap/apr_ldap_rebind.c target = ldap/apr_ldap.la Index: include/apr_ldap.h.in =================================================================== --- include/apr_ldap.h.in (revision 1909133) +++ include/apr_ldap.h.in (working copy) @@ -84,6 +84,8 @@ /* * Detected standard functions */ +#define APR_HAS_LDAP_INITIALIZE @apu_has_ldap_initialize@ +#define APR_HAS_LDAP_SASL_INTERACTIVE_BIND @apu_has_ldap_sasl_interactive_bind@ #define APR_HAS_LDAPSSL_CLIENT_INIT @apu_has_ldapssl_client_init@ #define APR_HAS_LDAPSSL_CLIENT_DEINIT @apu_has_ldapssl_client_deinit@ #define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT @apu_has_ldapssl_add_trusted_cert@ @@ -151,6 +153,11 @@ int rc; } apr_ldap_err_t; +/** + * Opaque structure tracking the state of an LDAP connection. + */ +typedef struct apr_ldap_t apr_ldap_t; + #ifdef __cplusplus } #endif @@ -181,6 +188,11 @@ #define apr_ldap_rebind_init apr__ldap_rebind_init #define apr_ldap_rebind_add apr__ldap_rebind_add #define apr_ldap_rebind_remove apr__ldap_rebind_remove +#define apr_ldap_initialize apr__ldap_initialize +#define apr_ldap_get_option_ex apr__ldap_get_option_ex +#define apr_ldap_set_option_ex apr__ldap_set_option_ex +#define apr_ldap_result apr__ldap_result +#define apr_ldap_bind apr__ldap_bind #define APU_DECLARE_LDAP(type) type #else @@ -187,9 +199,11 @@ #define APU_DECLARE_LDAP(type) APU_DECLARE(type) #endif +#include "apu_errno.h" #include "apr_ldap_url.h" #include "apr_ldap_init.h" #include "apr_ldap_option.h" +#include "apr_ldap_bind.h" #include "apr_ldap_rebind.h" #endif /* APR_HAS_LDAP */ Index: include/apr_ldap.hnw =================================================================== --- include/apr_ldap.hnw (revision 1909133) +++ include/apr_ldap.hnw (working copy) @@ -79,6 +79,8 @@ /* * Detected standard functions */ +#define APR_HAS_LDAP_INITIALIZE 0 +#define APR_HAS_LDAP_SASL_INTERACTIVE_BIND 0 #define APR_HAS_LDAPSSL_CLIENT_INIT 1 #define APR_HAS_LDAPSSL_CLIENT_DEINIT 1 #define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 1 @@ -120,6 +122,11 @@ int rc; } apr_ldap_err_t; +/** + * Opaque structure tracking the state of an LDAP connection. + */ +typedef struct apr_ldap_t apr_ldap_t; + #ifdef __cplusplus } #endif @@ -141,6 +148,11 @@ #define apr_ldap_rebind_init apr__ldap_rebind_init #define apr_ldap_rebind_add apr__ldap_rebind_add #define apr_ldap_rebind_remove apr__ldap_rebind_remove +#define apr_ldap_initialize apr__ldap_initialize +#define apr_ldap_get_option_ex apr__ldap_get_option_ex +#define apr_ldap_set_option_ex apr__ldap_set_option_ex +#define apr_ldap_result apr__ldap_result +#define apr_ldap_bind apr__ldap_bind #define APU_DECLARE_LDAP(type) type #else @@ -147,9 +159,11 @@ #define APU_DECLARE_LDAP(type) APU_DECLARE(type) #endif +#include "apu_errno.h" #include "apr_ldap_url.h" #include "apr_ldap_init.h" #include "apr_ldap_option.h" +#include "apr_ldap_bind.h" #include "apr_ldap_rebind.h" /** @} */ Index: include/apr_ldap.hw =================================================================== --- include/apr_ldap.hw (revision 1909133) +++ include/apr_ldap.hw (working copy) @@ -82,6 +82,8 @@ /* * Detected standard functions */ +#define APR_HAS_LDAP_INITIALIZE 0 +#define APR_HAS_LDAP_SASL_INTERACTIVE_BIND 0 #define APR_HAS_LDAPSSL_CLIENT_INIT 0 #define APR_HAS_LDAPSSL_CLIENT_DEINIT 0 #define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 0 @@ -151,6 +153,11 @@ int rc; } apr_ldap_err_t; +/** + * Opaque structure tracking the state of an LDAP connection. + */ +typedef struct apr_ldap_t apr_ldap_t; + #ifdef __cplusplus } #endif @@ -181,6 +188,11 @@ #define apr_ldap_rebind_init apr__ldap_rebind_init #define apr_ldap_rebind_add apr__ldap_rebind_add #define apr_ldap_rebind_remove apr__ldap_rebind_remove +#define apr_ldap_initialize apr__ldap_initialize +#define apr_ldap_get_option_ex apr__ldap_get_option_ex +#define apr_ldap_set_option_ex apr__ldap_set_option_ex +#define apr_ldap_result apr__ldap_result +#define apr_ldap_bind apr__ldap_bind #define APU_DECLARE_LDAP(type) type #else @@ -187,9 +199,11 @@ #define APU_DECLARE_LDAP(type) APU_DECLARE(type) #endif +#include "apu_errno.h" #include "apr_ldap_url.h" #include "apr_ldap_init.h" #include "apr_ldap_option.h" +#include "apr_ldap_bind.h" #include "apr_ldap_rebind.h" /** @} */ Index: include/apr_ldap.hwc =================================================================== --- include/apr_ldap.hwc (revision 1909133) +++ include/apr_ldap.hwc (working copy) @@ -82,6 +82,8 @@ /* * Detected standard functions */ +#define APR_HAS_LDAP_INITIALIZE 0 +#define APR_HAS_LDAP_SASL_INTERACTIVE_BIND 0 #define APR_HAS_LDAPSSL_CLIENT_INIT 0 #define APR_HAS_LDAPSSL_CLIENT_DEINIT 0 #define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 0 @@ -181,6 +183,11 @@ #define apr_ldap_rebind_init apr__ldap_rebind_init #define apr_ldap_rebind_add apr__ldap_rebind_add #define apr_ldap_rebind_remove apr__ldap_rebind_remove +#define apr_ldap_initialize apr__ldap_initialize +#define apr_ldap_get_option_ex apr__ldap_get_option_ex +#define apr_ldap_set_option_ex apr__ldap_set_option_ex +#define apr_ldap_result apr__ldap_result +#define apr_ldap_bind apr__ldap_bind #define APU_DECLARE_LDAP(type) type #else @@ -187,9 +194,11 @@ #define APU_DECLARE_LDAP(type) APU_DECLARE(type) #endif +#include "apu_errno.h" #include "apr_ldap_url.h" #include "apr_ldap_init.h" #include "apr_ldap_option.h" +#include "apr_ldap_bind.h" #include "apr_ldap_rebind.h" /** @} */ Index: include/apr_ldap_bind.h =================================================================== --- include/apr_ldap_bind.h (nonexistent) +++ include/apr_ldap_bind.h (working copy) @@ -0,0 +1,122 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The APR LDAP bind functions provide the ability to bind to a directory + * in a generic way. + * + * First we try binding interactively using SASL, falling back to SASL bind, + * then simple bind, as supported on the platform. + * + * @file apr_ldap_bind.h + * @brief Apache LDAP library + */ + +#ifndef APU_LDAP_BIND_H +#define APU_LDAP_BIND_H + +/** + * @addtogroup APR_Util_LDAP + * @{ + **/ + +#if defined(DOXYGEN) +#include "apr_ldap.h" +#endif + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/** LDAP interaction identifiers */ +typedef enum { + APR_LDAP_INTERACT_GETREALM = 0x4008, /**< SASL realm for the authentication attempt */ + APR_LDAP_INTERACT_AUTHNAME = 0x4002, /**< SASL username to authenticate */ + APR_LDAP_INTERACT_USER = 0x4001, /**< SASL username to use for proxy authorization */ + APR_LDAP_INTERACT_PASS = 0x4004, /**< SASL password for the provided username */ + APR_LDAP_INTERACT_NOECHOPROMPT = 0x4006, /**< SASL generic prompt for input with input echoing disabled */ + APR_LDAP_INTERACT_ECHOPROMPT = 0x4005, /**< SASL generic prompt for input with input echoing enabled */ +} apr_ldap_bind_interact_e; + +typedef struct apr_ldap_bind_interact_t { + apr_ldap_bind_interact_e id; /* same as client/user callback ID */ + const char *challenge; /* presented to user (e.g. OTP challenge) */ + const char *prompt; /* presented to user (e.g. "Username: ") */ + const char *defresult; /* default result string */ + const void *result; /* set to point to result */ + unsigned len; /* set to length of result */ +} apr_ldap_bind_interact_t; + +typedef int (apr_ldap_interact_proc)( + apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx); + +typedef struct apr_ldap_message_t apr_ldap_message_t; + + +/** + * APR result function. + * + * This function returns the result of a previous request, ready for further + * processing. + * + * @return APR_INCOMPLETE means that at least one result has been + * returned, and needs to be passed back to the function that + * generated this message for further processing. + * APR_SUCCESS means that no further messages are available, and + * results are complete. Other error codes indicate that the message + * read was not successful. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_result(apr_ldap_message_t *msg, + apr_interval_time_t timeout, + apu_err_t *result) + __attribute__((nonnull(1,3))); + +/** + * APR LDAP bind function + * + * This function binds a previously initialised LDAP connection + * to the directory. + * + * Binds are attempted as SASL interactive, falling back to a + * standard SASL bind, falling back to a simple bind, depending + * on the capabilities of the platform. + * + * Binds are attempted asynchronously. If APR_INCOMPLETE is returned, + * this function must be called again. + * + * @return APR_INCOMPLETE means that processing has occurred, and + * the message in reply needs to be fetched using apr_ldap_return(). + * APR_SUCCESS means that the processing is complete, and the bind + * has been successful. Other error codes indicate that the bind + * was not successful. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_bind(apr_ldap_t *ldap, + const char *dn, + const char *mech, + apr_ldap_interact_proc *interact, + void *ctx, + apr_interval_time_t timeout, + apr_ldap_message_t **msg, + apu_err_t *result) + __attribute__((nonnull(1,4,7,8))); + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APU_LDAP_BIND_H */ + Index: include/apr_ldap_init.h =================================================================== --- include/apr_ldap_init.h (revision 1909133) +++ include/apr_ldap_init.h (working copy) @@ -135,6 +135,7 @@ * @param portno The port to connect to * @param secure The security mode to set * @param result_err The returned result + * @deprecated Replaced by apr_ldap_initialize() */ APU_DECLARE_LDAP(int) apr_ldap_init(apr_pool_t *pool, LDAP **ldap, @@ -154,6 +155,32 @@ APU_DECLARE_LDAP(int) apr_ldap_info(apr_pool_t *pool, apr_ldap_err_t **result_err); +/** + * APR LDAP initialise function + * + * This function is responsible for initialising an LDAP + * connection in a toolkit independant way. It does the + * job of ldap_initialize() from the C api. + * + * It handles the SSL case, the non-SSL case, and the IPC + * case, and attempts to hide the complexity setup from the + * user. + * + * A cleanup is registered in the pool. + * + * @param pool The pool to use + * @param uri The URI of the LDAP server + * @param ldap The ldap context returned + * @param result_err On error, error details are written to the + * structure. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_initialize(apr_pool_t *pool, + const char *uri, + apr_ldap_t **ldap, + apu_err_t *result) + __attribute__((nonnull(1, 2, 3, 4))); + + #ifdef __cplusplus } #endif Index: include/apr_ldap_option.h =================================================================== --- include/apr_ldap_option.h (revision 1909133) +++ include/apr_ldap_option.h (working copy) @@ -27,6 +27,8 @@ */ #include "apr_ldap.h" +#include "apr_tables.h" +#include "apr_network_io.h" #if APR_HAS_LDAP @@ -34,6 +36,43 @@ extern "C" { #endif /* __cplusplus */ + +/** LDAP API information */ +typedef struct apr_ldapi_apiinfo_t { + int api_version; /* revision of API supported */ + int protocol_version; /* highest LDAP version supported */ + const char **extensions; /* names of API extensions */ + const char *vendor_name; /* name of supplier */ + int vendor_version; /* supplier-specific version * 100 */ +} apr_ldapi_apiinfo_t; + +typedef struct apr_ldap_apifeature_info_t { + const char *name; /* LDAP_API_FEATURE_* (less prefix) */ + int version; /* value of LDAP_API_FEATURE_... */ +} apr_ldap_apifeature_info_t; + +/** LDAP Protocol Versions */ +typedef enum { + APR_LDAP_VERSION1 = 1, /**< LDAP version 1 */ + APR_LDAP_VERSION2 = 2, /**< LDAP version 2 */ + APR_LDAP_VERSION3 = 3 /**< LDAP version 3 */ +} apr_ldap_protocol_version_e; + +/** LDAP deref settings */ +typedef enum { + APR_LDAP_DEREF_NEVER = 0, /**< Aliases should never be dereferenced */ + APR_LDAP_DEREF_SEARCHING = 1, /**< Aliases should be dereferenced during the search, but not when locating the base object of the search. */ + APR_LDAP_DEREF_FINDING = 2, /**< Aliases should be dereferenced when locating the base object, but not during the search. */ + APR_LDAP_DEREF_ALWAYS = 3 /**< Aliases should always be dereferenced */ +} apr_ldap_deref_e; + +/** LDAP options on or off */ +typedef enum { + APR_LDAP_OPT_OFF = 0, /**< Option set off */ + APR_LDAP_OPT_ON = 1 /**< Option set on */ +} apr_ldap_switch_e; + + /* * The following defines handle the different TLS certificate * options available. If these options are missing, APR will try and @@ -65,11 +104,36 @@ * chase before giving up on the search. */ #define APR_LDAP_OPT_REFHOPLIMIT 0x6ffb - /** - * Structures for the apr_set_option() cases + * Get the native LDAP handle. */ +#define APR_LDAP_OPT_HANDLE 0x6ffa +/** + * Get/Set the LDAP protocol version. + */ +#define APR_LDAP_OPT_PROTOCOL_VERSION 0x6ff9 +/** + * Get the LDAP API info. + */ +#define APR_LDAP_OPT_API_INFO 0x6ff8 +/** + * Get the LDAP API feature info. + */ +#define APR_LDAP_OPT_API_FEATURE_INFO 0x6ff7 +/** + * Get the dereference setting. + */ +#define APR_LDAP_OPT_DEREF 0x6ff6 +/** + * Get the most recent result code. + */ +#define APR_LDAP_OPT_RESULT_CODE 0x6ff5 +/** + * Get the underlying socket. + */ +#define APR_LDAP_OPT_DESC 0x6ff4 + /** * APR_LDAP_OPT_TLS_CERT * @@ -202,7 +266,47 @@ /** end TLS encryption (STOPTLS) */ #define APR_LDAP_STOPTLS 3 + +/** LDAP TLS options */ +typedef enum { + APR_LDAP_TLS_NONE = APR_LDAP_NONE, /**< No encryption */ + APR_LDAP_TLS_SSL = APR_LDAP_SSL, /**< SSL encryption (ldaps://) */ + APR_LDAP_TLS_STARTTLS = APR_LDAP_STARTTLS, /**< TLS encryption (STARTTLS) */ + APR_LDAP_TLS_STOPTLS = APR_LDAP_STOPTLS /**< end TLS encryption (STOPTLS) */ +} apr_ldap_tls_e; + + +/** LDAP TLS verify options */ +typedef enum { + APR_LDAP_VERIFY_OFF = 0, /**< No verification */ + APR_LDAP_VERIFY_ON = 1 /**< TLS verification */ +} apr_ldap_verify_e; + + +/** @see apr_ldap_opt_t */ +typedef union apr_ldap_opt_t apr_ldap_opt_t; /** + * A union of all option structures so we know what + * the max size is. + */ +union apr_ldap_opt_t { + void *handle; /** LDAP native handle */ + void *opt; /** LDAP native option */ + apr_socket_t *socket; /** LDAP native socket */ + apr_ldapi_apiinfo_t info; /** LDAP API information */ + apr_ldap_apifeature_info_t ldfi; /** LDAP API feature information */ + apr_ldap_protocol_version_e pv; /** Protocol version */ + apr_array_header_t *certs; /** TLS certificates */ + apr_ldap_tls_e tls; /** TLS on/off/starttls */ + apr_ldap_verify_e verify; /** TLS verification */ + apr_ldap_deref_e deref; /** Alias dereference */ + apr_ldap_switch_e refs; /** Referrals chased */ + int refhoplimit; /** Referral hop limit */ + int result; /** Result code */ +}; + + +/** * APR LDAP get option function * * This function gets option values from a given LDAP session if @@ -213,6 +317,7 @@ * @param outvalue The value returned (if any) * @param result_err The apr_ldap_err_t structure contained detailed results * of the operation. + * @deprecated Replaced by apr_ldap_get_option_ex() */ APU_DECLARE_LDAP(int) apr_ldap_get_option(apr_pool_t *pool, LDAP *ldap, @@ -235,6 +340,7 @@ * @param invalue The value to set * @param result_err The apr_ldap_err_t structure contained detailed results * of the operation. + * @deprecated Replaced by apr_ldap_set_option_ex() */ APU_DECLARE_LDAP(int) apr_ldap_set_option(apr_pool_t *pool, LDAP *ldap, @@ -242,6 +348,45 @@ const void *invalue, apr_ldap_err_t **result_err); +/** + * APR LDAP get option function + * + * This function gets option values from a given LDAP session if + * one was specified. It maps to the native ldap_get_option() function. + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to return + * @param outvalue The value returned (if any) + * @param result_err On error, error details are written to the + * structure. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_get_option_ex(apr_ldap_t *ldap, + int option, + apr_ldap_opt_t *outvalue, + apu_err_t *result_err) + __attribute__((nonnull(3, 4))); + +/** + * APR LDAP set option function + * + * This function sets option values to a given LDAP session if + * one was specified. It maps to the native ldap_set_option() function. + * + * Where an option is not supported by an LDAP toolkit, this function + * will try and apply legacy functions to achieve the same effect, + * depending on the platform. + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to set + * @param invalue The value to set + * @param result_err On error, error details are written to the + * structure. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_set_option_ex(apr_ldap_t *ldap, + int option, + const apr_ldap_opt_t *invalue, + apu_err_t *result_err) + __attribute__((nonnull(4))); + + #ifdef __cplusplus } #endif Index: include/apu_errno.h =================================================================== --- include/apu_errno.h (revision 1909133) +++ include/apu_errno.h (working copy) @@ -54,6 +54,10 @@ * APR_EINITENGINE The engine could not be initialised * APR_EREINIT Underlying crypto has already been initialised * APR_ENOVERIFY The signature verification failed + * APR_PROXY_AUTH Proxy authorization has failed + * APR_INAPPROPRIATE_AUTH Authentication not appropriate for this entry + * APR_INVALID_CREDENTIALS Invalid credentials were presented + * APR_INSUFFICIENT_ACCESS The user has insufficient access * </PRE> * * <PRE> @@ -88,6 +92,18 @@ #define APR_EREINIT (APR_UTIL_START_STATUS + 12) /** @see APR_STATUS_IS_ENOVERIFY */ #define APR_ENOVERIFY (APR_UTIL_START_STATUS + 13) +/** @see APR_STATUS_IS_EDOWN */ +#define APR_EDOWN (APR_UTIL_START_STATUS + 101) +/** @see APR_STATUS_IS_AUTH_UNKNOWN */ +#define APR_AUTH_UNKNOWN (APR_UTIL_START_STATUS + 102) +/** @see APR_STATUS_IS_PROXY_AUTH */ +#define APR_PROXY_AUTH (APR_UTIL_START_STATUS + 103) +/** @see APR_STATUS_IS_INAPPROPRIATE_AUTH */ +#define APR_INAPPROPRIATE_AUTH (APR_UTIL_START_STATUS + 104) +/** @see APR_STATUS_IS_INVALID_CREDENTIALS */ +#define APR_INVALID_CREDENTIALS (APR_UTIL_START_STATUS + 105) +/** @see APR_STATUS_IS_INSUFFICIENT_ACCESS */ +#define APR_INSUFFICIENT_ACCESS (APR_UTIL_START_STATUS + 106) /** @} */ /** @@ -160,8 +176,34 @@ * The signature verification failed */ #define APR_STATUS_IS_ENOVERIFY(s) ((s) == APR_ENOVERIFY) +/** + * The server is down + */ +#define APR_STATUS_IS_EDOWN(s) ((s) == APR_EDOWN) +/** + * Authentication mechanism not supoorted by this server + */ +#define APR_STATUS_IS_AUTH_UNKNOWN(s) ((s) == APR_AUTH_UNKNOWN) +/** + * Proxy authorization has failed + */ +#define APR_STATUS_IS_PROXY_AUTH(s) ((s) == APR_PROXY_AUTH) +/** + * Inappropriate authentication was specified (e.g., simple auth + * was specified but the entry does not have a userPassword attribute). + */ +#define APR_STATUS_IS_INAPPROPRIATE_AUTH(s) ((s) == APR_INAPPROPRIATE_AUTH) +/** + * Invalid credentials were presented (e.g., the wrong password). + */ +#define APR_STATUS_IS_INVALID_CREDENTIALS(s) ((s) == APR_INVALID_CREDENTIALS) +/** + * The user has insufficient access to perform the operation. + */ +#define APR_STATUS_IS_INSUFFICIENT_ACCESS(s) ((s) == APR_INSUFFICIENT_ACCESS) /** @} */ + /** * This structure allows the underlying API error codes to be returned * along with plain text error messages that explain to us mere mortals Index: include/private/apr_ldap_private.h =================================================================== --- include/private/apr_ldap_private.h (nonexistent) +++ include/private/apr_ldap_private.h (working copy) @@ -0,0 +1,93 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apu.h" +#include "apr_network_io.h" + +#ifndef APR_LDAP_PRIVATE_H +#define APR_LDAP_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if APR_HAS_LDAP + +typedef struct apr_ldap_t { + apr_pool_t *pool; + LDAP *ld; + apr_socket_t *socket; +} apr_ldap_t; + +typedef struct apr_ldap_message_t { + apr_ldap_t *ld; + const char *rmech; + LDAPMessage *message; + int msgid; +} apr_ldap_message_t; + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_status(int rc, apr_status_t status); + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_message_clear(apr_ldap_message_t *msg); + +APU_DECLARE_LDAP(apr_ldap_message_t *) apr_ldap_message_make(apr_ldap_t *ldap); + +#if APU_DSO_BUILD + +/* For LDAP internal builds, wrap our LDAP namespace */ + +struct apr__ldap_dso_fntable { + int (*info)(apr_pool_t *pool, apr_ldap_err_t **result_err); + int (*init)(apr_pool_t *pool, LDAP **ldap, const char *hostname, + int portno, int secure, apr_ldap_err_t **result_err); + int (*ssl_init)(apr_pool_t *pool, const char *cert_auth_file, + int cert_file_type, apr_ldap_err_t **result_err); + int (*ssl_deinit)(void); + int (*get_option)(apr_pool_t *pool, LDAP *ldap, int option, + void *outvalue, apr_ldap_err_t **result_err); + int (*set_option)(apr_pool_t *pool, LDAP *ldap, int option, + const void *invalue, apr_ldap_err_t **result_err); + apr_status_t (*rebind_init)(apr_pool_t *pool); + apr_status_t (*rebind_add)(apr_pool_t *pool, LDAP *ld, + const char *bindDN, const char *bindPW); + apr_status_t (*rebind_remove)(LDAP *ld); + apr_status_t (*initialize)(apr_pool_t *pool, const char *uri, + apr_ldap_t **ldap, + apu_err_t *result_err); + apr_status_t (*get_option_ex)(apr_ldap_t *ldap, int option, + apr_ldap_opt_t *outvalue, apu_err_t *result_err); + apr_status_t (*set_option_ex)(apr_ldap_t *ldap, int option, + const apr_ldap_opt_t *invalue, apu_err_t *result_err); + apr_status_t (*result)(apr_ldap_message_t *msg, apr_interval_time_t timeout, + apu_err_t *result); + apr_status_t (*bind)(apr_ldap_t *ldap, const char *dn, const char *mech, + apr_ldap_interact_proc *interact, void *ctx, + apr_interval_time_t timeout, + apr_ldap_message_t **msg, apu_err_t *result); +}; + +#endif /* APU_DSO_BUILD */ + +#endif /* APR_HAS_LDAP */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_LDAP_PRIVATE_H */ + + Index: include/private/apu_internal.h =================================================================== --- include/private/apu_internal.h (revision 1909133) +++ include/private/apu_internal.h (working copy) @@ -40,29 +40,6 @@ apr_status_t apu_dso_load(apr_dso_handle_t **dso, apr_dso_handle_sym_t *dsoptr, const char *module, const char *modsym, apr_pool_t *pool); -#if APR_HAS_LDAP - -/* For LDAP internal builds, wrap our LDAP namespace */ - -struct apr__ldap_dso_fntable { - int (*info)(apr_pool_t *pool, apr_ldap_err_t **result_err); - int (*init)(apr_pool_t *pool, LDAP **ldap, const char *hostname, - int portno, int secure, apr_ldap_err_t **result_err); - int (*ssl_init)(apr_pool_t *pool, const char *cert_auth_file, - int cert_file_type, apr_ldap_err_t **result_err); - int (*ssl_deinit)(void); - int (*get_option)(apr_pool_t *pool, LDAP *ldap, int option, - void *outvalue, apr_ldap_err_t **result_err); - int (*set_option)(apr_pool_t *pool, LDAP *ldap, int option, - const void *invalue, apr_ldap_err_t **result_err); - apr_status_t (*rebind_init)(apr_pool_t *pool); - apr_status_t (*rebind_add)(apr_pool_t *pool, LDAP *ld, - const char *bindDN, const char *bindPW); - apr_status_t (*rebind_remove)(LDAP *ld); -}; - -#endif /* APR_HAS_LDAP */ - #ifdef __cplusplus } #endif Index: ldap/NWGNUmakefile =================================================================== --- ldap/NWGNUmakefile (revision 1909133) +++ ldap/NWGNUmakefile (working copy) @@ -232,6 +232,7 @@ $(OBJDIR)/apr_ldap_init.o \ $(OBJDIR)/apr_ldap_option.o \ $(OBJDIR)/apr_ldap_url.o \ + $(OBJDIR)/apr_ldap_bind.o \ $(OBJDIR)/apr_ldap_rebind.o \ $(OBJDIR)/apr_ldap_stub.o \ $(EOLIST) Index: ldap/apr_ldap.dsp =================================================================== --- ldap/apr_ldap.dsp (revision 1909133) +++ ldap/apr_ldap.dsp (working copy) @@ -180,6 +180,10 @@ # End Source File # Begin Source File +SOURCE=.\apr_ldap_bind.c +# End Source File +# Begin Source File + SOURCE=.\apr_ldap_rebind.c # End Source File # End Group @@ -200,6 +204,10 @@ # End Source File # Begin Source File +SOURCE=..\include\apr_ldap_bind.h +# End Source File +# Begin Source File + SOURCE=..\include\apr_ldap_rebind.h # End Source File # Begin Source File Index: ldap/apr_ldap.mak =================================================================== --- ldap/apr_ldap.mak (revision 1909133) +++ ldap/apr_ldap.mak (working copy) @@ -54,6 +54,7 @@ -@erase "$(INTDIR)\apr_ldap-1.res" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_src.idb" -@erase "$(INTDIR)\apr_ldap_src.pdb" @@ -111,6 +112,7 @@ LINK32_OBJS= \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap-1.res" \ "..\..\apr\Release\libapr-1.lib" \ @@ -161,6 +163,7 @@ -@erase "$(INTDIR)\apr_ldap-1.res" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_src.idb" -@erase "$(INTDIR)\apr_ldap_src.pdb" @@ -218,6 +221,7 @@ LINK32_OBJS= \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap-1.res" \ "..\..\apr\Debug\libapr-1.lib" \ @@ -268,6 +272,7 @@ -@erase "$(INTDIR)\apr_ldap-1.res" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_src.idb" -@erase "$(INTDIR)\apr_ldap_src.pdb" @@ -325,6 +330,7 @@ LINK32_OBJS= \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap-1.res" \ "..\..\apr\x64\Release\libapr-1.lib" \ @@ -375,6 +381,7 @@ -@erase "$(INTDIR)\apr_ldap-1.res" -@erase "$(INTDIR)\apr_ldap_init.obj" -@erase "$(INTDIR)\apr_ldap_option.obj" + -@erase "$(INTDIR)\apr_ldap_bind.obj" -@erase "$(INTDIR)\apr_ldap_rebind.obj" -@erase "$(INTDIR)\apr_ldap_src.idb" -@erase "$(INTDIR)\apr_ldap_src.pdb" @@ -432,6 +439,7 @@ LINK32_OBJS= \ "$(INTDIR)\apr_ldap_init.obj" \ "$(INTDIR)\apr_ldap_option.obj" \ + "$(INTDIR)\apr_ldap_bind.obj" \ "$(INTDIR)\apr_ldap_rebind.obj" \ "$(INTDIR)\apr_ldap-1.res" \ "..\..\apr\x64\Debug\libapr-1.lib" \ @@ -478,6 +486,11 @@ "$(INTDIR)\apr_ldap_option.obj" : $(SOURCE) "$(INTDIR)" +SOURCE=.\apr_ldap_bind.c + +"$(INTDIR)\apr_ldap_bind.obj" : $(SOURCE) "$(INTDIR)" + + SOURCE=.\apr_ldap_rebind.c "$(INTDIR)\apr_ldap_rebind.obj" : $(SOURCE) "$(INTDIR)" Index: ldap/apr_ldap_bind.c =================================================================== --- ldap/apr_ldap_bind.c (nonexistent) +++ ldap/apr_ldap_bind.c (working copy) @@ -0,0 +1,284 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * apr_ldap_bind.c: LDAP v2/v3 common initialise + * + */ + +#include "apr.h" +#include "apu.h" +#include "apu_config.h" + +#if APU_DSO_BUILD +#define APU_DSO_LDAP_BUILD +#endif + +#include "apr_ldap.h" +#include "apr_ldap_private.h" +#include "apu_internal.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_strings.h" + +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#else +#ifdef HAVE_SASL_H +#include <sasl.h> +#endif +#endif + +#if APR_HAS_LDAP + +typedef struct apr_ldap_bind_ctx_t { + apr_ldap_t *ld; + apr_ldap_interact_proc *interact; + void *ctx; +} apr_ldap_bind_ctx_t; + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_message_clear(apr_ldap_message_t *msg) +{ + if (msg) { + msg->rmech = NULL; + if (msg->message) { + ldap_msgfree(msg->message); + msg->message = NULL; + } + msg->msgid = 0; + } + + return APR_SUCCESS; +} + +static apr_status_t message_cleanup(void *dptr) +{ + return apr_ldap_message_clear(dptr); +} + +APU_DECLARE_LDAP(apr_ldap_message_t *) apr_ldap_message_make(apr_ldap_t *ldap) +{ + apr_ldap_message_t *msg = apr_pcalloc(ldap->pool, sizeof(apr_ldap_message_t)); + + if (msg) { + msg->ld = ldap; + apr_pool_cleanup_register(ldap->pool, msg, message_cleanup, + apr_pool_cleanup_null); + } + + return msg; +} + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_result(apr_ldap_message_t *msg, + apr_interval_time_t timeout, + apu_err_t *result) +{ + int res; + + LDAP *ld = msg->ld->ld; + + struct timeval tv, *tvptr; + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_usec = (long) apr_time_usec(timeout); + tvptr = &tv; + } + + if (msg->message) { + ldap_msgfree( msg->message ); + } + + res = ldap_result( ld, msg->msgid, LDAP_MSG_RECEIVED, tvptr, &msg->message ); + if ( res == -1 ) { + result->reason = "LDAP: ldap_result() retrieval failed"; + + /* -1 is LDAP_SERVER_DOWN in openldap, use something else */ +#ifdef LDAP_OPT_ERROR_NUMBER + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &result->rc); +#endif +#ifdef LDAP_OPT_RESULT_CODE + ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &result->rc); +#endif + result->msg = ldap_err2string(result->rc); + return apr_ldap_status(result->rc, APR_EGENERAL); + } + else if (res == 0) { + result->reason = "LDAP: ldap_result() timed out"; + result->rc = LDAP_TIMEOUT; + result->msg = ldap_err2string(result->rc); + return APR_ETIMEDOUT; + } + + res = ldap_count_messages(ld, msg->message); + if ( res == -1 ) { + result->reason = "LDAP: ldap_count_entries() retrieval failed"; + + /* -1 is LDAP_SERVER_DOWN in openldap, use something else */ +#ifdef LDAP_OPT_ERROR_NUMBER + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &result->rc); +#endif +#ifdef LDAP_OPT_RESULT_CODE + ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &result->rc); +#endif + result->msg = ldap_err2string(result->rc); + return apr_ldap_status(result->rc, APR_EGENERAL); + } + else if (res == 0) { + return APR_SUCCESS; + } + else { + return APR_INCOMPLETE; + } + +} + + +static int bind_sasl_interact(LDAP *ld, unsigned flags, void *ctx, void *in ) +{ + apr_ldap_bind_ctx_t *payload = ctx; + sasl_interact_t *sasl_interact = in; + + if (!ld) { + return LDAP_PARAM_ERROR; + } + + while( sasl_interact->id != SASL_CB_LIST_END ) { + + apr_ldap_bind_interact_t interaction; + + interaction.id = sasl_interact->id; + interaction.challenge = sasl_interact->challenge; + interaction.prompt = sasl_interact->prompt; + interaction.defresult = sasl_interact->defresult; + interaction.result = NULL; + interaction.len = 0; + + int rc = payload->interact(payload->ld, flags, &interaction, payload->ctx ); + + if (rc) { + return rc; + } + + sasl_interact->result = interaction.result; + sasl_interact->len = interaction.len; + + sasl_interact++; + } + + return LDAP_SUCCESS; +} + + +/** + * APR LDAP bind function + * + * This function binds a previously initialised LDAP connection + * to the directory. + * + * Binds are attempted as SASL interactive, falling back to a + * standard SASL bind, falling back to a simple bind, depending + * on the capabilities of the platform. + * + * Binds are attempted asynchronously. If APR_EAGAIN is returned, + * this function must be called again. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_bind(apr_ldap_t *ldap, + const char *dn, + const char *mech, + apr_ldap_interact_proc *interact, + void *ctx, + apr_interval_time_t timeout, + apr_ldap_message_t **msg, + apu_err_t *result) +{ +#if APR_HAS_LDAP_SASL_INTERACTIVE_BIND + + LDAPControl *sctrls[] = { 0 }; + LDAPControl *cctrls[] = { 0 }; + + unsigned int flags = LDAP_SASL_QUIET; + + apr_ldap_bind_ctx_t payload; + + struct timeval tv, *tvptr; + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_usec = (long) apr_time_usec(timeout); + tvptr = &tv; + } + + memset(result, 0, sizeof(*result)); + + payload.ld = ldap; + payload.interact = interact; + payload.ctx = ctx; + + if (!*msg) { + *msg = apr_ldap_message_make(ldap); + if (!*msg) { + return APR_ENOMEM; + } + } + +#ifdef LDAP_OPT_NETWORK_TIMEOUT + if (!(*msg)->message) { + result->rc = ldap_set_option(ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, tvptr); + if (result->rc != LDAP_SUCCESS) { + result->msg = ldap_err2string(result->rc); + result->reason = "LDAP: Could not set network timeout"; + return APR_EINVAL; + } + } +#endif + + result->rc = ldap_sasl_interactive_bind(ldap->ld, dn, mech, + sctrls, cctrls, flags, bind_sasl_interact, &payload, + (*msg)->message, &(*msg)->rmech, &(*msg)->msgid ); + + if (result->rc == LDAP_SUCCESS) { + apr_ldap_message_clear(*msg); + return APR_SUCCESS; + } + else if (result->rc == LDAP_SASL_BIND_IN_PROGRESS) { + return APR_INCOMPLETE; + } + else { + apr_ldap_message_clear(*msg); + result->msg = ldap_err2string(result->rc); + result->reason = "LDAP: ldap_sasl_interactive_bind() failed"; + return apr_ldap_status(result->rc, APR_EGENERAL); + } + +#else + result->reason = "LDAP: Bind not yet supported by APR on this " + "LDAP SDK"; + result->rc = LDAP_UNWILLING_TO_PERFORM; + return APR_ENOTIMPL; +#endif +} + + + +#endif /* APR_HAS_LDAP */ + Index: ldap/apr_ldap_init.c =================================================================== --- ldap/apr_ldap_init.c (revision 1909133) +++ ldap/apr_ldap_init.c (working copy) @@ -31,6 +31,7 @@ #endif #include "apr_ldap.h" +#include "apr_ldap_private.h" #include "apu_internal.h" #include "apr_errno.h" #include "apr_pools.h" @@ -213,6 +214,130 @@ } +static apr_status_t ldap_cleanup(void *dptr) +{ + if (dptr) { + + apr_ldap_t *ldap = dptr; + + if (ldap->ld) { + ldap_unbind(ldap->ld); + ldap->ld = NULL; + } + } + + return APR_SUCCESS; +} + +/** + * APR LDAP initialise function + * + * This function is responsible for initialising an LDAP + * connection in a toolkit independant way. It does the + * job of ldap_initialize() from the C api. + * + * It handles the SSL case, the non-SSL case, and the IPC + * case, and attempts to hide the complexity setup from the + * user. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_initialize(apr_pool_t *pool, + const char *uri, + apr_ldap_t **ldap, + apu_err_t *result) +{ + LDAP *ld = NULL; + int rc; + + memset(result, 0, sizeof(*result)); + + *ldap = apr_pcalloc(pool, sizeof(apr_ldap_t)); + if (!*ldap) { + return APR_ENOMEM; + } + +#if APR_HAS_LDAP_INITIALIZE + + rc = ldap_initialize(&ld, uri); + +#else + + { + apr_ldap_url_desc_t *urld; + apr_status_t status; + int secure; + + status = apr_ldap_url_parse(pool, uri, &(urld), result_err); + if (status != APR_SUCCESS) { + return status; + } + + secure = apr_ldap_is_ldaps_url(uri); + +#if APR_HAS_LDAPSSL_INIT + ld = ldapssl_init(urld->lud_host, urld->lud_port, secure); +#elif APR_HAS_LDAP_SSLINIT + ld = ldap_sslinit((char *)urld->lud_host, urld->lud_port, secure); +#else + ld = ldap_init((char *)urld->lud_host, urld->lud_port); +#endif + + } + +#endif + + if (rc != LDAP_SUCCESS) { + + result->rc = rc; + result->msg = apr_pstrdup(pool, ldap_err2string(result-> rc)); + result->reason = apr_pstrdup(pool, "LDAP: Could not initialise"); + + return APR_EINVAL; + } + + (*ldap)->ld = ld; + (*ldap)->pool = pool; + + apr_pool_cleanup_register(pool, (*ldap), ldap_cleanup, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_status(int rc, apr_status_t status) +{ + + switch (rc) { + case LDAP_TIMEOUT: + return APR_ETIMEDOUT; + + case LDAP_SERVER_DOWN: + return APR_EDOWN; + + case LDAP_AUTH_UNKNOWN: + return APR_AUTH_UNKNOWN; + +#ifdef LDAP_X_PROXY_AUTHZ_FAILURE + case LDAP_X_PROXY_AUTHZ_FAILURE: + return APR_PROXY_AUTH; + +#endif + case LDAP_INAPPROPRIATE_AUTH: + return APR_INAPPROPRIATE_AUTH; + + case LDAP_INVALID_CREDENTIALS: + return APR_INVALID_CREDENTIALS; + + case LDAP_INSUFFICIENT_ACCESS: + return APR_INSUFFICIENT_ACCESS; + + default: + return status; + } + +} + + #if APU_DSO_BUILD /* For DSO builds, export the table of entry points into the apr_ldap DSO @@ -227,7 +352,12 @@ apr_ldap_set_option, apr_ldap_rebind_init, apr_ldap_rebind_add, - apr_ldap_rebind_remove + apr_ldap_rebind_remove, + apr_ldap_initialize, + apr_ldap_get_option_ex, + apr_ldap_set_option_ex, + apr_ldap_result, + apr_ldap_bind }; #endif /* APU_DSO_BUILD */ Index: ldap/apr_ldap_option.c =================================================================== --- ldap/apr_ldap_option.c (revision 1909133) +++ ldap/apr_ldap_option.c (working copy) @@ -30,17 +30,19 @@ #endif #include "apr_ldap.h" +#include "apr_ldap_private.h" #include "apr_errno.h" #include "apr_pools.h" #include "apr_strings.h" #include "apr_tables.h" +#include "apr_portable.h" #if APR_HAS_LDAP -static void option_set_cert(apr_pool_t *pool, LDAP *ldap, const void *invalue, - apr_ldap_err_t *result); -static void option_set_tls(apr_pool_t *pool, LDAP *ldap, const void *invalue, - apr_ldap_err_t *result); +static int option_set_cert(apr_pool_t *pool, LDAP *ldap, const void *invalue, + apu_err_t *result); +static int option_set_tls(apr_pool_t *pool, LDAP *ldap, const void *invalue, + apu_err_t *result); /** * APR LDAP get option function @@ -102,11 +104,11 @@ switch (option) { case APR_LDAP_OPT_TLS_CERT: - option_set_cert(pool, ldap, invalue, result); + option_set_cert(pool, ldap, invalue, (apu_err_t *)result); break; case APR_LDAP_OPT_TLS: - option_set_tls(pool, ldap, invalue, result); + option_set_tls(pool, ldap, invalue, (apu_err_t *)result); break; case APR_LDAP_OPT_VERIFY_CERT: @@ -220,8 +222,8 @@ * APR_LDAP_STARTTLS: STARTTLS encryption * APR_LDAP_STOPTLS: Stop existing TLS connecttion */ -static void option_set_tls(apr_pool_t *pool, LDAP *ldap, const void *invalue, - apr_ldap_err_t *result) +static int option_set_tls(apr_pool_t *pool, LDAP *ldap, const void *invalue, + apu_err_t *result) { #if APR_HAS_LDAP_SSL /* compiled with ssl support */ @@ -378,6 +380,7 @@ #endif /* APR_HAS_LDAP_SSL */ + return result->rc; } /** @@ -393,8 +396,8 @@ * Microsoft: unknown * Solaris: unknown */ -static void option_set_cert(apr_pool_t *pool, LDAP *ldap, - const void *invalue, apr_ldap_err_t *result) +static int option_set_cert(apr_pool_t *pool, LDAP *ldap, + const void *invalue, apu_err_t *result) { #if APR_HAS_LDAP_SSL #if APR_HAS_LDAPSSL_CLIENT_INIT || APR_HAS_OPENLDAP_LDAPSDK @@ -646,7 +649,332 @@ result->rc = -1; #endif /* APR_HAS_LDAP_SSL */ + return result->rc; } +/** + * APR LDAP get option function + * + * This function gets option values from a given LDAP session if + * one was specified. + * + * If result_err is NULL, no error detail is returned. If *result_err is + * NULL, an error detail will be created and returned. If *result_err is + * not NULL, an error detail will be written to this location. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_get_option_ex(apr_ldap_t *ldap, + int option, + apr_ldap_opt_t *outvalue, + apu_err_t *result) +{ + int rc; + + memset(result, 0, sizeof(*result)); + + switch (option) { + case APR_LDAP_OPT_API_INFO: { + LDAPAPIInfo info = { 0 }; + + info.ldapai_info_version = LDAP_API_INFO_VERSION; + + rc = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info); + + outvalue->info.api_version = info.ldapai_api_version; + outvalue->info.protocol_version = info.ldapai_protocol_version; + outvalue->info.extensions = (const char **)info.ldapai_extensions; + outvalue->info.vendor_name = info.ldapai_vendor_name; + outvalue->info.vendor_version = info.ldapai_vendor_version; + + break; + + } + case APR_LDAP_OPT_API_FEATURE_INFO: { + LDAPAPIFeatureInfo ldfi = { 0 }; + + ldfi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION; + ldfi.ldapaif_name = (char *)outvalue->ldfi.name; + + rc = ldap_get_option(NULL, LDAP_OPT_API_FEATURE_INFO, &ldfi); + + outvalue->ldfi.version = ldfi.ldapaif_version; + + break; + + } + case APR_LDAP_OPT_PROTOCOL_VERSION: { + + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_PROTOCOL_VERSION, &outvalue->pv); + + break; + } + case APR_LDAP_OPT_HANDLE: { + + outvalue->handle = ldap ? ldap->ld : NULL; + + return APR_SUCCESS; + } + case APR_LDAP_OPT_DESC: { + + apr_status_t status = APR_SUCCESS; + + if (!ldap->socket) { + apr_os_sock_t sock; + + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_DESC, &sock); + + if (rc == LDAP_SUCCESS) { + status = apr_os_sock_put(&ldap->socket, &sock, ldap->pool); + } + else { + status = APR_EGENERAL; + } + } + outvalue->socket = ldap->socket; + + return status; + } + case APR_LDAP_OPT_DEREF: { + + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_DEREF, &outvalue->deref); + + break; + } + case APR_LDAP_OPT_REFERRALS: { + int refs; + + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFERRALS, &refs); + + if (rc == LDAP_SUCCESS) { + outvalue->refs = refs ? APR_LDAP_OPT_ON : APR_LDAP_OPT_OFF; + } + + break; + } + case APR_LDAP_OPT_REFHOPLIMIT: { +#if defined(LDAP_OPT_REFERRAL_HOP_LIMIT) + /* Microsoft and Mozilla SDKs define LDAP_OPT_REFERRAL_HOP_LIMIT + */ + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFERRAL_HOP_LIMIT, &outvalue->refhoplimit); +#else +#if !defined(LDAP_OPT_REFHOPLIMIT) || APR_HAS_NOVELL_LDAPSDK || APR_HAS_OPENLDAP_LDAPSDK + result->reason = "LDAP: Referral hop limit not yet supported by APR on this " + "LDAP SDK"; + result->rc = LDAP_UNWILLING_TO_PERFORM; + return APR_ENOTIMPL; +#else + /* Setting this option is supported on at least TIVOLI_SDK. Folks who know + * the NOVELL, NETSCAPE, MOZILLA, and SOLARIS SDKs should note here if + * the SDK at least tolerates this option being set. + */ + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFHOPLIMIT, &outvalue->refhoplimit); +#endif +#endif + + break; + } + case APR_LDAP_OPT_RESULT_CODE: { + +#ifdef LDAP_OPT_RESULT_CODE + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_RESULT_CODE, &outvalue->result); +#else +#ifdef LDAP_OPT_ERROR_NUMBER + rc = ldap_get_option(ldap ? ldap->ld : NULL, LDAP_OPT_ERROR_NUMBER, &outvalue->result); +#endif +#endif + break; + } + case APR_LDAP_OPT_TLS_CERT: { + + result->reason = "LDAP: Could not get an option APR_LDAP_OPT_TLS_CERT: not implemented"; + + return APR_ENOTIMPL; + } + case APR_LDAP_OPT_TLS: { + + result->reason = "LDAP: Could not get an option APR_LDAP_OPT_TLS: not implemented"; + + return APR_ENOTIMPL; + } + case APR_LDAP_OPT_VERIFY_CERT: { + + result->reason = "LDAP: Could not get an option APR_LDAP_OPT_VERIFY_CERT: not implemented"; + + return APR_ENOTIMPL; + } + default: + rc = ldap_get_option(ldap ? ldap->ld : NULL, option, &outvalue->opt); + } + + if (rc != LDAP_SUCCESS) { + + result->rc = rc; + result->msg = ldap_err2string(result->rc); + result->reason = "LDAP: Could not get an option"; + + return APR_EINVAL; + } + + return APR_SUCCESS; +} + +/** + * APR LDAP set option function + * + * This function sets option values to a given LDAP session if + * one was specified. + * + * Where an option is not supported by an LDAP toolkit, this function + * will try and apply legacy functions to achieve the same effect, + * depending on the platform. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_set_option_ex(apr_ldap_t *ldap, + int option, + const apr_ldap_opt_t *invalue, + apu_err_t *result) +{ + int rc; + + memset(result, 0, sizeof(*result)); + + switch (option) { + case APR_LDAP_OPT_API_INFO: + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case APR_LDAP_OPT_API_FEATURE_INFO: + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case APR_LDAP_OPT_PROTOCOL_VERSION: + rc = ldap_set_option(ldap ? ldap->ld : NULL, LDAP_OPT_PROTOCOL_VERSION, &invalue->pv); + break; + + case APR_LDAP_OPT_HANDLE: + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case APR_LDAP_OPT_DESC: + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case APR_LDAP_OPT_DEREF: + rc = ldap_set_option(ldap ? ldap->ld : NULL, LDAP_OPT_DEREF, &invalue->deref); + break; + + case APR_LDAP_OPT_REFERRALS: { + void *refs = invalue->refs ? LDAP_OPT_ON : LDAP_OPT_OFF; + + /* Setting this option is supported on at least TIVOLI_SDK and OpenLDAP. Folks + * who know the NOVELL, NETSCAPE, MOZILLA, and SOLARIS SDKs should note here if + * the SDK at least tolerates this option being set, or add an elif to handle + * special cases (i.e. different LDAP_OPT_X value). + */ + rc = ldap_set_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFERRALS, refs); + break; + + } + case APR_LDAP_OPT_REFHOPLIMIT: +#if defined(LDAP_OPT_REFERRAL_HOP_LIMIT) + /* Microsoft and Mozilla SDKs define LDAP_OPT_REFERRAL_HOP_LIMIT + */ + rc = ldap_set_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFERRAL_HOP_LIMIT, &invalue->refhoplimit); +#else +#if !defined(LDAP_OPT_REFHOPLIMIT) || APR_HAS_NOVELL_LDAPSDK || APR_HAS_OPENLDAP_LDAPSDK + /* If the LDAP_OPT_REFHOPLIMIT symbol is missing, assume that the + * particular LDAP library has a reasonable default. So far certain + * versions of the OpenLDAP SDK miss this symbol (but default to 5), + * and the Microsoft SDK misses the symbol (the default is not known). + */ + result->reason = "LDAP: Referral hop limit not yet supported by APR on this " + "LDAP SDK"; + result->rc = LDAP_UNWILLING_TO_PERFORM; + return APR_ENOTIMPL; +#else + /* Setting this option is supported on at least TIVOLI_SDK. Folks who know + * the NOVELL, NETSCAPE, MOZILLA, and SOLARIS SDKs should note here if + * the SDK at least tolerates this option being set, or add an elif to handle + * special cases so an error isn't returned if there is a perfectly good + * default value that just can't be changed (like openLDAP). + */ + rc = ldap_set_option(ldap ? ldap->ld : NULL, LDAP_OPT_REFHOPLIMIT, &invalue->refhoplimit); +#endif +#endif + break; + + case APR_LDAP_OPT_RESULT_CODE: + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case APR_LDAP_OPT_TLS_CERT: + rc = option_set_cert(ldap->pool, ldap ? ldap->ld : NULL, invalue->certs, result); + break; + + case APR_LDAP_OPT_TLS: + rc = option_set_tls(ldap->pool, ldap ? ldap->ld : NULL, &invalue->tls, result); + break; + + case APR_LDAP_OPT_VERIFY_CERT: +#if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSK + result->reason = "LDAP: Verify certificate not yet supported by APR on the " + "Netscape, Solaris or Mozilla LDAP SDKs"; + result->rc = LDAP_UNWILLING_TO_PERFORM; + return APR_ENOTIMPL; +#endif +#if APR_HAS_NOVELL_LDAPSDK + if (invalue->verify) { + result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER); + } + else { + result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE); + } +#endif +#if APR_HAS_OPENLDAP_LDAPSDK +#ifdef LDAP_OPT_X_TLS + /* This is not a per-connection setting so just pass NULL for the + Ldap connection handle */ + if (invalue->verify) { + int i = LDAP_OPT_X_TLS_DEMAND; + result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i); + } + else { + int i = LDAP_OPT_X_TLS_NEVER; + result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i); + } +#else + result->reason = "LDAP: SSL/TLS not yet supported by APR on this " + "version of the OpenLDAP toolkit"; + result->rc = LDAP_UNWILLING_TO_PERFORM; + return APR_ENOTIMPL; +#endif +#endif + + /* handle the error case */ + if (result->rc != LDAP_SUCCESS) { + result->msg = ldap_err2string(result->rc); + result->reason = "LDAP: Could not set verify mode"; + return APR_EINVAL; + } + return APR_SUCCESS; + + default: + rc = ldap_set_option(ldap ? ldap->ld : NULL, option, invalue->opt); + } + + if (rc != LDAP_OPT_SUCCESS) { + + result->rc = rc; + if (!result->msg) { + result->msg = apr_pstrdup(ldap->pool, ldap_err2string(result->rc)); + } + if (result->reason) { + result->reason = apr_pstrdup(ldap->pool, "LDAP: Could not set an option"); + } + + return APR_EINVAL; + } + + return APR_SUCCESS; +} + #endif /* APR_HAS_LDAP */ Index: ldap/apr_ldap_stub.c =================================================================== --- ldap/apr_ldap_stub.c (revision 1909133) +++ ldap/apr_ldap_stub.c (working copy) @@ -18,6 +18,7 @@ #include "apu.h" #include "apu_config.h" #include "apr_ldap.h" +#include "apr_ldap_private.h" #include "apu_internal.h" #include "apr_dso.h" #include "apr_errno.h" @@ -139,6 +140,55 @@ return lfn->rebind_remove(ld); } +APU_DECLARE_LDAP(int) apr_ldap_initialize(apr_pool_t *pool, + const char *uri, + apr_ldap_t **ldap, + apu_err_t *result) +{ + LOAD_LDAP_STUB(pool, -1); + return lfn->initialize(pool, uri, ldap, result); +} + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_get_option_ex(apr_ldap_t *ldap, + int option, + apr_ldap_opt_t *outvalue, + apu_err_t *result) +{ + LOAD_LDAP_STUB(ldap->pool, -1); + return lfn->get_option_ex(ldap, option, outvalue, result); +} + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_set_option_ex(apr_ldap_t *ldap, + int option, + const apr_ldap_opt_t *invalue, + apu_err_t *result) +{ + LOAD_LDAP_STUB(ldap->pool, -1); + return lfn->set_option_ex(ldap, option, invalue, result); +} + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_result(apr_ldap_message_t *msg, + apr_interval_time_t timeout, + apu_err_t *result) +{ + LOAD_LDAP_STUB(msg->ld->pool, APR_EGENERAL); + return lfn->result(msg, timeout, result); +} + +APU_DECLARE_LDAP(apr_status_t) apr_ldap_bind(apr_ldap_t *ldap, + const char *dn, + const char *mech, + apr_ldap_interact_proc *interact, + void *ctx, + apr_interval_time_t timeout, + apr_ldap_message_t **msg, + apu_err_t *result) +{ + LOAD_LDAP_STUB(ldap->pool, -1); + return lfn->bind(ldap, dn, mech, interact, ctx, timeout, msg, result); +} + + #endif /* APU_DSO_BUILD */ #endif /* APR_HAS_LDAP */ Index: libaprutil.dsp =================================================================== --- libaprutil.dsp (revision 1909133) +++ libaprutil.dsp (working copy) @@ -360,6 +360,11 @@ # End Source File # Begin Source File +SOURCE=.\ldap\apr_ldap_bind.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + SOURCE=.\ldap\apr_ldap_rebind.c # PROP Exclude_From_Build 1 # End Source File Index: libaprutil.mak =================================================================== --- libaprutil.mak (revision 1909133) +++ libaprutil.mak (working copy) @@ -1006,7 +1006,8 @@ SOURCE=.\ldap\apr_ldap_init.c SOURCE=.\ldap\apr_ldap_option.c -SOURCE=.\ldap\apr_ldap_rebind.c +SOURCE=.\ldap\apr_ldap_bind.c +SOURCE=.\ldap\apr_ldap_rebind.c SOURCE=.\ldap\apr_ldap_stub.c "$(INTDIR)\apr_ldap_stub.obj" : $(SOURCE) "$(INTDIR)" ".\include\apu.h" ".\include\private\apu_config.h" ".\include\apr_ldap.h" Index: test/testldap.c =================================================================== --- test/testldap.c (revision 1909133) +++ test/testldap.c (working copy) @@ -91,10 +91,8 @@ return 0; } - ptr = strstr (ldap_host, "\r\n"); - if (ptr) { - *ptr = '\0'; - } + ptr = ldap_host; + strsep (&ptr, "\r\n"); apr_file_close(thefile); return 1; @@ -140,92 +138,268 @@ return 0; } -static void test_ldap_connection(abts_case *tc, LDAP *ldap) +static apr_status_t bind_interact_external(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) { - int version = LDAP_VERSION3; - int failures, result; - + return APR_SUCCESS; +} + +static apr_status_t bind_interact_plain(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) +{ + + switch (interact->id) { + case APR_LDAP_INTERACT_USER: + break; + case APR_LDAP_INTERACT_AUTHNAME: + interact->result = "user"; + interact->len = strlen(interact->result); + break; + case APR_LDAP_INTERACT_PASS: + interact->result = "opensesame"; + interact->len = strlen(interact->result); + break; + default: + break; + } + + return APR_SUCCESS; +} + +static void test_ldap_connection(abts_case *tc, apr_ldap_t *ldap, const char *mech, apr_ldap_interact_proc *interact) +{ + apu_err_t result; + apr_ldap_message_t *msg = NULL; + apr_ldap_opt_t opt; + apr_status_t status; + /* always default to LDAP V3 */ - ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); + opt.pv = APR_LDAP_VERSION3; + apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &result); - for (failures=0; failures<10; failures++) - { - result = ldap_simple_bind_s(ldap, - (char *)NULL, - (char *)NULL); - if (LDAP_SERVER_DOWN != result) + apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_HANDLE, &opt, &result); + ABTS_TRUE(tc, opt.handle != NULL); + + do { + status = apr_ldap_bind(ldap, NULL, mech, interact, NULL, apr_time_from_sec(5), &msg, &result); + + if (APR_SUCCESS == status) { break; - } + } + else if (APR_INCOMPLETE == status) { + /* keep going */ + } + else if (APR_STATUS_IS_ETIMEDOUT(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_EDOWN(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_AUTH_UNKNOWN(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_PROXY_AUTH(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_INAPPROPRIATE_AUTH(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_INVALID_CREDENTIALS(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else if (APR_STATUS_IS_INSUFFICIENT_ACCESS(status)) { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + break; + } + else { + abts_log_message("%s - %s (%d)\n", result.reason, result.msg, result.rc); + ABTS_TRUE(tc, status == LDAP_SUCCESS); + break; + } - ABTS_TRUE(tc, result == LDAP_SUCCESS); - if (result != LDAP_SUCCESS) { - abts_log_message("%s\n", ldap_err2string(result)); - } + ABTS_TRUE(tc, msg != NULL); - ldap_unbind_s(ldap); + status = apr_ldap_result(msg, apr_time_from_sec(5), &result); + if (APR_SUCCESS == status) { + /* no more messages */ + break; + } + else if (APR_INCOMPLETE == status) { + /* keep going */ + } + else { + abts_log_message("%s\n", result.reason); + ABTS_TRUE(tc, status == LDAP_SUCCESS); + break; + } + + } while (APR_INCOMPLETE == status); + + status = apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_DESC, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_ASSERT(tc, "failed to get descriptor", opt.socket != NULL); + return; } +static void test_ldap_global_opts(abts_case *tc, void *data) +{ + apu_err_t result; + apr_ldap_opt_t opt; + apr_status_t status; + + status = apr_ldap_get_option_ex(NULL, APR_LDAP_OPT_API_INFO, &opt, &result); + + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_TRUE(tc, result.rc == 0); + ABTS_TRUE(tc, opt.info.vendor_name != NULL); + + opt.ldfi.name = "THREAD_SAFE"; + status = apr_ldap_get_option_ex(NULL, APR_LDAP_OPT_API_FEATURE_INFO, &opt, &result); + /* feature may exist, or may not */ + ABTS_TRUE(tc, status == APR_SUCCESS || status == APR_EINVAL); + +} + +static void test_ldap_opts(abts_case *tc, void *data) +{ + apr_pool_t *pool; + apr_ldap_t *ldap; + apu_err_t result; + const char *url; + + apr_pool_create(&pool, p); + + url = apr_psprintf(pool, "ldap://%s:%d", "localhost", LDAP_PORT); + + apr_ldap_initialize(pool, url, &ldap, &(result)); + + ABTS_TRUE(tc, ldap != NULL); + + if (result.rc == LDAP_SUCCESS) { + + apr_status_t status; + apr_ldap_opt_t opt; + + opt.pv = APR_LDAP_VERSION3; + status = apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + status = apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_ASSERT(tc, "failed to set protocol version", opt.pv == APR_LDAP_VERSION3); + + opt.deref = APR_LDAP_DEREF_ALWAYS; + status = apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_DEREF, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + status = apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_DEREF, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_ASSERT(tc, "failed to set deref", opt.deref == APR_LDAP_DEREF_ALWAYS); + + opt.refs = APR_LDAP_OPT_ON; + status = apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_REFERRALS, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + status = apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_REFERRALS, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_ASSERT(tc, "failed to set referrals", opt.refs == APR_LDAP_OPT_ON); + + opt.refhoplimit = 5; + status = apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_REFHOPLIMIT, &opt, &result); + if (APR_ENOTIMPL != status) { + ABTS_TRUE(tc, status == APR_SUCCESS); + status = apr_ldap_get_option_ex(ldap, APR_LDAP_OPT_REFHOPLIMIT, &opt, &result); + ABTS_TRUE(tc, status == APR_SUCCESS); + ABTS_ASSERT(tc, "failed to set refhoplimit", opt.refhoplimit == 5); + } + + } + + apr_pool_destroy(pool); +} + static void test_ldap(abts_case *tc, void *data) { - apr_pool_t *pool = p; - LDAP *ldap; - apr_ldap_err_t *result = NULL; + apr_pool_t *pool; + apr_ldap_t *ldap; + apu_err_t result; + const char *url; + apr_pool_create(&pool, p); ABTS_ASSERT(tc, "failed to get host", ldap_host[0] != '\0'); + + url = apr_psprintf(pool, "ldap://%s:%d", ldap_host, LDAP_PORT); - apr_ldap_init(pool, &ldap, - ldap_host, LDAP_PORT, - APR_LDAP_NONE, &(result)); + apr_ldap_initialize(pool, url, &ldap, &(result)); ABTS_TRUE(tc, ldap != NULL); - ABTS_PTR_NOTNULL(tc, result); - if (result->rc == LDAP_SUCCESS) { - test_ldap_connection(tc, ldap); + if (result.rc == LDAP_SUCCESS) { + test_ldap_connection(tc, ldap, "PLAIN", bind_interact_plain); } + + apr_pool_destroy(pool); } static void test_ldaps(abts_case *tc, void *data) { - apr_pool_t *pool = p; - LDAP *ldap; - apr_ldap_err_t *result = NULL; + apr_pool_t *pool; + apr_ldap_t *ldap; + apu_err_t result; + const char *url; - apr_ldap_init(pool, &ldap, - ldap_host, LDAPS_PORT, - APR_LDAP_SSL, &(result)); + apr_pool_create(&pool, p); + url = apr_psprintf(pool, "ldaps://%s:%d", ldap_host, LDAPS_PORT); + + apr_ldap_initialize(pool, url, &ldap, &(result)); + ABTS_TRUE(tc, ldap != NULL); - ABTS_PTR_NOTNULL(tc, result); - if (result->rc == LDAP_SUCCESS) { + if (result.rc == LDAP_SUCCESS) { add_ldap_certs(tc); - test_ldap_connection(tc, ldap); + test_ldap_connection(tc, ldap, "EXTERNAL", bind_interact_external); + test_ldap_connection(tc, ldap, "PLAIN", bind_interact_plain); } + + apr_pool_destroy(pool); } static void test_ldap_tls(abts_case *tc, void *data) { - apr_pool_t *pool = p; - LDAP *ldap; - apr_ldap_err_t *result = NULL; + apr_pool_t *pool; + apr_ldap_t *ldap; + apu_err_t result; + const char *url; + apr_ldap_opt_t opt; - apr_ldap_init(pool, &ldap, - ldap_host, LDAP_PORT, - APR_LDAP_STARTTLS, &(result)); + apr_pool_create(&pool, p); + opt.tls = APR_LDAP_TLS_STARTTLS; + + url = apr_psprintf(pool, "ldap://%s:%d", ldap_host, LDAP_PORT); + + apr_ldap_initialize(pool, url, &ldap, &(result)); + + if (result.rc == LDAP_SUCCESS) { + apr_ldap_set_option_ex(ldap, APR_LDAP_OPT_TLS, &opt, &(result)); + } + ABTS_TRUE(tc, ldap != NULL); - ABTS_PTR_NOTNULL(tc, result); - if (result->rc == LDAP_SUCCESS) { + if (result.rc == LDAP_SUCCESS) { add_ldap_certs(tc); - test_ldap_connection(tc, ldap); + test_ldap_connection(tc, ldap, "EXTERNAL", bind_interact_external); + test_ldap_connection(tc, ldap, "PLAIN", bind_interact_plain); } + + apr_pool_destroy(pool); } #endif /* APR_HAS_LDAP */ @@ -238,11 +412,17 @@ apr_ldap_ssl_init(p, NULL, 0, &result); + abts_run_test(suite, test_ldap_global_opts, NULL); + abts_run_test(suite, test_ldap_opts, NULL); + if (get_ldap_host()) { abts_run_test(suite, test_ldap, NULL); abts_run_test(suite, test_ldaps, NULL); abts_run_test(suite, test_ldap_tls, NULL); } + + apr_ldap_ssl_deinit(); + #endif /* APR_HAS_LDAP */ return suite;