]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
happy new year
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 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             err = ber_write( ber, ld->ld_options.ldo_peer,
263                     sizeof(struct sockaddr), 0);
264         }
265         if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
266             char *dn = ld->ld_options.ldo_cldapdn;
267             if (!dn) dn = "";
268             err = ber_printf( ber, "{ist{seeiib", *idp, dn,
269                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
270                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
271                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
272                 attrsonly );
273         } else
274 #endif
275         {
276             err = ber_printf( ber, "{it{seeiib", *idp,
277                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
278                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
279                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
280                 attrsonly );
281         }
282
283         if ( err == -1 ) {
284                 ld->ld_errno = LDAP_ENCODING_ERROR;
285                 ber_free( ber, 1 );
286                 return( NULL );
287         }
288
289         if( filter == NULL ) {
290                 filter = "(objectclass=*)";
291         }
292
293         err = ldap_pvt_put_filter( ber, filter );
294
295         if ( err  == -1 ) {
296                 ld->ld_errno = LDAP_FILTER_ERROR;
297                 ber_free( ber, 1 );
298                 return( NULL );
299         }
300
301 #ifdef LDAP_DEBUG
302         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
303                 char    buf[ BUFSIZ ] = { ' ', '*', '\0' };
304
305                 if ( attrs != NULL ) {
306                         char    *ptr;
307                         int     i;
308
309                         for ( ptr = buf, i = 0;
310                                 attrs[ i ] != NULL && ptr < &buf[ sizeof( buf ) ];
311                                 i++ )
312                         {
313                                 ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
314                                         " %s", attrs[ i ] );
315                         }
316
317                         if ( ptr >= &buf[ sizeof( buf ) ] ) {
318                                 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
319                                         "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
320                         } 
321                 }
322
323                 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", buf, 0, 0 );
324         }
325 #endif /* LDAP_DEBUG */
326
327         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
328                 ld->ld_errno = LDAP_ENCODING_ERROR;
329                 ber_free( ber, 1 );
330                 return( NULL );
331         }
332
333         /* Put Server Controls */
334         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
335                 ber_free( ber, 1 );
336                 return( NULL );
337         }
338
339         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
340                 ld->ld_errno = LDAP_ENCODING_ERROR;
341                 ber_free( ber, 1 );
342                 return( NULL );
343         }
344
345         return( ber );
346 }
347
348 int
349 ldap_search_st(
350         LDAP *ld, LDAP_CONST char *base, int scope,
351         LDAP_CONST char *filter, char **attrs,
352         int attrsonly, struct timeval *timeout, LDAPMessage **res )
353 {
354         int     msgid;
355
356         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
357             == -1 )
358                 return( ld->ld_errno );
359
360         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 )
361                 return( ld->ld_errno );
362
363         if ( ld->ld_errno == LDAP_TIMEOUT ) {
364                 (void) ldap_abandon( ld, msgid );
365                 ld->ld_errno = LDAP_TIMEOUT;
366                 return( ld->ld_errno );
367         }
368
369         return( ldap_result2error( ld, *res, 0 ) );
370 }
371
372 int
373 ldap_search_s(
374         LDAP *ld,
375         LDAP_CONST char *base,
376         int scope,
377         LDAP_CONST char *filter,
378         char **attrs,
379         int attrsonly,
380         LDAPMessage **res )
381 {
382         int     msgid;
383
384         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
385             == -1 )
386                 return( ld->ld_errno );
387
388         if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 )
389                 return( ld->ld_errno );
390
391         return( ldap_result2error( ld, *res, 0 ) );
392 }
393
394 static char escape[128] = {
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         1, 1, 1, 1, 1, 1, 1, 1,
399
400         0, 0, 0, 0, 0, 0, 0, 0,
401         1, 1, 1, 0, 0, 0, 0, 0,
402         0, 0, 0, 0, 0, 0, 0, 0,
403         0, 0, 0, 0, 0, 0, 0, 0,
404
405         0, 0, 0, 0, 0, 0, 0, 0,
406         0, 0, 0, 0, 0, 0, 0, 0,
407         0, 0, 0, 0, 0, 0, 0, 0,
408         0, 0, 0, 0, 1, 0, 0, 0,
409
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, 0,
413         0, 0, 0, 0, 0, 0, 0, 1
414 };
415 #define NEEDFLTESCAPE(c)        ((c) & 0x80 || escape[ (unsigned)(c) ])
416
417 /*
418  * compute the length of the escaped value
419  */
420 ber_len_t
421 ldap_bv2escaped_filter_value_len( struct berval *in )
422 {
423         ber_len_t       i, l;
424
425         assert( in != NULL );
426
427         if ( in->bv_len == 0 ) {
428                 return 0;
429         }
430
431         for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
432                 char c = in->bv_val[ i ];
433                 if ( NEEDFLTESCAPE( c ) ) {
434                         l += 2;
435                 }
436         }
437
438         return l;
439 }
440
441 int
442 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
443 {
444         return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
445 }
446
447 int
448 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
449 {
450         ber_len_t       i, l;
451
452         assert( in != NULL );
453         assert( out != NULL );
454
455         BER_BVZERO( out );
456
457         if ( in->bv_len == 0 ) {
458                 return 0;
459         }
460
461         /* assume we'll escape everything */
462         l = ldap_bv2escaped_filter_value_len( in );
463         if ( l == in->bv_len ) {
464                 if ( inplace ) {
465                         *out = *in;
466                 } else {
467                         ber_dupbv( out, in );
468                 }
469                 return 0;
470         }
471         out->bv_val = LDAP_MALLOCX( l + 1, ctx );
472         if ( out->bv_val == NULL ) {
473                 return -1;
474         }
475
476         for ( i = 0; i < in->bv_len; i++ ) {
477                 char c = in->bv_val[ i ];
478                 if ( NEEDFLTESCAPE( c ) ) {
479                         assert( out->bv_len < l - 2 );
480                         out->bv_val[out->bv_len++] = '\\';
481                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
482                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
483
484                 } else {
485                         assert( out->bv_len < l );
486                         out->bv_val[out->bv_len++] = c;
487                 }
488         }
489
490         out->bv_val[out->bv_len] = '\0';
491
492         return 0;
493 }
494