Home | History | Annotate | Line # | Download | only in libldap
search.c revision 1.1.1.1.6.2
      1 /* $OpenLDAP: pkg/ldap/libraries/libldap/search.c,v 1.76.2.5 2008/02/11 23:26:41 kurt Exp $ */
      2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      3  *
      4  * Copyright 1998-2008 The OpenLDAP Foundation.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted only as authorized by the OpenLDAP
      9  * Public License.
     10  *
     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>.
     14  */
     15 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
     16  * All rights reserved.
     17  */
     18 
     19 #include "portable.h"
     20 
     21 #include <stdio.h>
     22 
     23 #include <ac/stdlib.h>
     24 
     25 #include <ac/socket.h>
     26 #include <ac/string.h>
     27 #include <ac/time.h>
     28 
     29 #include "ldap-int.h"
     30 #include "ldap_log.h"
     31 
     32 /*
     33  * ldap_search_ext - initiate an ldap search operation.
     34  *
     35  * Parameters:
     36  *
     37  *	ld		LDAP descriptor
     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
     48  *
     49  * Example:
     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,
     53  *		&msgid );
     54  */
     55 int
     56 ldap_search_ext(
     57 	LDAP *ld,
     58 	LDAP_CONST char *base,
     59 	int scope,
     60 	LDAP_CONST char *filter,
     61 	char **attrs,
     62 	int attrsonly,
     63 	LDAPControl **sctrls,
     64 	LDAPControl **cctrls,
     65 	struct timeval *timeout,
     66 	int sizelimit,
     67 	int *msgidp )
     68 {
     69 	int rc;
     70 	BerElement	*ber;
     71 	int timelimit;
     72 	ber_int_t id;
     73 
     74 	Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
     75 
     76 	assert( ld != NULL );
     77 	assert( LDAP_VALID( ld ) );
     78 
     79 	/* check client controls */
     80 	rc = ldap_int_client_controls( ld, cctrls );
     81 	if( rc != LDAP_SUCCESS ) return rc;
     82 
     83 	/*
     84 	 * if timeout is provided, both tv_sec and tv_usec must
     85 	 * not be zero
     86 	 */
     87 	if( timeout != NULL ) {
     88 		if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
     89 			return LDAP_PARAM_ERROR;
     90 		}
     91 
     92 		/* timelimit must be non-zero if timeout is provided */
     93 		timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
     94 
     95 	} else {
     96 		/* no timeout, no timelimit */
     97 		timelimit = -1;
     98 	}
     99 
    100 	ber = ldap_build_search_req( ld, base, scope, filter, attrs,
    101 	    attrsonly, sctrls, cctrls, timelimit, sizelimit, &id );
    102 
    103 	if ( ber == NULL ) {
    104 		return ld->ld_errno;
    105 	}
    106 
    107 
    108 	/* send the message */
    109 	*msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
    110 
    111 	if( *msgidp < 0 )
    112 		return ld->ld_errno;
    113 
    114 	return LDAP_SUCCESS;
    115 }
    116 
    117 int
    118 ldap_search_ext_s(
    119 	LDAP *ld,
    120 	LDAP_CONST char *base,
    121 	int scope,
    122 	LDAP_CONST char *filter,
    123 	char **attrs,
    124 	int attrsonly,
    125 	LDAPControl **sctrls,
    126 	LDAPControl **cctrls,
    127 	struct timeval *timeout,
    128 	int sizelimit,
    129 	LDAPMessage **res )
    130 {
    131 	int rc;
    132 	int	msgid;
    133 
    134 	rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
    135 		sctrls, cctrls, timeout, sizelimit, &msgid );
    136 
    137 	if ( rc != LDAP_SUCCESS ) {
    138 		return( rc );
    139 	}
    140 
    141 	rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
    142 
    143 	if( rc <= 0 ) {
    144 		/* error(-1) or timeout(0) */
    145 		return( ld->ld_errno );
    146 	}
    147 
    148 	if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
    149 		return( ld->ld_errno );
    150 	}
    151 
    152 	return( ldap_result2error( ld, *res, 0 ) );
    153 }
    154 
    155 /*
    156  * ldap_search - initiate an ldap search operation.
    157  *
    158  * Parameters:
    159  *
    160  *	ld		LDAP descriptor
    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
    171  *
    172  * Example:
    173  *	char	*attrs[] = { "mail", "title", 0 };
    174  *	msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
    175  *	    attrs, attrsonly );
    176  */
    177 int
    178 ldap_search(
    179 	LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
    180 	char **attrs, int attrsonly )
    181 {
    182 	BerElement	*ber;
    183 	ber_int_t	id;
    184 
    185 	Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
    186 
    187 	assert( ld != NULL );
    188 	assert( LDAP_VALID( ld ) );
    189 
    190 	ber = ldap_build_search_req( ld, base, scope, filter, attrs,
    191 	    attrsonly, NULL, NULL, -1, -1, &id );
    192 
    193 	if ( ber == NULL ) {
    194 		return( -1 );
    195 	}
    196 
    197 
    198 	/* send the message */
    199 	return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
    200 }
    201 
    202 
    203 BerElement *
    204 ldap_build_search_req(
    205 	LDAP *ld,
    206 	LDAP_CONST char *base,
    207 	ber_int_t scope,
    208 	LDAP_CONST char *filter,
    209 	char **attrs,
    210 	ber_int_t attrsonly,
    211 	LDAPControl **sctrls,
    212 	LDAPControl **cctrls,
    213 	ber_int_t timelimit,
    214 	ber_int_t sizelimit,
    215 	ber_int_t *idp)
    216 {
    217 	BerElement	*ber;
    218 	int		err;
    219 
    220 	/*
    221 	 * Create the search request.  It looks like this:
    222 	 *	SearchRequest := [APPLICATION 3] SEQUENCE {
    223 	 *		baseObject	DistinguishedName,
    224 	 *		scope		ENUMERATED {
    225 	 *			baseObject	(0),
    226 	 *			singleLevel	(1),
    227 	 *			wholeSubtree	(2)
    228 	 *		},
    229 	 *		derefAliases	ENUMERATED {
    230 	 *			neverDerefaliases	(0),
    231 	 *			derefInSearching	(1),
    232 	 *			derefFindingBaseObj	(2),
    233 	 *			alwaysDerefAliases	(3)
    234 	 *		},
    235 	 *		sizelimit	INTEGER (0 .. 65535),
    236 	 *		timelimit	INTEGER (0 .. 65535),
    237 	 *		attrsOnly	BOOLEAN,
    238 	 *		filter		Filter,
    239 	 *		attributes	SEQUENCE OF AttributeType
    240 	 *	}
    241 	 * wrapped in an ldap message.
    242 	 */
    243 
    244 	/* create a message to send */
    245 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
    246 		return( NULL );
    247 	}
    248 
    249 	if ( base == NULL ) {
    250 		/* no base provided, use session default base */
    251 		base = ld->ld_options.ldo_defbase;
    252 
    253 		if ( base == NULL ) {
    254 			/* no session default base, use top */
    255 			base = "";
    256 		}
    257 	}
    258 
    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 );
    265 	}
    266 	if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
    267 	    char *dn = ld->ld_options.ldo_cldapdn;
    268 	    if (!dn) dn = "";
    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,
    273 		attrsonly );
    274 	} else
    275 #endif
    276 	{
    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,
    281 		attrsonly );
    282 	}
    283 
    284 	if ( err == -1 ) {
    285 		ld->ld_errno = LDAP_ENCODING_ERROR;
    286 		ber_free( ber, 1 );
    287 		return( NULL );
    288 	}
    289 
    290 	if( filter == NULL ) {
    291 		filter = "(objectclass=*)";
    292 	}
    293 
    294 	err = ldap_pvt_put_filter( ber, filter );
    295 
    296 	if ( err  == -1 ) {
    297 		ld->ld_errno = LDAP_FILTER_ERROR;
    298 		ber_free( ber, 1 );
    299 		return( NULL );
    300 	}
    301 
    302 #ifdef LDAP_DEBUG
    303 	if ( ldap_debug & LDAP_DEBUG_ARGS ) {
    304 		char	buf[ BUFSIZ ] = { ' ', '*', '\0' };
    305 
    306 		if ( attrs != NULL ) {
    307 			char	*ptr;
    308 			int	i;
    309 
    310 			for ( ptr = buf, i = 0;
    311 				attrs[ i ] != NULL && ptr < &buf[ sizeof( buf ) ];
    312 				i++ )
    313 			{
    314 				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
    315 					" %s", attrs[ i ] );
    316 			}
    317 
    318 			if ( ptr >= &buf[ sizeof( buf ) ] ) {
    319 				AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
    320 					"...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
    321 			}
    322 		}
    323 
    324 		Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", buf, 0, 0 );
    325 	}
    326 #endif /* LDAP_DEBUG */
    327 
    328 	if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
    329 		ld->ld_errno = LDAP_ENCODING_ERROR;
    330 		ber_free( ber, 1 );
    331 		return( NULL );
    332 	}
    333 
    334 	/* Put Server Controls */
    335 	if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
    336 		ber_free( ber, 1 );
    337 		return( NULL );
    338 	}
    339 
    340 	if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
    341 		ld->ld_errno = LDAP_ENCODING_ERROR;
    342 		ber_free( ber, 1 );
    343 		return( NULL );
    344 	}
    345 
    346 	return( ber );
    347 }
    348 
    349 int
    350 ldap_search_st(
    351 	LDAP *ld, LDAP_CONST char *base, int scope,
    352 	LDAP_CONST char *filter, char **attrs,
    353 	int attrsonly, struct timeval *timeout, LDAPMessage **res )
    354 {
    355 	int	msgid;
    356 
    357 	if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
    358 	    == -1 )
    359 		return( ld->ld_errno );
    360 
    361 	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
    362 		return( ld->ld_errno );
    363 
    364 	if ( ld->ld_errno == LDAP_TIMEOUT ) {
    365 		(void) ldap_abandon( ld, msgid );
    366 		ld->ld_errno = LDAP_TIMEOUT;
    367 		return( ld->ld_errno );
    368 	}
    369 
    370 	return( ldap_result2error( ld, *res, 0 ) );
    371 }
    372 
    373 int
    374 ldap_search_s(
    375 	LDAP *ld,
    376 	LDAP_CONST char *base,
    377 	int scope,
    378 	LDAP_CONST char *filter,
    379 	char **attrs,
    380 	int attrsonly,
    381 	LDAPMessage **res )
    382 {
    383 	int	msgid;
    384 
    385 	if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
    386 	    == -1 )
    387 		return( ld->ld_errno );
    388 
    389 	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
    390 		return( ld->ld_errno );
    391 
    392 	return( ldap_result2error( ld, *res, 0 ) );
    393 }
    394 
    395 static char escape[128] = {
    396 	1, 1, 1, 1, 1, 1, 1, 1,
    397 	1, 1, 1, 1, 1, 1, 1, 1,
    398 	1, 1, 1, 1, 1, 1, 1, 1,
    399 	1, 1, 1, 1, 1, 1, 1, 1,
    400 
    401 	0, 0, 0, 0, 0, 0, 0, 0,
    402 	1, 1, 1, 0, 0, 0, 0, 0,
    403 	0, 0, 0, 0, 0, 0, 0, 0,
    404 	0, 0, 0, 0, 0, 0, 0, 0,
    405 
    406 	0, 0, 0, 0, 0, 0, 0, 0,
    407 	0, 0, 0, 0, 0, 0, 0, 0,
    408 	0, 0, 0, 0, 0, 0, 0, 0,
    409 	0, 0, 0, 0, 1, 0, 0, 0,
    410 
    411 	0, 0, 0, 0, 0, 0, 0, 0,
    412 	0, 0, 0, 0, 0, 0, 0, 0,
    413 	0, 0, 0, 0, 0, 0, 0, 0,
    414 	0, 0, 0, 0, 0, 0, 0, 1
    415 };
    416 #define	NEEDFLTESCAPE(c)	((c) & 0x80 || escape[ (unsigned)(c) ])
    417 
    418 /*
    419  * compute the length of the escaped value
    420  */
    421 ber_len_t
    422 ldap_bv2escaped_filter_value_len( struct berval *in )
    423 {
    424 	ber_len_t	i, l;
    425 
    426 	assert( in != NULL );
    427 
    428 	if ( in->bv_len == 0 ) {
    429 		return 0;
    430 	}
    431 
    432 	for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
    433 		char c = in->bv_val[ i ];
    434 		if ( NEEDFLTESCAPE( c ) ) {
    435 			l += 2;
    436 		}
    437 	}
    438 
    439 	return l;
    440 }
    441 
    442 int
    443 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
    444 {
    445 	return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
    446 }
    447 
    448 int
    449 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
    450 {
    451 	ber_len_t	i, l;
    452 
    453 	assert( in != NULL );
    454 	assert( out != NULL );
    455 
    456 	BER_BVZERO( out );
    457 
    458 	if ( in->bv_len == 0 ) {
    459 		return 0;
    460 	}
    461 
    462 	/* assume we'll escape everything */
    463 	l = ldap_bv2escaped_filter_value_len( in );
    464 	if ( l == in->bv_len ) {
    465 		if ( inplace ) {
    466 			*out = *in;
    467 		} else {
    468 			ber_dupbv( out, in );
    469 		}
    470 		return 0;
    471 	}
    472 	out->bv_val = LDAP_MALLOCX( l + 1, ctx );
    473 	if ( out->bv_val == NULL ) {
    474 		return -1;
    475 	}
    476 
    477 	for ( i = 0; i < in->bv_len; i++ ) {
    478 		char c = in->bv_val[ i ];
    479 		if ( NEEDFLTESCAPE( c ) ) {
    480 			assert( out->bv_len < l - 2 );
    481 			out->bv_val[out->bv_len++] = '\\';
    482 			out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
    483 			out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
    484 
    485 		} else {
    486 			assert( out->bv_len < l );
    487 			out->bv_val[out->bv_len++] = c;
    488 		}
    489 	}
    490 
    491 	out->bv_val[out->bv_len] = '\0';
    492 
    493 	return 0;
    494 }
    495 
    496