Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- 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 {