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-2011 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
40static int	test_filter_and( Operation *op, Entry *e, Filter *flist );
41static int	test_filter_or( Operation *op, Entry *e, Filter *flist );
42static int	test_substrings_filter( Operation *op, Entry *e, Filter *f);
43static int	test_ava_filter( Operation *op,
44	Entry *e, AttributeAssertion *ava, int type );
45static int	test_mra_filter( Operation *op,
46	Entry *e, MatchingRuleAssertion *mra );
47static 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
60int
61test_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	}
153out:
154	Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
155	return( rc );
156}
157
158static 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
503cleanup:;
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
526static int
527test_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
812static int
813test_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
867static int
868test_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
898static int
899test_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
929static int
930test_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