option.c 21.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * WLDAP32 - LDAP support for Wine
 *
 * Copyright 2005 Hans Leidekker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23 24 25
 */

#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"

26
#include "wine/debug.h"
27
#include "winldap_private.h"
28 29 30

WINE_DEFAULT_DEBUG_CHANNEL(wldap32);

31 32 33
/***********************************************************************
 *      ldap_get_optionA     (WLDAP32.@)
 */
34
ULONG CDECL ldap_get_optionA( LDAP *ld, int option, void *value )
35
{
36
    ULONG ret;
37 38 39

    TRACE( "(%p, 0x%08x, %p)\n", ld, option, value );

40
    if (!ld || !value) return WLDAP32_LDAP_PARAM_ERROR;
41 42 43

    switch (option)
    {
44
    case WLDAP32_LDAP_OPT_API_FEATURE_INFO:
45 46 47 48
    {
        LDAPAPIFeatureInfoW featureW;
        LDAPAPIFeatureInfoA *featureA = value;

49
        if (!featureA->ldapaif_name) return WLDAP32_LDAP_PARAM_ERROR;
50 51

        featureW.ldapaif_info_version = featureA->ldapaif_info_version;
52
        if (!(featureW.ldapaif_name = strAtoW( featureA->ldapaif_name ))) return WLDAP32_LDAP_NO_MEMORY;
53 54 55 56
        featureW.ldapaif_version = 0;

        ret = ldap_get_optionW( ld, option, &featureW );

57
        if (ret == WLDAP32_LDAP_SUCCESS) featureA->ldapaif_version = featureW.ldapaif_version;
58
        free( featureW.ldapaif_name );
59 60
        return ret;
    }
61
    case WLDAP32_LDAP_OPT_API_INFO:
62 63 64 65 66 67 68
    {
        LDAPAPIInfoW infoW;
        LDAPAPIInfoA *infoA = value;

        infoW.ldapai_info_version = infoA->ldapai_info_version;

        ret = ldap_get_optionW( ld, option, &infoW );
69 70 71 72
        if (ret != WLDAP32_LDAP_SUCCESS) return ret;

        infoA->ldapai_extensions = strarrayWtoA( infoW.ldapai_extensions );
        if (infoW.ldapai_extensions && !infoA->ldapai_extensions)
73
        {
74 75 76
            strarrayfreeW( infoW.ldapai_extensions );
            free( infoW.ldapai_vendor_name );
            return WLDAP32_LDAP_NO_MEMORY;
77
        }
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

        infoA->ldapai_vendor_name = strWtoA( infoW.ldapai_vendor_name );
        if (infoW.ldapai_vendor_name && !infoA->ldapai_vendor_name)
        {
            strarrayfreeW( infoW.ldapai_extensions );
            free( infoW.ldapai_vendor_name );
            strarrayfreeA( infoA->ldapai_extensions );
            return WLDAP32_LDAP_NO_MEMORY;
        }

        infoA->ldapai_api_version = infoW.ldapai_api_version;
        infoA->ldapai_protocol_version = infoW.ldapai_protocol_version;
        infoA->ldapai_vendor_version = infoW.ldapai_vendor_version;

        return WLDAP32_LDAP_SUCCESS;
93 94
    }

95
    case WLDAP32_LDAP_OPT_AUTO_RECONNECT:
96 97 98 99 100 101 102
    case WLDAP32_LDAP_OPT_DEREF:
    case WLDAP32_LDAP_OPT_DESC:
    case WLDAP32_LDAP_OPT_ERROR_NUMBER:
    case WLDAP32_LDAP_OPT_PROTOCOL_VERSION:
    case WLDAP32_LDAP_OPT_REFERRALS:
    case WLDAP32_LDAP_OPT_SIZELIMIT:
    case WLDAP32_LDAP_OPT_TIMELIMIT:
103 104
        return ldap_get_optionW( ld, option, value );

105 106 107
    case WLDAP32_LDAP_OPT_REFERRAL_HOP_LIMIT:
        return ldap_get_optionW( ld, LDAP_OPT_REFHOPLIMIT, value );

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    case WLDAP32_LDAP_OPT_HOST_NAME:
    {
        WCHAR *hostW;
        char *host;

        ret = ldap_get_optionW( ld, option, &hostW );
        if (!ret)
        {
            host = strWtoA( hostW );
            if (!host)
                ret = WLDAP32_LDAP_NO_MEMORY;
            else
                *(char **)value = host;
            free( hostW );
        }
        return map_error( ret );
    }

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    case WLDAP32_LDAP_OPT_CACHE_ENABLE:
    case WLDAP32_LDAP_OPT_CACHE_FN_PTRS:
    case WLDAP32_LDAP_OPT_CACHE_STRATEGY:
    case WLDAP32_LDAP_OPT_IO_FN_PTRS:
    case WLDAP32_LDAP_OPT_REBIND_ARG:
    case WLDAP32_LDAP_OPT_REBIND_FN:
    case WLDAP32_LDAP_OPT_RESTART:
    case WLDAP32_LDAP_OPT_THREAD_FN_PTRS:
        return WLDAP32_LDAP_LOCAL_ERROR;

    case WLDAP32_LDAP_OPT_AREC_EXCLUSIVE:
    case WLDAP32_LDAP_OPT_CLIENT_CERTIFICATE:
    case WLDAP32_LDAP_OPT_DNSDOMAIN_NAME:
    case WLDAP32_LDAP_OPT_ENCRYPT:
    case WLDAP32_LDAP_OPT_ERROR_STRING:
    case WLDAP32_LDAP_OPT_FAST_CONCURRENT_BIND:
    case WLDAP32_LDAP_OPT_GETDSNAME_FLAGS:
    case WLDAP32_LDAP_OPT_HOST_REACHABLE:
    case WLDAP32_LDAP_OPT_PING_KEEP_ALIVE:
    case WLDAP32_LDAP_OPT_PING_LIMIT:
    case WLDAP32_LDAP_OPT_PING_WAIT_TIME:
    case WLDAP32_LDAP_OPT_PROMPT_CREDENTIALS:
    case WLDAP32_LDAP_OPT_REF_DEREF_CONN_PER_MSG:
    case WLDAP32_LDAP_OPT_REFERRAL_CALLBACK:
    case WLDAP32_LDAP_OPT_ROOTDSE_CACHE:
    case WLDAP32_LDAP_OPT_SASL_METHOD:
    case WLDAP32_LDAP_OPT_SECURITY_CONTEXT:
    case WLDAP32_LDAP_OPT_SEND_TIMEOUT:
    case WLDAP32_LDAP_OPT_SERVER_CERTIFICATE:
    case WLDAP32_LDAP_OPT_SERVER_CONTROLS:
    case WLDAP32_LDAP_OPT_SERVER_ERROR:
    case WLDAP32_LDAP_OPT_SERVER_EXT_ERROR:
    case WLDAP32_LDAP_OPT_SIGN:
    case WLDAP32_LDAP_OPT_SSL:
    case WLDAP32_LDAP_OPT_SSL_INFO:
    case WLDAP32_LDAP_OPT_SSPI_FLAGS:
    case WLDAP32_LDAP_OPT_TCP_KEEPALIVE:
163
        FIXME( "Unsupported option: 0x%02x\n", option );
164
        return WLDAP32_LDAP_NOT_SUPPORTED;
165 166 167

    default:
        FIXME( "Unknown option: 0x%02x\n", option );
168
        return WLDAP32_LDAP_LOCAL_ERROR;
169 170 171
    }
}

172 173 174
/***********************************************************************
 *      ldap_get_optionW     (WLDAP32.@)
 */
175
ULONG CDECL ldap_get_optionW( LDAP *ld, int option, void *value )
176
{
177
    ULONG ret;
178 179 180

    TRACE( "(%p, 0x%08x, %p)\n", ld, option, value );

181
    if (!ld || !value) return WLDAP32_LDAP_PARAM_ERROR;
182 183 184

    switch (option)
    {
185
    case WLDAP32_LDAP_OPT_API_FEATURE_INFO:
186
    {
187
        LDAPAPIFeatureInfo featureU;
188 189
        LDAPAPIFeatureInfoW *featureW = value;

190
        if (!featureW->ldapaif_name) return WLDAP32_LDAP_PARAM_ERROR;
191 192

        featureU.ldapaif_info_version = featureW->ldapaif_info_version;
193 194 195
        if ((featureU.ldapaif_name = strWtoU( featureW->ldapaif_name )))
        {
            featureU.ldapaif_version = 0;
196
            ret = map_error( ldap_get_option( CTX(ld), option, &featureU ) );
197
        }
198
        else return WLDAP32_LDAP_NO_MEMORY;
199

200
        if (ret == WLDAP32_LDAP_SUCCESS) featureW->ldapaif_version = featureU.ldapaif_version;
201
        free( featureU.ldapaif_name );
202 203
        return ret;
    }
204
    case WLDAP32_LDAP_OPT_API_INFO:
205
    {
206
        LDAPAPIInfo infoU;
207 208 209 210
        LDAPAPIInfoW *infoW = value;

        infoU.ldapai_info_version = infoW->ldapai_info_version;

211 212 213 214 215
        ret = ldap_get_option( CTX(ld), option, &infoU );
        if (ret != LDAP_SUCCESS) return map_error( ret );

        infoW->ldapai_extensions = strarrayUtoW( infoU.ldapai_extensions );
        if (infoU.ldapai_extensions && !infoW->ldapai_extensions)
216
        {
217 218 219 220
            ret = WLDAP32_LDAP_NO_MEMORY;
            strarrayfreeU( infoU.ldapai_extensions );
            free( infoU.ldapai_vendor_name );
            return WLDAP32_LDAP_NO_MEMORY;
221
        }
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

        infoW->ldapai_vendor_name = strUtoW( infoU.ldapai_vendor_name );
        if (infoU.ldapai_vendor_name && !infoW->ldapai_vendor_name)
        {
            strarrayfreeU( infoU.ldapai_extensions );
            free( infoU.ldapai_vendor_name );
            strarrayfreeW( infoW->ldapai_extensions );
            return WLDAP32_LDAP_NO_MEMORY;
        }

        infoW->ldapai_api_version = infoU.ldapai_api_version;
        infoW->ldapai_protocol_version = infoU.ldapai_protocol_version;
        infoW->ldapai_vendor_version = infoU.ldapai_vendor_version;

        return WLDAP32_LDAP_SUCCESS;
237
    }
238 239 240 241 242 243 244
    case WLDAP32_LDAP_OPT_AUTO_RECONNECT:
    {
        BOOL *on = value;
        ret = map_error( ldap_get_option( CTX(ld), LDAP_OPT_RESTART, value ) );
        if (!ret) *on = !!*on;
        return ret;
    }
245

246 247 248 249 250 251 252
    case WLDAP32_LDAP_OPT_DEREF:
    case WLDAP32_LDAP_OPT_DESC:
    case WLDAP32_LDAP_OPT_ERROR_NUMBER:
    case WLDAP32_LDAP_OPT_PROTOCOL_VERSION:
    case WLDAP32_LDAP_OPT_REFERRALS:
    case WLDAP32_LDAP_OPT_SIZELIMIT:
    case WLDAP32_LDAP_OPT_TIMELIMIT:
253
        return map_error( ldap_get_option( CTX(ld), option, value ) );
254

255 256 257
    case WLDAP32_LDAP_OPT_REFERRAL_HOP_LIMIT:
        return map_error( ldap_get_option( CTX(ld), LDAP_OPT_REFHOPLIMIT, value ) );

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    case WLDAP32_LDAP_OPT_HOST_NAME:
    {
        WCHAR *hostW;
        char *host;

        ret = ldap_get_option( CTX(ld), LDAP_OPT_HOST_NAME, &host );
        if (!ret)
        {
            hostW = strUtoW( host );
            if (!hostW)
                ret = WLDAP32_LDAP_NO_MEMORY;
            else
                *(WCHAR **)value = hostW;
            free( host );
        }
        return map_error( ret );
    }

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    case WLDAP32_LDAP_OPT_CACHE_ENABLE:
    case WLDAP32_LDAP_OPT_CACHE_FN_PTRS:
    case WLDAP32_LDAP_OPT_CACHE_STRATEGY:
    case WLDAP32_LDAP_OPT_IO_FN_PTRS:
    case WLDAP32_LDAP_OPT_REBIND_ARG:
    case WLDAP32_LDAP_OPT_REBIND_FN:
    case WLDAP32_LDAP_OPT_RESTART:
    case WLDAP32_LDAP_OPT_THREAD_FN_PTRS:
        return WLDAP32_LDAP_LOCAL_ERROR;

    case WLDAP32_LDAP_OPT_AREC_EXCLUSIVE:
    case WLDAP32_LDAP_OPT_CLIENT_CERTIFICATE:
    case WLDAP32_LDAP_OPT_DNSDOMAIN_NAME:
    case WLDAP32_LDAP_OPT_ENCRYPT:
    case WLDAP32_LDAP_OPT_ERROR_STRING:
    case WLDAP32_LDAP_OPT_FAST_CONCURRENT_BIND:
    case WLDAP32_LDAP_OPT_GETDSNAME_FLAGS:
    case WLDAP32_LDAP_OPT_HOST_REACHABLE:
    case WLDAP32_LDAP_OPT_PING_KEEP_ALIVE:
    case WLDAP32_LDAP_OPT_PING_LIMIT:
    case WLDAP32_LDAP_OPT_PING_WAIT_TIME:
    case WLDAP32_LDAP_OPT_PROMPT_CREDENTIALS:
    case WLDAP32_LDAP_OPT_REF_DEREF_CONN_PER_MSG:
    case WLDAP32_LDAP_OPT_REFERRAL_CALLBACK:
    case WLDAP32_LDAP_OPT_ROOTDSE_CACHE:
    case WLDAP32_LDAP_OPT_SASL_METHOD:
    case WLDAP32_LDAP_OPT_SECURITY_CONTEXT:
    case WLDAP32_LDAP_OPT_SEND_TIMEOUT:
    case WLDAP32_LDAP_OPT_SERVER_CERTIFICATE:
    case WLDAP32_LDAP_OPT_SERVER_CONTROLS:
    case WLDAP32_LDAP_OPT_SERVER_ERROR:
    case WLDAP32_LDAP_OPT_SERVER_EXT_ERROR:
    case WLDAP32_LDAP_OPT_SIGN:
    case WLDAP32_LDAP_OPT_SSL:
    case WLDAP32_LDAP_OPT_SSL_INFO:
    case WLDAP32_LDAP_OPT_SSPI_FLAGS:
    case WLDAP32_LDAP_OPT_TCP_KEEPALIVE:
313
        FIXME( "Unsupported option: 0x%02x\n", option );
314
        return WLDAP32_LDAP_NOT_SUPPORTED;
315 316 317

    default:
        FIXME( "Unknown option: 0x%02x\n", option );
318
        return WLDAP32_LDAP_LOCAL_ERROR;
319 320 321
    }
}

322 323 324
/***********************************************************************
 *      ldap_set_optionA     (WLDAP32.@)
 */
325
ULONG CDECL ldap_set_optionA( LDAP *ld, int option, void *value )
326
{
327
    ULONG ret;
328 329 330

    TRACE( "(%p, 0x%08x, %p)\n", ld, option, value );

331
    if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
332 333 334

    switch (option)
    {
335
    case WLDAP32_LDAP_OPT_SERVER_CONTROLS:
336 337
    {
        LDAPControlW **ctrlsW;
338
        if (!(ctrlsW = controlarrayAtoW( value ))) return WLDAP32_LDAP_NO_MEMORY;
339 340 341 342
        ret = ldap_set_optionW( ld, option, ctrlsW );
        controlarrayfreeW( ctrlsW );
        return ret;
    }
343
    case WLDAP32_LDAP_OPT_AUTO_RECONNECT:
344
    case WLDAP32_LDAP_OPT_CLIENT_CERTIFICATE:
345 346
    case WLDAP32_LDAP_OPT_DEREF:
    case WLDAP32_LDAP_OPT_DESC:
347
    case WLDAP32_LDAP_OPT_ENCRYPT:
348 349 350
    case WLDAP32_LDAP_OPT_ERROR_NUMBER:
    case WLDAP32_LDAP_OPT_PROTOCOL_VERSION:
    case WLDAP32_LDAP_OPT_REFERRALS:
351
    case WLDAP32_LDAP_OPT_REFERRAL_HOP_LIMIT:
352
    case WLDAP32_LDAP_OPT_ROOTDSE_CACHE:
353
    case WLDAP32_LDAP_OPT_SERVER_CERTIFICATE:
354
    case WLDAP32_LDAP_OPT_SIGN:
355
    case WLDAP32_LDAP_OPT_SIZELIMIT:
356
    case WLDAP32_LDAP_OPT_SSL:
357
    case WLDAP32_LDAP_OPT_TIMELIMIT:
358 359
        return ldap_set_optionW( ld, option, value );

360 361 362 363 364 365 366 367 368 369 370 371 372
    case WLDAP32_LDAP_OPT_HOST_NAME:
    {
        char **host = value;
        WCHAR *hostW;

        hostW = strAtoW( *host );
        if (!hostW) return WLDAP32_LDAP_NO_MEMORY;

        ret = ldap_set_optionW( ld, option, &hostW );
        free( hostW );
        return map_error( ret );
    }

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    case WLDAP32_LDAP_OPT_CACHE_ENABLE:
    case WLDAP32_LDAP_OPT_CACHE_FN_PTRS:
    case WLDAP32_LDAP_OPT_CACHE_STRATEGY:
    case WLDAP32_LDAP_OPT_IO_FN_PTRS:
    case WLDAP32_LDAP_OPT_REBIND_ARG:
    case WLDAP32_LDAP_OPT_REBIND_FN:
    case WLDAP32_LDAP_OPT_RESTART:
    case WLDAP32_LDAP_OPT_THREAD_FN_PTRS:
        return WLDAP32_LDAP_LOCAL_ERROR;

    case WLDAP32_LDAP_OPT_API_FEATURE_INFO:
    case WLDAP32_LDAP_OPT_API_INFO:
        return WLDAP32_LDAP_UNWILLING_TO_PERFORM;

    case WLDAP32_LDAP_OPT_AREC_EXCLUSIVE:
    case WLDAP32_LDAP_OPT_DNSDOMAIN_NAME:
    case WLDAP32_LDAP_OPT_ERROR_STRING:
    case WLDAP32_LDAP_OPT_FAST_CONCURRENT_BIND:
    case WLDAP32_LDAP_OPT_GETDSNAME_FLAGS:
    case WLDAP32_LDAP_OPT_HOST_REACHABLE:
    case WLDAP32_LDAP_OPT_PING_KEEP_ALIVE:
    case WLDAP32_LDAP_OPT_PING_LIMIT:
    case WLDAP32_LDAP_OPT_PING_WAIT_TIME:
    case WLDAP32_LDAP_OPT_PROMPT_CREDENTIALS:
    case WLDAP32_LDAP_OPT_REF_DEREF_CONN_PER_MSG:
    case WLDAP32_LDAP_OPT_REFERRAL_CALLBACK:
    case WLDAP32_LDAP_OPT_SASL_METHOD:
    case WLDAP32_LDAP_OPT_SECURITY_CONTEXT:
    case WLDAP32_LDAP_OPT_SEND_TIMEOUT:
    case WLDAP32_LDAP_OPT_SERVER_ERROR:
    case WLDAP32_LDAP_OPT_SERVER_EXT_ERROR:
    case WLDAP32_LDAP_OPT_SSL_INFO:
    case WLDAP32_LDAP_OPT_SSPI_FLAGS:
    case WLDAP32_LDAP_OPT_TCP_KEEPALIVE:
407
        FIXME( "Unsupported option: 0x%02x\n", option );
408
        return WLDAP32_LDAP_NOT_SUPPORTED;
409 410 411

    default:
        FIXME( "Unknown option: 0x%02x\n", option );
412
        return WLDAP32_LDAP_LOCAL_ERROR;
413 414 415
    }
}

416
static BOOL query_supported_server_ctrls( LDAP *ld )
417 418
{
    char *attrs[] = { (char *)"supportedControl", NULL };
419 420
    LDAPMessage *res, *entry;
    struct berval **ctrls = SERVER_CTRLS(ld);
421
    ULONG ret;
422

423
    if (ctrls) return TRUE;
424

425 426
    ret = map_error( ldap_search_ext_s( CTX(ld), (char *)"", WLDAP32_LDAP_SCOPE_BASE, (char *)"(objectClass=*)",
                                        attrs, FALSE, NULL, NULL, NULL, 0, &res ) );
427
    if (ret == WLDAP32_LDAP_SUCCESS)
428
    {
429
        if ((entry = ldap_first_entry( CTX(ld), res )))
430 431
        {
            ULONG count, i;
432 433
            ctrls = ldap_get_values_len( CTX(ld), entry, attrs[0] );
            count = ldap_count_values_len( ctrls );
434
            for (i = 0; i < count; i++) TRACE( "%lu: %s\n", i, debugstr_an( ctrls[i]->bv_val, ctrls[i]->bv_len ) );
435
            *(struct berval ***)&SERVER_CTRLS(ld) = ctrls;
436
        }
437
    }
438
    else return FALSE;
439

440
    ldap_msgfree( res );
441
    return ctrls != NULL;
442 443
}

444
static BOOL is_supported_server_ctrls( LDAP *ld, LDAPControl **ctrls )
445 446 447 448 449 450 451
{
    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 );
452
    server_count = ldap_count_values_len( SERVER_CTRLS(ld) );
453 454 455

    for (n = 0; n < user_count; n++)
    {
456 457
        TRACE("looking for %s\n", debugstr_a(ctrls[n]->ldctl_oid));

458 459
        for (i = 0; i < server_count; i++)
        {
460
            struct berval **server_ctrls = SERVER_CTRLS(ld);
461
            if (!strncmp( ctrls[n]->ldctl_oid, server_ctrls[i]->bv_val, server_ctrls[i]->bv_len))
462
            {
463
                supported++;
464 465
                break;
            }
466 467 468 469 470 471
        }
    }

    return supported == user_count;
}

472 473
/***********************************************************************
 *      ldap_set_optionW     (WLDAP32.@)
474
 */
475
ULONG CDECL ldap_set_optionW( LDAP *ld, int option, void *value )
476
{
477
    ULONG ret;
478 479 480

    TRACE( "(%p, 0x%08x, %p)\n", ld, option, value );

481
    if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
482 483 484

    switch (option)
    {
485
    case WLDAP32_LDAP_OPT_SERVER_CONTROLS:
486
    {
487
        LDAPControl **ctrlsU;
488

489
        if (!(ctrlsU = controlarrayWtoU( value ))) return WLDAP32_LDAP_NO_MEMORY;
490

491
        if (!is_supported_server_ctrls( ld, ctrlsU ))
492
            ret = WLDAP32_LDAP_PARAM_ERROR;
493
        else
494 495
            ret = map_error( ldap_set_option( CTX(ld), option, ctrlsU ) );

496 497 498
        controlarrayfreeU( ctrlsU );
        return ret;
    }
499
    case WLDAP32_LDAP_OPT_REFERRALS:
500
    {
501 502 503 504 505 506 507
        if (value == WLDAP32_LDAP_OPT_ON)
            value = LDAP_OPT_ON;
        else if (value == WLDAP32_LDAP_OPT_OFF)
            value = LDAP_OPT_OFF;
        else if (value == (void *)LDAP_CHASE_SUBORDINATE_REFERRALS ||
                 value == (void *)LDAP_CHASE_EXTERNAL_REFERRALS ||
                 value == (void *)(LDAP_CHASE_SUBORDINATE_REFERRALS|LDAP_CHASE_EXTERNAL_REFERRALS))
508 509 510 511
        {
            FIXME( "upgrading referral value %p to LDAP_OPT_ON (OpenLDAP lacks sufficient granularity)\n", value );
            value = LDAP_OPT_ON;
        }
512 513 514 515 516 517 518 519 520 521 522 523 524 525
        else if (*(ULONG *)value == 1)
            value = LDAP_OPT_ON;
        else if (*(ULONG *)value == 0)
            value = LDAP_OPT_OFF;
        else if (*(ULONG *)value == LDAP_CHASE_SUBORDINATE_REFERRALS ||
                 *(ULONG *)value == LDAP_CHASE_EXTERNAL_REFERRALS ||
                 *(ULONG *)value == (LDAP_CHASE_SUBORDINATE_REFERRALS|LDAP_CHASE_EXTERNAL_REFERRALS))
        {
            FIXME( "upgrading referral value 0x%lx to LDAP_OPT_ON (OpenLDAP lacks sufficient granularity)\n", *(ULONG *)value );
            value = LDAP_OPT_ON;
        }
        else
            return WLDAP32_LDAP_PARAM_ERROR;

526
        return map_error( ldap_set_option( CTX(ld), option, value ) );
527
    }
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
    case WLDAP32_LDAP_OPT_AUTO_RECONNECT:
    {
        if (value == WLDAP32_LDAP_OPT_ON)
            value = LDAP_OPT_ON;
        else if (value == WLDAP32_LDAP_OPT_OFF)
            value = LDAP_OPT_OFF;
        else if (*(ULONG *)value == 1)
            value = LDAP_OPT_ON;
        else if (*(ULONG *)value == 0)
            value = LDAP_OPT_OFF;
        else
            return WLDAP32_LDAP_PARAM_ERROR;

        return map_error( ldap_set_option( CTX(ld), LDAP_OPT_RESTART, value ) );
    }

544 545 546 547
    case WLDAP32_LDAP_OPT_CLIENT_CERTIFICATE:
        CLIENT_CERT_CALLBACK(ld) = value;
        return WLDAP32_LDAP_SUCCESS;

548
    case WLDAP32_LDAP_OPT_REFERRAL_HOP_LIMIT:
549
        return map_error( ldap_set_option( CTX(ld), LDAP_OPT_REFHOPLIMIT, value ) );
550

551
    case WLDAP32_LDAP_OPT_SERVER_CERTIFICATE:
552
        SERVER_CERT_CALLBACK(ld) = value;
553 554
        return WLDAP32_LDAP_SUCCESS;

555 556 557 558 559 560
    case WLDAP32_LDAP_OPT_DEREF:
    case WLDAP32_LDAP_OPT_DESC:
    case WLDAP32_LDAP_OPT_ERROR_NUMBER:
    case WLDAP32_LDAP_OPT_PROTOCOL_VERSION:
    case WLDAP32_LDAP_OPT_SIZELIMIT:
    case WLDAP32_LDAP_OPT_TIMELIMIT:
561
        return map_error( ldap_set_option( CTX(ld), option, value ) );
562

563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    case WLDAP32_LDAP_OPT_SSL:
    {
        BOOL turn_on;
        char *uri, *new_uri;

        if (value == WLDAP32_LDAP_OPT_ON)
            turn_on = TRUE;
        else if (value == WLDAP32_LDAP_OPT_OFF)
            turn_on = FALSE;
        else if (*(ULONG *)value == 1)
            turn_on = TRUE;
        else if (*(ULONG *)value == 0)
            turn_on = FALSE;
        else
            return WLDAP32_LDAP_PARAM_ERROR;

        ret = ldap_get_option( CTX(ld), LDAP_OPT_URI, &uri );
        if (ret != LDAP_SUCCESS) return map_error( ret );

        if (turn_on)
            new_uri = strreplace( uri, "ldap://", "ldaps://" );
        else
            new_uri = strreplace( uri, "ldaps://", "ldap://" );

        ret = map_error( ldap_set_option( CTX(ld), LDAP_OPT_URI, new_uri ) );
        ldap_memfree(uri);
        free(new_uri);
        return ret;
    }

593 594 595 596 597 598 599 600 601 602 603 604 605
    case WLDAP32_LDAP_OPT_HOST_NAME:
    {
        WCHAR **hostW = value;
        char *host;

        host = strWtoU( *hostW );
        if (!host) return WLDAP32_LDAP_NO_MEMORY;

        ret = ldap_set_option( CTX(ld), LDAP_OPT_HOST_NAME, host );
        free( host );
        return map_error( ret );
    }

606 607 608 609 610 611 612 613 614 615 616 617 618 619
    case WLDAP32_LDAP_OPT_CACHE_ENABLE:
    case WLDAP32_LDAP_OPT_CACHE_FN_PTRS:
    case WLDAP32_LDAP_OPT_CACHE_STRATEGY:
    case WLDAP32_LDAP_OPT_IO_FN_PTRS:
    case WLDAP32_LDAP_OPT_REBIND_ARG:
    case WLDAP32_LDAP_OPT_REBIND_FN:
    case WLDAP32_LDAP_OPT_RESTART:
    case WLDAP32_LDAP_OPT_THREAD_FN_PTRS:
        return WLDAP32_LDAP_LOCAL_ERROR;

    case WLDAP32_LDAP_OPT_API_FEATURE_INFO:
    case WLDAP32_LDAP_OPT_API_INFO:
        return WLDAP32_LDAP_UNWILLING_TO_PERFORM;

620 621 622 623 624 625
    case WLDAP32_LDAP_OPT_ENCRYPT:
    case WLDAP32_LDAP_OPT_ROOTDSE_CACHE:
    case WLDAP32_LDAP_OPT_SIGN:
        if (value == WLDAP32_LDAP_OPT_OFF || (value != WLDAP32_LDAP_OPT_ON && *(ULONG *)value == 0))
            return WLDAP32_LDAP_SUCCESS;
        /* fall through */
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
    case WLDAP32_LDAP_OPT_AREC_EXCLUSIVE:
    case WLDAP32_LDAP_OPT_DNSDOMAIN_NAME:
    case WLDAP32_LDAP_OPT_ERROR_STRING:
    case WLDAP32_LDAP_OPT_FAST_CONCURRENT_BIND:
    case WLDAP32_LDAP_OPT_GETDSNAME_FLAGS:
    case WLDAP32_LDAP_OPT_HOST_REACHABLE:
    case WLDAP32_LDAP_OPT_PING_KEEP_ALIVE:
    case WLDAP32_LDAP_OPT_PING_LIMIT:
    case WLDAP32_LDAP_OPT_PING_WAIT_TIME:
    case WLDAP32_LDAP_OPT_PROMPT_CREDENTIALS:
    case WLDAP32_LDAP_OPT_REF_DEREF_CONN_PER_MSG:
    case WLDAP32_LDAP_OPT_REFERRAL_CALLBACK:
    case WLDAP32_LDAP_OPT_SASL_METHOD:
    case WLDAP32_LDAP_OPT_SECURITY_CONTEXT:
    case WLDAP32_LDAP_OPT_SEND_TIMEOUT:
    case WLDAP32_LDAP_OPT_SERVER_ERROR:
    case WLDAP32_LDAP_OPT_SERVER_EXT_ERROR:
    case WLDAP32_LDAP_OPT_SSL_INFO:
    case WLDAP32_LDAP_OPT_SSPI_FLAGS:
    case WLDAP32_LDAP_OPT_TCP_KEEPALIVE:
646
        FIXME( "Unsupported option: 0x%02x\n", option );
647
        return WLDAP32_LDAP_NOT_SUPPORTED;
648 649 650

    default:
        FIXME( "Unknown option: 0x%02x\n", option );
651
        return WLDAP32_LDAP_LOCAL_ERROR;
652 653
    }
}