]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
ITS#5291, more for rev 1.79 search timeouts
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
16  * All rights reserved.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/stdlib.h>
24
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/time.h>
28
29 #include "ldap-int.h"
30 #include "ldap_log.h"
31
32 /*
33  * ldap_search_ext - initiate an ldap search operation.
34  *
35  * Parameters:
36  *
37  *      ld              LDAP descriptor
38  *      base            DN of the base object
39  *      scope           the search scope - one of
40  *                              LDAP_SCOPE_BASE (baseObject),
41  *                          LDAP_SCOPE_ONELEVEL (oneLevel),
42  *                              LDAP_SCOPE_SUBTREE (subtree), or
43  *                              LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
44  *      filter          a string containing the search filter
45  *                      (e.g., "(|(cn=bob)(sn=bob))")
46  *      attrs           list of attribute types to return for matches
47  *      attrsonly       1 => attributes only 0 => attributes and values
48  *
49  * Example:
50  *      char    *attrs[] = { "mail", "title", 0 };
51  *      ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
52  *          attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
53  *              &msgid );
54  */
55 int
56 ldap_search_ext(
57         LDAP *ld,
58         LDAP_CONST char *base,
59         int scope,
60         LDAP_CONST char *filter,
61         char **attrs,
62         int attrsonly,
63         LDAPControl **sctrls,
64         LDAPControl **cctrls,
65         struct timeval *timeout,
66         int sizelimit,
67         int *msgidp )
68 {
69         int rc;
70         BerElement      *ber;
71         int timelimit;
72         ber_int_t id;
73
74         Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
75
76         assert( ld != NULL );
77         assert( LDAP_VALID( ld ) );
78
79         /* check client controls */
80         rc = ldap_int_client_controls( ld, cctrls );
81         if( rc != LDAP_SUCCESS ) return rc;
82
83         /*
84          * if timeout is provided, both tv_sec and tv_usec must
85          * not be zero
86          */
87         if( timeout != NULL ) {
88                 if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
89                         return LDAP_PARAM_ERROR;
90                 }
91
92                 /* timelimit must be non-zero if timeout is provided */
93                 timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
94
95         } else {
96                 /* no timeout, no timelimit */
97                 timelimit = -1;
98         }
99
100         ber = ldap_build_search_req( ld, base, scope, filter, attrs,
101             attrsonly, sctrls, cctrls, timelimit, sizelimit, &id ); 
102
103         if ( ber == NULL ) {
104                 return ld->ld_errno;
105         }
106
107
108         /* send the message */
109         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
110
111         if( *msgidp < 0 )
112                 return ld->ld_errno;
113
114         return LDAP_SUCCESS;
115 }
116
117 int
118 ldap_search_ext_s(
119         LDAP *ld,
120         LDAP_CONST char *base,
121         int scope,
122         LDAP_CONST char *filter,
123         char **attrs,
124         int attrsonly,
125         LDAPControl **sctrls,
126         LDAPControl **cctrls,
127         struct timeval *timeout,
128         int sizelimit,
129         LDAPMessage **res )
130 {
131         int rc;
132         int     msgid;
133
134         rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
135                 sctrls, cctrls, timeout, sizelimit, &msgid );
136
137         if ( rc != LDAP_SUCCESS ) {
138                 return( rc );
139         }
140
141         rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
142
143         if( rc <= 0 ) {
144                 /* error(-1) or timeout(0) */
145                 return( ld->ld_errno );
146         }
147
148         if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
149                 return( ld->ld_errno );
150         }
151
152         return( ldap_result2error( ld, *res, 0 ) );
153 }
154
155 /*
156  * ldap_search - initiate an ldap search operation.
157  *
158  * Parameters:
159  *
160  *      ld              LDAP descriptor
161  *      base            DN of the base object
162  *      scope           the search scope - one of
163  *                              LDAP_SCOPE_BASE (baseObject),
164  *                          LDAP_SCOPE_ONELEVEL (oneLevel),
165  *                              LDAP_SCOPE_SUBTREE (subtree), or
166  *                              LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
167  *      filter          a string containing the search filter
168  *                      (e.g., "(|(cn=bob)(sn=bob))")
169  *      attrs           list of attribute types to return for matches
170  *      attrsonly       1 => attributes only 0 => attributes and values
171  *
172  * Example:
173  *      char    *attrs[] = { "mail", "title", 0 };
174  *      msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
175  *          attrs, attrsonly );
176  */
177 int
178 ldap_search(
179         LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
180         char **attrs, int attrsonly )
181 {
182         BerElement      *ber;
183         ber_int_t       id;
184
185         Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
186
187         assert( ld != NULL );
188         assert( LDAP_VALID( ld ) );
189
190         ber = ldap_build_search_req( ld, base, scope, filter, attrs,
191             attrsonly, NULL, NULL, -1, -1, &id ); 
192
193         if ( ber == NULL ) {
194                 return( -1 );
195         }
196
197
198         /* send the message */
199         return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
200 }
201
202
203 BerElement *
204 ldap_build_search_req(
205         LDAP *ld,
206         LDAP_CONST char *base,
207         ber_int_t scope,
208         LDAP_CONST char *filter,
209         char **attrs,
210         ber_int_t attrsonly,
211         LDAPControl **sctrls,
212         LDAPControl **cctrls,
213         ber_int_t timelimit,
214         ber_int_t sizelimit,
215         ber_int_t *idp)
216 {
217         BerElement      *ber;
218         int             err;
219
220         /*
221          * Create the search request.  It looks like this:
222          *      SearchRequest := [APPLICATION 3] SEQUENCE {
223          *              baseObject      DistinguishedName,
224          *              scope           ENUMERATED {
225          *                      baseObject      (0),
226          *                      singleLevel     (1),
227          *                      wholeSubtree    (2)
228          *              },
229          *              derefAliases    ENUMERATED {
230          *                      neverDerefaliases       (0),
231          *                      derefInSearching        (1),
232          *                      derefFindingBaseObj     (2),
233          *                      alwaysDerefAliases      (3)
234          *              },
235          *              sizelimit       INTEGER (0 .. 65535),
236          *              timelimit       INTEGER (0 .. 65535),
237          *              attrsOnly       BOOLEAN,
238          *              filter          Filter,
239          *              attributes      SEQUENCE OF AttributeType
240          *      }
241          * wrapped in an ldap message.
242          */
243
244         /* create a message to send */
245         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
246                 return( NULL );
247         }
248
249         if ( base == NULL ) {
250                 /* no base provided, use session default base */
251                 base = ld->ld_options.ldo_defbase;
252
253                 if ( base == NULL ) {
254                         /* no session default base, use top */
255                         base = "";
256                 }
257         }
258
259         LDAP_NEXT_MSGID( ld, *idp );
260 #ifdef LDAP_CONNECTIONLESS
261         if ( LDAP_IS_UDP(ld) ) {
262                 struct sockaddr sa = {0};
263                 /* dummy, filled with ldo_peer in request.c */
264             err = ber_write( ber, &sa, sizeof( sa ), 0 );
265         }
266         if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
267             char *dn = ld->ld_options.ldo_cldapdn;
268             if (!dn) dn = "";
269             err = ber_printf( ber, "{ist{seeiib", *idp, dn,
270                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
271                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
272                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
273                 attrsonly );
274         } else
275 #endif
276         {
277             err = ber_printf( ber, "{it{seeiib", *idp,
278                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
279                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
280                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
281                 attrsonly );
282         }
283
284         if ( err == -1 ) {
285                 ld->ld_errno = LDAP_ENCODING_ERROR;
286                 ber_free( ber, 1 );
287                 return( NULL );
288         }
289
290         if( filter == NULL ) {
291                 filter = "(objectclass=*)";
292         }
293
294         err = ldap_pvt_put_filter( ber, filter );
295
296         if ( err  == -1 ) {
297                 ld->ld_errno = LDAP_FILTER_ERROR;
298                 ber_free( ber, 1 );
299                 return( NULL );
300         }
301
302 #ifdef LDAP_DEBUG
303         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
304                 char    buf[ BUFSIZ ] = { ' ', '*', '\0' };
305
306                 if ( attrs != NULL ) {
307                         char    *ptr;
308                         int     i;
309
310                         for ( ptr = buf, i = 0;
311                                 attrs[ i ] != NULL && ptr < &buf[ sizeof( buf ) ];
312                                 i++ )
313                         {
314                                 ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
315                                         " %s", attrs[ i ] );
316                         }
317
318                         if ( ptr >= &buf[ sizeof( buf ) ] ) {
319                                 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
320                                         "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
321                         } 
322                 }
323
324                 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", buf, 0, 0 );
325         }
326 #endif /* LDAP_DEBUG */
327
328         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
329                 ld->ld_errno = LDAP_ENCODING_ERROR;
330                 ber_free( ber, 1 );
331                 return( NULL );
332         }
333
334         /* Put Server Controls */
335         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
336                 ber_free( ber, 1 );
337                 return( NULL );
338         }
339
340         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
341                 ld->ld_errno = LDAP_ENCODING_ERROR;
342                 ber_free( ber, 1 );
343                 return( NULL );
344         }
345
346         return( ber );
347 }
348
349 int
350 ldap_search_st(
351         LDAP *ld, LDAP_CONST char *base, int scope,
352         LDAP_CONST char *filter, char **attrs,
353         int attrsonly, struct timeval *timeout, LDAPMessage **res )
354 {
355         int     msgid;
356
357         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
358             == -1 )
359                 return( ld->ld_errno );
360
361         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
362                 return( ld->ld_errno );
363
364         if ( ld->ld_errno == LDAP_TIMEOUT ) {
365                 (void) ldap_abandon( ld, msgid );
366                 ld->ld_errno = LDAP_TIMEOUT;
367                 return( ld->ld_errno );
368         }
369
370         return( ldap_result2error( ld, *res, 0 ) );
371 }
372
373 int
374 ldap_search_s(
375         LDAP *ld,
376         LDAP_CONST char *base,
377         int scope,
378         LDAP_CONST char *filter,
379         char **attrs,
380         int attrsonly,
381         LDAPMessage **res )
382 {
383         int     msgid;
384
385         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
386             == -1 )
387                 return( ld->ld_errno );
388
389         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
390                 return( ld->ld_errno );
391
392         return( ldap_result2error( ld, *res, 0 ) );
393 }
394
395 static char escape[128] = {
396         1, 1, 1, 1, 1, 1, 1, 1,
397         1, 1, 1, 1, 1, 1, 1, 1,
398         1, 1, 1, 1, 1, 1, 1, 1,
399         1, 1, 1, 1, 1, 1, 1, 1,
400
401         0, 0, 0, 0, 0, 0, 0, 0,
402         1, 1, 1, 0, 0, 0, 0, 0,
403         0, 0, 0, 0, 0, 0, 0, 0,
404         0, 0, 0, 0, 0, 0, 0, 0,
405
406         0, 0, 0, 0, 0, 0, 0, 0,
407         0, 0, 0, 0, 0, 0, 0, 0,
408         0, 0, 0, 0, 0, 0, 0, 0,
409         0, 0, 0, 0, 1, 0, 0, 0,
410
411         0, 0, 0, 0, 0, 0, 0, 0,
412         0, 0, 0, 0, 0, 0, 0, 0,
413         0, 0, 0, 0, 0, 0, 0, 0,
414         0, 0, 0, 0, 0, 0, 0, 1
415 };
416 #define NEEDFLTESCAPE(c)        ((c) & 0x80 || escape[ (unsigned)(c) ])
417
418 /*
419  * compute the length of the escaped value
420  */
421 ber_len_t
422 ldap_bv2escaped_filter_value_len( struct berval *in )
423 {
424         ber_len_t       i, l;
425
426         assert( in != NULL );
427
428         if ( in->bv_len == 0 ) {
429                 return 0;
430         }
431
432         for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
433                 char c = in->bv_val[ i ];
434                 if ( NEEDFLTESCAPE( c ) ) {
435                         l += 2;
436                 }
437         }
438
439         return l;
440 }
441
442 int
443 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
444 {
445         return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
446 }
447
448 int
449 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
450 {
451         ber_len_t       i, l;
452
453         assert( in != NULL );
454         assert( out != NULL );
455
456         BER_BVZERO( out );
457
458         if ( in->bv_len == 0 ) {
459                 return 0;
460         }
461
462         /* assume we'll escape everything */
463         l = ldap_bv2escaped_filter_value_len( in );
464         if ( l == in->bv_len ) {
465                 if ( inplace ) {
466                         *out = *in;
467                 } else {
468                         ber_dupbv( out, in );
469                 }
470                 return 0;
471         }
472         out->bv_val = LDAP_MALLOCX( l + 1, ctx );
473         if ( out->bv_val == NULL ) {
474                 return -1;
475         }
476
477         for ( i = 0; i < in->bv_len; i++ ) {
478                 char c = in->bv_val[ i ];
479                 if ( NEEDFLTESCAPE( c ) ) {
480                         assert( out->bv_len < l - 2 );
481                         out->bv_val[out->bv_len++] = '\\';
482                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
483                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
484
485                 } else {
486                         assert( out->bv_len < l );
487                         out->bv_val[out->bv_len++] = c;
488                 }
489         }
490
491         out->bv_val[out->bv_len] = '\0';
492
493         return 0;
494 }
495