2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2009 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
15 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
16 * All rights reserved.
23 #include <ac/stdlib.h>
25 #include <ac/socket.h>
26 #include <ac/string.h>
33 * ldap_search_ext - initiate an ldap search operation.
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
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,
58 LDAP_CONST char *base,
60 LDAP_CONST char *filter,
65 struct timeval *timeout,
69 return ldap_pvt_search( ld, base, scope, filter, attrs,
70 attrsonly, sctrls, cctrls, timeout, sizelimit, -1, msgidp );
76 LDAP_CONST char *base,
78 LDAP_CONST char *filter,
83 struct timeval *timeout,
93 Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
96 assert( LDAP_VALID( ld ) );
98 /* check client controls */
99 rc = ldap_int_client_controls( ld, cctrls );
100 if( rc != LDAP_SUCCESS ) return rc;
103 * if timeout is provided, both tv_sec and tv_usec must
106 if( timeout != NULL ) {
107 if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
108 return LDAP_PARAM_ERROR;
111 /* timelimit must be non-zero if timeout is provided */
112 timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
115 /* no timeout, no timelimit */
119 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
120 attrsonly, sctrls, cctrls, timelimit, sizelimit, deref, &id );
127 /* send the message */
128 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
139 LDAP_CONST char *base,
141 LDAP_CONST char *filter,
144 LDAPControl **sctrls,
145 LDAPControl **cctrls,
146 struct timeval *timeout,
150 return ldap_pvt_search_s( ld, base, scope, filter, attrs,
151 attrsonly, sctrls, cctrls, timeout, sizelimit, -1, res );
157 LDAP_CONST char *base,
159 LDAP_CONST char *filter,
162 LDAPControl **sctrls,
163 LDAPControl **cctrls,
164 struct timeval *timeout,
172 rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly,
173 sctrls, cctrls, timeout, sizelimit, deref, &msgid );
175 if ( rc != LDAP_SUCCESS ) {
179 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
182 /* error(-1) or timeout(0) */
183 return( ld->ld_errno );
186 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
187 return( ld->ld_errno );
190 return( ldap_result2error( ld, *res, 0 ) );
194 * ldap_search - initiate an ldap search operation.
199 * base DN of the base object
200 * scope the search scope - one of
201 * LDAP_SCOPE_BASE (baseObject),
202 * LDAP_SCOPE_ONELEVEL (oneLevel),
203 * LDAP_SCOPE_SUBTREE (subtree), or
204 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
205 * filter a string containing the search filter
206 * (e.g., "(|(cn=bob)(sn=bob))")
207 * attrs list of attribute types to return for matches
208 * attrsonly 1 => attributes only 0 => attributes and values
211 * char *attrs[] = { "mail", "title", 0 };
212 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
213 * attrs, attrsonly );
217 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
218 char **attrs, int attrsonly )
223 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
225 assert( ld != NULL );
226 assert( LDAP_VALID( ld ) );
228 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
229 attrsonly, NULL, NULL, -1, -1, -1, &id );
236 /* send the message */
237 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
242 ldap_build_search_req(
244 LDAP_CONST char *base,
246 LDAP_CONST char *filter,
249 LDAPControl **sctrls,
250 LDAPControl **cctrls,
260 * Create the search request. It looks like this:
261 * SearchRequest := [APPLICATION 3] SEQUENCE {
262 * baseObject DistinguishedName,
268 * derefAliases ENUMERATED {
269 * neverDerefaliases (0),
270 * derefInSearching (1),
271 * derefFindingBaseObj (2),
272 * alwaysDerefAliases (3)
274 * sizelimit INTEGER (0 .. 65535),
275 * timelimit INTEGER (0 .. 65535),
278 * attributes SEQUENCE OF AttributeType
280 * wrapped in an ldap message.
283 /* create a message to send */
284 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
288 if ( base == NULL ) {
289 /* no base provided, use session default base */
290 base = ld->ld_options.ldo_defbase;
292 if ( base == NULL ) {
293 /* no session default base, use top */
298 LDAP_NEXT_MSGID( ld, *idp );
299 #ifdef LDAP_CONNECTIONLESS
300 if ( LDAP_IS_UDP(ld) ) {
301 struct sockaddr sa = {0};
302 /* dummy, filled with ldo_peer in request.c */
303 err = ber_write( ber, &sa, sizeof( sa ), 0 );
305 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
306 char *dn = ld->ld_options.ldo_cldapdn;
308 err = ber_printf( ber, "{ist{seeiib", *idp, dn,
309 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
310 (deref < 0) ? ld->ld_deref : deref,
311 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
312 (timelimit < 0) ? ld->ld_timelimit : timelimit,
317 err = ber_printf( ber, "{it{seeiib", *idp,
318 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
319 (deref < 0) ? ld->ld_deref : deref,
320 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
321 (timelimit < 0) ? ld->ld_timelimit : timelimit,
326 ld->ld_errno = LDAP_ENCODING_ERROR;
331 if( filter == NULL ) {
332 filter = "(objectclass=*)";
335 err = ldap_pvt_put_filter( ber, filter );
338 ld->ld_errno = LDAP_FILTER_ERROR;
344 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
345 char buf[ BUFSIZ ], *ptr = " *";
347 if ( attrs != NULL ) {
348 int i, len, rest = sizeof( buf );
350 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
351 ptr = &buf[ sizeof( buf ) - rest ];
352 len = snprintf( ptr, rest, " %s", attrs[ i ] );
353 rest -= (len >= 0 ? len : (int) sizeof( buf ));
357 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
358 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
363 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
365 #endif /* LDAP_DEBUG */
367 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
368 ld->ld_errno = LDAP_ENCODING_ERROR;
373 /* Put Server Controls */
374 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
379 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
380 ld->ld_errno = LDAP_ENCODING_ERROR;
390 LDAP *ld, LDAP_CONST char *base, int scope,
391 LDAP_CONST char *filter, char **attrs,
392 int attrsonly, struct timeval *timeout, LDAPMessage **res )
396 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
398 return( ld->ld_errno );
400 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
401 return( ld->ld_errno );
403 if ( ld->ld_errno == LDAP_TIMEOUT ) {
404 (void) ldap_abandon( ld, msgid );
405 ld->ld_errno = LDAP_TIMEOUT;
406 return( ld->ld_errno );
409 return( ldap_result2error( ld, *res, 0 ) );
415 LDAP_CONST char *base,
417 LDAP_CONST char *filter,
424 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
426 return( ld->ld_errno );
428 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
429 return( ld->ld_errno );
431 return( ldap_result2error( ld, *res, 0 ) );
434 static char escape[128] = {
435 1, 1, 1, 1, 1, 1, 1, 1,
436 1, 1, 1, 1, 1, 1, 1, 1,
437 1, 1, 1, 1, 1, 1, 1, 1,
438 1, 1, 1, 1, 1, 1, 1, 1,
440 0, 0, 0, 0, 0, 0, 0, 0,
441 1, 1, 1, 0, 0, 0, 0, 0,
442 0, 0, 0, 0, 0, 0, 0, 0,
443 0, 0, 0, 0, 0, 0, 0, 0,
445 0, 0, 0, 0, 0, 0, 0, 0,
446 0, 0, 0, 0, 0, 0, 0, 0,
447 0, 0, 0, 0, 0, 0, 0, 0,
448 0, 0, 0, 0, 1, 0, 0, 0,
450 0, 0, 0, 0, 0, 0, 0, 0,
451 0, 0, 0, 0, 0, 0, 0, 0,
452 0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 1
455 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
458 * compute the length of the escaped value
461 ldap_bv2escaped_filter_value_len( struct berval *in )
465 assert( in != NULL );
467 if ( in->bv_len == 0 ) {
471 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
472 char c = in->bv_val[ i ];
473 if ( NEEDFLTESCAPE( c ) ) {
482 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
484 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
488 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
492 assert( in != NULL );
493 assert( out != NULL );
497 if ( in->bv_len == 0 ) {
501 /* assume we'll escape everything */
502 l = ldap_bv2escaped_filter_value_len( in );
503 if ( l == in->bv_len ) {
507 ber_dupbv( out, in );
511 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
512 if ( out->bv_val == NULL ) {
516 for ( i = 0; i < in->bv_len; i++ ) {
517 char c = in->bv_val[ i ];
518 if ( NEEDFLTESCAPE( c ) ) {
519 assert( out->bv_len < l - 2 );
520 out->bv_val[out->bv_len++] = '\\';
521 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
522 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
525 assert( out->bv_len < l );
526 out->bv_val[out->bv_len++] = c;
530 out->bv_val[out->bv_len] = '\0';