xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/search.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
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