]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
Sync with HEAD
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2005 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, 1, 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         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
302                 ld->ld_errno = LDAP_ENCODING_ERROR;
303                 ber_free( ber, 1 );
304                 return( NULL );
305         }
306
307         /* Put Server Controls */
308         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
309                 ber_free( ber, 1 );
310                 return( NULL );
311         }
312
313         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
314                 ld->ld_errno = LDAP_ENCODING_ERROR;
315                 ber_free( ber, 1 );
316                 return( NULL );
317         }
318
319         return( ber );
320 }
321
322 int
323 ldap_search_st(
324         LDAP *ld, LDAP_CONST char *base, int scope,
325         LDAP_CONST char *filter, char **attrs,
326         int attrsonly, struct timeval *timeout, LDAPMessage **res )
327 {
328         int     msgid;
329
330         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
331             == -1 )
332                 return( ld->ld_errno );
333
334         if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
335                 return( ld->ld_errno );
336
337         if ( ld->ld_errno == LDAP_TIMEOUT ) {
338                 (void) ldap_abandon( ld, msgid );
339                 ld->ld_errno = LDAP_TIMEOUT;
340                 return( ld->ld_errno );
341         }
342
343         return( ldap_result2error( ld, *res, 0 ) );
344 }
345
346 int
347 ldap_search_s(
348         LDAP *ld,
349         LDAP_CONST char *base,
350         int scope,
351         LDAP_CONST char *filter,
352         char **attrs,
353         int attrsonly,
354         LDAPMessage **res )
355 {
356         int     msgid;
357
358         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
359             == -1 )
360                 return( ld->ld_errno );
361
362         if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
363                 return( ld->ld_errno );
364
365         return( ldap_result2error( ld, *res, 0 ) );
366 }
367
368 int
369 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
370 {
371         char c;
372         ber_len_t i;
373         static char escape[128] = {
374                 1, 1, 1, 1, 1, 1, 1, 1,
375                 1, 1, 1, 1, 1, 1, 1, 1,
376                 1, 1, 1, 1, 1, 1, 1, 1,
377                 1, 1, 1, 1, 1, 1, 1, 1,
378
379                 1, 1, 1, 0, 0, 0, 0, 0,
380                 0, 0, 0, 0, 0, 0, 0, 0,
381                 0, 0, 0, 0, 0, 0, 0, 0,
382                 0, 0, 0, 0, 0, 0, 0, 0,
383
384                 0, 0, 0, 0, 0, 0, 0, 0,
385                 0, 0, 0, 0, 0, 0, 0, 0,
386                 0, 0, 0, 0, 0, 0, 0, 0,
387                 0, 0, 0, 0, 1, 0, 0, 0,
388
389                 0, 0, 0, 0, 0, 0, 0, 0,
390                 0, 0, 0, 0, 0, 0, 0, 0,
391                 0, 0, 0, 0, 0, 0, 0, 0,
392                 0, 0, 0, 0, 0, 0, 0, 1
393         };
394
395         out->bv_len = 0;
396         out->bv_val = NULL;
397
398         if( in->bv_len == 0 ) return 0;
399
400         /* assume we'll escape everything */
401         out->bv_val = LDAP_MALLOC( 3 * in->bv_len + 1 );
402         if( out->bv_val == NULL ) return -1;
403
404         for( i=0; i<in->bv_len; i++ ) {
405                 if (c & 0x80 || escape[in->bv_val[i]]) {
406                         out->bv_val[out->bv_len++] = '\\';
407                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
408                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
409                 } else {
410                         out->bv_val[out->bv_len++] = c;
411                 }
412         }
413
414         out->bv_val[out->bv_len] = '\0';
415         return 0;
416 }
417