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