1 /* filterentry.c - apply a filter to an entry */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 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 switch ( f->f_choice ) {
70 case SLAPD_FILTER_COMPUTED:
71 Debug( LDAP_DEBUG_FILTER, " COMPUTED %s (%d)\n",
72 f->f_result == LDAP_COMPARE_FALSE ? "false" :
73 f->f_result == LDAP_COMPARE_TRUE ? "true" :
74 f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
80 case LDAP_FILTER_EQUALITY:
81 Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
82 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
85 case LDAP_FILTER_SUBSTRINGS:
86 Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
87 rc = test_substrings_filter( op, e, f );
91 Debug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
92 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
96 Debug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
97 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
100 case LDAP_FILTER_PRESENT:
101 Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
102 rc = test_presence_filter( op, e, f->f_desc );
105 case LDAP_FILTER_APPROX:
106 Debug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
107 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
110 case LDAP_FILTER_AND:
111 Debug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
112 rc = test_filter_and( op, e, f->f_and );
116 Debug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
117 rc = test_filter_or( op, e, f->f_or );
120 case LDAP_FILTER_NOT:
121 Debug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
122 rc = test_filter( op, e, f->f_not );
124 /* Flip true to false and false to true
125 * but leave Undefined alone.
128 case LDAP_COMPARE_TRUE:
129 rc = LDAP_COMPARE_FALSE;
131 case LDAP_COMPARE_FALSE:
132 rc = LDAP_COMPARE_TRUE;
137 case LDAP_FILTER_EXT:
138 Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 );
139 rc = test_mra_filter( op, e, f->f_mra );
143 Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n",
145 rc = LDAP_PROTOCOL_ERROR;
148 Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
152 static int test_mra_filter(
155 MatchingRuleAssertion *mra )
159 BER_MEMFREE_FN *memfree;
160 #ifdef LDAP_COMP_MATCH
161 int i, num_attr_vals = 0;
166 memfree = slap_sl_free;
168 memctx = op->o_tmpmemctx;
169 memfree = op->o_tmpfree;
172 if ( mra->ma_desc ) {
174 * if ma_desc is available, then we're filtering for
175 * one attribute, and SEARCH permissions can be checked
178 if ( !access_allowed( op, e,
179 mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
181 return LDAP_INSUFFICIENT_ACCESS;
184 if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
188 rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
189 SLAP_MR_EXT, &e->e_nname, &mra->ma_value, &text );
192 if( rc != LDAP_SUCCESS ) return rc;
193 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
194 return LDAP_COMPARE_FALSE;
197 for ( a = attrs_find( e->e_attrs, mra->ma_desc );
199 a = attrs_find( a->a_next, mra->ma_desc ) )
202 int normalize_attribute = 0;
204 #ifdef LDAP_COMP_MATCH
205 /* Component Matching */
206 if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
208 if ( !a->a_comp_data ) {
210 !BER_BVISNULL( &a->a_vals[num_attr_vals] );
215 if ( num_attr_vals <= 0 ) {
216 /* no attribute value */
217 return LDAP_INAPPROPRIATE_MATCHING;
221 /* following malloced will be freed by comp_tree_free () */
222 a->a_comp_data = malloc( sizeof( ComponentData ) +
223 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
225 if ( !a->a_comp_data ) return LDAP_NO_MEMORY;
226 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)
227 ((char*)a->a_comp_data + sizeof(ComponentData));
228 a->a_comp_data->cd_tree[num_attr_vals - 1] =
229 (ComponentSyntaxInfo*) NULL;
230 a->a_comp_data->cd_mem_op =
231 nibble_mem_allocator( 1024*16, 1024 );
236 /* If ma_rule is not the same as the attribute's
237 * normal rule, then we can't use the a_nvals.
239 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
244 normalize_attribute = 1;
246 #ifdef LDAP_COMP_MATCH
249 for ( ; !BER_BVISNULL( bv ); bv++ ) {
254 #ifdef LDAP_COMP_MATCH
256 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
258 /* Check if decoded component trees are already linked */
259 if ( num_attr_vals ) {
260 a->a_comp_data->cd_tree[i] = attr_converter(
261 a, a->a_desc->ad_type->sat_syntax, bv );
264 if ( !a->a_comp_data->cd_tree[i] ) {
265 return LDAP_OPERATIONS_ERROR;
267 rc = value_match( &ret, a->a_desc, mra->ma_rule,
269 (struct berval*)a->a_comp_data->cd_tree[i++],
274 struct berval nbv = BER_BVNULL;
276 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
279 Document: draft-ietf-ldapbis-protocol
281 4.5.1. Search Request
283 If the type field is present and the matchingRule is present,
284 the matchValue is compared against entry attributes of the
285 specified type. In this case, the matchingRule MUST be one
286 suitable for use with the specified type (see [Syntaxes]),
287 otherwise the filter item is Undefined.
290 In this case, since the matchingRule requires the assertion
291 value to be normalized, we normalize the attribute value
292 according to the syntax of the matchingRule.
294 This should likely be done inside value_match(), by passing
295 the appropriate flags, but this is not done at present.
298 if ( mra->ma_rule->smr_normalize(
299 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
300 mra->ma_rule->smr_syntax,
302 bv, &nbv, memctx ) != LDAP_SUCCESS )
304 /* FIXME: stop processing? */
312 rc = value_match( &ret, a->a_desc, mra->ma_rule,
313 SLAP_MR_EXT, &nbv, &mra->ma_value, &text );
315 if ( nbv.bv_val != bv->bv_val ) {
316 memfree( nbv.bv_val, memctx );
320 if ( rc != LDAP_SUCCESS ) return rc;
321 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
327 * No attribute description: test all
329 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
330 struct berval *bv, value;
331 const char *text = NULL;
333 int normalize_attribute = 0;
335 /* check if matching is appropriate */
336 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
340 /* normalize for equality */
341 rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
342 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
343 &mra->ma_value, &value, &text, memctx );
344 if ( rc != LDAP_SUCCESS ) continue;
346 /* check search access */
347 if ( !access_allowed( op, e,
348 a->a_desc, &value, ACL_SEARCH, NULL ) )
350 memfree( value.bv_val, memctx );
353 #ifdef LDAP_COMP_MATCH
354 /* Component Matching */
356 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
360 rc = value_match( &ret, a->a_desc, mra->ma_rule,
362 (struct berval*)a, (void*)mra, &text );
363 if ( rc != LDAP_SUCCESS ) break;
366 rc = LDAP_COMPARE_TRUE;
374 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
379 normalize_attribute = 1;
382 for ( ; !BER_BVISNULL( bv ); bv++ ) {
384 struct berval nbv = BER_BVNULL;
386 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
387 /* see comment above */
388 if ( mra->ma_rule->smr_normalize(
389 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
390 mra->ma_rule->smr_syntax,
392 bv, &nbv, memctx ) != LDAP_SUCCESS )
394 /* FIXME: stop processing? */
402 rc = value_match( &ret, a->a_desc, mra->ma_rule,
403 SLAP_MR_EXT, &nbv, &value, &text );
405 if ( nbv.bv_val != bv->bv_val ) {
406 memfree( nbv.bv_val, memctx );
409 if ( rc != LDAP_SUCCESS ) break;
412 rc = LDAP_COMPARE_TRUE;
416 memfree( value.bv_val, memctx );
417 if ( rc != LDAP_SUCCESS ) return rc;
421 /* check attrs in DN AVAs if required */
422 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
427 /* parse and pretty the dn */
428 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
429 if ( rc != LDAP_SUCCESS ) {
430 return LDAP_INVALID_SYNTAX;
433 /* for each AVA of each RDN ... */
434 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
435 LDAPRDN rdn = dn[ iRDN ];
437 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
438 LDAPAVA *ava = rdn[ iAVA ];
439 struct berval *bv = &ava->la_value,
442 AttributeDescription *ad =
443 (AttributeDescription *)ava->la_private;
447 assert( ad != NULL );
449 if ( mra->ma_desc ) {
450 /* have a mra type? check for subtype */
451 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
454 value = mra->ma_value;
457 const char *text = NULL;
459 /* check if matching is appropriate */
460 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
464 /* normalize for equality */
465 rc = asserted_value_validate_normalize( ad,
467 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
468 &mra->ma_value, &value, &text, memctx );
469 if ( rc != LDAP_SUCCESS ) continue;
471 /* check search access */
472 if ( !access_allowed( op, e,
473 ad, &value, ACL_SEARCH, NULL ) )
475 memfree( value.bv_val, memctx );
480 if ( mra->ma_rule->smr_normalize ) {
481 /* see comment above */
482 if ( mra->ma_rule->smr_normalize(
483 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
484 mra->ma_rule->smr_syntax,
486 bv, &nbv, memctx ) != LDAP_SUCCESS )
488 /* FIXME: stop processing? */
499 rc = value_match( &ret, ad, mra->ma_rule, SLAP_MR_EXT,
500 &nbv, &value, &text );
503 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
504 memfree( value.bv_val, memctx );
507 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
508 memfree( nbv.bv_val, memctx );
511 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
513 if ( rc != LDAP_SUCCESS ) {
514 ldap_dnfree_x( dn, memctx );
519 ldap_dnfree_x( dn, memctx );
522 return LDAP_COMPARE_FALSE;
529 AttributeAssertion *ava,
534 #ifdef LDAP_COMP_MATCH
535 int i, num_attr_vals = 0;
536 AttributeAliasing *a_alias = NULL;
539 if ( !access_allowed( op, e,
540 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
542 return LDAP_INSUFFICIENT_ACCESS;
545 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
546 && op && op->o_bd && op->o_bd->be_has_subordinates )
551 if( type != LDAP_FILTER_EQUALITY &&
552 type != LDAP_FILTER_APPROX )
554 /* No other match is allowed */
555 return LDAP_INAPPROPRIATE_MATCHING;
558 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
564 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
567 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
574 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
575 return LDAP_COMPARE_FALSE;
578 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
583 if( type != LDAP_FILTER_EQUALITY &&
584 type != LDAP_FILTER_APPROX )
586 /* No other match is allowed */
587 return LDAP_INAPPROPRIATE_MATCHING;
590 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
591 assert( mr != NULL );
593 rc = value_match( &match, slap_schema.si_ad_entryDN, mr,
594 SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text );
596 if( rc != LDAP_SUCCESS ) return rc;
597 if( match == 0 ) return LDAP_COMPARE_TRUE;
598 return LDAP_COMPARE_FALSE;
601 rc = LDAP_COMPARE_FALSE;
603 #ifdef LDAP_COMP_MATCH
604 if ( is_aliased_attribute && ava->aa_cf )
606 a_alias = is_aliased_attribute ( ava->aa_desc );
608 ava->aa_desc = a_alias->aa_aliased_ad;
614 for(a = attrs_find( e->e_attrs, ava->aa_desc );
616 a = attrs_find( a->a_next, ava->aa_desc ) )
622 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
623 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
625 rc = LDAP_INSUFFICIENT_ACCESS;
629 use = SLAP_MR_EQUALITY;
632 case LDAP_FILTER_APPROX:
633 use = SLAP_MR_EQUALITY_APPROX;
634 mr = a->a_desc->ad_type->sat_approx;
635 if( mr != NULL ) break;
637 /* fallthru: use EQUALITY matching rule if no APPROX rule */
639 case LDAP_FILTER_EQUALITY:
640 /* use variable set above so fall thru use is not clobbered */
641 mr = a->a_desc->ad_type->sat_equality;
646 use = SLAP_MR_ORDERING;
647 mr = a->a_desc->ad_type->sat_ordering;
655 rc = LDAP_INAPPROPRIATE_MATCHING;
659 #ifdef LDAP_COMP_MATCH
660 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
661 /* Component Matching */
662 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
663 if ( num_attr_vals <= 0 )/* no attribute value */
664 return LDAP_INAPPROPRIATE_MATCHING;
665 num_attr_vals++;/* for NULL termination */
667 /* following malloced will be freed by comp_tree_free () */
668 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
670 if ( !a->a_comp_data ) {
671 return LDAP_NO_MEMORY;
674 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
677 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
680 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
681 if ( a->a_comp_data->cd_mem_op == NULL ) {
682 free ( a->a_comp_data );
683 a->a_comp_data = NULL;
684 return LDAP_OPERATIONS_ERROR;
691 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
695 #ifdef LDAP_COMP_MATCH
696 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
697 /* Check if decoded component trees are already linked */
698 struct berval cf_bv = { 20, "componentFilterMatch" };
699 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
700 MatchingRuleAssertion mra;
701 mra.ma_cf = ava->aa_cf;
703 if ( a->a_comp_data->cd_tree[i] == NULL )
704 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
706 if ( !a->a_comp_data->cd_tree[i] ) {
707 free_ComponentData ( a );
708 return LDAP_OPERATIONS_ERROR;
711 ret = value_match( &match, a->a_desc, cf_mr,
713 (struct berval*)a->a_comp_data->cd_tree[i++],
714 (void*)&mra, &text );
715 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
716 /* cached component tree is broken, just remove it */
717 free_ComponentData ( a );
721 ava->aa_desc = a_alias->aa_aliasing_ad;
726 ret = value_match( &match, a->a_desc, mr, use,
727 bv, &ava->aa_value, &text );
730 if( ret != LDAP_SUCCESS ) {
736 case LDAP_FILTER_EQUALITY:
737 case LDAP_FILTER_APPROX:
738 if ( match == 0 ) return LDAP_COMPARE_TRUE;
742 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
746 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
752 #ifdef LDAP_COMP_MATCH
754 ava->aa_desc = a_alias->aa_aliasing_ad;
762 test_presence_filter(
765 AttributeDescription *desc )
770 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
771 return LDAP_INSUFFICIENT_ACCESS;
774 if ( desc == slap_schema.si_ad_hasSubordinates ) {
776 * XXX: fairly optimistic: if the function is defined,
777 * then PRESENCE must succeed, because hasSubordinate
778 * is boolean-valued; I think we may live with this
779 * simplification by now.
781 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
782 return LDAP_COMPARE_TRUE;
785 return LDAP_COMPARE_FALSE;
788 if ( desc == slap_schema.si_ad_entryDN ||
789 desc == slap_schema.si_ad_subschemaSubentry )
791 /* entryDN and subschemaSubentry are always present */
792 return LDAP_COMPARE_TRUE;
795 rc = LDAP_COMPARE_FALSE;
797 for(a = attrs_find( e->e_attrs, desc );
799 a = attrs_find( a->a_next, desc ) )
801 if (( desc != a->a_desc ) && !access_allowed( op,
802 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
804 rc = LDAP_INSUFFICIENT_ACCESS;
808 rc = LDAP_COMPARE_TRUE;
823 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
825 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
827 for ( f = flist; f != NULL; f = f->f_next ) {
828 int rc = test_filter( op, e, f );
830 if ( rc == LDAP_COMPARE_FALSE ) {
831 /* filter is False */
836 if ( rc != LDAP_COMPARE_TRUE ) {
837 /* filter is Undefined unless later elements are False */
842 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
854 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
856 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
858 for ( f = flist; f != NULL; f = f->f_next ) {
859 int rc = test_filter( op, e, f );
861 if ( rc == LDAP_COMPARE_TRUE ) {
867 if ( rc != LDAP_COMPARE_FALSE ) {
868 /* filter is Undefined unless later elements are True */
873 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
879 test_substrings_filter(
887 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
889 if ( !access_allowed( op, e,
890 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
892 return LDAP_INSUFFICIENT_ACCESS;
895 rc = LDAP_COMPARE_FALSE;
897 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
899 a = attrs_find( a->a_next, f->f_sub_desc ) )
904 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
905 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
907 rc = LDAP_INSUFFICIENT_ACCESS;
911 mr = a->a_desc->ad_type->sat_substr;
913 rc = LDAP_INAPPROPRIATE_MATCHING;
917 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
921 ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
922 bv, f->f_sub, &text );
924 if( ret != LDAP_SUCCESS ) {
928 if ( match == 0 ) return LDAP_COMPARE_TRUE;
932 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",