1 /* 2 * WLDAP32 - LDAP support for Wine 3 * 4 * Copyright 2005 Hans Leidekker 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * 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 #include "config.h" 22 #include "wine/port.h" 23 24 #include <stdarg.h> 25 #include <stdio.h> 26 #ifdef HAVE_LDAP_H 27 #include <ldap.h> 28 #endif 29 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winnls.h" 33 34 #include "winldap_private.h" 35 #include "wldap32.h" 36 #include "wine/debug.h" 37 38 WINE_DEFAULT_DEBUG_CHANNEL(wldap32); 39 40 /*********************************************************************** 41 * ldap_abandon (WLDAP32.@) 42 * 43 * Cancel an asynchronous operation. 44 * 45 * PARAMS 46 * ld [I] Pointer to an LDAP context. 47 * msgid [I] ID of the operation to cancel. 48 * 49 * RETURNS 50 * Success: LDAP_SUCCESS 51 * Failure: An LDAP error code. 52 */ 53 ULONG CDECL WLDAP32_ldap_abandon( WLDAP32_LDAP *ld, ULONG msgid ) 54 { 55 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; 56 #ifdef HAVE_LDAP 57 58 TRACE( "(%p, 0x%08x)\n", ld, msgid ); 59 60 if (!ld) return ~0u; 61 ret = map_error( ldap_abandon_ext( ld, msgid, NULL, NULL )); 62 63 #endif 64 return ret; 65 } 66 67 /*********************************************************************** 68 * ldap_check_filterA (WLDAP32.@) 69 * 70 * See ldap_check_filterW. 71 */ 72 ULONG CDECL ldap_check_filterA( WLDAP32_LDAP *ld, PCHAR filter ) 73 { 74 ULONG ret; 75 WCHAR *filterW = NULL; 76 77 TRACE( "(%p, %s)\n", ld, debugstr_a(filter) ); 78 79 if (!ld) return WLDAP32_LDAP_PARAM_ERROR; 80 81 if (filter) { 82 filterW = strAtoW( filter ); 83 if (!filterW) return WLDAP32_LDAP_NO_MEMORY; 84 } 85 86 ret = ldap_check_filterW( ld, filterW ); 87 88 strfreeW( filterW ); 89 return ret; 90 } 91 92 /*********************************************************************** 93 * ldap_check_filterW (WLDAP32.@) 94 * 95 * Check filter syntax. 96 * 97 * PARAMS 98 * ld [I] Pointer to an LDAP context. 99 * filter [I] Filter string. 100 * 101 * RETURNS 102 * Success: LDAP_SUCCESS 103 * Failure: An LDAP error code. 104 */ 105 ULONG CDECL ldap_check_filterW( WLDAP32_LDAP *ld, PWCHAR filter ) 106 { 107 TRACE( "(%p, %s)\n", ld, debugstr_w(filter) ); 108 109 if (!ld) return WLDAP32_LDAP_PARAM_ERROR; 110 return WLDAP32_LDAP_SUCCESS; /* FIXME: do some checks */ 111 } 112 113 /*********************************************************************** 114 * ldap_cleanup (WLDAP32.@) 115 */ 116 ULONG CDECL ldap_cleanup( HANDLE instance ) 117 { 118 TRACE( "(%p)\n", instance ); 119 return WLDAP32_LDAP_SUCCESS; 120 } 121 122 /*********************************************************************** 123 * ldap_conn_from_msg (WLDAP32.@) 124 * 125 * Get the LDAP context for a given message. 126 * 127 * PARAMS 128 * ld [I] Pointer to an LDAP context. 129 * res [I] LDAP message. 130 * 131 * RETURNS 132 * Success: Pointer to an LDAP context. 133 * Failure: NULL 134 */ 135 WLDAP32_LDAP * CDECL ldap_conn_from_msg( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res ) 136 { 137 TRACE( "(%p, %p)\n", ld, res ); 138 139 if (!ld || !res) return NULL; 140 return ld; /* FIXME: not always correct */ 141 } 142 143 /*********************************************************************** 144 * ldap_count_entries (WLDAP32.@) 145 * 146 * Count the number of entries returned from a search. 147 * 148 * PARAMS 149 * ld [I] Pointer to an LDAP context. 150 * res [I] LDAP message. 151 * 152 * RETURNS 153 * Success: The number of entries. 154 * Failure: ~0u 155 */ 156 ULONG CDECL WLDAP32_ldap_count_entries( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res ) 157 { 158 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; 159 #ifdef HAVE_LDAP 160 161 TRACE( "(%p, %p)\n", ld, res ); 162 163 if (!ld) return ~0u; 164 ret = ldap_count_entries( ld, res ); 165 166 #endif 167 return ret; 168 } 169 170 /*********************************************************************** 171 * ldap_count_references (WLDAP32.@) 172 * 173 * Count the number of references returned from a search. 174 * 175 * PARAMS 176 * ld [I] Pointer to an LDAP context. 177 * res [I] LDAP message. 178 * 179 * RETURNS 180 * Success: The number of references. 181 * Failure: ~0u 182 */ 183 ULONG CDECL WLDAP32_ldap_count_references( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res ) 184 { 185 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; 186 #ifdef HAVE_LDAP_COUNT_REFERENCES 187 188 TRACE( "(%p, %p)\n", ld, res ); 189 190 if (!ld) return 0; 191 ret = ldap_count_references( ld, res ); 192 193 #endif 194 return ret; 195 } 196 197 static ULONG get_escape_size( PCHAR src, ULONG srclen ) 198 { 199 ULONG i, size = 0; 200 201 if (src) 202 { 203 for (i = 0; i < srclen; i++) 204 { 205 if ((src[i] >= '0' && src[i] <= '9') || 206 (src[i] >= 'A' && src[i] <= 'Z') || 207 (src[i] >= 'a' && src[i] <= 'z')) 208 size++; 209 else 210 size += 3; 211 } 212 } 213 return size + 1; 214 } 215 216 static void escape_filter_element( PCHAR src, ULONG srclen, PCHAR dst ) 217 { 218 ULONG i; 219 static const char fmt[] = "\\%02X"; 220 char *d = dst; 221 222 for (i = 0; i < srclen; i++) 223 { 224 if ((src[i] >= '0' && src[i] <= '9') || 225 (src[i] >= 'A' && src[i] <= 'Z') || 226 (src[i] >= 'a' && src[i] <= 'z')) 227 *d++ = src[i]; 228 else 229 d += sprintf( d, fmt, (unsigned char)src[i] ); 230 } 231 *++d = 0; 232 } 233 234 /*********************************************************************** 235 * ldap_escape_filter_elementA (WLDAP32.@) 236 * 237 * See ldap_escape_filter_elementW. 238 */ 239 ULONG CDECL ldap_escape_filter_elementA( PCHAR src, ULONG srclen, PCHAR dst, ULONG dstlen ) 240 { 241 ULONG len; 242 243 TRACE( "(%p, 0x%08x, %p, 0x%08x)\n", src, srclen, dst, dstlen ); 244 245 len = get_escape_size( src, srclen ); 246 if (!dst) return len; 247 248 if (!src || dstlen < len) 249 return WLDAP32_LDAP_PARAM_ERROR; 250 else 251 { 252 escape_filter_element( src, srclen, dst ); 253 return WLDAP32_LDAP_SUCCESS; 254 } 255 } 256 257 /*********************************************************************** 258 * ldap_escape_filter_elementW (WLDAP32.@) 259 * 260 * Escape binary data for safe passing in filters. 261 * 262 * PARAMS 263 * src [I] Filter element to be escaped. 264 * srclen [I] Length in bytes of the filter element. 265 * dst [O] Destination buffer for the escaped filter element. 266 * dstlen [I] Length in bytes of the destination buffer. 267 * 268 * RETURNS 269 * Success: LDAP_SUCCESS 270 * Failure: An LDAP error code. 271 */ 272 ULONG CDECL ldap_escape_filter_elementW( PCHAR src, ULONG srclen, PWCHAR dst, ULONG dstlen ) 273 { 274 ULONG len; 275 276 TRACE( "(%p, 0x%08x, %p, 0x%08x)\n", src, srclen, dst, dstlen ); 277 278 len = get_escape_size( src, srclen ); 279 if (!dst) return len; 280 281 /* no matter what you throw at it, this is what native returns */ 282 return WLDAP32_LDAP_PARAM_ERROR; 283 } 284 285 /*********************************************************************** 286 * ldap_first_attributeA (WLDAP32.@) 287 * 288 * See ldap_first_attributeW. 289 */ 290 PCHAR CDECL ldap_first_attributeA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, 291 WLDAP32_BerElement** ptr ) 292 { 293 PCHAR ret = NULL; 294 #ifdef HAVE_LDAP 295 WCHAR *retW; 296 297 TRACE( "(%p, %p, %p)\n", ld, entry, ptr ); 298 299 if (!ld || !entry) return NULL; 300 retW = ldap_first_attributeW( ld, entry, ptr ); 301 302 ret = strWtoA( retW ); 303 ldap_memfreeW( retW ); 304 305 #endif 306 return ret; 307 } 308 309 /*********************************************************************** 310 * ldap_first_attributeW (WLDAP32.@) 311 * 312 * Get the first attribute for a given entry. 313 * 314 * PARAMS 315 * ld [I] Pointer to an LDAP context. 316 * entry [I] Entry to retrieve attribute for. 317 * ptr [O] Position pointer. 318 * 319 * RETURNS 320 * Success: Name of the first attribute. 321 * Failure: NULL 322 * 323 * NOTES 324 * Use ldap_memfree to free the returned string. 325 */ 326 PWCHAR CDECL ldap_first_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, 327 WLDAP32_BerElement** ptr ) 328 { 329 PWCHAR ret = NULL; 330 #ifdef HAVE_LDAP 331 char *retU; 332 333 TRACE( "(%p, %p, %p)\n", ld, entry, ptr ); 334 335 if (!ld || !entry) return NULL; 336 retU = ldap_first_attribute( ld, entry, ptr ); 337 338 ret = strUtoW( retU ); 339 ldap_memfree( retU ); 340 341 #endif 342 return ret; 343 } 344 345 /*********************************************************************** 346 * ldap_first_entry (WLDAP32.@) 347 * 348 * Get the first entry from a result message. 349 * 350 * PARAMS 351 * ld [I] Pointer to an LDAP context. 352 * res [I] Search result message. 353 * 354 * RETURNS 355 * Success: The first entry. 356 * Failure: NULL 357 * 358 * NOTES 359 * The returned entry will be freed when the message is freed. 360 */ 361 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_first_entry( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res ) 362 { 363 #ifdef HAVE_LDAP 364 365 TRACE( "(%p, %p)\n", ld, res ); 366 367 if (!ld || !res) return NULL; 368 return ldap_first_entry( ld, res ); 369 370 #else 371 return NULL; 372 #endif 373 } 374 375 /*********************************************************************** 376 * ldap_first_reference (WLDAP32.@) 377 * 378 * Get the first reference from a result message. 379 * 380 * PARAMS 381 * ld [I] Pointer to an LDAP context. 382 * res [I] Search result message. 383 * 384 * RETURNS 385 * Success: The first reference. 386 * Failure: NULL 387 */ 388 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_first_reference( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res ) 389 { 390 #ifdef HAVE_LDAP_FIRST_REFERENCE 391 392 TRACE( "(%p, %p)\n", ld, res ); 393 394 if (!ld) return NULL; 395 return ldap_first_reference( ld, res ); 396 397 #else 398 return NULL; 399 #endif 400 } 401 402 /*********************************************************************** 403 * ldap_memfreeA (WLDAP32.@) 404 * 405 * See ldap_memfreeW. 406 */ 407 void CDECL ldap_memfreeA( PCHAR block ) 408 { 409 TRACE( "(%p)\n", block ); 410 strfreeA( block ); 411 } 412 413 /*********************************************************************** 414 * ldap_memfreeW (WLDAP32.@) 415 * 416 * Free a block of memory. 417 * 418 * PARAMS 419 * block [I] Pointer to memory block to be freed. 420 */ 421 void CDECL ldap_memfreeW( PWCHAR block ) 422 { 423 TRACE( "(%p)\n", block ); 424 strfreeW( block ); 425 } 426 427 /*********************************************************************** 428 * ldap_msgfree (WLDAP32.@) 429 * 430 * Free a message. 431 * 432 * PARAMS 433 * res [I] Message to be freed. 434 */ 435 ULONG CDECL WLDAP32_ldap_msgfree( WLDAP32_LDAPMessage *res ) 436 { 437 ULONG ret = WLDAP32_LDAP_SUCCESS; 438 #ifdef HAVE_LDAP 439 440 TRACE( "(%p)\n", res ); 441 ldap_msgfree( res ); 442 443 #endif 444 return ret; 445 } 446 447 /*********************************************************************** 448 * ldap_next_attributeA (WLDAP32.@) 449 * 450 * See ldap_next_attributeW. 451 */ 452 PCHAR CDECL ldap_next_attributeA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, 453 WLDAP32_BerElement *ptr ) 454 { 455 PCHAR ret = NULL; 456 #ifdef HAVE_LDAP 457 WCHAR *retW; 458 459 TRACE( "(%p, %p, %p)\n", ld, entry, ptr ); 460 461 if (!ld || !entry || !ptr) return NULL; 462 retW = ldap_next_attributeW( ld, entry, ptr ); 463 464 ret = strWtoA( retW ); 465 ldap_memfreeW( retW ); 466 467 #endif 468 return ret; 469 } 470 471 /*********************************************************************** 472 * ldap_next_attributeW (WLDAP32.@) 473 * 474 * Get the next attribute for a given entry. 475 * 476 * PARAMS 477 * ld [I] Pointer to an LDAP context. 478 * entry [I] Entry to retrieve attribute for. 479 * ptr [I/O] Position pointer. 480 * 481 * RETURNS 482 * Success: The name of the next attribute. 483 * Failure: NULL 484 * 485 * NOTES 486 * Free the returned string after each iteration with ldap_memfree. 487 * When done iterating and when ptr != NULL, call ber_free( ptr, 0 ). 488 */ 489 PWCHAR CDECL ldap_next_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, 490 WLDAP32_BerElement *ptr ) 491 { 492 PWCHAR ret = NULL; 493 #ifdef HAVE_LDAP 494 char *retU; 495 496 TRACE( "(%p, %p, %p)\n", ld, entry, ptr ); 497 498 if (!ld || !entry || !ptr) return NULL; 499 retU = ldap_next_attribute( ld, entry, ptr ); 500 501 ret = strUtoW( retU ); 502 ldap_memfree( retU ); 503 504 #endif 505 return ret; 506 } 507 508 /*********************************************************************** 509 * ldap_next_entry (WLDAP32.@) 510 * 511 * Get the next entry from a result message. 512 * 513 * PARAMS 514 * ld [I] Pointer to an LDAP context. 515 * entry [I] Entry returned by a previous call. 516 * 517 * RETURNS 518 * Success: The next entry. 519 * Failure: NULL 520 * 521 * NOTES 522 * The returned entry will be freed when the message is freed. 523 */ 524 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_next_entry( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry ) 525 { 526 #ifdef HAVE_LDAP 527 528 TRACE( "(%p, %p)\n", ld, entry ); 529 530 if (!ld || !entry) return NULL; 531 return ldap_next_entry( ld, entry ); 532 533 #else 534 return NULL; 535 #endif 536 } 537 538 /*********************************************************************** 539 * ldap_next_reference (WLDAP32.@) 540 * 541 * Get the next reference from a result message. 542 * 543 * PARAMS 544 * ld [I] Pointer to an LDAP context. 545 * entry [I] Entry returned by a previous call. 546 * 547 * RETURNS 548 * Success: The next reference. 549 * Failure: NULL 550 * 551 * NOTES 552 * The returned entry will be freed when the message is freed. 553 */ 554 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_next_reference( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry ) 555 { 556 #ifdef HAVE_LDAP_NEXT_REFERENCE 557 558 TRACE( "(%p, %p)\n", ld, entry ); 559 560 if (!ld || !entry) return NULL; 561 return ldap_next_reference( ld, entry ); 562 563 #else 564 return NULL; 565 #endif 566 } 567 568 /*********************************************************************** 569 * ldap_result (WLDAP32.@) 570 * 571 * Get the result of an asynchronous operation. 572 * 573 * PARAMS 574 * ld [I] Pointer to an LDAP context. 575 * msgid [I] Message ID of the operation. 576 * all [I] How many results should be returned? 577 * timeout [I] How long to wait for the results? 578 * res [O] Result message for the operation. 579 * 580 * RETURNS 581 * Success: One of the following values: 582 * 583 * LDAP_RES_ADD 584 * LDAP_RES_BIND 585 * LDAP_RES_COMPARE 586 * LDAP_RES_DELETE 587 * LDAP_RES_EXTENDED 588 * LDAP_RES_MODIFY 589 * LDAP_RES_MODRDN 590 * LDAP_RES_REFERRAL 591 * LDAP_RES_SEARCH_ENTRY 592 * LDAP_RES_SEARCH_RESULT 593 * 594 * Failure: ~0u 595 * 596 * This function returns 0 when the timeout has expired. 597 * 598 * NOTES 599 * A NULL timeout pointer causes the function to block waiting 600 * for results to arrive. A timeout value of 0 causes the function 601 * to immediately return any available results. Free returned results 602 * with ldap_msgfree. 603 */ 604 ULONG CDECL WLDAP32_ldap_result( WLDAP32_LDAP *ld, ULONG msgid, ULONG all, 605 struct l_timeval *timeout, WLDAP32_LDAPMessage **res ) 606 { 607 ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; 608 #ifdef HAVE_LDAP 609 610 TRACE( "(%p, 0x%08x, 0x%08x, %p, %p)\n", ld, msgid, all, timeout, res ); 611 612 if (!ld || !res || msgid == ~0u) return ~0u; 613 ret = ldap_result( ld, msgid, all, (struct timeval *)timeout, res ); 614 615 #endif 616 return ret; 617 } 618 619 /*********************************************************************** 620 * LdapUnicodeToUTF8 (WLDAP32.@) 621 * 622 * Convert a wide character string to a UTF8 string. 623 * 624 * PARAMS 625 * src [I] Wide character string to convert. 626 * srclen [I] Size of string to convert, in characters. 627 * dst [O] Pointer to a buffer that receives the converted string. 628 * dstlen [I] Size of the destination buffer in characters. 629 * 630 * RETURNS 631 * The number of characters written into the destination buffer. 632 * 633 * NOTES 634 * Set dstlen to zero to ask for the required buffer size. 635 */ 636 int CDECL LdapUnicodeToUTF8( LPCWSTR src, int srclen, LPSTR dst, int dstlen ) 637 { 638 return WideCharToMultiByte( CP_UTF8, 0, src, srclen, dst, dstlen, NULL, NULL ); 639 } 640 641 /*********************************************************************** 642 * LdapUTF8ToUnicode (WLDAP32.@) 643 * 644 * Convert a UTF8 string to a wide character string. 645 * 646 * PARAMS 647 * src [I] UTF8 string to convert. 648 * srclen [I] Size of string to convert, in characters. 649 * dst [O] Pointer to a buffer that receives the converted string. 650 * dstlen [I] Size of the destination buffer in characters. 651 * 652 * RETURNS 653 * The number of characters written into the destination buffer. 654 * 655 * NOTES 656 * Set dstlen to zero to ask for the required buffer size. 657 */ 658 int CDECL LdapUTF8ToUnicode( LPCSTR src, int srclen, LPWSTR dst, int dstlen ) 659 { 660 return MultiByteToWideChar( CP_UTF8, 0, src, srclen, dst, dstlen ); 661 } 662