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