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