Release 1.5.29.
[wine] / dlls / wldap32 / misc.c
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         {
230             sprintf( d, fmt, (unsigned char)src[i] );
231             d += 3;
232         }
233     }
234     *++d = 0;
235 }
236
237 /***********************************************************************
238  *      ldap_escape_filter_elementA     (WLDAP32.@)
239  *
240  * See ldap_escape_filter_elementW.
241  */
242 ULONG CDECL ldap_escape_filter_elementA( PCHAR src, ULONG srclen, PCHAR dst, ULONG dstlen )
243 {
244     ULONG len;
245
246     TRACE( "(%p, 0x%08x, %p, 0x%08x)\n", src, srclen, dst, dstlen );
247
248     len = get_escape_size( src, srclen );
249     if (!dst) return len;
250
251     if (!src || dstlen < len)
252         return WLDAP32_LDAP_PARAM_ERROR;
253     else
254     {
255         escape_filter_element( src, srclen, dst );
256         return WLDAP32_LDAP_SUCCESS;
257     }
258 }
259
260 /***********************************************************************
261  *      ldap_escape_filter_elementW     (WLDAP32.@)
262  *
263  * Escape binary data for safe passing in filters.
264  *
265  * PARAMS
266  *  src    [I] Filter element to be escaped.
267  *  srclen [I] Length in bytes of the filter element.
268  *  dst    [O] Destination buffer for the escaped filter element.
269  *  dstlen [I] Length in bytes of the destination buffer.
270  *
271  * RETURNS
272  *  Success: LDAP_SUCCESS
273  *  Failure: An LDAP error code.
274  */
275 ULONG CDECL ldap_escape_filter_elementW( PCHAR src, ULONG srclen, PWCHAR dst, ULONG dstlen )
276 {
277     ULONG len;
278
279     TRACE( "(%p, 0x%08x, %p, 0x%08x)\n", src, srclen, dst, dstlen );
280
281     len = get_escape_size( src, srclen );
282     if (!dst) return len;
283
284     /* no matter what you throw at it, this is what native returns */
285     return WLDAP32_LDAP_PARAM_ERROR;
286 }
287
288 /***********************************************************************
289  *      ldap_first_attributeA     (WLDAP32.@)
290  *
291  * See ldap_first_attributeW.
292  */
293 PCHAR CDECL ldap_first_attributeA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
294     WLDAP32_BerElement** ptr )
295 {
296     PCHAR ret = NULL;
297 #ifdef HAVE_LDAP
298     WCHAR *retW;
299
300     TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
301
302     if (!ld || !entry) return NULL;
303     retW = ldap_first_attributeW( ld, entry, ptr );
304
305     ret = strWtoA( retW );
306     ldap_memfreeW( retW );
307
308 #endif
309     return ret;
310 }
311
312 /***********************************************************************
313  *      ldap_first_attributeW     (WLDAP32.@)
314  *
315  * Get the first attribute for a given entry. 
316  *
317  * PARAMS
318  *  ld    [I] Pointer to an LDAP context.
319  *  entry [I] Entry to retrieve attribute for.
320  *  ptr   [O] Position pointer.
321  *
322  * RETURNS
323  *  Success: Name of the first attribute.
324  *  Failure: NULL
325  *
326  * NOTES
327  *  Use ldap_memfree to free the returned string.
328  */
329 PWCHAR CDECL ldap_first_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
330     WLDAP32_BerElement** ptr )
331 {
332     PWCHAR ret = NULL;
333 #ifdef HAVE_LDAP
334     char *retU;
335
336     TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
337
338     if (!ld || !entry) return NULL;
339     retU = ldap_first_attribute( ld, entry, ptr );
340
341     ret = strUtoW( retU );
342     ldap_memfree( retU );
343
344 #endif
345     return ret;
346 }
347
348 /***********************************************************************
349  *      ldap_first_entry     (WLDAP32.@)
350  *
351  * Get the first entry from a result message.
352  *
353  * PARAMS
354  *  ld  [I] Pointer to an LDAP context.
355  *  res [I] Search result message.
356  *
357  * RETURNS
358  *  Success: The first entry.
359  *  Failure: NULL
360  *
361  * NOTES
362  *  The returned entry will be freed when the message is freed. 
363  */
364 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_first_entry( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res )
365 {
366 #ifdef HAVE_LDAP
367
368     TRACE( "(%p, %p)\n", ld, res );
369
370     if (!ld || !res) return NULL;
371     return ldap_first_entry( ld, res );
372
373 #else
374     return NULL;
375 #endif
376 }
377
378 /***********************************************************************
379  *      ldap_first_reference     (WLDAP32.@)
380  *
381  * Get the first reference from a result message.
382  *
383  * PARAMS
384  *  ld  [I] Pointer to an LDAP context.
385  *  res [I] Search result message.
386  *
387  * RETURNS
388  *  Success: The first reference.
389  *  Failure: NULL
390  */
391 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_first_reference( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *res )
392 {
393 #ifdef HAVE_LDAP_FIRST_REFERENCE
394
395     TRACE( "(%p, %p)\n", ld, res );
396
397     if (!ld) return NULL;
398     return ldap_first_reference( ld, res );
399
400 #else
401     return NULL;
402 #endif
403 }
404
405 /***********************************************************************
406  *      ldap_memfreeA     (WLDAP32.@)
407  *
408  * See ldap_memfreeW.
409  */
410 void CDECL ldap_memfreeA( PCHAR block )
411 {
412     TRACE( "(%p)\n", block );
413     strfreeA( block );
414 }
415
416 /***********************************************************************
417  *      ldap_memfreeW     (WLDAP32.@)
418  *
419  * Free a block of memory.
420  *
421  * PARAMS
422  *  block [I] Pointer to memory block to be freed.
423  */
424 void CDECL ldap_memfreeW( PWCHAR block )
425 {
426     TRACE( "(%p)\n", block );
427     strfreeW( block );
428 }
429
430 /***********************************************************************
431  *      ldap_msgfree     (WLDAP32.@)
432  *
433  * Free a message.
434  *
435  * PARAMS
436  *  res [I] Message to be freed.
437  */
438 ULONG CDECL WLDAP32_ldap_msgfree( WLDAP32_LDAPMessage *res )
439 {
440     ULONG ret = WLDAP32_LDAP_SUCCESS;
441 #ifdef HAVE_LDAP
442
443     TRACE( "(%p)\n", res );
444     ldap_msgfree( res );
445
446 #endif
447     return ret;
448 }
449
450 /***********************************************************************
451  *      ldap_next_attributeA     (WLDAP32.@)
452  *
453  * See ldap_next_attributeW.
454  */
455 PCHAR CDECL ldap_next_attributeA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
456     WLDAP32_BerElement *ptr )
457 {
458     PCHAR ret = NULL;
459 #ifdef HAVE_LDAP
460     WCHAR *retW;
461
462     TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
463
464     if (!ld || !entry || !ptr) return NULL;
465     retW = ldap_next_attributeW( ld, entry, ptr );
466
467     ret = strWtoA( retW );
468     ldap_memfreeW( retW );
469
470 #endif
471     return ret;
472 }
473
474 /***********************************************************************
475  *      ldap_next_attributeW     (WLDAP32.@)
476  *
477  * Get the next attribute for a given entry.
478  *
479  * PARAMS
480  *  ld    [I]   Pointer to an LDAP context.
481  *  entry [I]   Entry to retrieve attribute for.
482  *  ptr   [I/O] Position pointer.
483  *
484  * RETURNS
485  *  Success: The name of the next attribute.
486  *  Failure: NULL
487  *
488  * NOTES
489  *  Free the returned string after each iteration with ldap_memfree.
490  *  When done iterating and when ptr != NULL, call ber_free( ptr, 0 ).
491  */
492 PWCHAR CDECL ldap_next_attributeW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry,
493     WLDAP32_BerElement *ptr )
494 {
495     PWCHAR ret = NULL;
496 #ifdef HAVE_LDAP
497     char *retU;
498
499     TRACE( "(%p, %p, %p)\n", ld, entry, ptr );
500
501     if (!ld || !entry || !ptr) return NULL;
502     retU = ldap_next_attribute( ld, entry, ptr );
503
504     ret = strUtoW( retU );
505     ldap_memfree( retU );
506
507 #endif
508     return ret;
509 }
510
511 /***********************************************************************
512  *      ldap_next_entry     (WLDAP32.@)
513  *
514  * Get the next entry from a result message.
515  *
516  * PARAMS
517  *  ld    [I] Pointer to an LDAP context.
518  *  entry [I] Entry returned by a previous call.
519  *
520  * RETURNS
521  *  Success: The next entry.
522  *  Failure: NULL
523  *
524  * NOTES
525  *  The returned entry will be freed when the message is freed.
526  */
527 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_next_entry( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry )
528 {
529 #ifdef HAVE_LDAP
530
531     TRACE( "(%p, %p)\n", ld, entry );
532
533     if (!ld || !entry) return NULL;
534     return ldap_next_entry( ld, entry );
535
536 #else
537     return NULL;
538 #endif
539 }
540
541 /***********************************************************************
542  *      ldap_next_reference     (WLDAP32.@)
543  *
544  * Get the next reference from a result message.
545  *
546  * PARAMS
547  *  ld    [I] Pointer to an LDAP context.
548  *  entry [I] Entry returned by a previous call.
549  *
550  * RETURNS
551  *  Success: The next reference.
552  *  Failure: NULL
553  *
554  * NOTES
555  *  The returned entry will be freed when the message is freed.
556  */
557 WLDAP32_LDAPMessage * CDECL WLDAP32_ldap_next_reference( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry )
558 {
559 #ifdef HAVE_LDAP_NEXT_REFERENCE
560
561     TRACE( "(%p, %p)\n", ld, entry );
562
563     if (!ld || !entry) return NULL;
564     return ldap_next_reference( ld, entry );
565
566 #else
567     return NULL;
568 #endif
569 }
570
571 /***********************************************************************
572  *      ldap_result     (WLDAP32.@)
573  *
574  * Get the result of an asynchronous operation.
575  *
576  * PARAMS
577  *  ld      [I] Pointer to an LDAP context.
578  *  msgid   [I] Message ID of the operation.
579  *  all     [I] How many results should be returned?
580  *  timeout [I] How long to wait for the results?
581  *  res     [O] Result message for the operation.
582  *
583  * RETURNS
584  *  Success: One of the following values:
585  *
586  *   LDAP_RES_ADD
587  *   LDAP_RES_BIND
588  *   LDAP_RES_COMPARE
589  *   LDAP_RES_DELETE
590  *   LDAP_RES_EXTENDED
591  *   LDAP_RES_MODIFY
592  *   LDAP_RES_MODRDN
593  *   LDAP_RES_REFERRAL
594  *   LDAP_RES_SEARCH_ENTRY
595  *   LDAP_RES_SEARCH_RESULT
596  *
597  *  Failure: ~0u
598  *
599  *  This function returns 0 when the timeout has expired.
600  *
601  * NOTES
602  *  A NULL timeout pointer causes the function to block waiting
603  *  for results to arrive. A timeout value of 0 causes the function
604  *  to immediately return any available results. Free returned results
605  *  with ldap_msgfree.
606  */
607 ULONG CDECL WLDAP32_ldap_result( WLDAP32_LDAP *ld, ULONG msgid, ULONG all,
608     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
609 {
610     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
611 #ifdef HAVE_LDAP
612
613     TRACE( "(%p, 0x%08x, 0x%08x, %p, %p)\n", ld, msgid, all, timeout, res );
614
615     if (!ld || !res || msgid == ~0u) return ~0u;
616     ret = ldap_result( ld, msgid, all, (struct timeval *)timeout, res );
617
618 #endif
619     return ret;
620 }
621
622 /***********************************************************************
623  *      LdapUnicodeToUTF8     (WLDAP32.@)
624  *
625  * Convert a wide character string to a UTF8 string.
626  *
627  * PARAMS
628  *  src    [I] Wide character string to convert.
629  *  srclen [I] Size of string to convert, in characters.
630  *  dst    [O] Pointer to a buffer that receives the converted string.
631  *  dstlen [I] Size of the destination buffer in characters. 
632  *
633  * RETURNS
634  *  The number of characters written into the destination buffer.
635  *
636  * NOTES
637  *  Set dstlen to zero to ask for the required buffer size.
638  */
639 int CDECL LdapUnicodeToUTF8( LPCWSTR src, int srclen, LPSTR dst, int dstlen )
640 {
641     return WideCharToMultiByte( CP_UTF8, 0, src, srclen, dst, dstlen, NULL, NULL );
642 }
643
644 /***********************************************************************
645  *      LdapUTF8ToUnicode     (WLDAP32.@)
646  *
647  * Convert a UTF8 string to a wide character string.
648  *
649  * PARAMS
650  *  src    [I] UTF8 string to convert.
651  *  srclen [I] Size of string to convert, in characters.
652  *  dst    [O] Pointer to a buffer that receives the converted string.
653  *  dstlen [I] Size of the destination buffer in characters. 
654  *
655  * RETURNS
656  *  The number of characters written into the destination buffer.
657  *
658  * NOTES
659  *  Set dstlen to zero to ask for the required buffer size.
660  */
661 int CDECL LdapUTF8ToUnicode( LPCSTR src, int srclen, LPWSTR dst, int dstlen )
662 {
663     return MultiByteToWideChar( CP_UTF8, 0, src, srclen, dst, dstlen );
664 }