]> git.sur5r.net Git - openldap/blob - servers/slapd/component.c
8060adb285dda31de19d6cbf427b0731284534a0
[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-2004 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  * This three 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 convert_asn_to_ldap_func* csi_converter = NULL ;
40 free_component_func* component_destructor = NULL ;
41 test_component_func* test_one_component = NULL;
42 test_component_func* test_all_components = NULL;
43
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, Attribute        *a, struct berval *bv,
66                         ComponentFilter *f );
67
68 int
69 componentCertificateValidate(
70         Syntax *syntax,
71         struct berval *val )
72 {
73         return LDAP_SUCCESS;
74 }
75
76 int
77 componentFilterValidate(
78         Syntax *syntax,
79         struct berval *val )
80 {
81         return LDAP_SUCCESS;
82 }
83
84 int
85 allComponentsValidate(
86         Syntax *syntax,
87         struct berval *val )
88 {
89         return LDAP_SUCCESS;
90 }
91
92 int
93 componentFilterMatch ( 
94         int *matchp, 
95         slap_mask_t flags, 
96         Syntax *syntax, 
97         MatchingRule *mr,
98         struct berval *value, 
99         void *assertedValue )
100 {
101         Attribute *a = (Attribute*)value;
102         MatchingRuleAssertion * ma = (MatchingRuleAssertion*)assertedValue;
103
104         int rc;
105
106         if ( !(mr && mr->smr_usage & SLAP_MR_COMPONENT) || !ma->ma_cf )
107                 return LDAP_INAPPROPRIATE_MATCHING;
108                 
109         rc = test_comp_filter( syntax, a, a->a_vals, ma->ma_cf );
110
111         if ( rc == LDAP_COMPARE_TRUE ) {
112                 *matchp = 0;
113                 return LDAP_SUCCESS;
114         }
115         else if ( rc == LDAP_COMPARE_FALSE ) {
116                 *matchp = 1;
117                 return LDAP_SUCCESS;
118         }
119         else {
120                 return LDAP_INAPPROPRIATE_MATCHING;
121         }
122         
123 }
124 int
125 directoryComponentsMatch( 
126         int *matchp, 
127         slap_mask_t flags, 
128         Syntax *syntax, 
129         MatchingRule *mr,
130         struct berval *value, 
131         void *assertedValue )
132 {
133         /* Only for Registeration */
134         *matchp = 0;
135         return LDAP_SUCCESS;
136 }
137
138 int
139 allComponentsMatch( 
140         int *matchp, 
141         slap_mask_t flags, 
142         Syntax *syntax, 
143         MatchingRule *mr,
144         struct berval *value, 
145         void *assertedValue )
146 {
147         /* Only for Registeration */
148         *matchp = 0;
149         return LDAP_SUCCESS;
150 }
151
152 static int
153 slapd_ber2cav( struct berval* bv, ComponentAssertionValue* cav)
154 {
155         int len;
156
157         cav->cav_ptr = cav->cav_buf = bv->bv_val;
158         cav->cav_end = bv->bv_val + bv->bv_len;
159
160         return LDAP_SUCCESS;
161 }
162
163 int
164 get_comp_filter( Operation* op, struct berval* bv, ComponentFilter** filt,
165                  const char **text )
166 {
167         ComponentAssertionValue cav;
168         int rc;
169
170         Debug( LDAP_DEBUG_FILTER, "get_comp_filter\n", 0, 0, 0 );
171         if ( (rc = slapd_ber2cav(bv, &cav) ) != LDAP_SUCCESS ) {
172                 return rc;
173         }
174         rc = parse_comp_filter( op, &cav, filt, text );
175         bv->bv_val = cav.cav_ptr;
176
177         return rc;
178 }
179
180 static void
181 eat_whsp( ComponentAssertionValue* cav )
182 {
183         for ( ; ( *cav->cav_ptr == ' ' ) && ( cav->cav_ptr < cav->cav_end ) ; ) {
184                 cav->cav_ptr++;
185         }
186 }
187
188 static int
189 cav_cur_len( ComponentAssertionValue* cav )
190 {
191         return cav->cav_end - cav->cav_ptr;
192 }
193
194 static ber_tag_t
195 comp_first_element( ComponentAssertionValue* cav )
196 {
197         eat_whsp( cav );
198         if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
199                 return LDAP_COMP_FILTER_ITEM;
200         }
201         else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
202                 return LDAP_COMP_FILTER_AND;
203         }
204         else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
205                 return LDAP_COMP_FILTER_OR;
206         }
207         else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
208                 return LDAP_COMP_FILTER_NOT;
209         }
210         else
211                 return LDAP_COMP_FILTER_UNDEFINED;
212 }
213
214 static ber_tag_t
215 comp_next_element( ComponentAssertionValue* cav )
216 {
217
218         eat_whsp( cav );
219         if ( *(cav->cav_ptr) == ',' ) {
220                 /* move pointer to the next CA */
221                 cav->cav_ptr++;
222                 return comp_first_element( cav );
223         }
224         else return LDAP_COMP_FILTER_UNDEFINED;
225 }
226
227 static int
228 get_comp_filter_list( Operation *op, ComponentAssertionValue *cav,
229                         ComponentFilter** f, const char** text )
230 {
231         ComponentFilter **new;
232         int             err;
233         ber_tag_t       tag;
234
235         Debug( LDAP_DEBUG_FILTER, "get_comp_filter_list\n", 0, 0, 0 );
236         new = f;
237         for ( tag = comp_first_element( cav ); tag != LDAP_COMP_FILTER_UNDEFINED;
238                 tag = comp_next_element( cav ) )
239         {
240                 err = parse_comp_filter( op, cav, new, text );
241                 if ( err != LDAP_SUCCESS )
242                         return ( err );
243                 new = &(*new)->cf_next;
244         }
245         *new = NULL;
246
247         return( LDAP_SUCCESS );
248 }
249
250 static int
251 get_componentId( Operation *op, ComponentAssertionValue* cav,
252                         ComponentId ** cid, const char** text )
253 {
254         ber_tag_t type;
255         ComponentId _cid;
256         int len;
257
258         type = peek_componentId_type( cav );
259
260         Debug( LDAP_DEBUG_FILTER, "get_compId [%d]\n", type, 0, 0 );
261         len = 0;
262         _cid.ci_type = type;
263         _cid.ci_next = NULL;
264         switch ( type ) {
265         case LDAP_COMPREF_IDENTIFIER :
266                 _cid.ci_val.ci_identifier.bv_val = cav->cav_ptr;
267                 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
268                         cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
269                 _cid.ci_val.ci_identifier.bv_len = len;
270                 cav->cav_ptr += len;
271                 break;
272         case LDAP_COMPREF_FROM_BEGINNING :
273                 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
274                         cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
275                 _cid.ci_val.ci_from_beginning = strtol( cav->cav_ptr, NULL, 0 );
276                 cav->cav_ptr += len;
277                 break;
278         case LDAP_COMPREF_FROM_END :
279                 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
280                         cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
281                 _cid.ci_val.ci_from_end = strtol( cav->cav_ptr, NULL, 0 );
282                 cav->cav_ptr += len;
283                 break;
284         case LDAP_COMPREF_COUNT :
285                 _cid.ci_val.ci_count = 0;
286                 cav->cav_ptr++;
287                 break;
288         case LDAP_COMPREF_CONTENT :
289                 _cid.ci_val.ci_content = 1;
290                 cav->cav_ptr += strlen("content");
291                 break;
292         case LDAP_COMPREF_SELECT :
293                 if ( cav->cav_ptr[len] != '(' )
294                         return LDAP_COMPREF_UNDEFINED;
295                 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
296                       cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' &&
297                       cav->cav_ptr[len] != ')' ; len++ );
298                 _cid.ci_val.ci_select_value.bv_val = cav->cav_ptr + 1;
299                 _cid.ci_val.ci_select_value.bv_len = len - 1 ;
300                 cav->cav_ptr += len;
301                 break;
302         case LDAP_COMPREF_ALL :
303                 _cid.ci_val.ci_all = '*';
304                 cav->cav_ptr++;
305                 break;
306         default :
307                 return LDAP_COMPREF_UNDEFINED;
308         }
309
310         *cid = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx );
311         **cid = _cid;
312         return LDAP_SUCCESS;
313 }
314
315 static int
316 peek_componentId_type( ComponentAssertionValue* cav )
317 {
318         eat_whsp( cav );
319         if ( cav->cav_ptr[0] == '-' )
320                 return LDAP_COMPREF_FROM_END;
321         else if ( cav->cav_ptr[0] == '(' )
322                 return LDAP_COMPREF_SELECT;
323         else if ( cav->cav_ptr[0] == '*' )
324                 return LDAP_COMPREF_ALL;
325         else if ( strncmp(cav->cav_ptr,"all",3) == 0 )
326                 return LDAP_COMPREF_ALL;
327         else if ( cav->cav_ptr[0] == '0' )
328                 return LDAP_COMPREF_COUNT;
329         else if ( cav->cav_ptr[0] > '0' && cav->cav_ptr[0] <= '9' )
330                 return LDAP_COMPREF_FROM_BEGINNING;
331         else if ( (cav->cav_end - cav->cav_ptr) >= 7 &&
332                 strncmp(cav->cav_ptr,"content",7) == 0 )
333                 return LDAP_COMPREF_CONTENT;
334         else if ( (cav->cav_ptr[0] >= 'a' && cav->cav_ptr[0] <= 'z') ||
335                         (cav->cav_ptr[0] >= 'A' && cav->cav_ptr[0] <= 'Z') )
336                  
337                 return LDAP_COMPREF_IDENTIFIER;
338         else
339                 return LDAP_COMPREF_UNDEFINED;
340 }
341
342 static ber_tag_t
343 comp_next_id( ComponentAssertionValue* cav )
344 {
345
346         if ( *(cav->cav_ptr) == '.' ) {
347                 cav->cav_ptr++;
348                 return LDAP_COMPREF_DEFINED;
349         }
350         else return LDAP_COMPREF_UNDEFINED;
351 }
352
353 static int
354 get_component_reference( Operation *op, ComponentAssertionValue* cav,
355                         ComponentReference** cr, const char** text )
356 {
357         int rc,count=0;
358         ber_int_t type;
359         ComponentReference* ca_comp_ref;
360         ComponentId** cr_list;
361
362         eat_whsp( cav );
363
364         if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS )
365                 return rc;
366
367         ca_comp_ref =
368                 op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx );
369
370         cr_list = &ca_comp_ref->cr_list;
371
372         for ( type = peek_componentId_type( cav ) ; type != LDAP_COMPREF_UNDEFINED
373                 ; type = comp_next_id( cav ), count++ ) {
374                 rc = get_componentId( op, cav, cr_list, text );
375                 if ( rc == LDAP_SUCCESS ) {
376                         if ( count == 0 ) ca_comp_ref->cr_curr = ca_comp_ref->cr_list;
377                         cr_list = &(*cr_list)->ci_next;
378                 }
379                 else if ( rc == LDAP_COMPREF_UNDEFINED )
380                         return rc;
381         }
382         ca_comp_ref->cr_len = count;
383
384         if ( ( rc = strip_cav_str( cav,"\"") ) != LDAP_SUCCESS ) {
385                 op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
386                 return rc;
387         }
388
389         if ( rc == LDAP_SUCCESS ) {     
390                 *cr = ca_comp_ref;
391                 **cr = *ca_comp_ref;    
392         }
393         else op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
394
395         return rc;
396 }
397
398 static int
399 get_ca_use_default( Operation *op, ComponentAssertionValue* cav,
400                 int* ca_use_def, const char**  text )
401 {
402         strip_cav_str( cav, "useDefaultValues" );
403         if ( peek_cav_str( cav, "TRUE" ) == LDAP_SUCCESS ) {
404                 strip_cav_str( cav, "TRUE" );
405                 *ca_use_def = 1;
406         } else if ( peek_cav_str( cav, "FALSE" ) == LDAP_SUCCESS ) {
407                 strip_cav_str( cav, "FALSE" );
408                 *ca_use_def = 0;
409         } else {
410                 return LDAP_INVALID_SYNTAX;
411         }
412
413         return LDAP_SUCCESS;
414 }
415
416 static int
417 get_matching_rule( Operation *op, ComponentAssertionValue* cav,
418                 MatchingRule** mr, const char**  text )
419 {
420         int count = 0;
421         struct berval rule_text = { 0L, NULL };
422
423         eat_whsp( cav );
424
425         for ( ; ; count++ ) {
426                 if ( cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == ',' ||
427                         cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == '{' ||
428                         cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '\n' )
429                         break;
430         }
431
432         if ( count == 0 ) {
433                 *text = "component matching rule not recognized";
434                 return LDAP_INAPPROPRIATE_MATCHING;
435         }
436         
437         rule_text.bv_len = count;
438         rule_text.bv_val = cav->cav_ptr;
439         *mr = mr_bvfind( &rule_text );
440         cav->cav_ptr += count;
441         Debug( LDAP_DEBUG_FILTER, "get_matching_rule: %s\n", (*mr)->smr_mrule.mr_oid, 0, 0 );
442         if ( *mr == NULL ) {
443                 *text = "component matching rule not recognized";
444                 return LDAP_INAPPROPRIATE_MATCHING;
445         }
446         return LDAP_SUCCESS;
447 }
448
449 static int
450 get_GSER_value( ComponentAssertionValue* cav, struct berval* bv )
451 {
452         int count, sequent_dquote, unclosed_brace, succeed;
453
454         eat_whsp( cav );
455         /*
456          * Four cases of GSER <Values>
457          * 1) "..." :
458          *      StringVal, GeneralizedTimeVal, UTCTimeVal, ObjectDescriptorVal
459          * 2) '...'B or '...'H :
460          *      BitStringVal, OctetStringVal
461          * 3) {...} :
462          *      SEQUENCE, SEQUENCEOF, SETOF, SET, CHOICE
463          * 4) Between two white spaces
464          *      INTEGER, BOOLEAN, NULL,ENUMERATE, etc
465          */
466
467         succeed = 0;
468         if ( cav->cav_ptr[0] == '"' ) {
469                 for( count = 1, sequent_dquote = 0 ; ; count++ ) {
470                         /* In order to find escaped double quote */
471                         if ( cav->cav_ptr[count] == '"' ) sequent_dquote++;
472                         else sequent_dquote = 0;
473
474                         if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end ) {
475                                 break;
476                         }
477                                 
478                         if ( ( cav->cav_ptr[count] == '"' && cav->cav_ptr[count-1] != '"') ||
479                         ( sequent_dquote > 2 && (sequent_dquote%2) == 1 ) ) {
480                                 succeed = 1;
481                                 break;
482                         }
483                 }
484         }
485         else if ( cav->cav_ptr[0] == '\'' ) {
486                 for( count = 1 ; ; count++ ) {
487                         if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end ) {
488                                 break;
489                         }
490                         if ((cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'B')||
491                         (cav->cav_ptr[count-1] == '\'' && cav->cav_ptr[count] == 'H') ) {
492                                 succeed = 1;
493                                 break;
494                         }
495                 }
496                                 
497         }
498         else if ( cav->cav_ptr[0] == '{' ) {
499                 for( count = 1, unclosed_brace = 1 ; ; count++ ) {
500                         if ( cav->cav_ptr[count] == '{' ) unclosed_brace++;
501                         if ( cav->cav_ptr[count] == '}' ) unclosed_brace--;
502
503                         if ( cav->cav_ptr[count] == '\0' || (cav->cav_ptr+count) > cav->cav_end )
504                                 break;
505                         if ( unclosed_brace == 0 ) {
506                                 succeed = 1;
507                                 break;
508                         }
509                 }
510         }
511         else {
512                 succeed = 1;
513                 /*Find  following white space where the value is ended*/
514                 for( count = 1 ; ; count++ ) {
515                         if ( cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == ' ' || (cav->cav_ptr+count) > cav->cav_end ) {
516                                 break;
517                         }
518                 }
519         }
520
521         if ( !succeed ) return LDAP_FILTER_ERROR;
522
523         bv->bv_val = cav->cav_ptr;
524         bv->bv_len = count ;
525         cav->cav_ptr += count;
526         return LDAP_SUCCESS;
527 }
528
529 static int
530 get_matching_value( Operation *op, ComponentAssertion* ca,
531                         ComponentAssertionValue* cav, struct berval* bv,
532                         const char**  text )
533 {
534         if ( !(ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT)) ) {
535                 if ( get_GSER_value( cav, bv ) != LDAP_SUCCESS ) {
536                         return LDAP_FILTER_ERROR;
537                 }
538
539         } else {
540                 /* embeded componentFilterMatch Description */
541                 bv->bv_val = cav->cav_ptr;
542                 bv->bv_len = cav_cur_len( cav );
543         }
544
545         return LDAP_SUCCESS;
546 }
547
548 /* Don't move the position pointer, just peek given string */
549 static int
550 peek_cav_str( ComponentAssertionValue* cav, char* str )
551 {
552         eat_whsp( cav );
553         if ( cav_cur_len( cav ) >= strlen( str ) &&
554                 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 )
555                 return LDAP_SUCCESS;
556         else 
557                 return LDAP_INVALID_SYNTAX;
558 }
559
560 static int
561 strip_cav_str( ComponentAssertionValue* cav, char* str)
562 {
563         eat_whsp( cav );
564         if ( cav_cur_len( cav ) >= strlen( str ) &&
565                 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 ) {
566                 cav->cav_ptr += strlen( str );
567                 return LDAP_SUCCESS;
568         }
569         else 
570                 return LDAP_INVALID_SYNTAX;
571 }
572
573 /*
574  * TAG : "item", "and", "or", "not"
575  */
576 static int
577 strip_cav_tag( ComponentAssertionValue* cav )
578 {
579
580         eat_whsp( cav );
581         if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
582                 strip_cav_str( cav , "item:" );
583                 return LDAP_COMP_FILTER_ITEM;
584         }
585         else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
586                 strip_cav_str( cav , "and:" );
587                 return LDAP_COMP_FILTER_AND;
588         }
589         else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
590                 strip_cav_str( cav , "or:" );
591                 return LDAP_COMP_FILTER_OR;
592         }
593         else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
594                 strip_cav_str( cav , "not:" );
595                 return LDAP_COMP_FILTER_NOT;
596         }
597         else
598                 return LBER_ERROR;
599 }
600
601 /*
602  * when encoding, "item" is denotation of ComponentAssertion
603  * ComponentAssertion :: SEQUENCE {
604  *      component               ComponentReference (SIZE(1..MAX)) OPTIONAL,
605  *      useDefaultValues        BOOLEAN DEFAULT TRUE,
606  *      rule                    MATCHING-RULE.&id,
607  *      value                   MATCHING-RULE.&AssertionType }
608  */
609 static int
610 get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca,
611                 const char** text )
612 {
613         int rc;
614         ComponentAssertion* _ca;
615
616         Debug( LDAP_DEBUG_FILTER, "get_item: %s\n", 0, 0, 0 );
617         _ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
618
619         _ca->ca_comp_data.cd_tree = NULL;
620         _ca->ca_comp_data.cd_mem_op = NULL;
621
622         rc = peek_cav_str( cav, "component" );
623         if ( rc == LDAP_SUCCESS ) {
624                 strip_cav_str( cav, "component" );
625                 rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text );
626                 if ( rc != LDAP_SUCCESS ) {
627                         rc = LDAP_INVALID_SYNTAX;
628                         op->o_tmpfree( _ca, op->o_tmpmemctx );
629                         return rc;
630                 }
631         }
632
633         if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
634                 return rc;
635
636         rc = peek_cav_str( cav, "useDefaultValues");
637         if ( rc == LDAP_SUCCESS ) {
638                 rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text );
639                 if ( rc != LDAP_SUCCESS ) {
640                         rc = LDAP_INVALID_SYNTAX;
641                         op->o_tmpfree( _ca, op->o_tmpmemctx );
642                         return rc;
643                 }
644                 if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
645                         return rc;
646         }
647         else _ca->ca_use_def = 1;
648
649         if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS &&
650                 get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) {
651                 rc = LDAP_INAPPROPRIATE_MATCHING;
652                 op->o_tmpfree( _ca, op->o_tmpmemctx );
653                 return rc;
654         }
655         
656         if ( ( rc = strip_cav_str( cav,",") ) != LDAP_SUCCESS )
657                 return rc;
658         if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS &&
659                 get_matching_value( op, _ca, cav, &_ca->ca_ma_value,text ) == LDAP_SUCCESS )) {
660                 rc = LDAP_INVALID_SYNTAX;
661                 op->o_tmpfree( _ca, op->o_tmpmemctx );
662                 return rc;
663         }
664
665         /* componentFilterMatch contains componentFilterMatch in it */
666         if ( strcmp(_ca->ca_ma_rule->smr_mrule.mr_oid, OID_COMP_FILTER_MATCH ) == 0) {
667                 struct berval bv;
668                 bv.bv_val = cav->cav_ptr;
669                 bv.bv_len = cav_cur_len( cav );
670                 rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text );
671                 if ( rc != LDAP_SUCCESS ) {
672                         op->o_tmpfree( _ca, op->o_tmpmemctx );
673                         return rc;
674                 }
675                 cav->cav_ptr = bv.bv_val;
676                 assert( cav->cav_end >= bv.bv_val );
677         }
678
679         *ca = _ca;
680         return LDAP_SUCCESS;
681 }
682
683 static int
684 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
685                                 ComponentFilter** filt, const char** text )
686 {
687         /*
688          * A component filter looks like this coming in:
689          *      Filter ::= CHOICE {
690          *              item    [0]     ComponentAssertion,
691          *              and     [1]     SEQUENCE OF ComponentFilter,
692          *              or      [2]     SEQUENCE OF ComponentFilter,
693          *              not     [3]     ComponentFilter,
694          *      }
695          */
696
697         ber_tag_t       tag;
698         int             err;
699         ComponentFilter f;
700         /* TAG : item, and, or, not in RFC 2254 */
701         tag = strip_cav_tag( cav );
702
703         if ( tag == LBER_ERROR ) {
704                 *text = "error decoding comp filter";
705                 return LDAP_PROTOCOL_ERROR;
706         }
707
708         if ( tag != LDAP_COMP_FILTER_NOT )
709                 strip_cav_str( cav, "{");
710
711         err = LDAP_SUCCESS;
712
713         f.cf_next = NULL;
714         f.cf_choice = tag; 
715
716         switch ( f.cf_choice ) {
717         case LDAP_COMP_FILTER_AND:
718         Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_AND\n", 0, 0, 0 );
719                 err = get_comp_filter_list( op, cav, &f.cf_and, text );
720                 if ( err != LDAP_SUCCESS ) {
721                         break;
722                 }
723                 if ( f.cf_and == NULL ) {
724                         f.cf_choice = SLAPD_FILTER_COMPUTED;
725                         f.cf_result = LDAP_COMPARE_TRUE;
726                 }
727                 break;
728
729         case LDAP_COMP_FILTER_OR:
730         Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_OR\n", 0, 0, 0 );
731                 err = get_comp_filter_list( op, cav, &f.cf_or, text );
732                 if ( err != LDAP_SUCCESS ) {
733                         break;
734                 }
735                 if ( f.cf_or == NULL ) {
736                         f.cf_choice = SLAPD_FILTER_COMPUTED;
737                         f.cf_result = LDAP_COMPARE_FALSE;
738                 }
739                 /* no assert - list could be empty */
740                 break;
741
742         case LDAP_COMP_FILTER_NOT:
743         Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_NOT\n", 0, 0, 0 );
744                 err = parse_comp_filter( op, cav, &f.cf_not, text );
745                 if ( err != LDAP_SUCCESS ) {
746                         break;
747                 }
748
749                 assert( f.cf_not != NULL );
750                 if ( f.cf_not->cf_choice == SLAPD_FILTER_COMPUTED ) {
751                         int fresult = f.cf_not->cf_result;
752                         f.cf_choice = SLAPD_FILTER_COMPUTED;
753                         op->o_tmpfree( f.cf_not, op->o_tmpmemctx );
754                         f.cf_not = NULL;
755
756                         switch ( fresult ) {
757                         case LDAP_COMPARE_TRUE:
758                                 f.cf_result = LDAP_COMPARE_FALSE;
759                                 break;
760                         case LDAP_COMPARE_FALSE:
761                                 f.cf_result = LDAP_COMPARE_TRUE;
762                                 break;
763                         default: ;
764                                 /* (!Undefined) is Undefined */
765                         }
766                 }
767                 break;
768
769         case LDAP_COMP_FILTER_ITEM:
770         Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_ITEM\n", 0, 0, 0 );
771                 err = get_item( op, cav, &f.cf_ca, text );
772                 if ( err != LDAP_SUCCESS ) {
773                         break;
774                 }
775
776                 assert( f.cf_ca != NULL );
777                 break;
778
779         default:
780                 f.cf_choice = SLAPD_FILTER_COMPUTED;
781                 f.cf_result = SLAPD_COMPARE_UNDEFINED;
782                 break;
783         }
784
785         if ( tag != LDAP_COMP_FILTER_NOT )
786                 strip_cav_str( cav, "}");
787
788         if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) {
789                 *text = NULL;
790                 f.cf_choice = SLAPD_FILTER_COMPUTED;
791                 f.cf_result = SLAPD_COMPARE_UNDEFINED;
792                 err = LDAP_SUCCESS;
793         }
794
795         if ( err == LDAP_SUCCESS ) {
796                 *filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx );
797                 **filt = f;
798         }
799
800         return( err );
801 }
802
803 static int
804 test_comp_filter_and(
805         Syntax *syn,
806         Attribute *a,
807         struct berval  *bv,
808         ComponentFilter *flist )
809 {
810         ComponentFilter *f;
811         int rtn = LDAP_COMPARE_TRUE;
812
813         for ( f = flist ; f != NULL; f = f->cf_next ) {
814                 int rc = test_comp_filter( syn, a, bv, f );
815                 if ( rc == LDAP_COMPARE_FALSE ) {
816                         rtn = rc;
817                         break;
818                 }
819         
820                 if ( rc != LDAP_COMPARE_TRUE ) {
821                         rtn = rc;
822                 }
823         }
824
825         return rtn;
826 }
827
828 static int
829 test_comp_filter_or(
830         Syntax *syn,
831         Attribute *a,
832         struct berval     *bv,
833         ComponentFilter *flist )
834 {
835         ComponentFilter *f;
836         int rtn = LDAP_COMPARE_TRUE;
837
838         for ( f = flist ; f != NULL; f = f->cf_next ) {
839                 int rc = test_comp_filter( syn, a, bv, f );
840                 if ( rc == LDAP_COMPARE_TRUE ) {
841                         rtn = rc;
842                         break;
843                 }
844         
845                 if ( rc != LDAP_COMPARE_FALSE ) {
846                         rtn = rc;
847                 }
848         }
849
850         return rtn;
851 }
852
853 int
854 csi_value_match( MatchingRule *mr, struct berval* bv_attr,
855                 struct berval* bv_assert )
856 {
857         int rc;
858         int match;
859
860         assert( mr != NULL );
861         assert( !(mr->smr_usage & SLAP_MR_COMPONENT) );
862
863         if( !mr->smr_match ) {
864                 return LDAP_INAPPROPRIATE_MATCHING;
865         }
866
867         rc = (mr->smr_match)( &match, 0, NULL /*ad->ad_type->sat_syntax*/,
868                                 mr, bv_attr, bv_assert );
869         if ( rc == LDAP_SUCCESS )
870                 return match? LDAP_COMPARE_FALSE:LDAP_COMPARE_TRUE;
871         else
872                 return rc;
873 }
874
875 int
876 component_value_match( MatchingRule* mr,
877         ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert )
878 {
879         if ( mr->smr_usage & SLAP_MR_COMPONENT ){
880                 if ( strcmp( mr->smr_mrule.mr_oid, OID_ALL_COMP_MATCH ) == 0 )
881                 {
882                         /* allComponentMatch */
883                         return csi_attr->csi_comp_desc->cd_all_match( NULL,
884                                                 csi_attr, csi_assert );
885                 } else {
886                         return csi_assert->csi_comp_desc->cd_all_match(
887                                 mr->smr_mrule.mr_oid, csi_attr, csi_assert );
888                 }
889
890         } else {
891                 if ( csi_attr->csi_comp_desc->cd_type == ASN_BASIC ) {
892                         struct berval bv1, bv2;
893                         char attr_buf[MAX_LDAP_STR_LEN],assert_buf[MAX_LDAP_STR_LEN];
894                         bv1.bv_val = attr_buf;
895                         bv2.bv_val = assert_buf;
896                         if ( csi_converter &&
897                                 ( csi_converter ( csi_attr, &bv1 ) == LDAP_SUCCESS ) &&
898                                 ( csi_converter ( csi_assert, &bv2 ) == LDAP_SUCCESS ) )
899                         {
900                                 return csi_value_match( mr, &bv1, &bv2 );
901
902                         } else {
903                                 return LDAP_INAPPROPRIATE_MATCHING;
904                         }
905
906                 } else if ( csi_attr->csi_comp_desc->cd_type == ASN_COMPOSITE )
907                 {
908                         return LDAP_INAPPROPRIATE_MATCHING;
909                 }
910         }
911 }
912
913 /*
914  * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE
915  */
916 static int
917 test_comp_filter_item(
918         Syntax *syn,
919         Attribute       *a,
920         struct berval   *bv,
921         ComponentAssertion *ca )
922 {
923         int rc, len;
924         ComponentSyntaxInfo* csi_attr, *csi_assert=NULL;
925         void *attr_nm, *assert_nm;
926
927         if ( strcmp(ca->ca_ma_rule->smr_mrule.mr_oid,
928                 OID_COMP_FILTER_MATCH ) == 0 && ca->ca_cf ) {
929                 /* componentFilterMatch inside of componentFilterMatch */
930                 rc = test_comp_filter( syn, a, bv, ca->ca_cf );
931                 return rc;
932         }
933
934         /* load attribute containg components */
935         if ( !a->a_comp_data && attr_converter && nibble_mem_allocator ) {
936                 a->a_comp_data = malloc( sizeof( ComponentData ) );
937                 /* Memory chunk pre-allocation for decoders */
938                 a->a_comp_data->cd_mem_op = (void*) nibble_mem_allocator ( 1024, 128 );
939                 a->a_comp_data->cd_tree = attr_converter (a, syn, bv);
940         }
941
942         if ( a->a_comp_data->cd_tree == NULL ) {
943                 free ( a->a_comp_data );
944                 return LDAP_PROTOCOL_ERROR;
945         }
946
947         /* Memory for storing will-be-extracted attribute values */
948         attr_nm = nibble_mem_allocator ( 256, 64 );
949         if ( !attr_nm )return LDAP_PROTOCOL_ERROR;
950         /* component reference initialization */
951         ca->ca_comp_ref->cr_curr = ca->ca_comp_ref->cr_list;
952         /* load component containg the referenced component */
953         csi_attr = (((ComponentSyntaxInfo*)a->a_comp_data->cd_tree)->csi_comp_desc->cd_extract_i)( attr_nm, ca->ca_comp_ref, a->a_comp_data->cd_tree );
954         if ( !csi_attr )
955                 return LDAP_PROTOCOL_ERROR;
956
957         /* Memory for storing component assertion values */
958         assert_nm = nibble_mem_allocator ( 256, 64 );
959         if ( !assert_nm ) return LDAP_PROTOCOL_ERROR;
960         /* perform matching */
961         if ( ca->ca_comp_ref->cr_curr->ci_type == LDAP_COMPREF_ALL ) {
962                 /*
963                  * If <all> type component referenced is used
964                  * more than one component will be tested
965                  */
966                 if ( test_all_components )
967                         rc = test_all_components ( assert_nm, csi_attr, ca );
968                 else
969                         rc = LDAP_PROTOCOL_ERROR;
970         } else {
971                 /*
972                  * Exactly one component is referenced
973                  * Fast Path for matching for this case
974                  */
975                 if ( test_one_component )
976                         rc = test_one_component ( assert_nm, csi_attr, ca );
977                 else
978                         rc = LDAP_PROTOCOL_ERROR;
979         }
980         /* free memory used for storing extracted attribute value */
981         nibble_mem_free ( attr_nm );
982         return rc;
983 }
984
985 static int
986 test_comp_filter(
987     Syntax *syn,
988     Attribute   *a,
989     struct berval *bv,
990     ComponentFilter *f )
991 {
992         int     rc;
993
994         if ( !f ) return LDAP_PROTOCOL_ERROR;
995
996         Debug( LDAP_DEBUG_FILTER, "test_comp_filter\n", 0, 0, 0 );
997         switch ( f->cf_choice ) {
998         case SLAPD_FILTER_COMPUTED:
999                 rc = f->cf_result;
1000                 break;
1001         case LDAP_COMP_FILTER_AND:
1002                 rc = test_comp_filter_and( syn, a, bv, f->cf_and );
1003                 break;
1004         case LDAP_COMP_FILTER_OR:
1005                 rc = test_comp_filter_or( syn, a, bv, f->cf_or );
1006                 break;
1007         case LDAP_COMP_FILTER_NOT:
1008                 rc = test_comp_filter( syn, a, bv, f->cf_not );
1009
1010                 switch ( rc ) {
1011                 case LDAP_COMPARE_TRUE:
1012                         rc = LDAP_COMPARE_FALSE;
1013                         break;
1014                 case LDAP_COMPARE_FALSE:
1015                         rc = LDAP_COMPARE_TRUE;
1016                         break;
1017                 }
1018                 break;
1019         case LDAP_COMP_FILTER_ITEM:
1020                 rc = test_comp_filter_item( syn, a, bv, f->cf_ca );
1021                 break;
1022         default:
1023                 rc = LDAP_PROTOCOL_ERROR;
1024         }
1025
1026         return( rc );
1027 }
1028
1029 static void
1030 free_comp_filter_list( ComponentFilter* f )
1031 {
1032         ComponentFilter* tmp;
1033         for ( tmp = f ; tmp; tmp = tmp->cf_next );
1034         {
1035                 free_comp_filter( tmp );
1036         }
1037 }
1038
1039 static void
1040 free_comp_filter( ComponentFilter* f )
1041 {
1042         switch ( f->cf_choice ) {
1043         case LDAP_COMP_FILTER_AND:
1044         case LDAP_COMP_FILTER_OR:
1045         case LDAP_COMP_FILTER_NOT:
1046                 free_comp_filter( f->cf_any );
1047                 break;
1048
1049         case LDAP_COMP_FILTER_ITEM:
1050                 if ( nibble_mem_free && f->cf_ca->ca_comp_data.cd_mem_op )
1051                         nibble_mem_free( f->cf_ca->ca_comp_data.cd_mem_op );
1052                 break;
1053
1054         default:
1055                 break;
1056         }
1057 }
1058
1059 void
1060 component_free( ComponentFilter *f ) {
1061         free_comp_filter( f );
1062 }
1063
1064 #endif