]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
ITS#5916 - externally callable functions are ldap_pvt, not ldap_int.
[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, ld->ld_deref,
319                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
320                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
321                 attrsonly );
322         }
323
324         if ( err == -1 ) {
325                 ld->ld_errno = LDAP_ENCODING_ERROR;
326                 ber_free( ber, 1 );
327                 return( NULL );
328         }
329
330         if( filter == NULL ) {
331                 filter = "(objectclass=*)";
332         }
333
334         err = ldap_pvt_put_filter( ber, filter );
335
336         if ( err  == -1 ) {
337                 ld->ld_errno = LDAP_FILTER_ERROR;
338                 ber_free( ber, 1 );
339                 return( NULL );
340         }
341
342 #ifdef LDAP_DEBUG
343         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
344                 char    buf[ BUFSIZ ], *ptr = " *";
345
346                 if ( attrs != NULL ) {
347                         int     i, len, rest = sizeof( buf );
348
349                         for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
350                                 ptr = &buf[ sizeof( buf ) - rest ];
351                                 len = snprintf( ptr, rest, " %s", attrs[ i ] );
352                                 rest -= (len >= 0 ? len : (int) sizeof( buf ));
353                         }
354
355                         if ( rest <= 0 ) {
356                                 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
357                                         "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
358                         } 
359                         ptr = buf;
360                 }
361
362                 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
363         }
364 #endif /* LDAP_DEBUG */
365
366         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
367                 ld->ld_errno = LDAP_ENCODING_ERROR;
368                 ber_free( ber, 1 );
369                 return( NULL );
370         }
371
372         /* Put Server Controls */
373         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
374                 ber_free( ber, 1 );
375                 return( NULL );
376         }
377
378         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
379                 ld->ld_errno = LDAP_ENCODING_ERROR;
380                 ber_free( ber, 1 );
381                 return( NULL );
382         }
383
384         return( ber );
385 }
386
387 int
388 ldap_search_st(
389         LDAP *ld, LDAP_CONST char *base, int scope,
390         LDAP_CONST char *filter, char **attrs,
391         int attrsonly, struct timeval *timeout, LDAPMessage **res )
392 {
393         int     msgid;
394
395         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
396             == -1 )
397                 return( ld->ld_errno );
398
399         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
400                 return( ld->ld_errno );
401
402         if ( ld->ld_errno == LDAP_TIMEOUT ) {
403                 (void) ldap_abandon( ld, msgid );
404                 ld->ld_errno = LDAP_TIMEOUT;
405                 return( ld->ld_errno );
406         }
407
408         return( ldap_result2error( ld, *res, 0 ) );
409 }
410
411 int
412 ldap_search_s(
413         LDAP *ld,
414         LDAP_CONST char *base,
415         int scope,
416         LDAP_CONST char *filter,
417         char **attrs,
418         int attrsonly,
419         LDAPMessage **res )
420 {
421         int     msgid;
422
423         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
424             == -1 )
425                 return( ld->ld_errno );
426
427         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
428                 return( ld->ld_errno );
429
430         return( ldap_result2error( ld, *res, 0 ) );
431 }
432
433 static char escape[128] = {
434         1, 1, 1, 1, 1, 1, 1, 1,
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
439         0, 0, 0, 0, 0, 0, 0, 0,
440         1, 1, 1, 0, 0, 0, 0, 0,
441         0, 0, 0, 0, 0, 0, 0, 0,
442         0, 0, 0, 0, 0, 0, 0, 0,
443
444         0, 0, 0, 0, 0, 0, 0, 0,
445         0, 0, 0, 0, 0, 0, 0, 0,
446         0, 0, 0, 0, 0, 0, 0, 0,
447         0, 0, 0, 0, 1, 0, 0, 0,
448
449         0, 0, 0, 0, 0, 0, 0, 0,
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, 1
453 };
454 #define NEEDFLTESCAPE(c)        ((c) & 0x80 || escape[ (unsigned)(c) ])
455
456 /*
457  * compute the length of the escaped value
458  */
459 ber_len_t
460 ldap_bv2escaped_filter_value_len( struct berval *in )
461 {
462         ber_len_t       i, l;
463
464         assert( in != NULL );
465
466         if ( in->bv_len == 0 ) {
467                 return 0;
468         }
469
470         for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
471                 char c = in->bv_val[ i ];
472                 if ( NEEDFLTESCAPE( c ) ) {
473                         l += 2;
474                 }
475         }
476
477         return l;
478 }
479
480 int
481 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
482 {
483         return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
484 }
485
486 int
487 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
488 {
489         ber_len_t       i, l;
490
491         assert( in != NULL );
492         assert( out != NULL );
493
494         BER_BVZERO( out );
495
496         if ( in->bv_len == 0 ) {
497                 return 0;
498         }
499
500         /* assume we'll escape everything */
501         l = ldap_bv2escaped_filter_value_len( in );
502         if ( l == in->bv_len ) {
503                 if ( inplace ) {
504                         *out = *in;
505                 } else {
506                         ber_dupbv( out, in );
507                 }
508                 return 0;
509         }
510         out->bv_val = LDAP_MALLOCX( l + 1, ctx );
511         if ( out->bv_val == NULL ) {
512                 return -1;
513         }
514
515         for ( i = 0; i < in->bv_len; i++ ) {
516                 char c = in->bv_val[ i ];
517                 if ( NEEDFLTESCAPE( c ) ) {
518                         assert( out->bv_len < l - 2 );
519                         out->bv_val[out->bv_len++] = '\\';
520                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
521                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
522
523                 } else {
524                         assert( out->bv_len < l );
525                         out->bv_val[out->bv_len++] = c;
526                 }
527         }
528
529         out->bv_val[out->bv_len] = '\0';
530
531         return 0;
532 }
533