int mdb_filter_candidates( Operation *op, MDB_txn *rtxn, Filter *f, ID *ids, ID *tmp, ID *stack ) { int rc = 0; #ifdef LDAP_COMP_MATCH AttributeAliasing *aa; #endif Debug( LDAP_DEBUG_FILTER, "=> mdb_filter_candidates\n", 0, 0, 0 ); if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { MDB_IDL_ZERO( ids ); goto out; } switch ( f->f_choice ) { case SLAPD_FILTER_COMPUTED: switch( f->f_result ) { case SLAPD_COMPARE_UNDEFINED: /* This technically is not the same as FALSE, but it * certainly will produce no matches. */ /* FALL THRU */ case LDAP_COMPARE_FALSE: MDB_IDL_ZERO( ids ); break; case LDAP_COMPARE_TRUE: MDB_IDL_ALL( ids ); break; case LDAP_SUCCESS: /* this is a pre-computed scope, leave it alone */ break; } break; case LDAP_FILTER_PRESENT: Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 ); rc = presence_candidates( op, rtxn, f->f_desc, ids ); break; case LDAP_FILTER_EQUALITY: Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 ); #ifdef LDAP_COMP_MATCH if ( is_aliased_attribute && ( aa = is_aliased_attribute ( f->f_ava->aa_desc ) ) ) { rc = ava_comp_candidates ( op, rtxn, f->f_ava, aa, ids, tmp, stack ); } else #endif { rc = equality_candidates( op, rtxn, f->f_ava, ids, tmp ); } break; case LDAP_FILTER_APPROX: Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 ); rc = approx_candidates( op, rtxn, f->f_ava, ids, tmp ); break; case LDAP_FILTER_SUBSTRINGS: Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 ); rc = substring_candidates( op, rtxn, f->f_sub, ids, tmp ); break; case LDAP_FILTER_GE: /* if no GE index, use pres */ Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 ); if( f->f_ava->aa_desc->ad_type->sat_ordering && ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage & SLAP_MR_ORDERED_INDEX ) ) rc = inequality_candidates( op, rtxn, f->f_ava, ids, tmp, LDAP_FILTER_GE ); else rc = presence_candidates( op, rtxn, f->f_ava->aa_desc, ids ); break; case LDAP_FILTER_LE: /* if no LE index, use pres */ Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 ); if( f->f_ava->aa_desc->ad_type->sat_ordering && ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage & SLAP_MR_ORDERED_INDEX ) ) rc = inequality_candidates( op, rtxn, f->f_ava, ids, tmp, LDAP_FILTER_LE ); else rc = presence_candidates( op, rtxn, f->f_ava->aa_desc, ids ); break; case LDAP_FILTER_NOT: /* no indexing to support NOT filters */ Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 ); MDB_IDL_ALL( ids ); break; case LDAP_FILTER_AND: Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 ); rc = list_candidates( op, rtxn, f->f_and, LDAP_FILTER_AND, ids, tmp, stack ); break; case LDAP_FILTER_OR: Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 ); rc = list_candidates( op, rtxn, f->f_or, LDAP_FILTER_OR, ids, tmp, stack ); break; case LDAP_FILTER_EXT: Debug( LDAP_DEBUG_FILTER, "\tEXT\n", 0, 0, 0 ); rc = ext_candidates( op, rtxn, f->f_mra, ids, tmp, stack ); break; default: Debug( LDAP_DEBUG_FILTER, "\tUNKNOWN %lu\n", (unsigned long) f->f_choice, 0, 0 ); /* Must not return NULL, otherwise extended filters break */ MDB_IDL_ALL( ids ); } out: Debug( LDAP_DEBUG_FILTER, "<= mdb_filter_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST( ids ), (long) MDB_IDL_LAST( ids ) ); return rc; }
int get_mra( Operation *op, BerElement *ber, Filter *f, const char **text ) { int rc; ber_tag_t tag, rtag; ber_len_t length; struct berval type = BER_BVNULL; struct berval value = BER_BVNULL; struct berval rule_text = BER_BVNULL; MatchingRuleAssertion ma = { 0 }; #ifdef LDAP_COMP_MATCH AttributeAliasing* aa = NULL; #endif rtag = ber_scanf( ber, "{t" /*"}"*/, &tag ); if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); *text = "Error parsing matching rule assertion"; return SLAPD_DISCONNECT; } if ( tag == LDAP_FILTER_EXT_OID ) { rtag = ber_scanf( ber, "m", &rule_text ); if ( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf for mr\n", 0, 0, 0 ); *text = "Error parsing matching rule in matching rule assertion"; return SLAPD_DISCONNECT; } rtag = ber_scanf( ber, "t", &tag ); if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); *text = "Error parsing matching rule assertion"; return SLAPD_DISCONNECT; } } if ( tag == LDAP_FILTER_EXT_TYPE ) { rtag = ber_scanf( ber, "m", &type ); if ( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf for ad\n", 0, 0, 0 ); *text = "Error parsing attribute description in matching rule assertion"; return SLAPD_DISCONNECT; } rtag = ber_scanf( ber, "t", &tag ); if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); *text = "Error parsing matching rule assertion"; return SLAPD_DISCONNECT; } } if ( tag != LDAP_FILTER_EXT_VALUE ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf missing value\n", 0, 0, 0 ); *text = "Missing value in matching rule assertion"; return SLAPD_DISCONNECT; } rtag = ber_scanf( ber, "m", &value ); if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); *text = "Error decoding value in matching rule assertion"; return SLAPD_DISCONNECT; } tag = ber_peek_tag( ber, &length ); if ( tag == LDAP_FILTER_EXT_DNATTRS ) { rtag = ber_scanf( ber, /*"{"*/ "b}", &ma.ma_dnattrs ); } else { rtag = ber_scanf( ber, /*"{"*/ "}" ); } if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_mra ber_scanf\n", 0, 0, 0 ); *text = "Error decoding dnattrs matching rule assertion"; return SLAPD_DISCONNECT; } if( type.bv_val != NULL ) { rc = slap_bv2ad( &type, &ma.ma_desc, text ); if( rc != LDAP_SUCCESS ) { f->f_choice |= SLAPD_FILTER_UNDEFINED; rc = slap_bv2undef_ad( &type, &ma.ma_desc, text, SLAP_AD_PROXIED|SLAP_AD_NOINSERT ); if( rc != LDAP_SUCCESS ) { ma.ma_desc = slap_bv2tmp_ad( &type, op->o_tmpmemctx ); rc = LDAP_SUCCESS; } } } if( rule_text.bv_val != NULL ) { ma.ma_rule = mr_bvfind( &rule_text ); if( ma.ma_rule == NULL ) { *text = "matching rule not recognized"; return LDAP_INAPPROPRIATE_MATCHING; } } if ( ma.ma_rule == NULL ) { /* * Need either type or rule ... */ if ( ma.ma_desc == NULL ) { *text = "no matching rule or type"; return LDAP_INAPPROPRIATE_MATCHING; } if ( ma.ma_desc->ad_type->sat_equality != NULL && ma.ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT ) { /* no matching rule was provided, use the attribute's equality rule if it supports extensible matching. */ ma.ma_rule = ma.ma_desc->ad_type->sat_equality; } else { *text = "no appropriate rule to use for type"; return LDAP_INAPPROPRIATE_MATCHING; } } if ( ma.ma_desc != NULL ) { if( !mr_usable_with_at( ma.ma_rule, ma.ma_desc->ad_type ) ) { *text = "matching rule use with this attribute not appropriate"; return LDAP_INAPPROPRIATE_MATCHING; } } /* * Normalize per matching rule */ rc = asserted_value_validate_normalize( ma.ma_desc, ma.ma_rule, SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, &value, &ma.ma_value, text, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) return rc; #ifdef LDAP_COMP_MATCH /* Check If this attribute is aliased */ if ( is_aliased_attribute && ma.ma_desc && ( aa = is_aliased_attribute ( ma.ma_desc ) ) ) { rc = get_aliased_filter ( op, &ma, aa, text ); if ( rc != LDAP_SUCCESS ) return rc; } else if ( ma.ma_rule && ma.ma_rule->smr_usage & SLAP_MR_COMPONENT ) { /* Matching Rule for Component Matching */ rc = get_comp_filter( op, &ma.ma_value, &ma.ma_cf, text ); if ( rc != LDAP_SUCCESS ) return rc; } #endif length = sizeof(ma); /* Append rule_text to end of struct */ if (rule_text.bv_val) length += rule_text.bv_len + 1; f->f_mra = op->o_tmpalloc( length, op->o_tmpmemctx ); *f->f_mra = ma; if (rule_text.bv_val) { f->f_mra->ma_rule_text.bv_len = rule_text.bv_len; f->f_mra->ma_rule_text.bv_val = (char *)(f->f_mra+1); AC_MEMCPY(f->f_mra->ma_rule_text.bv_val, rule_text.bv_val, rule_text.bv_len+1); } return LDAP_SUCCESS; }
static int test_ava_filter( Operation *op, Entry *e, AttributeAssertion *ava, int type ) { int rc; Attribute *a; #ifdef LDAP_COMP_MATCH int i, num_attr_vals = 0; AttributeAliasing *a_alias = NULL; #endif if ( !access_allowed( op, e, ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) ) { return LDAP_INSUFFICIENT_ACCESS; } if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates && op && op->o_bd && op->o_bd->be_has_subordinates ) { int hasSubordinates; struct berval hs; if( type != LDAP_FILTER_EQUALITY && type != LDAP_FILTER_APPROX ) { /* No other match is allowed */ return LDAP_INAPPROPRIATE_MATCHING; } if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) != LDAP_SUCCESS ) { return LDAP_OTHER; } if ( hasSubordinates == LDAP_COMPARE_TRUE ) { hs = slap_true_bv; } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) { hs = slap_false_bv; } else { return LDAP_OTHER; } if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE; return LDAP_COMPARE_FALSE; } if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { MatchingRule *mr; int match; const char *text; if( type != LDAP_FILTER_EQUALITY && type != LDAP_FILTER_APPROX ) { /* No other match is allowed */ return LDAP_INAPPROPRIATE_MATCHING; } mr = slap_schema.si_ad_entryDN->ad_type->sat_equality; assert( mr != NULL ); rc = value_match( &match, slap_schema.si_ad_entryDN, mr, SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text ); if( rc != LDAP_SUCCESS ) return rc; if( match == 0 ) return LDAP_COMPARE_TRUE; return LDAP_COMPARE_FALSE; } rc = LDAP_COMPARE_FALSE; #ifdef LDAP_COMP_MATCH if ( is_aliased_attribute && ava->aa_cf ) { a_alias = is_aliased_attribute ( ava->aa_desc ); if ( a_alias ) ava->aa_desc = a_alias->aa_aliased_ad; else ava->aa_cf = NULL; } #endif for(a = attrs_find( e->e_attrs, ava->aa_desc ); a != NULL; a = attrs_find( a->a_next, ava->aa_desc ) ) { int use; MatchingRule *mr; struct berval *bv; if (( ava->aa_desc != a->a_desc ) && !access_allowed( op, e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL )) { rc = LDAP_INSUFFICIENT_ACCESS; continue; } use = SLAP_MR_EQUALITY; switch ( type ) { case LDAP_FILTER_APPROX: use = SLAP_MR_EQUALITY_APPROX; mr = a->a_desc->ad_type->sat_approx; if( mr != NULL ) break; /* fallthru: use EQUALITY matching rule if no APPROX rule */ case LDAP_FILTER_EQUALITY: /* use variable set above so fall thru use is not clobbered */ mr = a->a_desc->ad_type->sat_equality; break; case LDAP_FILTER_GE: case LDAP_FILTER_LE: use = SLAP_MR_ORDERING; mr = a->a_desc->ad_type->sat_ordering; break; default: mr = NULL; } if( mr == NULL ) { rc = LDAP_INAPPROPRIATE_MATCHING; continue; } /* We have no Sort optimization for Approx matches */ if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && type != LDAP_FILTER_APPROX ) { unsigned slot; int ret; /* For Ordering matches, we just need to do one comparison with * either the first (least) or last (greatest) value. */ if ( use == SLAP_MR_ORDERING ) { const char *text; int match, which; which = (type == LDAP_FILTER_LE) ? 0 : a->a_numvals-1; ret = value_match( &match, a->a_desc, mr, use, &a->a_nvals[which], &ava->aa_value, &text ); if ( ret != LDAP_SUCCESS ) return ret; if (( type == LDAP_FILTER_LE && match <= 0 ) || ( type == LDAP_FILTER_GE && match >= 0 )) return LDAP_COMPARE_TRUE; continue; } /* Only Equality will get here */ ret = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, &ava->aa_value, &slot, NULL ); if ( ret == LDAP_SUCCESS ) return LDAP_COMPARE_TRUE; else if ( ret != LDAP_NO_SUCH_ATTRIBUTE ) return ret; #if 0 /* The following is useful if we want to know which values * matched an ordering test. But here we don't care, we just * want to know if any value did, and that is checked above. */ if ( ret == LDAP_NO_SUCH_ATTRIBUTE ) { /* If insertion point is not the end of the list, there was * at least one value greater than the assertion. */ if ( type == LDAP_FILTER_GE && slot < a->a_numvals ) return LDAP_COMPARE_TRUE; /* Likewise, if insertion point is not the head of the list, * there was at least one value less than the assertion. */ if ( type == LDAP_FILTER_LE && slot > 0 ) return LDAP_COMPARE_TRUE; return LDAP_COMPARE_FALSE; } #endif continue; } #ifdef LDAP_COMP_MATCH if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) { /* Component Matching */ for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ ); if ( num_attr_vals <= 0 )/* no attribute value */ return LDAP_INAPPROPRIATE_MATCHING; num_attr_vals++;/* for NULL termination */ /* following malloced will be freed by comp_tree_free () */ a->a_comp_data = SLAP_MALLOC( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals ); if ( !a->a_comp_data ) { return LDAP_NO_MEMORY; } a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData)); i = num_attr_vals; for ( ; i ; i-- ) { a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL; } a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 ); if ( a->a_comp_data->cd_mem_op == NULL ) { free ( a->a_comp_data ); a->a_comp_data = NULL; return LDAP_OPERATIONS_ERROR; } } i = 0; #endif for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) { int ret, match; const char *text; #ifdef LDAP_COMP_MATCH if( attr_converter && ava->aa_cf && a->a_comp_data ) { /* Check if decoded component trees are already linked */ struct berval cf_bv = { 20, "componentFilterMatch" }; MatchingRule* cf_mr = mr_bvfind( &cf_bv ); MatchingRuleAssertion mra; mra.ma_cf = ava->aa_cf; if ( a->a_comp_data->cd_tree[i] == NULL ) a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i)); /* decoding error */ if ( !a->a_comp_data->cd_tree[i] ) { free_ComponentData ( a ); return LDAP_OPERATIONS_ERROR; } ret = value_match( &match, a->a_desc, cf_mr, SLAP_MR_COMPONENT, (struct berval*)a->a_comp_data->cd_tree[i++], (void*)&mra, &text ); if ( ret == LDAP_INAPPROPRIATE_MATCHING ) { /* cached component tree is broken, just remove it */ free_ComponentData ( a ); return ret; } if ( a_alias ) ava->aa_desc = a_alias->aa_aliasing_ad; } else #endif { ret = ordered_value_match( &match, a->a_desc, mr, use, bv, &ava->aa_value, &text ); } if( ret != LDAP_SUCCESS ) { rc = ret; break; } switch ( type ) { case LDAP_FILTER_EQUALITY: case LDAP_FILTER_APPROX: if ( match == 0 ) return LDAP_COMPARE_TRUE; break; case LDAP_FILTER_GE: if ( match >= 0 ) return LDAP_COMPARE_TRUE; break; case LDAP_FILTER_LE: if ( match <= 0 ) return LDAP_COMPARE_TRUE; break; } } } #ifdef LDAP_COMP_MATCH if ( a_alias ) ava->aa_desc = a_alias->aa_aliasing_ad; #endif return rc; }
int get_ava( Operation *op, BerElement *ber, Filter *f, unsigned usage, const char **text ) { int rc; ber_tag_t rtag; struct berval type, value; AttributeAssertion *aa; #ifdef LDAP_COMP_MATCH AttributeAliasing* a_alias = NULL; #endif rtag = ber_scanf( ber, "{mm}", &type, &value ); if( rtag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, " get_ava ber_scanf\n", 0, 0, 0 ); *text = "Error decoding attribute value assertion"; return SLAPD_DISCONNECT; } aa = op->o_tmpalloc( sizeof( AttributeAssertion ), op->o_tmpmemctx ); aa->aa_desc = NULL; aa->aa_value.bv_val = NULL; #ifdef LDAP_COMP_MATCH aa->aa_cf = NULL; #endif rc = slap_bv2ad( &type, &aa->aa_desc, text ); if( rc != LDAP_SUCCESS ) { f->f_choice |= SLAPD_FILTER_UNDEFINED; *text = NULL; rc = slap_bv2undef_ad( &type, &aa->aa_desc, text, SLAP_AD_PROXIED|SLAP_AD_NOINSERT ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_FILTER, "get_ava: unknown attributeType %s\n", type.bv_val, 0, 0 ); aa->aa_desc = slap_bv2tmp_ad( &type, op->o_tmpmemctx ); ber_dupbv_x( &aa->aa_value, &value, op->o_tmpmemctx ); f->f_ava = aa; return LDAP_SUCCESS; } } rc = asserted_value_validate_normalize( aa->aa_desc, ad_mr(aa->aa_desc, usage), usage, &value, &aa->aa_value, text, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { f->f_choice |= SLAPD_FILTER_UNDEFINED; Debug( LDAP_DEBUG_FILTER, "get_ava: illegal value for attributeType %s\n", type.bv_val, 0, 0 ); ber_dupbv_x( &aa->aa_value, &value, op->o_tmpmemctx ); *text = NULL; rc = LDAP_SUCCESS; } #ifdef LDAP_COMP_MATCH if( is_aliased_attribute ) { a_alias = is_aliased_attribute ( aa->aa_desc ); if ( a_alias ) { rc = get_aliased_filter_aa ( op, aa, a_alias, text ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_FILTER, "get_ava: Invalid Attribute Aliasing\n", 0, 0, 0 ); return rc; } } } #endif f->f_ava = aa; return LDAP_SUCCESS; }