Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: component.c,v 1.4 2025/09/05 21:16:25 christos Exp $	*/
      2 
      3 /* component.c -- Component Filter Match Routines */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2003-2024 The OpenLDAP Foundation.
      8  * Portions Copyright 2004 by IBM Corporation.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted only as authorized by the OpenLDAP
     13  * Public License.
     14  *
     15  * A copy of this license is available in the file LICENSE in the
     16  * top-level directory of the distribution or, alternatively, at
     17  * <http://www.OpenLDAP.org/license.html>.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __RCSID("$NetBSD: component.c,v 1.4 2025/09/05 21:16:25 christos Exp $");
     22 
     23 #include "portable.h"
     24 
     25 #include <ac/string.h>
     26 #include <ac/socket.h>
     27 
     28 #include "lutil.h"
     29 #include <ldap.h>
     30 #include "slap.h"
     31 
     32 #ifdef LDAP_COMP_MATCH
     33 
     34 #include "component.h"
     35 
     36 /*
     37  * Following function pointers are initialized
     38  * when a component module is loaded
     39  */
     40 alloc_nibble_func* nibble_mem_allocator = NULL;
     41 free_nibble_func* nibble_mem_free = NULL;
     42 convert_attr_to_comp_func* attr_converter = NULL;
     43 convert_assert_to_comp_func* assert_converter = NULL ;
     44 free_component_func* component_destructor = NULL ;
     45 test_component_func* test_components = NULL;
     46 test_membership_func* is_aliased_attribute = NULL;
     47 component_encoder_func* component_encoder = NULL;
     48 get_component_info_func* get_component_description = NULL;
     49 #define OID_ALL_COMP_MATCH "1.2.36.79672281.1.13.6"
     50 #define OID_COMP_FILTER_MATCH "1.2.36.79672281.1.13.2"
     51 #define MAX_LDAP_STR_LEN 128
     52 
     53 static int
     54 peek_componentId_type( ComponentAssertionValue* cav );
     55 
     56 static int
     57 strip_cav_str( ComponentAssertionValue* cav, char* str);
     58 
     59 static int
     60 peek_cav_str( ComponentAssertionValue* cav, char* str );
     61 
     62 static int
     63 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
     64 				ComponentFilter** filt, const char** text );
     65 
     66 static void
     67 free_comp_filter( ComponentFilter* f );
     68 
     69 static int
     70 test_comp_filter( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *f );
     71 
     72 int
     73 componentCertificateValidate(
     74 	Syntax *syntax,
     75 	struct berval *val )
     76 {
     77 	return LDAP_SUCCESS;
     78 }
     79 
     80 int
     81 componentFilterValidate(
     82 	Syntax *syntax,
     83 	struct berval *val )
     84 {
     85 	return LDAP_SUCCESS;
     86 }
     87 
     88 int
     89 allComponentsValidate(
     90 	Syntax *syntax,
     91 	struct berval *val )
     92 {
     93 	return LDAP_SUCCESS;
     94 }
     95 
     96 int
     97 componentFilterMatch (
     98 	int *matchp,
     99 	slap_mask_t flags,
    100 	Syntax *syntax,
    101 	MatchingRule *mr,
    102 	struct berval *value,
    103 	void *assertedValue )
    104 {
    105 	ComponentSyntaxInfo *csi_attr = (ComponentSyntaxInfo*)value;
    106 	MatchingRuleAssertion * ma = (MatchingRuleAssertion*)assertedValue;
    107 	int rc;
    108 
    109 	if ( !mr || !ma->ma_cf ) return LDAP_INAPPROPRIATE_MATCHING;
    110 
    111 	/* Check if the component module is loaded */
    112 	if ( !attr_converter || !nibble_mem_allocator ) {
    113 		return LDAP_OTHER;
    114 	}
    115 
    116 	rc = test_comp_filter( syntax, csi_attr, ma->ma_cf );
    117 
    118 	if ( rc == LDAP_COMPARE_TRUE ) {
    119 		*matchp = 0;
    120 		return LDAP_SUCCESS;
    121 	}
    122 	else if ( rc == LDAP_COMPARE_FALSE ) {
    123 		*matchp = 1;
    124 		return LDAP_SUCCESS;
    125 	}
    126 	else {
    127 		return LDAP_INAPPROPRIATE_MATCHING;
    128 	}
    129 }
    130 
    131 int
    132 directoryComponentsMatch(
    133 	int *matchp,
    134 	slap_mask_t flags,
    135 	Syntax *syntax,
    136 	MatchingRule *mr,
    137 	struct berval *value,
    138 	void *assertedValue )
    139 {
    140 	/* Only for registration */
    141 	*matchp = 0;
    142 	return LDAP_SUCCESS;
    143 }
    144 
    145 int
    146 allComponentsMatch(
    147 	int *matchp,
    148 	slap_mask_t flags,
    149 	Syntax *syntax,
    150 	MatchingRule *mr,
    151 	struct berval *value,
    152 	void *assertedValue )
    153 {
    154 	/* Only for registration */
    155 	*matchp = 0;
    156 	return LDAP_SUCCESS;
    157 }
    158 
    159 static int
    160 slapd_ber2cav( struct berval* bv, ComponentAssertionValue* cav )
    161 {
    162 	cav->cav_ptr = cav->cav_buf = bv->bv_val;
    163 	cav->cav_end = bv->bv_val + bv->bv_len;
    164 
    165 	return LDAP_SUCCESS;
    166 }
    167 
    168 ComponentReference*
    169 dup_comp_ref ( Operation* op, ComponentReference* cr )
    170 {
    171 	ComponentReference* dup_cr;
    172 	ComponentId* ci_curr;
    173 	ComponentId** ci_temp;
    174 
    175 	dup_cr = op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx );
    176 
    177 	dup_cr->cr_len = cr->cr_len;
    178 	dup_cr->cr_string = cr->cr_string;
    179 
    180 	ci_temp = &dup_cr->cr_list;
    181 	ci_curr = cr->cr_list;
    182 
    183 	for ( ; ci_curr != NULL ;
    184 		ci_curr = ci_curr->ci_next, ci_temp = &(*ci_temp)->ci_next )
    185 	{
    186 		*ci_temp = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx );
    187 		if ( !*ci_temp ) return NULL;
    188 		**ci_temp = *ci_curr;
    189 	}
    190 
    191 	dup_cr->cr_curr = dup_cr->cr_list;
    192 
    193 	return dup_cr;
    194 }
    195 
    196 static int
    197 dup_comp_filter_list (
    198 	Operation *op,
    199 	struct berval *bv,
    200 	ComponentFilter* in_f,
    201 	ComponentFilter** out_f )
    202 {
    203 	ComponentFilter **new, *f;
    204 	int		rc;
    205 
    206 	new = out_f;
    207 	for ( f = in_f; f != NULL; f = f->cf_next ) {
    208 		rc = dup_comp_filter( op, bv, f, new );
    209 		if ( rc != LDAP_SUCCESS ) {
    210 			return rc;
    211 		}
    212 		new = &(*new)->cf_next;
    213 	}
    214 	return LDAP_SUCCESS;
    215 }
    216 
    217 int
    218 get_len_of_next_assert_value ( struct berval* bv, char separator )
    219 {
    220 	ber_len_t i = 0;
    221 	while (1) {
    222 		if ( (bv->bv_val[ i ] == separator) || ( i >= bv->bv_len) )
    223 			break;
    224 		i++;
    225 	}
    226 	bv->bv_val += (i + 1);
    227 	bv->bv_len -= (i + 1);
    228 	return i;
    229 }
    230 
    231 int
    232 dup_comp_filter_item (
    233 	Operation *op,
    234 	struct berval* assert_bv,
    235 	ComponentAssertion* in_ca,
    236 	ComponentAssertion** out_ca )
    237 {
    238 	int len;
    239 
    240 	if ( !in_ca->ca_comp_ref ) return SLAPD_DISCONNECT;
    241 
    242 	*out_ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
    243 	if ( !(*out_ca) ) return LDAP_NO_MEMORY;
    244 
    245 	(*out_ca)->ca_comp_data.cd_tree = NULL;
    246 	(*out_ca)->ca_comp_data.cd_mem_op = NULL;
    247 
    248 	(*out_ca)->ca_comp_ref = dup_comp_ref ( op, in_ca->ca_comp_ref );
    249 	(*out_ca)->ca_use_def = 0;
    250 	(*out_ca)->ca_ma_rule = in_ca->ca_ma_rule;
    251 
    252 	(*out_ca)->ca_ma_value.bv_val = assert_bv->bv_val;
    253 	len = get_len_of_next_assert_value ( assert_bv, '$' );
    254 	if ( len <= 0 ) return SLAPD_DISCONNECT;
    255 	(*out_ca)->ca_ma_value.bv_len = len;
    256 
    257 	return LDAP_SUCCESS;
    258 }
    259 
    260 int
    261 dup_comp_filter (
    262 	Operation* op,
    263 	struct berval *bv,
    264 	ComponentFilter *in_f,
    265 	ComponentFilter **out_f )
    266 {
    267 	int	rc;
    268 	ComponentFilter dup_f = {0};
    269 
    270 	if ( !in_f ) return LDAP_PROTOCOL_ERROR;
    271 
    272 	switch ( in_f->cf_choice ) {
    273 	case LDAP_COMP_FILTER_AND:
    274 		rc = dup_comp_filter_list( op, bv, in_f->cf_and, &dup_f.cf_and);
    275 		dup_f.cf_choice = LDAP_COMP_FILTER_AND;
    276 		break;
    277 	case LDAP_COMP_FILTER_OR:
    278 		rc = dup_comp_filter_list( op, bv, in_f->cf_or, &dup_f.cf_or);
    279 		dup_f.cf_choice = LDAP_COMP_FILTER_OR;
    280 		break;
    281 	case LDAP_COMP_FILTER_NOT:
    282 		rc = dup_comp_filter( op, bv, in_f->cf_not, &dup_f.cf_not);
    283 		dup_f.cf_choice = LDAP_COMP_FILTER_NOT;
    284 		break;
    285 	case LDAP_COMP_FILTER_ITEM:
    286 		rc = dup_comp_filter_item( op, bv, in_f->cf_ca ,&dup_f.cf_ca );
    287 		dup_f.cf_choice = LDAP_COMP_FILTER_ITEM;
    288 		break;
    289 	default:
    290 		rc = LDAP_PROTOCOL_ERROR;
    291 	}
    292 
    293 	if ( rc == LDAP_SUCCESS ) {
    294 		*out_f = op->o_tmpalloc( sizeof(dup_f), op->o_tmpmemctx );
    295 		**out_f = dup_f;
    296 	}
    297 
    298 	return( rc );
    299 }
    300 
    301 int
    302 get_aliased_filter_aa ( Operation* op, AttributeAssertion* a_assert, AttributeAliasing* aa, const char** text )
    303 {
    304 	struct berval assert_bv;
    305 
    306 	Debug( LDAP_DEBUG_FILTER, "get_aliased_filter\n" );
    307 
    308 	if ( !aa->aa_cf  )
    309 		return LDAP_PROTOCOL_ERROR;
    310 
    311 	assert_bv = a_assert->aa_value;
    312 	/*
    313 	 * Duplicate aa->aa_cf to ma->ma_cf by replacing the
    314 	 * the component assertion value in assert_bv
    315 	 * Multiple values may be separated with '$'
    316 	 */
    317 	return dup_comp_filter ( op, &assert_bv, aa->aa_cf, &a_assert->aa_cf );
    318 }
    319 
    320 int
    321 get_aliased_filter( Operation* op,
    322 	MatchingRuleAssertion* ma, AttributeAliasing* aa,
    323 	const char** text )
    324 {
    325 	struct berval assert_bv;
    326 
    327 	Debug( LDAP_DEBUG_FILTER, "get_aliased_filter\n" );
    328 
    329 	if ( !aa->aa_cf  ) return LDAP_PROTOCOL_ERROR;
    330 
    331 	assert_bv = ma->ma_value;
    332 	/* Attribute Description is replaced with aliased one */
    333 	ma->ma_desc = aa->aa_aliased_ad;
    334 	ma->ma_rule = aa->aa_mr;
    335 	/*
    336 	 * Duplicate aa->aa_cf to ma->ma_cf by replacing the
    337 	 * the component assertion value in assert_bv
    338 	 * Multiple values may be separated with '$'
    339 	 */
    340 	return dup_comp_filter ( op, &assert_bv, aa->aa_cf, &ma->ma_cf );
    341 }
    342 
    343 int
    344 get_comp_filter( Operation* op, struct berval* bv,
    345 	ComponentFilter** filt, const char **text )
    346 {
    347 	ComponentAssertionValue cav;
    348 	int rc;
    349 
    350 	Debug( LDAP_DEBUG_FILTER, "get_comp_filter\n" );
    351 	if ( (rc = slapd_ber2cav(bv, &cav) ) != LDAP_SUCCESS ) {
    352 		return rc;
    353 	}
    354 	rc = parse_comp_filter( op, &cav, filt, text );
    355 	/* bv->bv_val = cav.cav_ptr; */
    356 
    357 	return rc;
    358 }
    359 
    360 static void
    361 eat_whsp( ComponentAssertionValue* cav )
    362 {
    363 	for ( ; ( *cav->cav_ptr == ' ' ) && ( cav->cav_ptr < cav->cav_end ) ; ) {
    364 		cav->cav_ptr++;
    365 	}
    366 }
    367 
    368 static int
    369 cav_cur_len( ComponentAssertionValue* cav )
    370 {
    371 	return cav->cav_end - cav->cav_ptr;
    372 }
    373 
    374 static ber_tag_t
    375 comp_first_element( ComponentAssertionValue* cav )
    376 {
    377 	eat_whsp( cav );
    378 	if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
    379 		return LDAP_COMP_FILTER_ITEM;
    380 
    381 	} else if ( cav_cur_len( cav ) >= 7 &&
    382 		strncmp( cav->cav_ptr, "and", 3 ) == 0 )
    383 	{
    384 		return LDAP_COMP_FILTER_AND;
    385 
    386 	} else if ( cav_cur_len( cav ) >= 6 &&
    387 		strncmp( cav->cav_ptr, "or" , 2 ) == 0 )
    388 	{
    389 		return LDAP_COMP_FILTER_OR;
    390 
    391 	} else if ( cav_cur_len( cav ) >= 7 &&
    392 		strncmp( cav->cav_ptr, "not", 3 ) == 0 )
    393 	{
    394 		return LDAP_COMP_FILTER_NOT;
    395 
    396 	} else {
    397 		return LDAP_COMP_FILTER_UNDEFINED;
    398 	}
    399 }
    400 
    401 static ber_tag_t
    402 comp_next_element( ComponentAssertionValue* cav )
    403 {
    404 	eat_whsp( cav );
    405 	if ( *(cav->cav_ptr) == ',' ) {
    406 		/* move pointer to the next CA */
    407 		cav->cav_ptr++;
    408 		return comp_first_element( cav );
    409 	}
    410 	else return LDAP_COMP_FILTER_UNDEFINED;
    411 }
    412 
    413 static int
    414 get_comp_filter_list( Operation *op, ComponentAssertionValue *cav,
    415 	ComponentFilter** f, const char** text )
    416 {
    417 	ComponentFilter **new;
    418 	int		err;
    419 	ber_tag_t	tag;
    420 
    421 	Debug( LDAP_DEBUG_FILTER, "get_comp_filter_list\n" );
    422 	new = f;
    423 	for ( tag = comp_first_element( cav );
    424 		tag != LDAP_COMP_FILTER_UNDEFINED;
    425 		tag = comp_next_element( cav ) )
    426 	{
    427 		err = parse_comp_filter( op, cav, new, text );
    428 		if ( err != LDAP_SUCCESS ) return ( err );
    429 		new = &(*new)->cf_next;
    430 	}
    431 	*new = NULL;
    432 
    433 	return( LDAP_SUCCESS );
    434 }
    435 
    436 static int
    437 get_componentId( Operation *op, ComponentAssertionValue* cav,
    438 	ComponentId ** cid, const char** text )
    439 {
    440 	ber_tag_t type;
    441 	ComponentId _cid;
    442 	int len;
    443 
    444 	type = peek_componentId_type( cav );
    445 
    446 	Debug( LDAP_DEBUG_FILTER, "get_compId [%lu]\n",
    447 		(unsigned long) type );
    448 	len = 0;
    449 	_cid.ci_type = type;
    450 	_cid.ci_next = NULL;
    451 	switch ( type ) {
    452 	case LDAP_COMPREF_IDENTIFIER :
    453 		_cid.ci_val.ci_identifier.bv_val = cav->cav_ptr;
    454 		for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
    455 			cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
    456 		_cid.ci_val.ci_identifier.bv_len = len;
    457 		cav->cav_ptr += len;
    458 		break;
    459 	case LDAP_COMPREF_FROM_BEGINNING :
    460 		for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
    461 			cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
    462 		_cid.ci_val.ci_from_beginning = strtol( cav->cav_ptr, NULL, 0 );
    463 		cav->cav_ptr += len;
    464 		break;
    465 	case LDAP_COMPREF_FROM_END :
    466 		for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
    467 			cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
    468 		_cid.ci_val.ci_from_end = strtol( cav->cav_ptr, NULL, 0 );
    469 		cav->cav_ptr += len;
    470 		break;
    471 	case LDAP_COMPREF_COUNT :
    472 		_cid.ci_val.ci_count = 0;
    473 		cav->cav_ptr++;
    474 		break;
    475 	case LDAP_COMPREF_CONTENT :
    476 		_cid.ci_val.ci_content = 1;
    477 		cav->cav_ptr += strlen("content");
    478 		break;
    479 	case LDAP_COMPREF_SELECT :
    480 		if ( cav->cav_ptr[len] != '(' ) return LDAP_COMPREF_UNDEFINED;
    481 		for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
    482 	  	      cav->cav_ptr[len] != '\"' && cav->cav_ptr[len] != ')'
    483 			; len++ );
    484 		_cid.ci_val.ci_select_value.bv_val = cav->cav_ptr + 1;
    485 		_cid.ci_val.ci_select_value.bv_len = len - 1 ;
    486 		cav->cav_ptr += len + 1;
    487 		break;
    488 	case LDAP_COMPREF_ALL :
    489 		_cid.ci_val.ci_all = '*';
    490 		cav->cav_ptr++;
    491 		break;
    492 	default :
    493 		return LDAP_COMPREF_UNDEFINED;
    494 	}
    495 
    496 	if ( op ) {
    497 		*cid = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx );
    498 	} else {
    499 		*cid = SLAP_MALLOC( sizeof( ComponentId ) );
    500 	}
    501 	if (*cid == NULL) {
    502 		return LDAP_NO_MEMORY;
    503 	}
    504 	**cid = _cid;
    505 	return LDAP_SUCCESS;
    506 }
    507 
    508 static int
    509 peek_componentId_type( ComponentAssertionValue* cav )
    510 {
    511 	eat_whsp( cav );
    512 
    513 	if ( cav->cav_ptr[0] == '-' ) {
    514 		return LDAP_COMPREF_FROM_END;
    515 
    516 	} else if ( cav->cav_ptr[0] == '(' ) {
    517 		return LDAP_COMPREF_SELECT;
    518 
    519 	} else if ( cav->cav_ptr[0] == '*' ) {
    520 		return LDAP_COMPREF_ALL;
    521 
    522 	} else if ( cav->cav_ptr[0] == '0' ) {
    523 		return LDAP_COMPREF_COUNT;
    524 
    525 	} else if ( cav->cav_ptr[0] > '0' && cav->cav_ptr[0] <= '9' ) {
    526 		return LDAP_COMPREF_FROM_BEGINNING;
    527 
    528 	} else if ( (cav->cav_end - cav->cav_ptr) >= 7 &&
    529 		strncmp(cav->cav_ptr,"content",7) == 0 )
    530 	{
    531 		return LDAP_COMPREF_CONTENT;
    532 	} else if ( (cav->cav_ptr[0] >= 'a' && cav->cav_ptr[0] <= 'z') ||
    533 			(cav->cav_ptr[0] >= 'A' && cav->cav_ptr[0] <= 'Z') )
    534 	{
    535 		return LDAP_COMPREF_IDENTIFIER;
    536 	}
    537 
    538 	return LDAP_COMPREF_UNDEFINED;
    539 }
    540 
    541 static ber_tag_t
    542 comp_next_id( ComponentAssertionValue* cav )
    543 {
    544 	if ( *(cav->cav_ptr) == '.' ) {
    545 		cav->cav_ptr++;
    546 		return LDAP_COMPREF_DEFINED;
    547 	}
    548 
    549 	return LDAP_COMPREF_UNDEFINED;
    550 }
    551 
    552 
    553 
    554 static int
    555 get_component_reference(
    556 	Operation *op,
    557 	ComponentAssertionValue* cav,
    558 	ComponentReference** cr,
    559 	const char** text )
    560 {
    561 	int rc, count = 0;
    562 	ber_int_t type;
    563 	ComponentReference* ca_comp_ref;
    564 	ComponentId** cr_list;
    565 	char* start, *end;
    566 
    567 	eat_whsp( cav );
    568 
    569 	start = cav->cav_ptr;
    570 	if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS ) return rc;
    571 	if ( op ) {
    572 		ca_comp_ref = op->o_tmpalloc( sizeof( ComponentReference ),
    573 			op->o_tmpmemctx );
    574 	} else {
    575 		ca_comp_ref = SLAP_MALLOC( sizeof( ComponentReference ) );
    576 	}
    577 
    578 	if ( !ca_comp_ref ) return LDAP_NO_MEMORY;
    579 
    580 	cr_list = &ca_comp_ref->cr_list;
    581 
    582 	for ( type = peek_componentId_type( cav ) ; type != LDAP_COMPREF_UNDEFINED
    583 		; type = comp_next_id( cav ), count++ )
    584 	{
    585 		rc = get_componentId( op, cav, cr_list, text );
    586 		if ( rc == LDAP_SUCCESS ) {
    587 			if ( count == 0 ) ca_comp_ref->cr_curr = ca_comp_ref->cr_list;
    588 			cr_list = &(*cr_list)->ci_next;
    589 
    590 		} else if ( rc == LDAP_COMPREF_UNDEFINED ) {
    591 			if ( op ) {
    592 				op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
    593 			} else {
    594 				free( ca_comp_ref );
    595 			}
    596 			return rc;
    597 		}
    598 	}
    599 	ca_comp_ref->cr_len = count;
    600 	end = cav->cav_ptr;
    601 	if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS ) {
    602 		if ( op ) {
    603 			op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
    604 		} else {
    605 			free( ca_comp_ref );
    606 		}
    607 		return rc;
    608 	}
    609 
    610 	*cr = ca_comp_ref;
    611 	**cr = *ca_comp_ref;
    612 
    613 	(*cr)->cr_string.bv_val = start;
    614 	(*cr)->cr_string.bv_len = end - start + 1;
    615 
    616 	return rc;
    617 }
    618 
    619 int
    620 insert_component_reference(
    621 	ComponentReference *cr,
    622 	ComponentReference** cr_list)
    623 {
    624 	if ( !cr ) return LDAP_PARAM_ERROR;
    625 
    626 	if ( !(*cr_list) ) {
    627 		*cr_list = cr;
    628 		cr->cr_next = NULL;
    629 	} else {
    630 		cr->cr_next = *cr_list;
    631 		*cr_list = cr;
    632 	}
    633 	return LDAP_SUCCESS;
    634 }
    635 
    636 /*
    637  * If there is '.' in the name of a given attribute
    638  * the first '.'- following characters are considered
    639  * as a component reference of the attribute
    640  * EX) userCertificate.toBeSigned.serialNumber
    641  * attribute : userCertificate
    642  * component reference : toBeSigned.serialNumber
    643  */
    644 int
    645 is_component_reference( char* attr ) {
    646 	int i;
    647 	for ( i=0; attr[i] != '\0' ; i++ ) {
    648 		if ( attr[i] == '.' ) return (1);
    649 	}
    650 	return (0);
    651 }
    652 
    653 int
    654 extract_component_reference(
    655 	char* attr,
    656 	ComponentReference** cr )
    657 {
    658 	int i, rc;
    659 	char* cr_ptr;
    660 	int cr_len;
    661 	ComponentAssertionValue cav;
    662 	char text[1][128];
    663 
    664 	for ( i=0; attr[i] != '\0' ; i++ ) {
    665 		if ( attr[i] == '.' ) break;
    666 	}
    667 
    668 	if (attr[i] != '.' ) return LDAP_PARAM_ERROR;
    669 	attr[i] = '\0';
    670 
    671 	cr_ptr = attr + i + 1 ;
    672 	cr_len = strlen ( cr_ptr );
    673 	if ( cr_len <= 0 ) return LDAP_PARAM_ERROR;
    674 
    675 	/* enclosed between double quotes*/
    676 	cav.cav_ptr = cav.cav_buf = ch_malloc (cr_len+2);
    677 	memcpy( cav.cav_buf+1, cr_ptr, cr_len );
    678 	cav.cav_buf[0] = '"';
    679 	cav.cav_buf[cr_len+1] = '"';
    680 	cav.cav_end = cr_ptr + cr_len + 2;
    681 
    682 	rc = get_component_reference ( NULL, &cav, cr, (const char**)text );
    683 	if ( rc != LDAP_SUCCESS ) return rc;
    684 	(*cr)->cr_string.bv_val = cav.cav_buf;
    685 	(*cr)->cr_string.bv_len = cr_len + 2;
    686 
    687 	return LDAP_SUCCESS;
    688 }
    689 
    690 static int
    691 get_ca_use_default( Operation *op,
    692 	ComponentAssertionValue* cav,
    693 	int* ca_use_def, const char**  text )
    694 {
    695 	strip_cav_str( cav, "useDefaultValues" );
    696 
    697 	if ( peek_cav_str( cav, "TRUE" ) == LDAP_SUCCESS ) {
    698 		strip_cav_str( cav, "TRUE" );
    699 		*ca_use_def = 1;
    700 
    701 	} else if ( peek_cav_str( cav, "FALSE" ) == LDAP_SUCCESS ) {
    702 		strip_cav_str( cav, "FALSE" );
    703 		*ca_use_def = 0;
    704 
    705 	} else {
    706 		return LDAP_INVALID_SYNTAX;
    707 	}
    708 
    709 	return LDAP_SUCCESS;
    710 }
    711 
    712 static int
    713 get_matching_rule( Operation *op, ComponentAssertionValue* cav,
    714 		MatchingRule** mr, const char**  text )
    715 {
    716 	int count = 0;
    717 	struct berval rule_text = { 0L, NULL };
    718 
    719 	eat_whsp( cav );
    720 
    721 	for ( ; ; count++ ) {
    722 		if ( cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == ',' ||
    723 			cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == '{' ||
    724 			cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '\n' )
    725 		{
    726 			break;
    727 		}
    728 	}
    729 
    730 	if ( count == 0 ) {
    731 		*text = "component matching rule not recognized";
    732 		return LDAP_INAPPROPRIATE_MATCHING;
    733 	}
    734 
    735 	rule_text.bv_len = count;
    736 	rule_text.bv_val = cav->cav_ptr;
    737 	*mr = mr_bvfind( &rule_text );
    738 	cav->cav_ptr += count;
    739 	Debug( LDAP_DEBUG_FILTER, "get_matching_rule: %s\n",
    740 		(*mr)->smr_mrule.mr_oid );
    741 	if ( *mr == NULL ) {
    742 		*text = "component matching rule not recognized";
    743 		return LDAP_INAPPROPRIATE_MATCHING;
    744 	}
    745 	return LDAP_SUCCESS;
    746 }
    747 
    748 static int
    749 get_GSER_value( ComponentAssertionValue* cav, struct berval* bv )
    750 {
    751 	int count, sequent_dquote, unclosed_brace, succeed;
    752 
    753 	eat_whsp( cav );
    754 	/*
    755 	 * Four cases of GSER <Values>
    756 	 * 1) "..." :
    757 	 *	StringVal, GeneralizedTimeVal, UTCTimeVal, ObjectDescriptorVal
    758 	 * 2) '...'B or '...'H :
    759 	 *	BitStringVal, OctetStringVal
    760 	 * 3) {...} :
    761 	 *	SEQUENCE, SEQUENCEOF, SETOF, SET, CHOICE
    762 	 * 4) Between two white spaces
    763 	 *	INTEGER, BOOLEAN, NULL,ENUMERATE, etc
    764 	 */
    765 
    766 	succeed = 0;
    767 	if ( cav->cav_ptr[0] == '"' ) {
    768 		for( count = 1, sequent_dquote = 0 ; ; count++ ) {
    769 			/* In order to find escaped double quote */
    770 			if ( cav->cav_ptr[count] == '"' ) sequent_dquote++;
    771 			else sequent_dquote = 0;
    772 
    773 			if ( cav->cav_ptr[count] == '\0' ||
    774 				(cav->cav_ptr+count) > cav->cav_end )
    775 			{
    776 				break;
    777 			}
    778 
    779 			if ( ( cav->cav_ptr[count] == '"' &&
    780 				cav->cav_ptr[count-1] != '"') ||
    781 				( sequent_dquote > 2 && (sequent_dquote%2) == 1 ) )
    782 			{
    783 				succeed = 1;
    784 				break;
    785 			}
    786 		}
    787 
    788 		if ( !succeed || cav->cav_ptr[count] != '"' ) {
    789 			return LDAP_FILTER_ERROR;
    790 		}
    791 
    792 		bv->bv_val = cav->cav_ptr + 1;
    793 		bv->bv_len = count - 1; /* exclude '"' */
    794 
    795 	} else if ( cav->cav_ptr[0] == '\'' ) {
    796 		for( count = 1 ; ; count++ ) {
    797 			if ( cav->cav_ptr[count] == '\0' ||
    798 				(cav->cav_ptr+count) > cav->cav_end )
    799 			{
    800 				break;
    801 			}
    802 			if ((cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'B') ||
    803 				(cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'H') )
    804 			{
    805 				succeed = 1;
    806 				break;
    807 			}
    808 		}
    809 
    810 		if ( !succeed ||
    811 			!(cav->cav_ptr[count] == 'H' || cav->cav_ptr[count] == 'B') )
    812 		{
    813 			return LDAP_FILTER_ERROR;
    814 		}
    815 
    816 		bv->bv_val = cav->cav_ptr + 1;/*the next to '"' */
    817 		bv->bv_len = count - 2;/* exclude "'H" or "'B" */
    818 
    819 	} else if ( cav->cav_ptr[0] == '{' ) {
    820 		for( count = 1, unclosed_brace = 1 ; ; count++ ) {
    821 			if ( cav->cav_ptr[count] == '{' ) unclosed_brace++;
    822 			if ( cav->cav_ptr[count] == '}' ) unclosed_brace--;
    823 
    824 			if ( cav->cav_ptr[count] == '\0' ||
    825 				(cav->cav_ptr+count) > cav->cav_end )
    826 			{
    827 				break;
    828 			}
    829 			if ( unclosed_brace == 0 ) {
    830 				succeed = 1;
    831 				break;
    832 			}
    833 		}
    834 
    835 		if ( !succeed || cav->cav_ptr[count] != '}' ) return LDAP_FILTER_ERROR;
    836 
    837 		bv->bv_val = cav->cav_ptr + 1;/*the next to '"' */
    838 		bv->bv_len = count - 1;/* exclude  "'B" */
    839 
    840 	} else {
    841 		succeed = 1;
    842 		/*Find  following white space where the value is ended*/
    843 		for( count = 1 ; ; count++ ) {
    844 			if ( cav->cav_ptr[count] == '\0' ||
    845 				cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == '}' ||
    846 				cav->cav_ptr[count] == '{' ||
    847 				(cav->cav_ptr+count) > cav->cav_end )
    848 			{
    849 				break;
    850 			}
    851 		}
    852 		bv->bv_val = cav->cav_ptr;
    853 		bv->bv_len = count;
    854 	}
    855 
    856 	cav->cav_ptr += bv->bv_len;
    857 	return LDAP_SUCCESS;
    858 }
    859 
    860 static int
    861 get_matching_value( Operation *op, ComponentAssertion* ca,
    862 	ComponentAssertionValue* cav, struct berval* bv,
    863 	const char**  text )
    864 {
    865 	if ( !(ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT)) ) {
    866 		if ( get_GSER_value( cav, bv ) != LDAP_SUCCESS ) {
    867 			return LDAP_FILTER_ERROR;
    868 		}
    869 
    870 	} else {
    871 		/* embedded componentFilterMatch Description */
    872 		bv->bv_val = cav->cav_ptr;
    873 		bv->bv_len = cav_cur_len( cav );
    874 	}
    875 
    876 	return LDAP_SUCCESS;
    877 }
    878 
    879 /* Don't move the position pointer, just peek given string */
    880 static int
    881 peek_cav_str( ComponentAssertionValue* cav, char* str )
    882 {
    883 	eat_whsp( cav );
    884 	if ( cav_cur_len( cav ) >= strlen( str ) &&
    885 		strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 )
    886 	{
    887 		return LDAP_SUCCESS;
    888 	}
    889 
    890 	return LDAP_INVALID_SYNTAX;
    891 }
    892 
    893 static int
    894 strip_cav_str( ComponentAssertionValue* cav, char* str)
    895 {
    896 	eat_whsp( cav );
    897 	if ( cav_cur_len( cav ) >= strlen( str ) &&
    898 		strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 )
    899 	{
    900 		cav->cav_ptr += strlen( str );
    901 		return LDAP_SUCCESS;
    902 	}
    903 
    904 	return LDAP_INVALID_SYNTAX;
    905 }
    906 
    907 /*
    908  * TAG : "item", "and", "or", "not"
    909  */
    910 static ber_tag_t
    911 strip_cav_tag( ComponentAssertionValue* cav )
    912 {
    913 	int rc;
    914 
    915 	eat_whsp( cav );
    916 	if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
    917 		if ( strip_cav_str( cav , "item:" ))
    918 			goto fail;
    919 		return LDAP_COMP_FILTER_ITEM;
    920 
    921 	} else if ( cav_cur_len( cav ) >= 7 &&
    922 		strncmp( cav->cav_ptr, "and", 3 ) == 0 )
    923 	{
    924 		if ( strip_cav_str( cav , "and:" ))
    925 			goto fail;
    926 		return LDAP_COMP_FILTER_AND;
    927 
    928 	} else if ( cav_cur_len( cav ) >= 6 &&
    929 		strncmp( cav->cav_ptr, "or" , 2 ) == 0 )
    930 	{
    931 		if ( strip_cav_str( cav , "or:" ))
    932 			goto fail;
    933 		return LDAP_COMP_FILTER_OR;
    934 
    935 	} else if ( cav_cur_len( cav ) >= 7 &&
    936 		strncmp( cav->cav_ptr, "not", 3 ) == 0 )
    937 	{
    938 		if ( strip_cav_str( cav , "not:" ))
    939 			goto fail;
    940 		return LDAP_COMP_FILTER_NOT;
    941 	}
    942 
    943 fail:
    944 	return LBER_ERROR;
    945 }
    946 
    947 /*
    948  * when encoding, "item" is denotation of ComponentAssertion
    949  * ComponentAssertion :: SEQUENCE {
    950  *	component		ComponentReference (SIZE(1..MAX)) OPTIONAL,
    951  *	useDefaultValues	BOOLEAN DEFAULT TRUE,
    952  *	rule			MATCHING-RULE.&id,
    953  *	value			MATCHING-RULE.&AssertionType }
    954  */
    955 static int
    956 get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca,
    957 		const char** text )
    958 {
    959 	int rc, freeval = 0;
    960 	ComponentAssertion* _ca;
    961 	struct berval value;
    962 	MatchingRule* mr;
    963 
    964 	Debug( LDAP_DEBUG_FILTER, "get_item \n" );
    965 	if ( op )
    966 		_ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
    967 	else
    968 		_ca = SLAP_MALLOC( sizeof( ComponentAssertion ) );
    969 
    970 	if ( !_ca ) return LDAP_NO_MEMORY;
    971 
    972 	_ca->ca_comp_data.cd_tree = NULL;
    973 	_ca->ca_comp_data.cd_mem_op = NULL;
    974 	BER_BVZERO( &_ca->ca_ma_value );
    975 
    976 	rc = peek_cav_str( cav, "component" );
    977 	if ( rc == LDAP_SUCCESS ) {
    978 		strip_cav_str( cav, "component" );
    979 		rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text );
    980 		if ( rc != LDAP_SUCCESS ) {
    981 			rc = LDAP_INVALID_SYNTAX;
    982 fail:
    983 			if ( freeval )
    984 				op->o_tmpfree( _ca->ca_ma_value.bv_val, op->o_tmpmemctx );
    985 			if ( op )
    986 				op->o_tmpfree( _ca, op->o_tmpmemctx );
    987 			else
    988 				free( _ca );
    989 			return rc;
    990 		}
    991 		if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
    992 			goto fail;
    993 	} else {
    994 		_ca->ca_comp_ref = NULL;
    995 	}
    996 
    997 	rc = peek_cav_str( cav, "useDefaultValues");
    998 	if ( rc == LDAP_SUCCESS ) {
    999 		rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text );
   1000 		if ( rc != LDAP_SUCCESS ) {
   1001 			rc = LDAP_INVALID_SYNTAX;
   1002 			goto fail;
   1003 		}
   1004 		if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
   1005 			goto fail;
   1006 	}
   1007 	else _ca->ca_use_def = 1;
   1008 
   1009 	if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS &&
   1010 		get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) {
   1011 		rc = LDAP_INAPPROPRIATE_MATCHING;
   1012 		goto fail;
   1013 	}
   1014 
   1015 	if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
   1016 		goto fail;
   1017 	if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS &&
   1018 		get_matching_value( op, _ca, cav,&value ,text ) == LDAP_SUCCESS )) {
   1019 		rc = LDAP_INVALID_SYNTAX;
   1020 		goto fail;
   1021 	}
   1022 
   1023 	/*
   1024 	 * Normalize the value of this component assertion when the matching
   1025 	 * rule is one of existing matching rules
   1026 	 */
   1027 	mr = _ca->ca_ma_rule;
   1028 	if ( op && !(mr->smr_usage & (SLAP_MR_COMPONENT)) && mr->smr_normalize ) {
   1029 
   1030 		value.bv_val[value.bv_len] = '\0';
   1031 		rc = mr->smr_normalize (
   1032 			SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
   1033 			NULL, mr,
   1034 			&value, &_ca->ca_ma_value, op->o_tmpmemctx );
   1035 		if ( rc != LDAP_SUCCESS )
   1036 			goto fail;
   1037 		freeval = 1;
   1038 	}
   1039 	else
   1040 		_ca->ca_ma_value = value;
   1041 	/*
   1042 	 * Validate the value of this component assertion
   1043 	 */
   1044 	if ( op && mr->smr_syntax->ssyn_validate( mr->smr_syntax, &_ca->ca_ma_value) != LDAP_SUCCESS ) {
   1045 		rc = LDAP_INVALID_SYNTAX;
   1046 		goto fail;
   1047 	}
   1048 
   1049 
   1050 	/* componentFilterMatch contains componentFilterMatch in it */
   1051 	if ( strcmp(_ca->ca_ma_rule->smr_mrule.mr_oid, OID_COMP_FILTER_MATCH ) == 0) {
   1052 		struct berval bv;
   1053 		bv.bv_val = cav->cav_ptr;
   1054 		bv.bv_len = cav_cur_len( cav );
   1055 		rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text );
   1056 		if ( rc != LDAP_SUCCESS )
   1057 			goto fail;
   1058 		cav->cav_ptr = bv.bv_val;
   1059 		assert( cav->cav_end >= bv.bv_val );
   1060 	}
   1061 
   1062 	*ca = _ca;
   1063 	return LDAP_SUCCESS;
   1064 }
   1065 
   1066 static int
   1067 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
   1068 				ComponentFilter** filt, const char** text )
   1069 {
   1070 	/*
   1071 	 * A component filter looks like this coming in:
   1072 	 *	Filter ::= CHOICE {
   1073 	 *		item	[0]	ComponentAssertion,
   1074 	 *		and	[1]	SEQUENCE OF ComponentFilter,
   1075 	 *		or	[2]	SEQUENCE OF ComponentFilter,
   1076 	 *		not	[3]	ComponentFilter,
   1077 	 *	}
   1078 	 */
   1079 
   1080 	ber_tag_t	tag;
   1081 	int		err = LDAP_SUCCESS;
   1082 	ComponentFilter	f;
   1083 	/* TAG : item, and, or, not in RFC 4515 */
   1084 	tag = strip_cav_tag( cav );
   1085 
   1086 	if ( tag == LBER_ERROR ) {
   1087 		*text = "error decoding comp filter";
   1088 		return LDAP_PROTOCOL_ERROR;
   1089 	}
   1090 
   1091 	if ( tag != LDAP_COMP_FILTER_NOT ) {
   1092 		err = strip_cav_str( cav, "{");
   1093 		if ( err )
   1094 			goto invalid;
   1095 	}
   1096 
   1097 	f.cf_next = NULL;
   1098 	f.cf_choice = tag;
   1099 
   1100 	switch ( f.cf_choice ) {
   1101 	case LDAP_COMP_FILTER_AND:
   1102 	Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_AND\n" );
   1103 		err = get_comp_filter_list( op, cav, &f.cf_and, text );
   1104 		if ( err != LDAP_SUCCESS ) {
   1105 			break;
   1106 		}
   1107 		if ( f.cf_and == NULL ) {
   1108 			f.cf_choice = SLAPD_FILTER_COMPUTED;
   1109 			f.cf_result = LDAP_COMPARE_TRUE;
   1110 		}
   1111 		break;
   1112 
   1113 	case LDAP_COMP_FILTER_OR:
   1114 	Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_OR\n" );
   1115 		err = get_comp_filter_list( op, cav, &f.cf_or, text );
   1116 		if ( err != LDAP_SUCCESS ) {
   1117 			break;
   1118 		}
   1119 		if ( f.cf_or == NULL ) {
   1120 			f.cf_choice = SLAPD_FILTER_COMPUTED;
   1121 			f.cf_result = LDAP_COMPARE_FALSE;
   1122 		}
   1123 		/* no assert - list could be empty */
   1124 		break;
   1125 
   1126 	case LDAP_COMP_FILTER_NOT:
   1127 	Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_NOT\n" );
   1128 		err = parse_comp_filter( op, cav, &f.cf_not, text );
   1129 		if ( err != LDAP_SUCCESS ) {
   1130 			break;
   1131 		}
   1132 
   1133 		assert( f.cf_not != NULL );
   1134 		if ( f.cf_not->cf_choice == SLAPD_FILTER_COMPUTED ) {
   1135 			int fresult = f.cf_not->cf_result;
   1136 			f.cf_choice = SLAPD_FILTER_COMPUTED;
   1137 			op->o_tmpfree( f.cf_not, op->o_tmpmemctx );
   1138 			f.cf_not = NULL;
   1139 
   1140 			switch ( fresult ) {
   1141 			case LDAP_COMPARE_TRUE:
   1142 				f.cf_result = LDAP_COMPARE_FALSE;
   1143 				break;
   1144 			case LDAP_COMPARE_FALSE:
   1145 				f.cf_result = LDAP_COMPARE_TRUE;
   1146 				break;
   1147 			default: ;
   1148 				/* (!Undefined) is Undefined */
   1149 			}
   1150 		}
   1151 		break;
   1152 
   1153 	case LDAP_COMP_FILTER_ITEM:
   1154 	Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_ITEM\n" );
   1155 		err = get_item( op, cav, &f.cf_ca, text );
   1156 		if ( err != LDAP_SUCCESS ) {
   1157 			break;
   1158 		}
   1159 
   1160 		assert( f.cf_ca != NULL );
   1161 		break;
   1162 
   1163 	default:
   1164 		f.cf_choice = SLAPD_FILTER_COMPUTED;
   1165 		f.cf_result = SLAPD_COMPARE_UNDEFINED;
   1166 		break;
   1167 	}
   1168 
   1169 invalid:
   1170 	if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) {
   1171 		*text = "Component Filter Syntax Error";
   1172 		return err;
   1173 	}
   1174 
   1175 	if ( tag != LDAP_COMP_FILTER_NOT )
   1176 		err = strip_cav_str( cav, "}");
   1177 
   1178 	if ( err == LDAP_SUCCESS ) {
   1179 		if ( op ) {
   1180 			*filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx );
   1181 		} else {
   1182 			*filt = SLAP_MALLOC( sizeof(f) );
   1183 		}
   1184 		if ( *filt == NULL ) {
   1185 			return LDAP_NO_MEMORY;
   1186 		}
   1187 		**filt = f;
   1188 	}
   1189 
   1190 	return( err );
   1191 }
   1192 
   1193 static int
   1194 test_comp_filter_and(
   1195 	Syntax *syn,
   1196 	ComponentSyntaxInfo *a,
   1197 	ComponentFilter *flist )
   1198 {
   1199 	ComponentFilter *f;
   1200 	int rtn = LDAP_COMPARE_TRUE;
   1201 
   1202 	for ( f = flist ; f != NULL; f = f->cf_next ) {
   1203 		int rc = test_comp_filter( syn, a, f );
   1204 		if ( rc == LDAP_COMPARE_FALSE ) {
   1205 			rtn = rc;
   1206 			break;
   1207 		}
   1208 
   1209 		if ( rc != LDAP_COMPARE_TRUE ) {
   1210 			rtn = rc;
   1211 		}
   1212 	}
   1213 
   1214 	return rtn;
   1215 }
   1216 
   1217 static int
   1218 test_comp_filter_or(
   1219 	Syntax *syn,
   1220 	ComponentSyntaxInfo *a,
   1221 	ComponentFilter *flist )
   1222 {
   1223 	ComponentFilter *f;
   1224 	int rtn = LDAP_COMPARE_TRUE;
   1225 
   1226 	for ( f = flist ; f != NULL; f = f->cf_next ) {
   1227 		int rc = test_comp_filter( syn, a, f );
   1228 		if ( rc == LDAP_COMPARE_TRUE ) {
   1229 			rtn = rc;
   1230 			break;
   1231 		}
   1232 
   1233 		if ( rc != LDAP_COMPARE_FALSE ) {
   1234 			rtn = rc;
   1235 		}
   1236 	}
   1237 
   1238 	return rtn;
   1239 }
   1240 
   1241 int
   1242 csi_value_match( MatchingRule *mr, struct berval* bv_attr,
   1243 	struct berval* bv_assert )
   1244 {
   1245 	int rc;
   1246 	int match;
   1247 
   1248 	assert( mr != NULL );
   1249 	assert( !(mr->smr_usage & SLAP_MR_COMPONENT) );
   1250 
   1251 	if( !mr->smr_match ) return LDAP_INAPPROPRIATE_MATCHING;
   1252 
   1253 	rc = (mr->smr_match)( &match, 0, NULL /*ad->ad_type->sat_syntax*/,
   1254 		mr, bv_attr, bv_assert );
   1255 
   1256 	if ( rc != LDAP_SUCCESS ) return rc;
   1257 
   1258 	return match ? LDAP_COMPARE_FALSE : LDAP_COMPARE_TRUE;
   1259 }
   1260 
   1261 /*
   1262  * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE
   1263  */
   1264 static int
   1265 test_comp_filter_item(
   1266 	Syntax *syn,
   1267 	ComponentSyntaxInfo *csi_attr,
   1268 	ComponentAssertion *ca )
   1269 {
   1270 	int rc;
   1271 	void *attr_nm, *assert_nm;
   1272 
   1273 	if ( strcmp(ca->ca_ma_rule->smr_mrule.mr_oid,
   1274 		OID_COMP_FILTER_MATCH ) == 0 && ca->ca_cf ) {
   1275 		/* componentFilterMatch inside of componentFilterMatch */
   1276 		rc = test_comp_filter( syn, csi_attr, ca->ca_cf );
   1277 		return rc;
   1278 	}
   1279 
   1280 	/* Memory for storing will-be-extracted attribute values */
   1281 	attr_nm = nibble_mem_allocator ( 1024*4 , 1024 );
   1282 	if ( !attr_nm ) return LDAP_PROTOCOL_ERROR;
   1283 
   1284 	/* Memory for storing component assertion values */
   1285 	if( !ca->ca_comp_data.cd_mem_op ) {
   1286 		assert_nm = nibble_mem_allocator ( 256, 64 );
   1287 		if ( !assert_nm ) {
   1288 			nibble_mem_free ( attr_nm );
   1289 			return LDAP_PROTOCOL_ERROR;
   1290 		}
   1291 		ca->ca_comp_data.cd_mem_op = assert_nm;
   1292 
   1293 	} else {
   1294 		assert_nm = ca->ca_comp_data.cd_mem_op;
   1295 	}
   1296 
   1297 	/* component reference initialization */
   1298 	if ( ca->ca_comp_ref ) {
   1299 		ca->ca_comp_ref->cr_curr = ca->ca_comp_ref->cr_list;
   1300 	}
   1301 	rc = test_components( attr_nm, assert_nm, csi_attr, ca );
   1302 
   1303 	/* free memory used for storing extracted attribute value */
   1304 	nibble_mem_free ( attr_nm );
   1305 	return rc;
   1306 }
   1307 
   1308 static int
   1309 test_comp_filter(
   1310     Syntax *syn,
   1311     ComponentSyntaxInfo *a,
   1312     ComponentFilter *f )
   1313 {
   1314 	int	rc;
   1315 
   1316 	if ( !f ) return LDAP_PROTOCOL_ERROR;
   1317 
   1318 	Debug( LDAP_DEBUG_FILTER, "test_comp_filter\n" );
   1319 	switch ( f->cf_choice ) {
   1320 	case SLAPD_FILTER_COMPUTED:
   1321 		rc = f->cf_result;
   1322 		break;
   1323 	case LDAP_COMP_FILTER_AND:
   1324 		rc = test_comp_filter_and( syn, a, f->cf_and );
   1325 		break;
   1326 	case LDAP_COMP_FILTER_OR:
   1327 		rc = test_comp_filter_or( syn, a, f->cf_or );
   1328 		break;
   1329 	case LDAP_COMP_FILTER_NOT:
   1330 		rc = test_comp_filter( syn, a, f->cf_not );
   1331 
   1332 		switch ( rc ) {
   1333 		case LDAP_COMPARE_TRUE:
   1334 			rc = LDAP_COMPARE_FALSE;
   1335 			break;
   1336 		case LDAP_COMPARE_FALSE:
   1337 			rc = LDAP_COMPARE_TRUE;
   1338 			break;
   1339 		}
   1340 		break;
   1341 	case LDAP_COMP_FILTER_ITEM:
   1342 		rc = test_comp_filter_item( syn, a, f->cf_ca );
   1343 		break;
   1344 	default:
   1345 		rc = LDAP_PROTOCOL_ERROR;
   1346 	}
   1347 
   1348 	return( rc );
   1349 }
   1350 
   1351 static void
   1352 free_comp_filter_list( ComponentFilter* f )
   1353 {
   1354 	ComponentFilter* tmp;
   1355 	for ( tmp = f; tmp; tmp = tmp->cf_next ) {
   1356 		free_comp_filter( tmp );
   1357 	}
   1358 }
   1359 
   1360 static void
   1361 free_comp_filter( ComponentFilter* f )
   1362 {
   1363 	if ( !f ) {
   1364 		Debug( LDAP_DEBUG_FILTER,
   1365 			"free_comp_filter: Invalid filter so failed to release memory\n" );
   1366 		return;
   1367 	}
   1368 	switch ( f->cf_choice ) {
   1369 	case LDAP_COMP_FILTER_AND:
   1370 	case LDAP_COMP_FILTER_OR:
   1371 		free_comp_filter_list( f->cf_any );
   1372 		break;
   1373 	case LDAP_COMP_FILTER_NOT:
   1374 		free_comp_filter( f->cf_any );
   1375 		break;
   1376 	case LDAP_COMP_FILTER_ITEM:
   1377 		if ( nibble_mem_free && f->cf_ca->ca_comp_data.cd_mem_op ) {
   1378 			nibble_mem_free( f->cf_ca->ca_comp_data.cd_mem_op );
   1379 		}
   1380 		break;
   1381 	default:
   1382 		break;
   1383 	}
   1384 }
   1385 
   1386 void
   1387 component_free( ComponentFilter *f ) {
   1388 	free_comp_filter( f );
   1389 }
   1390 
   1391 void
   1392 free_ComponentData( Attribute *a ) {
   1393 	if ( a->a_comp_data->cd_mem_op )
   1394 		component_destructor( a->a_comp_data->cd_mem_op );
   1395 	free ( a->a_comp_data );
   1396 	a->a_comp_data = NULL;
   1397 }
   1398 #endif
   1399