Introduced AAIP code. Now linking with libacl.

(Todo: handle system dependy of -lacl in configure.ac)
release-1.5.4.branch
Thomas Schmitt 14 years ago
parent e8f1dfb8e5
commit 3294dd5e94
  1. 62
      Makefile.am
  2. 333
      doc/susp_aaip_0_2.txt
  3. 283
      libisofs/aaip-os-freebsd.c
  4. 371
      libisofs/aaip-os-linux.c
  5. 1693
      libisofs/aaip_0_2.c
  6. 381
      libisofs/aaip_0_2.h

@ -9,6 +9,9 @@ lib_LTLIBRARIES = libisofs/libisofs.la
libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
# ts A80114 : added aaip_0_2.*
libisofs_libisofs_la_SOURCES = \
libisofs/builder.h \
libisofs/builder.c \
@ -57,9 +60,12 @@ libisofs_libisofs_la_SOURCES = \
libisofs/make_isohybrid_mbr.c \
libisofs/iso1999.h \
libisofs/iso1999.c \
libisofs/data_source.c
libisofs/data_source.c \
libisofs/aaip_0_2.h \
libisofs/aaip_0_2.c
libisofs_libisofs_la_LIBADD= \
$(THREAD_LIBS)
$(THREAD_LIBS) \
-lacl
libinclude_HEADERS = \
libisofs/libisofs.h
@ -81,51 +87,61 @@ noinst_PROGRAMS = \
demo/isogrow
demo_lsl_CPPFLAGS = -Ilibisofs
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_lsl_SOURCES = demo/lsl.c
demo_cat_CPPFLAGS = -Ilibisofs
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_cat_SOURCES = demo/cat.c
demo_catbuffer_CPPFLAGS = -Ilibisofs
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_catbuffer_SOURCES = demo/cat_buffer.c
demo_tree_CPPFLAGS = -Ilibisofs
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_tree_SOURCES = demo/tree.c
demo_find_CPPFLAGS = -Ilibisofs
demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_find_SOURCES = demo/find.c
demo_ecma119tree_CPPFLAGS = -Ilibisofs
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
demo_iso_CPPFLAGS = -Ilibisofs
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_iso_SOURCES = demo/iso.c
demo_isoread_CPPFLAGS = -Ilibisofs
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isoread_SOURCES = demo/iso_read.c
demo_isocat_CPPFLAGS = -Ilibisofs
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isocat_SOURCES = demo/iso_cat.c
demo_isomodify_CPPFLAGS = -Ilibisofs
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isomodify_SOURCES = demo/iso_modify.c
demo_isoms_CPPFLAGS = -Ilibisofs
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isoms_SOURCES = demo/iso_ms.c
demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn
demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD) \
-lburn
demo_isogrow_SOURCES = demo/iso_grow.c
@ -135,7 +151,8 @@ check_PROGRAMS = \
test/test
test_test_CPPFLAGS = -Ilibisofs
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD) -lcunit
test_test_LDFLAGS = -L.. -lm
test_test_SOURCES = \
@ -177,6 +194,8 @@ uninstall-local:
nodist_pkgconfig_DATA = \
libisofs-1.pc
# ts A80114 : added aaip-os*
EXTRA_DIST = \
libisofs-1.pc.in \
version.h.in \
@ -186,9 +205,12 @@ EXTRA_DIST = \
AUTHORS \
COPYRIGHT \
COPYING \
NEWS \
INSTALL \
TODO \
ChangeLog \
Roadmap
NEWS \
INSTALL \
TODO \
ChangeLog \
Roadmap \
doc/susp_aaip_0_2.txt \
libisofs/aaip-os-linux.c \
libisofs/aaip-os-freebsd.c

@ -0,0 +1,333 @@
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.
This SUSP field and the ER entry of AAIP shall only be present if the ER entry
of RRIP is present.
-------------------------------------------------------------------------------
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
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)

@ -0,0 +1,283 @@
/*
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 <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/acl.h>
/* ------------------------------ 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);
}

@ -0,0 +1,371 @@
/*
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 <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/acl.h>
#include <attr/xattr.h>
#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);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,381 @@
/*
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,