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>
27 #ifdef LDAP_COMP_MATCH
32 peek_componentId_type( ComponentAssertionValue* cav );
35 strip_cav_str( ComponentAssertionValue* cav, char* str);
38 peek_cav_str( ComponentAssertionValue* cav, char* str );
41 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
42 ComponentFilter** filt, const char** text );
45 test_comp_filter_attr( Operation *op, Attribute *a, struct berval *bv,
49 componentFilterValidate(
57 componentFilterMatch (
65 /* FIXME: to be implemented */
72 slapd_ber2cav( struct berval* bv, ComponentAssertionValue* cav)
76 len = ldap_pvt_filter_value_unescape( bv->bv_val );
77 cav->cav_ptr = cav->cav_buf = bv->bv_val;
78 cav->cav_end = bv->bv_val + len;
82 get_comp_filter ( Operation* op, struct berval* bv, ComponentFilter** filt,
85 ComponentAssertionValue cav;
87 Debug( LDAP_DEBUG_FILTER, "get_comp_filter\n", 0, 0, 0 );
88 slapd_ber2cav(bv, &cav);
89 rc = parse_comp_filter( op, &cav, filt, text );
90 bv->bv_val = cav.cav_ptr;
95 eat_whsp( ComponentAssertionValue* cav )
97 while ( ( cav->cav_ptr <= cav->cav_end ) && ( *cav->cav_ptr == ' ' ) )
102 cav_cur_len( ComponentAssertionValue* cav )
104 return cav->cav_end - cav->cav_ptr;
108 comp_first_element( ComponentAssertionValue* cav )
111 if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
112 return LDAP_COMP_FILTER_ITEM;
114 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
115 return LDAP_COMP_FILTER_AND;
117 else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
118 return LDAP_COMP_FILTER_OR;
120 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
121 return LDAP_COMP_FILTER_NOT;
124 return LDAP_COMP_FILTER_UNDEFINED;
128 comp_next_element( ComponentAssertionValue* cav )
132 if ( *(cav->cav_ptr) == ',' ) {
133 /* move pointer to the next CA */
135 return comp_first_element( cav );
137 else return LDAP_COMP_FILTER_UNDEFINED;
141 get_comp_filter_list( Operation *op, ComponentAssertionValue *cav,
142 ComponentFilter** f, const char** text )
144 ComponentFilter **new;
150 Debug( LDAP_DEBUG_FILTER, "get_comp_filter_list\n", 0, 0, 0 );
152 for ( tag = comp_first_element( cav ); tag != LDAP_COMP_FILTER_UNDEFINED;
153 tag = comp_next_element( cav ) )
155 err = parse_comp_filter( op, cav, new, text );
156 if ( err != LDAP_SUCCESS )
158 new = &(*new)->cf_next;
163 return( LDAP_SUCCESS );
167 get_componentId( Operation *op, ComponentAssertionValue* cav,
168 ComponentId ** cid, const char** text )
174 type = peek_componentId_type( cav );
176 Debug( LDAP_DEBUG_FILTER, "get_compId [%d]\n", type, 0, 0 );
181 case LDAP_COMPREF_IDENTIFIER :
182 _cid.ci_val.ci_identifier.bv_val = cav->cav_ptr;
183 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
184 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
185 _cid.ci_val.ci_identifier.bv_len = len;
188 case LDAP_COMPREF_FROM_BEGINNING :
189 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
190 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
191 _cid.ci_val.ci_from_beginning = strtol( cav->cav_ptr, NULL, 0 );
194 case LDAP_COMPREF_FROM_END :
195 for( ;cav->cav_ptr[len] != ' ' && cav->cav_ptr[len] != '\0' &&
196 cav->cav_ptr[len] != '.' && cav->cav_ptr[len] != '\"' ; len++ );
197 _cid.ci_val.ci_from_end = strtol( cav->cav_ptr, NULL, 0 );
200 case LDAP_COMPREF_COUNT :
201 _cid.ci_val.ci_count = 0;
204 case LDAP_COMPREF_CONTENT :
205 /* FIXEME: yet to be implemented */
207 case LDAP_COMPREF_SELECT :
208 /* FIXEME: yet to be implemented */
210 case LDAP_COMPREF_ALL :
211 _cid.ci_val.ci_all = '*';
213 Debug( LDAP_DEBUG_FILTER, "get_compId : ALL\n", 0, 0, 0 );
216 return LDAP_COMPREF_UNDEFINED;
219 *cid = op->o_tmpalloc( sizeof( ComponentId ), op->o_tmpmemctx );
225 peek_componentId_type( ComponentAssertionValue* cav )
228 if ( cav->cav_ptr[0] == '-' )
229 return LDAP_COMPREF_FROM_END;
230 else if ( cav->cav_ptr[0] == '(' )
231 return LDAP_COMPREF_SELECT;
232 else if ( cav->cav_ptr[0] == '*' )
233 return LDAP_COMPREF_ALL;
234 else if ( cav->cav_ptr[0] == '0' )
235 return LDAP_COMPREF_COUNT;
236 else if ( cav->cav_ptr[0] > '0' && cav->cav_ptr[0] <= '9' )
237 return LDAP_COMPREF_FROM_BEGINNING;
238 else if ( (cav->cav_end - cav->cav_ptr) >= 7 &&
239 strncmp(cav->cav_ptr,"content",7) == 0 )
240 return LDAP_COMPREF_CONTENT;
241 else if ( cav->cav_ptr[0] >= 'a' && cav->cav_ptr[0] <= 'z' )
242 return LDAP_COMPREF_IDENTIFIER;
244 return LDAP_COMPREF_UNDEFINED;
248 comp_next_id( ComponentAssertionValue* cav )
251 if ( *(cav->cav_ptr) == '.' ) {
253 return LDAP_COMPREF_DEFINED;
255 else return LDAP_COMPREF_UNDEFINED;
259 get_component_reference( Operation *op, ComponentAssertionValue* cav,
260 ComponentReference** cr, const char** text )
264 ComponentReference* ca_comp_ref;
265 ComponentId** cr_list;
269 op->o_tmpalloc( sizeof( ComponentReference ), op->o_tmpmemctx );
271 cr_list = &ca_comp_ref->cr_list;
272 strip_cav_str( cav, "\"");
273 for ( type = peek_componentId_type( cav ) ; type != LDAP_COMPREF_UNDEFINED
274 ; type = comp_next_id( cav ), count++ ) {
275 rc = get_componentId( op, cav, cr_list, text );
276 if ( rc == LDAP_SUCCESS ) {
277 if ( count == 0 ) ca_comp_ref->cr_curr = ca_comp_ref->cr_list;
278 cr_list = &(*cr_list)->ci_next;
281 ca_comp_ref->cr_len = count;
282 strip_cav_str( cav, "\"");
284 if ( rc == LDAP_SUCCESS ) {
288 else op->o_tmpfree( ca_comp_ref , op->o_tmpmemctx );
294 get_ca_use_default( Operation *op, ComponentAssertionValue* cav,
295 int* ca_use_def, const char** text )
298 if ( peek_cav_str( cav, "useDefaultValues" ) == LDAP_SUCCESS ) {
299 strip_cav_str( cav, "useDefaultValues" );
300 if ( peek_cav_str( cav, "TRUE" ) == LDAP_SUCCESS ) {
301 strip_cav_str( cav, "TRUE" );
304 else if ( peek_cav_str( cav, "FALSE" ) == LDAP_SUCCESS ) {
305 strip_cav_str( cav, "FALSE" );
309 return LDAP_INVALID_SYNTAX;
311 else /* If not defined, default value is TRUE */
317 get_matching_rule( Operation *op, ComponentAssertionValue* cav,
318 MatchingRule** mr, const char** text )
322 struct berval rule_text = { 0L, NULL };
326 for ( ; ; count++ ) {
327 if ( cav->cav_ptr[count] == ' ' || cav->cav_ptr[count] == ',' ||
328 cav->cav_ptr[count] == '\0' || cav->cav_ptr[count] == '{' ||
329 cav->cav_ptr[count] == '}' || cav->cav_ptr[count] == '\n' )
334 *text = "component matching rule not recognized";
335 return LDAP_INAPPROPRIATE_MATCHING;
338 rule_text.bv_len = count;
339 rule_text.bv_val = cav->cav_ptr;
340 *mr = mr_bvfind( &rule_text );
341 cav->cav_ptr += count;
342 Debug( LDAP_DEBUG_FILTER, "get_matching_rule: %s\n", (*mr)->smr_mrule.mr_oid, 0, 0 );
344 *text = "component matching rule not recognized";
345 return LDAP_INAPPROPRIATE_MATCHING;
351 get_GSER_value( ComponentAssertionValue* cav, struct berval* bv )
357 * Four cases of GSER <Values>
359 * StringVal, GeneralizedTimeVal, UTCTimeVal, ObjectDescriptorVal
360 * 2) '...'B or '...'H :
361 * BitStringVal, OctetStringVal
363 * SEQUENCE, SEQUENCEOF, SETOF, SET, CHOICE
364 * 4) Between two white spaces
365 * INTEGER, BOOLEAN, NULL,ENUMERATE, etc
368 if ( cav->cav_ptr[0] == '"' ) {
369 for( count = 0 ; ; count++ ) {
370 if ( cav->cav_ptr[count] == '\0' ||
371 ( cav->cav_ptr[count] == '"' && cav->cav_ptr[count-1] != '"') )
375 else if ( cav->cav_ptr[0] == '\'' ) {
376 for( count = 0 ; ; count++ ) {
377 if ( cav->cav_ptr[count] == '\0' ||
378 (cav->cav_ptr[count] == '\'' && cav->cav_ptr[count] == 'B')||
379 (cav->cav_ptr[count] == '\'' && cav->cav_ptr[count] == 'H') )
384 else if ( cav->cav_ptr[0] == '{' ) {
385 for( count = 0 ; ; count++ ) {
386 if ( cav->cav_ptr[count] == '\0' ||
387 (cav->cav_ptr[count] == '}' && cav->cav_ptr[count] == ' ') )
392 for( count = 0 ; ; count++ ) {
393 if ( cav->cav_ptr[count] == ' ')
398 bv->bv_val = cav->cav_ptr;
400 cav->cav_ptr += count;
404 get_matching_value( Operation *op, ComponentAssertion* ca,
405 ComponentAssertionValue* cav, struct berval* bv,
411 if ( !(ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT)) ) {
412 get_GSER_value( cav, bv );
415 /* embeded componentFilterMatch Description */
416 bv->bv_val = cav->cav_ptr;
417 bv->bv_len = cav_cur_len( cav );
423 /* Don't move the position pointer, just peek given string */
425 peek_cav_str( ComponentAssertionValue* cav, char* str )
428 if ( cav_cur_len( cav ) >= strlen( str ) &&
429 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 )
432 return LDAP_INVALID_SYNTAX;
436 strip_cav_str( ComponentAssertionValue* cav, char* str)
439 if ( cav_cur_len( cav ) >= strlen( str ) &&
440 strncmp( cav->cav_ptr, str, strlen( str ) ) == 0 ) {
441 cav->cav_ptr += strlen( str );
445 return LDAP_INVALID_SYNTAX;
449 * TAG : "item", "and", "or", "not"
452 strip_cav_tag( ComponentAssertionValue* cav )
456 if ( cav_cur_len( cav ) >= 8 && strncmp( cav->cav_ptr, "item", 4 ) == 0 ) {
457 strip_cav_str( cav , "item:" );
458 return LDAP_COMP_FILTER_ITEM;
460 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "and", 3 ) == 0 ) {
461 strip_cav_str( cav , "and:" );
462 return LDAP_COMP_FILTER_AND;
464 else if ( cav_cur_len( cav ) >= 6 && strncmp( cav->cav_ptr, "or" , 2 ) == 0 ) {
465 strip_cav_str( cav , "or:" );
466 return LDAP_COMP_FILTER_OR;
468 else if ( cav_cur_len( cav ) >= 7 && strncmp( cav->cav_ptr, "not", 3 ) == 0 ) {
469 strip_cav_str( cav , "not:" );
470 return LDAP_COMP_FILTER_NOT;
477 * when encoding, "item" is denotation of ComponentAssertion
478 * ComponentAssertion :: SEQUENCE {
479 * component ComponentReference (SIZE(1..MAX)) OPTIONAL,
480 * useDefaultValues BOOLEAN DEFAULT TRUE,
481 * rule MATCHING-RULE.&id,
482 * value MATCHING-RULE.&AssertionType }
485 get_item( Operation *op, ComponentAssertionValue* cav, ComponentAssertion** ca,
489 ComponentAssertion* _ca;
491 Debug( LDAP_DEBUG_FILTER, "get_item: %s\n", 0, 0, 0 );
492 _ca = op->o_tmpalloc( sizeof( ComponentAssertion ), op->o_tmpmemctx );
494 rc = peek_cav_str( cav, "component" );
495 if ( rc == LDAP_SUCCESS ) {
496 strip_cav_str( cav, "component" );
497 rc = get_component_reference( op, cav, &_ca->ca_comp_ref, text );
498 if ( rc != LDAP_SUCCESS ) {
499 rc = LDAP_INVALID_SYNTAX;
500 op->o_tmpfree( _ca, op->o_tmpmemctx );
505 strip_cav_str( cav,",");
506 rc = peek_cav_str( cav, "useDefaultValues");
507 if ( rc == LDAP_SUCCESS ) {
508 rc = get_ca_use_default( op, cav, &_ca->ca_use_def, text );
509 if ( rc != LDAP_SUCCESS ) {
510 rc = LDAP_INVALID_SYNTAX;
511 op->o_tmpfree( _ca, op->o_tmpmemctx );
516 if ( !( strip_cav_str( cav, "rule" ) == LDAP_SUCCESS &&
517 get_matching_rule( op, cav , &_ca->ca_ma_rule, text ) == LDAP_SUCCESS )) {
518 rc = LDAP_INAPPROPRIATE_MATCHING;
519 op->o_tmpfree( _ca, op->o_tmpmemctx );
523 strip_cav_str( cav,",");
524 if ( !(strip_cav_str( cav, "value" ) == LDAP_SUCCESS &&
525 get_matching_value( op, _ca, cav, &_ca->ca_ma_value,text ) == LDAP_SUCCESS )) {
526 rc = LDAP_INVALID_SYNTAX;
527 op->o_tmpfree( _ca, op->o_tmpmemctx );
531 /* componentFilterMatch contains componentFilterMatch in it */
532 if ( _ca->ca_ma_rule->smr_usage & (SLAP_MR_COMPONENT) ) {
534 bv.bv_val = cav->cav_ptr;
535 bv.bv_len = cav_cur_len( cav );
536 rc = get_comp_filter( op, &bv,(ComponentFilter**)&_ca->ca_cf, text );
537 if ( rc != LDAP_SUCCESS ) {
538 op->o_tmpfree( _ca, op->o_tmpmemctx );
541 cav->cav_ptr = bv.bv_val;
542 assert( cav->cav_end >= bv.bv_val );
550 parse_comp_filter( Operation* op, ComponentAssertionValue* cav,
551 ComponentFilter** filt, const char** text )
554 * A component filter looks like this coming in:
555 * Filter ::= CHOICE {
556 * item [0] ComponentAssertion,
557 * and [1] SEQUENCE OF ComponentFilter,
558 * or [2] SEQUENCE OF ComponentFilter,
559 * not [3] ComponentFilter,
567 /* TAG : item, and, or, not in RFC 2254 */
568 tag = strip_cav_tag( cav );
570 if ( tag == LBER_ERROR ) {
571 *text = "error decoding comp filter";
572 return LDAP_PROTOCOL_ERROR;
575 if ( tag != LDAP_COMP_FILTER_NOT )
576 strip_cav_str( cav, "{");
583 switch ( f.cf_choice ) {
584 case LDAP_COMP_FILTER_AND:
585 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_AND\n", 0, 0, 0 );
586 err = get_comp_filter_list( op, cav, &f.cf_and, text );
587 if ( err != LDAP_SUCCESS ) {
590 if ( f.cf_and == NULL ) {
591 f.cf_choice = SLAPD_FILTER_COMPUTED;
592 f.cf_result = LDAP_COMPARE_TRUE;
596 case LDAP_COMP_FILTER_OR:
597 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_OR\n", 0, 0, 0 );
598 err = get_comp_filter_list( op, cav, &f.cf_or, text );
599 if ( err != LDAP_SUCCESS ) {
602 if ( f.cf_or == NULL ) {
603 f.cf_choice = SLAPD_FILTER_COMPUTED;
604 f.cf_result = LDAP_COMPARE_FALSE;
606 /* no assert - list could be empty */
609 case LDAP_COMP_FILTER_NOT:
610 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_NOT\n", 0, 0, 0 );
611 err = parse_comp_filter( op, cav, &f.cf_not, text );
612 if ( err != LDAP_SUCCESS ) {
616 assert( f.cf_not != NULL );
617 if ( f.cf_not->cf_choice == SLAPD_FILTER_COMPUTED ) {
618 int fresult = f.cf_not->cf_result;
619 f.cf_choice = SLAPD_FILTER_COMPUTED;
620 op->o_tmpfree( f.cf_not, op->o_tmpmemctx );
624 case LDAP_COMPARE_TRUE:
625 f.cf_result = LDAP_COMPARE_FALSE;
627 case LDAP_COMPARE_FALSE:
628 f.cf_result = LDAP_COMPARE_TRUE;
631 /* (!Undefined) is Undefined */
636 case LDAP_COMP_FILTER_ITEM:
637 Debug( LDAP_DEBUG_FILTER, "LDAP_COMP_FILTER_ITEM\n", 0, 0, 0 );
638 err = get_item( op, cav, &f.cf_ca, text );
639 if ( err != LDAP_SUCCESS ) {
643 assert( f.cf_ca != NULL );
647 f.cf_choice = SLAPD_FILTER_COMPUTED;
648 f.cf_result = SLAPD_COMPARE_UNDEFINED;
652 if ( tag != LDAP_COMP_FILTER_NOT )
653 strip_cav_str( cav, "}");
655 if ( err != LDAP_SUCCESS && err != SLAPD_DISCONNECT ) {
657 f.cf_choice = SLAPD_FILTER_COMPUTED;
658 f.cf_result = SLAPD_COMPARE_UNDEFINED;
662 if ( err == LDAP_SUCCESS ) {
663 *filt = op->o_tmpalloc( sizeof(f), op->o_tmpmemctx );
671 test_comp_filter_and(
675 ComponentFilter *flist )
678 int rtn = LDAP_COMPARE_TRUE;
680 for ( f = flist ; f != NULL; f = f->cf_next ) {
681 int rc = test_comp_filter_attr( op, a, bv, f );
682 if ( rc == LDAP_COMPARE_FALSE ) {
687 if ( rc != LDAP_COMPARE_TRUE ) {
700 ComponentFilter *flist )
703 int rtn = LDAP_COMPARE_TRUE;
705 for ( f = flist ; f != NULL; f = f->cf_next ) {
706 int rc = test_comp_filter_attr( op, a, bv, f );
707 if ( rc == LDAP_COMPARE_TRUE ) {
712 if ( rc != LDAP_COMPARE_FALSE ) {
721 * Convert attribute value to C internal data structure
722 * This function has an associated ASN.1 type
723 * bv must contain the value for the type( type name is T1 )
724 * This function is linked to ssyn_attr2comp
728 * return codes : LDAP_COMPARE_TRUE, LDAP_COMPARE_FALSE
731 test_comp_filter_item(
735 ComponentAssertion *ca )
737 int rc = LDAP_COMPARE_TRUE;
739 ComponentSyntaxInfo* csi_attr, *csi_assert;
741 if ( (ca->ca_ma_rule->smr_usage & SLAP_MR_COMPONENT) && ca->ca_cf ) {
742 /* componentFilterMatch inside of componentFilterMatch */
743 rc = test_comp_filter_attr( op, a, bv, ca->ca_cf );
747 assert( !(ca->ca_ma_rule->smr_usage & SLAP_MR_COMPONENT) );
748 /* FIXME : Return ALWAYS true */
749 return LDAP_COMPARE_TRUE;
753 * If matched, LDAP_COMPARE_TRUE is returned
756 test_comp_filter_entry(
759 MatchingRuleAssertion *mra )
764 mra->ma_cf->cf_ca->ca_mra = mra;
766 Debug( LDAP_DEBUG_FILTER, "test_comp_filter_entry\n", 0, 0, 0 );
767 if ( mra->ma_desc ) {
769 * ma_desc is available, so filtering for one attribute
770 * SEARCH permissionc can be checked directly
772 if ( !access_allowed( op, e, mra->ma_desc,
773 &mra->ma_value, ACL_SEARCH, NULL ) )
775 return LDAP_INSUFFICIENT_ACCESS;
777 /* Find attributes that componentFilter Match can be applied to */
778 for( a=attrs_find( e->e_attrs, mra->ma_desc );
780 a = attrs_find( a->a_next, mra->ma_desc ) )
782 struct berval *bv = a->a_vals;
784 for ( ; bv->bv_val != NULL ; bv++ ) {
787 rc = test_comp_filter_attr( op, a, bv, mra->ma_cf );
788 if ( rc == LDAP_COMPARE_TRUE ) return rc;
794 * No attribute description : test all
796 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
797 struct berval *bv, value;
798 const char *text = NULL;
801 /* check if matching is appropriate */
802 if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type
807 /* check search access */
808 if ( !access_allowed( op, e,
809 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
815 for ( ; bv->bv_val != NULL ; bv++ ) {
818 rc = test_comp_filter_attr( op, a, bv, mra->ma_cf );
819 if ( rc == LDAP_COMPARE_TRUE ) break;
821 if ( rc != LDAP_SUCCESS ) return rc;
825 return LDAP_COMPARE_FALSE;
829 test_comp_filter_attr(
837 Debug( LDAP_DEBUG_FILTER, "test_comp_filter_attr\n", 0, 0, 0 );
838 switch ( f->cf_choice ) {
839 case SLAPD_FILTER_COMPUTED:
842 case LDAP_COMP_FILTER_AND:
843 rc = test_comp_filter_and( op, a, bv, f->cf_and );
845 case LDAP_COMP_FILTER_OR:
846 rc = test_comp_filter_or( op, a, bv, f->cf_or );
848 case LDAP_COMP_FILTER_NOT:
849 rc = test_comp_filter_attr( op, a, bv, f->cf_not );
852 case LDAP_COMPARE_TRUE:
853 rc = LDAP_COMPARE_FALSE;
855 case LDAP_COMPARE_FALSE:
856 rc = LDAP_COMPARE_TRUE;
860 case LDAP_COMP_FILTER_ITEM:
861 rc = test_comp_filter_item( op, a, bv, f->cf_ca );
864 rc = LDAP_PROTOCOL_ERROR;