2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2012 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 if ( ld->ld_errno == LDAP_TIMEOUT ) {
186 /* cleanup request */
187 (void) ldap_abandon( ld, msgid );
188 ld->ld_errno = LDAP_TIMEOUT;
190 return( ld->ld_errno );
193 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
194 return( ld->ld_errno );
197 return( ldap_result2error( ld, *res, 0 ) );
201 * ldap_search - initiate an ldap search operation.
206 * base DN of the base object
207 * scope the search scope - one of
208 * LDAP_SCOPE_BASE (baseObject),
209 * LDAP_SCOPE_ONELEVEL (oneLevel),
210 * LDAP_SCOPE_SUBTREE (subtree), or
211 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
212 * filter a string containing the search filter
213 * (e.g., "(|(cn=bob)(sn=bob))")
214 * attrs list of attribute types to return for matches
215 * attrsonly 1 => attributes only 0 => attributes and values
218 * char *attrs[] = { "mail", "title", 0 };
219 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
220 * attrs, attrsonly );
224 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
225 char **attrs, int attrsonly )
230 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
232 assert( ld != NULL );
233 assert( LDAP_VALID( ld ) );
235 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
236 attrsonly, NULL, NULL, -1, -1, -1, &id );
243 /* send the message */
244 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
249 ldap_build_search_req(
251 LDAP_CONST char *base,
253 LDAP_CONST char *filter,
256 LDAPControl **sctrls,
257 LDAPControl **cctrls,
267 * Create the search request. It looks like this:
268 * SearchRequest := [APPLICATION 3] SEQUENCE {
269 * baseObject DistinguishedName,
275 * derefAliases ENUMERATED {
276 * neverDerefaliases (0),
277 * derefInSearching (1),
278 * derefFindingBaseObj (2),
279 * alwaysDerefAliases (3)
281 * sizelimit INTEGER (0 .. 65535),
282 * timelimit INTEGER (0 .. 65535),
285 * attributes SEQUENCE OF AttributeType
287 * wrapped in an ldap message.
290 /* create a message to send */
291 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
295 if ( base == NULL ) {
296 /* no base provided, use session default base */
297 base = ld->ld_options.ldo_defbase;
299 if ( base == NULL ) {
300 /* no session default base, use top */
305 LDAP_NEXT_MSGID( ld, *idp );
306 #ifdef LDAP_CONNECTIONLESS
307 if ( LDAP_IS_UDP(ld) ) {
308 struct sockaddr sa = {0};
309 /* dummy, filled with ldo_peer in request.c */
310 err = ber_write( ber, (char *) &sa, sizeof( sa ), 0 );
312 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
313 char *dn = ld->ld_options.ldo_cldapdn;
315 err = ber_printf( ber, "{ist{seeiib", *idp, dn,
316 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
317 (deref < 0) ? ld->ld_deref : deref,
318 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
319 (timelimit < 0) ? ld->ld_timelimit : timelimit,
324 err = ber_printf( ber, "{it{seeiib", *idp,
325 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
326 (deref < 0) ? ld->ld_deref : deref,
327 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
328 (timelimit < 0) ? ld->ld_timelimit : timelimit,
333 ld->ld_errno = LDAP_ENCODING_ERROR;
338 if( filter == NULL ) {
339 filter = "(objectclass=*)";
342 err = ldap_pvt_put_filter( ber, filter );
345 ld->ld_errno = LDAP_FILTER_ERROR;
351 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
352 char buf[ BUFSIZ ], *ptr = " *";
354 if ( attrs != NULL ) {
355 int i, len, rest = sizeof( buf );
357 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
358 ptr = &buf[ sizeof( buf ) - rest ];
359 len = snprintf( ptr, rest, " %s", attrs[ i ] );
360 rest -= (len >= 0 ? len : (int) sizeof( buf ));
364 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
365 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
370 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
372 #endif /* LDAP_DEBUG */
374 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
375 ld->ld_errno = LDAP_ENCODING_ERROR;
380 /* Put Server Controls */
381 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
386 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
387 ld->ld_errno = LDAP_ENCODING_ERROR;
397 LDAP *ld, LDAP_CONST char *base, int scope,
398 LDAP_CONST char *filter, char **attrs,
399 int attrsonly, struct timeval *timeout, LDAPMessage **res )
405 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
407 return( ld->ld_errno );
409 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
410 return( ld->ld_errno );
412 if ( ld->ld_errno == LDAP_TIMEOUT ) {
413 (void) ldap_abandon( ld, msgid );
414 ld->ld_errno = LDAP_TIMEOUT;
415 return( ld->ld_errno );
418 return( ldap_result2error( ld, *res, 0 ) );
424 LDAP_CONST char *base,
426 LDAP_CONST char *filter,
435 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
437 return( ld->ld_errno );
439 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
440 return( ld->ld_errno );
442 return( ldap_result2error( ld, *res, 0 ) );
445 static char escape[128] = {
446 1, 1, 1, 1, 1, 1, 1, 1,
447 1, 1, 1, 1, 1, 1, 1, 1,
448 1, 1, 1, 1, 1, 1, 1, 1,
449 1, 1, 1, 1, 1, 1, 1, 1,
451 0, 0, 0, 0, 0, 0, 0, 0,
452 1, 1, 1, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 0,
454 0, 0, 0, 0, 0, 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, 1, 0, 0, 0,
461 0, 0, 0, 0, 0, 0, 0, 0,
462 0, 0, 0, 0, 0, 0, 0, 0,
463 0, 0, 0, 0, 0, 0, 0, 0,
464 0, 0, 0, 0, 0, 0, 0, 1
466 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
469 * compute the length of the escaped value
472 ldap_bv2escaped_filter_value_len( struct berval *in )
476 assert( in != NULL );
478 if ( in->bv_len == 0 ) {
482 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
483 char c = in->bv_val[ i ];
484 if ( NEEDFLTESCAPE( c ) ) {
493 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
495 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
499 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
503 assert( in != NULL );
504 assert( out != NULL );
508 if ( in->bv_len == 0 ) {
512 /* assume we'll escape everything */
513 l = ldap_bv2escaped_filter_value_len( in );
514 if ( l == in->bv_len ) {
518 ber_dupbv( out, in );
522 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
523 if ( out->bv_val == NULL ) {
527 for ( i = 0; i < in->bv_len; i++ ) {
528 char c = in->bv_val[ i ];
529 if ( NEEDFLTESCAPE( c ) ) {
530 assert( out->bv_len < l - 2 );
531 out->bv_val[out->bv_len++] = '\\';
532 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
533 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
536 assert( out->bv_len < l );
537 out->bv_val[out->bv_len++] = c;
541 out->bv_val[out->bv_len] = '\0';