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