Dmitry Timoshkov : wldap32: Locally cache "supportedControl" rootDSE attribute, and check it in ldap_set_option(LDAP_OPT_SERVER_CONTROLS).
Alexandre Julliard
julliard at winehq.org
Fri Apr 3 14:55:38 CDT 2020
Module: wine
Branch: master
Commit: 07b18a7672308ddc5124749603ea7f5c8b5ee254
URL: https://source.winehq.org/git/wine.git/?a=commit;h=07b18a7672308ddc5124749603ea7f5c8b5ee254
Author: Dmitry Timoshkov <dmitry at baikal.ru>
Date: Fri Apr 3 16:57:03 2020 +0800
wldap32: Locally cache "supportedControl" rootDSE attribute, and check it in ldap_set_option(LDAP_OPT_SERVER_CONTROLS).
Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/adsldp/tests/ldap.c | 3 ---
dlls/wldap32/bind.c | 4 +++
dlls/wldap32/option.c | 57 +++++++++++++++++++++++++++++++++++++++++-
dlls/wldap32/tests/parse.c | 2 --
dlls/wldap32/winldap_private.h | 1 +
5 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/dlls/adsldp/tests/ldap.c b/dlls/adsldp/tests/ldap.c
index 80815b07a0..208a9fa2fe 100644
--- a/dlls/adsldp/tests/ldap.c
+++ b/dlls/adsldp/tests/ldap.c
@@ -498,15 +498,12 @@ todo_wine
pref[1].vValue.Integer = ADS_SECURITY_INFO_OWNER | ADS_SECURITY_INFO_GROUP | ADS_SECURITY_INFO_DACL;
pref[1].dwStatus = 0xdeadbeef;
hr = IDirectorySearch_SetSearchPreference(ds, pref, ARRAY_SIZE(pref));
-todo_wine
ok(hr == S_ADS_ERRORSOCCURRED, "got %#x\n", hr);
ok(pref[0].dwStatus == ADS_STATUS_S_OK, "got %d\n", pref[0].dwStatus);
/* ldap.forumsys.com doesn't support NT security, real ADs DC - does */
-todo_wine
ok(pref[1].dwStatus == ADS_STATUS_INVALID_SEARCHPREF, "got %d\n", pref[1].dwStatus);
hr = IDirectorySearch_ExecuteSearch(ds, (WCHAR *)L"(objectClass=*)", NULL, ~0, &sh);
-todo_wine
ok(hr == S_OK, "got %#x\n", hr);
if (hr != S_OK) goto fail;
diff --git a/dlls/wldap32/bind.c b/dlls/wldap32/bind.c
index aedda13634..1498dc49fe 100644
--- a/dlls/wldap32/bind.c
+++ b/dlls/wldap32/bind.c
@@ -766,6 +766,8 @@ ULONG CDECL WLDAP32_ldap_unbind( WLDAP32_LDAP *ld )
if (ld)
{
ret = map_error( ldap_unbind_ext( ld->ld, NULL, NULL ));
+ if ( ld->ld_server_ctrls )
+ ldap_value_free_len( ld->ld_server_ctrls );
heap_free( ld );
}
else
@@ -797,6 +799,8 @@ ULONG CDECL WLDAP32_ldap_unbind_s( WLDAP32_LDAP *ld )
if (ld)
{
ret = map_error( ldap_unbind_ext_s( ld->ld, NULL, NULL ));
+ if ( ld->ld_server_ctrls )
+ ldap_value_free_len( ld->ld_server_ctrls );
heap_free( ld );
}
else
diff --git a/dlls/wldap32/option.c b/dlls/wldap32/option.c
index 8a8a86b579..87eb779953 100644
--- a/dlls/wldap32/option.c
+++ b/dlls/wldap32/option.c
@@ -398,6 +398,58 @@ ULONG CDECL ldap_set_optionA( WLDAP32_LDAP *ld, int option, void *value )
return ret;
}
+#ifdef HAVE_LDAP
+
+static BOOL query_supported_server_ctrls( WLDAP32_LDAP *ld )
+{
+ char *attrs[] = { (char *)"supportedControl", NULL };
+ LDAPMessage *res, *entry;
+
+ if ( ld->ld_server_ctrls ) return TRUE;
+
+ if (ldap_search_ext_s( ld->ld, (char *)"", LDAP_SCOPE_BASE, (char *)"(objectClass=*)", attrs, FALSE,
+ NULL, NULL, NULL, 0, &res ) != LDAP_SUCCESS)
+ return FALSE;
+
+ entry = ldap_first_entry( ld->ld, res );
+ if (entry)
+ {
+ ULONG count, i;
+
+ ld->ld_server_ctrls = ldap_get_values_len( ld->ld, entry, attrs[0] );
+ count = ldap_count_values_len( ld->ld_server_ctrls );
+ for (i = 0; i < count; i++)
+ TRACE("%u: %s\n", i, debugstr_an( ld->ld_server_ctrls[i]->bv_val, ld->ld_server_ctrls[i]->bv_len ));
+ }
+
+ ldap_msgfree( res );
+
+ return ld->ld_server_ctrls != NULL;
+}
+
+static BOOL is_supported_server_ctrls( WLDAP32_LDAP *ld, LDAPControl **ctrls )
+{
+ ULONG user_count, server_count, i, n, supported = 0;
+
+ if (!query_supported_server_ctrls( ld ))
+ return TRUE; /* can't verify, let the server handle it on next query */
+
+ user_count = controlarraylenU( ctrls );
+ server_count = ldap_count_values_len( ld->ld_server_ctrls );
+
+ for (n = 0; n < user_count; n++)
+ {
+ for (i = 0; i < server_count; i++)
+ {
+ if (!strncmp( ctrls[n]->ldctl_oid, ld->ld_server_ctrls[i]->bv_val, ld->ld_server_ctrls[i]->bv_len))
+ supported++;
+ }
+ }
+
+ return supported == user_count;
+}
+#endif
+
/***********************************************************************
* ldap_set_optionW (WLDAP32.@)
*
@@ -433,7 +485,10 @@ ULONG CDECL ldap_set_optionW( WLDAP32_LDAP *ld, int option, void *value )
ctrlsU = controlarrayWtoU( value );
if (!ctrlsU) return WLDAP32_LDAP_NO_MEMORY;
- ret = map_error( ldap_set_option( ld->ld, option, ctrlsU ));
+ if (!is_supported_server_ctrls( ld, ctrlsU ))
+ ret = WLDAP32_LDAP_PARAM_ERROR;
+ else
+ ret = map_error( ldap_set_option( ld->ld, option, ctrlsU ));
controlarrayfreeU( ctrlsU );
return ret;
}
diff --git a/dlls/wldap32/tests/parse.c b/dlls/wldap32/tests/parse.c
index c2435809d2..5a49b9c69d 100644
--- a/dlls/wldap32/tests/parse.c
+++ b/dlls/wldap32/tests/parse.c
@@ -201,12 +201,10 @@ static void test_ldap_server_control( void )
ctrls[0] = &mask;
ctrls[1] = NULL;
ret = ldap_set_optionW(ld, LDAP_OPT_SERVER_CONTROLS, ctrls);
-todo_wine
ok( ret == LDAP_PARAM_ERROR, "ldap_set_optionW should fail: 0x%x\n", ret );
res = NULL;
ret = ldap_search_sA( ld, (char *)"OU=scientists,DC=example,DC=com", LDAP_SCOPE_BASE, (char *)"(objectclass=*)", NULL, FALSE, &res );
-todo_wine
ok( !ret, "ldap_search_sA failed 0x%x\n", ret );
ok( res != NULL, "expected res != NULL\n" );
diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h
index 0332deafa2..30c12a909c 100644
--- a/dlls/wldap32/winldap_private.h
+++ b/dlls/wldap32/winldap_private.h
@@ -131,6 +131,7 @@ typedef struct wldap32
ULONG ld_cldaptimeout;
ULONG ld_refhoplimit;
ULONG ld_options;
+ struct berval **ld_server_ctrls;
} WLDAP32_LDAP, *WLDAP32_PLDAP;
typedef struct ldapmodA {
More information about the wine-cvs
mailing list