]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
fix ITS#3499 (may need further testing)
[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