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 #ifdef LDAP_COMP_MATCH
661 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
662 /* Component Matching */
663 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
664 if ( num_attr_vals <= 0 )/* no attribute value */
665 return LDAP_INAPPROPRIATE_MATCHING;
666 num_attr_vals++;/* for NULL termination */
668 /* following malloced will be freed by comp_tree_free () */
669 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
671 if ( !a->a_comp_data ) {
672 return LDAP_NO_MEMORY;
675 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
678 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
681 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
682 if ( a->a_comp_data->cd_mem_op == NULL ) {
683 free ( a->a_comp_data );
684 a->a_comp_data = NULL;
685 return LDAP_OPERATIONS_ERROR;
692 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
696 #ifdef LDAP_COMP_MATCH
697 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
698 /* Check if decoded component trees are already linked */
699 struct berval cf_bv = { 20, "componentFilterMatch" };
700 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
701 MatchingRuleAssertion mra;
702 mra.ma_cf = ava->aa_cf;
704 if ( a->a_comp_data->cd_tree[i] == NULL )
705 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
707 if ( !a->a_comp_data->cd_tree[i] ) {
708 free_ComponentData ( a );
709 return LDAP_OPERATIONS_ERROR;
712 ret = value_match( &match, a->a_desc, cf_mr,
714 (struct berval*)a->a_comp_data->cd_tree[i++],
715 (void*)&mra, &text );
716 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
717 /* cached component tree is broken, just remove it */
718 free_ComponentData ( a );
722 ava->aa_desc = a_alias->aa_aliasing_ad;
727 ret = ordered_value_match( &match, a->a_desc, mr, use,
728 bv, &ava->aa_value, &text );
731 if( ret != LDAP_SUCCESS ) {
737 case LDAP_FILTER_EQUALITY:
738 case LDAP_FILTER_APPROX:
739 if ( match == 0 ) return LDAP_COMPARE_TRUE;
743 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
747 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
753 #ifdef LDAP_COMP_MATCH
755 ava->aa_desc = a_alias->aa_aliasing_ad;
763 test_presence_filter(
766 AttributeDescription *desc )
771 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
772 return LDAP_INSUFFICIENT_ACCESS;
775 if ( desc == slap_schema.si_ad_hasSubordinates ) {
777 * XXX: fairly optimistic: if the function is defined,
778 * then PRESENCE must succeed, because hasSubordinate
779 * is boolean-valued; I think we may live with this
780 * simplification by now.
782 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
783 return LDAP_COMPARE_TRUE;
786 return LDAP_COMPARE_FALSE;
789 if ( desc == slap_schema.si_ad_entryDN ||
790 desc == slap_schema.si_ad_subschemaSubentry )
792 /* entryDN and subschemaSubentry are always present */
793 return LDAP_COMPARE_TRUE;
796 rc = LDAP_COMPARE_FALSE;
798 for(a = attrs_find( e->e_attrs, desc );
800 a = attrs_find( a->a_next, desc ) )
802 if (( desc != a->a_desc ) && !access_allowed( op,
803 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
805 rc = LDAP_INSUFFICIENT_ACCESS;
809 rc = LDAP_COMPARE_TRUE;
824 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
826 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
828 for ( f = flist; f != NULL; f = f->f_next ) {
829 int rc = test_filter( op, e, f );
831 if ( rc == LDAP_COMPARE_FALSE ) {
832 /* filter is False */
837 if ( rc != LDAP_COMPARE_TRUE ) {
838 /* filter is Undefined unless later elements are False */
843 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
855 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
857 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
859 for ( f = flist; f != NULL; f = f->f_next ) {
860 int rc = test_filter( op, e, f );
862 if ( rc == LDAP_COMPARE_TRUE ) {
868 if ( rc != LDAP_COMPARE_FALSE ) {
869 /* filter is Undefined unless later elements are True */
874 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
880 test_substrings_filter(
888 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
890 if ( !access_allowed( op, e,
891 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
893 return LDAP_INSUFFICIENT_ACCESS;
896 rc = LDAP_COMPARE_FALSE;
898 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
900 a = attrs_find( a->a_next, f->f_sub_desc ) )
905 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
906 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
908 rc = LDAP_INSUFFICIENT_ACCESS;
912 mr = a->a_desc->ad_type->sat_substr;
914 rc = LDAP_INAPPROPRIATE_MATCHING;
918 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
922 ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
923 bv, f->f_sub, &text );
925 if( ret != LDAP_SUCCESS ) {
929 if ( match == 0 ) return LDAP_COMPARE_TRUE;
933 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",