/* $NetBSD: component.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ /* component.c -- Component Filter Match Routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2003-2021 The OpenLDAP Foundation. * Portions Copyright 2004 by IBM Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include __RCSID("$NetBSD: component.c,v 1.3 2021/08/14 16:14:58 christos Exp $"); #include "portable.h" #include #include #include "lutil.h" #include #include "slap.h" #ifdef LDAP_COMP_MATCH #include "component.h" /* * Following function pointers are initialized * when a component module is loaded */ alloc_nibble_func* nibble_mem_allocator = NULL; free_nibble_func* nibble_mem_free = NULL; convert_attr_to_comp_func* attr_converter = NULL; convert_assert_to_comp_func* assert_converter = NULL ; free_component_func* component_destructor = NULL ; test_component_func* test_components = NULL; test_membership_func* is_aliased_attribute = NULL; component_encoder_func* component_encoder = NULL; get_component_info_func* get_component_description = NULL; #define OID_ALL_COMP_MATCH "1.2.36.79672281.1.13.6" #define OID_COMP_FILTER_MATCH "1.2.36.79672281.1.13.2" #define MAX_LDAP_STR_LEN 128 static int peek_componentId_type( ComponentAssertionValue* cav ); static int strip_cav_str( ComponentAssertionValue* cav, char* str); static int peek_cav_str( ComponentAssertionValue* cav, char* str ); static int parse_comp_filter( Operation* op, ComponentAssertionValue* cav, ComponentFilter** filt, const char** text ); static void free_comp_filter( ComponentFilter* f ); static int test_comp_filter( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *f ); int componentCertificateValidate( Syntax *syntax, struct berval *val ) { return LDAP_SUCCESS; } int componentFilterValidate( Syntax *syntax, struct berval *val ) { return LDAP_SUCCESS; } int allComponentsValidate( Syntax *syntax, struct berval *val ) { return LDAP_SUCCESS; } int componentFilterMatch ( int *matchp, slap_mask_t flags, Syntax *syntax, MatchingRule *mr, struct berval *value, void *assertedValue ) { ComponentSyntaxInfo *csi_attr = (ComponentSyntaxInfo*)value; MatchingRuleAssertion * ma = (MatchingRuleAssertion*)assertedValue; int rc; if ( !mr || !ma->ma_cf ) return LDAP_INAPPROPRIATE_MATCHING; /* Check if the component module is loaded */ if ( !attr_converter || !nibble_mem_allocator ) { return LDAP_OTHER; } rc = test_comp_filter( syntax, csi_attr, ma->ma_cf ); if ( rc == LDAP_COMPARE_TRUE ) { *matchp = 0; return LDAP_SUCCESS; } else if ( rc == LDAP_COMPARE_FALSE ) { *matchp = 1; return LDAP_SUCCESS; } else { return LDAP_INAPPROPRIATE_MATCHING; } } int directoryComponentsMatch( int *matchp, slap_mask_t flags, Syntax *syntax, MatchingRule *mr, struct berval *value, void *assertedValue ) { /* Only for registration */ *matchp = 0; return LDAP_SUCCESS; } int allComponentsMatch( int *matchp, slap_mask_t flags, Syntax *syntax, MatchingRule *mr, struct berval *value, void *assertedValue ) { /* Only for registration */ *matchp = 0; return LDAP_SUCCESS; } static int slapd_ber2cav( struct berval* bv, ComponentAssertionValue* cav ) { cav->cav_ptr = cav->cav_buf = bv->bv_val; cav->cav_end = bv->bv_val + bv->bv_len; return LDAP_SUCCESS; } ComponentReference* dup_comp_ref ( Operation* op, ComponentReference* cr ) { ComponentReference* dup_cr; ComponentId* ci_curr; ComponentId** ci_temp; dup_cr = op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx ); dup_cr->cr_len = cr->cr_len; dup_cr->cr_string = cr->cr_string; ci_temp = &dup_cr->cr_list; ci_curr = cr->cr_list; for ( ; ci_curr != NULL ; ci_curr = ci_curr->ci_next, ci_temp = &(*ci_temp)->ci_next ) { *ci_temp = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx ); if ( !*ci_temp ) return NULL; **ci_temp = *ci_curr; } dup_cr->cr_curr = dup_cr->cr_list; return dup_cr; } static int dup_comp_filter_list ( Operation *op, struct berval *bv, ComponentFilter* in_f, ComponentFilter** out_f ) { ComponentFilter **new, *f; int rc; new = out_f; for ( f = in_f; f != NULL; f = f->cf_next ) { rc = dup_comp_filter( op, bv, f, new ); if ( rc != LDAP_SUCCESS ) { return rc; } new = &(*new)->cf_next; } return LDAP_SUCCESS; } int get_len_of_next_assert_value ( struct berval* bv, char separator ) { ber_len_t i = 0; while (1) { if ( (bv->bv_val[ i ] == separator) || ( i >= bv->bv_len) ) break; i++; } bv->bv_val += (i + 1); bv->bv_len -= (i + 1); return i; } int dup_comp_filter_item ( Operation *op, struct berval* assert_bv, ComponentAssertion* in_ca, ComponentAssertion** out_ca ) { int len; if ( !in_ca->ca_comp_ref ) return SLAPD_DISCONNECT; *out_ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx ); if ( !(*out_ca) ) return LDAP_NO_MEMORY; (*out_ca)->ca_comp_data.cd_tree = NULL; (*out_ca)->ca_comp_data.cd_mem_op = NULL; (*out_ca)->ca_comp_ref = dup_comp_ref ( op, in_ca->ca_comp_ref ); (*out_ca)->ca_use_def = 0; (*out_ca)->ca_ma_rule = in_ca->ca_ma_rule; (*out_ca)->ca_ma_value.bv_val = assert_bv->bv_val; len = get_len_of_next_assert_value ( assert_bv, '$' ); if ( len <= 0 ) return SLAPD_DISCONNECT; (*out_ca)->ca_ma_value.bv_len = len; return LDAP_SUCCESS; } int dup_comp_filter ( Operation* op, struct berval *bv, ComponentFilter *in_f, ComponentFilter **out_f ) { int rc; ComponentFilter dup_f = {0}; if ( !in_f ) return LDAP_PROTOCOL_ERROR; switch ( in_f->cf_choice ) { case LDAP_COMP_FILTER_AND: rc = dup_comp_filter_list( op, bv, in_f->cf_and, &dup_f.cf_and); dup_f.cf_choice = LDAP_COMP_FILTER_AND; break; case LDAP_COMP_FILTER_OR: rc = dup_comp_filter_list( op, bv, in_f->cf_or, &dup_f.cf_or); dup_f.cf_choice = LDAP_COMP_FILTER_OR; break; case LDAP_COMP_FILTER_NOT: rc = dup_comp_filter( op, bv, in_f->cf_not, &dup_f.cf_not); dup_f.cf_choice = LDAP_COMP_FILTER_NOT; break; case LDAP_COMP_FILTER_ITEM: rc = dup_comp_filter_item( op, bv, in_f->cf_ca ,&dup_f.cf_ca ); dup_f.cf_choice = LDAP_COMP_FILTER_ITEM; break; default: rc = LDAP_PROTOCOL_ERROR; } if ( rc == LDAP_SUCCESS ) { *out_f = op->o_tmpalloc( sizeof(dup_f), op->o_tmpmemctx ); **out_f = dup_f; } return( rc ); } int get_aliased_filter_aa ( Operation* op, AttributeAssertion* a_assert, AttributeAliasing* aa, const char** text ) { struct berval assert_bv; Debug( LDAP_DEBUG_FILTER, "get_aliased_filter\n" ); if ( !aa->aa_cf ) return LDAP_PROTOCOL_ERROR; assert_bv = a_assert->aa_value; /* * Duplicate aa->aa_cf to ma->ma_cf by replacing the * the component assertion value in assert_bv * Multiple values may be separated with '$' */ return dup_comp_filter ( op, &assert_bv, aa->aa_cf, &a_assert->aa_cf ); } int get_aliased_filter( Operation* op, MatchingRuleAssertion* ma, AttributeAliasing* aa, const char** text ) { struct berval assert_bv; Debug( LDAP_DEBUG_FILTER, "get_aliased_filter\n" ); if ( !aa->aa_cf ) return LDAP_PROTOCOL_ERROR; assert_bv = ma->ma_value; /* Attribute Description is replaced with aliased one */ ma->ma_desc = aa->aa_aliased_ad; ma->ma_rule = aa->aa_mr; /* * Duplicate aa->aa_cf to ma->ma_cf by replacing the * the component assertion value in assert_bv * Multiple values may be separated with '$' */ return dup_comp_filter ( op, &assert_bv, aa->aa_cf, &ma->ma_cf ); } int get_comp_filter( Operation* op, struct berval* bv, ComponentFilter** filt, const char **text ) { ComponentAssertionValue cav; int rc; Debug( LDAP_DEBUG_FILTER, "get_comp_filter\n" ); if ( (rc = slapd_ber2cav(bv, &cav) ) != LDAP_SUCCESS ) { return rc; } rc = parse_comp_filter( op, &cav, filt, text ); /* bv->bv_val = cav.cav_ptr; */ return rc; } static void eat_whsp( ComponentAssertionValue* cav ) { for ( ; ( *cav->cav_ptr == ' ' ) && ( cav->cav_ptr < cav->cav_end ) ; ) { cav->cav_ptr++; } } static int cav_cur_len( ComponentAssertionValue* cav ) { return cav->cav_end - cav->cav_ptr; } static ber_tag_t comp_first_element( ComponentAssertionValue* cav ) { eat_whsp( cav ); if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) { return LDAP_COMP_FILTER_ITEM; } else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) { return LDAP_COMP_FILTER_AND; } else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) { return LDAP_COMP_FILTER_OR; } else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) { return LDAP_COMP_FILTER_NOT; } else { return LDAP_COMP_FILTER_UNDEFINED; } } static ber_tag_t comp_next_element( ComponentAssertionValue* cav ) { eat_whsp( cav ); if ( *(cav->cav_ptr) == ',' ) { /* move pointer to the next CA */ cav->cav_ptr++; return comp_first_element( cav ); } else return LDAP_COMP_FILTER_UNDEFINED; } static int get_comp_filter_list( Operation *op, ComponentAssertionValue *cav, ComponentFilter** f, const char** text ) { ComponentFilter **new; int err; ber_tag_t tag; Debug( LDAP_DEBUG_FILTER, "get_comp_filter_list\n" ); new = f; for ( tag = comp_first_element( cav ); tag != LDAP_COMP_FILTER_UNDEFINED; tag = comp_next_element( cav ) ) { err = parse_comp_filter( op, cav, new, text ); if ( err != LDAP_SUCCESS ) return ( err ); new = &(*new)->cf_next; } *new = NULL; return( LDAP_SUCCESS ); } static int get_componentId( Operation *op, ComponentAssertionValue* cav, ComponentId ** cid, const char** text ) { ber_tag_t type; ComponentId _cid; int len; type = peek_componentId_type( cav ); Debug( LDAP_DEBUG_FILTER, "get_compId [%lu]\n", (unsigned long) type ); len = 0; _cid.ci_type = type; _cid.ci_next = NULL; switch ( type ) { case LDAP_COMPREF_IDENTIFIER : _cid.ci_val.ci_identifier.bv_val = cav->cav_ptr; for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' && cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ ); _cid.ci_val.ci_identifier.bv_len = len; cav->cav_ptr += len; break; case LDAP_COMPREF_FROM_BEGINNING : for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' && cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ ); _cid.ci_val.ci_from_beginning = strtol( cav->cav_ptr, NULL, 0 ); cav->cav_ptr += len; break; case LDAP_COMPREF_FROM_END : for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' && cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ ); _cid.ci_val.ci_from_end = strtol( cav->cav_ptr, NULL, 0 ); cav->cav_ptr += len; break; case LDAP_COMPREF_COUNT : _cid.ci_val.ci_count = 0; cav->cav_ptr++; break; case LDAP_COMPREF_CONTENT : _cid.ci_val.ci_content = 1; cav->cav_ptr += strlen("content"); break; case LDAP_COMPREF_SELECT : if ( cav->cav_ptr[len] != '(' ) return LDAP_COMPREF_UNDEFINED; for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' && cav->cav_ptr[len] != '\"' && cav->cav_ptr[len] != ')' ; len++ ); _cid.ci_val.ci_select_value.bv_val = cav->cav_ptr + 1; _cid.ci_val.ci_select_value.bv_len = len - 1 ; cav->cav_ptr += len + 1; break; case LDAP_COMPREF_ALL : _cid.ci_val.ci_all = '*'; cav->cav_ptr++; break; default : return LDAP_COMPREF_UNDEFINED; } if ( op ) { *cid = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx ); } else { *cid = SLAP_MALLOC( sizeof( ComponentId ) ); } if (*cid == NULL) { return LDAP_NO_MEMORY; } **cid = _cid; return LDAP_SUCCESS; } static int peek_componentId_type( ComponentAssertionValue* cav ) { eat_whsp( cav ); if ( cav->cav_ptr[0] == '-' ) { return LDAP_COMPREF_FROM_END; } else if ( cav->cav_ptr[0] == '(' ) { return LDAP_COMPREF_SELECT; } else if ( cav->cav_ptr[0] == '*' ) { return LDAP_COMPREF_ALL; } else if ( cav->cav_ptr[0] == '0' ) { return LDAP_COMPREF_COUNT; } else if ( cav->cav_ptr[0] > '0' && cav->cav_ptr[0] <= '9' ) { return LDAP_COMPREF_FROM_BEGINNING; } else if ( (cav->cav_end - cav->cav_ptr) >= 7 && strncmp(cav->cav_ptr,"content",7) == 0 ) { return LDAP_COMPREF_CONTENT; } else if ( (cav->cav_ptr[0] >= 'a' && cav->cav_ptr[0] <= 'z') || (cav->cav_ptr[0] >= 'A' && cav->cav_ptr[0] <= 'Z') ) { return LDAP_COMPREF_IDENTIFIER; } return LDAP_COMPREF_UNDEFINED; } static ber_tag_t comp_next_id( ComponentAssertionValue* cav ) { if ( *(cav->cav_ptr) == '.' ) { cav->cav_ptr++; return LDAP_COMPREF_DEFINED; } return LDAP_COMPREF_UNDEFINED; } static int get_component_reference( Operation *op, ComponentAssertionValue* cav, ComponentReference** cr, const char** text ) { int rc, count = 0; ber_int_t type; ComponentReference* ca_comp_ref; ComponentId** cr_list; char* start, *end; eat_whsp( cav ); start = cav->cav_ptr; if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS ) return rc; if ( op ) { ca_comp_ref = op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx ); } else { ca_comp_ref = SLAP_MALLOC( sizeof( ComponentReference ) ); } if ( !ca_comp_ref ) return LDAP_NO_MEMORY; cr_list = &ca_comp_ref->cr_list; for ( type = peek_componentId_type( cav ) ; type != LDAP_COMPREF_UNDEFINED ; type = comp_next_id( cav ), count++ ) { rc = get_componentId( op, cav, cr_list, text ); if ( rc == LDAP_SUCCESS ) { if ( count == 0 ) ca_comp_ref->cr_curr = ca_comp_ref->cr_list; cr_list = &(*cr_list)->ci_next; } else if ( rc == LDAP_COMPREF_UNDEFINED ) { if ( op ) { op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx ); } else { free( ca_comp_ref ); } return rc; } } ca_comp_ref->cr_len = count; end = cav->cav_ptr; if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS ) { if ( op ) { op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx ); } else { free( ca_comp_ref ); } return rc; } *cr = ca_comp_ref; **cr = *ca_comp_ref; (*cr)->cr_string.bv_val = start; (*cr)->cr_string.bv_len = end - start + 1; return rc; } int insert_component_reference( ComponentReference *cr, ComponentReference** cr_list) { if ( !cr ) return LDAP_PARAM_ERROR; if ( !(*cr_list) ) { *cr_list = cr; cr->cr_next = NULL; } else { cr->cr_next = *cr_list; *cr_list = cr; } return LDAP_SUCCESS; } /* * If there is '.' in the name of a given attribute * the first '.'- following characters are considered * as a component reference of the attribute * EX) userCertificate.toBeSigned.serialNumber * attribute : userCertificate * component reference : toBeSigned.serialNumber */ int is_component_reference( char* attr ) { int i; for ( i=0; attr[i] != '\0' ; i++ ) { if ( attr[i] == '.' ) return (1); } return (0); } int extract_component_reference( char* attr, ComponentReference** cr ) { int i, rc; char* cr_ptr; int cr_len; ComponentAssertionValue cav; char text[1][128]; for ( i=0; attr[i] != '\0' ; i++ ) { if ( attr[i] == '.' ) break; } if (attr[i] != '.' ) return LDAP_PARAM_ERROR; attr[i] = '\0'; cr_ptr = attr + i + 1 ; cr_len = strlen ( cr_ptr ); if ( cr_len <= 0 ) return LDAP_PARAM_ERROR; /* enclosed between double quotes*/ cav.cav_ptr = cav.cav_buf = ch_malloc (cr_len+2); memcpy( cav.cav_buf+1, cr_ptr, cr_len ); cav.cav_buf[0] = '"'; cav.cav_buf[cr_len+1] = '"'; cav.cav_end = cr_ptr + cr_len + 2; rc = get_component_reference ( NULL, &cav, cr, (const char**)text ); if ( rc != LDAP_SUCCESS ) return rc; (*cr)->cr_string.bv_val = cav.cav_buf; (*cr)->cr_string.bv_len = cr_len + 2; return LDAP_SUCCESS; } static int get_ca_use_default( Operation *op, ComponentAssertionValue* cav, int* ca_use_def, const char** text ) { strip_cav_str( cav, "useDefaultValues" ); if ( peek_cav_str( cav, "TRUE" ) == LDAP_SUCCESS ) { strip_cav_str( cav, "TRUE" ); *ca_use_def = 1; } else if ( peek_cav_str( cav, "FALSE" ) == LDAP_SUCCESS ) { strip_cav_str( cav, "FALSE" ); *ca_use_def = 0; } else { return LDAP_INVALID_SYNTAX; } return LDAP_SUCCESS; } static int get_matching_rule( Operation *op, ComponentAssertionValue* cav, MatchingRule** mr, const char** text ) { int count = 0; struct berval rule_text = { 0L, NULL }; eat_whsp( cav ); for ( ; ; count++ ) { if ( cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == ',' || cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == '{' || cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '\n' ) { break; } } if ( count == 0 ) { *text = "component matching rule not recognized"; return LDAP_INAPPROPRIATE_MATCHING; } rule_text.bv_len = count; rule_text.bv_val = cav->cav_ptr; *mr = mr_bvfind( &rule_text ); cav->cav_ptr += count; Debug( LDAP_DEBUG_FILTER, "get_matching_rule: %s\n", (*mr)->smr_mrule.mr_oid ); if ( *mr == NULL ) { *text = "component matching rule not recognized"; return LDAP_INAPPROPRIATE_MATCHING; } return LDAP_SUCCESS; } static int get_GSER_value( ComponentAssertionValue* cav, struct berval* bv ) { int count, sequent_dquote, unclosed_brace, succeed; eat_whsp( cav ); /* * Four cases of GSER * 1) "..." : * StringVal, GeneralizedTimeVal, UTCTimeVal, ObjectDescriptorVal * 2) '...'B or '...'H : * BitStringVal, OctetStringVal * 3) {...} : * SEQUENCE, SEQUENCEOF, SETOF, SET, CHOICE * 4) Between two white spaces * INTEGER, BOOLEAN, NULL,ENUMERATE, etc */ succeed = 0; if ( cav->cav_ptr[0] == '"' ) { for( count = 1, sequent_dquote = 0 ; ; count++ ) { /* In order to find escaped double quote */ if ( cav->cav_ptr[count] == '"' ) sequent_dquote++; else sequent_dquote = 0; if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end ) { break; } if ( ( cav->cav_ptr[count] == '"' && cav->cav_ptr[count-1] != '"') || ( sequent_dquote > 2 && (sequent_dquote%2) == 1 ) ) { succeed = 1; break; } } if ( !succeed || cav->cav_ptr[count] != '"' ) { return LDAP_FILTER_ERROR; } bv->bv_val = cav->cav_ptr + 1; bv->bv_len = count - 1; /* exclude '"' */ } else if ( cav->cav_ptr[0] == '\'' ) { for( count = 1 ; ; count++ ) { if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end ) { break; } if ((cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'B') || (cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'H') ) { succeed = 1; break; } } if ( !succeed || !(cav->cav_ptr[count] == 'H' || cav->cav_ptr[count] == 'B') ) { return LDAP_FILTER_ERROR; } bv->bv_val = cav->cav_ptr + 1;/*the next to '"' */ bv->bv_len = count - 2;/* exclude "'H" or "'B" */ } else if ( cav->cav_ptr[0] == '{' ) { for( count = 1, unclosed_brace = 1 ; ; count++ ) { if ( cav->cav_ptr[count] == '{' ) unclosed_brace++; if ( cav->cav_ptr[count] == '}' ) unclosed_brace--; if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end ) { break; } if ( unclosed_brace == 0 ) { succeed = 1; break; } } if ( !succeed || cav->cav_ptr[count] != '}' ) return LDAP_FILTER_ERROR; bv->bv_val = cav->cav_ptr + 1;/*the next to '"' */ bv->bv_len = count - 1;/* exclude "'B" */ } else { succeed = 1; /*Find following white space where the value is ended*/ for( count = 1 ; ; count++ ) { if ( cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '{' || (cav->cav_ptr+count) > cav->cav_end ) { break; } } bv->bv_val = cav->cav_ptr; bv->bv_len = count; } cav->cav_ptr += bv->bv_len; return LDAP_SUCCESS; } static int get_matching_value( Operation *op, ComponentAssertion* ca, ComponentAssertionValue* cav, struct berval* bv, const char** text ) { if ( !(ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT)) ) { if ( get_GSER_value( cav, bv ) != LDAP_SUCCESS ) { return LDAP_FILTER_ERROR; } } else { /* embedded componentFilterMatch Description */ bv->bv_val = cav->cav_ptr; bv->bv_len = cav_cur_len( cav ); } return LDAP_SUCCESS; } /* Don't move the position pointer, just peek given string */ static int peek_cav_str( ComponentAssertionValue* cav, char* str ) { eat_whsp( cav ); if ( cav_cur_len( cav ) >= strlen( str ) && strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 ) { return LDAP_SUCCESS; } return LDAP_INVALID_SYNTAX; } static int strip_cav_str( ComponentAssertionValue* cav, char* str) { eat_whsp( cav ); if ( cav_cur_len( cav ) >= strlen( str ) && strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 ) { cav->cav_ptr += strlen( str ); return LDAP_SUCCESS; } return LDAP_INVALID_SYNTAX; } /* * TAG : "item", "and", "or", "not" */ static ber_tag_t strip_cav_tag( ComponentAssertionValue* cav ) { int rc; eat_whsp( cav ); if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) { if ( strip_cav_str( cav , "item:" )) goto fail; return LDAP_COMP_FILTER_ITEM; } else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) { if ( strip_cav_str( cav , "and:" )) goto fail; return LDAP_COMP_FILTER_AND; } else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) { if ( strip_cav_str( cav , "or:" )) goto fail; return LDAP_COMP_FILTER_OR; } else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) { if ( strip_cav_str( cav , "not:" )) goto fail; return LDAP_COMP_FILTER_NOT; } fail: return LBER_ERROR; } /* * when encoding, "item" is denotation of ComponentAssertion * ComponentAssertion :: SEQUENCE { * component ComponentReference (SIZE(1..MAX)) OPTIONAL, * useDefaultValues BOOLEAN DEFAULT TRUE, * rule MATCHING-RULE.&id, * value MATCHING-RULE.&AssertionType } */ static int get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca, const char** text ) { int rc, freeval = 0; ComponentAssertion* _ca; struct berval value; MatchingRule* mr; Debug( LDAP_DEBUG_FILTER, "get_item \n" ); if ( op ) _ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx ); else _ca = SLAP_MALLOC( sizeof( ComponentAssertion ) ); if ( !_ca ) return LDAP_NO_MEMORY; _ca->ca_comp_data.cd_tree = NULL; _ca->ca_comp_data.cd_mem_op = NULL; BER_BVZERO( &_ca->ca_ma_value ); rc = peek_cav_str( cav, "component" ); if ( rc == LDAP_SUCCESS ) { strip_cav_str( cav, "component" ); rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text ); if ( rc != LDAP_SUCCESS ) { rc = LDAP_INVALID_SYNTAX; fail: if ( freeval ) op->o_tmpfree( _ca->ca_ma_value.bv_val, op->o_tmpmemctx ); if ( op ) op->o_tmpfree( _ca, op->o_tmpmemctx ); else free( _ca ); return rc; } if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS ) goto fail; } else { _ca->ca_comp_ref = NULL; } rc = peek_cav_str( cav, "useDefaultValues"); if ( rc == LDAP_SUCCESS ) { rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text ); if ( rc != LDAP_SUCCESS ) { rc = LDAP_INVALID_SYNTAX; goto fail; } if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS ) goto fail; } else _ca->ca_use_def = 1; if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS && get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) { rc = LDAP_INAPPROPRIATE_MATCHING; goto fail; } if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS ) goto fail; if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS && get_matching_value( op, _ca, cav,&value ,text ) == LDAP_SUCCESS )) { rc = LDAP_INVALID_SYNTAX; goto fail; } /* * Normalize the value of this component assertion when the matching * rule is one of existing matching rules */ mr = _ca->ca_ma_rule; if ( op && !(mr->smr_usage & (SLAP_MR_COMPONENT)) && mr->smr_normalize ) { value.bv_val[value.bv_len] = '\0'; rc = mr->smr_normalize ( SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, NULL, mr, &value, &_ca->ca_ma_value, op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) goto fail; freeval = 1; } else _ca->ca_ma_value = value; /* * Validate the value of this component assertion */ if ( op && mr->smr_syntax->ssyn_validate( mr->smr_syntax, &_ca->ca_ma_value) != LDAP_SUCCESS ) { rc = LDAP_INVALID_SYNTAX; goto fail; } /* componentFilterMatch contains componentFilterMatch in it */ if ( strcmp(_ca->ca_ma_rule->smr_mrule.mr_oid, OID_COMP_FILTER_MATCH ) == 0) { struct berval bv; bv.bv_val = cav->cav_ptr; bv.bv_len = cav_cur_len( cav ); rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text ); if ( rc != LDAP_SUCCESS ) goto fail; cav->cav_ptr = bv.bv_val; assert( cav->cav_end >= bv.bv_val ); } *ca = _ca; return LDAP_SUCCESS; } static int parse_comp_filter( Operation* op, ComponentAssertionValue* cav, ComponentFilter** filt, const char** text ) { /* * A component filter looks like this coming in: * Filter ::= CHOICE { * item [0] ComponentAssertion, * and [1] SEQUENCE OF ComponentFilter, * or [2] SEQUENCE OF ComponentFilter, * not [3] ComponentFilter, * } */ ber_tag_t tag; int err = LDAP_SUCCESS; ComponentFilter f; /* TAG : item, and, or, not in RFC 4515 */ tag = strip_cav_tag( cav ); if ( tag == LBER_ERROR ) { *text = "error decoding comp filter"; return LDAP_PROTOCOL_ERROR; } if ( tag != LDAP_COMP_FILTER_NOT ) { err = strip_cav_str( cav, "{"); if ( err ) goto invalid; } f.cf_next = NULL; f.cf_choice = tag; switch ( f.cf_choice ) { case LDAP_COMP_FILTER_AND: Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_AND\n" ); err = get_comp_filter_list( op, cav, &f.cf_and, text ); if ( err != LDAP_SUCCESS ) { break; } if ( f.cf_and == NULL ) { f.cf_choice = SLAPD_FILTER_COMPUTED; f.cf_result = LDAP_COMPARE_TRUE; } break; case LDAP_COMP_FILTER_OR: Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_OR\n" ); err = get_comp_filter_list( op, cav, &f.cf_or, text ); if ( err != LDAP_SUCCESS ) { break; } if ( f.cf_or == NULL ) { f.cf_choice = SLAPD_FILTER_COMPUTED; f.cf_result = LDAP_COMPARE_FALSE; } /* no assert - list could be empty */ break; case LDAP_COMP_FILTER_NOT: Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_NOT\n" ); err = parse_comp_filter( op, cav, &f.cf_not, text ); if ( err != LDAP_SUCCESS ) { break; } assert( f.cf_not != NULL ); if ( f.cf_not->cf_choice == SLAPD_FILTER_COMPUTED ) { int fresult = f.cf_not->cf_result; f.cf_choice = SLAPD_FILTER_COMPUTED; op->o_tmpfree( f.cf_not, op->o_tmpmemctx ); f.cf_not = NULL; switch ( fresult ) { case LDAP_COMPARE_TRUE: f.cf_result = LDAP_COMPARE_FALSE; break; case LDAP_COMPARE_FALSE: f.cf_result = LDAP_COMPARE_TRUE; break; default: ; /* (!Undefined) is Undefined */ } } break; case LDAP_COMP_FILTER_ITEM: Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_ITEM\n" ); err = get_item( op, cav, &f.cf_ca, text ); if ( err != LDAP_SUCCESS ) { break; } assert( f.cf_ca != NULL ); break; default: f.cf_choice = SLAPD_FILTER_COMPUTED; f.cf_result = SLAPD_COMPARE_UNDEFINED; break; } invalid: if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) { *text = "Component Filter Syntax Error"; return err; } if ( tag != LDAP_COMP_FILTER_NOT ) err = strip_cav_str( cav, "}"); if ( err == LDAP_SUCCESS ) { if ( op ) { *filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx ); } else { *filt = SLAP_MALLOC( sizeof(f) ); } if ( *filt == NULL ) { return LDAP_NO_MEMORY; } **filt = f; } return( err ); } static int test_comp_filter_and( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *flist ) { ComponentFilter *f; int rtn = LDAP_COMPARE_TRUE; for ( f = flist ; f != NULL; f = f->cf_next ) { int rc = test_comp_filter( syn, a, f ); if ( rc == LDAP_COMPARE_FALSE ) { rtn = rc; break; } if ( rc != LDAP_COMPARE_TRUE ) { rtn = rc; } } return rtn; } static int test_comp_filter_or( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *flist ) { ComponentFilter *f; int rtn = LDAP_COMPARE_TRUE; for ( f = flist ; f != NULL; f = f->cf_next ) { int rc = test_comp_filter( syn, a, f ); if ( rc == LDAP_COMPARE_TRUE ) { rtn = rc; break; } if ( rc != LDAP_COMPARE_FALSE ) { rtn = rc; } } return rtn; } int csi_value_match( MatchingRule *mr, struct berval* bv_attr, struct berval* bv_assert ) { int rc; int match; assert( mr != NULL ); assert( !(mr->smr_usage & SLAP_MR_COMPONENT) ); if( !mr->smr_match ) return LDAP_INAPPROPRIATE_MATCHING; rc = (mr->smr_match)( &match, 0, NULL /*ad->ad_type->sat_syntax*/, mr, bv_attr, bv_assert ); if ( rc != LDAP_SUCCESS ) return rc; return match ? LDAP_COMPARE_FALSE : LDAP_COMPARE_TRUE; } /* * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE */ static int test_comp_filter_item( Syntax *syn, ComponentSyntaxInfo *csi_attr, ComponentAssertion *ca ) { int rc; void *attr_nm, *assert_nm; if ( strcmp(ca->ca_ma_rule->smr_mrule.mr_oid, OID_COMP_FILTER_MATCH ) == 0 && ca->ca_cf ) { /* componentFilterMatch inside of componentFilterMatch */ rc = test_comp_filter( syn, csi_attr, ca->ca_cf ); return rc; } /* Memory for storing will-be-extracted attribute values */ attr_nm = nibble_mem_allocator ( 1024*4 , 1024 ); if ( !attr_nm ) return LDAP_PROTOCOL_ERROR; /* Memory for storing component assertion values */ if( !ca->ca_comp_data.cd_mem_op ) { assert_nm = nibble_mem_allocator ( 256, 64 ); if ( !assert_nm ) { nibble_mem_free ( attr_nm ); return LDAP_PROTOCOL_ERROR; } ca->ca_comp_data.cd_mem_op = assert_nm; } else { assert_nm = ca->ca_comp_data.cd_mem_op; } /* component reference initialization */ if ( ca->ca_comp_ref ) { ca->ca_comp_ref->cr_curr = ca->ca_comp_ref->cr_list; } rc = test_components( attr_nm, assert_nm, csi_attr, ca ); /* free memory used for storing extracted attribute value */ nibble_mem_free ( attr_nm ); return rc; } static int test_comp_filter( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *f ) { int rc; if ( !f ) return LDAP_PROTOCOL_ERROR; Debug( LDAP_DEBUG_FILTER, "test_comp_filter\n" ); switch ( f->cf_choice ) { case SLAPD_FILTER_COMPUTED: rc = f->cf_result; break; case LDAP_COMP_FILTER_AND: rc = test_comp_filter_and( syn, a, f->cf_and ); break; case LDAP_COMP_FILTER_OR: rc = test_comp_filter_or( syn, a, f->cf_or ); break; case LDAP_COMP_FILTER_NOT: rc = test_comp_filter( syn, a, f->cf_not ); switch ( rc ) { case LDAP_COMPARE_TRUE: rc = LDAP_COMPARE_FALSE; break; case LDAP_COMPARE_FALSE: rc = LDAP_COMPARE_TRUE; break; } break; case LDAP_COMP_FILTER_ITEM: rc = test_comp_filter_item( syn, a, f->cf_ca ); break; default: rc = LDAP_PROTOCOL_ERROR; } return( rc ); } static void free_comp_filter_list( ComponentFilter* f ) { ComponentFilter* tmp; for ( tmp = f; tmp; tmp = tmp->cf_next ) { free_comp_filter( tmp ); } } static void free_comp_filter( ComponentFilter* f ) { if ( !f ) { Debug( LDAP_DEBUG_FILTER, "free_comp_filter: Invalid filter so failed to release memory\n" ); return; } switch ( f->cf_choice ) { case LDAP_COMP_FILTER_AND: case LDAP_COMP_FILTER_OR: free_comp_filter_list( f->cf_any ); break; case LDAP_COMP_FILTER_NOT: free_comp_filter( f->cf_any ); break; case LDAP_COMP_FILTER_ITEM: if ( nibble_mem_free && f->cf_ca->ca_comp_data.cd_mem_op ) { nibble_mem_free( f->cf_ca->ca_comp_data.cd_mem_op ); } break; default: break; } } void component_free( ComponentFilter *f ) { free_comp_filter( f ); } void free_ComponentData( Attribute *a ) { if ( a->a_comp_data->cd_mem_op ) component_destructor( a->a_comp_data->cd_mem_op ); free ( a->a_comp_data ); a->a_comp_data = NULL; } #endif