1 /* component.c -- Component Filter Match Routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2004 The OpenLDAP Foundation.
6 * Portions Copyright 2004 by IBM Corporation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
20 #include <ac/string.h>
21 #include <ac/socket.h>
28 #ifdef LDAP_COMP_MATCH
33 peek_componentId_type( ComponentAssertionValue* cav );
36 strip_cav_str( ComponentAssertionValue* cav, char* str);
39 peek_cav_str( ComponentAssertionValue* cav, char* str );
42 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
43 ComponentFilter** filt, const char** text );
46 test_comp_filter_attr( Operation *op, Attribute *a, struct berval *bv,
50 componentFilterValidate(
58 componentFilterMatch (
66 /* FIXME: to be implemented */
73 slapd_ber2cav( struct berval* bv, ComponentAssertionValue* cav)
77 len = ldap_pvt_filter_value_unescape( bv->bv_val );
78 cav->cav_ptr = cav->cav_buf = bv->bv_val;
79 cav->cav_end = bv->bv_val + len;
83 get_comp_filter ( Operation* op, struct berval* bv, ComponentFilter** filt,
86 ComponentAssertionValue cav;
88 Debug( LDAP_DEBUG_FILTER, "get_comp_filter\n", 0, 0, 0 );
89 slapd_ber2cav(bv, &cav);
90 rc = parse_comp_filter( op, &cav, filt, text );
91 bv->bv_val = cav.cav_ptr;
96 eat_whsp( ComponentAssertionValue* cav )
98 while ( ( cav->cav_ptr <= cav->cav_end ) && ( *cav->cav_ptr == ' ' ) )
103 cav_cur_len( ComponentAssertionValue* cav )
105 return cav->cav_end - cav->cav_ptr;
109 comp_first_element( ComponentAssertionValue* cav )
112 if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
113 return LDAP_COMP_FILTER_ITEM;
115 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
116 return LDAP_COMP_FILTER_AND;
118 else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
119 return LDAP_COMP_FILTER_OR;
121 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
122 return LDAP_COMP_FILTER_NOT;
125 return LDAP_COMP_FILTER_UNDEFINED;
129 comp_next_element( ComponentAssertionValue* cav )
133 if ( *(cav->cav_ptr) == ',' ) {
134 /* move pointer to the next CA */
136 return comp_first_element( cav );
138 else return LDAP_COMP_FILTER_UNDEFINED;
142 get_comp_filter_list( Operation *op, ComponentAssertionValue *cav,
143 ComponentFilter** f, const char** text )
145 ComponentFilter **new;
151 Debug( LDAP_DEBUG_FILTER, "get_comp_filter_list\n", 0, 0, 0 );
153 for ( tag = comp_first_element( cav ); tag != LDAP_COMP_FILTER_UNDEFINED;
154 tag = comp_next_element( cav ) )
156 err = parse_comp_filter( op, cav, new, text );
157 if ( err != LDAP_SUCCESS )
159 new = &(*new)->cf_next;
164 return( LDAP_SUCCESS );
168 get_componentId( Operation *op, ComponentAssertionValue* cav,
169 ComponentId ** cid, const char** text )
175 type = peek_componentId_type( cav );
177 Debug( LDAP_DEBUG_FILTER, "get_compId [%d]\n", type, 0, 0 );
182 case LDAP_COMPREF_IDENTIFIER :
183 _cid.ci_val.ci_identifier.bv_val = cav->cav_ptr;
184 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
185 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
186 _cid.ci_val.ci_identifier.bv_len = len;
189 case LDAP_COMPREF_FROM_BEGINNING :
190 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
191 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
192 _cid.ci_val.ci_from_beginning = strtol( cav->cav_ptr, NULL, 0 );
195 case LDAP_COMPREF_FROM_END :
196 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
197 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
198 _cid.ci_val.ci_from_end = strtol( cav->cav_ptr, NULL, 0 );
201 case LDAP_COMPREF_COUNT :
202 _cid.ci_val.ci_count = 0;
205 case LDAP_COMPREF_CONTENT :
206 /* FIXEME: yet to be implemented */
208 case LDAP_COMPREF_SELECT :
209 /* FIXEME: yet to be implemented */
211 case LDAP_COMPREF_ALL :
212 _cid.ci_val.ci_all = '*';
214 Debug( LDAP_DEBUG_FILTER, "get_compId : ALL\n", 0, 0, 0 );
217 return LDAP_COMPREF_UNDEFINED;
220 *cid = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx );
226 peek_componentId_type( ComponentAssertionValue* cav )
229 if ( cav->cav_ptr[0] == '-' )
230 return LDAP_COMPREF_FROM_END;
231 else if ( cav->cav_ptr[0] == '(' )
232 return LDAP_COMPREF_SELECT;
233 else if ( cav->cav_ptr[0] == '*' )
234 return LDAP_COMPREF_ALL;
235 else if ( cav->cav_ptr[0] == '0' )
236 return LDAP_COMPREF_COUNT;
237 else if ( cav->cav_ptr[0] > '0' && cav->cav_ptr[0] <= '9' )
238 return LDAP_COMPREF_FROM_BEGINNING;
239 else if ( (cav->cav_end - cav->cav_ptr) >= 7 &&
240 strncmp(cav->cav_ptr,"content",7) == 0 )
241 return LDAP_COMPREF_CONTENT;
242 else if ( cav->cav_ptr[0] >= 'a' && cav->cav_ptr[0] <= 'z' )
243 return LDAP_COMPREF_IDENTIFIER;
245 return LDAP_COMPREF_UNDEFINED;
249 comp_next_id( ComponentAssertionValue* cav )
252 if ( *(cav->cav_ptr) == '.' ) {
254 return LDAP_COMPREF_DEFINED;
256 else return LDAP_COMPREF_UNDEFINED;
260 get_component_reference( Operation *op, ComponentAssertionValue* cav,
261 ComponentReference** cr, const char** text )
265 ComponentReference* ca_comp_ref;
266 ComponentId** cr_list;
270 op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx );
272 cr_list = &ca_comp_ref->cr_list;
273 strip_cav_str( cav, "\"");
274 for ( type = peek_componentId_type( cav ) ; type != LDAP_COMPREF_UNDEFINED
275 ; type = comp_next_id( cav ), count++ ) {
276 rc = get_componentId( op, cav, cr_list, text );
277 if ( rc == LDAP_SUCCESS ) {
278 if ( count == 0 ) ca_comp_ref->cr_curr = ca_comp_ref->cr_list;
279 cr_list = &(*cr_list)->ci_next;
282 ca_comp_ref->cr_len = count;
283 strip_cav_str( cav, "\"");
285 if ( rc == LDAP_SUCCESS ) {
289 else op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
295 get_ca_use_default( Operation *op, ComponentAssertionValue* cav,
296 int* ca_use_def, const char** text )
299 if ( peek_cav_str( cav, "useDefaultValues" ) == LDAP_SUCCESS ) {
300 strip_cav_str( cav, "useDefaultValues" );
301 if ( peek_cav_str( cav, "TRUE" ) == LDAP_SUCCESS ) {
302 strip_cav_str( cav, "TRUE" );
305 else if ( peek_cav_str( cav, "FALSE" ) == LDAP_SUCCESS ) {
306 strip_cav_str( cav, "FALSE" );
310 return LDAP_INVALID_SYNTAX;
312 else /* If not defined, default value is TRUE */
318 get_matching_rule( Operation *op, ComponentAssertionValue* cav,
319 MatchingRule** mr, const char** text )
323 struct berval rule_text = { 0L, NULL };
327 for ( ; ; count++ ) {
328 if ( cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == ',' ||
329 cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == '{' ||
330 cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '\n' )
335 *text = "component matching rule not recognized";
336 return LDAP_INAPPROPRIATE_MATCHING;
339 rule_text.bv_len = count;
340 rule_text.bv_val = cav->cav_ptr;
341 *mr = mr_bvfind( &rule_text );
342 cav->cav_ptr += count;
343 Debug( LDAP_DEBUG_FILTER, "get_matching_rule: %s\n", (*mr)->smr_mrule.mr_oid, 0, 0 );
345 *text = "component matching rule not recognized";
346 return LDAP_INAPPROPRIATE_MATCHING;
352 get_GSER_value( ComponentAssertionValue* cav, struct berval* bv )
358 * Four cases of GSER <Values>
360 * StringVal, GeneralizedTimeVal, UTCTimeVal, ObjectDescriptorVal
361 * 2) '...'B or '...'H :
362 * BitStringVal, OctetStringVal
364 * SEQUENCE, SEQUENCEOF, SETOF, SET, CHOICE
365 * 4) Between two white spaces
366 * INTEGER, BOOLEAN, NULL,ENUMERATE, etc
369 if ( cav->cav_ptr[0] == '"' ) {
370 for( count = 0 ; ; count++ ) {
371 if ( cav->cav_ptr[count] == '\0' ||
372 ( cav->cav_ptr[count] == '"' && cav->cav_ptr[count-1] != '"') )
376 else if ( cav->cav_ptr[0] == '\'' ) {
377 for( count = 0 ; ; count++ ) {
378 if ( cav->cav_ptr[count] == '\0' ||
379 (cav->cav_ptr[count] == '\'' && cav->cav_ptr[count] == 'B')||
380 (cav->cav_ptr[count] == '\'' && cav->cav_ptr[count] == 'H') )
385 else if ( cav->cav_ptr[0] == '{' ) {
386 for( count = 0 ; ; count++ ) {
387 if ( cav->cav_ptr[count] == '\0' ||
388 (cav->cav_ptr[count] == '}' && cav->cav_ptr[count] == ' ') )
393 for( count = 0 ; ; count++ ) {
394 if ( cav->cav_ptr[count] == ' ')
399 bv->bv_val = cav->cav_ptr;
401 cav->cav_ptr += count;
405 get_matching_value( Operation *op, ComponentAssertion* ca,
406 ComponentAssertionValue* cav, struct berval* bv,
412 if ( !(ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT)) ) {
413 get_GSER_value( cav, bv );
416 /* embeded componentFilterMatch Description */
417 bv->bv_val = cav->cav_ptr;
418 bv->bv_len = cav_cur_len( cav );
424 /* Don't move the position pointer, just peek given string */
426 peek_cav_str( ComponentAssertionValue* cav, char* str )
429 if ( cav_cur_len( cav ) >= strlen( str ) &&
430 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 )
433 return LDAP_INVALID_SYNTAX;
437 strip_cav_str( ComponentAssertionValue* cav, char* str)
440 if ( cav_cur_len( cav ) >= strlen( str ) &&
441 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 ) {
442 cav->cav_ptr += strlen( str );
446 return LDAP_INVALID_SYNTAX;
450 * TAG : "item", "and", "or", "not"
453 strip_cav_tag( ComponentAssertionValue* cav )
457 if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
458 strip_cav_str( cav , "item:" );
459 return LDAP_COMP_FILTER_ITEM;
461 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
462 strip_cav_str( cav , "and:" );
463 return LDAP_COMP_FILTER_AND;
465 else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
466 strip_cav_str( cav , "or:" );
467 return LDAP_COMP_FILTER_OR;
469 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
470 strip_cav_str( cav , "not:" );
471 return LDAP_COMP_FILTER_NOT;
478 * when encoding, "item" is denotation of ComponentAssertion
479 * ComponentAssertion :: SEQUENCE {
480 * component ComponentReference (SIZE(1..MAX)) OPTIONAL,
481 * useDefaultValues BOOLEAN DEFAULT TRUE,
482 * rule MATCHING-RULE.&id,
483 * value MATCHING-RULE.&AssertionType }
486 get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca,
490 ComponentAssertion* _ca;
492 Debug( LDAP_DEBUG_FILTER, "get_item: %s\n", 0, 0, 0 );
493 _ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
495 rc = peek_cav_str( cav, "component" );
496 if ( rc == LDAP_SUCCESS ) {
497 strip_cav_str( cav, "component" );
498 rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text );
499 if ( rc != LDAP_SUCCESS ) {
500 rc = LDAP_INVALID_SYNTAX;
501 op->o_tmpfree( _ca, op->o_tmpmemctx );
506 strip_cav_str( cav,",");
507 rc = peek_cav_str( cav, "useDefaultValues");
508 if ( rc == LDAP_SUCCESS ) {
509 rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text );
510 if ( rc != LDAP_SUCCESS ) {
511 rc = LDAP_INVALID_SYNTAX;
512 op->o_tmpfree( _ca, op->o_tmpmemctx );
517 if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS &&
518 get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) {
519 rc = LDAP_INAPPROPRIATE_MATCHING;
520 op->o_tmpfree( _ca, op->o_tmpmemctx );
524 strip_cav_str( cav,",");
525 if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS &&
526 get_matching_value( op, _ca, cav, &_ca->ca_ma_value,text ) == LDAP_SUCCESS )) {
527 rc = LDAP_INVALID_SYNTAX;
528 op->o_tmpfree( _ca, op->o_tmpmemctx );
532 /* componentFilterMatch contains componentFilterMatch in it */
533 if ( _ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT) ) {
535 bv.bv_val = cav->cav_ptr;
536 bv.bv_len = cav_cur_len( cav );
537 rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text );
538 if ( rc != LDAP_SUCCESS ) {
539 op->o_tmpfree( _ca, op->o_tmpmemctx );
542 cav->cav_ptr = bv.bv_val;
543 assert( cav->cav_end >= bv.bv_val );
551 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
552 ComponentFilter** filt, const char** text )
555 * A component filter looks like this coming in:
556 * Filter ::= CHOICE {
557 * item [0] ComponentAssertion,
558 * and [1] SEQUENCE OF ComponentFilter,
559 * or [2] SEQUENCE OF ComponentFilter,
560 * not [3] ComponentFilter,
568 /* TAG : item, and, or, not in RFC 2254 */
569 tag = strip_cav_tag( cav );
571 if ( tag == LBER_ERROR ) {
572 *text = "error decoding comp filter";
573 return LDAP_PROTOCOL_ERROR;
576 if ( tag != LDAP_COMP_FILTER_NOT )
577 strip_cav_str( cav, "{");
584 switch ( f.cf_choice ) {
585 case LDAP_COMP_FILTER_AND:
586 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_AND\n", 0, 0, 0 );
587 err = get_comp_filter_list( op, cav, &f.cf_and, text );
588 if ( err != LDAP_SUCCESS ) {
591 if ( f.cf_and == NULL ) {
592 f.cf_choice = SLAPD_FILTER_COMPUTED;
593 f.cf_result = LDAP_COMPARE_TRUE;
597 case LDAP_COMP_FILTER_OR:
598 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_OR\n", 0, 0, 0 );
599 err = get_comp_filter_list( op, cav, &f.cf_or, text );
600 if ( err != LDAP_SUCCESS ) {
603 if ( f.cf_or == NULL ) {
604 f.cf_choice = SLAPD_FILTER_COMPUTED;
605 f.cf_result = LDAP_COMPARE_FALSE;
607 /* no assert - list could be empty */
610 case LDAP_COMP_FILTER_NOT:
611 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_NOT\n", 0, 0, 0 );
612 err = parse_comp_filter( op, cav, &f.cf_not, text );
613 if ( err != LDAP_SUCCESS ) {
617 assert( f.cf_not != NULL );
618 if ( f.cf_not->cf_choice == SLAPD_FILTER_COMPUTED ) {
619 int fresult = f.cf_not->cf_result;
620 f.cf_choice = SLAPD_FILTER_COMPUTED;
621 op->o_tmpfree( f.cf_not, op->o_tmpmemctx );
625 case LDAP_COMPARE_TRUE:
626 f.cf_result = LDAP_COMPARE_FALSE;
628 case LDAP_COMPARE_FALSE:
629 f.cf_result = LDAP_COMPARE_TRUE;
632 /* (!Undefined) is Undefined */
637 case LDAP_COMP_FILTER_ITEM:
638 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_ITEM\n", 0, 0, 0 );
639 err = get_item( op, cav, &f.cf_ca, text );
640 if ( err != LDAP_SUCCESS ) {
644 assert( f.cf_ca != NULL );
648 f.cf_choice = SLAPD_FILTER_COMPUTED;
649 f.cf_result = SLAPD_COMPARE_UNDEFINED;
653 if ( tag != LDAP_COMP_FILTER_NOT )
654 strip_cav_str( cav, "}");
656 if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) {
658 f.cf_choice = SLAPD_FILTER_COMPUTED;
659 f.cf_result = SLAPD_COMPARE_UNDEFINED;
663 if ( err == LDAP_SUCCESS ) {
664 *filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx );
672 test_comp_filter_and(
676 ComponentFilter *flist )
679 int rtn = LDAP_COMPARE_TRUE;
681 for ( f = flist ; f != NULL; f = f->cf_next ) {
682 int rc = test_comp_filter_attr( op, a, bv, f );
683 if ( rc == LDAP_COMPARE_FALSE ) {
688 if ( rc != LDAP_COMPARE_TRUE ) {
701 ComponentFilter *flist )
704 int rtn = LDAP_COMPARE_TRUE;
706 for ( f = flist ; f != NULL; f = f->cf_next ) {
707 int rc = test_comp_filter_attr( op, a, bv, f );
708 if ( rc == LDAP_COMPARE_TRUE ) {
713 if ( rc != LDAP_COMPARE_FALSE ) {
722 * Convert attribute value to C internal data structure
723 * This function has an associated ASN.1 type
724 * bv must contain the value for the type( type name is T1 )
725 * This function is linked to ssyn_attr2comp
729 * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE
732 test_comp_filter_item(
736 ComponentAssertion *ca )
738 int rc = LDAP_COMPARE_TRUE;
740 ComponentSyntaxInfo* csi_attr, *csi_assert;
742 if ( (ca->ca_ma_rule->smr_usage & SLAP_MR_COMPONENT) && ca->ca_cf ) {
743 /* componentFilterMatch inside of componentFilterMatch */
744 rc = test_comp_filter_attr( op, a, bv, ca->ca_cf );
748 assert( !(ca->ca_ma_rule->smr_usage & SLAP_MR_COMPONENT) );
749 /* FIXME : Return ALWAYS true */
750 return LDAP_COMPARE_TRUE;
754 * If matched, LDAP_COMPARE_TRUE is returned
757 test_comp_filter_entry(
760 MatchingRuleAssertion *mra )
765 mra->ma_cf->cf_ca->ca_mra = mra;
767 Debug( LDAP_DEBUG_FILTER, "test_comp_filter_entry\n", 0, 0, 0 );
768 if ( mra->ma_desc ) {
770 * ma_desc is available, so filtering for one attribute
771 * SEARCH permissionc can be checked directly
773 if ( !access_allowed( op, e, mra->ma_desc,
774 &mra->ma_value, ACL_SEARCH, NULL ) )
776 return LDAP_INSUFFICIENT_ACCESS;
778 /* Find attributes that componentFilter Match can be applied to */
779 for( a=attrs_find( e->e_attrs, mra->ma_desc );
781 a = attrs_find( a->a_next, mra->ma_desc ) )
783 struct berval *bv = a->a_vals;
785 for ( ; bv->bv_val != NULL ; bv++ ) {
788 rc = test_comp_filter_attr( op, a, bv, mra->ma_cf );
789 if ( rc == LDAP_COMPARE_TRUE ) return rc;
795 * No attribute description : test all
797 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
798 struct berval *bv, value;
799 const char *text = NULL;
802 /* check if matching is appropriate */
803 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type
808 /* check search access */
809 if ( !access_allowed( op, e,
810 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
816 for ( ; bv->bv_val != NULL ; bv++ ) {
819 rc = test_comp_filter_attr( op, a, bv, mra->ma_cf );
820 if ( rc == LDAP_COMPARE_TRUE ) break;
822 if ( rc != LDAP_SUCCESS ) return rc;
826 return LDAP_COMPARE_FALSE;
830 test_comp_filter_attr(
838 Debug( LDAP_DEBUG_FILTER, "test_comp_filter_attr\n", 0, 0, 0 );
839 switch ( f->cf_choice ) {
840 case SLAPD_FILTER_COMPUTED:
843 case LDAP_COMP_FILTER_AND:
844 rc = test_comp_filter_and( op, a, bv, f->cf_and );
846 case LDAP_COMP_FILTER_OR:
847 rc = test_comp_filter_or( op, a, bv, f->cf_or );
849 case LDAP_COMP_FILTER_NOT:
850 rc = test_comp_filter_attr( op, a, bv, f->cf_not );
853 case LDAP_COMPARE_TRUE:
854 rc = LDAP_COMPARE_FALSE;
856 case LDAP_COMPARE_FALSE:
857 rc = LDAP_COMPARE_TRUE;
861 case LDAP_COMP_FILTER_ITEM:
862 rc = test_comp_filter_item( op, a, bv, f->cf_ca );
865 rc = LDAP_PROTOCOL_ERROR;