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