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,
440 AttributeDescription *ad =
441 (AttributeDescription *)ava->la_private;
447 if ( mra->ma_desc ) {
448 /* have a mra type? check for subtype */
449 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
452 value = mra->ma_value;
455 const char *text = NULL;
457 /* check if matching is appropriate */
458 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
462 /* normalize for equality */
463 rc = asserted_value_validate_normalize( ad,
465 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
466 &mra->ma_value, &value, &text, memctx );
467 if ( rc != LDAP_SUCCESS ) continue;
469 /* check search access */
470 if ( !access_allowed( op, e,
471 ad, &value, ACL_SEARCH, NULL ) )
473 memfree( value.bv_val, memctx );
478 if ( mra->ma_rule->smr_normalize ) {
479 /* see comment above */
480 if ( mra->ma_rule->smr_normalize(
481 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
482 mra->ma_rule->smr_syntax,
484 bv, &nbv, memctx ) != LDAP_SUCCESS )
486 /* FIXME: stop processing? */
497 rc = value_match( &ret, ad, mra->ma_rule, 0,
498 &nbv, &value, &text );
501 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
502 memfree( value.bv_val, memctx );
505 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
506 memfree( nbv.bv_val, memctx );
509 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
511 if ( rc != LDAP_SUCCESS ) {
512 ldap_dnfree_x( dn, memctx );
517 ldap_dnfree_x( dn, memctx );
520 return LDAP_COMPARE_FALSE;
527 AttributeAssertion *ava,
532 #ifdef LDAP_COMP_MATCH
533 int i, num_attr_vals = 0;
534 AttributeAliasing *a_alias = NULL;
537 if ( !access_allowed( op, e,
538 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
540 return LDAP_INSUFFICIENT_ACCESS;
543 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
544 && op && op->o_bd && op->o_bd->be_has_subordinates )
549 if( type != LDAP_FILTER_EQUALITY &&
550 type != LDAP_FILTER_APPROX )
552 /* No other match is allowed */
553 return LDAP_INAPPROPRIATE_MATCHING;
556 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
562 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
565 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
572 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
573 return LDAP_COMPARE_FALSE;
576 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
581 if( type != LDAP_FILTER_EQUALITY &&
582 type != LDAP_FILTER_APPROX )
584 /* No other match is allowed */
585 return LDAP_INAPPROPRIATE_MATCHING;
588 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
591 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
592 &e->e_nname, &ava->aa_value, &text );
594 if( rc != LDAP_SUCCESS ) return rc;
595 if( match == 0 ) return LDAP_COMPARE_TRUE;
596 return LDAP_COMPARE_FALSE;
599 rc = LDAP_COMPARE_FALSE;
601 #ifdef LDAP_COMP_MATCH
602 if ( is_aliased_attribute && ava->aa_cf )
604 a_alias = is_aliased_attribute ( ava->aa_desc );
606 ava->aa_desc = a_alias->aa_aliased_ad;
612 for(a = attrs_find( e->e_attrs, ava->aa_desc );
614 a = attrs_find( a->a_next, ava->aa_desc ) )
619 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
620 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
622 rc = LDAP_INSUFFICIENT_ACCESS;
627 case LDAP_FILTER_APPROX:
628 mr = a->a_desc->ad_type->sat_approx;
629 if( mr != NULL ) break;
631 /* use EQUALITY matching rule if no APPROX rule */
633 case LDAP_FILTER_EQUALITY:
634 mr = a->a_desc->ad_type->sat_equality;
639 mr = a->a_desc->ad_type->sat_ordering;
647 rc = LDAP_INAPPROPRIATE_MATCHING;
651 #ifdef LDAP_COMP_MATCH
652 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
653 /* Component Matching */
654 for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
655 if ( num_attr_vals <= 0 )/* no attribute value */
656 return LDAP_INAPPROPRIATE_MATCHING;
657 num_attr_vals++;/* for NULL termination */
659 /* following malloced will be freed by comp_tree_free () */
660 a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
662 if ( !a->a_comp_data ) {
663 return LDAP_NO_MEMORY;
666 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
669 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
672 a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
673 if ( a->a_comp_data->cd_mem_op == NULL ) {
674 free ( a->a_comp_data );
675 a->a_comp_data = NULL;
676 return LDAP_OPERATIONS_ERROR;
683 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
687 #ifdef LDAP_COMP_MATCH
688 if( attr_converter && ava->aa_cf && a->a_comp_data ) {
689 /* Check if decoded component trees are already linked */
690 struct berval cf_bv = { 20, "componentFilterMatch" };
691 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
692 MatchingRuleAssertion mra;
693 mra.ma_cf = ava->aa_cf;
695 if ( a->a_comp_data->cd_tree[i] == NULL )
696 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
698 if ( !a->a_comp_data->cd_tree[i] ) {
699 free_ComponentData ( a );
700 return LDAP_OPERATIONS_ERROR;
703 ret = value_match( &match, a->a_desc, cf_mr, 0,
704 (struct berval*)a->a_comp_data->cd_tree[i++], (void*)&mra, &text );
705 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
706 /* cached component tree is broken, just remove it */
707 free_ComponentData ( a );
711 ava->aa_desc = a_alias->aa_aliasing_ad;
717 ret = value_match( &match, a->a_desc, mr, 0,
718 bv, &ava->aa_value, &text );
721 if( ret != LDAP_SUCCESS ) {
727 case LDAP_FILTER_EQUALITY:
728 case LDAP_FILTER_APPROX:
729 if ( match == 0 ) return LDAP_COMPARE_TRUE;
733 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
737 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
743 #ifdef LDAP_COMP_MATCH
745 ava->aa_desc = a_alias->aa_aliasing_ad;
753 test_presence_filter(
756 AttributeDescription *desc )
761 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
762 return LDAP_INSUFFICIENT_ACCESS;
765 if ( desc == slap_schema.si_ad_hasSubordinates ) {
767 * XXX: fairly optimistic: if the function is defined,
768 * then PRESENCE must succeed, because hasSubordinate
769 * is boolean-valued; I think we may live with this
770 * simplification by now.
772 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
773 return LDAP_COMPARE_TRUE;
776 return LDAP_COMPARE_FALSE;
779 if ( desc == slap_schema.si_ad_entryDN ||
780 desc == slap_schema.si_ad_subschemaSubentry )
782 /* entryDN and subschemaSubentry are always present */
783 return LDAP_COMPARE_TRUE;
786 rc = LDAP_COMPARE_FALSE;
788 for(a = attrs_find( e->e_attrs, desc );
790 a = attrs_find( a->a_next, desc ) )
792 if (( desc != a->a_desc ) && !access_allowed( op,
793 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
795 rc = LDAP_INSUFFICIENT_ACCESS;
799 rc = LDAP_COMPARE_TRUE;
814 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
816 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
818 for ( f = flist; f != NULL; f = f->f_next ) {
819 int rc = test_filter( op, e, f );
821 if ( rc == LDAP_COMPARE_FALSE ) {
822 /* filter is False */
827 if ( rc != LDAP_COMPARE_TRUE ) {
828 /* filter is Undefined unless later elements are False */
833 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
845 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
847 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
849 for ( f = flist; f != NULL; f = f->f_next ) {
850 int rc = test_filter( op, e, f );
852 if ( rc == LDAP_COMPARE_TRUE ) {
858 if ( rc != LDAP_COMPARE_FALSE ) {
859 /* filter is Undefined unless later elements are True */
864 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
870 test_substrings_filter(
878 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
880 if ( !access_allowed( op, e,
881 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
883 return LDAP_INSUFFICIENT_ACCESS;
886 rc = LDAP_COMPARE_FALSE;
888 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
890 a = attrs_find( a->a_next, f->f_sub_desc ) )
895 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
896 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
898 rc = LDAP_INSUFFICIENT_ACCESS;
902 mr = a->a_desc->ad_type->sat_substr;
904 rc = LDAP_INAPPROPRIATE_MATCHING;
908 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
912 ret = value_match( &match, a->a_desc, mr, 0,
913 bv, f->f_sub, &text );
915 if( ret != LDAP_SUCCESS ) {
919 if ( match == 0 ) return LDAP_COMPARE_TRUE;
923 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",