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 #ifdef LDAP_COMP_MATCH
200 /* Component Matching */
201 if( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
203 if ( !a->a_comp_data ) {
205 a->a_vals[num_attr_vals].bv_val != NULL;
210 if ( num_attr_vals <= 0 ) {
211 /* no attribute value */
212 return LDAP_INAPPROPRIATE_MATCHING;
216 /* following malloced will be freed by comp_tree_free () */
217 a->a_comp_data = malloc( sizeof( ComponentData ) +
218 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
220 if ( !a->a_comp_data ) return LDAP_NO_MEMORY;
221 a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)
222 ((char*)a->a_comp_data + sizeof(ComponentData));
223 a->a_comp_data->cd_tree[num_attr_vals - 1] =
224 (ComponentSyntaxInfo*) NULL;
225 a->a_comp_data->cd_mem_op =
226 nibble_mem_allocator( 1024*16, 1024 );
231 /* If ma_rule is not the same as the attribute's
232 * normal rule, then we can't use the a_nvals.
234 if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
239 #ifdef LDAP_COMP_MATCH
242 for ( ; bv->bv_val != NULL; bv++ ) {
247 #ifdef LDAP_COMP_MATCH
249 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
250 /* Check if decoded component trees are already linked */
251 if ( num_attr_vals ) {
252 a->a_comp_data->cd_tree[i] = attr_converter(
253 a, a->a_desc->ad_type->sat_syntax, bv );
256 if ( !a->a_comp_data->cd_tree[i] ) {
257 return LDAP_OPERATIONS_ERROR;
259 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
260 (struct berval*)a->a_comp_data->cd_tree[i++],
265 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
266 bv, &mra->ma_value, &text );
269 if( rc != LDAP_SUCCESS ) return rc;
270 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
276 * No attribute description: test all
278 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
279 struct berval *bv, value;
280 const char *text = NULL;
283 /* check if matching is appropriate */
284 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type )) {
288 /* normalize for equality */
289 rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
290 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
291 &mra->ma_value, &value, &text, memctx );
292 if ( rc != LDAP_SUCCESS ) continue;
294 /* check search access */
295 if ( !access_allowed( op, e,
296 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
297 memfree( value.bv_val, memctx );
300 #ifdef LDAP_COMP_MATCH
301 /* Component Matching */
303 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT)
307 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
308 (struct berval*)a, (void*)mra, &text );
309 if( rc != LDAP_SUCCESS ) break;
312 rc = LDAP_COMPARE_TRUE;
320 if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
326 for ( ; bv->bv_val != NULL; bv++ ) {
329 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
332 if( rc != LDAP_SUCCESS ) break;
335 rc = LDAP_COMPARE_TRUE;
339 memfree( value.bv_val, memctx );
340 if ( rc != LDAP_SUCCESS ) return rc;
344 /* check attrs in DN AVAs if required */
345 if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
350 /* parse and pretty the dn */
351 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
352 if ( rc != LDAP_SUCCESS ) {
353 return LDAP_INVALID_SYNTAX;
356 /* for each AVA of each RDN ... */
357 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
358 LDAPRDN rdn = dn[ iRDN ];
360 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
361 LDAPAVA *ava = rdn[ iAVA ];
362 struct berval *bv = &ava->la_value, value;
363 AttributeDescription *ad =
364 (AttributeDescription *)ava->la_private;
370 if ( mra->ma_desc ) {
371 /* have a mra type? check for subtype */
372 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
375 value = mra->ma_value;
378 const char *text = NULL;
380 /* check if matching is appropriate */
381 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type )) {
385 /* normalize for equality */
386 rc = asserted_value_validate_normalize( ad,
388 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
389 &mra->ma_value, &value, &text, memctx );
390 if ( rc != LDAP_SUCCESS ) continue;
392 /* check search access */
393 if ( !access_allowed( op, e,
394 ad, &value, ACL_SEARCH, NULL ) )
396 memfree( value.bv_val, memctx );
402 rc = value_match( &ret, ad, mra->ma_rule, 0,
404 if ( value.bv_val != mra->ma_value.bv_val ) {
405 memfree( value.bv_val, memctx );
408 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
410 if( rc != LDAP_SUCCESS ) {
411 ldap_dnfree_x( dn, memctx );
416 ldap_dnfree_x( dn, memctx );
419 return LDAP_COMPARE_FALSE;
426 AttributeAssertion *ava,
432 if ( !access_allowed( op, e,
433 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
435 return LDAP_INSUFFICIENT_ACCESS;
438 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
439 && op && op->o_bd && op->o_bd->be_has_subordinates )
444 if( type != LDAP_FILTER_EQUALITY &&
445 type != LDAP_FILTER_APPROX )
447 /* No other match is allowed */
448 return LDAP_INAPPROPRIATE_MATCHING;
451 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
457 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
460 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
467 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
468 return LDAP_COMPARE_FALSE;
471 if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
476 if( type != LDAP_FILTER_EQUALITY &&
477 type != LDAP_FILTER_APPROX )
479 /* No other match is allowed */
480 return LDAP_INAPPROPRIATE_MATCHING;
483 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
486 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
487 &e->e_nname, &ava->aa_value, &text );
489 if( rc != LDAP_SUCCESS ) return rc;
490 if( match == 0 ) return LDAP_COMPARE_TRUE;
491 return LDAP_COMPARE_FALSE;
494 rc = LDAP_COMPARE_FALSE;
496 for(a = attrs_find( e->e_attrs, ava->aa_desc );
498 a = attrs_find( a->a_next, ava->aa_desc ) )
503 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
504 e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
506 rc = LDAP_INSUFFICIENT_ACCESS;
511 case LDAP_FILTER_APPROX:
512 mr = a->a_desc->ad_type->sat_approx;
513 if( mr != NULL ) break;
515 /* use EQUALITY matching rule if no APPROX rule */
517 case LDAP_FILTER_EQUALITY:
518 mr = a->a_desc->ad_type->sat_equality;
523 mr = a->a_desc->ad_type->sat_ordering;
531 rc = LDAP_INAPPROPRIATE_MATCHING;
535 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
539 ret = value_match( &match, a->a_desc, mr, 0,
540 bv, &ava->aa_value, &text );
542 if( ret != LDAP_SUCCESS ) {
548 case LDAP_FILTER_EQUALITY:
549 case LDAP_FILTER_APPROX:
550 if ( match == 0 ) return LDAP_COMPARE_TRUE;
554 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
558 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
569 test_presence_filter(
572 AttributeDescription *desc )
577 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
578 return LDAP_INSUFFICIENT_ACCESS;
581 if ( desc == slap_schema.si_ad_hasSubordinates ) {
583 * XXX: fairly optimistic: if the function is defined,
584 * then PRESENCE must succeed, because hasSubordinate
585 * is boolean-valued; I think we may live with this
586 * simplification by now.
588 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
589 return LDAP_COMPARE_TRUE;
592 return LDAP_COMPARE_FALSE;
595 if ( desc == slap_schema.si_ad_entryDN ||
596 desc == slap_schema.si_ad_subschemaSubentry )
598 /* entryDN and subschemaSubentry are always present */
599 return LDAP_COMPARE_TRUE;
602 rc = LDAP_COMPARE_FALSE;
604 for(a = attrs_find( e->e_attrs, desc );
606 a = attrs_find( a->a_next, desc ) )
608 if (( desc != a->a_desc ) && !access_allowed( op,
609 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
611 rc = LDAP_INSUFFICIENT_ACCESS;
615 rc = LDAP_COMPARE_TRUE;
630 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
632 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
634 for ( f = flist; f != NULL; f = f->f_next ) {
635 int rc = test_filter( op, e, f );
637 if ( rc == LDAP_COMPARE_FALSE ) {
638 /* filter is False */
643 if ( rc != LDAP_COMPARE_TRUE ) {
644 /* filter is Undefined unless later elements are False */
649 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
661 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
663 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
665 for ( f = flist; f != NULL; f = f->f_next ) {
666 int rc = test_filter( op, e, f );
668 if ( rc == LDAP_COMPARE_TRUE ) {
674 if ( rc != LDAP_COMPARE_FALSE ) {
675 /* filter is Undefined unless later elements are True */
680 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
686 test_substrings_filter(
694 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
696 if ( !access_allowed( op, e,
697 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
699 return LDAP_INSUFFICIENT_ACCESS;
702 rc = LDAP_COMPARE_FALSE;
704 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
706 a = attrs_find( a->a_next, f->f_sub_desc ) )
711 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
712 e, a->a_desc, NULL, ACL_SEARCH, NULL ))
714 rc = LDAP_INSUFFICIENT_ACCESS;
718 mr = a->a_desc->ad_type->sat_substr;
720 rc = LDAP_INAPPROPRIATE_MATCHING;
724 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
728 ret = value_match( &match, a->a_desc, mr, 0,
729 bv, f->f_sub, &text );
731 if( ret != LDAP_SUCCESS ) {
735 if ( match == 0 ) return LDAP_COMPARE_TRUE;
739 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",