1 /* filterentry.c - apply a filter to an entry */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2004 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, Entry *e, AttributeAssertion *ava, int type );
41 static int test_mra_filter( Operation *op, Entry *e, MatchingRuleAssertion *mra );
42 static int test_presence_filter( Operation *op, Entry *e, AttributeDescription *desc );
46 * test_filter - test a filter against a single entry.
48 * LDAP_COMPARE_TRUE filter matched
49 * LDAP_COMPARE_FALSE filter did not match
50 * SLAPD_COMPARE_UNDEFINED filter is undefined
51 * or an ldap result code indicating error
61 Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
63 switch ( f->f_choice ) {
64 case SLAPD_FILTER_COMPUTED:
65 Debug( LDAP_DEBUG_FILTER, " COMPUTED %s (%d)\n",
66 f->f_result == LDAP_COMPARE_FALSE ? "false" :
67 f->f_result == LDAP_COMPARE_TRUE ? "true" :
68 f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
74 case LDAP_FILTER_EQUALITY:
75 Debug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
77 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
80 case LDAP_FILTER_SUBSTRINGS:
81 Debug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
83 rc = test_substrings_filter( op, e, f );
87 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
91 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
94 case LDAP_FILTER_PRESENT:
95 Debug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
96 rc = test_presence_filter( op, e, f->f_desc );
99 case LDAP_FILTER_APPROX:
100 Debug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
101 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
104 case LDAP_FILTER_AND:
105 Debug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
106 rc = test_filter_and( op, e, f->f_and );
110 Debug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
111 rc = test_filter_or( op, e, f->f_or );
114 case LDAP_FILTER_NOT:
115 Debug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
116 rc = test_filter( op, e, f->f_not );
118 /* Flip true to false and false to true
119 * but leave Undefined alone.
122 case LDAP_COMPARE_TRUE:
123 rc = LDAP_COMPARE_FALSE;
125 case LDAP_COMPARE_FALSE:
126 rc = LDAP_COMPARE_TRUE;
131 case LDAP_FILTER_EXT:
132 Debug( LDAP_DEBUG_FILTER, " EXT\n", 0, 0, 0 );
133 rc = test_mra_filter( op, e, f->f_mra );
137 Debug( LDAP_DEBUG_ANY, " unknown filter type %lu\n",
139 rc = LDAP_PROTOCOL_ERROR;
142 Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
146 static int test_mra_filter(
149 MatchingRuleAssertion *mra )
153 BER_MEMFREE_FN *memfree;
157 memfree = slap_sl_free;
159 memctx = op->o_tmpmemctx;
160 memfree = op->o_tmpfree;
163 #ifdef LDAP_COMP_MATCH
164 /* Component Matching */
166 mra->ma_rule->smr_usage & (SLAP_MR_COMPONENT) ){
167 return test_comp_filter_entry( op, e, mra );
170 if ( mra->ma_desc ) {
172 * if ma_desc is available, then we're filtering for
173 * one attribute, and SEARCH permissions can be checked
176 if( !access_allowed( op, e,
177 mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
179 return LDAP_INSUFFICIENT_ACCESS;
182 for(a = attrs_find( e->e_attrs, mra->ma_desc );
184 a = attrs_find( a->a_next, mra->ma_desc ) )
187 /* If ma_rule is not the same as the attribute's
188 * normal rule, then we can't use the a_nvals.
190 if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
196 for ( ; bv->bv_val != NULL; bv++ ) {
201 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
202 bv, &mra->ma_value, &text );
204 if( rc != LDAP_SUCCESS ) return rc;
205 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
211 * No attribute description: test all
213 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
214 struct berval *bv, value;
215 const char *text = NULL;
218 /* check if matching is appropriate */
219 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type )) {
223 /* normalize for equality */
224 rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
225 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
226 &mra->ma_value, &value, &text, memctx );
227 if ( rc != LDAP_SUCCESS ) continue;
229 /* check search access */
230 if ( !access_allowed( op, e,
231 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
232 memfree( value.bv_val, memctx );
237 if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
243 for ( ; bv->bv_val != NULL; bv++ ) {
246 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
249 if( rc != LDAP_SUCCESS ) break;
252 rc = LDAP_COMPARE_TRUE;
256 memfree( value.bv_val, memctx );
257 if ( rc != LDAP_SUCCESS ) return rc;
261 /* check attrs in DN AVAs if required */
262 if ( mra->ma_dnattrs ) {
267 /* parse and pretty the dn */
268 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
269 if ( rc != LDAP_SUCCESS ) {
270 return LDAP_INVALID_SYNTAX;
273 /* for each AVA of each RDN ... */
274 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
275 LDAPRDN rdn = dn[ iRDN ];
277 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
278 LDAPAVA *ava = rdn[ iAVA ];
279 struct berval *bv = &ava->la_value, value;
280 AttributeDescription *ad =
281 (AttributeDescription *)ava->la_private;
287 if ( mra->ma_desc ) {
288 /* have a mra type? check for subtype */
289 if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
292 value = mra->ma_value;
295 const char *text = NULL;
297 /* check if matching is appropriate */
298 if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type )) {
302 /* normalize for equality */
303 rc = asserted_value_validate_normalize( ad,
305 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
306 &mra->ma_value, &value, &text, memctx );
307 if ( rc != LDAP_SUCCESS ) continue;
309 /* check search access */
310 if ( !access_allowed( op, e,
311 ad, &value, ACL_SEARCH, NULL ) )
313 memfree( value.bv_val, memctx );
319 rc = value_match( &ret, ad, mra->ma_rule, 0,
322 if ( value.bv_val != mra->ma_value.bv_val ) {
323 memfree( value.bv_val, memctx );
326 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
328 if( rc != LDAP_SUCCESS ) {
329 ldap_dnfree_x( dn, memctx );
334 ldap_dnfree_x( dn, memctx );
337 return LDAP_COMPARE_FALSE;
344 AttributeAssertion *ava,
349 if ( !access_allowed( op, e,
350 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
352 return LDAP_INSUFFICIENT_ACCESS;
355 for(a = attrs_find( e->e_attrs, ava->aa_desc );
357 a = attrs_find( a->a_next, ava->aa_desc ) )
363 case LDAP_FILTER_APPROX:
364 mr = a->a_desc->ad_type->sat_approx;
365 if( mr != NULL ) break;
367 /* use EQUALITY matching rule if no APPROX rule */
369 case LDAP_FILTER_EQUALITY:
370 mr = a->a_desc->ad_type->sat_equality;
375 mr = a->a_desc->ad_type->sat_ordering;
386 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
391 rc = value_match( &ret, a->a_desc, mr, 0,
392 bv, &ava->aa_value, &text );
394 if( rc != LDAP_SUCCESS ) return rc;
397 case LDAP_FILTER_EQUALITY:
398 case LDAP_FILTER_APPROX:
399 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
403 if ( ret >= 0 ) return LDAP_COMPARE_TRUE;
407 if ( ret <= 0 ) return LDAP_COMPARE_TRUE;
413 if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
414 && op && op->o_bd && op->o_bd->be_has_subordinates )
420 * No other match should be allowed ...
422 assert( type == LDAP_FILTER_EQUALITY );
424 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
430 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
433 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
440 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
441 return LDAP_COMPARE_FALSE;
444 return( LDAP_COMPARE_FALSE );
449 test_presence_filter(
452 AttributeDescription *desc )
456 if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
457 return LDAP_INSUFFICIENT_ACCESS;
460 a = attrs_find( e->e_attrs, desc );
461 if ( a == NULL && desc == slap_schema.si_ad_hasSubordinates ) {
464 * XXX: fairly optimistic: if the function is defined,
465 * then PRESENCE must succeed, because hasSubordinate
466 * is boolean-valued; I think we may live with this
467 * simplification by now
469 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
470 return LDAP_COMPARE_TRUE;
473 return LDAP_COMPARE_FALSE;
476 return a != NULL ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
487 int rtn = LDAP_COMPARE_TRUE; /* True if empty */
489 Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
492 for ( f = flist; f != NULL; f = f->f_next ) {
493 int rc = test_filter( op, e, f );
495 if ( rc == LDAP_COMPARE_FALSE ) {
496 /* filter is False */
501 if ( rc != LDAP_COMPARE_TRUE ) {
502 /* filter is Undefined unless later elements are False */
507 Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
520 int rtn = LDAP_COMPARE_FALSE; /* False if empty */
522 Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
524 for ( f = flist; f != NULL; f = f->f_next ) {
525 int rc = test_filter( op, e, f );
527 if ( rc == LDAP_COMPARE_TRUE ) {
533 if ( rc != LDAP_COMPARE_FALSE ) {
534 /* filter is Undefined unless later elements are True */
539 Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
545 test_substrings_filter(
552 Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
554 if ( !access_allowed( op, e,
555 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
557 return LDAP_INSUFFICIENT_ACCESS;
560 for(a = attrs_find( e->e_attrs, f->f_sub_desc );
562 a = attrs_find( a->a_next, f->f_sub_desc ) )
564 MatchingRule *mr = a->a_desc->ad_type->sat_substr;
567 if( mr == NULL ) continue;
569 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
574 rc = value_match( &ret, a->a_desc, mr, 0,
575 bv, f->f_sub, &text );
577 if( rc != LDAP_SUCCESS ) return rc;
578 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
582 Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter 1\n",
584 return LDAP_COMPARE_FALSE;