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