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,
74 Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
77 assert( LDAP_VALID( ld ) );
79 /* check client controls */
80 rc = ldap_int_client_controls( ld, cctrls );
81 if( rc != LDAP_SUCCESS ) return rc;
84 * if timeout is provided, both tv_sec and tv_usec must
87 if( timeout != NULL ) {
88 if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
89 return LDAP_PARAM_ERROR;
92 /* timelimit must be non-zero if timeout is provided */
93 timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
96 /* no timeout, no timelimit */
100 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
101 attrsonly, sctrls, cctrls, timelimit, sizelimit, &id );
108 /* send the message */
109 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
120 LDAP_CONST char *base,
122 LDAP_CONST char *filter,
125 LDAPControl **sctrls,
126 LDAPControl **cctrls,
127 struct timeval *timeout,
134 rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
135 sctrls, cctrls, timeout, sizelimit, &msgid );
137 if ( rc != LDAP_SUCCESS ) {
141 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
144 /* error(-1) or timeout(0) */
145 return( ld->ld_errno );
148 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
149 return( ld->ld_errno );
152 return( ldap_result2error( ld, *res, 0 ) );
156 * ldap_search - initiate an ldap search operation.
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
173 * char *attrs[] = { "mail", "title", 0 };
174 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
175 * attrs, attrsonly );
179 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
180 char **attrs, int attrsonly )
185 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
187 assert( ld != NULL );
188 assert( LDAP_VALID( ld ) );
190 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
191 attrsonly, NULL, NULL, -1, -1, &id );
198 /* send the message */
199 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
204 ldap_build_search_req(
206 LDAP_CONST char *base,
208 LDAP_CONST char *filter,
211 LDAPControl **sctrls,
212 LDAPControl **cctrls,
221 * Create the search request. It looks like this:
222 * SearchRequest := [APPLICATION 3] SEQUENCE {
223 * baseObject DistinguishedName,
229 * derefAliases ENUMERATED {
230 * neverDerefaliases (0),
231 * derefInSearching (1),
232 * derefFindingBaseObj (2),
233 * alwaysDerefAliases (3)
235 * sizelimit INTEGER (0 .. 65535),
236 * timelimit INTEGER (0 .. 65535),
239 * attributes SEQUENCE OF AttributeType
241 * wrapped in an ldap message.
244 /* create a message to send */
245 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
249 if ( base == NULL ) {
250 /* no base provided, use session default base */
251 base = ld->ld_options.ldo_defbase;
253 if ( base == NULL ) {
254 /* no session default base, use top */
259 LDAP_NEXT_MSGID( ld, *idp );
260 #ifdef LDAP_CONNECTIONLESS
261 if ( LDAP_IS_UDP(ld) ) {
262 struct sockaddr sa = {0};
263 /* dummy, filled with ldo_peer in request.c */
264 err = ber_write( ber, &sa, sizeof( sa ), 0 );
266 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
267 char *dn = ld->ld_options.ldo_cldapdn;
269 err = ber_printf( ber, "{ist{seeiib", *idp, dn,
270 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
271 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
272 (timelimit < 0) ? ld->ld_timelimit : timelimit,
277 err = ber_printf( ber, "{it{seeiib", *idp,
278 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
279 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
280 (timelimit < 0) ? ld->ld_timelimit : timelimit,
285 ld->ld_errno = LDAP_ENCODING_ERROR;
290 if( filter == NULL ) {
291 filter = "(objectclass=*)";
294 err = ldap_pvt_put_filter( ber, filter );
297 ld->ld_errno = LDAP_FILTER_ERROR;
303 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
304 char buf[ BUFSIZ ], *ptr = " *";
306 if ( attrs != NULL ) {
307 int i, len, rest = sizeof( buf );
309 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
310 ptr = &buf[ sizeof( buf ) - rest ];
311 len = snprintf( ptr, rest, " %s", attrs[ i ] );
312 rest -= (len >= 0 ? len : (int) sizeof( buf ));
316 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
317 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
322 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
324 #endif /* LDAP_DEBUG */
326 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
327 ld->ld_errno = LDAP_ENCODING_ERROR;
332 /* Put Server Controls */
333 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
338 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
339 ld->ld_errno = LDAP_ENCODING_ERROR;
349 LDAP *ld, LDAP_CONST char *base, int scope,
350 LDAP_CONST char *filter, char **attrs,
351 int attrsonly, struct timeval *timeout, LDAPMessage **res )
355 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
357 return( ld->ld_errno );
359 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
360 return( ld->ld_errno );
362 if ( ld->ld_errno == LDAP_TIMEOUT ) {
363 (void) ldap_abandon( ld, msgid );
364 ld->ld_errno = LDAP_TIMEOUT;
365 return( ld->ld_errno );
368 return( ldap_result2error( ld, *res, 0 ) );
374 LDAP_CONST char *base,
376 LDAP_CONST char *filter,
383 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
385 return( ld->ld_errno );
387 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
388 return( ld->ld_errno );
390 return( ldap_result2error( ld, *res, 0 ) );
393 static char escape[128] = {
394 1, 1, 1, 1, 1, 1, 1, 1,
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,
399 0, 0, 0, 0, 0, 0, 0, 0,
400 1, 1, 1, 0, 0, 0, 0, 0,
401 0, 0, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0,
404 0, 0, 0, 0, 0, 0, 0, 0,
405 0, 0, 0, 0, 0, 0, 0, 0,
406 0, 0, 0, 0, 0, 0, 0, 0,
407 0, 0, 0, 0, 1, 0, 0, 0,
409 0, 0, 0, 0, 0, 0, 0, 0,
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, 1
414 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
417 * compute the length of the escaped value
420 ldap_bv2escaped_filter_value_len( struct berval *in )
424 assert( in != NULL );
426 if ( in->bv_len == 0 ) {
430 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
431 char c = in->bv_val[ i ];
432 if ( NEEDFLTESCAPE( c ) ) {
441 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
443 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
447 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
451 assert( in != NULL );
452 assert( out != NULL );
456 if ( in->bv_len == 0 ) {
460 /* assume we'll escape everything */
461 l = ldap_bv2escaped_filter_value_len( in );
462 if ( l == in->bv_len ) {
466 ber_dupbv( out, in );
470 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
471 if ( out->bv_val == NULL ) {
475 for ( i = 0; i < in->bv_len; i++ ) {
476 char c = in->bv_val[ i ];
477 if ( NEEDFLTESCAPE( c ) ) {
478 assert( out->bv_len < l - 2 );
479 out->bv_val[out->bv_len++] = '\\';
480 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
481 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
484 assert( out->bv_len < l );
485 out->bv_val[out->bv_len++] = c;
489 out->bv_val[out->bv_len] = '\0';