]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
5ae25a366c5d7b9abfef3f22f8c6e39e9e63c0cf
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2009 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 ], *ptr = " *";
305
306                 if ( attrs != NULL ) {
307                         int     i, len, rest = sizeof( buf );
308
309                         for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
310                                 ptr = &buf[ sizeof( buf ) - rest ];
311                                 len = snprintf( ptr, rest, " %s", attrs[ i ] );
312                                 rest -= (len >= 0 ? len : (int) sizeof( buf ));
313                         }
314
315                         if ( rest <= 0 ) {
316                                 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
317                                         "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
318                         } 
319                         ptr = buf;
320                 }
321
322                 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
323         }
324 #endif /* LDAP_DEBUG */
325
326         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
327                 ld->ld_errno = LDAP_ENCODING_ERROR;
328                 ber_free( ber, 1 );
329                 return( NULL );
330         }
331
332         /* Put Server Controls */
333         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
334                 ber_free( ber, 1 );
335                 return( NULL );
336         }
337
338         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
339                 ld->ld_errno = LDAP_ENCODING_ERROR;
340                 ber_free( ber, 1 );
341                 return( NULL );
342         }
343
344         return( ber );
345 }
346
347 int
348 ldap_search_st(
349         LDAP *ld, LDAP_CONST char *base, int scope,
350         LDAP_CONST char *filter, char **attrs,
351         int attrsonly, struct timeval *timeout, LDAPMessage **res )
352 {
353         int     msgid;
354
355         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
356             == -1 )
357                 return( ld->ld_errno );
358
359         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
360                 return( ld->ld_errno );
361
362         if ( ld->ld_errno == LDAP_TIMEOUT ) {
363                 (void) ldap_abandon( ld, msgid );
364                 ld->ld_errno = LDAP_TIMEOUT;
365                 return( ld->ld_errno );
366         }
367
368         return( ldap_result2error( ld, *res, 0 ) );
369 }
370
371 int
372 ldap_search_s(
373         LDAP *ld,
374         LDAP_CONST char *base,
375         int scope,
376         LDAP_CONST char *filter,
377         char **attrs,
378         int attrsonly,
379         LDAPMessage **res )
380 {
381         int     msgid;
382
383         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
384             == -1 )
385                 return( ld->ld_errno );
386
387         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
388                 return( ld->ld_errno );
389
390         return( ldap_result2error( ld, *res, 0 ) );
391 }
392
393 static char escape[128] = {
394         1, 1, 1, 1, 1, 1, 1, 1,
395         1, 1, 1, 1, 1, 1, 1, 1,
396         1, 1, 1, 1, 1, 1, 1, 1,
397         1, 1, 1, 1, 1, 1, 1, 1,
398
399         0, 0, 0, 0, 0, 0, 0, 0,
400         1, 1, 1, 0, 0, 0, 0, 0,
401         0, 0, 0, 0, 0, 0, 0, 0,
402         0, 0, 0, 0, 0, 0, 0, 0,
403
404         0, 0, 0, 0, 0, 0, 0, 0,
405         0, 0, 0, 0, 0, 0, 0, 0,
406         0, 0, 0, 0, 0, 0, 0, 0,
407         0, 0, 0, 0, 1, 0, 0, 0,
408
409         0, 0, 0, 0, 0, 0, 0, 0,
410         0, 0, 0, 0, 0, 0, 0, 0,
411         0, 0, 0, 0, 0, 0, 0, 0,
412         0, 0, 0, 0, 0, 0, 0, 1
413 };
414 #define NEEDFLTESCAPE(c)        ((c) & 0x80 || escape[ (unsigned)(c) ])
415
416 /*
417  * compute the length of the escaped value
418  */
419 ber_len_t
420 ldap_bv2escaped_filter_value_len( struct berval *in )
421 {
422         ber_len_t       i, l;
423
424         assert( in != NULL );
425
426         if ( in->bv_len == 0 ) {
427                 return 0;
428         }
429
430         for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
431                 char c = in->bv_val[ i ];
432                 if ( NEEDFLTESCAPE( c ) ) {
433                         l += 2;
434                 }
435         }
436
437         return l;
438 }
439
440 int
441 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
442 {
443         return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
444 }
445
446 int
447 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
448 {
449         ber_len_t       i, l;
450
451         assert( in != NULL );
452         assert( out != NULL );
453
454         BER_BVZERO( out );
455
456         if ( in->bv_len == 0 ) {
457                 return 0;
458         }
459
460         /* assume we'll escape everything */
461         l = ldap_bv2escaped_filter_value_len( in );
462         if ( l == in->bv_len ) {
463                 if ( inplace ) {
464                         *out = *in;
465                 } else {
466                         ber_dupbv( out, in );
467                 }
468                 return 0;
469         }
470         out->bv_val = LDAP_MALLOCX( l + 1, ctx );
471         if ( out->bv_val == NULL ) {
472                 return -1;
473         }
474
475         for ( i = 0; i < in->bv_len; i++ ) {
476                 char c = in->bv_val[ i ];
477                 if ( NEEDFLTESCAPE( c ) ) {
478                         assert( out->bv_len < l - 2 );
479                         out->bv_val[out->bv_len++] = '\\';
480                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
481                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
482
483                 } else {
484                         assert( out->bv_len < l );
485                         out->bv_val[out->bv_len++] = c;
486                 }
487         }
488
489         out->bv_val[out->bv_len] = '\0';
490
491         return 0;
492 }
493