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,
174 rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly,
175 sctrls, cctrls, timeout, sizelimit, deref, &msgid );
177 if ( rc != LDAP_SUCCESS ) {
181 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
184 /* error(-1) or timeout(0) */
185 return( ld->ld_errno );
188 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
189 return( ld->ld_errno );
192 return( ldap_result2error( ld, *res, 0 ) );
196 * ldap_search - initiate an ldap search operation.
201 * base DN of the base object
202 * scope the search scope - one of
203 * LDAP_SCOPE_BASE (baseObject),
204 * LDAP_SCOPE_ONELEVEL (oneLevel),
205 * LDAP_SCOPE_SUBTREE (subtree), or
206 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
207 * filter a string containing the search filter
208 * (e.g., "(|(cn=bob)(sn=bob))")
209 * attrs list of attribute types to return for matches
210 * attrsonly 1 => attributes only 0 => attributes and values
213 * char *attrs[] = { "mail", "title", 0 };
214 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
215 * attrs, attrsonly );
219 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
220 char **attrs, int attrsonly )
225 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
227 assert( ld != NULL );
228 assert( LDAP_VALID( ld ) );
230 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
231 attrsonly, NULL, NULL, -1, -1, -1, &id );
238 /* send the message */
239 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
244 ldap_build_search_req(
246 LDAP_CONST char *base,
248 LDAP_CONST char *filter,
251 LDAPControl **sctrls,
252 LDAPControl **cctrls,
262 * Create the search request. It looks like this:
263 * SearchRequest := [APPLICATION 3] SEQUENCE {
264 * baseObject DistinguishedName,
270 * derefAliases ENUMERATED {
271 * neverDerefaliases (0),
272 * derefInSearching (1),
273 * derefFindingBaseObj (2),
274 * alwaysDerefAliases (3)
276 * sizelimit INTEGER (0 .. 65535),
277 * timelimit INTEGER (0 .. 65535),
280 * attributes SEQUENCE OF AttributeType
282 * wrapped in an ldap message.
285 /* create a message to send */
286 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
290 if ( base == NULL ) {
291 /* no base provided, use session default base */
292 base = ld->ld_options.ldo_defbase;
294 if ( base == NULL ) {
295 /* no session default base, use top */
300 LDAP_NEXT_MSGID( ld, *idp );
301 #ifdef LDAP_CONNECTIONLESS
302 if ( LDAP_IS_UDP(ld) ) {
303 struct sockaddr sa = {0};
304 /* dummy, filled with ldo_peer in request.c */
305 err = ber_write( ber, &sa, sizeof( sa ), 0 );
307 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
308 char *dn = ld->ld_options.ldo_cldapdn;
310 err = ber_printf( ber, "{ist{seeiib", *idp, dn,
311 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
312 (deref < 0) ? ld->ld_deref : deref,
313 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
314 (timelimit < 0) ? ld->ld_timelimit : timelimit,
319 err = ber_printf( ber, "{it{seeiib", *idp,
320 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
321 (deref < 0) ? ld->ld_deref : deref,
322 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
323 (timelimit < 0) ? ld->ld_timelimit : timelimit,
328 ld->ld_errno = LDAP_ENCODING_ERROR;
333 if( filter == NULL ) {
334 filter = "(objectclass=*)";
337 err = ldap_pvt_put_filter( ber, filter );
340 ld->ld_errno = LDAP_FILTER_ERROR;
346 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
347 char buf[ BUFSIZ ], *ptr = " *";
349 if ( attrs != NULL ) {
350 int i, len, rest = sizeof( buf );
352 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
353 ptr = &buf[ sizeof( buf ) - rest ];
354 len = snprintf( ptr, rest, " %s", attrs[ i ] );
355 rest -= (len >= 0 ? len : (int) sizeof( buf ));
359 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
360 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
365 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
367 #endif /* LDAP_DEBUG */
369 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
370 ld->ld_errno = LDAP_ENCODING_ERROR;
375 /* Put Server Controls */
376 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
381 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
382 ld->ld_errno = LDAP_ENCODING_ERROR;
392 LDAP *ld, LDAP_CONST char *base, int scope,
393 LDAP_CONST char *filter, char **attrs,
394 int attrsonly, struct timeval *timeout, LDAPMessage **res )
400 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
402 return( ld->ld_errno );
404 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
405 return( ld->ld_errno );
407 if ( ld->ld_errno == LDAP_TIMEOUT ) {
408 (void) ldap_abandon( ld, msgid );
409 ld->ld_errno = LDAP_TIMEOUT;
410 return( ld->ld_errno );
413 return( ldap_result2error( ld, *res, 0 ) );
419 LDAP_CONST char *base,
421 LDAP_CONST char *filter,
430 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
432 return( ld->ld_errno );
434 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
435 return( ld->ld_errno );
437 return( ldap_result2error( ld, *res, 0 ) );
440 static char escape[128] = {
441 1, 1, 1, 1, 1, 1, 1, 1,
442 1, 1, 1, 1, 1, 1, 1, 1,
443 1, 1, 1, 1, 1, 1, 1, 1,
444 1, 1, 1, 1, 1, 1, 1, 1,
446 0, 0, 0, 0, 0, 0, 0, 0,
447 1, 1, 1, 0, 0, 0, 0, 0,
448 0, 0, 0, 0, 0, 0, 0, 0,
449 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, 0,
454 0, 0, 0, 0, 1, 0, 0, 0,
456 0, 0, 0, 0, 0, 0, 0, 0,
457 0, 0, 0, 0, 0, 0, 0, 0,
458 0, 0, 0, 0, 0, 0, 0, 0,
459 0, 0, 0, 0, 0, 0, 0, 1
461 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
464 * compute the length of the escaped value
467 ldap_bv2escaped_filter_value_len( struct berval *in )
471 assert( in != NULL );
473 if ( in->bv_len == 0 ) {
477 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
478 char c = in->bv_val[ i ];
479 if ( NEEDFLTESCAPE( c ) ) {
488 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
490 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
494 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
498 assert( in != NULL );
499 assert( out != NULL );
503 if ( in->bv_len == 0 ) {
507 /* assume we'll escape everything */
508 l = ldap_bv2escaped_filter_value_len( in );
509 if ( l == in->bv_len ) {
513 ber_dupbv( out, in );
517 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
518 if ( out->bv_val == NULL ) {
522 for ( i = 0; i < in->bv_len; i++ ) {
523 char c = in->bv_val[ i ];
524 if ( NEEDFLTESCAPE( c ) ) {
525 assert( out->bv_len < l - 2 );
526 out->bv_val[out->bv_len++] = '\\';
527 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
528 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
531 assert( out->bv_len < l );
532 out->bv_val[out->bv_len++] = c;
536 out->bv_val[out->bv_len] = '\0';