1 /* filterentry.c - apply a filter to an entry */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2007 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17 * All rights reserved.
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.
31 #include <ac/socket.h>
32 #include <ac/string.h>
36 #ifdef LDAP_COMP_MATCH
37 #include "component.h"
40 static int test_filter_and( Operation *op, Entry *e, Filter *flist );
41 static int test_filter_or( Operation *op, Entry *e, Filter *flist );
42 static int test_substrings_filter( Operation *op, Entry *e, Filter *f);
43 static int test_ava_filter( Operation *op,
44 Entry *e, AttributeAssertion *ava, int type );
45 static int test_mra_filter( Operation *op,
46 Entry *e, MatchingRuleAssertion *mra );
47 static int test_presence_filter( Operation *op,
48 Entry *e, AttributeDescription *desc );
52 * test_filter - test a filter against a single entry.
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
67 Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
69 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
70 Debug( LDAP_DEBUG_FILTER, " UNDEFINED\n", 0, 0, 0 );
71 rc = SLAPD_COMPARE_UNDEFINED;
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",
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 );
91 case LDAP_FILTER_SUBSTRINGS:
92 Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
93 rc = test_substrings_filter( op, e, f );
97 Debug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
98 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
102 Debug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
103 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
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 );
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 );
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 );
122 Debug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
123 rc = test_filter_or( op, e, f->f_or );
126 case LDAP_FILTER_NOT:
127 Debug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
128 rc = test_filter( op, e, f->f_not );
130 /* Flip true to false and false to true
131 * but leave Undefined alone.
134 case LDAP_COMPARE_TRUE:
135 rc = LDAP_COMPARE_FALSE;
137 case LDAP_COMPARE_FALSE:
138 rc = LDAP_COMPARE_TRUE;
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 );
149 Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n",
151 rc = LDAP_PROTOCOL_ERROR;
154 Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
158 static int test_mra_filter(
161 MatchingRuleAssertion *mra )
165 BER_MEMFREE_FN *memfree;
166 #ifdef LDAP_COMP_MATCH
167 int i, num_attr_vals = 0;
172 memfree = slap_sl_free;
174 memctx = op->o_tmpmemctx;
175 memfree = op->o_tmpfree;
178 if ( mra->ma_desc ) {
180 * if ma_desc is available, then we're filtering for
181 * one attribute, and SEARCH permissions can be checked
184 if ( !access_allowed( op, e,
185 mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
187 return LDAP_INSUFFICIENT_ACCESS;
190 if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
194 rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
195 SLAP_MR_EXT, &e->e_nname, &mra->ma_value, &text );
198 if( rc != LDAP_SUCCESS ) return rc;
199 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
200 return LDAP_COMPARE_FALSE;
203 for ( a = attrs_find( e->e_attrs, mra->ma_desc );
205 a = attrs_find( a->a_next, mra->ma_desc ) )
208 int normalize_attribute = 0;
210 #ifdef LDAP_COMP_MATCH
211 /* Component Matching */
212 if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
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;
222 /* following malloced will be freed by comp_tree_free () */
223 a->a_comp_data = malloc( sizeof( ComponentData ) +
224 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
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 );
237 /* If ma_rule is not the same as the attribute's
238 * normal rule, then we can't use the a_nvals.
240 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
245 normalize_attribute = 1;
247 #ifdef LDAP_COMP_MATCH
250 for ( ; !BER_BVISNULL( bv ); bv++ ) {
255 #ifdef LDAP_COMP_MATCH
257 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
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 );
265 if ( !a->a_comp_data->cd_tree[i] ) {
266 return LDAP_OPERATIONS_ERROR;
268 rc = value_match( &ret, a->a_desc, mra->ma_rule,
270 (struct berval*)a->a_comp_data->cd_tree[i++],
275 struct berval nbv = BER_BVNULL;
277 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
282 4.5.1. Search Request
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.
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.
295 This should likely be done inside value_match(), by passing
296 the appropriate flags, but this is not done at present.
299 if ( mra->ma_rule->smr_normalize(
300 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
301 mra->ma_rule->smr_syntax,
303 bv, &nbv, memctx ) != LDAP_SUCCESS )
305 /* FIXME: stop processing? */
313 rc = value_match( &ret, a->a_desc, mra->ma_rule,
314 SLAP_MR_EXT, &nbv, &mra->ma_value, &text );
316 if ( nbv.bv_val != bv->bv_val ) {
317 memfree( nbv.bv_val, memctx );
321 if ( rc != LDAP_SUCCESS ) return rc;
322 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
328 * No attribute description: test all
330 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
331 struct berval *bv, value;
332 const char *text = NULL;
334 int normalize_attribute = 0;
336 /* check if matching is appropriate */
337 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
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;
347 /* check search access */
348 if ( !access_allowed( op, e,
349 a->a_desc, &value, ACL_SEARCH, NULL ) )
351 memfree( value.bv_val, memctx );
354 #ifdef LDAP_COMP_MATCH
355 /* Component Matching */
357 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
361 rc = value_match( &ret, a->a_desc, mra->ma_rule,
363 (struct berval*)a, (void*)mra, &text );
364 if ( rc != LDAP_SUCCESS ) break;
367 rc = LDAP_COMPARE_TRUE;
375 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
380 normalize_attribute = 1;
383 for ( ; !BER_BVISNULL( bv ); bv++ ) {
385 struct berval nbv = BER_BVNULL;
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,
393 bv, &nbv, memctx ) != LDAP_SUCCESS )
395 /* FIXME: stop processing? */
403 rc = value_match( &ret, a->a_desc, mra->ma_rule,
404 SLAP_MR_EXT, &nbv, &value, &text );
406 if ( nbv.bv_val != bv->bv_val ) {
407 memfree( nbv.bv_val, memctx );
410 if ( rc != LDAP_SUCCESS ) break;
413 rc = LDAP_COMPARE_TRUE;
417 memfree( value.bv_val, memctx );
418 if ( rc != LDAP_SUCCESS ) return rc;
422 /* check attrs in DN AVAs if required */
423 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
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;
434 /* for each AVA of each RDN ... */
435 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
436 LDAPRDN rdn = dn[ iRDN ];
438 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
439 LDAPAVA *ava = rdn[ iAVA ];
440 struct berval *bv = &ava->la_value,
443 AttributeDescription *ad =
444 (AttributeDescription *)ava->la_private;
448 assert( ad != NULL );
450 if ( mra->ma_desc ) {
451 /* have a mra type? check for subtype */
452 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
455 value = mra->ma_value;
458 const char *text = NULL;
460 /* check if matching is appropriate */
461 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
465 /* normalize for equality */
466 rc = asserted_value_validate_normalize( ad,
468 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
469 &mra->ma_value, &value, &text, memctx );
470 if ( rc != LDAP_SUCCESS ) continue;
472 /* check search access */
473 if ( !access_allowed( op, e,
474 ad, &value, ACL_SEARCH, NULL ) )
476 memfree( value.bv_val, memctx );
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,
487 bv, &nbv, memctx ) != LDAP_SUCCESS )
489 /* FIXME: stop processing? */
500 rc = value_match( &ret, ad, mra->ma_rule, SLAP_MR_EXT,
501 &nbv, &value, &text );
504 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
505 memfree( value.bv_val, memctx );
508 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
509 memfree( nbv.bv_val, memctx );
512 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
514 if ( rc != LDAP_SUCCESS ) {
515 ldap_dnfree_x( dn, memctx );
520 ldap_dnfree_x( dn, memctx );
523 return LDAP_COMPARE_FALSE;
530 AttributeAssertion *ava,
535 #ifdef LDAP_COMP_MATCH
536 int i, num_attr_vals = 0;
537 AttributeAliasing *a_alias = NULL;
540 if ( !access_allowed( op, e,
541 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
543 return LDAP_INSUFFICIENT_ACCESS;
546 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
547 && op && op->o_bd && op->o_bd->be_has_subordinates )
552 if( type != LDAP_FILTER_EQUALITY &&
553 type != LDAP_FILTER_APPROX )
555 /* No other match is allowed */
556 return LDAP_INAPPROPRIATE_MATCHING;
559 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
565 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
568 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
575 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
576 return LDAP_COMPARE_FALSE;
579 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
584 if( type != LDAP_FILTER_EQUALITY &&
585 type != LDAP_FILTER_APPROX )
587 /* No other match is allowed */
588 return LDAP_INAPPROPRIATE_MATCHING;
591 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
592 assert( mr != NULL );
594 rc = value_match( &match, slap_schema.si_ad_entryDN, mr,
595 SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text );
597 if( rc != LDAP_SUCCESS ) return rc;
598 if( match == 0 ) return LDAP_COMPARE_TRUE;
599 return LDAP_COMPARE_FALSE;
602 rc = LDAP_COMPARE_FALSE;
604 #ifdef LDAP_COMP_MATCH
605 if ( is_aliased_attribute && ava->aa_cf )
607 a_alias = is_aliased_attribute ( ava->aa_desc );
609 ava->aa_desc = a_alias->aa_aliased_ad;
615 for(a = attrs_find( e->e_attrs, ava->aa_desc );
617 a = attrs_find( a->a_next, ava->aa_desc ) )
623 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
624 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
626 rc = LDAP_INSUFFICIENT_ACCESS;
630 use = SLAP_MR_EQUALITY;
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;
638 /* fallthru: use EQUALITY matching rule if no APPROX rule */
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;
647 use = SLAP_MR_ORDERING;
648 mr = a->a_desc->ad_type->sat_ordering;
656 rc = LDAP_INAPPROPRIATE_MATCHING;
660 if ( a->a_flags & SLAP_ATTR_SORTED_VALS ) {
662 rc = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
663 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
664 &ava->aa_value, &slot, NULL );
665 if ( rc == LDAP_SUCCESS )
666 return LDAP_COMPARE_TRUE;
667 if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
668 /* If insertion point is not the end of the list, there was
669 * at least one value greater than the assertion.
671 if ( type == LDAP_FILTER_GE && slot < a->a_numvals )
672 return LDAP_COMPARE_TRUE;
673 /* Likewise, if insertion point is not the head of the list,
674 * there was at least one value less than the assertion.
676 if ( type == LDAP_FILTER_LE && slot > 0 )
677 return LDAP_COMPARE_TRUE;
678 return LDAP_COMPARE_FALSE;
683 #ifdef LDAP_COMP_MATCH
684 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
685 /* Component Matching */
686 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
687 if ( num_attr_vals <= 0 )/* no attribute value */
688 return LDAP_INAPPROPRIATE_MATCHING;
689 num_attr_vals++;/* for NULL termination */
691 /* following malloced will be freed by comp_tree_free () */
692 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
694 if ( !a->a_comp_data ) {
695 return LDAP_NO_MEMORY;
698 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
701 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
704 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
705 if ( a->a_comp_data->cd_mem_op == NULL ) {
706 free ( a->a_comp_data );
707 a->a_comp_data = NULL;
708 return LDAP_OPERATIONS_ERROR;
715 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
719 #ifdef LDAP_COMP_MATCH
720 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
721 /* Check if decoded component trees are already linked */
722 struct berval cf_bv = { 20, "componentFilterMatch" };
723 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
724 MatchingRuleAssertion mra;
725 mra.ma_cf = ava->aa_cf;
727 if ( a->a_comp_data->cd_tree[i] == NULL )
728 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
730 if ( !a->a_comp_data->cd_tree[i] ) {
731 free_ComponentData ( a );
732 return LDAP_OPERATIONS_ERROR;
735 ret = value_match( &match, a->a_desc, cf_mr,
737 (struct berval*)a->a_comp_data->cd_tree[i++],
738 (void*)&mra, &text );
739 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
740 /* cached component tree is broken, just remove it */
741 free_ComponentData ( a );
745 ava->aa_desc = a_alias->aa_aliasing_ad;
750 ret = ordered_value_match( &match, a->a_desc, mr, use,
751 bv, &ava->aa_value, &text );
754 if( ret != LDAP_SUCCESS ) {
760 case LDAP_FILTER_EQUALITY:
761 case LDAP_FILTER_APPROX:
762 if ( match == 0 ) return LDAP_COMPARE_TRUE;
766 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
770 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
776 #ifdef LDAP_COMP_MATCH
778 ava->aa_desc = a_alias->aa_aliasing_ad;
786 test_presence_filter(
789 AttributeDescription *desc )
794 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
795 return LDAP_INSUFFICIENT_ACCESS;
798 if ( desc == slap_schema.si_ad_hasSubordinates ) {
800 * XXX: fairly optimistic: if the function is defined,
801 * then PRESENCE must succeed, because hasSubordinate
802 * is boolean-valued; I think we may live with this
803 * simplification by now.
805 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
806 return LDAP_COMPARE_TRUE;
809 return LDAP_COMPARE_FALSE;
812 if ( desc == slap_schema.si_ad_entryDN ||
813 desc == slap_schema.si_ad_subschemaSubentry )
815 /* entryDN and subschemaSubentry are always present */
816 return LDAP_COMPARE_TRUE;
819 rc = LDAP_COMPARE_FALSE;
821 for(a = attrs_find( e->e_attrs, desc );
823 a = attrs_find( a->a_next, desc ) )
825 if (( desc != a->a_desc ) && !access_allowed( op,
826 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
828 rc = LDAP_INSUFFICIENT_ACCESS;
832 rc = LDAP_COMPARE_TRUE;
847 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
849 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
851 for ( f = flist; f != NULL; f = f->f_next ) {
852 int rc = test_filter( op, e, f );
854 if ( rc == LDAP_COMPARE_FALSE ) {
855 /* filter is False */
860 if ( rc != LDAP_COMPARE_TRUE ) {
861 /* filter is Undefined unless later elements are False */
866 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
878 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
880 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
882 for ( f = flist; f != NULL; f = f->f_next ) {
883 int rc = test_filter( op, e, f );
885 if ( rc == LDAP_COMPARE_TRUE ) {
891 if ( rc != LDAP_COMPARE_FALSE ) {
892 /* filter is Undefined unless later elements are True */
897 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
903 test_substrings_filter(
911 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
913 if ( !access_allowed( op, e,
914 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
916 return LDAP_INSUFFICIENT_ACCESS;
919 rc = LDAP_COMPARE_FALSE;
921 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
923 a = attrs_find( a->a_next, f->f_sub_desc ) )
928 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
929 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
931 rc = LDAP_INSUFFICIENT_ACCESS;
935 mr = a->a_desc->ad_type->sat_substr;
937 rc = LDAP_INAPPROPRIATE_MATCHING;
941 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
945 ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
946 bv, f->f_sub, &text );
948 if( ret != LDAP_SUCCESS ) {
952 if ( match == 0 ) return LDAP_COMPARE_TRUE;
956 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",