diff --git a/configure b/configure index 7828d8543ca..cd6d8e248cd 100755 --- a/configure +++ b/configure @@ -9615,9 +9615,9 @@ LDAPLIBS="" if test "$ac_cv_header_ldap_h" = "yes" -a "$ac_cv_header_lber_h" = "yes" then - echo "$as_me:$LINENO: checking for ldap_init in -lldap" >&5 -echo $ECHO_N "checking for ldap_init in -lldap... $ECHO_C" >&6 -if test "${ac_cv_lib_ldap_ldap_init+set}" = set; then + echo "$as_me:$LINENO: checking for ldap_initialize in -lldap" >&5 +echo $ECHO_N "checking for ldap_initialize in -lldap... $ECHO_C" >&6 +if test "${ac_cv_lib_ldap_ldap_initialize+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9635,11 +9635,11 @@ extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char ldap_init (); +char ldap_initialize (); int main () { -ldap_init (); +ldap_initialize (); ; return 0; } @@ -9665,20 +9665,20 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_ldap_ldap_init=yes + ac_cv_lib_ldap_ldap_initialize=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_ldap_ldap_init=no +ac_cv_lib_ldap_ldap_initialize=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_ldap_ldap_init" >&5 -echo "${ECHO_T}$ac_cv_lib_ldap_ldap_init" >&6 -if test $ac_cv_lib_ldap_ldap_init = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_ldap_ldap_initialize" >&5 +echo "${ECHO_T}$ac_cv_lib_ldap_ldap_initialize" >&6 +if test $ac_cv_lib_ldap_ldap_initialize = yes; then echo "$as_me:$LINENO: checking for ber_init in -llber" >&5 echo $ECHO_N "checking for ber_init in -llber... $ECHO_C" >&6 if test "${ac_cv_lib_lber_ber_init+set}" = set; then diff --git a/configure.ac b/configure.ac index 39031d9c3a7..a834d404491 100644 --- a/configure.ac +++ b/configure.ac @@ -545,7 +545,7 @@ dnl **** Check for OpenLDAP *** AC_SUBST(LDAPLIBS,"") if test "$ac_cv_header_ldap_h" = "yes" -a "$ac_cv_header_lber_h" = "yes" then - AC_CHECK_LIB(ldap, ldap_init, + AC_CHECK_LIB(ldap, ldap_initialize, [AC_CHECK_LIB(lber, ber_init, [AC_DEFINE(HAVE_LDAP, 1, [Define if you have the OpenLDAP development environment]) LDAPLIBS="-lldap -llber"])]) diff --git a/dlls/wldap32/init.c b/dlls/wldap32/init.c index 8e5f29fa85f..050f1305cf8 100644 --- a/dlls/wldap32/init.c +++ b/dlls/wldap32/init.c @@ -23,6 +23,7 @@ #include "wine/port.h" #include "wine/debug.h" +#include #include #include "windef.h" @@ -39,25 +40,228 @@ #include "winldap_private.h" #include "wldap32.h" +#ifdef HAVE_LDAP /* Should eventually be determined by the algorithm documented on MSDN. */ static const WCHAR defaulthost[] = { 'l','o','c','a','l','h','o','s','t',0 }; +/* Split a space separated string of hostnames into a string array */ +static char **split_hostnames( const char *hostnames ) +{ + char **res, *str, *p, *q; + unsigned int i = 0; + + str = strdupU( hostnames ); + if (!str) return NULL; + + p = str; + while (isspace( *p )) p++; + if (*p) i++; + + while (*p) + { + if (isspace( *p )) + { + while (isspace( *p )) p++; + if (*p) i++; + } + p++; + } + + res = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(char *) ); + if (!res) + { + HeapFree( GetProcessHeap(), 0, str ); + return NULL; + } + + p = str; + while (isspace( *p )) p++; + + q = p; + i = 0; + + while (*p) + { + if (p[1] != '\0') + { + if (isspace( *p )) + { + *p = '\0'; p++; + res[i] = strdupU( q ); + if (!res[i]) goto oom; + i++; + + while (isspace( *p )) p++; + q = p; + } + } + else + { + res[i] = strdupU( q ); + if (!res[i]) goto oom; + i++; + } + p++; + } + res[i] = NULL; + + HeapFree( GetProcessHeap(), 0, str ); + return res; + +oom: + for (--i; i >= 0; i--) + strfreeU( res[i] ); + + HeapFree( GetProcessHeap(), 0, res ); + HeapFree( GetProcessHeap(), 0, str ); + + return NULL; +} + +/* Determine if a URL starts with a known LDAP scheme */ +static int has_ldap_scheme( char *url ) +{ + if (!strncasecmp( url, "ldap://", 7 ) || + !strncasecmp( url, "ldaps://", 8 ) || + !strncasecmp( url, "ldapi://", 8 ) || + !strncasecmp( url, "cldap://", 8 )) return 1; + return 0; +} + +/* Flatten an array of hostnames into a space separated string of URLs. + * Prepend a given scheme and append a given portnumber to each hostname + * if necessary. + */ +static char *join_hostnames( char *scheme, char **hostnames, ULONG portnumber ) +{ + char *res, *p, *q, **v; + unsigned int i = 0, size = 0; + static const char sep[] = " ", fmt[] = ":%ld"; + char port[6]; + + sprintf( port, fmt, portnumber ); + + for (v = hostnames; *v; v++) + { + if (!has_ldap_scheme( *v )) + { + size += strlen( scheme ); + q = *v; + } + else + /* skip past colon in scheme prefix */ + q = strchr( *v, '/' ); + + size += strlen( *v ); + + if (!strchr( q, ':' )) + size += strlen( port ); + + i++; + } + + size += (i - 1) * strlen( sep ); + + res = HeapAlloc( GetProcessHeap(), 0, size + 1 ); + if (!res) return NULL; + + p = res; + for (v = hostnames; *v; v++) + { + if (v != hostnames) + { + strcpy( p, sep ); + p += strlen( sep ); + } + + if (!has_ldap_scheme( *v )) + { + strcpy( p, scheme ); + p += strlen( scheme ); + q = *v; + } + else + /* skip past colon in scheme prefix */ + q = strchr( *v, '/' ); + + strcpy( p, *v ); + p += strlen( *v ); + + if (!strchr( q, ':' )) + { + strcpy( p, port ); + p += strlen( port ); + } + } + return res; +} + +static char *urlify_hostnames( char *scheme, char *hostnames, ULONG port ) +{ + char *url, **strarray; + + strarray = split_hostnames( hostnames ); + url = join_hostnames( scheme, strarray, port ); + strarrayfreeU( strarray ); + + return url; +} +#endif + WINE_DEFAULT_DEBUG_CHANNEL(wldap32); WLDAP32_LDAP *cldap_openA( PCHAR hostname, ULONG portnumber ) { +#ifdef HAVE_LDAP + WLDAP32_LDAP *ld = NULL; + WCHAR *hostnameW = NULL; + TRACE( "(%s, %ld)\n", debugstr_a(hostname), portnumber ); - /* FIXME: should use UDP instead of TCP */ - return ldap_openA( hostname, portnumber ); + if (hostname) { + hostnameW = strAtoW( hostname ); + if (!hostnameW) goto exit; + } + + ld = cldap_openW( hostnameW, portnumber ); + +exit: + strfreeW( hostnameW ); + return ld; + +#endif + return NULL; } WLDAP32_LDAP *cldap_openW( PWCHAR hostname, ULONG portnumber ) { +#ifdef HAVE_LDAP + LDAP *ld = NULL; + char *hostnameU = NULL, *url = NULL; + TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber ); - /* FIXME: should use UDP instead of TCP */ - return ldap_openW( hostname, portnumber ); + if (hostname) { + hostnameU = strWtoU( hostname ); + if (!hostnameU) goto exit; + } + else { + hostnameU = strWtoU( defaulthost ); + if (!hostnameU) goto exit; + } + + url = urlify_hostnames( "cldap://", hostnameU, portnumber ); + if (!url) goto exit; + + ldap_initialize( &ld, url ); + +exit: + strfreeU( hostnameU ); + strfreeU( url ); + return ld; + +#endif + return NULL; } ULONG ldap_connect( WLDAP32_LDAP *ld, LDAP_TIMEVAL *timeout ) @@ -65,7 +269,7 @@ ULONG ldap_connect( WLDAP32_LDAP *ld, LDAP_TIMEVAL *timeout ) TRACE( "(%p, %p)\n", ld, timeout ); if (!ld || !timeout) return WLDAP32_LDAP_PARAM_ERROR; - return LDAP_SUCCESS; + return LDAP_SUCCESS; /* FIXME: do something, e.g. ping the host */ } WLDAP32_LDAP *ldap_initA( PCHAR hostname, ULONG portnumber ) @@ -95,7 +299,7 @@ WLDAP32_LDAP *ldap_initW( PWCHAR hostname, ULONG portnumber ) { #ifdef HAVE_LDAP LDAP *ld = NULL; - char *hostnameU = NULL; + char *hostnameU = NULL, *url = NULL; TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber ); @@ -108,10 +312,14 @@ WLDAP32_LDAP *ldap_initW( PWCHAR hostname, ULONG portnumber ) if (!hostnameU) goto exit; } - ld = ldap_init( hostnameU, portnumber ); + url = urlify_hostnames( "ldap://", hostnameU, portnumber ); + if (!url) goto exit; + + ldap_initialize( &ld, url ); exit: strfreeU( hostnameU ); + strfreeU( url ); return ld; #endif @@ -145,7 +353,7 @@ WLDAP32_LDAP *ldap_openW( PWCHAR hostname, ULONG portnumber ) { #ifdef HAVE_LDAP LDAP *ld = NULL; - char *hostnameU = NULL; + char *hostnameU = NULL, *url = NULL; TRACE( "(%s, %ld)\n", debugstr_w(hostname), portnumber ); @@ -158,10 +366,70 @@ WLDAP32_LDAP *ldap_openW( PWCHAR hostname, ULONG portnumber ) if (!hostnameU) goto exit; } - ld = ldap_open( hostnameU, portnumber ); + url = urlify_hostnames( "ldap://", hostnameU, portnumber ); + if (!url) goto exit; + + ldap_initialize( &ld, url ); exit: strfreeU( hostnameU ); + strfreeU( url ); + return ld; + +#endif + return NULL; +} + +WLDAP32_LDAP *ldap_sslinitA( PCHAR hostname, ULONG portnumber, int secure ) +{ +#ifdef HAVE_LDAP + WLDAP32_LDAP *ld; + WCHAR *hostnameW = NULL; + + TRACE( "(%s, %ld, 0x%08x)\n", debugstr_a(hostname), portnumber, secure ); + + if (hostname) { + hostnameW = strAtoW( hostname ); + if (!hostnameW) return NULL; + } + + ld = ldap_sslinitW( hostnameW, portnumber, secure ); + + strfreeW( hostnameW ); + return ld; + +#endif + return NULL; +} + +WLDAP32_LDAP *ldap_sslinitW( PWCHAR hostname, ULONG portnumber, int secure ) +{ +#ifdef HAVE_LDAP + WLDAP32_LDAP *ld; + char *hostnameU = NULL, *url = NULL; + + TRACE( "(%s, %ld, 0x%08x)\n", debugstr_w(hostname), portnumber, secure ); + + if (hostname) { + hostnameU = strWtoU( hostname ); + if (!hostnameU) goto exit; + } + else { + hostnameU = strWtoU( defaulthost ); + if (!hostnameU) goto exit; + } + + if (secure) + url = urlify_hostnames( "ldaps://", hostnameU, portnumber ); + else + url = urlify_hostnames( "ldap://", hostnameU, portnumber ); + + if (!url) goto exit; + ldap_initialize( &ld, url ); + +exit: + strfreeU( hostnameU ); + strfreeU( url ); return ld; #endif @@ -231,3 +499,15 @@ exit: #endif return ret; } + +ULONG ldap_startup( PLDAP_VERSION_INFO version, HANDLE *instance ) +{ + TRACE( "(%p, %p)\n", version, instance ); + return LDAP_SUCCESS; +} + +BOOLEAN ldap_stop_tls_s( WLDAP32_LDAP *ld ) +{ + TRACE( "(%p)\n", ld ); + return 0; /* FIXME: find a way to stop tls on a connection */ +} diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h index f7db4497b3a..8f995e3c196 100644 --- a/dlls/wldap32/winldap_private.h +++ b/dlls/wldap32/winldap_private.h @@ -373,8 +373,12 @@ ULONG ldap_simple_bindA(WLDAP32_LDAP*,PCHAR,PCHAR); ULONG ldap_simple_bindW(WLDAP32_LDAP*,PWCHAR,PWCHAR); ULONG ldap_simple_bind_sA(WLDAP32_LDAP*,PCHAR,PCHAR); ULONG ldap_simple_bind_sW(WLDAP32_LDAP*,PWCHAR,PWCHAR); +WLDAP32_LDAP *ldap_sslinitA(PCHAR,ULONG,int); +WLDAP32_LDAP *ldap_sslinitW(PWCHAR,ULONG,int); ULONG ldap_start_tls_sA(WLDAP32_PLDAP,PULONG,WLDAP32_LDAPMessage**,PLDAPControlA*,PLDAPControlA*); ULONG ldap_start_tls_sW(WLDAP32_PLDAP,PULONG,WLDAP32_LDAPMessage**,PLDAPControlW*,PLDAPControlW*); +ULONG ldap_startup(PLDAP_VERSION_INFO,HANDLE*); +BOOLEAN ldap_stop_tls_s(WLDAP32_PLDAP); ULONG ldap_ufn2dnA(PCHAR,PCHAR*); ULONG ldap_ufn2dnW(PWCHAR,PWCHAR*); ULONG WLDAP32_ldap_unbind(WLDAP32_LDAP*); diff --git a/dlls/wldap32/wldap32.h b/dlls/wldap32/wldap32.h index c84fb57aad5..753a1688bc2 100644 --- a/dlls/wldap32/wldap32.h +++ b/dlls/wldap32/wldap32.h @@ -22,6 +22,17 @@ * to and from ansi (A), wide character (W) and utf8 (U) encodings. */ +static inline char *strdupU( const char *src ) +{ + char *dst; + + if (!src) return NULL; + dst = HeapAlloc( GetProcessHeap(), 0, (strlen( src ) + 1) * sizeof(char) ); + if (dst) + strcpy( dst, src ); + return dst; +} + static inline LPWSTR strAtoW( LPCSTR str ) { LPWSTR ret = NULL; diff --git a/dlls/wldap32/wldap32.spec b/dlls/wldap32/wldap32.spec index d30218a1cbb..48ebc28732e 100644 --- a/dlls/wldap32/wldap32.spec +++ b/dlls/wldap32/wldap32.spec @@ -188,7 +188,7 @@ 198 stub ldap_set_dbg_flags 199 stub ldap_set_dbg_routine 200 cdecl ldap_memfree(ptr) ldap_memfreeA -201 stub ldap_startup +201 cdecl ldap_startup(ptr ptr) 202 cdecl ldap_cleanup(long) 203 cdecl ldap_search_ext_sW(ptr wstr long wstr ptr long ptr ptr ptr long ptr) 204 stub ldap_search_init_page @@ -204,9 +204,9 @@ 214 cdecl ldap_simple_bindW(ptr wstr wstr) 215 cdecl ldap_simple_bind_sA(ptr str str) 216 cdecl ldap_simple_bind_sW(ptr wstr wstr) -217 stub ldap_sslinit -218 stub ldap_sslinitA -219 stub ldap_sslinitW +217 cdecl ldap_sslinit(str long long) ldap_sslinitA +218 cdecl ldap_sslinitA(str long long) +219 cdecl ldap_sslinitW(str long long) 220 cdecl ldap_ufn2dn(str ptr) ldap_ufn2dnA 221 cdecl ldap_ufn2dnA(str ptr) 222 cdecl ldap_ufn2dnW(wstr ptr) @@ -240,6 +240,6 @@ 322 stub ldap_parse_vlv_controlA 329 cdecl ldap_start_tls_sW(ptr ptr ptr ptr ptr) 330 cdecl ldap_start_tls_sA(ptr ptr ptr ptr ptr) -331 stub ldap_stop_tls_s +331 cdecl ldap_stop_tls_s(ptr) 332 cdecl ldap_extended_operation_sW(ptr wstr ptr ptr ptr ptr ptr) 333 cdecl ldap_extended_operation_sA(ptr str ptr ptr ptr ptr ptr)