372 lines
11 KiB
C
372 lines
11 KiB
C
|
|
||
|
/*
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|