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>
37 static int test_filter_and( Operation *op, Entry *e, Filter *flist );
38 static int test_filter_or( Operation *op, Entry *e, Filter *flist );
39 static int test_substrings_filter( Operation *op, Entry *e, Filter *f);
40 static int test_ava_filter( Operation *op,
41 Entry *e, AttributeAssertion *ava, int type );
42 static int test_mra_filter( Operation *op,
43 Entry *e, MatchingRuleAssertion *mra );
44 static int test_presence_filter( Operation *op,
45 Entry *e, AttributeDescription *desc );
49 * test_filter - test a filter against a single entry.
51 * LDAP_COMPARE_TRUE filter matched
52 * LDAP_COMPARE_FALSE filter did not match
53 * SLAPD_COMPARE_UNDEFINED filter is undefined
54 * or an ldap result code indicating error
64 Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
66 switch ( f->f_choice ) {
67 case SLAPD_FILTER_COMPUTED:
68 Debug( LDAP_DEBUG_FILTER, " COMPUTED %s (%d)\n",
69 f->f_result == LDAP_COMPARE_FALSE ? "false" :
70 f->f_result == LDAP_COMPARE_TRUE ? "true" :
71 f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
77 case LDAP_FILTER_EQUALITY:
78 Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
79 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
82 case LDAP_FILTER_SUBSTRINGS:
83 Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
84 rc = test_substrings_filter( op, e, f );
88 Debug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
89 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
93 Debug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
94 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
97 case LDAP_FILTER_PRESENT:
98 Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
99 rc = test_presence_filter( op, e, f->f_desc );
102 case LDAP_FILTER_APPROX:
103 Debug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
104 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
107 case LDAP_FILTER_AND:
108 Debug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
109 rc = test_filter_and( op, e, f->f_and );
113 Debug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
114 rc = test_filter_or( op, e, f->f_or );
117 case LDAP_FILTER_NOT:
118 Debug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
119 rc = test_filter( op, e, f->f_not );
121 /* Flip true to false and false to true
122 * but leave Undefined alone.
125 case LDAP_COMPARE_TRUE:
126 rc = LDAP_COMPARE_FALSE;
128 case LDAP_COMPARE_FALSE:
129 rc = LDAP_COMPARE_TRUE;
134 case LDAP_FILTER_EXT:
135 Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 );
136 rc = test_mra_filter( op, e, f->f_mra );
140 Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n",
142 rc = LDAP_PROTOCOL_ERROR;
145 Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
149 static int test_mra_filter(
152 MatchingRuleAssertion *mra )
156 BER_MEMFREE_FN *memfree;
157 #ifdef LDAP_COMP_MATCH
158 int i, num_attr_vals;
163 memfree = slap_sl_free;
165 memctx = op->o_tmpmemctx;
166 memfree = op->o_tmpfree;
169 if ( mra->ma_desc ) {
171 * if ma_desc is available, then we're filtering for
172 * one attribute, and SEARCH permissions can be checked
175 if ( !access_allowed( op, e,
176 mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
178 return LDAP_INSUFFICIENT_ACCESS;
181 if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
185 rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
186 0, &e->e_nname, &mra->ma_value, &text );
189 if( rc != LDAP_SUCCESS ) return rc;
190 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
191 return LDAP_COMPARE_FALSE;
194 for ( a = attrs_find( e->e_attrs, mra->ma_desc );
196 a = attrs_find( a->a_next, mra->ma_desc ) )
199 int normalize_attribute = 0;
201 #ifdef LDAP_COMP_MATCH
202 /* Component Matching */
203 if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
205 if ( !a->a_comp_data ) {
207 !BER_BVISNULL( &a->a_vals[num_attr_vals] );
212 if ( num_attr_vals <= 0 ) {
213 /* no attribute value */
214 return LDAP_INAPPROPRIATE_MATCHING;
218 /* following malloced will be freed by comp_tree_free () */
219 a->a_comp_data = malloc( sizeof( ComponentData ) +
220 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
222 if ( !a->a_comp_data ) return LDAP_NO_MEMORY;
223 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)
224 ((char*)a->a_comp_data + sizeof(ComponentData));
225 a->a_comp_data->cd_tree[num_attr_vals - 1] =
226 (ComponentSyntaxInfo*) NULL;
227 a->a_comp_data->cd_mem_op =
228 nibble_mem_allocator( 1024*16, 1024 );
233 /* If ma_rule is not the same as the attribute's
234 * normal rule, then we can't use the a_nvals.
236 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
241 normalize_attribute = 1;
243 #ifdef LDAP_COMP_MATCH
246 for ( ; !BER_BVISNULL( bv ); bv++ ) {
251 #ifdef LDAP_COMP_MATCH
253 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
255 /* Check if decoded component trees are already linked */
256 if ( num_attr_vals ) {
257 a->a_comp_data->cd_tree[i] = attr_converter(
258 a, a->a_desc->ad_type->sat_syntax, bv );
261 if ( !a->a_comp_data->cd_tree[i] ) {
262 return LDAP_OPERATIONS_ERROR;
264 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
265 (struct berval*)a->a_comp_data->cd_tree[i++],
270 struct berval nbv = BER_BVNULL;
272 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
275 Document: draft-ietf-ldapbis-protocol
277 4.5.1. Search Request
279 If the type field is present and the matchingRule is present,
280 the matchValue is compared against entry attributes of the
281 specified type. In this case, the matchingRule MUST be one
282 suitable for use with the specified type (see [Syntaxes]),
283 otherwise the filter item is Undefined.
286 In this case, since the matchingRule requires the assertion
287 value to be normalized, we normalize the attribute value
288 according to the syntax of the matchingRule.
290 This should likely be done inside value_match(), by passing
291 the appropriate flags, but this is not done at present.
294 if ( mra->ma_rule->smr_normalize(
295 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
296 mra->ma_rule->smr_syntax,
298 bv, &nbv, memctx ) != LDAP_SUCCESS )
300 /* FIXME: stop processing? */
308 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
309 &nbv, &mra->ma_value, &text );
311 if ( nbv.bv_val != bv->bv_val ) {
312 memfree( nbv.bv_val, memctx );
316 if ( rc != LDAP_SUCCESS ) return rc;
317 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
323 * No attribute description: test all
325 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
326 struct berval *bv, value;
327 const char *text = NULL;
329 int normalize_attribute = 0;
331 /* check if matching is appropriate */
332 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
336 /* normalize for equality */
337 rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
338 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
339 &mra->ma_value, &value, &text, memctx );
340 if ( rc != LDAP_SUCCESS ) continue;
342 /* check search access */
343 if ( !access_allowed( op, e,
344 a->a_desc, &value, ACL_SEARCH, NULL ) )
346 memfree( value.bv_val, memctx );
349 #ifdef LDAP_COMP_MATCH
350 /* Component Matching */
352 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
356 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
357 (struct berval*)a, (void*)mra, &text );
358 if ( rc != LDAP_SUCCESS ) break;
361 rc = LDAP_COMPARE_TRUE;
369 if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
374 normalize_attribute = 1;
377 for ( ; !BER_BVISNULL( bv ); bv++ ) {
379 struct berval nbv = BER_BVNULL;
381 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
382 /* see comment above */
383 if ( mra->ma_rule->smr_normalize(
384 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
385 mra->ma_rule->smr_syntax,
387 bv, &nbv, memctx ) != LDAP_SUCCESS )
389 /* FIXME: stop processing? */
397 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
398 &nbv, &value, &text );
400 if ( nbv.bv_val != bv->bv_val ) {
401 memfree( nbv.bv_val, memctx );
404 if ( rc != LDAP_SUCCESS ) break;
407 rc = LDAP_COMPARE_TRUE;
411 memfree( value.bv_val, memctx );
412 if ( rc != LDAP_SUCCESS ) return rc;
416 /* check attrs in DN AVAs if required */
417 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
422 /* parse and pretty the dn */
423 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
424 if ( rc != LDAP_SUCCESS ) {
425 return LDAP_INVALID_SYNTAX;
428 /* for each AVA of each RDN ... */
429 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
430 LDAPRDN rdn = dn[ iRDN ];
432 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
433 LDAPAVA *ava = rdn[ iAVA ];
434 struct berval *bv = &ava->la_value, value;
435 AttributeDescription *ad =
436 (AttributeDescription *)ava->la_private;
442 if ( mra->ma_desc ) {
443 /* have a mra type? check for subtype */
444 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
447 value = mra->ma_value;
450 const char *text = NULL;
452 /* check if matching is appropriate */
453 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
457 /* normalize for equality */
458 rc = asserted_value_validate_normalize( ad,
460 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
461 &mra->ma_value, &value, &text, memctx );
462 if ( rc != LDAP_SUCCESS ) continue;
464 /* check search access */
465 if ( !access_allowed( op, e,
466 ad, &value, ACL_SEARCH, NULL ) )
468 memfree( value.bv_val, memctx );
474 rc = value_match( &ret, ad, mra->ma_rule, 0,
476 if ( value.bv_val != mra->ma_value.bv_val ) {
477 memfree( value.bv_val, memctx );
480 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
482 if ( rc != LDAP_SUCCESS ) {
483 ldap_dnfree_x( dn, memctx );
488 ldap_dnfree_x( dn, memctx );
491 return LDAP_COMPARE_FALSE;
498 AttributeAssertion *ava,
504 if ( !access_allowed( op, e,
505 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
507 return LDAP_INSUFFICIENT_ACCESS;
510 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
511 && op && op->o_bd && op->o_bd->be_has_subordinates )
516 if( type != LDAP_FILTER_EQUALITY &&
517 type != LDAP_FILTER_APPROX )
519 /* No other match is allowed */
520 return LDAP_INAPPROPRIATE_MATCHING;
523 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
529 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
532 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
539 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
540 return LDAP_COMPARE_FALSE;
543 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
548 if( type != LDAP_FILTER_EQUALITY &&
549 type != LDAP_FILTER_APPROX )
551 /* No other match is allowed */
552 return LDAP_INAPPROPRIATE_MATCHING;
555 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
558 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
559 &e->e_nname, &ava->aa_value, &text );
561 if( rc != LDAP_SUCCESS ) return rc;
562 if( match == 0 ) return LDAP_COMPARE_TRUE;
563 return LDAP_COMPARE_FALSE;
566 rc = LDAP_COMPARE_FALSE;
568 for(a = attrs_find( e->e_attrs, ava->aa_desc );
570 a = attrs_find( a->a_next, ava->aa_desc ) )
575 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
576 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
578 rc = LDAP_INSUFFICIENT_ACCESS;
583 case LDAP_FILTER_APPROX:
584 mr = a->a_desc->ad_type->sat_approx;
585 if( mr != NULL ) break;
587 /* use EQUALITY matching rule if no APPROX rule */
589 case LDAP_FILTER_EQUALITY:
590 mr = a->a_desc->ad_type->sat_equality;
595 mr = a->a_desc->ad_type->sat_ordering;
603 rc = LDAP_INAPPROPRIATE_MATCHING;
607 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
611 ret = value_match( &match, a->a_desc, mr, 0,
612 bv, &ava->aa_value, &text );
614 if( ret != LDAP_SUCCESS ) {
620 case LDAP_FILTER_EQUALITY:
621 case LDAP_FILTER_APPROX:
622 if ( match == 0 ) return LDAP_COMPARE_TRUE;
626 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
630 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
641 test_presence_filter(
644 AttributeDescription *desc )
649 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
650 return LDAP_INSUFFICIENT_ACCESS;
653 if ( desc == slap_schema.si_ad_hasSubordinates ) {
655 * XXX: fairly optimistic: if the function is defined,
656 * then PRESENCE must succeed, because hasSubordinate
657 * is boolean-valued; I think we may live with this
658 * simplification by now.
660 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
661 return LDAP_COMPARE_TRUE;
664 return LDAP_COMPARE_FALSE;
667 if ( desc == slap_schema.si_ad_entryDN ||
668 desc == slap_schema.si_ad_subschemaSubentry )
670 /* entryDN and subschemaSubentry are always present */
671 return LDAP_COMPARE_TRUE;
674 rc = LDAP_COMPARE_FALSE;
676 for(a = attrs_find( e->e_attrs, desc );
678 a = attrs_find( a->a_next, desc ) )
680 if (( desc != a->a_desc ) && !access_allowed( op,
681 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
683 rc = LDAP_INSUFFICIENT_ACCESS;
687 rc = LDAP_COMPARE_TRUE;
702 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
704 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
706 for ( f = flist; f != NULL; f = f->f_next ) {
707 int rc = test_filter( op, e, f );
709 if ( rc == LDAP_COMPARE_FALSE ) {
710 /* filter is False */
715 if ( rc != LDAP_COMPARE_TRUE ) {
716 /* filter is Undefined unless later elements are False */
721 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
733 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
735 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
737 for ( f = flist; f != NULL; f = f->f_next ) {
738 int rc = test_filter( op, e, f );
740 if ( rc == LDAP_COMPARE_TRUE ) {
746 if ( rc != LDAP_COMPARE_FALSE ) {
747 /* filter is Undefined unless later elements are True */
752 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
758 test_substrings_filter(
766 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
768 if ( !access_allowed( op, e,
769 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
771 return LDAP_INSUFFICIENT_ACCESS;
774 rc = LDAP_COMPARE_FALSE;
776 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
778 a = attrs_find( a->a_next, f->f_sub_desc ) )
783 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
784 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
786 rc = LDAP_INSUFFICIENT_ACCESS;
790 mr = a->a_desc->ad_type->sat_substr;
792 rc = LDAP_INAPPROPRIATE_MATCHING;
796 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
800 ret = value_match( &match, a->a_desc, mr, 0,
801 bv, f->f_sub, &text );
803 if( ret != LDAP_SUCCESS ) {
807 if ( match == 0 ) return LDAP_COMPARE_TRUE;
811 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",