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