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