xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/search.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: search.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/libldap/search.c,v 1.76.2.9 2009/02/20 00:28:32 quanah Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2009 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 	rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly,
175 		sctrls, cctrls, timeout, sizelimit, deref, &msgid );
176 
177 	if ( rc != LDAP_SUCCESS ) {
178 		return( rc );
179 	}
180 
181 	rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
182 
183 	if( rc <= 0 ) {
184 		/* error(-1) or timeout(0) */
185 		return( ld->ld_errno );
186 	}
187 
188 	if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
189 		return( ld->ld_errno );
190 	}
191 
192 	return( ldap_result2error( ld, *res, 0 ) );
193 }
194 
195 /*
196  * ldap_search - initiate an ldap search operation.
197  *
198  * Parameters:
199  *
200  *	ld		LDAP descriptor
201  *	base		DN of the base object
202  *	scope		the search scope - one of
203  *				LDAP_SCOPE_BASE (baseObject),
204  *			    LDAP_SCOPE_ONELEVEL (oneLevel),
205  *				LDAP_SCOPE_SUBTREE (subtree), or
206  *				LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
207  *	filter		a string containing the search filter
208  *			(e.g., "(|(cn=bob)(sn=bob))")
209  *	attrs		list of attribute types to return for matches
210  *	attrsonly	1 => attributes only 0 => attributes and values
211  *
212  * Example:
213  *	char	*attrs[] = { "mail", "title", 0 };
214  *	msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
215  *	    attrs, attrsonly );
216  */
217 int
218 ldap_search(
219 	LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
220 	char **attrs, int attrsonly )
221 {
222 	BerElement	*ber;
223 	ber_int_t	id;
224 
225 	Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
226 
227 	assert( ld != NULL );
228 	assert( LDAP_VALID( ld ) );
229 
230 	ber = ldap_build_search_req( ld, base, scope, filter, attrs,
231 	    attrsonly, NULL, NULL, -1, -1, -1, &id );
232 
233 	if ( ber == NULL ) {
234 		return( -1 );
235 	}
236 
237 
238 	/* send the message */
239 	return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
240 }
241 
242 
243 BerElement *
244 ldap_build_search_req(
245 	LDAP *ld,
246 	LDAP_CONST char *base,
247 	ber_int_t scope,
248 	LDAP_CONST char *filter,
249 	char **attrs,
250 	ber_int_t attrsonly,
251 	LDAPControl **sctrls,
252 	LDAPControl **cctrls,
253 	ber_int_t timelimit,
254 	ber_int_t sizelimit,
255 	ber_int_t deref,
256 	ber_int_t *idp)
257 {
258 	BerElement	*ber;
259 	int		err;
260 
261 	/*
262 	 * Create the search request.  It looks like this:
263 	 *	SearchRequest := [APPLICATION 3] SEQUENCE {
264 	 *		baseObject	DistinguishedName,
265 	 *		scope		ENUMERATED {
266 	 *			baseObject	(0),
267 	 *			singleLevel	(1),
268 	 *			wholeSubtree	(2)
269 	 *		},
270 	 *		derefAliases	ENUMERATED {
271 	 *			neverDerefaliases	(0),
272 	 *			derefInSearching	(1),
273 	 *			derefFindingBaseObj	(2),
274 	 *			alwaysDerefAliases	(3)
275 	 *		},
276 	 *		sizelimit	INTEGER (0 .. 65535),
277 	 *		timelimit	INTEGER (0 .. 65535),
278 	 *		attrsOnly	BOOLEAN,
279 	 *		filter		Filter,
280 	 *		attributes	SEQUENCE OF AttributeType
281 	 *	}
282 	 * wrapped in an ldap message.
283 	 */
284 
285 	/* create a message to send */
286 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
287 		return( NULL );
288 	}
289 
290 	if ( base == NULL ) {
291 		/* no base provided, use session default base */
292 		base = ld->ld_options.ldo_defbase;
293 
294 		if ( base == NULL ) {
295 			/* no session default base, use top */
296 			base = "";
297 		}
298 	}
299 
300 	LDAP_NEXT_MSGID( ld, *idp );
301 #ifdef LDAP_CONNECTIONLESS
302 	if ( LDAP_IS_UDP(ld) ) {
303 		struct sockaddr sa = {0};
304 		/* dummy, filled with ldo_peer in request.c */
305 	    err = ber_write( ber, &sa, sizeof( sa ), 0 );
306 	}
307 	if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
308 	    char *dn = ld->ld_options.ldo_cldapdn;
309 	    if (!dn) dn = "";
310 	    err = ber_printf( ber, "{ist{seeiib", *idp, dn,
311 		LDAP_REQ_SEARCH, base, (ber_int_t) scope,
312 		(deref < 0) ? ld->ld_deref : deref,
313 		(sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
314 		(timelimit < 0) ? ld->ld_timelimit : timelimit,
315 		attrsonly );
316 	} else
317 #endif
318 	{
319 	    err = ber_printf( ber, "{it{seeiib", *idp,
320 		LDAP_REQ_SEARCH, base, (ber_int_t) scope,
321 		(deref < 0) ? ld->ld_deref : deref,
322 		(sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
323 		(timelimit < 0) ? ld->ld_timelimit : timelimit,
324 		attrsonly );
325 	}
326 
327 	if ( err == -1 ) {
328 		ld->ld_errno = LDAP_ENCODING_ERROR;
329 		ber_free( ber, 1 );
330 		return( NULL );
331 	}
332 
333 	if( filter == NULL ) {
334 		filter = "(objectclass=*)";
335 	}
336 
337 	err = ldap_pvt_put_filter( ber, filter );
338 
339 	if ( err  == -1 ) {
340 		ld->ld_errno = LDAP_FILTER_ERROR;
341 		ber_free( ber, 1 );
342 		return( NULL );
343 	}
344 
345 #ifdef LDAP_DEBUG
346 	if ( ldap_debug & LDAP_DEBUG_ARGS ) {
347 		char	buf[ BUFSIZ ], *ptr = " *";
348 
349 		if ( attrs != NULL ) {
350 			int	i, len, rest = sizeof( buf );
351 
352 			for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
353 				ptr = &buf[ sizeof( buf ) - rest ];
354 				len = snprintf( ptr, rest, " %s", attrs[ i ] );
355 				rest -= (len >= 0 ? len : (int) sizeof( buf ));
356 			}
357 
358 			if ( rest <= 0 ) {
359 				AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
360 					"...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
361 			}
362 			ptr = buf;
363 		}
364 
365 		Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
366 	}
367 #endif /* LDAP_DEBUG */
368 
369 	if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
370 		ld->ld_errno = LDAP_ENCODING_ERROR;
371 		ber_free( ber, 1 );
372 		return( NULL );
373 	}
374 
375 	/* Put Server Controls */
376 	if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
377 		ber_free( ber, 1 );
378 		return( NULL );
379 	}
380 
381 	if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
382 		ld->ld_errno = LDAP_ENCODING_ERROR;
383 		ber_free( ber, 1 );
384 		return( NULL );
385 	}
386 
387 	return( ber );
388 }
389 
390 int
391 ldap_search_st(
392 	LDAP *ld, LDAP_CONST char *base, int scope,
393 	LDAP_CONST char *filter, char **attrs,
394 	int attrsonly, struct timeval *timeout, LDAPMessage **res )
395 {
396 	int	msgid;
397 
398 	if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
399 	    == -1 )
400 		return( ld->ld_errno );
401 
402 	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
403 		return( ld->ld_errno );
404 
405 	if ( ld->ld_errno == LDAP_TIMEOUT ) {
406 		(void) ldap_abandon( ld, msgid );
407 		ld->ld_errno = LDAP_TIMEOUT;
408 		return( ld->ld_errno );
409 	}
410 
411 	return( ldap_result2error( ld, *res, 0 ) );
412 }
413 
414 int
415 ldap_search_s(
416 	LDAP *ld,
417 	LDAP_CONST char *base,
418 	int scope,
419 	LDAP_CONST char *filter,
420 	char **attrs,
421 	int attrsonly,
422 	LDAPMessage **res )
423 {
424 	int	msgid;
425 
426 	if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
427 	    == -1 )
428 		return( ld->ld_errno );
429 
430 	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
431 		return( ld->ld_errno );
432 
433 	return( ldap_result2error( ld, *res, 0 ) );
434 }
435 
436 static char escape[128] = {
437 	1, 1, 1, 1, 1, 1, 1, 1,
438 	1, 1, 1, 1, 1, 1, 1, 1,
439 	1, 1, 1, 1, 1, 1, 1, 1,
440 	1, 1, 1, 1, 1, 1, 1, 1,
441 
442 	0, 0, 0, 0, 0, 0, 0, 0,
443 	1, 1, 1, 0, 0, 0, 0, 0,
444 	0, 0, 0, 0, 0, 0, 0, 0,
445 	0, 0, 0, 0, 0, 0, 0, 0,
446 
447 	0, 0, 0, 0, 0, 0, 0, 0,
448 	0, 0, 0, 0, 0, 0, 0, 0,
449 	0, 0, 0, 0, 0, 0, 0, 0,
450 	0, 0, 0, 0, 1, 0, 0, 0,
451 
452 	0, 0, 0, 0, 0, 0, 0, 0,
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, 1
456 };
457 #define	NEEDFLTESCAPE(c)	((c) & 0x80 || escape[ (unsigned)(c) ])
458 
459 /*
460  * compute the length of the escaped value
461  */
462 ber_len_t
463 ldap_bv2escaped_filter_value_len( struct berval *in )
464 {
465 	ber_len_t	i, l;
466 
467 	assert( in != NULL );
468 
469 	if ( in->bv_len == 0 ) {
470 		return 0;
471 	}
472 
473 	for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
474 		char c = in->bv_val[ i ];
475 		if ( NEEDFLTESCAPE( c ) ) {
476 			l += 2;
477 		}
478 	}
479 
480 	return l;
481 }
482 
483 int
484 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
485 {
486 	return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
487 }
488 
489 int
490 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
491 {
492 	ber_len_t	i, l;
493 
494 	assert( in != NULL );
495 	assert( out != NULL );
496 
497 	BER_BVZERO( out );
498 
499 	if ( in->bv_len == 0 ) {
500 		return 0;
501 	}
502 
503 	/* assume we'll escape everything */
504 	l = ldap_bv2escaped_filter_value_len( in );
505 	if ( l == in->bv_len ) {
506 		if ( inplace ) {
507 			*out = *in;
508 		} else {
509 			ber_dupbv( out, in );
510 		}
511 		return 0;
512 	}
513 	out->bv_val = LDAP_MALLOCX( l + 1, ctx );
514 	if ( out->bv_val == NULL ) {
515 		return -1;
516 	}
517 
518 	for ( i = 0; i < in->bv_len; i++ ) {
519 		char c = in->bv_val[ i ];
520 		if ( NEEDFLTESCAPE( c ) ) {
521 			assert( out->bv_len < l - 2 );
522 			out->bv_val[out->bv_len++] = '\\';
523 			out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
524 			out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
525 
526 		} else {
527 			assert( out->bv_len < l );
528 			out->bv_val[out->bv_len++] = c;
529 		}
530 	}
531 
532 	out->bv_val[out->bv_len] = '\0';
533 
534 	return 0;
535 }
536 
537