]> git.sur5r.net Git - openldap/blob - libraries/libldap/search.c
ITS#4614 - complain if glue/subordinate are attempted on the same backend
[openldap] / libraries / libldap / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 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  * returns ((ber_len_t)(-1)) if no escaping is required.
420  */
421 ber_len_t
422 ldap_bv2escaped_filter_value_len( struct berval *in )
423 {
424         ber_len_t       i, l;
425
426         assert( in != NULL );
427
428         if ( in->bv_len == 0 ) {
429                 return 0;
430         }
431
432         /* assume we'll escape everything */
433         for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
434                 char c = in->bv_val[ i ];
435                 if ( NEEDFLTESCAPE( c ) ) {
436                         l += 2;
437                 }
438         }
439
440         return l;
441 }
442
443 int
444 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
445 {
446         return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
447 }
448
449 int
450 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
451 {
452         ber_len_t       i, l;
453
454         assert( in != NULL );
455         assert( out != NULL );
456
457         BER_BVZERO( out );
458
459         if ( in->bv_len == 0 ) {
460                 return 0;
461         }
462
463         /* assume we'll escape everything */
464         l = ldap_bv2escaped_filter_value_len( in );
465         if ( l == in->bv_len ) {
466                 if ( inplace ) {
467                         *out = *in;
468                 } else {
469                         ber_dupbv( out, in );
470                 }
471                 return 0;
472         }
473         out->bv_val = LDAP_MALLOCX( l + 1, ctx );
474         if ( out->bv_val == NULL ) {
475                 return -1;
476         }
477
478         for ( i = 0; i < in->bv_len; i++ ) {
479                 char c = in->bv_val[ i ];
480                 if ( NEEDFLTESCAPE( c ) ) {
481                         assert( out->bv_len < l - 2 );
482                         out->bv_val[out->bv_len++] = '\\';
483                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
484                         out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
485
486                 } else {
487                         assert( out->bv_len < l );
488                         out->bv_val[out->bv_len++] = c;
489                 }
490         }
491
492         out->bv_val[out->bv_len] = '\0';
493
494         return 0;
495 }
496