1 /* filterentry.c - apply a filter to an entry */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2005 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;
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 0, &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, 0,
268 (struct berval*)a->a_comp_data->cd_tree[i++],
273 struct berval nbv = BER_BVNULL;
275 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
278 Document: draft-ietf-ldapbis-protocol
280 4.5.1. Search Request
282 If the type field is present and the matchingRule is present,
283 the matchValue is compared against entry attributes of the
284 specified type. In this case, the matchingRule MUST be one
285 suitable for use with the specified type (see [Syntaxes]),
286 otherwise the filter item is Undefined.
289 In this case, since the matchingRule requires the assertion
290 value to be normalized, we normalize the attribute value
291 according to the syntax of the matchingRule.
293 This should likely be done inside value_match(), by passing
294 the appropriate flags, but this is not done at present.
297 if ( mra->ma_rule->smr_normalize(
298 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
299 mra->ma_rule->smr_syntax,
301 bv, &nbv, memctx ) != LDAP_SUCCESS )
303 /* FIXME: stop processing? */
311 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
312 &nbv, &mra->ma_value, &text );
314 if ( nbv.bv_val != bv->bv_val ) {
315 memfree( nbv.bv_val, memctx );
319 if ( rc != LDAP_SUCCESS ) return rc;
320 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
326 * No attribute description: test all
328 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
329 struct berval *bv, value;
330 const char *text = NULL;
332 int normalize_attribute = 0;
334 /* check if matching is appropriate */
335 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
339 /* normalize for equality */
340 rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
341 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
342 &mra->ma_value, &value, &text, memctx );
343 if ( rc != LDAP_SUCCESS ) continue;
345 /* check search access */
346 if ( !access_allowed( op, e,
347 a->a_desc, &value, ACL_SEARCH, NULL ) )
349 memfree( value.bv_val, memctx );
352 #ifdef LDAP_COMP_MATCH
353 /* Component Matching */
355 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
359 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
360 (struct berval*)a, (void*)mra, &text );
361 if ( rc != LDAP_SUCCESS ) break;
364 rc = LDAP_COMPARE_TRUE;
372 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
377 normalize_attribute = 1;
380 for ( ; !BER_BVISNULL( bv ); bv++ ) {
382 struct berval nbv = BER_BVNULL;
384 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
385 /* see comment above */
386 if ( mra->ma_rule->smr_normalize(
387 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
388 mra->ma_rule->smr_syntax,
390 bv, &nbv, memctx ) != LDAP_SUCCESS )
392 /* FIXME: stop processing? */
400 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
401 &nbv, &value, &text );
403 if ( nbv.bv_val != bv->bv_val ) {
404 memfree( nbv.bv_val, memctx );
407 if ( rc != LDAP_SUCCESS ) break;
410 rc = LDAP_COMPARE_TRUE;
414 memfree( value.bv_val, memctx );
415 if ( rc != LDAP_SUCCESS ) return rc;
419 /* check attrs in DN AVAs if required */
420 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
425 /* parse and pretty the dn */
426 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
427 if ( rc != LDAP_SUCCESS ) {
428 return LDAP_INVALID_SYNTAX;
431 /* for each AVA of each RDN ... */
432 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
433 LDAPRDN rdn = dn[ iRDN ];
435 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
436 LDAPAVA *ava = rdn[ iAVA ];
437 struct berval *bv = &ava->la_value, value;
438 AttributeDescription *ad =
439 (AttributeDescription *)ava->la_private;
445 if ( mra->ma_desc ) {
446 /* have a mra type? check for subtype */
447 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
450 value = mra->ma_value;
453 const char *text = NULL;
455 /* check if matching is appropriate */
456 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
460 /* normalize for equality */
461 rc = asserted_value_validate_normalize( ad,
463 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
464 &mra->ma_value, &value, &text, memctx );
465 if ( rc != LDAP_SUCCESS ) continue;
467 /* check search access */
468 if ( !access_allowed( op, e,
469 ad, &value, ACL_SEARCH, NULL ) )
471 memfree( value.bv_val, memctx );
477 rc = value_match( &ret, ad, mra->ma_rule, 0,
479 if ( value.bv_val != mra->ma_value.bv_val ) {
480 memfree( value.bv_val, memctx );
483 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
485 if ( rc != LDAP_SUCCESS ) {
486 ldap_dnfree_x( dn, memctx );
491 ldap_dnfree_x( dn, memctx );
494 return LDAP_COMPARE_FALSE;
501 AttributeAssertion *ava,
506 #ifdef LDAP_COMP_MATCH
507 int i, num_attr_vals;
508 AttributeAliasing *a_alias = NULL;
511 if ( !access_allowed( op, e,
512 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
514 return LDAP_INSUFFICIENT_ACCESS;
517 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
518 && op && op->o_bd && op->o_bd->be_has_subordinates )
523 if( type != LDAP_FILTER_EQUALITY &&
524 type != LDAP_FILTER_APPROX )
526 /* No other match is allowed */
527 return LDAP_INAPPROPRIATE_MATCHING;
530 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
536 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
539 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
546 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
547 return LDAP_COMPARE_FALSE;
550 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
555 if( type != LDAP_FILTER_EQUALITY &&
556 type != LDAP_FILTER_APPROX )
558 /* No other match is allowed */
559 return LDAP_INAPPROPRIATE_MATCHING;
562 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
565 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
566 &e->e_nname, &ava->aa_value, &text );
568 if( rc != LDAP_SUCCESS ) return rc;
569 if( match == 0 ) return LDAP_COMPARE_TRUE;
570 return LDAP_COMPARE_FALSE;
573 rc = LDAP_COMPARE_FALSE;
575 #ifdef LDAP_COMP_MATCH
576 if ( is_aliased_attribute && ava->aa_cf )
578 a_alias = is_aliased_attribute ( ava->aa_desc );
580 ava->aa_desc = a_alias->aa_aliased_ad;
586 for(a = attrs_find( e->e_attrs, ava->aa_desc );
588 a = attrs_find( a->a_next, ava->aa_desc ) )
593 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
594 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
596 rc = LDAP_INSUFFICIENT_ACCESS;
601 case LDAP_FILTER_APPROX:
602 mr = a->a_desc->ad_type->sat_approx;
603 if( mr != NULL ) break;
605 /* use EQUALITY matching rule if no APPROX rule */
607 case LDAP_FILTER_EQUALITY:
608 mr = a->a_desc->ad_type->sat_equality;
613 mr = a->a_desc->ad_type->sat_ordering;
621 rc = LDAP_INAPPROPRIATE_MATCHING;
625 #ifdef LDAP_COMP_MATCH
626 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
627 /* Component Matching */
628 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
629 if ( num_attr_vals <= 0 )/* no attribute value */
630 return LDAP_INAPPROPRIATE_MATCHING;
631 num_attr_vals++;/* for NULL termination */
633 /* following malloced will be freed by comp_tree_free () */
634 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
636 if ( !a->a_comp_data ) {
637 return LDAP_NO_MEMORY;
640 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
643 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
646 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
647 if ( a->a_comp_data->cd_mem_op == NULL ) {
648 free ( a->a_comp_data );
649 a->a_comp_data = NULL;
650 return LDAP_OPERATIONS_ERROR;
657 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
661 #ifdef LDAP_COMP_MATCH
662 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
663 /* Check if decoded component trees are already linked */
664 struct berval cf_bv = { 20, "componentFilterMatch" };
665 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
666 MatchingRuleAssertion mra;
667 mra.ma_cf = ava->aa_cf;
669 if ( a->a_comp_data->cd_tree[i] == NULL )
670 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
672 if ( !a->a_comp_data->cd_tree[i] ) {
673 free_ComponentData ( a );
674 return LDAP_OPERATIONS_ERROR;
677 ret = value_match( &match, a->a_desc, cf_mr, 0,
678 (struct berval*)a->a_comp_data->cd_tree[i++], (void*)&mra, &text );
679 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
680 /* cached component tree is broken, just remove it */
681 free_ComponentData ( a );
685 ava->aa_desc = a_alias->aa_aliasing_ad;
691 ret = value_match( &match, a->a_desc, mr, 0,
692 bv, &ava->aa_value, &text );
695 if( ret != LDAP_SUCCESS ) {
701 case LDAP_FILTER_EQUALITY:
702 case LDAP_FILTER_APPROX:
703 if ( match == 0 ) return LDAP_COMPARE_TRUE;
707 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
711 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
717 #ifdef LDAP_COMP_MATCH
719 ava->aa_desc = a_alias->aa_aliasing_ad;
727 test_presence_filter(
730 AttributeDescription *desc )
735 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
736 return LDAP_INSUFFICIENT_ACCESS;
739 if ( desc == slap_schema.si_ad_hasSubordinates ) {
741 * XXX: fairly optimistic: if the function is defined,
742 * then PRESENCE must succeed, because hasSubordinate
743 * is boolean-valued; I think we may live with this
744 * simplification by now.
746 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
747 return LDAP_COMPARE_TRUE;
750 return LDAP_COMPARE_FALSE;
753 if ( desc == slap_schema.si_ad_entryDN ||
754 desc == slap_schema.si_ad_subschemaSubentry )
756 /* entryDN and subschemaSubentry are always present */
757 return LDAP_COMPARE_TRUE;
760 rc = LDAP_COMPARE_FALSE;
762 for(a = attrs_find( e->e_attrs, desc );
764 a = attrs_find( a->a_next, desc ) )
766 if (( desc != a->a_desc ) && !access_allowed( op,
767 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
769 rc = LDAP_INSUFFICIENT_ACCESS;
773 rc = LDAP_COMPARE_TRUE;
788 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
790 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
792 for ( f = flist; f != NULL; f = f->f_next ) {
793 int rc = test_filter( op, e, f );
795 if ( rc == LDAP_COMPARE_FALSE ) {
796 /* filter is False */
801 if ( rc != LDAP_COMPARE_TRUE ) {
802 /* filter is Undefined unless later elements are False */
807 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
819 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
821 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
823 for ( f = flist; f != NULL; f = f->f_next ) {
824 int rc = test_filter( op, e, f );
826 if ( rc == LDAP_COMPARE_TRUE ) {
832 if ( rc != LDAP_COMPARE_FALSE ) {
833 /* filter is Undefined unless later elements are True */
838 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
844 test_substrings_filter(
852 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
854 if ( !access_allowed( op, e,
855 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
857 return LDAP_INSUFFICIENT_ACCESS;
860 rc = LDAP_COMPARE_FALSE;
862 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
864 a = attrs_find( a->a_next, f->f_sub_desc ) )
869 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
870 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
872 rc = LDAP_INSUFFICIENT_ACCESS;
876 mr = a->a_desc->ad_type->sat_substr;
878 rc = LDAP_INAPPROPRIATE_MATCHING;
882 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
886 ret = value_match( &match, a->a_desc, mr, 0,
887 bv, f->f_sub, &text );
889 if( ret != LDAP_SUCCESS ) {
893 if ( match == 0 ) return LDAP_COMPARE_TRUE;
897 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",