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