-- v2: wldap32/tests: Add some tests for LDAP authentication to a Kerberos DC. wldap32: ldap_init() should resolve NULL hostname to default Kerberos DC. wldap32: Use correct host when connecting to Kerberos DC.
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/wldap32/Makefile.in | 2 +- dlls/wldap32/bind.c | 3 +- dlls/wldap32/init.c | 50 ++++++++++++++++++++++++++++------ dlls/wldap32/winldap_private.h | 2 +- 4 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/dlls/wldap32/Makefile.in b/dlls/wldap32/Makefile.in index 30b1c389b60..10f96c9e8ff 100644 --- a/dlls/wldap32/Makefile.in +++ b/dlls/wldap32/Makefile.in @@ -1,6 +1,6 @@ MODULE = wldap32.dll IMPORTLIB = wldap32 -IMPORTS = $(LDAP_PE_LIBS) crypt32 secur32 ws2_32 user32 +IMPORTS = $(LDAP_PE_LIBS) crypt32 secur32 ws2_32 user32 netapi32 EXTRAINCL = $(LDAP_PE_CFLAGS)
SOURCES = \ diff --git a/dlls/wldap32/bind.c b/dlls/wldap32/bind.c index f150a4f0c02..c297c234ad6 100644 --- a/dlls/wldap32/bind.c +++ b/dlls/wldap32/bind.c @@ -140,7 +140,7 @@ static int interact_callback( LDAP *ld, unsigned flags, void *defaults, void *sa SEC_WINNT_AUTH_IDENTITY_W *id = defaults; struct sasl_interact *ptr = sasl_interact;
- TRACE( "%p, %08xlx, %p, %p\n", ld, flags, defaults, sasl_interact ); + TRACE( "%p, %08x, %p, %p\n", ld, flags, defaults, sasl_interact );
if (!defaults) return 0;
@@ -495,6 +495,7 @@ ULONG CDECL WLDAP32_ldap_unbind( LDAP *ld )
if (SERVER_CTRLS(ld)) ldap_value_free_len( SERVER_CTRLS(ld) );
+ free( ld->ld_host ); free( ld ); return ret; } diff --git a/dlls/wldap32/init.c b/dlls/wldap32/init.c index 44fc44ee485..dcd20fea999 100644 --- a/dlls/wldap32/init.c +++ b/dlls/wldap32/init.c @@ -26,6 +26,9 @@ #include "winternl.h" #include "schannel.h" #include "sspi.h" +#include "dsgetdc.h" +#include "lmcons.h" +#include "lmapibuf.h"
#include "wine/debug.h" #include "winldap_private.h" @@ -231,15 +234,20 @@ LDAP * CDECL cldap_openW( WCHAR *hostname, ULONG portnumber ) { LDAP *ld = NULL; char *hostnameU, *url = NULL; + WCHAR *hostnameW;
TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
- if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit; if (!(url = urlify_hostnames( "cldap://", hostnameU, portnumber ))) goto exit;
ld = create_context( url ); - exit: + if (ld) + ld->ld_host = hostnameW; + else + free( hostnameW ); free( hostnameU ); free( url ); return ld; @@ -252,6 +260,7 @@ ULONG CDECL WLDAP32_ldap_connect( LDAP *ld, struct l_timeval *timeout ) { QUERYCLIENTCERT *client_cert_callback = CLIENT_CERT_CALLBACK(ld); VERIFYSERVERCERT *server_cert_callback = SERVER_CERT_CALLBACK(ld); + DOMAIN_CONTROLLER_INFOW *dcinfo; int ret;
TRACE( "(%p, %p)\n", ld, timeout ); @@ -263,6 +272,16 @@ ULONG CDECL WLDAP32_ldap_connect( LDAP *ld, struct l_timeval *timeout ) FIXME( "mTLS is not implemented\n" );
if (timeout && (timeout->tv_sec || timeout->tv_usec)) FIXME( "ignoring timeout\n" ); + + if (DsGetDcNameW( NULL, ld->ld_host, NULL, NULL, DS_RETURN_DNS_NAME, &dcinfo ) == ERROR_SUCCESS) + { + WCHAR *dc_name; + TRACE( "ld_host %s resolved to DC %s\n", debugstr_w( ld->ld_host ), debugstr_w( dcinfo->DomainControllerName ) ); + dc_name = dcinfo->DomainControllerName + 2; + ldap_set_optionW( ld, WLDAP32_LDAP_OPT_HOST_NAME, &dc_name ); + NetApiBufferFree( dcinfo ); + } + if ((ret = ldap_connect( CTX(ld) ))) return map_error( ret );
if (server_cert_callback) @@ -316,15 +335,20 @@ LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber ) { LDAP *ld = NULL; char *hostnameU, *url = NULL; + WCHAR *hostnameW;
TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
- if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit; if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit;
ld = create_context( url ); - exit: + if (ld) + ld->ld_host = hostnameW; + else + free( hostnameW ); free( hostnameU ); free( url ); return ld; @@ -355,15 +379,20 @@ LDAP * CDECL ldap_openW( WCHAR *hostname, ULONG portnumber ) { LDAP *ld = NULL; char *hostnameU, *url = NULL; + WCHAR *hostnameW;
TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
- if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit; if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit;
ld = create_context( url ); - exit: + if (ld) + ld->ld_host = hostnameW; + else + free( hostnameW ); free( hostnameU ); free( url ); return ld; @@ -394,10 +423,12 @@ LDAP * CDECL ldap_sslinitW( WCHAR *hostname, ULONG portnumber, int secure ) { LDAP *ld = NULL; char *hostnameU, *url = NULL; + WCHAR *hostnameW;
TRACE( "(%s, %lu, %d)\n", debugstr_w(hostname), portnumber, secure );
- if (!(hostnameU = strWtoU( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit;
if (secure) url = urlify_hostnames( "ldaps://", hostnameU, portnumber ); @@ -406,8 +437,11 @@ LDAP * CDECL ldap_sslinitW( WCHAR *hostname, ULONG portnumber, int secure ) if (!url) goto exit;
ld = create_context( url ); - exit: + if (ld) + ld->ld_host = hostnameW; + else + free( hostnameW ); free( hostnameU ); free( url ); return ld; diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h index d75ba425774..da1824f3749 100644 --- a/dlls/wldap32/winldap_private.h +++ b/dlls/wldap32/winldap_private.h @@ -206,7 +206,7 @@ struct ld_sb typedef struct ldap { struct ld_sb ld_sb; - char *ld_host; + WCHAR *ld_host; ULONG ld_version; UCHAR ld_lberoptions; ULONG ld_deref;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/wldap32/init.c | 50 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/dlls/wldap32/init.c b/dlls/wldap32/init.c index dcd20fea999..472bf2ffdbf 100644 --- a/dlls/wldap32/init.c +++ b/dlls/wldap32/init.c @@ -334,15 +334,17 @@ LDAP * CDECL ldap_initA( const PCHAR hostname, ULONG portnumber ) LDAP * CDECL ldap_initW( const PWCHAR hostname, ULONG portnumber ) { LDAP *ld = NULL; - char *hostnameU, *url = NULL; - WCHAR *hostnameW; + char *hostnameU = NULL, *url = NULL; + WCHAR *hostnameW = NULL;
TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
- if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; - if (!(hostnameU = strWtoU( hostnameW ))) goto exit; - if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit; - + if (hostname) + { + if (!(hostnameW = wcsdup( hostname ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit; + if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit; + } ld = create_context( url ); exit: if (ld) @@ -378,15 +380,17 @@ LDAP * CDECL ldap_openA( char *hostname, ULONG portnumber ) LDAP * CDECL ldap_openW( WCHAR *hostname, ULONG portnumber ) { LDAP *ld = NULL; - char *hostnameU, *url = NULL; - WCHAR *hostnameW; + char *hostnameU = NULL, *url = NULL; + WCHAR *hostnameW = NULL;
TRACE( "(%s, %lu)\n", debugstr_w(hostname), portnumber );
- if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; - if (!(hostnameU = strWtoU( hostnameW ))) goto exit; - if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit; - + if (hostname) + { + if (!(hostnameW = wcsdup( hostname ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit; + if (!(url = urlify_hostnames( "ldap://", hostnameU, portnumber ))) goto exit; + } ld = create_context( url ); exit: if (ld) @@ -422,20 +426,22 @@ LDAP * CDECL ldap_sslinitA( char *hostname, ULONG portnumber, int secure ) LDAP * CDECL ldap_sslinitW( WCHAR *hostname, ULONG portnumber, int secure ) { LDAP *ld = NULL; - char *hostnameU, *url = NULL; - WCHAR *hostnameW; + char *hostnameU = NULL, *url = NULL; + WCHAR *hostnameW = NULL;
TRACE( "(%s, %lu, %d)\n", debugstr_w(hostname), portnumber, secure );
- if (!(hostnameW = wcsdup( hostname ? hostname : L"localhost" ))) return NULL; - if (!(hostnameU = strWtoU( hostnameW ))) goto exit; - - if (secure) - url = urlify_hostnames( "ldaps://", hostnameU, portnumber ); - else - url = urlify_hostnames( "ldap://", hostnameU, portnumber ); - if (!url) goto exit; + if (hostname) + { + if (!(hostnameW = wcsdup( hostname ))) return NULL; + if (!(hostnameU = strWtoU( hostnameW ))) goto exit;
+ if (secure) + url = urlify_hostnames( "ldaps://", hostnameU, portnumber ); + else + url = urlify_hostnames( "ldap://", hostnameU, portnumber ); + if (!url) goto exit; + } ld = create_context( url ); exit: if (ld)
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/wldap32/tests/Makefile.in | 2 +- dlls/wldap32/tests/parse.c | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/dlls/wldap32/tests/Makefile.in b/dlls/wldap32/tests/Makefile.in index b387ec95a71..10488eedbe3 100644 --- a/dlls/wldap32/tests/Makefile.in +++ b/dlls/wldap32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = wldap32.dll -IMPORTS = crypt32 wldap32 +IMPORTS = crypt32 wldap32 netapi32
SOURCES = \ ber.c \ diff --git a/dlls/wldap32/tests/parse.c b/dlls/wldap32/tests/parse.c index faf49622586..760bf0ce703 100644 --- a/dlls/wldap32/tests/parse.c +++ b/dlls/wldap32/tests/parse.c @@ -25,6 +25,9 @@ #include <winbase.h> #include <winldap.h> #include <winber.h> +#include <dsgetdc.h> +#include <lmcons.h> +#include <lmapibuf.h>
#include "wine/test.h"
@@ -671,10 +674,63 @@ static void test_ldap_host_name(void) ldap_unbind( ld ); }
+static void test_ldap_search_dc(void) +{ + DOMAIN_CONTROLLER_INFOW *info; + char *attrs[] = { (char *)"defaultNamingContext", NULL }; + LDAP *ld; + int version; + LDAPMessage *res, *entry; + char **values; + ULONG ret; + + ret = DsGetDcNameW( NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &info ); + if (ret != ERROR_SUCCESS) + { + skip( "Computer is not part of an Active Directory Domain\n" ); + return; + } + trace( "Computer is part of domain %s\n", wine_dbgstr_w(info->DomainName) ); + NetApiBufferFree( info ); + + ld = ldap_initA( NULL, 389 ); + ok( ld != NULL, "ldap_init failed\n" ); + + version = LDAP_VERSION3; + ret = ldap_set_optionW( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + if (ret == LDAP_SERVER_DOWN || ret == LDAP_UNAVAILABLE) + { + skip( "test server can't be reached\n" ); + ldap_unbind( ld ); + return; + } + + ret = ldap_search_sA( ld, NULL, LDAP_SCOPE_BASE, (char *)"(objectclass=*)", attrs, FALSE, &res ); + ok( !ret, "ldap_search_s error %#lx\n", ret ); + if (ret) + { + ldap_unbind( ld ); + return; + } + + entry = ldap_first_entry( ld, res ); + ok( entry != NULL, "expected entry != NULL\n" ); + + values = ldap_get_valuesA( ld, entry, attrs[0] ); + ok( entry != NULL, "expected values != NULL\n" ); + trace( "%s[0]: %s\n", attrs[0], values[0] ); + + ldap_value_freeA( values ); + ldap_msgfree( res ); + + ldap_unbind( ld ); +} + START_TEST (parse) { LDAP *ld;
+ test_ldap_search_dc(); test_ldap_host_name(); test_ldap_paged_search(); test_ldap_server_control();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=151202
Your paranoid android.
=== debian11b (64 bit WoW report) ===
kernel32: comm.c:1586: Test failed: Unexpected time 1001, expected around 500
user32: input.c:4306: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000B500EC, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
On Mon Feb 3 12:47:10 2025 +0000, Dmitry Timoshkov wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/7235/diffs?diff_id=155290&start_sha=797526f13d5f22f3040e84f3d28872e701cdf986#46468ae2cee87ce5aee89486923af6464ee698bd_4_3)
Agreed.
On Mon Feb 3 12:47:10 2025 +0000, Dmitry Timoshkov wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/7235/diffs?diff_id=155290&start_sha=797526f13d5f22f3040e84f3d28872e701cdf986#d1017f0b96365081c2df7bb36d4fabf11299eff6_244_246)
Added the checks.
This merge request was approved by Hans Leidekker.