component.c revision 1.1.1.5
1/*	$NetBSD: component.c,v 1.1.1.5 2017/02/09 01:46:59 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-2016 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.1.1.5 2017/02/09 01:46:59 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 */
40alloc_nibble_func* nibble_mem_allocator = NULL;
41free_nibble_func* nibble_mem_free = NULL;
42convert_attr_to_comp_func* attr_converter = NULL;
43convert_assert_to_comp_func* assert_converter = NULL ;
44free_component_func* component_destructor = NULL ;
45test_component_func* test_components = NULL;
46test_membership_func* is_aliased_attribute = NULL;
47component_encoder_func* component_encoder = NULL;
48get_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
53static int
54peek_componentId_type( ComponentAssertionValue* cav );
55
56static int
57strip_cav_str( ComponentAssertionValue* cav, char* str);
58
59static int
60peek_cav_str( ComponentAssertionValue* cav, char* str );
61
62static int
63parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
64				ComponentFilter** filt, const char** text );
65
66static void
67free_comp_filter( ComponentFilter* f );
68
69static int
70test_comp_filter( Syntax *syn, ComponentSyntaxInfo *a, ComponentFilter *f );
71
72int
73componentCertificateValidate(
74	Syntax *syntax,
75	struct berval *val )
76{
77	return LDAP_SUCCESS;
78}
79
80int
81componentFilterValidate(
82	Syntax *syntax,
83	struct berval *val )
84{
85	return LDAP_SUCCESS;
86}
87
88int
89allComponentsValidate(
90	Syntax *syntax,
91	struct berval *val )
92{
93	return LDAP_SUCCESS;
94}
95
96int
97componentFilterMatch (
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
131int
132directoryComponentsMatch(
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
145int
146allComponentsMatch(
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
159static int
160slapd_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
168ComponentReference*
169dup_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
196static int
197dup_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
217int
218get_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
231int
232dup_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
260int
261dup_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
301int
302get_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", 0, 0, 0 );
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
320int
321get_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", 0, 0, 0 );
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
343int
344get_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", 0, 0, 0 );
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
360static void
361eat_whsp( ComponentAssertionValue* cav )
362{
363	for ( ; ( *cav->cav_ptr == ' ' ) && ( cav->cav_ptr < cav->cav_end ) ; ) {
364		cav->cav_ptr++;
365	}
366}
367
368static int
369cav_cur_len( ComponentAssertionValue* cav )
370{
371	return cav->cav_end - cav->cav_ptr;
372}
373
374static ber_tag_t
375comp_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
401static ber_tag_t
402comp_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
413static int
414get_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", 0, 0, 0 );
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
436static int
437get_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, 0, 0 );
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
508static int
509peek_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
541static ber_tag_t
542comp_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
554static int
555get_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
619int
620insert_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 */
644int
645is_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
653int
654extract_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
690static int
691get_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
712static int
713get_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, 0, 0 );
741	if ( *mr == NULL ) {
742		*text = "component matching rule not recognized";
743		return LDAP_INAPPROPRIATE_MATCHING;
744	}
745	return LDAP_SUCCESS;
746}
747
748static int
749get_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
860static int
861get_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		/* embeded 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 */
880static int
881peek_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
893static int
894strip_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 */
910static ber_tag_t
911strip_cav_tag( ComponentAssertionValue* cav )
912{
913
914	eat_whsp( cav );
915	if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
916		strip_cav_str( cav , "item:" );
917		return LDAP_COMP_FILTER_ITEM;
918
919	} else if ( cav_cur_len( cav ) >= 7 &&
920		strncmp( cav->cav_ptr, "and", 3 ) == 0 )
921	{
922		strip_cav_str( cav , "and:" );
923		return LDAP_COMP_FILTER_AND;
924
925	} else if ( cav_cur_len( cav ) >= 6 &&
926		strncmp( cav->cav_ptr, "or" , 2 ) == 0 )
927	{
928		strip_cav_str( cav , "or:" );
929		return LDAP_COMP_FILTER_OR;
930
931	} else if ( cav_cur_len( cav ) >= 7 &&
932		strncmp( cav->cav_ptr, "not", 3 ) == 0 )
933	{
934		strip_cav_str( cav , "not:" );
935		return LDAP_COMP_FILTER_NOT;
936	}
937
938	return LBER_ERROR;
939}
940
941/*
942 * when encoding, "item" is denotation of ComponentAssertion
943 * ComponentAssertion :: SEQUENCE {
944 *	component		ComponentReference (SIZE(1..MAX)) OPTIONAL,
945 *	useDefaultValues	BOOLEAN DEFAULT TRUE,
946 *	rule			MATCHING-RULE.&id,
947 *	value			MATCHING-RULE.&AssertionType }
948 */
949static int
950get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca,
951		const char** text )
952{
953	int rc;
954	ComponentAssertion* _ca;
955	struct berval value;
956	MatchingRule* mr;
957
958	Debug( LDAP_DEBUG_FILTER, "get_item \n", 0, 0, 0 );
959	if ( op )
960		_ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
961	else
962		_ca = SLAP_MALLOC( sizeof( ComponentAssertion ) );
963
964	if ( !_ca ) return LDAP_NO_MEMORY;
965
966	_ca->ca_comp_data.cd_tree = NULL;
967	_ca->ca_comp_data.cd_mem_op = NULL;
968
969	rc = peek_cav_str( cav, "component" );
970	if ( rc == LDAP_SUCCESS ) {
971		strip_cav_str( cav, "component" );
972		rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text );
973		if ( rc != LDAP_SUCCESS ) {
974			if ( op )
975				op->o_tmpfree( _ca, op->o_tmpmemctx );
976			else
977				free( _ca );
978			return LDAP_INVALID_SYNTAX;
979		}
980		if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
981			return rc;
982	} else {
983		_ca->ca_comp_ref = NULL;
984	}
985
986	rc = peek_cav_str( cav, "useDefaultValues");
987	if ( rc == LDAP_SUCCESS ) {
988		rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text );
989		if ( rc != LDAP_SUCCESS ) {
990			if ( op )
991				op->o_tmpfree( _ca, op->o_tmpmemctx );
992			else
993				free( _ca );
994			return LDAP_INVALID_SYNTAX;
995		}
996		if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
997			return rc;
998	}
999	else _ca->ca_use_def = 1;
1000
1001	if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS &&
1002		get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) {
1003		if ( op )
1004			op->o_tmpfree( _ca, op->o_tmpmemctx );
1005		else
1006			free( _ca );
1007		return LDAP_INAPPROPRIATE_MATCHING;
1008	}
1009
1010	if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
1011		return rc;
1012	if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS &&
1013		get_matching_value( op, _ca, cav,&value ,text ) == LDAP_SUCCESS )) {
1014		if ( op )
1015			op->o_tmpfree( _ca, op->o_tmpmemctx );
1016		else
1017			free( _ca );
1018		return LDAP_INVALID_SYNTAX;
1019	}
1020
1021	/*
1022	 * Normalize the value of this component assertion when the matching
1023	 * rule is one of existing matching rules
1024	 */
1025	mr = _ca->ca_ma_rule;
1026	if ( op && !(mr->smr_usage & (SLAP_MR_COMPONENT)) && mr->smr_normalize ) {
1027
1028		value.bv_val[value.bv_len] = '\0';
1029		rc = mr->smr_normalize (
1030			SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
1031			NULL, mr,
1032			&value, &_ca->ca_ma_value, op->o_tmpmemctx );
1033		if ( rc != LDAP_SUCCESS )
1034			return rc;
1035	}
1036	else
1037		_ca->ca_ma_value = value;
1038	/*
1039	 * Validate the value of this component assertion
1040	 */
1041	if ( op && mr->smr_syntax->ssyn_validate( mr->smr_syntax, &_ca->ca_ma_value) != LDAP_SUCCESS ) {
1042		return LDAP_INVALID_SYNTAX;
1043	}
1044
1045
1046	/* componentFilterMatch contains componentFilterMatch in it */
1047	if ( strcmp(_ca->ca_ma_rule->smr_mrule.mr_oid, OID_COMP_FILTER_MATCH ) == 0) {
1048		struct berval bv;
1049		bv.bv_val = cav->cav_ptr;
1050		bv.bv_len = cav_cur_len( cav );
1051		rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text );
1052		if ( rc != LDAP_SUCCESS ) {
1053			if ( op )
1054				op->o_tmpfree( _ca, op->o_tmpmemctx );
1055			else
1056				free( _ca );
1057			return rc;
1058		}
1059		cav->cav_ptr = bv.bv_val;
1060		assert( cav->cav_end >= bv.bv_val );
1061	}
1062
1063	*ca = _ca;
1064	return LDAP_SUCCESS;
1065}
1066
1067static int
1068parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
1069				ComponentFilter** filt, const char** text )
1070{
1071	/*
1072	 * A component filter looks like this coming in:
1073	 *	Filter ::= CHOICE {
1074	 *		item	[0]	ComponentAssertion,
1075	 *		and	[1]	SEQUENCE OF ComponentFilter,
1076	 *		or	[2]	SEQUENCE OF ComponentFilter,
1077	 *		not	[3]	ComponentFilter,
1078	 *	}
1079	 */
1080
1081	ber_tag_t	tag;
1082	int		err;
1083	ComponentFilter	f;
1084	/* TAG : item, and, or, not in RFC 4515 */
1085	tag = strip_cav_tag( cav );
1086
1087	if ( tag == LBER_ERROR ) {
1088		*text = "error decoding comp filter";
1089		return LDAP_PROTOCOL_ERROR;
1090	}
1091
1092	if ( tag != LDAP_COMP_FILTER_NOT )
1093		strip_cav_str( cav, "{");
1094
1095	err = LDAP_SUCCESS;
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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", 0, 0, 0 );
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	if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) {
1170		*text = "Component Filter Syntax Error";
1171		return err;
1172	}
1173
1174	if ( tag != LDAP_COMP_FILTER_NOT )
1175		strip_cav_str( cav, "}");
1176
1177	if ( err == LDAP_SUCCESS ) {
1178		if ( op ) {
1179			*filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx );
1180		} else {
1181			*filt = SLAP_MALLOC( sizeof(f) );
1182		}
1183		if ( *filt == NULL ) {
1184			return LDAP_NO_MEMORY;
1185		}
1186		**filt = f;
1187	}
1188
1189	return( err );
1190}
1191
1192static int
1193test_comp_filter_and(
1194	Syntax *syn,
1195	ComponentSyntaxInfo *a,
1196	ComponentFilter *flist )
1197{
1198	ComponentFilter *f;
1199	int rtn = LDAP_COMPARE_TRUE;
1200
1201	for ( f = flist ; f != NULL; f = f->cf_next ) {
1202		int rc = test_comp_filter( syn, a, f );
1203		if ( rc == LDAP_COMPARE_FALSE ) {
1204			rtn = rc;
1205			break;
1206		}
1207
1208		if ( rc != LDAP_COMPARE_TRUE ) {
1209			rtn = rc;
1210		}
1211	}
1212
1213	return rtn;
1214}
1215
1216static int
1217test_comp_filter_or(
1218	Syntax *syn,
1219	ComponentSyntaxInfo *a,
1220	ComponentFilter *flist )
1221{
1222	ComponentFilter *f;
1223	int rtn = LDAP_COMPARE_TRUE;
1224
1225	for ( f = flist ; f != NULL; f = f->cf_next ) {
1226		int rc = test_comp_filter( syn, a, f );
1227		if ( rc == LDAP_COMPARE_TRUE ) {
1228			rtn = rc;
1229			break;
1230		}
1231
1232		if ( rc != LDAP_COMPARE_FALSE ) {
1233			rtn = rc;
1234		}
1235	}
1236
1237	return rtn;
1238}
1239
1240int
1241csi_value_match( MatchingRule *mr, struct berval* bv_attr,
1242	struct berval* bv_assert )
1243{
1244	int rc;
1245	int match;
1246
1247	assert( mr != NULL );
1248	assert( !(mr->smr_usage & SLAP_MR_COMPONENT) );
1249
1250	if( !mr->smr_match ) return LDAP_INAPPROPRIATE_MATCHING;
1251
1252	rc = (mr->smr_match)( &match, 0, NULL /*ad->ad_type->sat_syntax*/,
1253		mr, bv_attr, bv_assert );
1254
1255	if ( rc != LDAP_SUCCESS ) return rc;
1256
1257	return match ? LDAP_COMPARE_FALSE : LDAP_COMPARE_TRUE;
1258}
1259
1260/*
1261 * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE
1262 */
1263static int
1264test_comp_filter_item(
1265	Syntax *syn,
1266	ComponentSyntaxInfo *csi_attr,
1267	ComponentAssertion *ca )
1268{
1269	int rc;
1270	void *attr_nm, *assert_nm;
1271
1272	if ( strcmp(ca->ca_ma_rule->smr_mrule.mr_oid,
1273		OID_COMP_FILTER_MATCH ) == 0 && ca->ca_cf ) {
1274		/* componentFilterMatch inside of componentFilterMatch */
1275		rc = test_comp_filter( syn, csi_attr, ca->ca_cf );
1276		return rc;
1277	}
1278
1279	/* Memory for storing will-be-extracted attribute values */
1280	attr_nm = nibble_mem_allocator ( 1024*4 , 1024 );
1281	if ( !attr_nm ) return LDAP_PROTOCOL_ERROR;
1282
1283	/* Memory for storing component assertion values */
1284	if( !ca->ca_comp_data.cd_mem_op ) {
1285		assert_nm = nibble_mem_allocator ( 256, 64 );
1286		if ( !assert_nm ) {
1287			nibble_mem_free ( attr_nm );
1288			return LDAP_PROTOCOL_ERROR;
1289		}
1290		ca->ca_comp_data.cd_mem_op = assert_nm;
1291
1292	} else {
1293		assert_nm = ca->ca_comp_data.cd_mem_op;
1294	}
1295
1296	/* component reference initialization */
1297	if ( ca->ca_comp_ref ) {
1298		ca->ca_comp_ref->cr_curr = ca->ca_comp_ref->cr_list;
1299	}
1300	rc = test_components( attr_nm, assert_nm, csi_attr, ca );
1301
1302	/* free memory used for storing extracted attribute value */
1303	nibble_mem_free ( attr_nm );
1304	return rc;
1305}
1306
1307static int
1308test_comp_filter(
1309    Syntax *syn,
1310    ComponentSyntaxInfo *a,
1311    ComponentFilter *f )
1312{
1313	int	rc;
1314
1315	if ( !f ) return LDAP_PROTOCOL_ERROR;
1316
1317	Debug( LDAP_DEBUG_FILTER, "test_comp_filter\n", 0, 0, 0 );
1318	switch ( f->cf_choice ) {
1319	case SLAPD_FILTER_COMPUTED:
1320		rc = f->cf_result;
1321		break;
1322	case LDAP_COMP_FILTER_AND:
1323		rc = test_comp_filter_and( syn, a, f->cf_and );
1324		break;
1325	case LDAP_COMP_FILTER_OR:
1326		rc = test_comp_filter_or( syn, a, f->cf_or );
1327		break;
1328	case LDAP_COMP_FILTER_NOT:
1329		rc = test_comp_filter( syn, a, f->cf_not );
1330
1331		switch ( rc ) {
1332		case LDAP_COMPARE_TRUE:
1333			rc = LDAP_COMPARE_FALSE;
1334			break;
1335		case LDAP_COMPARE_FALSE:
1336			rc = LDAP_COMPARE_TRUE;
1337			break;
1338		}
1339		break;
1340	case LDAP_COMP_FILTER_ITEM:
1341		rc = test_comp_filter_item( syn, a, f->cf_ca );
1342		break;
1343	default:
1344		rc = LDAP_PROTOCOL_ERROR;
1345	}
1346
1347	return( rc );
1348}
1349
1350static void
1351free_comp_filter_list( ComponentFilter* f )
1352{
1353	ComponentFilter* tmp;
1354	for ( tmp = f; tmp; tmp = tmp->cf_next ) {
1355		free_comp_filter( tmp );
1356	}
1357}
1358
1359static void
1360free_comp_filter( ComponentFilter* f )
1361{
1362	if ( !f ) {
1363		Debug( LDAP_DEBUG_FILTER,
1364			"free_comp_filter: Invalid filter so failed to release memory\n",
1365			0, 0, 0 );
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
1386void
1387component_free( ComponentFilter *f ) {
1388	free_comp_filter( f );
1389}
1390
1391void
1392free_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