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