]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
We'll need queue macros in -llber...
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1990 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  search.c
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18
19 #include <ac/socket.h>
20 #include <ac/string.h>
21 #include <ac/time.h>
22
23 #include "ldap-int.h"
24
25
26 /*
27  * ldap_search_ext - initiate an ldap search operation.
28  *
29  * Parameters:
30  *
31  *      ld              LDAP descriptor
32  *      base            DN of the base object
33  *      scope           the search scope - one of LDAP_SCOPE_BASE,
34  *                          LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
35  *      filter          a string containing the search filter
36  *                      (e.g., "(|(cn=bob)(sn=bob))")
37  *      attrs           list of attribute types to return for matches
38  *      attrsonly       1 => attributes only 0 => attributes and values
39  *
40  * Example:
41  *      char    *attrs[] = { "mail", "title", 0 };
42  *      ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
43  *          attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
44  *              &msgid );
45  */
46 int
47 ldap_search_ext(
48         LDAP *ld,
49         LDAP_CONST char *base,
50         int scope,
51         LDAP_CONST char *filter,
52         char **attrs,
53         int attrsonly,
54         LDAPControl **sctrls,
55         LDAPControl **cctrls,
56         struct timeval *timeout,
57         int sizelimit,
58         int *msgidp )
59 {
60         int rc;
61         BerElement      *ber;
62         int timelimit;
63
64         Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
65
66         assert( ld != NULL );
67         assert( LDAP_VALID( ld ) );
68
69         /* check client controls */
70         rc = ldap_int_client_controls( ld, cctrls );
71         if( rc != LDAP_SUCCESS ) return rc;
72
73         /*
74          * if timeout is provided, both tv_sec and tv_usec must
75          * be non-zero
76          */
77         if( timeout != NULL ) {
78                 if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
79                         return LDAP_PARAM_ERROR;
80                 }
81
82                 /* timelimit must be non-zero if timeout is provided */
83                 timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
84
85         } else {
86                 /* no timeout, no timelimit */
87                 timelimit = -1;
88         }
89
90         ber = ldap_build_search_req( ld, base, scope, filter, attrs,
91             attrsonly, sctrls, cctrls, timelimit, sizelimit ); 
92
93         if ( ber == NULL ) {
94                 return ld->ld_errno;
95         }
96
97 #ifndef LDAP_NOCACHE
98         if ( ld->ld_cache != NULL ) {
99                 if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
100                         ber_free( ber, 1 );
101                         ld->ld_errno = LDAP_SUCCESS;
102                         *msgidp = ld->ld_msgid;
103                         return ld->ld_errno;
104                 }
105                 ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
106         }
107 #endif /* LDAP_NOCACHE */
108
109         /* send the message */
110         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber );
111
112         if( *msgidp < 0 )
113                 return ld->ld_errno;
114
115         return LDAP_SUCCESS;
116 }
117
118 int
119 ldap_search_ext_s(
120         LDAP *ld,
121         LDAP_CONST char *base,
122         int scope,
123         LDAP_CONST char *filter,
124         char **attrs,
125         int attrsonly,
126         LDAPControl **sctrls,
127         LDAPControl **cctrls,
128         struct timeval *timeout,
129         int sizelimit,
130         LDAPMessage **res )
131 {
132         int rc;
133         int     msgid;
134
135         rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
136                 sctrls, cctrls, timeout, sizelimit, &msgid );
137
138         if ( rc != LDAP_SUCCESS ) {
139                 return( rc );
140         }
141
142         rc = ldap_result( ld, msgid, 1, timeout, res );
143
144         if( rc <= 0 ) {
145                 /* error(-1) or timeout(0) */
146                 return( ld->ld_errno );
147         }
148
149         if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_EXTENDED_PARTIAL ) {
150                 return( ld->ld_errno );
151         }
152
153         return( ldap_result2error( ld, *res, 0 ) );
154 }
155
156 /*
157  * ldap_search - initiate an ldap search operation.
158  *
159  * Parameters:
160  *
161  *      ld              LDAP descriptor
162  *      base            DN of the base object
163  *      scope           the search scope - one of LDAP_SCOPE_BASE,
164  *                          LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
165  *      filter          a string containing the search filter
166  *                      (e.g., "(|(cn=bob)(sn=bob))")
167  *      attrs           list of attribute types to return for matches
168  *      attrsonly       1 => attributes only 0 => attributes and values
169  *
170  * Example:
171  *      char    *attrs[] = { "mail", "title", 0 };
172  *      msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
173  *          attrs, attrsonly );
174  */
175 int
176 ldap_search(
177         LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
178         char **attrs, int attrsonly )
179 {
180         BerElement      *ber;
181
182         Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
183
184         assert( ld != NULL );
185         assert( LDAP_VALID( ld ) );
186
187         ber = ldap_build_search_req( ld, base, scope, filter, attrs,
188             attrsonly, NULL, NULL, -1, -1 ); 
189
190         if ( ber == NULL ) {
191                 return( -1 );
192         }
193
194 #ifndef LDAP_NOCACHE
195         if ( ld->ld_cache != NULL ) {
196                 if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
197                         ber_free( ber, 1 );
198                         ld->ld_errno = LDAP_SUCCESS;
199                         return( ld->ld_msgid );
200                 }
201                 ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
202         }
203 #endif /* LDAP_NOCACHE */
204
205         /* send the message */
206         return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
207 }
208
209
210 BerElement *
211 ldap_build_search_req(
212         LDAP *ld,
213         LDAP_CONST char *base,
214         ber_int_t scope,
215         LDAP_CONST char *filter_in,
216         char **attrs,
217         ber_int_t attrsonly,
218         LDAPControl **sctrls,
219         LDAPControl **cctrls,
220         ber_int_t timelimit,
221         ber_int_t sizelimit )
222 {
223         BerElement      *ber;
224         int             err;
225         char    *filter;
226
227         /*
228          * Create the search request.  It looks like this:
229          *      SearchRequest := [APPLICATION 3] SEQUENCE {
230          *              baseObject      DistinguishedName,
231          *              scope           ENUMERATED {
232          *                      baseObject      (0),
233          *                      singleLevel     (1),
234          *                      wholeSubtree    (2)
235          *              },
236          *              derefAliases    ENUMERATED {
237          *                      neverDerefaliases       (0),
238          *                      derefInSearching        (1),
239          *                      derefFindingBaseObj     (2),
240          *                      alwaysDerefAliases      (3)
241          *              },
242          *              sizelimit       INTEGER (0 .. 65535),
243          *              timelimit       INTEGER (0 .. 65535),
244          *              attrsOnly       BOOLEAN,
245          *              filter          Filter,
246          *              attributes      SEQUENCE OF AttributeType
247          *      }
248          * wrapped in an ldap message.
249          */
250
251         /* create a message to send */
252         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
253                 return( NULL );
254         }
255
256         if ( base == NULL ) {
257                 /* no base provided, use session default base */
258                 base = ld->ld_options.ldo_defbase;
259
260                 if ( base == NULL ) {
261                         /* no session default base, use top */
262                         base = "";
263                 }
264         }
265
266 #ifdef LDAP_CONNECTIONLESS
267         if ( LDAP_IS_UDP(ld) ) {
268             err = ber_write( ber, ld->ld_options.ldo_peer,
269                     sizeof(struct sockaddr), 0);
270         }
271         if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
272             char *dn = ld->ld_options.ldo_cldapdn;
273             if (!dn) dn = "";
274             err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid, dn,
275                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
276                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
277                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
278                 attrsonly );
279         } else
280 #endif
281         {
282             err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
283                 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
284                 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
285                 (timelimit < 0) ? ld->ld_timelimit : timelimit,
286                 attrsonly );
287         }
288
289         if ( err == -1 ) {
290                 ld->ld_errno = LDAP_ENCODING_ERROR;
291                 ber_free( ber, 1 );
292                 return( NULL );
293         }
294
295         if( filter_in != NULL ) {
296                 filter = LDAP_STRDUP( filter_in );
297         } else {
298                 filter = LDAP_STRDUP( "(objectclass=*)" );
299         }
300         err = ldap_int_put_filter( ber, filter );
301         LDAP_FREE( filter );
302
303         if ( err  == -1 ) {
304                 ld->ld_errno = LDAP_FILTER_ERROR;
305                 ber_free( ber, 1 );
306                 return( NULL );
307         }
308
309         if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
310                 ld->ld_errno = LDAP_ENCODING_ERROR;
311                 ber_free( ber, 1 );
312                 return( NULL );
313         }
314
315         /* Put Server Controls */
316         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
317                 ber_free( ber, 1 );
318                 return( NULL );
319         }
320
321         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
322                 ld->ld_errno = LDAP_ENCODING_ERROR;
323                 ber_free( ber, 1 );
324                 return( NULL );
325         }
326
327         return( ber );
328 }
329
330 int
331 ldap_search_st(
332         LDAP *ld, LDAP_CONST char *base, int scope,
333         LDAP_CONST char *filter, char **attrs,
334         int attrsonly, struct timeval *timeout, LDAPMessage **res )
335 {
336         int     msgid;
337
338         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
339             == -1 )
340                 return( ld->ld_errno );
341
342         if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
343                 return( ld->ld_errno );
344
345         if ( ld->ld_errno == LDAP_TIMEOUT ) {
346                 (void) ldap_abandon( ld, msgid );
347                 ld->ld_errno = LDAP_TIMEOUT;
348                 return( ld->ld_errno );
349         }
350
351         return( ldap_result2error( ld, *res, 0 ) );
352 }
353
354 int
355 ldap_search_s(
356         LDAP *ld,
357         LDAP_CONST char *base,
358         int scope,
359         LDAP_CONST char *filter,
360         char **attrs,
361         int attrsonly,
362         LDAPMessage **res )
363 {
364         int     msgid;
365
366         if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
367             == -1 )
368                 return( ld->ld_errno );
369
370         if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
371                 return( ld->ld_errno );
372
373         return( ldap_result2error( ld, *res, 0 ) );
374 }
375