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 ) {
216 !BER_BVISNULL( &a->a_vals[num_attr_vals] );
221 if ( num_attr_vals <= 0 ) {
222 /* no attribute value */
223 return LDAP_INAPPROPRIATE_MATCHING;
227 /* following malloced will be freed by comp_tree_free () */
228 a->a_comp_data = malloc( sizeof( ComponentData ) +
229 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
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 );
242 /* If ma_rule is not the same as the attribute's
243 * normal rule, then we can't use the a_nvals.
245 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
250 normalize_attribute = 1;
252 #ifdef LDAP_COMP_MATCH
255 for ( ; !BER_BVISNULL( bv ); bv++ ) {
260 #ifdef LDAP_COMP_MATCH
262 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
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 );
270 if ( !a->a_comp_data->cd_tree[i] ) {
271 return LDAP_OPERATIONS_ERROR;
273 rc = value_match( &ret, a->a_desc, mra->ma_rule,
275 (struct berval*)a->a_comp_data->cd_tree[i++],
280 struct berval nbv = BER_BVNULL;
282 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
287 4.5.1. Search Request
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.
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.
300 This should likely be done inside value_match(), by passing
301 the appropriate flags, but this is not done at present.
304 if ( mra->ma_rule->smr_normalize(
305 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
306 mra->ma_rule->smr_syntax,
308 bv, &nbv, memctx ) != LDAP_SUCCESS )
310 /* FIXME: stop processing? */
318 rc = value_match( &ret, a->a_desc, mra->ma_rule,
319 SLAP_MR_EXT, &nbv, &mra->ma_value, &text );
321 if ( nbv.bv_val != bv->bv_val ) {
322 memfree( nbv.bv_val, memctx );
326 if ( rc != LDAP_SUCCESS ) return rc;
327 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
333 * No attribute description: test all
335 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
336 struct berval *bv, value;
337 const char *text = NULL;
339 int normalize_attribute = 0;
341 /* check if matching is appropriate */
342 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
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;
352 /* check search access */
353 if ( !access_allowed( op, e,
354 a->a_desc, &value, ACL_SEARCH, NULL ) )
356 memfree( value.bv_val, memctx );
359 #ifdef LDAP_COMP_MATCH
360 /* Component Matching */
362 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
366 rc = value_match( &ret, a->a_desc, mra->ma_rule,
368 (struct berval*)a, (void*)mra, &text );
369 if ( rc != LDAP_SUCCESS ) break;
372 rc = LDAP_COMPARE_TRUE;
380 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
385 normalize_attribute = 1;
388 for ( ; !BER_BVISNULL( bv ); bv++ ) {
390 struct berval nbv = BER_BVNULL;
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,
398 bv, &nbv, memctx ) != LDAP_SUCCESS )
400 /* FIXME: stop processing? */
408 rc = value_match( &ret, a->a_desc, mra->ma_rule,
409 SLAP_MR_EXT, &nbv, &value, &text );
411 if ( nbv.bv_val != bv->bv_val ) {
412 memfree( nbv.bv_val, memctx );
415 if ( rc != LDAP_SUCCESS ) break;
418 rc = LDAP_COMPARE_TRUE;
422 memfree( value.bv_val, memctx );
423 if ( rc != LDAP_SUCCESS ) return rc;
427 /* check attrs in DN AVAs if required */
428 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
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;
439 /* for each AVA of each RDN ... */
440 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
441 LDAPRDN rdn = dn[ iRDN ];
443 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
444 LDAPAVA *ava = rdn[ iAVA ];
445 struct berval *bv = &ava->la_value,
448 AttributeDescription *ad =
449 (AttributeDescription *)ava->la_private;
453 assert( ad != NULL );
455 if ( mra->ma_desc ) {
456 /* have a mra type? check for subtype */
457 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
460 value = mra->ma_value;
463 const char *text = NULL;
465 /* check if matching is appropriate */
466 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
470 /* normalize for equality */
471 rc = asserted_value_validate_normalize( ad,
473 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
474 &mra->ma_value, &value, &text, memctx );
475 if ( rc != LDAP_SUCCESS ) continue;
477 /* check search access */
478 if ( !access_allowed( op, e,
479 ad, &value, ACL_SEARCH, NULL ) )
481 memfree( value.bv_val, memctx );
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,
492 bv, &nbv, memctx ) != LDAP_SUCCESS )
494 /* FIXME: stop processing? */
505 rc = value_match( &ret, ad, mra->ma_rule, SLAP_MR_EXT,
506 &nbv, &value, &text );
509 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
510 memfree( value.bv_val, memctx );
513 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
514 memfree( nbv.bv_val, memctx );
517 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
519 if ( rc != LDAP_SUCCESS ) {
520 ldap_dnfree_x( dn, memctx );
525 ldap_dnfree_x( dn, memctx );
528 return LDAP_COMPARE_FALSE;
535 AttributeAssertion *ava,
540 #ifdef LDAP_COMP_MATCH
541 int i, num_attr_vals = 0;
542 AttributeAliasing *a_alias = NULL;
545 if ( !access_allowed( op, e,
546 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
548 return LDAP_INSUFFICIENT_ACCESS;
551 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
552 && op && op->o_bd && op->o_bd->be_has_subordinates )
557 if( type != LDAP_FILTER_EQUALITY &&
558 type != LDAP_FILTER_APPROX )
560 /* No other match is allowed */
561 return LDAP_INAPPROPRIATE_MATCHING;
564 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
570 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
573 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
580 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
581 return LDAP_COMPARE_FALSE;
584 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
589 if( type != LDAP_FILTER_EQUALITY &&
590 type != LDAP_FILTER_APPROX )
592 /* No other match is allowed */
593 return LDAP_INAPPROPRIATE_MATCHING;
596 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
597 assert( mr != NULL );
599 rc = value_match( &match, slap_schema.si_ad_entryDN, mr,
600 SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text );
602 if( rc != LDAP_SUCCESS ) return rc;
603 if( match == 0 ) return LDAP_COMPARE_TRUE;
604 return LDAP_COMPARE_FALSE;
607 rc = LDAP_COMPARE_FALSE;
609 #ifdef LDAP_COMP_MATCH
610 if ( is_aliased_attribute && ava->aa_cf )
612 a_alias = is_aliased_attribute ( ava->aa_desc );
614 ava->aa_desc = a_alias->aa_aliased_ad;
620 for(a = attrs_find( e->e_attrs, ava->aa_desc );
622 a = attrs_find( a->a_next, ava->aa_desc ) )
628 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
629 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
631 rc = LDAP_INSUFFICIENT_ACCESS;
635 use = SLAP_MR_EQUALITY;
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;
643 /* fallthru: use EQUALITY matching rule if no APPROX rule */
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;
652 use = SLAP_MR_ORDERING;
653 mr = a->a_desc->ad_type->sat_ordering;
661 rc = LDAP_INAPPROPRIATE_MATCHING;
665 #ifdef LDAP_COMP_MATCH
666 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
667 /* Component Matching */
668 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
669 if ( num_attr_vals <= 0 )/* no attribute value */
670 return LDAP_INAPPROPRIATE_MATCHING;
671 num_attr_vals++;/* for NULL termination */
673 /* following malloced will be freed by comp_tree_free () */
674 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
676 if ( !a->a_comp_data ) {
677 return LDAP_NO_MEMORY;
680 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
683 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
686 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
687 if ( a->a_comp_data->cd_mem_op == NULL ) {
688 free ( a->a_comp_data );
689 a->a_comp_data = NULL;
690 return LDAP_OPERATIONS_ERROR;
697 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
701 #ifdef LDAP_COMP_MATCH
702 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
703 /* Check if decoded component trees are already linked */
704 struct berval cf_bv = { 20, "componentFilterMatch" };
705 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
706 MatchingRuleAssertion mra;
707 mra.ma_cf = ava->aa_cf;
709 if ( a->a_comp_data->cd_tree[i] == NULL )
710 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
712 if ( !a->a_comp_data->cd_tree[i] ) {
713 free_ComponentData ( a );
714 return LDAP_OPERATIONS_ERROR;
717 ret = value_match( &match, a->a_desc, cf_mr,
719 (struct berval*)a->a_comp_data->cd_tree[i++],
720 (void*)&mra, &text );
721 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
722 /* cached component tree is broken, just remove it */
723 free_ComponentData ( a );
727 ava->aa_desc = a_alias->aa_aliasing_ad;
732 ret = value_match( &match, a->a_desc, mr, use,
733 bv, &ava->aa_value, &text );
736 if( ret != LDAP_SUCCESS ) {
742 case LDAP_FILTER_EQUALITY:
743 case LDAP_FILTER_APPROX:
744 if ( match == 0 ) return LDAP_COMPARE_TRUE;
748 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
752 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
758 #ifdef LDAP_COMP_MATCH
760 ava->aa_desc = a_alias->aa_aliasing_ad;
768 test_presence_filter(
771 AttributeDescription *desc )
776 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
777 return LDAP_INSUFFICIENT_ACCESS;
780 if ( desc == slap_schema.si_ad_hasSubordinates ) {
782 * XXX: fairly optimistic: if the function is defined,
783 * then PRESENCE must succeed, because hasSubordinate
784 * is boolean-valued; I think we may live with this
785 * simplification by now.
787 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
788 return LDAP_COMPARE_TRUE;
791 return LDAP_COMPARE_FALSE;
794 if ( desc == slap_schema.si_ad_entryDN ||
795 desc == slap_schema.si_ad_subschemaSubentry )
797 /* entryDN and subschemaSubentry are always present */
798 return LDAP_COMPARE_TRUE;
801 rc = LDAP_COMPARE_FALSE;
803 for(a = attrs_find( e->e_attrs, desc );
805 a = attrs_find( a->a_next, desc ) )
807 if (( desc != a->a_desc ) && !access_allowed( op,
808 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
810 rc = LDAP_INSUFFICIENT_ACCESS;
814 rc = LDAP_COMPARE_TRUE;
829 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
831 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
833 for ( f = flist; f != NULL; f = f->f_next ) {
834 int rc = test_filter( op, e, f );
836 if ( rc == LDAP_COMPARE_FALSE ) {
837 /* filter is False */
842 if ( rc != LDAP_COMPARE_TRUE ) {
843 /* filter is Undefined unless later elements are False */
848 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
860 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
862 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
864 for ( f = flist; f != NULL; f = f->f_next ) {
865 int rc = test_filter( op, e, f );
867 if ( rc == LDAP_COMPARE_TRUE ) {
873 if ( rc != LDAP_COMPARE_FALSE ) {
874 /* filter is Undefined unless later elements are True */
879 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
885 test_substrings_filter(
893 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
895 if ( !access_allowed( op, e,
896 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
898 return LDAP_INSUFFICIENT_ACCESS;
901 rc = LDAP_COMPARE_FALSE;
903 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
905 a = attrs_find( a->a_next, f->f_sub_desc ) )
910 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
911 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
913 rc = LDAP_INSUFFICIENT_ACCESS;
917 mr = a->a_desc->ad_type->sat_substr;
919 rc = LDAP_INAPPROPRIATE_MATCHING;
923 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
927 ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
928 bv, f->f_sub, &text );
930 if( ret != LDAP_SUCCESS ) {
934 if ( match == 0 ) return LDAP_COMPARE_TRUE;
938 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",