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