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_int_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_int_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_int_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, ld->ld_deref,
319 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
320 (timelimit < 0) ? ld->ld_timelimit : timelimit,
325 ld->ld_errno = LDAP_ENCODING_ERROR;
330 if( filter == NULL ) {
331 filter = "(objectclass=*)";
334 err = ldap_pvt_put_filter( ber, filter );
337 ld->ld_errno = LDAP_FILTER_ERROR;
343 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
344 char buf[ BUFSIZ ], *ptr = " *";
346 if ( attrs != NULL ) {
347 int i, len, rest = sizeof( buf );
349 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
350 ptr = &buf[ sizeof( buf ) - rest ];
351 len = snprintf( ptr, rest, " %s", attrs[ i ] );
352 rest -= (len >= 0 ? len : (int) sizeof( buf ));
356 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
357 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
362 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
364 #endif /* LDAP_DEBUG */
366 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
367 ld->ld_errno = LDAP_ENCODING_ERROR;
372 /* Put Server Controls */
373 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
378 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
379 ld->ld_errno = LDAP_ENCODING_ERROR;
389 LDAP *ld, LDAP_CONST char *base, int scope,
390 LDAP_CONST char *filter, char **attrs,
391 int attrsonly, struct timeval *timeout, LDAPMessage **res )
395 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
397 return( ld->ld_errno );
399 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
400 return( ld->ld_errno );
402 if ( ld->ld_errno == LDAP_TIMEOUT ) {
403 (void) ldap_abandon( ld, msgid );
404 ld->ld_errno = LDAP_TIMEOUT;
405 return( ld->ld_errno );
408 return( ldap_result2error( ld, *res, 0 ) );
414 LDAP_CONST char *base,
416 LDAP_CONST char *filter,
423 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
425 return( ld->ld_errno );
427 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
428 return( ld->ld_errno );
430 return( ldap_result2error( ld, *res, 0 ) );
433 static char escape[128] = {
434 1, 1, 1, 1, 1, 1, 1, 1,
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,
439 0, 0, 0, 0, 0, 0, 0, 0,
440 1, 1, 1, 0, 0, 0, 0, 0,
441 0, 0, 0, 0, 0, 0, 0, 0,
442 0, 0, 0, 0, 0, 0, 0, 0,
444 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, 1, 0, 0, 0,
449 0, 0, 0, 0, 0, 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, 1
454 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
457 * compute the length of the escaped value
460 ldap_bv2escaped_filter_value_len( struct berval *in )
464 assert( in != NULL );
466 if ( in->bv_len == 0 ) {
470 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
471 char c = in->bv_val[ i ];
472 if ( NEEDFLTESCAPE( c ) ) {
481 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
483 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
487 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
491 assert( in != NULL );
492 assert( out != NULL );
496 if ( in->bv_len == 0 ) {
500 /* assume we'll escape everything */
501 l = ldap_bv2escaped_filter_value_len( in );
502 if ( l == in->bv_len ) {
506 ber_dupbv( out, in );
510 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
511 if ( out->bv_val == NULL ) {
515 for ( i = 0; i < in->bv_len; i++ ) {
516 char c = in->bv_val[ i ];
517 if ( NEEDFLTESCAPE( c ) ) {
518 assert( out->bv_len < l - 2 );
519 out->bv_val[out->bv_len++] = '\\';
520 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
521 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
524 assert( out->bv_len < l );
525 out->bv_val[out->bv_len++] = c;
529 out->bv_val[out->bv_len] = '\0';