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