xref: /reactos/dll/win32/wldap32/misc.c (revision cc439606)
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