Release 1.5.29.
[wine] / dlls / wldap32 / search.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 #ifdef HAVE_LDAP_H
26 #include <ldap.h>
27 #endif
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32
33 #include "winldap_private.h"
34 #include "wldap32.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
38
39 /***********************************************************************
40  *      ldap_searchA     (WLDAP32.@)
41  *
42  * See ldap_searchW.
43  */
44 ULONG CDECL ldap_searchA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope, PCHAR filter,
45     PCHAR attrs[], ULONG attrsonly )
46 {
47     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
48 #ifdef HAVE_LDAP
49     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
50
51     ret = WLDAP32_LDAP_NO_MEMORY;
52
53     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x)\n", ld, debugstr_a(base),
54            scope, debugstr_a(filter), attrs, attrsonly );
55
56     if (!ld) return ~0u;
57
58     if (base) {
59         baseW = strAtoW( base );
60         if (!baseW) goto exit;
61     }
62     if (filter) {
63         filterW = strAtoW( filter );
64         if (!filterW) goto exit;
65     }
66     if (attrs) {
67         attrsW = strarrayAtoW( attrs );
68         if (!attrsW) goto exit;
69     }
70
71     ret = ldap_searchW( ld, baseW, scope, filterW, attrsW, attrsonly );
72
73 exit:
74     strfreeW( baseW );
75     strfreeW( filterW );
76     strarrayfreeW( attrsW );
77
78 #endif
79     return ret;
80 }
81
82 /***********************************************************************
83  *      ldap_searchW     (WLDAP32.@)
84  *
85  * Search a directory tree (asynchronous operation).
86  *
87  * PARAMS
88  *  ld        [I] Pointer to an LDAP context.
89  *  base      [I] Starting point for the search.
90  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
91  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
92  *  filter    [I] Search filter.
93  *  attrs     [I] Attributes to return.
94  *  attrsonly [I] Return no values, only attributes.
95  *
96  * RETURNS
97  *  Success: Message ID of the search operation.
98  *  Failure: ~0u
99  *
100  * NOTES
101  *  Call ldap_result with the message ID to get the result of
102  *  the operation. Cancel the operation by calling ldap_abandon
103  *  with the message ID.
104  */
105 ULONG CDECL ldap_searchW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope, PWCHAR filter,
106     PWCHAR attrs[], ULONG attrsonly )
107 {
108     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
109 #ifdef HAVE_LDAP
110     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
111     int msg;
112
113     ret = WLDAP32_LDAP_NO_MEMORY;
114
115     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x)\n", ld, debugstr_w(base),
116            scope, debugstr_w(filter), attrs, attrsonly );
117
118     if (!ld) return ~0u;
119
120     if (base) {
121         baseU = strWtoU( base );
122         if (!baseU) goto exit;
123     }
124     if (filter) {
125         filterU = strWtoU( filter );
126         if (!filterU) goto exit;
127     }
128     if (attrs) {
129         attrsU = strarrayWtoU( attrs );
130         if (!attrsU) goto exit;
131     }
132
133     ret = ldap_search_ext( ld, baseU, scope, filterU, attrsU, attrsonly,
134                            NULL, NULL, NULL, 0, &msg );
135
136     if (ret == LDAP_SUCCESS)
137         ret = msg;
138     else
139         ret = ~0u;
140
141 exit:
142     strfreeU( baseU );
143     strfreeU( filterU );
144     strarrayfreeU( attrsU );
145
146 #endif
147     return ret;
148 }
149
150 /***********************************************************************
151  *      ldap_search_extA     (WLDAP32.@)
152  *
153  * See ldap_search_extW.
154  */
155 ULONG CDECL ldap_search_extA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope,
156     PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *serverctrls,
157     PLDAPControlA *clientctrls, ULONG timelimit, ULONG sizelimit, ULONG *message )
158 {
159     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
160 #ifdef HAVE_LDAP
161     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
162     LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
163
164     ret = WLDAP32_LDAP_NO_MEMORY;
165
166     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n",
167            ld, debugstr_a(base), scope, debugstr_a(filter), attrs, attrsonly,
168            serverctrls, clientctrls, timelimit, sizelimit, message );
169
170     if (!ld) return WLDAP32_LDAP_PARAM_ERROR;
171
172     if (base) {
173         baseW = strAtoW( base );
174         if (!baseW) goto exit;
175     }
176     if (filter)
177     {
178         filterW = strAtoW( filter );
179         if (!filterW) goto exit;
180     }
181     if (attrs) {
182         attrsW = strarrayAtoW( attrs );
183         if (!attrsW) goto exit;
184     }
185     if (serverctrls) {
186         serverctrlsW = controlarrayAtoW( serverctrls );
187         if (!serverctrlsW) goto exit;
188     }
189     if (clientctrls) {
190         clientctrlsW = controlarrayAtoW( clientctrls );
191         if (!clientctrlsW) goto exit;
192     }
193
194     ret = ldap_search_extW( ld, baseW, scope, filterW, attrsW, attrsonly,
195                             serverctrlsW, clientctrlsW, timelimit, sizelimit, message );
196
197 exit:
198     strfreeW( baseW );
199     strfreeW( filterW );
200     strarrayfreeW( attrsW );
201     controlarrayfreeW( serverctrlsW );
202     controlarrayfreeW( clientctrlsW );
203
204 #endif
205     return ret;
206 }
207
208 /***********************************************************************
209  *      ldap_search_extW     (WLDAP32.@)
210  *
211  * Search a directory tree (asynchronous operation).
212  *
213  * PARAMS
214  *  ld          [I] Pointer to an LDAP context.
215  *  base        [I] Starting point for the search.
216  *  scope       [I] Search scope. One of LDAP_SCOPE_BASE,
217  *                  LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
218  *  filter      [I] Search filter.
219  *  attrs       [I] Attributes to return.
220  *  attrsonly   [I] Return no values, only attributes.
221  *  serverctrls [I] Array of LDAP server controls.
222  *  clientctrls [I] Array of LDAP client controls.
223  *  timelimit   [I] Timeout in seconds.
224  *  sizelimit   [I] Maximum number of entries to return. Zero means unlimited.
225  *  message     [O] Message ID of the search operation.
226  *
227  * RETURNS
228  *  Success: LDAP_SUCCESS
229  *  Failure: An LDAP error code.
230  *
231  * NOTES
232  *  Call ldap_result with the message ID to get the result of
233  *  the operation. Cancel the operation by calling ldap_abandon
234  *  with the message ID.
235  */
236 ULONG CDECL ldap_search_extW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope,
237     PWCHAR filter, PWCHAR attrs[], ULONG attrsonly, PLDAPControlW *serverctrls,
238     PLDAPControlW *clientctrls, ULONG timelimit, ULONG sizelimit, ULONG *message )
239 {
240     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
241 #ifdef HAVE_LDAP
242     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
243     LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
244     struct timeval tv, *tvp = NULL;
245
246     ret = WLDAP32_LDAP_NO_MEMORY;
247
248     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, 0x%08x, 0x%08x, %p)\n",
249            ld, debugstr_w(base), scope, debugstr_w(filter), attrs, attrsonly,
250            serverctrls, clientctrls, timelimit, sizelimit, message );
251
252     if (!ld) return ~0u;
253
254     if (base) {
255         baseU = strWtoU( base );
256         if (!baseU) goto exit;
257     }
258     if (filter) {
259         filterU = strWtoU( filter );
260         if (!filterU) goto exit;
261     }
262     if (attrs) {
263         attrsU = strarrayWtoU( attrs );
264         if (!attrsU) goto exit;
265     }
266     if (serverctrls) {
267         serverctrlsU = controlarrayWtoU( serverctrls );
268         if (!serverctrlsU) goto exit;
269     }
270     if (clientctrls) {
271         clientctrlsU = controlarrayWtoU( clientctrls );
272         if (!clientctrlsU) goto exit;
273     }
274
275     if (timelimit)
276     {
277         tv.tv_sec = timelimit;
278         tv.tv_usec = 0;
279         tvp = &tv;
280     }
281
282     ret = map_error( ldap_search_ext( ld, baseU, scope, filterU, attrsU, attrsonly,
283                                       serverctrlsU, clientctrlsU, tvp, sizelimit, (int *)message ));
284
285 exit:
286     strfreeU( baseU );
287     strfreeU( filterU );
288     strarrayfreeU( attrsU );
289     controlarrayfreeU( serverctrlsU );
290     controlarrayfreeU( clientctrlsU );
291
292 #endif
293     return ret;
294 }
295
296 /***********************************************************************
297  *      ldap_search_ext_sA     (WLDAP32.@)
298  *
299  * See ldap_search_ext_sW.
300  */
301 ULONG CDECL ldap_search_ext_sA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope,
302     PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *serverctrls,
303     PLDAPControlA *clientctrls, struct l_timeval* timeout, ULONG sizelimit, WLDAP32_LDAPMessage **res )
304 {
305     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
306 #ifdef HAVE_LDAP
307     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
308     LDAPControlW **serverctrlsW = NULL, **clientctrlsW = NULL;
309
310     ret = WLDAP32_LDAP_NO_MEMORY;
311
312     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, %p, 0x%08x, %p)\n",
313            ld, debugstr_a(base), scope, debugstr_a(filter), attrs, attrsonly,
314            serverctrls, clientctrls, timeout, sizelimit, res );
315
316     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
317
318     if (base) {
319         baseW = strAtoW( base );
320         if (!baseW) goto exit;
321     }
322     if (filter) {
323         filterW = strAtoW( filter );
324         if (!filterW) goto exit;
325     }
326     if (attrs) {
327         attrsW = strarrayAtoW( attrs );
328         if (!attrsW) goto exit;
329     }
330     if (serverctrls) {
331         serverctrlsW = controlarrayAtoW( serverctrls );
332         if (!serverctrlsW) goto exit;
333     }
334     if (clientctrls) {
335         clientctrlsW = controlarrayAtoW( clientctrls );
336         if (!clientctrlsW) goto exit;
337     }
338
339     ret = ldap_search_ext_sW( ld, baseW, scope, filterW, attrsW, attrsonly,
340                               serverctrlsW, clientctrlsW, timeout, sizelimit, res );
341
342 exit:
343     strfreeW( baseW );
344     strfreeW( filterW );
345     strarrayfreeW( attrsW );
346     controlarrayfreeW( serverctrlsW );
347     controlarrayfreeW( clientctrlsW );
348
349 #endif
350     return ret;
351 }
352
353 /***********************************************************************
354  *      ldap_search_ext_sW     (WLDAP32.@)
355  *
356  * Search a directory tree (synchronous operation).
357  *
358  * PARAMS
359  *  ld          [I] Pointer to an LDAP context.
360  *  base        [I] Starting point for the search.
361  *  scope       [I] Search scope. One of LDAP_SCOPE_BASE,
362  *                  LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
363  *  filter      [I] Search filter.
364  *  attrs       [I] Attributes to return.
365  *  attrsonly   [I] Return no values, only attributes.
366  *  serverctrls [I] Array of LDAP server controls.
367  *  clientctrls [I] Array of LDAP client controls.
368  *  timeout     [I] Timeout in seconds.
369  *  sizelimit   [I] Maximum number of entries to return. Zero means unlimited.
370  *  res         [O] Results of the search operation.
371  *
372  * RETURNS
373  *  Success: LDAP_SUCCESS
374  *  Failure: An LDAP error code.
375  *
376  * NOTES
377  *  Call ldap_msgfree to free the results.
378  */
379 ULONG CDECL ldap_search_ext_sW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope,
380     PWCHAR filter, PWCHAR attrs[], ULONG attrsonly, PLDAPControlW *serverctrls,
381     PLDAPControlW *clientctrls, struct l_timeval* timeout, ULONG sizelimit, WLDAP32_LDAPMessage **res )
382 {
383     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
384 #ifdef HAVE_LDAP
385     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
386     LDAPControl **serverctrlsU = NULL, **clientctrlsU = NULL;
387
388     ret = WLDAP32_LDAP_NO_MEMORY;
389
390     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p, %p, 0x%08x, %p)\n",
391            ld, debugstr_w(base), scope, debugstr_w(filter), attrs, attrsonly,
392            serverctrls, clientctrls, timeout, sizelimit, res );
393
394     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
395
396     if (base) {
397         baseU = strWtoU( base );
398         if (!baseU) goto exit;
399     }
400     if (filter) {
401         filterU = strWtoU( filter );
402         if (!filterU) goto exit;
403     }
404     if (attrs) {
405         attrsU = strarrayWtoU( attrs );
406         if (!attrsU) goto exit;
407     }
408     if (serverctrls) {
409         serverctrlsU = controlarrayWtoU( serverctrls );
410         if (!serverctrlsU) goto exit;
411     }
412     if (clientctrls) {
413         clientctrlsU = controlarrayWtoU( clientctrls );
414         if (!clientctrlsU) goto exit;
415     }
416
417     ret = map_error( ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
418                                         serverctrlsU, clientctrlsU, (struct timeval *)timeout,
419                                         sizelimit, res ));
420
421 exit:
422     strfreeU( baseU );
423     strfreeU( filterU );
424     strarrayfreeU( attrsU );
425     controlarrayfreeU( serverctrlsU );
426     controlarrayfreeU( clientctrlsU );
427
428 #endif
429     return ret;
430 }
431
432 /***********************************************************************
433  *      ldap_search_sA     (WLDAP32.@)
434  *
435  * See ldap_search_sW.
436  */
437 ULONG CDECL ldap_search_sA( WLDAP32_LDAP *ld, PCHAR base, ULONG scope, PCHAR filter,
438     PCHAR attrs[], ULONG attrsonly, WLDAP32_LDAPMessage **res )
439 {
440     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
441 #ifdef HAVE_LDAP
442     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
443
444     ret = WLDAP32_LDAP_NO_MEMORY;
445
446     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p)\n", ld, debugstr_a(base),
447            scope, debugstr_a(filter), attrs, attrsonly, res );
448
449     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
450
451     if (base) {
452         baseW = strAtoW( base );
453         if (!baseW) goto exit;
454     }
455     if (filter) {
456         filterW = strAtoW( filter );
457         if (!filterW) goto exit;
458     }
459     if (attrs) {
460         attrsW = strarrayAtoW( attrs );
461         if (!attrsW) goto exit;
462     }
463
464     ret = ldap_search_sW( ld, baseW, scope, filterW, attrsW, attrsonly, res );
465
466 exit:
467     strfreeW( baseW );
468     strfreeW( filterW );
469     strarrayfreeW( attrsW );
470
471 #endif
472     return ret;
473 }
474
475 /***********************************************************************
476  *      ldap_search_sW     (WLDAP32.@)
477  *
478  * Search a directory tree (synchronous operation).
479  *
480  * PARAMS
481  *  ld        [I] Pointer to an LDAP context.
482  *  base      [I] Starting point for the search.
483  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
484  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
485  *  filter    [I] Search filter.
486  *  attrs     [I] Attributes to return.
487  *  attrsonly [I] Return no values, only attributes.
488  *  res       [O] Results of the search operation.
489  *
490  * RETURNS
491  *  Success: LDAP_SUCCESS
492  *  Failure: An LDAP error code.
493  *
494  * NOTES
495  *  Call ldap_msgfree to free the results.
496  */
497 ULONG CDECL ldap_search_sW( WLDAP32_LDAP *ld, PWCHAR base, ULONG scope, PWCHAR filter,
498     PWCHAR attrs[], ULONG attrsonly, WLDAP32_LDAPMessage **res )
499 {
500     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
501 #ifdef HAVE_LDAP
502     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
503
504     ret = WLDAP32_LDAP_NO_MEMORY;
505
506     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p)\n", ld, debugstr_w(base),
507            scope, debugstr_w(filter), attrs, attrsonly, res );
508
509     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
510
511     if (base) {
512         baseU = strWtoU( base );
513         if (!baseU) goto exit;
514     }
515     if (filter) {
516         filterU = strWtoU( filter );
517         if (!filterU) goto exit;
518     }
519     if (attrs) {
520         attrsU = strarrayWtoU( attrs );
521         if (!attrsU) goto exit;
522     }
523
524     ret = map_error( ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
525                                         NULL, NULL, NULL, 0, res ));
526
527 exit:
528     strfreeU( baseU );
529     strfreeU( filterU );
530     strarrayfreeU( attrsU );
531
532 #endif
533     return ret;
534 }
535
536 /***********************************************************************
537  *      ldap_search_stA     (WLDAP32.@)
538  *
539  * See ldap_search_stW.
540  */
541 ULONG CDECL ldap_search_stA( WLDAP32_LDAP *ld, const PCHAR base, ULONG scope,
542     const PCHAR filter, PCHAR attrs[], ULONG attrsonly,
543     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
544 {
545     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
546 #ifdef HAVE_LDAP
547     WCHAR *baseW = NULL, *filterW = NULL, **attrsW = NULL;
548
549     ret = WLDAP32_LDAP_NO_MEMORY;
550
551     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p)\n", ld,
552            debugstr_a(base), scope, debugstr_a(filter), attrs,
553            attrsonly, timeout, res );
554
555     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
556
557     if (base) {
558         baseW = strAtoW( base );
559         if (!baseW) goto exit;
560     }
561     if (filter) {
562         filterW = strAtoW( filter );
563         if (!filterW) goto exit;
564     }
565     if (attrs) {
566         attrsW = strarrayAtoW( attrs );
567         if (!attrsW) goto exit;
568     }
569
570     ret = ldap_search_stW( ld, baseW, scope, filterW, attrsW, attrsonly,
571                            timeout, res );
572
573 exit:
574     strfreeW( baseW );
575     strfreeW( filterW );
576     strarrayfreeW( attrsW );
577
578 #endif
579     return ret;
580 }
581
582 /***********************************************************************
583  *      ldap_search_stW     (WLDAP32.@)
584  *
585  * Search a directory tree (synchronous operation).
586  *
587  * PARAMS
588  *  ld        [I] Pointer to an LDAP context.
589  *  base      [I] Starting point for the search.
590  *  scope     [I] Search scope. One of LDAP_SCOPE_BASE,
591  *                LDAP_SCOPE_ONELEVEL and LDAP_SCOPE_SUBTREE.
592  *  filter    [I] Search filter.
593  *  attrs     [I] Attributes to return.
594  *  attrsonly [I] Return no values, only attributes.
595  *  timeout   [I] Timeout in seconds.
596  *  res       [O] Results of the search operation.
597  *
598  * RETURNS
599  *  Success: LDAP_SUCCESS
600  *  Failure: An LDAP error code.
601  *
602  * NOTES
603  *  Call ldap_msgfree to free the results.
604  */
605 ULONG CDECL ldap_search_stW( WLDAP32_LDAP *ld, const PWCHAR base, ULONG scope,
606     const PWCHAR filter, PWCHAR attrs[], ULONG attrsonly,
607     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
608 {
609     ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
610 #ifdef HAVE_LDAP
611     char *baseU = NULL, *filterU = NULL, **attrsU = NULL;
612
613     ret = WLDAP32_LDAP_NO_MEMORY;
614
615     TRACE( "(%p, %s, 0x%08x, %s, %p, 0x%08x, %p, %p)\n", ld,
616            debugstr_w(base), scope, debugstr_w(filter), attrs,
617            attrsonly, timeout, res );
618
619     if (!ld || !res) return WLDAP32_LDAP_PARAM_ERROR;
620
621     if (base) {
622         baseU = strWtoU( base );
623         if (!baseU) goto exit;
624     }
625     if (filter) {
626         filterU = strWtoU( filter );
627         if (!filterU) goto exit;
628     }
629     if (attrs) {
630         attrsU = strarrayWtoU( attrs );
631         if (!attrsU) goto exit;
632     }
633
634     ret = map_error( ldap_search_ext_s( ld, baseU, scope, filterU, attrsU, attrsonly,
635                                         NULL, NULL, (struct timeval *)timeout, 0, res ));
636
637 exit:
638     strfreeU( baseU );
639     strfreeU( filterU );
640     strarrayfreeU( attrsU );
641
642 #endif
643     return ret;
644 }