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 */
WLDAP32_ldap_abandon(WLDAP32_LDAP * ld,ULONG msgid)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 */
ldap_check_filterA(WLDAP32_LDAP * ld,PCHAR filter)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 */
ldap_check_filterW(WLDAP32_LDAP * ld,PWCHAR filter)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 */
ldap_cleanup(HANDLE instance)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 */
ldap_conn_from_msg(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * res)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 */
WLDAP32_ldap_count_entries(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * res)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 */
WLDAP32_ldap_count_references(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * res)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
get_escape_size(PCHAR src,ULONG srclen)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
escape_filter_element(PCHAR src,ULONG srclen,PCHAR dst)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 */
ldap_escape_filter_elementA(PCHAR src,ULONG srclen,PCHAR dst,ULONG dstlen)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 */
ldap_escape_filter_elementW(PCHAR src,ULONG srclen,PWCHAR dst,ULONG dstlen)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 */
ldap_first_attributeA(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry,WLDAP32_BerElement ** ptr)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 */
ldap_first_attributeW(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry,WLDAP32_BerElement ** ptr)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 */
WLDAP32_ldap_first_entry(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * res)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 */
WLDAP32_ldap_first_reference(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * res)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 */
ldap_memfreeA(PCHAR block)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 */
ldap_memfreeW(PWCHAR block)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 */
WLDAP32_ldap_msgfree(WLDAP32_LDAPMessage * res)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 */
ldap_next_attributeA(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry,WLDAP32_BerElement * ptr)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 */
ldap_next_attributeW(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry,WLDAP32_BerElement * ptr)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 */
WLDAP32_ldap_next_entry(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry)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 */
WLDAP32_ldap_next_reference(WLDAP32_LDAP * ld,WLDAP32_LDAPMessage * entry)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 */
WLDAP32_ldap_result(WLDAP32_LDAP * ld,ULONG msgid,ULONG all,struct l_timeval * timeout,WLDAP32_LDAPMessage ** res)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 */
LdapUnicodeToUTF8(LPCWSTR src,int srclen,LPSTR dst,int dstlen)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 */
LdapUTF8ToUnicode(LPCSTR src,int srclen,LPWSTR dst,int dstlen)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