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