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