1 /* filterentry.c - apply a filter to an entry */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2021 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26 
27 #include "portable.h"
28 
29 #include <stdio.h>
30 
31 #include <ac/socket.h>
32 #include <ac/string.h>
33 
34 #include "slap.h"
35 
36 #ifdef LDAP_COMP_MATCH
37 #include "component.h"
38 #endif
39 
40 static int	test_filter_and( Operation *op, Entry *e, Filter *flist );
41 static int	test_filter_or( Operation *op, Entry *e, Filter *flist );
42 static int	test_substrings_filter( Operation *op, Entry *e, Filter *f);
43 static int	test_ava_filter( Operation *op,
44 	Entry *e, AttributeAssertion *ava, int type );
45 static int	test_mra_filter( Operation *op,
46 	Entry *e, MatchingRuleAssertion *mra );
47 static int	test_presence_filter( Operation *op,
48 	Entry *e, AttributeDescription *desc );
49 
50 
51 /*
52  * test_filter - test a filter against a single entry.
53  * returns:
54  *		LDAP_COMPARE_TRUE		filter matched
55  *		LDAP_COMPARE_FALSE		filter did not match
56  *		SLAPD_COMPARE_UNDEFINED	filter is undefined
57  *	or an ldap result code indicating error
58  */
59 
60 int
test_filter(Operation * op,Entry * e,Filter * f)61 test_filter(
62     Operation	*op,
63     Entry	*e,
64     Filter	*f )
65 {
66 	int	rc;
67 	Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
68 
69 	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
70 		Debug( LDAP_DEBUG_FILTER, "    UNDEFINED\n", 0, 0, 0 );
71 		rc = SLAPD_COMPARE_UNDEFINED;
72 		goto out;
73 	}
74 
75 	switch ( f->f_choice ) {
76 	case SLAPD_FILTER_COMPUTED:
77 		Debug( LDAP_DEBUG_FILTER, "    COMPUTED %s (%d)\n",
78 			f->f_result == LDAP_COMPARE_FALSE ? "false" :
79 			f->f_result == LDAP_COMPARE_TRUE ? "true" :
80 			f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
81 			f->f_result, 0 );
82 
83 		rc = f->f_result;
84 		break;
85 
86 	case LDAP_FILTER_EQUALITY:
87 		Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
88 		rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
89 		break;
90 
91 	case LDAP_FILTER_SUBSTRINGS:
92 		Debug( LDAP_DEBUG_FILTER, "    SUBSTRINGS\n", 0, 0, 0 );
93 		rc = test_substrings_filter( op, e, f );
94 		break;
95 
96 	case LDAP_FILTER_GE:
97 		Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
98 		rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
99 		break;
100 
101 	case LDAP_FILTER_LE:
102 		Debug( LDAP_DEBUG_FILTER, "    LE\n", 0, 0, 0 );
103 		rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
104 		break;
105 
106 	case LDAP_FILTER_PRESENT:
107 		Debug( LDAP_DEBUG_FILTER, "    PRESENT\n", 0, 0, 0 );
108 		rc = test_presence_filter( op, e, f->f_desc );
109 		break;
110 
111 	case LDAP_FILTER_APPROX:
112 		Debug( LDAP_DEBUG_FILTER, "    APPROX\n", 0, 0, 0 );
113 		rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
114 		break;
115 
116 	case LDAP_FILTER_AND:
117 		Debug( LDAP_DEBUG_FILTER, "    AND\n", 0, 0, 0 );
118 		rc = test_filter_and( op, e, f->f_and );
119 		break;
120 
121 	case LDAP_FILTER_OR:
122 		Debug( LDAP_DEBUG_FILTER, "    OR\n", 0, 0, 0 );
123 		rc = test_filter_or( op, e, f->f_or );
124 		break;
125 
126 	case LDAP_FILTER_NOT:
127 		Debug( LDAP_DEBUG_FILTER, "    NOT\n", 0, 0, 0 );
128 		rc = test_filter( op, e, f->f_not );
129 
130 		/* Flip true to false and false to true
131 		 * but leave Undefined alone.
132 		 */
133 		switch( rc ) {
134 		case LDAP_COMPARE_TRUE:
135 			rc = LDAP_COMPARE_FALSE;
136 			break;
137 		case LDAP_COMPARE_FALSE:
138 			rc = LDAP_COMPARE_TRUE;
139 			break;
140 		}
141 		break;
142 
143 	case LDAP_FILTER_EXT:
144 		Debug( LDAP_DEBUG_FILTER, "    EXT\n", 0, 0, 0 );
145 		rc = test_mra_filter( op, e, f->f_mra );
146 		break;
147 
148 	default:
149 		Debug( LDAP_DEBUG_ANY, "    unknown filter type %lu\n",
150 		    f->f_choice, 0, 0 );
151 		rc = LDAP_PROTOCOL_ERROR;
152 	}
153 out:
154 	Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
155 	return( rc );
156 }
157 
test_mra_filter(Operation * op,Entry * e,MatchingRuleAssertion * mra)158 static int test_mra_filter(
159 	Operation *op,
160 	Entry *e,
161 	MatchingRuleAssertion *mra )
162 {
163 	Attribute	*a;
164 	void		*memctx;
165 	BER_MEMFREE_FN	*memfree;
166 #ifdef LDAP_COMP_MATCH
167 	int i, num_attr_vals = 0;
168 #endif
169 
170 	if ( op == NULL ) {
171 		memctx = NULL;
172 		memfree = slap_sl_mfuncs.bmf_free;
173 	} else {
174 		memctx = op->o_tmpmemctx;
175 		memfree = op->o_tmpfree;
176 	}
177 
178 	if ( mra->ma_desc ) {
179 		/*
180 		 * if ma_desc is available, then we're filtering for
181 		 * one attribute, and SEARCH permissions can be checked
182 		 * directly.
183 		 */
184 		if ( !access_allowed( op, e,
185 			mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
186 		{
187 			return LDAP_INSUFFICIENT_ACCESS;
188 		}
189 
190 		if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
191 			int ret, rc;
192 			const char *text;
193 
194 			rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
195 				SLAP_MR_EXT, &e->e_nname, &mra->ma_value, &text );
196 
197 
198 			if( rc != LDAP_SUCCESS ) return rc;
199 			if ( ret == 0 ) return LDAP_COMPARE_TRUE;
200 			return LDAP_COMPARE_FALSE;
201 		}
202 
203 		for ( a = attrs_find( e->e_attrs, mra->ma_desc );
204 			a != NULL;
205 			a = attrs_find( a->a_next, mra->ma_desc ) )
206 		{
207 			struct berval	*bv;
208 			int		normalize_attribute = 0;
209 
210 #ifdef LDAP_COMP_MATCH
211 			/* Component Matching */
212 			if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
213 				num_attr_vals = 0;
214 				if ( !a->a_comp_data ) {
215 					num_attr_vals = a->a_numvals;
216 					if ( num_attr_vals <= 0 ) {
217 						/* no attribute value */
218 						return LDAP_INAPPROPRIATE_MATCHING;
219 					}
220 					num_attr_vals++;
221 
222 					/* following malloced will be freed by comp_tree_free () */
223 					a->a_comp_data = SLAP_MALLOC( sizeof( ComponentData ) +
224 						sizeof( ComponentSyntaxInfo* )*num_attr_vals );
225 
226 					if ( !a->a_comp_data ) return LDAP_NO_MEMORY;
227 					a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)
228 						((char*)a->a_comp_data + sizeof(ComponentData));
229 					a->a_comp_data->cd_tree[num_attr_vals - 1] =
230 						(ComponentSyntaxInfo*) NULL;
231 					a->a_comp_data->cd_mem_op =
232 						nibble_mem_allocator( 1024*16, 1024 );
233 				}
234 			}
235 #endif
236 
237 			/* If ma_rule is not the same as the attribute's
238 			 * normal rule, then we can't use the a_nvals.
239 			 */
240 			if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
241 				bv = a->a_nvals;
242 
243 			} else {
244 				bv = a->a_vals;
245 				normalize_attribute = 1;
246 			}
247 #ifdef LDAP_COMP_MATCH
248 			i = 0;
249 #endif
250 			for ( ; !BER_BVISNULL( bv ); bv++ ) {
251 				int ret;
252 				int rc;
253 				const char *text;
254 
255 #ifdef LDAP_COMP_MATCH
256 				if ( mra->ma_cf &&
257 					mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
258 				{
259 					/* Check if decoded component trees are already linked */
260 					if ( num_attr_vals ) {
261 						a->a_comp_data->cd_tree[i] = attr_converter(
262 							a, a->a_desc->ad_type->sat_syntax, bv );
263 					}
264 					/* decoding error */
265 					if ( !a->a_comp_data->cd_tree[i] ) {
266 						return LDAP_OPERATIONS_ERROR;
267 					}
268 					rc = value_match( &ret, a->a_desc, mra->ma_rule,
269 						SLAP_MR_COMPONENT,
270 						(struct berval*)a->a_comp_data->cd_tree[i++],
271 						(void*)mra, &text );
272 				} else
273 #endif
274 				{
275 					struct berval	nbv = BER_BVNULL;
276 
277 					if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
278 						/*
279 
280 				Document: RFC 4511
281 
282 				    4.5.1. Search Request
283 				        ...
284 				    If the type field is present and the matchingRule is present,
285 			            the matchValue is compared against entry attributes of the
286 			            specified type. In this case, the matchingRule MUST be one
287 				    suitable for use with the specified type (see [RFC4517]),
288 				    otherwise the filter item is Undefined.
289 
290 
291 				In this case, since the matchingRule requires the assertion
292 				value to be normalized, we normalize the attribute value
293 				according to the syntax of the matchingRule.
294 
295 				This should likely be done inside value_match(), by passing
296 				the appropriate flags, but this is not done at present.
297 				See ITS#3406.
298 						 */
299 						if ( mra->ma_rule->smr_normalize(
300 								SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
301 								mra->ma_rule->smr_syntax,
302 								mra->ma_rule,
303 								bv, &nbv, memctx ) != LDAP_SUCCESS )
304 						{
305 							/* FIXME: stop processing? */
306 							continue;
307 						}
308 
309 					} else {
310 						nbv = *bv;
311 					}
312 
313 					rc = value_match( &ret, a->a_desc, mra->ma_rule,
314 						SLAP_MR_EXT, &nbv, &mra->ma_value, &text );
315 
316 					if ( nbv.bv_val != bv->bv_val ) {
317 						memfree( nbv.bv_val, memctx );
318 					}
319 				}
320 
321 				if ( rc != LDAP_SUCCESS ) return rc;
322 				if ( ret == 0 ) return LDAP_COMPARE_TRUE;
323 			}
324 		}
325 
326 	} else {
327 		/*
328 		 * No attribute description: test all
329 		 */
330 		for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
331 			struct berval	*bv, value;
332 			const char	*text = NULL;
333 			int		rc;
334 			int		normalize_attribute = 0;
335 
336 			/* check if matching is appropriate */
337 			if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
338 				continue;
339 			}
340 
341 			/* normalize for equality */
342 			rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
343 				SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
344 				&mra->ma_value, &value, &text, memctx );
345 			if ( rc != LDAP_SUCCESS ) continue;
346 
347 			/* check search access */
348 			if ( !access_allowed( op, e,
349 				a->a_desc, &value, ACL_SEARCH, NULL ) )
350 			{
351 				memfree( value.bv_val, memctx );
352 				continue;
353 			}
354 #ifdef LDAP_COMP_MATCH
355 			/* Component Matching */
356 			if ( mra->ma_cf &&
357 				mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
358 			{
359 				int ret;
360 
361 				rc = value_match( &ret, a->a_desc, mra->ma_rule,
362 					SLAP_MR_COMPONENT,
363 					(struct berval*)a, (void*)mra, &text );
364 				if ( rc != LDAP_SUCCESS ) break;
365 
366 				if ( ret == 0 ) {
367 					rc = LDAP_COMPARE_TRUE;
368 					break;
369 				}
370 
371 			}
372 #endif
373 
374 			/* check match */
375 			if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
376 				bv = a->a_nvals;
377 
378 			} else {
379 				bv = a->a_vals;
380 				normalize_attribute = 1;
381 			}
382 
383 			for ( ; !BER_BVISNULL( bv ); bv++ ) {
384 				int		ret;
385 				struct berval	nbv = BER_BVNULL;
386 
387 				if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
388 					/* see comment above */
389 					if ( mra->ma_rule->smr_normalize(
390 							SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
391 							mra->ma_rule->smr_syntax,
392 							mra->ma_rule,
393 							bv, &nbv, memctx ) != LDAP_SUCCESS )
394 					{
395 						/* FIXME: stop processing? */
396 						continue;
397 					}
398 
399 				} else {
400 					nbv = *bv;
401 				}
402 
403 				rc = value_match( &ret, a->a_desc, mra->ma_rule,
404 					SLAP_MR_EXT, &nbv, &value, &text );
405 
406 				if ( nbv.bv_val != bv->bv_val ) {
407 					memfree( nbv.bv_val, memctx );
408 				}
409 
410 				if ( rc != LDAP_SUCCESS ) break;
411 
412 				if ( ret == 0 ) {
413 					rc = LDAP_COMPARE_TRUE;
414 					break;
415 				}
416 			}
417 			memfree( value.bv_val, memctx );
418 			if ( rc != LDAP_SUCCESS ) return rc;
419 		}
420 	}
421 
422 	/* check attrs in DN AVAs if required */
423 	if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
424 		LDAPDN		dn = NULL;
425 		int		iRDN, iAVA;
426 		int		rc;
427 
428 		/* parse and pretty the dn */
429 		rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
430 		if ( rc != LDAP_SUCCESS ) {
431 			return LDAP_INVALID_SYNTAX;
432 		}
433 
434 		/* for each AVA of each RDN ... */
435 		for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
436 			LDAPRDN		rdn = dn[ iRDN ];
437 
438 			for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
439 				LDAPAVA		*ava = rdn[ iAVA ];
440 				struct berval	*bv = &ava->la_value,
441 						value = BER_BVNULL,
442 						nbv = BER_BVNULL;
443 				AttributeDescription *ad =
444 					(AttributeDescription *)ava->la_private;
445 				int		ret;
446 				const char	*text;
447 
448 				assert( ad != NULL );
449 
450 				if ( mra->ma_desc ) {
451 					/* have a mra type? check for subtype */
452 					if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
453 						continue;
454 					}
455 					value = mra->ma_value;
456 
457 				} else {
458 					const char	*text = NULL;
459 
460 					/* check if matching is appropriate */
461 					if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
462 						continue;
463 					}
464 
465 					/* normalize for equality */
466 					rc = asserted_value_validate_normalize( ad,
467 						mra->ma_rule,
468 						SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
469 						&mra->ma_value, &value, &text, memctx );
470 					if ( rc != LDAP_SUCCESS ) continue;
471 
472 					/* check search access */
473 					if ( !access_allowed( op, e,
474 						ad, &value, ACL_SEARCH, NULL ) )
475 					{
476 						memfree( value.bv_val, memctx );
477 						continue;
478 					}
479 				}
480 
481 				if ( mra->ma_rule->smr_normalize ) {
482 					/* see comment above */
483 					if ( mra->ma_rule->smr_normalize(
484 							SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
485 							mra->ma_rule->smr_syntax,
486 							mra->ma_rule,
487 							bv, &nbv, memctx ) != LDAP_SUCCESS )
488 					{
489 						/* FIXME: stop processing? */
490 						rc = LDAP_SUCCESS;
491 						ret = -1;
492 						goto cleanup;
493 					}
494 
495 				} else {
496 					nbv = *bv;
497 				}
498 
499 				/* check match */
500 				rc = value_match( &ret, ad, mra->ma_rule, SLAP_MR_EXT,
501 					&nbv, &value, &text );
502 
503 cleanup:;
504 				if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
505 					memfree( value.bv_val, memctx );
506 				}
507 
508 				if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
509 					memfree( nbv.bv_val, memctx );
510 				}
511 
512 				if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
513 
514 				if ( rc != LDAP_SUCCESS ) {
515 					ldap_dnfree_x( dn, memctx );
516 					return rc;
517 				}
518 			}
519 		}
520 		ldap_dnfree_x( dn, memctx );
521 	}
522 
523 	return LDAP_COMPARE_FALSE;
524 }
525 
526 static int
test_ava_filter(Operation * op,Entry * e,AttributeAssertion * ava,int type)527 test_ava_filter(
528 	Operation	*op,
529 	Entry		*e,
530 	AttributeAssertion *ava,
531 	int		type )
532 {
533 	int rc;
534 	Attribute	*a;
535 #ifdef LDAP_COMP_MATCH
536 	int i, num_attr_vals = 0;
537 	AttributeAliasing *a_alias = NULL;
538 #endif
539 
540 	if ( !access_allowed( op, e,
541 		ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
542 	{
543 		return LDAP_INSUFFICIENT_ACCESS;
544 	}
545 
546 	if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
547 		&& op && op->o_bd && op->o_bd->be_has_subordinates )
548 	{
549 		int	hasSubordinates = 0;
550 		struct berval hs;
551 
552 		if( type != LDAP_FILTER_EQUALITY &&
553 			type != LDAP_FILTER_APPROX )
554 		{
555 			/* No other match is allowed */
556 			return LDAP_INAPPROPRIATE_MATCHING;
557 		}
558 
559 		if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
560 			LDAP_SUCCESS )
561 		{
562 			return LDAP_OTHER;
563 		}
564 
565 		if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
566 			hs = slap_true_bv;
567 
568 		} else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
569 			hs = slap_false_bv;
570 
571 		} else {
572 			return LDAP_OTHER;
573 		}
574 
575 		if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
576 		return LDAP_COMPARE_FALSE;
577 	}
578 
579 	if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
580 		MatchingRule *mr;
581 		int match;
582 		const char *text;
583 
584 		if( type != LDAP_FILTER_EQUALITY &&
585 			type != LDAP_FILTER_APPROX )
586 		{
587 			/* No other match is allowed */
588 			return LDAP_INAPPROPRIATE_MATCHING;
589 		}
590 
591 		mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
592 		assert( mr != NULL );
593 
594 		rc = value_match( &match, slap_schema.si_ad_entryDN, mr,
595 			SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text );
596 
597 		if( rc != LDAP_SUCCESS ) return rc;
598 		if( match == 0 ) return LDAP_COMPARE_TRUE;
599 		return LDAP_COMPARE_FALSE;
600 	}
601 
602 	rc = LDAP_COMPARE_FALSE;
603 
604 #ifdef LDAP_COMP_MATCH
605 	if ( is_aliased_attribute && ava->aa_cf )
606 	{
607 		a_alias = is_aliased_attribute ( ava->aa_desc );
608 		if ( a_alias )
609 			ava->aa_desc = a_alias->aa_aliased_ad;
610 		else
611 			ava->aa_cf = NULL;
612 	}
613 #endif
614 
615 	for(a = attrs_find( e->e_attrs, ava->aa_desc );
616 		a != NULL;
617 		a = attrs_find( a->a_next, ava->aa_desc ) )
618 	{
619 		int use;
620 		MatchingRule *mr;
621 		struct berval *bv;
622 
623 		if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
624 			e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
625 		{
626 			rc = LDAP_INSUFFICIENT_ACCESS;
627 			continue;
628 		}
629 
630 		use = SLAP_MR_EQUALITY;
631 
632 		switch ( type ) {
633 		case LDAP_FILTER_APPROX:
634 			use = SLAP_MR_EQUALITY_APPROX;
635 			mr = a->a_desc->ad_type->sat_approx;
636 			if( mr != NULL ) break;
637 
638 			/* fallthru: use EQUALITY matching rule if no APPROX rule */
639 
640 		case LDAP_FILTER_EQUALITY:
641 			/* use variable set above so fall thru use is not clobbered */
642 			mr = a->a_desc->ad_type->sat_equality;
643 			break;
644 
645 		case LDAP_FILTER_GE:
646 		case LDAP_FILTER_LE:
647 			use = SLAP_MR_ORDERING;
648 			mr = a->a_desc->ad_type->sat_ordering;
649 			break;
650 
651 		default:
652 			mr = NULL;
653 		}
654 
655 		if( mr == NULL ) {
656 			rc = LDAP_INAPPROPRIATE_MATCHING;
657 			continue;
658 		}
659 
660 		/* We have no Sort optimization for Approx matches */
661 		if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && type != LDAP_FILTER_APPROX ) {
662 			unsigned slot;
663 			int ret;
664 
665 			/* For Ordering matches, we just need to do one comparison with
666 			 * either the first (least) or last (greatest) value.
667 			 */
668 			if ( use == SLAP_MR_ORDERING ) {
669 				const char *text;
670 				int match, which;
671 				which = (type == LDAP_FILTER_LE) ? 0 : a->a_numvals-1;
672 				ret = value_match( &match, a->a_desc, mr, use,
673 					&a->a_nvals[which], &ava->aa_value, &text );
674 				if ( ret != LDAP_SUCCESS ) return ret;
675 				if (( type == LDAP_FILTER_LE && match <= 0 ) ||
676 					( type == LDAP_FILTER_GE && match >= 0 ))
677 					return LDAP_COMPARE_TRUE;
678 				continue;
679 			}
680 			/* Only Equality will get here */
681 			ret = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
682 				SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
683 				&ava->aa_value, &slot, NULL );
684 			if ( ret == LDAP_SUCCESS )
685 				return LDAP_COMPARE_TRUE;
686 			else if ( ret != LDAP_NO_SUCH_ATTRIBUTE )
687 				return ret;
688 #if 0
689 			/* The following is useful if we want to know which values
690 			 * matched an ordering test. But here we don't care, we just
691 			 * want to know if any value did, and that is checked above.
692 			 */
693 			if ( ret == LDAP_NO_SUCH_ATTRIBUTE ) {
694 				/* If insertion point is not the end of the list, there was
695 				 * at least one value greater than the assertion.
696 				 */
697 				if ( type == LDAP_FILTER_GE && slot < a->a_numvals )
698 					return LDAP_COMPARE_TRUE;
699 				/* Likewise, if insertion point is not the head of the list,
700 				 * there was at least one value less than the assertion.
701 				 */
702 				if ( type == LDAP_FILTER_LE && slot > 0 )
703 					return LDAP_COMPARE_TRUE;
704 				return LDAP_COMPARE_FALSE;
705 			}
706 #endif
707 			continue;
708 		}
709 
710 #ifdef LDAP_COMP_MATCH
711 		if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
712 			/* Component Matching */
713 			for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
714 			if ( num_attr_vals <= 0 )/* no attribute value */
715 				return LDAP_INAPPROPRIATE_MATCHING;
716 			num_attr_vals++;/* for NULL termination */
717 
718 			/* following malloced will be freed by comp_tree_free () */
719 			a->a_comp_data = SLAP_MALLOC( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
720 
721 			if ( !a->a_comp_data ) {
722 				return LDAP_NO_MEMORY;
723 			}
724 
725 			a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
726 			i = num_attr_vals;
727 			for ( ; i ; i-- ) {
728 				a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
729 			}
730 
731 			a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
732 			if ( a->a_comp_data->cd_mem_op == NULL ) {
733 				free ( a->a_comp_data );
734 				a->a_comp_data = NULL;
735 				return LDAP_OPERATIONS_ERROR;
736 			}
737 		}
738 
739 		i = 0;
740 #endif
741 
742 		for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
743 			int ret, match;
744 			const char *text;
745 
746 #ifdef LDAP_COMP_MATCH
747 			if( attr_converter && ava->aa_cf && a->a_comp_data ) {
748 				/* Check if decoded component trees are already linked */
749 				struct berval cf_bv = { 20, "componentFilterMatch" };
750 				MatchingRule* cf_mr = mr_bvfind( &cf_bv );
751 				MatchingRuleAssertion mra;
752 				mra.ma_cf = ava->aa_cf;
753 
754 				if ( a->a_comp_data->cd_tree[i] == NULL )
755 					a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
756 				/* decoding error */
757 				if ( !a->a_comp_data->cd_tree[i] ) {
758 					free_ComponentData ( a );
759 					return LDAP_OPERATIONS_ERROR;
760 				}
761 
762 				ret = value_match( &match, a->a_desc, cf_mr,
763 					SLAP_MR_COMPONENT,
764 					(struct berval*)a->a_comp_data->cd_tree[i++],
765 					(void*)&mra, &text );
766 				if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
767 					/* cached component tree is broken, just remove it */
768 					free_ComponentData ( a );
769 					return ret;
770 				}
771 				if ( a_alias )
772 					ava->aa_desc = a_alias->aa_aliasing_ad;
773 
774 			} else
775 #endif
776 			{
777 				ret = ordered_value_match( &match, a->a_desc, mr, use,
778 					bv, &ava->aa_value, &text );
779 			}
780 
781 			if( ret != LDAP_SUCCESS ) {
782 				rc = ret;
783 				break;
784 			}
785 
786 			switch ( type ) {
787 			case LDAP_FILTER_EQUALITY:
788 			case LDAP_FILTER_APPROX:
789 				if ( match == 0 ) return LDAP_COMPARE_TRUE;
790 				break;
791 
792 			case LDAP_FILTER_GE:
793 				if ( match >= 0 ) return LDAP_COMPARE_TRUE;
794 				break;
795 
796 			case LDAP_FILTER_LE:
797 				if ( match <= 0 ) return LDAP_COMPARE_TRUE;
798 				break;
799 			}
800 		}
801 	}
802 
803 #ifdef LDAP_COMP_MATCH
804 	if ( a_alias )
805 		ava->aa_desc = a_alias->aa_aliasing_ad;
806 #endif
807 
808 	return rc;
809 }
810 
811 
812 static int
test_presence_filter(Operation * op,Entry * e,AttributeDescription * desc)813 test_presence_filter(
814 	Operation	*op,
815 	Entry		*e,
816 	AttributeDescription *desc )
817 {
818 	Attribute	*a;
819 	int rc;
820 
821 	if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
822 		return LDAP_INSUFFICIENT_ACCESS;
823 	}
824 
825 	if ( desc == slap_schema.si_ad_hasSubordinates ) {
826 		/*
827 		 * XXX: fairly optimistic: if the function is defined,
828 		 * then PRESENCE must succeed, because hasSubordinate
829 		 * is boolean-valued; I think we may live with this
830 		 * simplification by now.
831 		 */
832 		if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
833 			return LDAP_COMPARE_TRUE;
834 		}
835 
836 		return LDAP_COMPARE_FALSE;
837 	}
838 
839 	if ( desc == slap_schema.si_ad_entryDN ||
840 		desc == slap_schema.si_ad_subschemaSubentry )
841 	{
842 		/* entryDN and subschemaSubentry are always present */
843 		return LDAP_COMPARE_TRUE;
844 	}
845 
846 	rc = LDAP_COMPARE_FALSE;
847 
848 	for(a = attrs_find( e->e_attrs, desc );
849 		a != NULL;
850 		a = attrs_find( a->a_next, desc ) )
851 	{
852 		if (( desc != a->a_desc ) && !access_allowed( op,
853 			e, a->a_desc, NULL, ACL_SEARCH, NULL ))
854 		{
855 			rc = LDAP_INSUFFICIENT_ACCESS;
856 			continue;
857 		}
858 
859 		rc = LDAP_COMPARE_TRUE;
860 		break;
861 	}
862 
863 	return rc;
864 }
865 
866 
867 static int
test_filter_and(Operation * op,Entry * e,Filter * flist)868 test_filter_and(
869 	Operation	*op,
870 	Entry	*e,
871 	Filter	*flist )
872 {
873 	Filter	*f;
874 	int rtn = LDAP_COMPARE_TRUE; /* True if empty */
875 
876 	Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
877 
878 	for ( f = flist; f != NULL; f = f->f_next ) {
879 		int rc = test_filter( op, e, f );
880 
881 		if ( rc == LDAP_COMPARE_FALSE ) {
882 			/* filter is False */
883 			rtn = rc;
884 			break;
885 		}
886 
887 		if ( rc != LDAP_COMPARE_TRUE ) {
888 			/* filter is Undefined unless later elements are False */
889 			rtn = rc;
890 		}
891 	}
892 
893 	Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
894 
895 	return rtn;
896 }
897 
898 static int
test_filter_or(Operation * op,Entry * e,Filter * flist)899 test_filter_or(
900 	Operation	*op,
901 	Entry	*e,
902 	Filter	*flist )
903 {
904 	Filter	*f;
905 	int rtn = LDAP_COMPARE_FALSE; /* False if empty */
906 
907 	Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
908 
909 	for ( f = flist; f != NULL; f = f->f_next ) {
910 		int rc = test_filter( op, e, f );
911 
912 		if ( rc == LDAP_COMPARE_TRUE ) {
913 			/* filter is True */
914 			rtn = rc;
915 			break;
916 		}
917 
918 		if ( rc != LDAP_COMPARE_FALSE ) {
919 			/* filter is Undefined unless later elements are True */
920 			rtn = rc;
921 		}
922 	}
923 
924 	Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
925 	return rtn;
926 }
927 
928 
929 static int
test_substrings_filter(Operation * op,Entry * e,Filter * f)930 test_substrings_filter(
931 	Operation	*op,
932 	Entry	*e,
933 	Filter	*f )
934 {
935 	Attribute	*a;
936 	int rc;
937 
938 	Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
939 
940 	if ( !access_allowed( op, e,
941 		f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
942 	{
943 		return LDAP_INSUFFICIENT_ACCESS;
944 	}
945 
946 	rc = LDAP_COMPARE_FALSE;
947 
948 	for(a = attrs_find( e->e_attrs, f->f_sub_desc );
949 		a != NULL;
950 		a = attrs_find( a->a_next, f->f_sub_desc ) )
951 	{
952 		MatchingRule *mr;
953 		struct berval *bv;
954 
955 		if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
956 			e, a->a_desc, NULL, ACL_SEARCH, NULL ))
957 		{
958 			rc = LDAP_INSUFFICIENT_ACCESS;
959 			continue;
960 		}
961 
962 		mr = a->a_desc->ad_type->sat_substr;
963 		if( mr == NULL ) {
964 			rc = LDAP_INAPPROPRIATE_MATCHING;
965 			continue;
966 		}
967 
968 		for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
969 			int ret, match;
970 			const char *text;
971 
972 			ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
973 				bv, f->f_sub, &text );
974 
975 			if( ret != LDAP_SUCCESS ) {
976 				rc = ret;
977 				break;
978 			}
979 			if ( match == 0 ) return LDAP_COMPARE_TRUE;
980 		}
981 	}
982 
983 	Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
984 		rc, 0, 0 );
985 	return rc;
986 }
987