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