filterentry.c revision 1.2
1/*	$NetBSD: filterentry.c,v 1.2 2020/08/11 13:15:39 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-2020 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.2 2020/08/11 13:15:39 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
45static int	test_filter_and( Operation *op, Entry *e, Filter *flist );
46static int	test_filter_or( Operation *op, Entry *e, Filter *flist );
47static int	test_substrings_filter( Operation *op, Entry *e, Filter *f);
48static int	test_ava_filter( Operation *op,
49	Entry *e, AttributeAssertion *ava, int type );
50static int	test_mra_filter( Operation *op,
51	Entry *e, MatchingRuleAssertion *mra );
52static 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
65int
66test_filter(
67    Operation	*op,
68    Entry	*e,
69    Filter	*f )
70{
71	int	rc;
72	Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
73
74	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
75		Debug( LDAP_DEBUG_FILTER, "    UNDEFINED\n", 0, 0, 0 );
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, 0 );
87
88		rc = f->f_result;
89		break;
90
91	case LDAP_FILTER_EQUALITY:
92		Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
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", 0, 0, 0 );
98		rc = test_substrings_filter( op, e, f );
99		break;
100
101	case LDAP_FILTER_GE:
102		Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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, 0, 0 );
156		rc = LDAP_PROTOCOL_ERROR;
157	}
158out:
159	Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
160	return( rc );
161}
162
163static 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
508cleanup:;
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
531static int
532test_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
817static int
818test_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
872static int
873test_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", 0, 0, 0 );
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, 0, 0 );
899
900	return rtn;
901}
902
903static int
904test_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", 0, 0, 0 );
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, 0, 0 );
930	return rtn;
931}
932
933
934static int
935test_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", 0, 0, 0 );
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, 0, 0 );
990	return rc;
991}
992