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