diff --git a/doc/susp_aaip_0_2.txt b/doc/susp_aaip_0_2.txt deleted file mode 100644 index 5d69c1be..00000000 --- a/doc/susp_aaip_0_2.txt +++ /dev/null @@ -1,333 +0,0 @@ - - - Arbitrary Attribute Interchange Protocol - - Draft version 0.2 - Dec 19 2008 - - Interchange of Persistent File Attributes - - by Thomas Schmitt - mailto:scdbackup@gmx.net - Libburnia project - mailto:libburn-hackers@pykix.org - - -AAIP is intended as companion of the Rock Ridge Interchange Protocol RRIP -which under the general design of System Use Sharing Protocol SUSP extends -ISO 9660 aka ECMA-119 filesystem semantics to match POSIX needs. - -Goal is to have for each file an arbitrary number of attributes which consist -of two components (Name and Value) of arbitrary length and to have a compact -representation of ACLs. - -This document describes a SUSP field with adjustable name (Signature Word). -The name is defined in an ER field of which the content form is described here. -Recommended is to use the name "AA" which collides neither with SUSP 1.12 nor -with RRIP 1.12. -The field has been designed to be as similar to the RRIP field SL as possible. - -Since the size of a SUSP field is limited to 255, multiple fields may be -needed to describe one component. The CE mechanism of SUSP shall be used to -address enough storage if needed. - -------------------------------------------------------------------------------- - -System Entries Provided by this Specification - -* AA (or another name which does not disturb other co-existing SUSP protocols) - -Description of the "AA" System Use Entry - -This SUSP field and the ER entry of AAIP shall only be present if the ER entry -of RRIP is present. - -The field has exactly the same layout as RRIP field SL. One has to expect -more data bytes than with SL, though, and any of the 256 possible byte values. -The reader shall be prepared to detect and handle oversized data. - -One or more AA fields form the Attribute List of a file object with -an even number of components. Each two consequtive components form a pair of -Name and Value. The empty name is reserved for a compact representation of -ALCs. The meaning of any other name is not specified by this document. - -All AA fields except the last one shall have the CONTINUE flag set. An AA -field with CONTINUE set to 0 indicates the end of the Attribute List. - -The format of the "AA" System Use Field is as follows: - - [1] "BP 1 to BP 2 - Signature Word" shall be (41)(41) ("AA") resp. the word - that is defined in the ER field. See below. - - [2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of - the "AA" entry recorded according to ISO 9660:7.1.1. - - [3] "BP 4 - System Use Entry Version" shall be 1 as in ISO 9660:7.1.1. - - [4] "BP 5 - Flags" shall contain bit field flags numbered 0 to 7 starting - with the least significant bit as follows: - 0 CONTINUE This AA field continues in the next AA field. - All other bits shall be set to 0. - - [5] "BP 6 to Length - Component Area" shall contain Component Records - as described below. - - | 'A' | 'A' | LENGTH | 1 | FLAGS | COMPONENT AREA | - - -Within "AA" fields each component (Name or Value) shall be recorded as one -or more component records. If a component does not fit into the remaining -space of an AA field then it shall be continued in following AA fields. - -All Component Records of a component except the last one shall have the -CONTINUE flag set. A Component Record with CONTINUE set to 0 indicates the end -of the component. An eventually following Component Record starts the next -component. - -------------------------------------------------------------------------------- - -The Component Record format is identical to the one of the SL field. -The complete form of the following summary can be found in RRIP 1.12 "4.1.3.1". -In case of discrepancies, RRIP 1.12 is the decisive specification. - -Component Records shall be recorded contiguously within each Component Area, -starting in the first byte of the Component Area. The last Component Record -in the Component Area of an "AA" System Use Entry may be continued in the -Component Area of the next recorded "AA" System Use Entry in the same -System Use Area. - -Each Component Record shall have the following format: - - [A] "BP 1 - Component Flags" shall contain bit field flags numbered 0 to 7, - starting with the least significant bit, as follows: - 0 CONTINUE This Component Record continues in the next - AA Component Record. - The following bits are defined but may not be set if the Component - Record shall carry payload. (Their use case is unclear yet.) - 1 CURRENT This Component Record refers to the current - directory. - 2 PARENT This Component Record refers to the parent of - the current directory. - 3 ROOT This Component Record refers to root directory. - - all others are RESERVED and shall be 0. - - No more than one of "AA" Component Flag Bits 0-3 shall be set to ONE. - - [B] "BP 2 - Component Length (LEN_CP)" shall specify as an 8-bit number the - number of component bytes in the Component Record. This length shall not - include the first two bytes of the Component Record. - If any of the bit positions 1-3 is set, the value of this field shall be - set to ZERO and no Component Content shall be recorded. - This field shall be recorded according to ISO 9660 Format section 7.1.1. - - [C] "BP 3 to 2 + LEN_CP - Component Content" shall contain the component - bytes in the Component Record. - - | COMPONENT FLAGS | LEN_CP | COMPONENT BYTES | - - -Example: Two pairs of "name"="long...content" and "one"="more" encoded as - two AA fields - - Field 1 contains the Component Record of Name and one Component Record of - Value : - { 'A', 'A', 255, 1, 1, - 0, 4, 'n', 'a', 'm', 'e', - 1, 255, 'l', 'o', 'n', 'g', ... 238 more bytes, 13 go to next AA ... } - Field 2 contains the rest of "long...content" and the complete second pair. - It marks the end of the Attribute List : - { 'A', 'A', 38, 1, 0, - ... 13 remaining bytes of the Component Record in first field ... - 0, 7, 'c', 'o', 'n', 't', 'e', 'n', 't', - 0, 3, 'o', 'n', 'e', - 0, 4, 'm', 'o', 'r', 'e' } - -------------------------------------------------------------------------------- - -Specification of binary ACL representation as special Arbitrary Attribute - -The Name component of a binary ACL shall be of length 0. - -The Value shall be an arbitrary number of ACL Entries: - - [a] "BP 1 - Entry Flags" shall contain bit field flags numbered 0 to 7, - starting with the least significant bit, as follows: - 0 EXEC indicates that this entry grants execute permission - 1 WRITE write permission - 2 READ read permission - 3 QUALIFIER indicates that one or more Qualifier Records follow - 4 - 7 TYPE - shall contain the tag type of the ACL entry as four bit code: - 0 TRANSLATE entry for a global map of name to numeric id - 1 ACL_USER_OBJ permissions of owning user (as of PX field) - 2 ACL_USER of arbitrary user, with name as qualifier - 3 ACL_GROUP_OBJ permissions of owning group (as of PX field) - 4 ACL_GROUP of arbitrary group, with name as qualifier - 5 ACL_MASK restricts 2, 3, and 4 via logical AND - 6 ACL_OTHER permissions of non-listed, non-owning users - 8 SWITCH_MARK switch from "access" ACL to "default" ACL - 10 ACL_USER_N like 2, with numeric user id as qualifier - 12 ACL_GROUP_N like 4, with numeric group id as qualifier - 15 FUTURE_VERSION will indicate that this document - does not apply to the entry. - The other values are reserved. Readers shall ignore them if - they are not aware of updates of this document which would - assign a meaning to them. - -If any of ACL_USER_OBJ, ACL_GROUP_OBJ, ACL_OTHER are missing then the settings -from the PX field shall get into effect. If they exist then they shall override -the PX field. - -A numeric qualifier is a binary number of variable length. The Most Significant -Byte comes first. The number shall be the "POSIX File User ID" resp. -"POSIX File Group ID" as also used in RRIP PX fields. The ids of owning user -and owning group shall be taken from the PX field of the file object. - -Optional TRANSLATE entries may associate user or group names with numeric -ids to allow the reading system to remap the numeric ids. See below. -The writer is not obliged to write them and the reader is not obliged to -interpret them. - -The ACL entries belong to the "access" ACL of a file object. An optional -SWITCH_MARK entry may direct further entries to the "default" ACL which -is defined for directory objects. The switching is controlled by the EXEC bit. - 0 "access" ACL - 1 "default" ACL -The bits for WRITE, READ, QUALIFIER shall be 0 with SWITCH_MARK. - -The eventually needed qualifier is stored in one or more Qualifier Records. - - [b] "BP 2 - Qualifier Record Head" shall be present only if QUALIFIER is set - to 1. It shall give the number of Qualifier Bytes and eventually - indicate that the qualifier continues in a Qualifier Record which comes - imediately after this record. - 0 to 127 Q_LENGTH, the qualifier is complete by this record - 128 to 255 Q_LENGTH+128, the qualifier is continued by next record - So a Qualifier Record can contain at most 127 Qualifier Bytes. - This field shall be recorded according to ISO 9660 Format section 7.1.1. - - [c] "BP 3 to BP 2 + Q_LENGTH - Qualifier Bytes" shall be present only if - QUALIFIER is set to 1 and hold the announced number of bytes of the - user or group name. - - | ENTRY FLAGS [ | QUALIFIER HEAD | QUALIFIER BYTES | ] - - -Example: From man 5 acl: u::rw-,u:lisa:rw-,g::r--,g:toolies:rw-,m::r--,o::r-- - { 'A', 'A', 28, 1, 0, - 0, 0, - 0, 19, 0x16, - 0x2E, 4, 'l', 'i', 's', 'a', - 0x34, - 0x4E, 7, 't', 'o', 'o', 'l', 'i', 'e', 's', - 0x54, - 0x64 } - -Example: An entry with very long qualifier u:His_Excellency_..._the_Boss:r-- - 0x2C, 255, 'H', 'i', 's', '_', 'E', 'x', 'c', 'e', 'l', 'e', - ... 117 more bytes ..., - 8, 't', 'h', 'e', '_', 'B', 'o', 's', 's', - -Example: User number 71 in numerical form gets rwx - 0xAF, 1, 71, - Group number 65534 gets r-x - 0xCD, 2, 255, 254, - - -------------------------------------------------------------------------------- - -About Names and Numeric Identifiers - -It makes an important difference whether qualifiers are represented as names -or as id numbers. By storing names (and usually wasting space) it is possible -to control permissions in a way that is portable between uncoordinated -computers as long as the human readable user/group names are present on both -sides. POSIX File ID numbers make most sense in backups which shall be read -by the same system which wrote it. -Rock Ridge can only record POSIX File Ids but not user or group names. - -The entry flag value 0x08 TRANSLATE is not a ACL entry of the hosting object -but rather a global hint about the relation of roles, names and numeric ids. -If it is recorded at all, then it shall be recorded with the first Directory -Entry of the volume's root directory. According to the description of SUSP -field ER, this has to be "dot" or (00). Other than with ER, a TRANSLATE entry -may not appear in the root of directory sub trees. - -An interested reader shall examine the Arbitrary Attributes of this Directory -Entry in order to collect a translation table. -The advised translation is: PX or AA Id number -> name -> local id number. - -The Qualifier Bytes of a TRANSLATE entry shall have the following format: - - [i] "BP 0 - Role" shall tell whether it is about a user name (role 0) or - a group name (role 1). Other values are not allowed. - - [ii] "BP 1 to BP 8 - Numeric Id" shall hold the 32 bit POSIX Id number of the - entry. This field shall be recorded according to ISO 9660:7.3.3. - -[iii] "BP 9 to End Of Qualifier - Name" shall hold the name bytes of this - entry. - - | ROLE | NUMERIC ID | NAME | - -Example: User id number 1001 gets associated with user name "lisa" - - 0x08, 13, 0, 233,3,0,0, 0,0,3,233, 'l', 'i', 's', 'a', - - -------------------------------------------------------------------------------- - -Specification of the ER System Use Entry Values for AAIP: - -This ER system entry shall only be present if the ER entry of RRIP is present. - -The Extension Version number for this version of AAIP shall be 1. - -The Extension Identifier field shall be "AAIP_0002" with Identifier Length 9. - -The mandatory content form of the Extension Descriptor is -"AA PROVIDES VIA AAIP 0.2 SUPPORT FOR ARBITRARY FILE ATTRIBUTES IN ISO 9660 IMAGES" -with possibly two letters other than "AA" at the start of the string. -The Description Length is 81. - -The reader of AAIP shall take the actual name of the AA field from BP 19 and -BP 20 of the ER field. - -The recommended content of the Extension Source is -"PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG". -The corresponding Source Length is 62. - - -------------------------------------------------------------------------------- - -Model Relations: - - Attribute List ------------- [1:0..1] ------------- ACL - [1:0..n] [1:0..n] - Arbitrary Attribute ( [1:0..1] ACL ) Entry - [1:2..2n] [1:0..1] - Component ( [1..m:1..n] AA Field ) Qualifier - [1:1..n] << one of >> - Component Record / \ \ - [1..m:1..n] Translation Entry , Name , Numeric Id - AA Field | | | - [1:1..n] [1:1..n] [1:1] - \ | / - Qualifier Record - -------------------------------------------------------------------------------- -Revoked drafts: - -There was a draft AAIP 0.0 with ER signature "AAIP_2008A". It did not resemble -the existing field SL and therefore shall not be used by writers of ISO images. - -------------------------------------------------------------------------------- -References: - -ECMA-119 http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf - -SUSP 1.12 ftp://ftp.ymi.com/pub/rockridge/susp112.ps - -RRIP 1.12 ftp://ftp.ymi.com/pub/rockridge/rrip112.ps -(especially field SL) - - diff --git a/test/aaip-os-freebsd.c b/test/aaip-os-freebsd.c deleted file mode 100644 index caa28da5..00000000 --- a/test/aaip-os-freebsd.c +++ /dev/null @@ -1,283 +0,0 @@ - -/* - - aaip-os-freebsd.c - Arbitrary Attribute Interchange Protocol , system adapter for getting and - setting of ACLs and XFS-style Extended Attributes. - - To be included by aaip_0_2.c -*/ - -#include -#include -#include -#include -#include -#include - -#include - - -/* ------------------------------ Getters --------------------------------- */ - -/* Obtain the ACL of the given file in long text form. - @param path Path to the file - @param text Will hold the result. This is a managed object which - finally has to be freed by a call to this function - with bit15 of flag. - @param flag Bitfield for control purposes - bit0= obtain default ACL rather than access ACL - bit15= free text and return 1 - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_get_acl_text(char *path, char **text, int flag) -{ - acl_t acl= NULL; - - if(flag & (1 << 15)) { - if(*text != NULL) - acl_free(text); - *text= NULL; - return(1); - } - *text= NULL; - - /* Note: no ACL_TYPE_DEFAULT in FreeBSD */ - if(flag & 1) - return(0); - - acl= acl_get_file(path, ACL_TYPE_ACCESS); - - if(acl == NULL) - return(-1); - *text= acl_to_text(acl, NULL); - acl_free(acl); - if(*text == NULL) - return(-1); - return(1); -} - - -/* Obtain the Extended Attributes and/or the ACLs of the given file in a form - that is ready for aaip_encode(). - - Note: There are no Extended Attributes in FreeBSD. So only ACL will be - obtained. - - @param path Path to the file - @param num_attrs Will return the number of name-value pairs - @param names Will return an array of pointers to 0-terminated names - @param value_lengths Will return an arry with the lenghts of values - @param values Will return an array of pointers to 8-bit values - @param flag Bitfield for control purposes - bit0= obtain ACL (access and eventually default) - bit1= use numeric ACL qualifiers rather than names - bit2= do not encode attributes other than ACL - bit15= free memory of names, value_lengths, values - @return >0 ok - <=0 error -*/ -int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names, - size_t **value_lengths, char ***values, int flag) -{ - int ret, retry= 0; - char *list= NULL; - ssize_t list_size= 0, i, num_names, value_ret; - size_t a_acl_len= 0, d_acl_len= 0, acl_len= 0; - unsigned char *a_acl= NULL, *d_acl= NULL, *acl= NULL; - char *acl_text= NULL; - - if(flag & (1 << 15)) { /* Free memory */ - if(*names != NULL) - list= (*names)[0]; - {ret= 1; goto ex;} - } - - *num_attrs= 0; - *names= NULL; - *value_lengths= NULL; - *values= NULL; - - if(flag & 1) - num_names++; - if(num_names == 0) - {ret= 1; goto ex;} - (*names)= calloc(num_names, sizeof(char *)); - (*value_lengths)= calloc(num_names, sizeof(size_t)); - (*values)= calloc(num_names, sizeof(char *)); - if(*names == NULL || *value_lengths == NULL || *values == NULL) - {ret= -1; goto ex;} - - for(i= *num_attrs; i < num_names; i++) - (*names)[i]= NULL; - for(i= 0; i < num_names; i++) { - (*values)[i]= NULL; - (*value_lengths)[i]= 0; - } - - if(flag & 1) { /* Obtain ACL */ - /* access-ACL */ - ret= aaip_get_acl_text(path, &acl_text, 0); - if(ret <= 0) - goto ex; - ret= aaip_encode_acl(acl_text, &a_acl_len, &a_acl, flag & 2); - if(ret <= 0) - goto ex; - aaip_get_acl_text("", &acl_text, 1 << 15); /* free */ - - /* Note: There are no default-ACL in FreeBSD */ - - /* Set as attribute with empty name */; - (*names)[*num_attrs]= strdup(""); - if((*names)[*num_attrs] == NULL) - {ret= -1; goto ex;} - (*values)[*num_attrs]= (char *) acl; - (*value_lengths)[*num_attrs]= acl_len; - (*num_attrs)++; - } - - ret= 1; -ex:; - if(a_acl != NULL) - free(a_acl); - if(d_acl != NULL) - free(d_acl); - if(acl_text != NULL) - aaip_get_acl_text("", &acl_text, 1 << 15); /* free */ - - if(ret <= 0 || (flag & (1 << 15))) { - if(list != NULL) - free(list); - if(*names != NULL) - free(*names); - *names= NULL; - if(*value_lengths != NULL) - free(*value_lengths); - *value_lengths= NULL; - if(*values != NULL) { - for(i= 0; i < *num_attrs; i++) - free((*values)[i]); - free(*values); - } - if(acl != NULL) - free(acl); - *values= NULL; - *num_attrs= 0; - } - return(ret); -} - - -/* ------------------------------ Setters --------------------------------- */ - - -/* Set the ACL of the given file to a given list in long text form. - @param path Path to the file - @param text The input text (0 terminated, ACL long text form) - @param flag Bitfield for control purposes - bit0= set default ACL rather than access ACL - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_set_acl_text(char *path, char *text, int flag) -{ - int ret; - acl_t acl= NULL; - - acl= acl_from_text(text); - if(acl == NULL) { - ret= -1; goto ex; - } - - /* Note: no ACL_TYPE_DEFAULT in FreeBSD */ - if(flag & 1) - {ret= 0; goto ex;} - - ret= acl_set_file(path, ACL_TYPE_ACCESS, acl); - - if(ret == -1) - goto ex; - ret= 1; -ex: - if(acl != NULL) - acl_free(acl); - return(ret); -} - - -/* Bring the given attributes and/or ACLs into effect with the given file. - - Note: There are no Extended Attributes in FreeBSD. So only ACL get set. - - @param flag Bitfield for control purposes - bit0= decode and set ACLs - ( bit1= first clear all existing attributes of the file ) - ( bit2= do not set attributes other than ACLs ) - @return 1 success - -1 error memory allocation - -2 error with decoding of ACL - -3 error with setting ACL - ( -4 error with setting attribute ) - ( -5 error with deleting attribute ) - -*/ -int aaip_set_attr_list(char *path, size_t num_attrs, char **names, - size_t *value_lengths, char **values, int flag) -{ - int ret, has_default_acl= 0; - size_t i, consumed, acl_text_fill, list_size= 0; - char *acl_text= NULL, *list= NULL; - - for(i= 0; i < num_attrs; i++) { - if(names[i] == NULL || values[i] == NULL) - continue; - if(names[i][0] == 0) { /* Decode ACLs */ - /* access ACL */ - ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i], - &consumed, NULL, 0, &acl_text_fill, 1); - if(ret <= 0) - {ret= -2; goto ex;} - acl_text= calloc(acl_text_fill, 1); - if(acl_text == NULL) - {ret= -1; goto ex;} - ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i], - &consumed, acl_text, acl_text_fill, &acl_text_fill, 0); - if(ret <= 0) - {ret= -2; goto ex;} - has_default_acl= (ret == 2); - ret= aaip_set_acl_text(path, acl_text, 0); - if(ret <= 0) - {ret= -3; goto ex;} - if(has_default_acl) { - free(acl_text); - acl_text= NULL; - ret= aaip_decode_acl((unsigned char *) (values[i] + consumed), - value_lengths[i] - consumed, &consumed, - NULL, 0, &acl_text_fill, 1); - if(ret <= 0) - {ret= -2; goto ex;} - acl_text= calloc(acl_text_fill, 1); - if(acl_text == NULL) - {ret= -1; goto ex;} - ret= aaip_decode_acl((unsigned char *) (values[i] + consumed), - value_lengths[i] - consumed, &consumed, - acl_text, acl_text_fill, &acl_text_fill, 0); - if(ret <= 0) - {ret= -2; goto ex;} - ret= aaip_set_acl_text(path, acl_text, 1); - if(ret <= 0) - {ret= -3; goto ex;} - } - } - } - ret= 1; -ex:; - if(acl_text != NULL) - free(acl_text); - if(list != NULL) - free(list); - return(ret); -} - - diff --git a/test/aaip-os-linux.c b/test/aaip-os-linux.c deleted file mode 100644 index c0e36e93..00000000 --- a/test/aaip-os-linux.c +++ /dev/null @@ -1,371 +0,0 @@ - -/* - - aaip-os-linux.c - Arbitrary Attribute Interchange Protocol , system adapter for getting and - setting of ACLs and XFS-style Extended Attributes. - - To be included by aaip_0_2.c -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define Aaip_acl_attrnamE "system.posix_acl_access" - - -/* ------------------------------ Getters --------------------------------- */ - -/* Obtain the ACL of the given file in long text form. - @param path Path to the file - @param text Will hold the result. This is a managed object which - finally has to be freed by a call to this function - with bit15 of flag. - @param flag Bitfield for control purposes - bit0= obtain default ACL rather than access ACL - bit15= free text and return 1 - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_get_acl_text(char *path, char **text, int flag) -{ - acl_t acl= NULL; - - if(flag & (1 << 15)) { - if(*text != NULL) - acl_free(text); - *text= NULL; - return(1); - } - *text= NULL; - acl= acl_get_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS); - if(acl == NULL) - return(-1); - *text= acl_to_text(acl, NULL); - acl_free(acl); - if(*text == NULL) - return(-1); - return(1); -} - - -/* Obtain the Extended Attributes and/or the ACLs of the given file in a form - that is ready for aaip_encode(). - @param path Path to the file - @param num_attrs Will return the number of name-value pairs - @param names Will return an array of pointers to 0-terminated names - @param value_lengths Will return an arry with the lenghts of values - @param values Will return an array of pointers to 8-bit values - @param flag Bitfield for control purposes - bit0= obtain ACL (access and eventually default) - bit1= use numeric ACL qualifiers rather than names - bit2= do not obtain attributes other than ACL - bit3= do not ignore eventual local ACL attribute - (e.g. system.posix_acl_access) - bit15= free memory of names, value_lengths, values - @return >0 ok - <=0 error -*/ -int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names, - size_t **value_lengths, char ***values, int flag) -{ - int ret, retry= 0; - char *list= NULL; - ssize_t list_size= 0, i, num_names= 0, value_ret; - size_t a_acl_len= 0, d_acl_len= 0, acl_len= 0; - unsigned char *a_acl= NULL, *d_acl= NULL, *acl= NULL; - char *acl_text= NULL; - - if(flag & (1 << 15)) { /* Free memory */ - if(*names != NULL) - list= (*names)[0]; - {ret= 1; goto ex;} - } - - *num_attrs= 0; - *names= NULL; - *value_lengths= NULL; - *values= NULL; - - /* Set up arrays */ - if(!(flag & 4)) { /* Get xattr names */ - list_size= listxattr(path, list, 0); - if(list_size == -1) - {ret= -1; goto ex;} - list= calloc(list_size, 1); - if(list == NULL) - {ret= -1; goto ex;} - list_size= listxattr(path, list, list_size); - if(list_size == -1) - {ret= -1; goto ex;} - for(i= 0; i < list_size; i+= strlen(list + i) + 1) - num_names++; - } - if(flag & 1) - num_names++; - if(num_names == 0) - {ret= 1; goto ex;} - (*names)= calloc(num_names, sizeof(char *)); - (*value_lengths)= calloc(num_names, sizeof(size_t)); - (*values)= calloc(num_names, sizeof(char *)); - if(*names == NULL || *value_lengths == NULL || *values == NULL) - {ret= -1; goto ex;} - - if(!(flag & 4)) - for(i= 0; i < list_size && num_names > *num_attrs; - i+= strlen(list + i) + 1) { - if(!(flag & 8)) - if(strcmp(list + i, Aaip_acl_attrnamE) == 0) - continue; - (*names)[(*num_attrs)++]= list + i; - } - for(i= *num_attrs; i < num_names; i++) - (*names)[i]= NULL; - for(i= 0; i < num_names; i++) { - (*values)[i]= NULL; - (*value_lengths)[i]= 0; - } - - if(!(flag & 4)) { /* Get xattr values */ - for(i= 0; i < *num_attrs; i++) { - if(!(flag & 8)) - if(strcmp((*names)[i], Aaip_acl_attrnamE) == 0) - continue; - value_ret= getxattr(path, (*names)[i], NULL, 0); - if(value_ret == -1) - continue; - (*values)[i]= calloc(value_ret + 1, 1); - if((*values)[i] == NULL) - {ret= -1; goto ex;} - (*value_lengths)[i]= getxattr(path, (*names)[i], (*values)[i], value_ret); - if(value_ret == -1) { /* there could be a race condition */ - if(retry++ > 5) - {ret= -1; goto ex;} - i--; - continue; - } - (*value_lengths)[i]= value_ret; - retry= 0; - } - } - - if(flag & 1) { /* Obtain ACL */ - /* access-ACL */ - ret= aaip_get_acl_text(path, &acl_text, 0); - if(ret <= 0) - goto ex; - ret= aaip_encode_acl(acl_text, &a_acl_len, &a_acl, flag & 2); - if(ret <= 0) - goto ex; - aaip_get_acl_text("", &acl_text, 1 << 15); /* free */ - - /* eventually default-ACL */ - ret= aaip_get_acl_text(path, &acl_text, 1); - if(ret > 0) { - /* encode and append to a_acl */; - ret= aaip_encode_acl(acl_text, &d_acl_len, &d_acl, (flag & 2) | 4); - if(ret <= 0) - goto ex; - acl= calloc(a_acl_len + d_acl_len + 1, 1); - if(acl == NULL) - {ret= -1; goto ex;} - if(a_acl_len) - memcpy(acl, a_acl, a_acl_len); - if(d_acl_len) - memcpy(acl + a_acl_len, d_acl, d_acl_len); - acl_len= a_acl_len + d_acl_len; - } else { - acl= a_acl; - a_acl= NULL; - acl_len= a_acl_len; - } - - /* Set as attribute with empty name */; - (*names)[*num_attrs]= strdup(""); - if((*names)[*num_attrs] == NULL) - {ret= -1; goto ex;} - (*values)[*num_attrs]= (char *) acl; - (*value_lengths)[*num_attrs]= acl_len; - (*num_attrs)++; - } - - ret= 1; -ex:; - if(a_acl != NULL) - free(a_acl); - if(d_acl != NULL) - free(d_acl); - if(acl_text != NULL) - aaip_get_acl_text("", &acl_text, 1 << 15); /* free */ - - if(ret <= 0 || (flag & (1 << 15))) { - if(list != NULL) - free(list); - if(*names != NULL) - free(*names); - *names= NULL; - if(*value_lengths != NULL) - free(*value_lengths); - *value_lengths= NULL; - if(*values != NULL) { - for(i= 0; i < *num_attrs; i++) - free((*values)[i]); - free(*values); - } - if(acl != NULL) - free(acl); - *values= NULL; - *num_attrs= 0; - } - return(ret); -} - - -/* ------------------------------ Setters --------------------------------- */ - - -/* Set the ACL of the given file to a given list in long text form. - @param path Path to the file - @param text The input text (0 terminated, ACL long text form) - @param flag Bitfield for control purposes - bit0= set default ACL rather than access ACL - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_set_acl_text(char *path, char *text, int flag) -{ - int ret; - acl_t acl= NULL; - - acl= acl_from_text(text); - if(acl == NULL) { - ret= -1; goto ex; - } - ret= acl_set_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS, acl); - if(ret == -1) - goto ex; - ret= 1; -ex: - if(acl != NULL) - acl_free(acl); - return(ret); -} - - -/* Bring the given attributes and/or ACLs into effect with the given file. - @param flag Bitfield for control purposes - bit0= decode and set ACLs - bit1= first clear all existing attributes of the file - bit2= do not set attributes other than ACLs - bit3= do not ignore eventual ACL attribute - (e.g. system.posix_acl_access) - @return 1 success - -1 error memory allocation - -2 error with decoding of ACL - -3 error with setting ACL - -4 error with setting attribute - -5 error with deleting attributes - -*/ -int aaip_set_attr_list(char *path, size_t num_attrs, char **names, - size_t *value_lengths, char **values, int flag) -{ - int ret, has_default_acl= 0; - size_t i, consumed, acl_text_fill, list_size= 0, acl_idx= 0; - char *acl_text= NULL, *list= NULL; - - if(flag & 2) /* Delete all file attributes */ - list_size= listxattr(path, list, 0); - if(list_size > 0) { /* Delete all file attributes */ - list= calloc(list_size, 1); - if(list == NULL) - {ret= -5; goto ex;} - list_size= listxattr(path, list, list_size); - if(list_size == -1) - {ret= -5; goto ex;} - for(i= 0; i < list_size; i+= strlen(list + i) + 1) { - if(!(flag & 8)) - if(strcmp(list + i, Aaip_acl_attrnamE) == 0) - continue; - ret= removexattr(path, list + i); - if(ret == -1) - {ret= -5; goto ex;} - } - free(list); list= NULL; - } - - for(i= 0; i < num_attrs; i++) { - if(names[i] == NULL || values[i] == NULL) - continue; - if(names[i][0] == 0) { /* ACLs */ - if(flag & 1) - acl_idx= i + 1; - continue; - } - /* Extended Attribute */ - if((flag & 1) && !(flag & 8)) - if(strcmp(names[i], Aaip_acl_attrnamE) == 0) - continue; - ret= setxattr(path, names[i], values[i], value_lengths[i], 0); - if(ret == -1) - {ret= -4; goto ex;} - } - -/* Decode ACLs */ - if(acl_idx == 0) - {ret= 1; goto ex;} - i= acl_idx - 1; - /* "access" ACL */ - ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i], - &consumed, NULL, 0, &acl_text_fill, 1); - if(ret <= 0) - {ret= -2; goto ex;} - acl_text= calloc(acl_text_fill, 1); - if(acl_text == NULL) - {ret= -1; goto ex;} - ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i], - &consumed, acl_text, acl_text_fill, &acl_text_fill, 0); - if(ret <= 0) - {ret= -2; goto ex;} - has_default_acl= (ret == 2); - ret= aaip_set_acl_text(path, acl_text, 0); - if(ret <= 0) - {ret= -3; goto ex;} - /* "default" ACL */ - if(has_default_acl) { - free(acl_text); - acl_text= NULL; - ret= aaip_decode_acl((unsigned char *) (values[i] + consumed), - value_lengths[i] - consumed, &consumed, - NULL, 0, &acl_text_fill, 1); - if(ret <= 0) - {ret= -2; goto ex;} - acl_text= calloc(acl_text_fill, 1); - if(acl_text == NULL) - {ret= -1; goto ex;} - ret= aaip_decode_acl((unsigned char *) (values[i] + consumed), - value_lengths[i] - consumed, &consumed, - acl_text, acl_text_fill, &acl_text_fill, 0); - if(ret <= 0) - {ret= -2; goto ex;} - ret= aaip_set_acl_text(path, acl_text, 1); - if(ret <= 0) - {ret= -3; goto ex;} - } - ret= 1; -ex:; - if(acl_text != NULL) - free(acl_text); - if(list != NULL) - free(list); - return(ret); -} - - diff --git a/test/aaip_0_2.c b/test/aaip_0_2.c deleted file mode 100644 index b550e92f..00000000 --- a/test/aaip_0_2.c +++ /dev/null @@ -1,1687 +0,0 @@ - -/* - - Arbitrary Attribute Interchange Protocol , AAIP version 0.2 - Demonstration implementation of encoding and decoding EA and ACL. - - See test/aaip_0_2.h - http://libburnia-project.org/wiki/AAIP - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* <<< */ -#define Aaip_encode_debuG 1 - -#include "aaip_0_2.h" - -#define Aaip_EXEC 1 -#define Aaip_WRITE 2 -#define Aaip_READ 4 - -#define Aaip_TRANSLATE 0 -#define Aaip_ACL_USER_OBJ 1 -#define Aaip_ACL_USER 2 -#define Aaip_ACL_GROUP_OBJ 3 -#define Aaip_ACL_GROUP 4 -#define Aaip_ACL_MASK 5 -#define Aaip_ACL_OTHER 6 -#define Aaip_SWITCH_MARK 8 -#define Aaip_ACL_USER_N 10 -#define Aaip_ACL_GROUP_N 12 -#define Aaip_FUTURE_VERSION 15 - -/* --------------------------------- Encoder ---------------------------- */ - - -static int aaip_encode_pair(char *name, size_t attr_length, char *attr, - unsigned int *num_recs, size_t *comp_size, - unsigned char *result, size_t result_fill, - int flag); - - -/* Convert an array of Arbitrary Attributes into a series of AAIP fields. - @param aa_name The 2 byte SUSP Signature Word of the fields - @param num_attrs Number of attributes - @param names Array of pointers to 0 terminated name strings - @param value_lengths Array of byte lengths for each value - @param values Array of pointers to the value bytes - @param result_len Number of bytes in the resulting SUSP field string - @param result *result will point to the start of the result string. - This is malloc() memory which needs to be freed when - no longer needed - @param flag Bitfield for control purposes - bit0= set CONTINUE bit of last AA field to 1 - @return >0 is the number of SUSP fields generated, - 0 means error -*/ -unsigned int aaip_encode(char aa_name[2], - unsigned int num_attrs, char **names, - size_t *value_lengths, char **values, - size_t *result_len, unsigned char **result, int flag) -{ - size_t mem_size= 0, comp_size; - unsigned int number_of_fields, i, num_recs, total_recs= 0, ret; - - /* Predict memory needs, number of SUSP fields and component records */ - *result_len= 0; - for(i= 0; i < num_attrs; i++) { - ret= aaip_encode_pair(names[i], value_lengths[i], values[i], - &num_recs, &comp_size, NULL, (size_t) 0, 1); - if(ret <= 0) - return(ret); - mem_size+= comp_size; - total_recs= num_recs; - } - number_of_fields= mem_size / 250 + !!(mem_size % 250); - mem_size+= number_of_fields * 5; - -#ifdef Aaip_encode_debuG - *result= (unsigned char *) calloc(1, mem_size + 1024000); - /* generous honeypot for overflows */ -#else - *result= (unsigned char *) calloc(1, mem_size); -#endif - - - /* Encode pairs into result */ - for(i= 0; i < num_attrs; i++) { - ret= aaip_encode_pair(names[i], value_lengths[i], values[i], - &num_recs, &comp_size, *result, *result_len, 0); - if(ret <= 0) - return(ret); - (*result_len)+= comp_size; - } - - /* write the field headers */ - for(i= 0; i < number_of_fields; i++) { - (*result)[i * 255 + 0]= aa_name[0]; - (*result)[i * 255 + 1]= aa_name[1]; - if(i < number_of_fields - 1 || (mem_size % 255) == 0) - (*result)[i * 255 + 2]= 255; - else - (*result)[i * 255 + 2]= mem_size % 255; - (*result)[i * 255 + 3]= 1; - (*result)[i * 255 + 4]= (flag & 1) || (i < number_of_fields - 1); - } - (*result_len)+= number_of_fields * 5; - -#ifdef Aaip_encode_debuG - if(*result_len != mem_size) { - fprintf(stderr, "aaip_encode(): MEMORY MISMATCH BY %d BYTES\n", - (int) (mem_size - *result_len)); - } - ret= 0; - for(i= 0; i < *result_len; i+= ((unsigned char *) (*result))[i + 2]) - ret++; - if(ret != number_of_fields) { - fprintf(stderr, "aaip_encode(): WRONG NUMBER OF FIELDS %d <> %d\n", - number_of_fields, ret); - } -#endif /* Aaip_encode_debuG */ - - return(number_of_fields); -} - - -static void aaip_encode_byte(unsigned char *result, size_t *result_fill, - unsigned char value) -{ - result[(*result_fill / 250) * 255 + 5 + (*result_fill % 250)]= value; - (*result_fill)++; -} - - -static int aaip_encode_comp(unsigned char *result, size_t *result_fill, - char *data, size_t l, int flag) -{ - size_t todo; - char *rpt, *comp_start; - - if(l == 0) { - aaip_encode_byte(result, result_fill, 0); - aaip_encode_byte(result, result_fill, 0); - return(1); - } - for(rpt= data; rpt - data < l;) { - todo= l - (rpt - data); - aaip_encode_byte(result, result_fill, (todo > 255)); - if(todo > 255) - todo= 255; - aaip_encode_byte(result, result_fill, todo); - for(comp_start= rpt; rpt - comp_start < todo; rpt++) - aaip_encode_byte(result, result_fill, *((unsigned char *) rpt)); - } - return(1); -} - - -/* Write the component records for name and attr. Skip the positions of - AA field headers. - @param flag bit0= only count but do not produce result -*/ -static int aaip_encode_pair(char *name, size_t attr_length, char *attr, - unsigned int *num_recs, size_t *comp_size, - unsigned char *result, size_t result_fill, - int flag) -{ - size_t l; - - l= strlen(name); - *num_recs= l / 255 + (!!(l % 255)) + (l == 0) + - attr_length / 255 + (!!(attr_length % 255)) + (attr_length == 0); - *comp_size= l + attr_length + 2 * *num_recs; - - if(flag & 1) - return(1); - - aaip_encode_comp(result, &result_fill, name, l, 0); - aaip_encode_comp(result, &result_fill, attr, attr_length, 0); - return(1); -} - - -/* ----------- Encoder for ACLs ----------- */ - -static ssize_t aaip_encode_acl_text(char *acl_text, - size_t result_size, unsigned char *result, int flag); - - -/* Convert an ACL text as of acl_to_text(3) into the value of an Arbitrary - Attribute. According to AAIP 0.2 this value is to be stored together with - an empty name. - @param acl_text The ACL in long text form - @param result_len Number of bytes in the resulting value - @param result *result will point to the start of the result string. - This is malloc() memory which needs to be freed when - no longer needed - @param flag Bitfield for control purposes - bit0= count only - bit1= use numeric qualifiers rather than names - bit2= this is a default ACL, prepend SWITCH_MARK - @return >0 means ok - 0 means error -*/ -int aaip_encode_acl(char *acl_text, - size_t *result_len, unsigned char **result, int flag) -{ - ssize_t bytes; - - *result= NULL; - *result_len= 0; - bytes= aaip_encode_acl_text(acl_text, (size_t) 0, NULL, 1 | (flag & 6)); - if(bytes < 0) - return(0); - if(flag & 1) { - *result_len= bytes; - return(1); - } - *result= calloc(bytes + 1, 1); - if(*result == NULL) - return(-1); - (*result)[bytes]= 0; - *result_len= bytes; - bytes= aaip_encode_acl_text(acl_text, *result_len, *result, (flag & 6)); - if(bytes != *result_len) { - *result_len= 0; - return(0); - } - return(1); -} - - -static double aaip_numeric_id(char *name, int flag) -{ - double num; - char *cpt; - - for(cpt= name; *cpt != 0; cpt++) - if(*cpt < '0' || *cpt >'9') - break; - if(*cpt != 0) - return(-1); - sscanf(name, "%lf", &num); - return(num); -} - - -/* - @param result_size Number of bytes to store result - @param result Pointer to the start of the result string. - @param flag Bitfield for control purposes - bit0= count only, do not really produce bytes - bit1= use numeric qualifiers - bit2= this is a default ACL, prepend SWITCH_MARK 1 - @return >=0 number of bytes produced resp. counted - <0 means error -*/ -static ssize_t aaip_encode_acl_text(char *acl_text, - size_t result_size, unsigned char *result, int flag) -{ - char *rpt, *npt, *cpt; - int qualifier= 0, perms, type, i, qualifier_len, num_recs; - uid_t uid, huid; - gid_t gid, hgid; - ssize_t count= 0; - struct passwd *pwd; - struct group *grp; - char name[1024]; - double num; - - if(flag & 4) { - /* set SWITCH_MARK to indicate a default ACL */; - if(!(flag & 1)) { - if(count >= result_size) - return(-1); - result[count]= (Aaip_SWITCH_MARK << 4) | Aaip_EXEC; - } - count++; - } - - for(rpt= acl_text; *rpt != 0; rpt= npt) { - npt= strchr(rpt, '\n'); - if(npt == 0) - npt= rpt + strlen(rpt); - else - npt++; - if(*rpt == '#') - continue; - cpt= strchr(rpt, ':'); - if(cpt == NULL) - continue; - cpt= strchr(cpt + 1, ':'); - if(cpt == NULL) - continue; - qualifier= 0; - if(strncmp(rpt, "user:", 5) == 0) { - if(cpt - rpt == 5) - type= Aaip_ACL_USER_OBJ; - else { - if(cpt - (rpt + 5) >= sizeof(name)) - continue; - strncpy(name, rpt + 5, cpt - (rpt + 5)); - name[cpt - (rpt + 5)]= 0; - if(flag & 2) { - type= Aaip_ACL_USER_N; - pwd= getpwnam(name); - if(pwd == NULL) { - num= aaip_numeric_id(name, 0); - if(num <= 0) - goto user_by_name; - uid= huid= num; - } else - uid= huid= pwd->pw_uid; - /* Convert uid into Qualifier Record */ - for(i= 0; huid != 0; i++) - huid= huid >> 8; - qualifier_len= i; - for(i= 0; i < qualifier_len ; i++) - name[i]= uid >> (8 * (qualifier_len - i - 1)); - } else { -user_by_name:; - type= Aaip_ACL_USER; - qualifier_len= strlen(name); - } - qualifier= 1; - } - } else if(strncmp(rpt, "group:", 6) == 0) { - if(cpt - rpt == 6) - type= Aaip_ACL_GROUP_OBJ; - else { - if(cpt - (rpt + 6) >= sizeof(name)) - continue; - strncpy(name, rpt + 6, cpt - (rpt + 6)); - if(flag & 2) { - type= Aaip_ACL_GROUP_N; - grp= getgrnam(name); - if(grp == NULL) { - num= aaip_numeric_id(name, 0); - if(num <= 0) - goto group_by_name; - gid= hgid= num; - } else - gid= hgid= grp->gr_gid; - /* Convert gid into Qualifier Record */ - for(i= 0; hgid != 0; i++) - hgid= hgid >> 8; - qualifier_len= i; - for(i= 0; i < qualifier_len ; i++) - name[i]= gid >> (8 * (qualifier_len - i - 1)); - - } else { -group_by_name:; - type= Aaip_ACL_GROUP; - qualifier_len= strlen(name); - } - qualifier= 1; - } - } else if(strncmp(rpt, "other:", 6) == 0) { - type= Aaip_ACL_OTHER; - } else if(strncmp(rpt, "mask:", 5) == 0) { - type= Aaip_ACL_MASK; - } else - continue; - - if(npt - cpt < 3) - continue; - perms= 0; - if(cpt[1] == 'r') - perms|= Aaip_READ; - if(cpt[2] == 'w') - perms|= Aaip_WRITE; - if(cpt[3] == 'x') - perms|= Aaip_EXEC; - - if(!(flag & 1)) { - if(count >= result_size) - return(-1); - result[count]= perms | ((!!qualifier) << 3) | (type << 4); - } - count++; - - if(qualifier) { - num_recs= (qualifier_len / 127) + !!(qualifier_len % 127); - if(!(flag & 1)) { - if(count + 1 > result_size) - return(-1); - for(i= 0; i < num_recs; i++) { - if(i < num_recs - 1) - result[count++]= 255; - else { - result[count++]= (qualifier_len % 127); - if(result[count - 1] == 0) - result[count - 1]= 127; - } - if(count + (result[count - 1] & 127) > result_size) - return(-1); - memcpy(result + count, name + i * 127, result[count - 1] & 127); - count+= result[count - 1] & 127; - } - } else - count+= qualifier_len + num_recs; - } - } - - return(count); -} - - -/* --------------------------------- Decoder ---------------------------- */ - -/* --- private --- */ - -/* Not less than 2 * 2048 */ -#define Aaip_buffer_sizE 4096 - -/* Enough for one full component record and three empty ones which might get - added in case of unclean end of attribute list. -*/ -#define Aaip_buffer_reservE (257 + 3 * 2) - - -struct aaip_state { - - /* AA field status */ - unsigned char aa_name[2]; - int aa_head_missing; /* number of bytes needed to complete AA field header */ - int aa_missing; /* number of bytes needed to complete current AA field */ - int aa_ends; /* 0= still AA fields expected, 1= last AA being processed, - 2= all AA fields processed, 3= all is delivered */ - - /* Buffer for component records */ - int recs_invalid; /* number of components to skip */ - unsigned char recs[Aaip_buffer_sizE + Aaip_buffer_reservE]; - size_t recs_fill; - unsigned char *recs_start; - int rec_head_missing; /* number of bytes needed to complete rec header */ - int rec_missing; /* number of bytes needed to complete current rec */ - int rec_ends; - - /* Counter for completed data */ - unsigned int num_recs; - size_t ready_bytes; - - /* Counter and meaning for completed components */ - unsigned int num_components; - size_t end_of_components; /* start index of eventual incomplete component */ - int first_is_name; - - /* Last return value of aaip_decode_pair() */ - int pair_status; - unsigned int pairs_skipped; - - /* status of aaip_decode_attrs() */ - size_t list_mem_used; - size_t list_size; - size_t list_num_attrs; - char **list_names; - size_t *list_value_lengths; - char **list_values; - char *name_buf; - size_t name_buf_size; - size_t name_buf_fill; - char *value_buf; - size_t value_buf_size; - size_t value_buf_fill; - int list_pending_pair; -}; - - -/* ------- functions ------ */ - - -size_t aaip_sizeof_aaip_state(void) -{ - return((size_t) sizeof(struct aaip_state)); -} - - -int aaip_init_aaip_state(struct aaip_state *aaip, char aa_name[2], int flag) -{ - aaip->aa_name[0]= aa_name[0]; - aaip->aa_name[1]= aa_name[1]; - aaip->aa_head_missing= 5; - aaip->aa_missing= 0; - - aaip->recs_invalid= 0; - memset(aaip->recs, 0, Aaip_buffer_sizE + Aaip_buffer_reservE); - aaip->recs_fill= 0; - aaip->recs_start= aaip->recs; - aaip->rec_head_missing= 2; - aaip->rec_missing= 0; - aaip->rec_ends= 0; - - aaip->num_recs= 0; - aaip->ready_bytes= 0; - - aaip->num_components= 0; - aaip->end_of_components= 0; - aaip->first_is_name= 1; - - aaip->pair_status= 2; - aaip->pairs_skipped= 0; - - aaip->list_mem_used= 0; - aaip->list_size= 0; - aaip->list_num_attrs= 0; - aaip->list_names= NULL; - aaip->list_value_lengths= NULL; - aaip->list_values= NULL; - aaip->name_buf= NULL; - aaip->name_buf_size= 0; - aaip->name_buf_fill= 0; - aaip->value_buf= NULL; - aaip->value_buf_size= 0; - aaip->value_buf_fill= 0; - aaip->list_pending_pair= 0; - return(1); -} - -/* -*/ -#define Aaip_with_ring_buffeR yes - -#ifdef Aaip_with_ring_buffeR - -/* Compute the one or two byte intervals in the ring buffer which form a - given byte interval in the virtual shift fifo. - @param idx The byte start index in the virtual shift fifo. - @param todo Number of bytes to cover - @param start_pt Will return the start address of the first interval - @param at_start_pt Will return the size of the first interval - @param at_recs Will return the size of the second interval which - always starts at aaip->recs - @param flag Bitfield for control purposes - @return 1= next start_pt is *start_pt + *at_start_pt - 2= next start_pt is aaip->recs + *at_recs -*/ -static int aaip_ring_adr(struct aaip_state *aaip, size_t idx, size_t todo, - unsigned char **start_pt, size_t *at_start_pt, - size_t *at_recs, int flag) -{ - size_t ahead; - - ahead= Aaip_buffer_sizE + Aaip_buffer_reservE - - (aaip->recs_start - aaip->recs); - if(idx < ahead) - *start_pt= (aaip->recs_start + idx); - else - *start_pt= aaip->recs + (idx - ahead); - ahead= Aaip_buffer_sizE + Aaip_buffer_reservE - (*start_pt - aaip->recs); - if(todo >= ahead) { - *at_start_pt= ahead; - *at_recs= todo - ahead; - return(2); - } - *at_start_pt= todo; - *at_recs= 0; - return(1); -} - - -/* - @param flag Bitfield for control purposes - bit0= count as ready_bytes -*/ -static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data, - size_t todo, int flag) -{ - unsigned char *start_pt; - size_t at_start_pt, at_recs; - - aaip_ring_adr(aaip, aaip->recs_fill, todo, - &start_pt, &at_start_pt, &at_recs, 0); - if(at_start_pt > 0) - memcpy(start_pt, data, at_start_pt); - if(at_recs > 0) - memcpy(aaip->recs, data + at_start_pt, at_recs); - aaip->recs_fill+= todo; - if(flag & 1) - aaip->ready_bytes+= todo; - return(1); -} - - -static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx, - unsigned char *data, size_t num_data, int flag) -{ - unsigned char *start_pt; - size_t at_start_pt, at_recs; - - aaip_ring_adr(aaip, idx, num_data, - &start_pt, &at_start_pt, &at_recs, 0); - if(at_start_pt > 0) - memcpy(data, start_pt, at_start_pt); - if(at_recs > 0) - memcpy(data + at_start_pt, aaip->recs, at_recs); - return(1); -} - - -static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx, - unsigned char data, int flag) -{ - unsigned char *start_pt; - size_t at_start_pt, at_recs; - - aaip_ring_adr(aaip, idx, 1, - &start_pt, &at_start_pt, &at_recs, 0); - *start_pt= data; - return(1); -} - - -static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag) -{ - unsigned char *start_pt; - size_t at_start_pt, at_recs; - - aaip_ring_adr(aaip, idx, 1, - &start_pt, &at_start_pt, &at_recs, 0); - return((int) *start_pt); -} - - -static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag) -{ - int ret; - unsigned char *start_pt; - size_t at_start_pt, at_recs; - - if(todo < aaip->recs_fill) { - ret= aaip_ring_adr(aaip, 0, todo, &start_pt, &at_start_pt, &at_recs, 0); - if(ret == 1) - aaip->recs_start= start_pt + todo; - else - aaip->recs_start= aaip->recs + at_recs; - } else { - aaip->recs_start= aaip->recs; - } - aaip->recs_fill-= todo; - if(aaip->end_of_components >= todo) - aaip->end_of_components-= todo; - else - aaip->end_of_components= 0; - return(1); -} - - -#else /* Aaip_with_ring_buffeR */ - - -/* - @param flag Bitfield for control purposes - bit0= count as ready_bytes -*/ -static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data, - size_t todo, int flag) -{ - memcpy(aaip->recs + aaip->recs_fill, data, todo); - aaip->recs_fill+= todo; - if(flag & 1) - aaip->ready_bytes+= todo; - return(1); -} - - -static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx, - unsigned char *data, size_t num_data, int flag) -{ - memcpy(data, aaip->recs + idx, num_data); - return(1); -} - - -static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx, - unsigned char data, int flag) -{ - aaip->recs[idx]= data; - return(1); -} - - -static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag) -{ - return((int) aaip->recs[idx]); -} - - -static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag) -{ - if(todo < aaip->recs_fill) - memmove(aaip->recs, aaip->recs + todo, aaip->recs_fill - todo); - aaip->recs_fill-= todo; - - if(aaip->end_of_components >= todo) - aaip->end_of_components-= todo; - else - aaip->end_of_components= 0; - return(1); -} - - -#endif /* ! Aaip_with_ring_buffeR */ - - -static int aaip_consume_rec_head(struct aaip_state *aaip, - unsigned char **data, size_t *num_data, int flag) -{ - size_t todo; - - todo= *num_data; - if(todo > aaip->aa_missing) - todo= aaip->aa_missing; - if(todo >= aaip->rec_head_missing) - todo= aaip->rec_head_missing; - if(!aaip->recs_invalid) - aaip_push_to_recs(aaip, *data, todo, 0); - aaip->rec_head_missing-= todo; - if(aaip->rec_head_missing == 0) { - aaip->rec_missing= aaip_get_buffer_byte(aaip, aaip->recs_fill - 1, 0); - aaip->rec_ends= !(aaip_get_buffer_byte(aaip, aaip->recs_fill - 2, 0) & 1); - } - aaip->aa_missing-= todo; - (*num_data)-= todo; - (*data)+= todo; - return(1); -} - - -static int aaip_consume_rec_data(struct aaip_state *aaip, - unsigned char **data, size_t *num_data, int flag) -{ - size_t todo; - - todo= *num_data; - if(todo > aaip->aa_missing) - todo= aaip->aa_missing; - if(todo > aaip->rec_missing) - todo= aaip->rec_missing; - if(!aaip->recs_invalid) - aaip_push_to_recs(aaip, *data, todo, 1); - aaip->rec_missing-= todo; - aaip->aa_missing-= todo; - (*num_data)-= todo; - (*data)+= todo; - if(aaip->rec_missing <= 0) { - if(aaip->recs_invalid > 0) { - if(aaip->rec_ends) - aaip->recs_invalid--; - } else { - aaip->num_recs++; - if(aaip->rec_ends) { - aaip->num_components++; - aaip->end_of_components= aaip->recs_fill; - } - } - aaip->rec_head_missing= 2; - } - return(0); -} - - -static int aaip_consume_aa_head(struct aaip_state *aaip, - unsigned char **data, size_t *num_data, int flag) -{ - size_t todo; - unsigned char aa_head[5]; - - todo= *num_data; - if(todo >= aaip->aa_head_missing) - todo= aaip->aa_head_missing; - aaip_push_to_recs(aaip, *data, todo, 0); - aaip->aa_head_missing-= todo; - if(aaip->aa_head_missing == 0) { - aaip_read_from_recs(aaip, aaip->recs_fill - 5, aa_head, 5, 0); - if(aa_head[0] != aaip->aa_name[0] || aa_head[1] != aaip->aa_name[1] || - aa_head[3] != 1) - return(-1); - aaip->aa_missing= aa_head[2]; - aaip->aa_ends= !(aa_head[4] & 1); - aaip->recs_fill-= 5; /* AA heads do not get delivered */ - if(aaip->aa_missing >= 5) - aaip->aa_missing-= 5; - else - aaip->aa_missing= 0; - } - (*num_data)-= todo; - (*data)+= todo; - return(1); -} - - -static int aaip_consume_aa_data(struct aaip_state *aaip, - unsigned char **data, size_t *num_data, int flag) -{ - size_t i; - static unsigned char zero_char[2]= {0, 0}; - - while(*num_data > 0 && aaip->aa_missing > 0) { - if(aaip->rec_head_missing > 0) { - aaip_consume_rec_head(aaip, data, num_data, 0); - if(*num_data == 0 || aaip->aa_missing <= 0) - return(1); - } - aaip_consume_rec_data(aaip, data, num_data, 0); - } - if(aaip->aa_missing <= 0) { - if(aaip->aa_ends) { - /* Check for incomplete pair and eventually make emergency closure */ - if(aaip->rec_head_missing != 2) { /* incomplete record detected */ - if(aaip->rec_head_missing) { - /* fake 0 length record */ - aaip_set_buffer_byte(aaip, aaip->recs_fill - 1, (unsigned char) 0, 0); - aaip_push_to_recs(aaip, zero_char, 1, 0); - } else { - /* fill in missing btes */ - for(i= 0; i < aaip->rec_missing; i++) - aaip_push_to_recs(aaip, zero_char, 1, 1); - } - aaip->rec_head_missing= 2; - aaip->rec_missing= 0; - aaip->num_recs++; - if(aaip->rec_ends) { - aaip->num_components++; - aaip->end_of_components= aaip->recs_fill; - } - } - if(aaip->end_of_components != aaip->recs_fill && - aaip->end_of_components != 0) { - /* incomplete component detected */ - /* add empty end record */ - aaip_push_to_recs(aaip, zero_char, 2, 0); - aaip->num_recs++; - aaip->num_components++; - aaip->end_of_components= aaip->recs_fill; - } - if(!(aaip->first_is_name ^ (aaip->num_components % 2))) { - /* value component is missing */ - /* add dummy component */ - aaip_push_to_recs(aaip, zero_char, 2, 0); - aaip->num_recs++; - aaip->num_components++; - aaip->end_of_components= aaip->recs_fill; - } - aaip->aa_ends= 2; - } else - aaip->aa_head_missing= 5; - } - return(0); -} - - -/* Submit small data chunk for decoding. - The return value will tell whether data are pending for being fetched. - @param aaip The AAIP decoder context - @param data Not more than 2048 bytes input for the decoder - @parm num_data Number of bytes in data - 0 inquires the buffer status avoiding replies <= 0 - @param ready_bytes Number of decoded bytes ready for delivery - @param flag Bitfield for control purposes - @return -1= non-AA field detected - *ready_bytes gives number of consumed bytes in data - 0= cannot accept data because buffer full - 1= no component record complete, submit more data - 2= component record complete, may be delivered - 3= component complete, may be delivered - 4= no component available, no more data expected, done -*/ -int aaip_submit_data(struct aaip_state *aaip, - unsigned char *data, size_t num_data, - size_t *ready_bytes, int flag) -{ - int ret; - unsigned char *in_data; - - if(aaip->aa_ends == 3) - return(4); - in_data= data; - if(num_data == 0) - goto ex; - if(aaip->recs_fill + num_data > Aaip_buffer_sizE) - return(0); - - while(num_data > 0) { - if(aaip->aa_head_missing > 0) { - ret= aaip_consume_aa_head(aaip, &data, &num_data, 0); - if(ret < 0) { - *ready_bytes= data - in_data; - return(-1); - } - if(num_data == 0 || aaip->aa_missing <= 0) - goto ex; - } - aaip_consume_aa_data(aaip, &data, &num_data, 0); - if(aaip->aa_missing) - break; - } -ex:; - *ready_bytes= aaip->ready_bytes; - if(aaip->num_components > 0) - return(3); - if(aaip->num_recs > 0) - return(2); - if(aaip->aa_ends && aaip->aa_head_missing == 0 && aaip->aa_missing == 0) - aaip->aa_ends= 2; - if(aaip->aa_ends == 2 && aaip->num_recs == 0) - aaip->aa_ends= 3; - if(aaip->aa_ends == 3) - return(4); - return(1); -} - - -/* Fetch the available part of current component. - The return value will tell whether it belongs to name or to value and - whether that name or value is completed now. - @param aaip The AAIP decoder context - @param result Has to point to storage for the component data - @param result_size Gives the amount of provided result storage - @param num_result Will tell the number of fetched result bytes - @param flag Bitfield for control purposes - bit0= discard data rather than copying to result - @return -2 = insufficient result_size - -1 = no data ready for delivery - 0 = result holds the final part of a name - 1 = result holds an intermediate part of a name - 2 = result holds the final part of a value - 3 = result holds an intermediate part of a value -*/ -int aaip_fetch_data(struct aaip_state *aaip, - char *result, size_t result_size, size_t *num_result, - int flag) -{ - int ret= -1, complete= 0, payload; - unsigned int i, num_bytes= 0, h; - - if(aaip->num_recs == 0) - return(-1); - - /* Copy data until end of buffer or end of component */ - h= 0; - for(i= 0; i < aaip->num_recs && !complete; i++) { - payload= aaip_get_buffer_byte(aaip, h + 1, 0); - if(!(flag & 1)) { - if(num_bytes + payload > result_size) - return(-2); - aaip_read_from_recs(aaip, h + 2, (unsigned char *) (result + num_bytes), - payload, 0); - *num_result= num_bytes + payload; - } - num_bytes+= payload; - if(!(aaip_get_buffer_byte(aaip, h, 0) & 1)) - complete= 1; - h+= payload + 2; - } - aaip->ready_bytes-= num_bytes; - aaip->num_recs-= i; - - /* Shift buffer */ - aaip_shift_recs(aaip, h, 0); - - /* Compute reply */ - ret= 2 * !aaip->first_is_name; - if(complete) { - aaip->first_is_name= !aaip->first_is_name; - if(aaip->num_components > 0) - aaip->num_components--; - } else - ret|= 1; - - return(ret); -} - - -/* Skip the current component and eventually the following value component. - This has to be called if fetching of a component shall be aborted - but the next component resp. pair shall be fetchable again. - aaip_submit_data() will not indicate readiness for fetching until all - bytes of the skipped components are submitted. Those bytes get discarded. - @param aaip The AAIP decoder context - @param flag Bitfield for control purposes - bit0= do not skip value if current component is name - @return <=0 error , 1= now in skip state, 2= not in skip state -*/ -int aaip_skip_component(struct aaip_state *aaip, int flag) -{ - int to_skip= 1; - - if(aaip->first_is_name && !(flag & 1)) - to_skip= 2; - if(aaip->recs_invalid) { - aaip->recs_invalid+= to_skip; - return(1); - } - - if(aaip->num_components) { - /* null-fetch */ - aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1); - to_skip--; - } - if(aaip->num_components && to_skip) { - /* null-fetch */ - aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1); - to_skip--; - } - if(to_skip) { - aaip->recs_fill= 0; - aaip->num_recs= 0; - aaip->ready_bytes= 0; - } - aaip->recs_invalid= to_skip; - if(aaip->aa_ends == 2 && aaip->num_recs == 0) - aaip->aa_ends= 3; - return(1 + (aaip->num_recs > 0)); -} - - -/* ------------------------- Pair Level Interface ------------------------ */ - -/* - @param flag Bitfield for control purposes - bit0= do not skip oversized component but return -2 - @return see aaip_decode_pair -*/ -static int aaip_advance_pair(struct aaip_state *aaip, - char *name, size_t name_size, size_t *name_fill, - char *value, size_t value_size, size_t *value_fill, - int flag) -{ - int ret; - char *wpt; - size_t size, num; - -retry:; - if(aaip->first_is_name) { - wpt= name + *name_fill; - size= name_size - *name_fill; - } else { - wpt= value + *value_fill; - size= value_size - *value_fill; - } - ret= aaip_fetch_data(aaip, wpt, size, &num, 0); - if(ret == -2) { /* insufficient result size */ - if(flag & 1) - return(-2); - ret= aaip_skip_component(aaip, 0); - *name_fill= *value_fill= 0; - aaip->pairs_skipped++; - if(ret == 2) /* Skip performed, valid data pending */ - goto retry; - } else if(ret == -1) { /* No data ready for delivery : may not happen */ - return(-1); - } else if(ret == 0) { /* result holds the final part of a name */ - (*name_fill)+= num; - /* peek for value data */ - ret= aaip_submit_data(aaip, NULL, (size_t) 0, &num, 0); - if(ret == 2 || ret == 3) { - /* fetch value data */; - ret= aaip_advance_pair(aaip, name, name_size, name_fill, - value, value_size, value_fill, flag); - return ret; - } else if(ret == 4) - return(5); - } else if(ret == 1) { /* result holds an intermediate part of a name */ - (*name_fill)+= num; - } else if(ret == 2) { /* result holds the final part of a value */ - (*value_fill)+= num; - if(aaip->num_components >= 2) - return(3); - if(aaip->aa_ends == 2 && aaip->num_recs == 0) - aaip->aa_ends= 3; - if(aaip->aa_ends == 3) - return(4); - return(2); - } else if(ret == 3) { - /* result holds an intermediate part of a value */; - (*value_fill)+= num; - } else { - return(-1); /* unknown reply from aaip_fetch_data() */ - } - return(1); -} - - -/* Accept raw input data and collect a pair of name and value. - The return value will indicate whether the pair is complete, whether more - pairs are complete or whether more data are desired. No input data will be - accepted as long as complete pairs are pending. The end of the attribute - list will be indicated. - @param aaip The AAIP decoder context - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param name Buffer to build the name string - @param name_size Maximum number of bytes in name - @param name_fill Holds the current buffer fill of name - @param value Buffer to build the value string - @param value_size Maximum number of bytes in value - @param value_fill Holds the current buffer fill of value - @param flag Bitfield for control purposes - bit0= do not skip oversized pair but return -2 - @return <0 error - -3 buffer full (program error) - -2 insufficient result_size (only with flag bit0) - -1 non-AA field detected - 0 data not accepted, first fetch pending pairs with num_data == 0 - 1 name and value are not valid yet, submit more data - 2 name and value are valid, submit more data - 3 name and value are valid, pairs pending, fetch with num_data == 0 - 4 name and value are valid, no more data expected - 5 name and value are not valid, no more data expected -*/ -int aaip_decode_pair(struct aaip_state *aaip, - unsigned char *data, size_t num_data, size_t *consumed, - char *name, size_t name_size, size_t *name_fill, - char *value, size_t value_size, size_t *value_fill, - int flag) -{ - int ret; - size_t ready_bytes; - - *consumed= 0; - if((aaip->pair_status < 0 && aaip->pair_status != -2) || - aaip->pair_status == 4 || - aaip->pair_status == 5) { /* dead ends */ - ret= aaip->pair_status; - goto ex; - } else if(aaip->pair_status == 2 || aaip->pair_status == 3) { - if(aaip->pair_status == 3 && num_data > 0) - {ret= 0; goto ex;} - /* Start a new pair */ - if(!aaip->first_is_name) /* Eventually skip orphaned value */ - aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1); - *name_fill= *value_fill= 0; - } - - if(num_data > 0) { - ret= aaip_submit_data(aaip, data, num_data, &ready_bytes, 0); - } else { - ret= 1; - if(aaip->num_components) - ret= 3; - else if(aaip->num_recs) - ret= 2; - } - if(ret < 0) { /* non-AA field detected */ - *consumed= ready_bytes; - {ret= -1; goto ex;} - } else if(ret == 0) { /* buffer overflow */; - /* should not happen with correct usage */ - {ret= -3; goto ex;} - } else if(ret == 1) { /* no component record complete */ - goto ex; - } else if(ret == 2) { /* component record complete, may be delivered */ - ; - } else if(ret == 3) { /* component complete, may be delivered */ - ; - } else if(ret == 4) { /* no component available, no more data expected */ - {ret= 5; goto ex;} - } else - {ret= -1; goto ex;} /* unknown reply from aaip_submit_data() */ - - *consumed= num_data; - ret= aaip_advance_pair(aaip, name, name_size, name_fill, - value, value_size, value_fill, flag & 1); - if(aaip->aa_ends == 3) { - if(ret >= 2 && ret <= 4) - ret= 4; - else - ret= 5; - } -ex:; - aaip->pair_status= ret; - return(ret); -} - - -unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag) -{ - return(aaip->pairs_skipped); -} - - -/* ------------------------- List Level Interface ------------------------ */ - - -#define Aaip_initial_name_leN 256 -#define Aaip_initial_value_leN 256 -#define Aaip_initial_list_sizE 2 -#define Aaip_list_enlargeR 1.5 - - -/* - @param flag Bitfield for control purposes - bit0= do not update *buf_size -*/ -static int aaip_enlarge_buf(struct aaip_state *aaip, size_t memory_limit, - size_t item_size, char **buf, size_t *buf_size, int flag) -{ - size_t new_size; - char *new_buf; - - new_size= *buf_size * Aaip_list_enlargeR; - if(aaip->list_mem_used + (new_size - *buf_size) * item_size >= memory_limit) - return(3); - aaip->list_mem_used+= (new_size - *buf_size) * item_size; - new_buf= realloc(*buf, new_size * item_size); - if(new_buf == NULL) - return(-1); - *buf= new_buf; - if(!(flag & 1)) - *buf_size= new_size; - return(1); -} - - -/* Accept raw input data and collect arrays of name pointers, value lengths - and value pointers. A handle object will emerge which finally has to be - be freed by a call with bit 15. - @param handle The decoding context. - It will be created by this call with flag bit 0 or if - *handle == NULL. This handle has to be the same as long - as decoding goes on and finally has to be freed by a - call with bit15. - @param aa_name The Signature Word (advised is "AA") - @param memory_limit Maximum number of bytes to allocate - @param num_attr_limit Maximum number of name-value pairs to allocate - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param flag Bitfield for control purposes - bit0= this is the first call with the given handle - (also in effect if *handle is NULL) - bit15= end decoding : - Free handle and its intermediate list memory. - @return <=0 error - -3 program error, unexpected reply from lower layers - -2 non-AA-field detected, arrays are complete, - call aaip_get_decoded_attrs() - -1 out of memory - 1 not complete yet, submit more data - 2 arrays are complete, call aaip_get_decoded_attrs() - 3 limit exceeded, not complete yet, - enlarge memory_limit or call with bit15 and give up - 4 limit exceeded, call aaip_get_decoded_attrs() and try again -*/ -int aaip_decode_attrs(struct aaip_state **handle, char aa_name[2], - size_t memory_limit, size_t num_attr_limit, - unsigned char *data, size_t num_data, size_t *consumed, - int flag) -{ - int ret, was_non_aa= 0; - struct aaip_state *aaip; - size_t h_num, *h_lengths, i, new_mem, pair_consumed= 0; - char **h_names, **h_values; - - *consumed= 0; - if(flag & (1 << 15)) { - if(*handle == NULL) - return(0); - ret= aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values, - 0); - if(ret > 0) - aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values, - 1 << 15); - if((*handle)->name_buf != NULL) - free((*handle)->name_buf); - if((*handle)->value_buf != NULL) - free((*handle)->value_buf); - free((char *) *handle); - *handle= NULL; - return(1); - } - - aaip= *handle; - if(aaip == NULL || (flag & 1)) { - aaip= *handle= calloc(1, sizeof(struct aaip_state)); - if(*handle == NULL) - return(-1); - aaip_init_aaip_state(*handle, aa_name, 0); - } - if(aaip->list_names == NULL || aaip->list_values == NULL || - aaip->list_value_lengths == NULL) { - /* Initialize arrays */ - aaip->list_size= Aaip_initial_list_sizE; - if(num_attr_limit > 0 && num_attr_limit < aaip->list_size) - aaip->list_size= num_attr_limit; - new_mem= aaip->list_size * (2*sizeof(char *) + sizeof(size_t)) + - Aaip_initial_name_leN + Aaip_initial_value_leN; - if(aaip->list_mem_used + new_mem >= memory_limit) - return(3); - aaip->list_mem_used+= new_mem; - aaip->list_names= calloc(sizeof(char *), aaip->list_size); - aaip->list_value_lengths= calloc(sizeof(size_t), aaip->list_size); - aaip->list_values= calloc(sizeof(char *), aaip->list_size); - if(aaip->list_names == NULL || aaip->list_value_lengths == NULL || - aaip->list_values == NULL) - return(-1); - for(i= 0; i < aaip->list_size; i++) { - aaip->list_names[i]= NULL; - aaip->list_value_lengths[i]= 0; - aaip->list_values[i]= NULL; - } - } - if(aaip->name_buf == NULL || aaip->value_buf == NULL) { - new_mem= Aaip_initial_name_leN + Aaip_initial_value_leN; - if(aaip->list_mem_used >= memory_limit) - return(3); - aaip->list_mem_used+= new_mem; - aaip->name_buf= calloc(sizeof(char *), Aaip_initial_name_leN); - aaip->value_buf= calloc(sizeof(char *), Aaip_initial_value_leN); - if(aaip->name_buf == NULL || aaip->value_buf == NULL) - return(-1); - aaip->name_buf_size= Aaip_initial_name_leN; - aaip->value_buf_size= Aaip_initial_name_leN; - } - - while(1) { - if(aaip->list_pending_pair > 0) { - /* the buffer holds a complete pair from a previous memory limit refusal */ - ret= aaip->list_pending_pair; - aaip->list_pending_pair= 0; - } else { - ret= aaip_decode_pair(aaip, data, num_data, &pair_consumed, - aaip->name_buf, aaip->name_buf_size, &aaip->name_buf_fill, - aaip->value_buf, aaip->value_buf_size, &aaip->value_buf_fill, - 1); - *consumed+= pair_consumed; - } - if(ret == -2) { /* insufficient result_size */ - if(aaip->first_is_name) - ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1, &(aaip->name_buf), - &(aaip->name_buf_size), 0); - else - ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1, - &(aaip->value_buf), &(aaip->value_buf_size), 0); - if(ret != 1) - return(ret); - - } else if(ret == -1) { /* non-AA field detected */ - was_non_aa= 1; - - } else if(ret < 0) { /* other error */ - return(-3); - - } else if(ret == 0) { /* first fetch pending pairs with num_data == 0 */ - /* should not happen, fetch more pairs */; - - } else if(ret == 1) { - /* name and value are not valid yet, submit more data */ - return(1); - - } else if(ret == 2 || ret == 3 || ret == 4) { - /* name and value are valid, submit more data */ - /* name and value are valid, pairs pending, fetch with num_data == 0 */ - /* name and value are valid, no more data expected */ - aaip->list_pending_pair= ret; - - if(aaip->list_num_attrs >= aaip->list_size) { - ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *), - (char **) &(aaip->list_names), &(aaip->list_size), 1); - if(ret != 1) - return(ret); - ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *), - (char **) &(aaip->list_values), &(aaip->list_size), 1); - if(ret != 1) - return(ret); - ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(size_t), - (char **) &(aaip->list_value_lengths), &(aaip->list_size), 0); - if(ret != 1) - return(ret); - } - - /* Allocate name and value in list */; - if(aaip->list_mem_used + aaip->name_buf_fill + aaip->value_buf_fill + 2 - > memory_limit) { - return(3); - } - aaip->list_mem_used+= aaip->name_buf_fill + aaip->value_buf_fill + 2; - i= aaip->list_num_attrs; - aaip->list_names[i]= calloc(aaip->name_buf_fill + 1, 1); - aaip->list_values[i]= calloc(aaip->value_buf_fill + 1, 1); - memcpy(aaip->list_names[i], aaip->name_buf, aaip->name_buf_fill); - aaip->list_names[i][aaip->name_buf_fill]= 0; - memcpy(aaip->list_values[i], aaip->value_buf, aaip->value_buf_fill); - aaip->list_values[i][aaip->value_buf_fill]= 0; - aaip->list_value_lengths[i]= aaip->value_buf_fill; - aaip->list_num_attrs++; - aaip->name_buf_fill= aaip->value_buf_fill= 0; - - ret= aaip->list_pending_pair; - aaip->list_pending_pair= 0; - - if(ret == 2) - return(1); - if(ret == 4) - break; - - } else if(ret == 5) - break; - else - return(-2); - - num_data= 0; /* consume pending pairs */ - } - aaip->list_pending_pair= 5; - return(2); -} - - -/* Obtain the resulting attributes when aaip_decode_attrs() indicates to - be done or to have the maximum possible amount of result ready. - The returned data objects finally have to be freed by a call with flag - bit 15. - @param handle The decoding context created by aaip_decode_attrs() - @param num_attrs Will return the number of name-value pairs - @param names Will return an array of pointers to 0-terminated names - @param value_lengths Will return an arry with the lenghts of values - @param values Will return an array of pointers to 8-bit values - @param flag Bitfield for control purposes - bit15= free memory of names, value_lengths, values - @return <0 error - 0 no attribute list ready - 1 ok -*/ -int aaip_get_decoded_attrs(struct aaip_state **handle, size_t *num_attrs, - char ***names, size_t **value_lengths, char ***values, - int flag) -{ - size_t i; - struct aaip_state *aaip; - - aaip= *((struct aaip_state **) handle); - if(flag & (1 << 15)) { - if(*names != NULL) { - for(i= 0; i < *num_attrs; i++) { - if((*names)[i] != NULL) - free((*names)[i]); - (*names)[i]= NULL; - } - free(*names); - *names= NULL; - } - if(*values != NULL) { - for(i= 0; i < *num_attrs; i++) { - if((*values)[i] != NULL) - free((*values)[i]); - (*values)[i]= NULL; - } - free(*values); - *values= NULL; - } - if(*value_lengths != NULL) - free(*value_lengths); - *value_lengths= NULL; - *num_attrs= 0; - return(1); - } - - /* Check whether decoding is finished yet */ - if(aaip->list_pending_pair != 5) - return(0); - - *num_attrs= aaip->list_num_attrs; - *names= aaip->list_names; - *value_lengths= aaip->list_value_lengths; - *values= aaip->list_values; - - /* Now the memory is owned by the caller */ - aaip->list_num_attrs= 0; - aaip->list_names= NULL; - aaip->list_value_lengths= NULL; - aaip->list_values= NULL; - aaip->list_size= 0; - aaip->list_pending_pair= 0; - return(1); -} - - -/* ------ Decoder for ACLs ------ */ - - -static int aaip_write_acl_line(char **result, size_t *result_size, - char *tag_type, char *qualifier, - char *permissions, int flag) -{ - size_t needed, tag_len, perm_len, qualifier_len; - - tag_len= strlen(tag_type); - qualifier_len= strlen(qualifier); - perm_len= strlen(permissions); - needed= tag_len + qualifier_len + perm_len + 3; - if((flag & 1)) { - (*result_size)+= needed; - return(1); - } - if(needed + 1 > *result_size) /* +1 : want to append a trailing 0 */ - return(-1); - memcpy((*result), tag_type, tag_len); - (*result)[tag_len]= ':'; - memcpy((*result) + tag_len + 1, qualifier, qualifier_len); - (*result)[tag_len + 1 + qualifier_len]= ':'; - memcpy((*result) + tag_len + 1 + qualifier_len + 1, permissions, perm_len); - (*result)[tag_len + 1 + qualifier_len + 1 + perm_len]= '\n'; - (*result)[tag_len + 1 + qualifier_len + 1 + perm_len + 1] = 0; - (*result)+= needed; - (*result_size)-= needed; - return(1); -} - - -static int aaip_read_qualifier(unsigned char *data, size_t num_data, - char *name, size_t name_size, size_t *name_fill, - int flag) -{ - int is_done= 0, rec_len= 0; - unsigned char *rpt; - - *name_fill= 0; - for(rpt= data; !is_done; rpt+= rec_len) { - rec_len= (*rpt) & 127; - is_done= !((*rpt) & 128); - if(*name_fill + rec_len >= name_size || rpt + 1 + rec_len - data > num_data) - return(-1); - memcpy(name + *name_fill, rpt + 1, rec_len); - rpt+= 1 + rec_len; - (*name_fill)+= rec_len; - name[*name_fill]= 0; - } - return(1); -} - - -/* Convert an AAIP ACL attribute value into the long text form of ACL. - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param acl_text Will be filled with ACL long text form - @param acl_text_size Maximum number of bytes to be written to acl_text - @param acl_text_fill Will return the number of bytes in acl_text - @param flag Bitfield for control purposes - bit0= count only, do not really produce bytes: - acl_text will not be touched, - acl_text_size will be ignored, - *acl_text_fill will return the counted number - plus 1 for a trailing zero. - bit1= expected is a default ACL (see return value 2) - @return 1 success - 2 success, begin of default/access ACL encountered, - submit data + *consumed for access/default ACL - -1 error with reading of qualifier - -2 error with writing of ACL text line - -3 version mismatch - -4 unknown tag type encountered -*/ -int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed, - char *acl_text, size_t acl_text_size, - size_t *acl_text_fill, int flag) -{ - unsigned char *rpt; - char perm_text[4], *wpt, name[1024]; - int type, qualifier= 0, perm, ret, i, cnt; - size_t w_size, name_fill; - uid_t uid; - gid_t gid; - struct passwd *pwd; - struct group *grp; - - cnt= flag & 1; - *consumed= 0; - wpt= acl_text; - w_size= acl_text_size; - *acl_text_fill= 0; - for(rpt= data; rpt - data < num_data; ) { - perm= *rpt; - strcpy(perm_text, "---"); - if(perm & Aaip_READ) - perm_text[0]= 'r'; - if(perm & Aaip_WRITE) - perm_text[1]= 'w'; - if(perm & Aaip_EXEC) - perm_text[2]= 'x'; - - type= (*rpt) >> 4; - if(type == Aaip_FUTURE_VERSION) /* indicate to caller: version mismatch */ - return(-3); - - qualifier= !!((*rpt) & 8); - if(qualifier) { - ret= aaip_read_qualifier(rpt + 1, num_data - (rpt + 1 - data), - name, sizeof(name), &name_fill, 0); - if(ret <= 0) - return(-1); - } - - /* Advance read pointer */ - (*consumed)+= 1 + (qualifier ? name_fill + 1 : 0); - rpt+= 1 + (qualifier ? name_fill + 1 : 0); - - ret= 1; - if(type == Aaip_TRANSLATE) { - /* rightfully ignored yet */; - continue; - } else if(type == Aaip_ACL_USER_OBJ) { - /* user::rwx */ - ret= aaip_write_acl_line(&wpt, &w_size, "user", "", perm_text, cnt); - } else if(type == Aaip_ACL_USER) { - /* user::rwx */; - ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt); - } else if(type == Aaip_ACL_GROUP_OBJ) { - /* user::rwx */ - ret= aaip_write_acl_line(&wpt, &w_size, "group", "", perm_text, cnt); - } else if(type == Aaip_ACL_GROUP) { - /* group::rwx */; - ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt); - } else if(type == Aaip_ACL_MASK) { - /* mask::rwx */ - ret= aaip_write_acl_line(&wpt, &w_size, "mask", "", perm_text, cnt); - } else if(type == Aaip_ACL_OTHER) { - /* other::rwx */ - ret= aaip_write_acl_line(&wpt, &w_size, "other", "", perm_text, cnt); - } else if(type == Aaip_SWITCH_MARK) { - /* Indicate to caller: end of desired ACL type access/default */ - if((!(perm & Aaip_EXEC)) ^ (!!(flag & 2))) - return(2); - } else if(type == Aaip_ACL_USER_N) { - /* determine username from uid */ - uid= 0; - for(i= 0; i < name_fill; i++) - uid= (uid << 8) | ((unsigned char *) name)[i]; - pwd= getpwuid(uid); - if(pwd == NULL) - sprintf(name, "%.f", (double) uid); - else if(strlen(pwd->pw_name) >= sizeof(name)) - sprintf(name, "%.f", (double) uid); - else - strcpy(name, pwd->pw_name); - /* user::rwx */; - ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt); - } else if(type == Aaip_ACL_GROUP_N) { - /* determine username from gid */; - gid= 0; - for(i= 0; i < name_fill; i++) - gid= (gid << 8) | ((unsigned char *) name)[i]; - grp= getgrgid(gid); - if(grp == NULL) - sprintf(name, "%.f", (double) gid); - else if(strlen(grp->gr_name) >= sizeof(name)) - sprintf(name, "%.f", (double) gid); - else - strcpy(name, grp->gr_name); - /* user::rwx */; - ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt); - } else { - /* indicate to caller: unknown type */ - return(-4); - } - if(ret <= 0) - return(-2); - } - if(flag & 1) - *acl_text_fill= w_size + 1; - return(1); -} - - -/* ----------------------- Adapter for operating systems ----------------- */ - - -#ifdef __FreeBSD__ - -#include "aaip-os-freebsd.c" - -#else - -#include "aaip-os-linux.c" - -#endif - diff --git a/test/aaip_0_2.h b/test/aaip_0_2.h deleted file mode 100644 index 6a3fa7fe..00000000 --- a/test/aaip_0_2.h +++ /dev/null @@ -1,381 +0,0 @@ - -/* - - Arbitrary Attribute Interchange Protocol , AAIP version 0.2 - Demonstration program for encoding and decoding EA and ACL. - - See http://libburnia-project.org/wiki/AAIP - or doc/susp_aaip_0_2.txt - - test/aaip_0.2.h - Public declarations - -*/ - -#ifndef Aaip_h_is_includeD -#define Aaip_h_is_includeD yes - - -/* --------------------------------- Encoder ---------------------------- */ - -/* Convert an array of Arbitrary Attributes into a series of AAIP fields. - @param aa_name The 2 byte SUSP Signature Word of the fields - @param num_attrs Number of attributes - @param names Array of pointers to 0 terminated name strings - @param value_lengths Array of byte lengths for each value - @param values Array of pointers to the value bytes - @param result_len Number of bytes in the resulting SUSP field string - @param result *result will point to the start of the result string. - This is malloc() memory which needs to be freed when - no longer needed - @param flag Bitfield for control purposes - bit0= set CONTINUE bit of last AA field to 1 - @return >0 is the number of SUSP fields generated, - 0 means error -*/ -unsigned int aaip_encode(char aa_name[2], - unsigned int num_attrs, char **names, - size_t *value_lengths, char **values, - size_t *result_len, unsigned char **result, int flag); - - -/* ------ ACL representation ------ */ - -/* Convert an ACL from long text form into the value of an Arbitrary - Attribute. According to AAIP 0.2 this value is to be stored together with - an empty name. - @param acl_text The ACL in long text form - @param result_len Number of bytes in the resulting value - @param result *result will point to the start of the result string. - This is malloc() memory which needs to be freed when - no longer needed - @param flag Bitfield for control purposes - bit0= count only - bit1= use numeric qualifiers rather than names - @return >0 means ok - 0 means error -*/ -int aaip_encode_acl(char *acl_text, - size_t *result_len, unsigned char **result, int flag); - - -/* ------ OS interface ------ */ - -/* Obtain the ACL of the given file in long text form. - @param path Path to the file - @param text Will hold the result. This is a managed object which - finally has to be freed by a call to this function - with bit15 of flag. - @param flag Bitfield for control purposes - bit0= obtain default ACL rather than access ACL - bit15= free text and return 1 - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_get_acl_text(char *path, char **text, int flag); - - -/* Obtain the Extended Attributes and/or the ACLs of the given file in a form - that is ready for aaip_encode(). The returned data objects finally have - to be freed by a call with flag bit 15. - @param path Path to the file - @param num_attrs Will return the number of name-value pairs - @param names Will return an array of pointers to 0-terminated names - @param value_lengths Will return an arry with the lenghts of values - @param values Will return an array of pointers to 8-bit values - @param flag Bitfield for control purposes - bit0= obtain ACLs (access and eventually default) via - system ACL API and encode - bit1= use numeric ACL qualifiers rather than names - bit2= do not obtain attributes other than ACLs - bit3= do not ignore eventual ACL attribute - (e.g. system.posix_acl_access) - bit15= free memory of names, value_lengths, values - @return >0 ok - <=0 error -*/ -int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names, - size_t **value_lengths, char ***values, int flag); - - -/* --------------------------------- Decoder ---------------------------- */ - -/* - The AAIP decoder offers several levels of abstraction of which the - lower two avoid the use of dynamic memory. It provides a stateful decoding - context with a small buffer which delivers results to caller provided - memory locations. - - The lowest level is the stream-like Component Level Interface. It allows - to decode very many very long attributes. - - Next is the Pair Level Interface which delivers to fixly sized storage for - name and value. It allows to decode very many attributes. - - The List Level Interface uses dynamic memory allocation to provide arrays - of names, values and value lengths. It is intended for moderately sized - attribute lists but may also be used as alternative to Pair Level. -*/ - - -/* The AAIP decoder context. -*/ -struct aaip_state; - - -/* Obtain the size in bytes of an aaip_state object. -*/ -size_t aaip_sizeof_aaip_state(void); - - -/* Initialize a AAIP decoder context. - This has to be done before the first AA field of a node is processed. - The caller has to provide the storage of the struct aaip_state. - @param aaip The AAIP decoder context to be initialized - @param aa_name The Signature Word (advised is "AA") - @param flag Bitfield for control purposes - submit 0 - @return <=0 error , >0 ok -*/ -int aaip_init_aaip_state(struct aaip_state *aaip, char aa_name[2], int flag); - - -/* ------------------------- Component Level Interface ------------------- */ -/* - Provides support for unlimited component size but demands the caller - to have a growing storage facility resp. to do own oversize handling. - - This interface expects moderatly sized input pieces and will hand out - moderately sized result pieces. The number of transactions is virtually - unlimited. -*/ - -/* Submit small data chunk for decoding. - The return value will tell whether data are pending for being fetched. - @param aaip The AAIP decoder context - @param data Not more than 2048 bytes input for the decoder - @param num_data Number of bytes in data - 0 inquires the buffer status avoiding replies <= 0 - @param ready_bytes Number of decoded bytes ready for delivery - @param flag Bitfield for control purposes - @return -1= non-AA field detected - *ready_bytes gives number of consumed bytes in data - 0= cannot accept data because buffer full - 1= no component record complete, submit more data - 2= component record complete, may be delivered - 3= component complete, may be delivered - 4= no component available, no more data expected, done -*/ -int aaip_submit_data(struct aaip_state *aaip, - unsigned char *data, size_t num_data, - size_t *ready_bytes, int flag); - - -/* Fetch the available part of current component. - The return value will tell whether it belongs to name or to value and - whether that name or value is completed now. - @param aaip The AAIP decoder context - @param result Has to point to storage for the component data - @param result_size Gives the amount of provided result storage - @param num_result Will tell the number of fetched result bytes - @param flag Bitfield for control purposes - bit0= discard data rather than copying to result - @return -2 = insufficient result_size - -1 = no data ready for delivery - 0 = result holds the final part of a name - 1 = result holds an intermediate part of a name - 2 = result holds the final part of a value - 3 = result holds an intermediate part of a value -*/ -int aaip_fetch_data(struct aaip_state *aaip, - char *result, size_t result_size, size_t *num_result, - int flag); - - -/* Skip the current component and eventually the following value component. - This has to be called if fetching of a component shall be aborted - but the next component resp. pair shall be fetchable again. - aaip_submit_data() will not indicate readiness for fetching until all - bytes of the skipped components are submitted. Those bytes get discarded. - @param aaip The AAIP decoder context - @param flag Bitfield for control purposes - bit0= do not skip value if current component is name - @return <=0 error , 1= now in skip state, 2= not in skip state -*/ -int aaip_skip_component(struct aaip_state *aaip, int flag); - - -/* ------------------------- Pair Level Interface ------------------------ */ -/* - Provides support for names and values of limited size. The limits are - given by the caller who has to provide the storage for name and value. - - This interface expects moderatly sized input pieces. - The number of input transcations is virtually unlimited. - The number of pair transactions after aaip_init() should be limited - to 4 billion. -*/ - - -/* Accept raw input data and collect a pair of name and value. - The return value will indicate whether the pair is complete, whether more - pairs are complete or whether more data are desired. No input data will be - accepted as long as complete pairs are pending. The end of the attribute - list will be indicated. - @param aaip The AAIP decoder context - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param name Buffer to build the name string - @param name_size Maximum number of bytes in name - @param name_fill Holds the current buffer fill of name - @param value Buffer to build the value string - @param value_size Maximum number of bytes in value - @param value_fill Holds the current buffer fill of value - @param flag Bitfield for control purposes - submit 0 for now - @return <0 error - 0 data not accepted, first fetch pending pairs with num_data == 0 - 1 name and value are not valid yet, submit more data - 2 name and value are valid, submit more data - 3 name and value are valid, pairs pending, fetch with num_data == 0 - 4 name and value are valid, no more data expected - 5 name and value are not valid, no more data expected - -*/ -int aaip_decode_pair(struct aaip_state *aaip, - unsigned char *data, size_t num_data, size_t *consumed, - char *name, size_t name_size, size_t *name_fill, - char *value, size_t value_size, size_t *value_fill, - int flag); - - -/* Inquire the number of pairs which were skipped because being oversized. - @param aaip The AAIP decoder context - @param flag Bitfield for control purposes - submit 0 for now - @return The number of pairs skipped since aaip_init() -*/ -unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag); - - -/* ------------------------- List Level Interface ------------------------ */ -/* - Provides support for names and values of limited size. The limits are - given for total memory consumption and for number of attributes. - - Iterated decoding is supported as long as no single attribute exceeds - the memory limit. -*/ - -/* Accept raw input data and collect arrays of name pointers, value lengths - and value pointers. A handle object will emerge which finally has to be - be freed by a call with bit 15. - @param handle The decoding context. - It will be created by this call with flag bit 0 or if - *handle == NULL. This handle has to be the same as long - as decoding goes on and finally has to be freed by a - call with bit15. - @param aa_name The Signature Word (advised is "AA") - @param memory_limit Maximum number of bytes to allocate - @param num_attr_limit Maximum number of name-value pairs to allocate - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param flag Bitfield for control purposes - bit0= this is the first call for a file object - bit15= end decoding : - Free handle and its intermediate list memory. - @return <=0 error - 1 not complete yet, submit more data - 2 arrays are complete, call aaip_get_decoded_attrs() - 3 limit exceeded, not complete yet, call with bit15 and give up - 4 limit exceeded, call aaip_get_decoded_attrs() and try again -*/ -int aaip_decode_attrs(struct aaip_state **handle, char aa_name[2], - size_t memory_limit, size_t num_attr_limit, - unsigned char *data, size_t num_data, size_t *consumed, - int flag); - - -/* Obtain the resulting attributes when aaip_decode_attrs() indicates to - be done or to have the maximum possible amount of result ready. - The returned data objects get detached from handle making it ready for - the next round of decoding with possibly a different input source. The - returned data objects finally have to be freed by a call with flag bit 15. - @param handle The decoding context created by aaip_decode_attrs() - @param num_attrs Will return the number of name-value pairs - @param names Will return an array of pointers to 0-terminated names - @param value_lengths Will return an arry with the lenghts of values - @param values Will return an array of pointers to 8-bit values - @param flag Bitfield for control purposes - bit15= free memory of names, value_lengths, values -*/ -int aaip_get_decoded_attrs(struct aaip_state **handle, size_t *num_attrs, - char ***names, size_t **value_lengths, char ***values, - int flag); - - -/* ------ ACL representation ------ */ - -/* Convert an AAIP 0.2 ACL attribute value into the long text form of ACL. - @param data The raw data to decode - @param num_data Number of data bytes provided - @param consumed Returns the number of consumed data bytes - @param acl_text Will be filled with ACL long text form - @param acl_text_size Maximum number of bytes to be written to acl_text - @param acl_text_fill Will return the number of bytes in acl_text - @param flag Bitfield for control purposes - bit0= count only, do not really produce bytes: - acl_text will not be touched, - acl_text_size will be ignored, - *acl_text_fill will return the counted number - bit1= expected is a default ACL (see return value 2) - @return 1 success - 2 success, begin of default/access ACL encountered, - submit data + *consumed for access/default ACL - -1 error with reading of qualifier - -2 error with writing of ACL text line - -3 version mismatch - -4 unknown tag type encountered -*/ -int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed, - char *acl_text, size_t acl_text_size, - size_t *acl_text_fill, int flag); - - -/* ------ OS interface ------ */ - -/* Set the ACL of the given file to a given list in long text form. - @param path Path to the file - @param text The input text (0 terminated, ACL long text form) - @param flag Bitfield for control purposes - bit0= set default ACL rather than access ACL - @return > 0 ok - -1 failure of system ACL service (see errno) -*/ -int aaip_set_acl_text(char *path, char *text, int flag); - - -/* Bring the given attributes and/or ACLs into effect with the given file. - @param path Path to the file - @param num_attrs Number of attributes - @param names Array of pointers to 0 terminated name strings - @param value_lengths Array of byte lengths for each attribute payload - @param values Array of pointers to the attribute payload bytes - @param flag Bitfield for control purposes - bit0= decode and set ACLs - bit1= first clear all existing attributes of the file - bit2= do not set attributes other than ACLs - bit3= do not ignore eventual ACL attribute - (e.g. system.posix_acl_access) - @return 1 success - -1 error memory allocation - -2 error with decoding of ACL - -3 error with setting ACL - -4 error with setting attribute - -5 error with deleting attributes - -*/ -int aaip_set_attr_list(char *path, size_t num_attrs, char **names, - size_t *value_lengths, char **values, int flag); - -#endif /* ! Aaip_h_is_includeD */ - diff --git a/test/aaip_0_2_test.c b/test/aaip_0_2_test.c deleted file mode 100644 index bb708760..00000000 --- a/test/aaip_0_2_test.c +++ /dev/null @@ -1,443 +0,0 @@ - -/* - - Arbitrary Attribute Interchange Protocol , AAIP version 0.2 - Demonstration program for encoding and decoding EA and ACL. - - See http://libburnia-project.org/wiki/AAIP - - test/aaip_0_2_test.c - Main program for test binary - - Compile: - cc -g -Wall -o test/aaip test/aaip_0_2.c test/aaip_0_2_test.c -lacl - - Usage: ./aaip name value - Long parameters ./aaip -name"x100" -value"x100" - - >>> ACLs - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "aaip_0_2.h" - -#define Aaip_test_name_sizE 1024 -#define Aaip_test_value_sizE 1024 - - -static int print_result(unsigned char *result, size_t result_len, int flag) -{ - int i; - - printf( - " - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n"); - printf("\n"); - printf("%4u : ", 0); - for(i= 0; i < result_len; i++) { - if(result[i] >= 32 && result[i] <= 126) - printf("'%c' ", result[i]); - else - printf("%3u ", (unsigned int) ((unsigned char *) result)[i]); - if((i % 10) == 9) - printf("\n%4u : ", (unsigned int) (i + 1)); - } - printf("\n\n"); - printf( - " - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n"); - printf("\n"); - return(1); -} - - -static int print_attrs(size_t num_attrs, char **names, size_t *value_lengths, - char **values, int flag) -{ - size_t i, j; - - for(i= 0; i < num_attrs; i++) { - printf("name='"); - for(j= 0; names[i][j] != 0; j++) { - if(names[i][j] >= 32 && names[i][j] <= 126 && - names[i][j] != '\\' && names[i][j] != '\'') - printf("%c", names[i][j]); - else - printf("\\%o", (unsigned int) ((unsigned char **) names)[i][j]); - } - printf("' (%d)\n", (int) j); - printf("value='"); - for(j= 0; j < value_lengths[i]; j++) { - if(values[i][j] >= 32 && values[i][j] <= 126 && - values[i][j] != '\\' && values[i][j] != '\'') - printf("%c", values[i][j]); - else - printf("\\%3.3o", (unsigned int) ((unsigned char **) values)[i][j]); - } - printf("' (%d)\n\n", (int) j); - } - return(1); -} - - -static int do_touch(char *path, int flag) -{ - FILE *fp; - - fp= fopen(path, "a"); - if(fp == NULL) { - fprintf(stderr, "fopen(\"%s\") failed: %d %s\n", - path, errno, errno != 0 ? strerror(errno) : ""); - return(0); - } - fclose(fp); - return(1); -} - - -static int decode_acl(unsigned char *result, size_t result_len, - char *out_path, int flag) -{ - int ret; - size_t consumed, text_fill; - char *text= NULL; - - ret= aaip_decode_acl(result, result_len, &consumed, NULL, 0, &text_fill, 1); - if(ret <= 0) { - fprintf(stderr, "aaip_decode_acl(,1) failed: ret= %d\n", ret); - ret= 0; goto ex; - } - text= calloc(text_fill, 1); - ret= aaip_decode_acl(result, result_len, &consumed, text, text_fill, - &text_fill, 0); - if(ret <= 0) { - fprintf(stderr, "aaip_decode_acl(,0) failed: ret= %d\n", ret); - ret= 0; goto ex; - } - printf("--- ret= %d , text=\n%s--- end of text\n\n", ret, text); - - if(out_path == NULL) - {ret= 1; goto ex;} - - ret= do_touch(out_path, 0); - if(ret <= 0) - goto ex; - - ret= aaip_set_acl_text(out_path, text, 0); - if(ret <= 0) { - fprintf(stderr, "aaip_set_acl_text() failed"); - if(ret == -1) - fprintf(stderr, ": %d %s\n", errno, errno != 0 ? strerror(errno) : ""); - else - fprintf(stderr, "\n"); - ret= 0; goto ex; - } - ret= 1; -ex: - if(text != NULL) - free(text); - return(ret); -} - - -static int test_acl(char *in_path, char *out_path, int flag) -{ - int ret; - char *acl_text= NULL; - unsigned char *result= NULL; - size_t result_len; - - ret= aaip_get_acl_text(in_path, &acl_text, 0); - if(ret <= 0) { - fprintf(stderr, "aaip_get_acl_text() failed"); - if(ret == -1) - fprintf(stderr, ": %d %s\n", errno, errno != 0 ? strerror(errno) : ""); - else - fprintf(stderr, "\n"); - ret= 6; goto ex; - } - printf("--- ACL:\n%s--- end of ACL\n\n", acl_text); - - ret= aaip_encode_acl(acl_text, &result_len, &result, 0); - if(ret <= 0) { - fprintf(stderr, "aaip_encode_acl(text) failed: ret= %d\n", ret); - ret= 7; goto ex; - } - print_result(result, result_len, 0); - ret= decode_acl(result, result_len, out_path, 0); - if(ret <= 0) - {ret= 8; goto ex;} - free(result); result= NULL; - - ret= aaip_encode_acl(acl_text, &result_len, &result, 2); - if(ret <= 0) { - fprintf(stderr, "aaip_encode_acl(num) failed: ret= %d\n", ret); - ret= 9; goto ex; - } - print_result(result, result_len, 0); - ret= decode_acl(result, result_len, out_path, 0); - if(ret <= 0) - {ret= 10; goto ex;} - - ret= 0; -ex:; - aaip_get_acl_text("", &acl_text, 1 << 15); - if(result != NULL) - free(result); - return(ret); -} - - -int synthetic_pairs(char *prog, int argc, char **argv, int flag) -{ - int ret, l, mult= 0, k; - size_t result_len, i; - unsigned char *result= NULL; - char **names= NULL, **values= NULL, *cpt, **param; - size_t *value_lengths= NULL; - - struct aaip_state *aaip; - size_t consumed= 0; - char name[Aaip_test_name_sizE + 1]; - size_t name_fill; - char value[Aaip_test_value_sizE + 1]; - size_t value_fill; - size_t todo; - int submit_data, is_done; - unsigned char *rpt; - unsigned int skipped, was_skipped= 0; - - aaip= (struct aaip_state *) calloc(aaip_sizeof_aaip_state(), 1); - names= calloc(sizeof(char *), argc / 2); - values= calloc(sizeof(char *), argc / 2); - value_lengths= calloc(sizeof(size_t), argc / 2); - - for(i= 0; i < argc; i++) { - if(i % 2) - param= values + i / 2; - else - param= names + i / 2; - (*param)= argv[i]; - if(argv[i][0] == '-') { - cpt= strchr(argv[i], 'x'); - if(cpt != NULL) { - l= cpt - argv[i] - 1; - if(l > 0) - sscanf(cpt + 1, "%d", &mult); - if(l > 0 && mult > 0) { - (*param)= calloc(1, l * mult + 1); - if((*param) != NULL) { - for(k= 0; k < mult; k++) - memcpy((*param) + k * l, argv[i] + 1, l); - (*param)[mult * l]= 0; - } else - (*param)= argv[i]; - } - } - } - if(i % 2) - value_lengths[i / 2]= strlen(values[i / 2]); - } - - ret= aaip_encode("AA", (unsigned int) (argc / 2), names, - value_lengths, values, - &result_len, &result, 0); - if(ret <= 0) { - fprintf(stderr, "%s : aaip_encode failed with ret= %d\n", prog, ret); - return(2); - } - print_result(result, result_len, 0); - - aaip_init_aaip_state(aaip, "AA", 0); - rpt= result; - submit_data= 1; - is_done= 0; - while(!is_done) { - if(submit_data) { - todo= result_len - (rpt - result); - if(todo > 2048) - todo= 2048; - if(todo == 0) { - fprintf(stderr, "%s : Out of data while still prompted to submit\n", - prog); - return(5); - } - } else - todo= 0; - ret= aaip_decode_pair(aaip, rpt, todo, &consumed, - name, Aaip_test_name_sizE, &name_fill, - value, Aaip_test_value_sizE, &value_fill, 0); - skipped= aaip_get_pairs_skipped(aaip, 0); - if(skipped > was_skipped) { - printf("- skipped %d pair%s -\n\n", skipped - was_skipped, - skipped - was_skipped > 1 ? "s" : ""); - was_skipped= skipped; - } - if(ret < 0) { - fprintf(stderr, "%s : aaip_decode_pair failed with ret= %d\n", prog, ret); - return(3); - } - rpt+= todo; - if(ret == 0) { - rpt-= todo; - submit_data= 0; - continue; - } else if(ret == 1) { - submit_data= 1; - continue; - } else if(ret == 2) { - submit_data= 1; - } else if(ret == 3) { - submit_data= 0; - } else if(ret == 4) { - is_done= 1; - } else if(ret == 5) { - is_done= 1; - break; - } else { - fprintf(stderr, "%s : Unknown return %d from aaip_decode_pair()\n", - prog, ret); - return(4); - } - name[name_fill]= 0; - value[value_fill]= 0; - if((name_fill < 1000 && value_fill < 1000)) { - printf("name = '%s' (%lu)\n", name, (unsigned long) name_fill); - printf("value= '%s' (%lu)\n", value, (unsigned long) value_fill); - } else { - printf("name = (%lu)\n", (unsigned long) name_fill); - printf("value= (%lu)\n", (unsigned long) value_fill); - } - printf("\n"); - } - - return(0); -} - - -/* - @param flag bit0= use numeric qualifiers -*/ -static int copy_all(char *in_path, char *out_path, int flag) -{ - int ret; - struct aaip_state *aaip= NULL; - size_t in_num_attrs, *in_value_lengths= NULL; - char **in_names= NULL, **in_values= NULL; - int is_done= 0, first_round= 1; - unsigned char *result= NULL, *rpt; - size_t result_len, todo, consumed; - size_t out_num_attrs, *out_value_lengths= NULL; - char **out_names= NULL, **out_values= NULL; - - ret= aaip_get_attr_list(in_path, &in_num_attrs, &in_names, &in_value_lengths, - &in_values, 1 | ((flag & 1) << 1)); - if(ret <= 0) - {ret= 11; goto ex;} - print_attrs(in_num_attrs, in_names, in_value_lengths, in_values, 0); - - ret= aaip_encode("AA", (unsigned int) in_num_attrs, in_names, - in_value_lengths, in_values, &result_len, &result, 0); - if(ret == 0) - {ret= 12; goto ex;} - - if(result_len <= 0) { - fprintf(stderr, "No result\n"); - ret= 13; goto ex; - } - print_result(result, result_len, 0); - - rpt= result; - while(!is_done) { - todo= result_len - (rpt - result); - if(todo > 2048) - todo= 2048; - if(todo == 0) { - fprintf(stderr, "Out of data while still prompted to submit\n"); - ret= 14; goto ex; - } - /* Allow 1 million bytes of memory consumption, 100,000 attributes */ - ret= aaip_decode_attrs(&aaip, "AA", (size_t) 1000000, (size_t) 100000, - rpt, todo, &consumed, first_round); - rpt+= consumed; - first_round= 0; - if(ret == 1) - continue; - if(ret == 2) - break; - fprintf(stderr, "aaip_decode_attrs() returns %d\n", ret); - ret= 15; goto ex; - } - if(rpt - result != result_len) { - fprintf(stderr, "aaip_decode_attrs() returns 2 but %d bytes are left\n", - (int) (result_len - (rpt - result))); - ret= 16; goto ex; - } - ret= aaip_get_decoded_attrs(&aaip, &out_num_attrs, &out_names, - &out_value_lengths, &out_values, 0); - - if(ret != 1) { - fprintf(stderr, "aaip_get_decoded_attrs() returns %d\n", ret); - ret= 17; goto ex; - } - print_attrs(out_num_attrs, out_names, out_value_lengths, out_values, 0); - - ret= do_touch(out_path, 0); - if(ret <= 0) - {ret= 19; goto ex;} - - ret= aaip_set_attr_list(out_path, out_num_attrs, out_names, out_value_lengths, - out_values, 1 | 2); - if(ret != 1) { - fprintf(stderr, "aaip_set_attr_list() returns %d\n", ret); - ret= 18; goto ex; - } - ret= 0; -ex:; - if(in_names != NULL || in_value_lengths != NULL || in_values != NULL) - aaip_get_attr_list(in_path, &in_num_attrs, &in_names, &in_value_lengths, - &in_values, 1 << 15); - if(out_names != NULL || out_value_lengths != NULL || out_values != NULL) - aaip_get_decoded_attrs(&aaip, &out_num_attrs, &out_names, - &out_value_lengths, &out_values, 15); - aaip_decode_attrs(&aaip, "AA", (size_t) 0, (size_t) 0, NULL, (size_t) 0, - &consumed, 1 << 15); - return(ret); -} - - -int main(int argc, char **argv) -{ - int ret; - - if(argc < 2) { -usage: - fprintf(stderr, "usage : %s options\n", argv[0]); - fprintf(stderr, " -pairs [-]name[xNNN] [-]value[xNNN] [...]\n"); - fprintf(stderr, " -copy_acl source_path target_path\n"); - fprintf(stderr, " -copy source_path target_path\n"); - exit(1); - } - if(strcmp(argv[1], "-pairs") == 0) { - if(argc < 4 || (argc % 2) != 0) - goto usage; - ret= synthetic_pairs(argv[0], argc - 2, argv + 2, 0); - } else if(strcmp(argv[1], "-copy_acl") == 0) { - if(argc != 4) - goto usage; - ret= test_acl(argv[2], argv[3], 0); - } else if(strcmp(argv[1], "-copy") == 0) { - if(argc != 4) - goto usage; - ret= copy_all(argv[2], argv[3], 1); - } else - goto usage; - exit(ret); -}