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