Add NFSv4 support to setfacl(1).
Reviewed by: rwatson
This commit is contained in:
parent
2ef29b4c33
commit
3f22187878
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=196936
@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
/* set the appropriate mask the given ACL's */
|
/* set the appropriate mask the given ACL's */
|
||||||
int
|
int
|
||||||
set_acl_mask(acl_t *prev_acl)
|
set_acl_mask(acl_t *prev_acl, const char *filename)
|
||||||
{
|
{
|
||||||
acl_entry_t entry;
|
acl_entry_t entry;
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
@ -59,7 +59,7 @@ set_acl_mask(acl_t *prev_acl)
|
|||||||
|
|
||||||
acl = acl_dup(*prev_acl);
|
acl = acl_dup(*prev_acl);
|
||||||
if (acl == NULL)
|
if (acl == NULL)
|
||||||
err(1, "acl_dup() failed");
|
err(1, "%s: acl_dup() failed", filename);
|
||||||
|
|
||||||
if (n_flag == 0) {
|
if (n_flag == 0) {
|
||||||
/*
|
/*
|
||||||
@ -70,7 +70,7 @@ set_acl_mask(acl_t *prev_acl)
|
|||||||
* class in the resulting ACL
|
* class in the resulting ACL
|
||||||
*/
|
*/
|
||||||
if (acl_calc_mask(&acl)) {
|
if (acl_calc_mask(&acl)) {
|
||||||
warn("acl_calc_mask() failed");
|
warn("%s: acl_calc_mask() failed", filename);
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -86,7 +86,8 @@ set_acl_mask(acl_t *prev_acl)
|
|||||||
while (acl_get_entry(acl, entry_id, &entry) == 1) {
|
while (acl_get_entry(acl, entry_id, &entry) == 1) {
|
||||||
entry_id = ACL_NEXT_ENTRY;
|
entry_id = ACL_NEXT_ENTRY;
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
if (acl_get_tag_type(entry, &tag) == -1)
|
||||||
err(1, "acl_get_tag_type() failed");
|
err(1, "%s: acl_get_tag_type() failed",
|
||||||
|
filename);
|
||||||
|
|
||||||
if (tag == ACL_MASK) {
|
if (tag == ACL_MASK) {
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
@ -100,7 +101,7 @@ set_acl_mask(acl_t *prev_acl)
|
|||||||
* file, then write an error message to standard error and
|
* file, then write an error message to standard error and
|
||||||
* continue with the next file.
|
* continue with the next file.
|
||||||
*/
|
*/
|
||||||
warnx("warning: no mask entry");
|
warnx("%s: warning: no mask entry", filename);
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,15 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "setfacl.h"
|
#include "setfacl.h"
|
||||||
|
|
||||||
static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new);
|
static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new,
|
||||||
|
int acl_brand);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new)
|
merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand)
|
||||||
{
|
{
|
||||||
acl_permset_t permset;
|
acl_permset_t permset;
|
||||||
|
acl_entry_type_t entry_type;
|
||||||
|
acl_flagset_t flagset;
|
||||||
int have_entry;
|
int have_entry;
|
||||||
uid_t *id, *id_new;
|
uid_t *id, *id_new;
|
||||||
|
|
||||||
@ -59,6 +62,18 @@ merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new)
|
|||||||
err(1, "acl_get_permset() failed");
|
err(1, "acl_get_permset() failed");
|
||||||
if (acl_set_permset(*entry_new, permset) == -1)
|
if (acl_set_permset(*entry_new, permset) == -1)
|
||||||
err(1, "acl_set_permset() failed");
|
err(1, "acl_set_permset() failed");
|
||||||
|
|
||||||
|
if (acl_brand == ACL_BRAND_NFS4) {
|
||||||
|
if (acl_get_entry_type_np(*entry, &entry_type))
|
||||||
|
err(1, "acl_get_entry_type_np() failed");
|
||||||
|
if (acl_set_entry_type_np(*entry_new, entry_type))
|
||||||
|
err(1, "acl_set_entry_type_np() failed");
|
||||||
|
if (acl_get_flagset_np(*entry, &flagset))
|
||||||
|
err(1, "acl_get_flagset_np() failed");
|
||||||
|
if (acl_set_flagset_np(*entry_new, flagset))
|
||||||
|
err(1, "acl_set_flagset_np() failed");
|
||||||
|
}
|
||||||
|
|
||||||
have_entry = 1;
|
have_entry = 1;
|
||||||
}
|
}
|
||||||
acl_free(id);
|
acl_free(id);
|
||||||
@ -71,20 +86,31 @@ merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new)
|
|||||||
* merge an ACL into existing file's ACL
|
* merge an ACL into existing file's ACL
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
merge_acl(acl_t acl, acl_t *prev_acl)
|
merge_acl(acl_t acl, acl_t *prev_acl, const char *filename)
|
||||||
{
|
{
|
||||||
acl_entry_t entry, entry_new;
|
acl_entry_t entry, entry_new;
|
||||||
acl_permset_t permset;
|
acl_permset_t permset;
|
||||||
acl_t acl_new;
|
acl_t acl_new;
|
||||||
acl_tag_t tag, tag_new;
|
acl_tag_t tag, tag_new;
|
||||||
int entry_id, entry_id_new, have_entry;
|
acl_entry_type_t entry_type, entry_type_new;
|
||||||
|
acl_flagset_t flagset;
|
||||||
|
int entry_id, entry_id_new, have_entry, entry_number = 0;
|
||||||
|
int acl_brand, prev_acl_brand;
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS)
|
acl_get_brand_np(acl, &acl_brand);
|
||||||
acl_new = acl_dup(prev_acl[ACCESS_ACL]);
|
acl_get_brand_np(*prev_acl, &prev_acl_brand);
|
||||||
else
|
|
||||||
acl_new = acl_dup(prev_acl[DEFAULT_ACL]);
|
if (acl_brand != prev_acl_brand) {
|
||||||
|
warnx("%s: branding mismatch; existing ACL is %s, "
|
||||||
|
"entry to be merged is %s", filename,
|
||||||
|
prev_acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e",
|
||||||
|
acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_new = acl_dup(*prev_acl);
|
||||||
if (acl_new == NULL)
|
if (acl_new == NULL)
|
||||||
err(1, "acl_dup() failed");
|
err(1, "%s: acl_dup() failed", filename);
|
||||||
|
|
||||||
entry_id = ACL_FIRST_ENTRY;
|
entry_id = ACL_FIRST_ENTRY;
|
||||||
|
|
||||||
@ -94,28 +120,45 @@ merge_acl(acl_t acl, acl_t *prev_acl)
|
|||||||
|
|
||||||
/* keep track of existing ACL_MASK entries */
|
/* keep track of existing ACL_MASK entries */
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
if (acl_get_tag_type(entry, &tag) == -1)
|
||||||
err(1, "acl_get_tag_type() failed - invalid ACL entry");
|
err(1, "%s: acl_get_tag_type() failed - "
|
||||||
|
"invalid ACL entry", filename);
|
||||||
if (tag == ACL_MASK)
|
if (tag == ACL_MASK)
|
||||||
have_mask = 1;
|
have_mask = 1;
|
||||||
|
|
||||||
/* check against the existing ACL entries */
|
/* check against the existing ACL entries */
|
||||||
entry_id_new = ACL_FIRST_ENTRY;
|
entry_id_new = ACL_FIRST_ENTRY;
|
||||||
while (have_entry == 0 &&
|
while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
|
||||||
acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
|
|
||||||
entry_id_new = ACL_NEXT_ENTRY;
|
entry_id_new = ACL_NEXT_ENTRY;
|
||||||
|
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
if (acl_get_tag_type(entry, &tag) == -1)
|
||||||
err(1, "acl_get_tag_type() failed");
|
err(1, "%s: acl_get_tag_type() failed",
|
||||||
|
filename);
|
||||||
if (acl_get_tag_type(entry_new, &tag_new) == -1)
|
if (acl_get_tag_type(entry_new, &tag_new) == -1)
|
||||||
err(1, "acl_get_tag_type() failed");
|
err(1, "%s: acl_get_tag_type() failed",
|
||||||
|
filename);
|
||||||
if (tag != tag_new)
|
if (tag != tag_new)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For NFSv4, in addition to "tag" and "id" we also
|
||||||
|
* compare "entry_type".
|
||||||
|
*/
|
||||||
|
if (acl_brand == ACL_BRAND_NFS4) {
|
||||||
|
if (acl_get_entry_type_np(entry, &entry_type))
|
||||||
|
err(1, "%s: acl_get_entry_type_np() "
|
||||||
|
"failed", filename);
|
||||||
|
if (acl_get_entry_type_np(entry_new, &entry_type_new))
|
||||||
|
err(1, "%s: acl_get_entry_type_np() "
|
||||||
|
"failed", filename);
|
||||||
|
if (entry_type != entry_type_new)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch(tag) {
|
switch(tag) {
|
||||||
case ACL_USER:
|
case ACL_USER:
|
||||||
case ACL_GROUP:
|
case ACL_GROUP:
|
||||||
have_entry = merge_user_group(&entry,
|
have_entry = merge_user_group(&entry,
|
||||||
&entry_new);
|
&entry_new, acl_brand);
|
||||||
if (have_entry == 0)
|
if (have_entry == 0)
|
||||||
break;
|
break;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
@ -123,37 +166,127 @@ merge_acl(acl_t acl, acl_t *prev_acl)
|
|||||||
case ACL_GROUP_OBJ:
|
case ACL_GROUP_OBJ:
|
||||||
case ACL_OTHER:
|
case ACL_OTHER:
|
||||||
case ACL_MASK:
|
case ACL_MASK:
|
||||||
|
case ACL_EVERYONE:
|
||||||
if (acl_get_permset(entry, &permset) == -1)
|
if (acl_get_permset(entry, &permset) == -1)
|
||||||
err(1, "acl_get_permset() failed");
|
err(1, "%s: acl_get_permset() failed",
|
||||||
|
filename);
|
||||||
if (acl_set_permset(entry_new, permset) == -1)
|
if (acl_set_permset(entry_new, permset) == -1)
|
||||||
err(1, "acl_set_permset() failed");
|
err(1, "%s: acl_set_permset() failed",
|
||||||
|
filename);
|
||||||
|
|
||||||
|
if (acl_brand == ACL_BRAND_NFS4) {
|
||||||
|
if (acl_get_entry_type_np(entry, &entry_type))
|
||||||
|
err(1, "%s: acl_get_entry_type_np() failed",
|
||||||
|
filename);
|
||||||
|
if (acl_set_entry_type_np(entry_new, entry_type))
|
||||||
|
err(1, "%s: acl_set_entry_type_np() failed",
|
||||||
|
filename);
|
||||||
|
if (acl_get_flagset_np(entry, &flagset))
|
||||||
|
err(1, "%s: acl_get_flagset_np() failed",
|
||||||
|
filename);
|
||||||
|
if (acl_set_flagset_np(entry_new, flagset))
|
||||||
|
err(1, "%s: acl_set_flagset_np() failed",
|
||||||
|
filename);
|
||||||
|
}
|
||||||
have_entry = 1;
|
have_entry = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* should never be here */
|
/* should never be here */
|
||||||
errx(1, "Invalid tag type: %i", tag);
|
errx(1, "%s: invalid tag type: %i", filename, tag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if this entry has not been found, it must be new */
|
/* if this entry has not been found, it must be new */
|
||||||
if (have_entry == 0) {
|
if (have_entry == 0) {
|
||||||
if (acl_create_entry(&acl_new, &entry_new) == -1) {
|
|
||||||
acl_free(acl_new);
|
/*
|
||||||
return (-1);
|
* NFSv4 ACL entries must be prepended to the ACL.
|
||||||
|
* Appending them at the end makes no sense, since
|
||||||
|
* in most cases they wouldn't even get evaluated.
|
||||||
|
*/
|
||||||
|
if (acl_brand == ACL_BRAND_NFS4) {
|
||||||
|
if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) {
|
||||||
|
warn("%s: acl_create_entry_np() failed", filename);
|
||||||
|
acl_free(acl_new);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Without this increment, adding several
|
||||||
|
* entries at once, for example
|
||||||
|
* "setfacl -m user:1:r:allow,user:2:r:allow",
|
||||||
|
* would make them appear in reverse order.
|
||||||
|
*/
|
||||||
|
entry_number++;
|
||||||
|
} else {
|
||||||
|
if (acl_create_entry(&acl_new, &entry_new) == -1) {
|
||||||
|
warn("%s: acl_create_entry() failed", filename);
|
||||||
|
acl_free(acl_new);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (acl_copy_entry(entry_new, entry) == -1)
|
if (acl_copy_entry(entry_new, entry) == -1)
|
||||||
err(1, "acl_copy_entry() failed");
|
err(1, "%s: acl_copy_entry() failed", filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS) {
|
acl_free(*prev_acl);
|
||||||
acl_free(prev_acl[ACCESS_ACL]);
|
*prev_acl = acl_new;
|
||||||
prev_acl[ACCESS_ACL] = acl_new;
|
|
||||||
} else {
|
return (0);
|
||||||
acl_free(prev_acl[DEFAULT_ACL]);
|
}
|
||||||
prev_acl[DEFAULT_ACL] = acl_new;
|
|
||||||
}
|
int
|
||||||
|
add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, const char *filename)
|
||||||
|
{
|
||||||
|
acl_entry_t entry, entry_new;
|
||||||
|
acl_t acl_new;
|
||||||
|
int entry_id, acl_brand, prev_acl_brand;
|
||||||
|
|
||||||
|
acl_get_brand_np(acl, &acl_brand);
|
||||||
|
acl_get_brand_np(*prev_acl, &prev_acl_brand);
|
||||||
|
|
||||||
|
if (prev_acl_brand != ACL_BRAND_NFS4) {
|
||||||
|
warnx("%s: the '-a' option is only applicable to NFSv4 ACLs",
|
||||||
|
filename);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acl_brand != ACL_BRAND_NFS4) {
|
||||||
|
warnx("%s: branding mismatch; existing ACL is NFSv4, "
|
||||||
|
"entry to be added is POSIX.1e", filename);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_new = acl_dup(*prev_acl);
|
||||||
|
if (acl_new == NULL)
|
||||||
|
err(1, "%s: acl_dup() failed", filename);
|
||||||
|
|
||||||
|
entry_id = ACL_FIRST_ENTRY;
|
||||||
|
|
||||||
|
while (acl_get_entry(acl, entry_id, &entry) == 1) {
|
||||||
|
entry_id = ACL_NEXT_ENTRY;
|
||||||
|
|
||||||
|
if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) {
|
||||||
|
warn("%s: acl_create_entry_np() failed", filename);
|
||||||
|
acl_free(acl_new);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Without this increment, adding several
|
||||||
|
* entries at once, for example
|
||||||
|
* "setfacl -m user:1:r:allow,user:2:r:allow",
|
||||||
|
* would make them appear in reverse order.
|
||||||
|
*/
|
||||||
|
entry_number++;
|
||||||
|
|
||||||
|
if (acl_copy_entry(entry_new, entry) == -1)
|
||||||
|
err(1, "%s: acl_copy_entry() failed", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_free(*prev_acl);
|
||||||
|
*prev_acl = acl_new;
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -41,21 +41,31 @@ __FBSDID("$FreeBSD$");
|
|||||||
* remove ACL entries from an ACL
|
* remove ACL entries from an ACL
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
remove_acl(acl_t acl, acl_t *prev_acl)
|
remove_acl(acl_t acl, acl_t *prev_acl, const char *filename)
|
||||||
{
|
{
|
||||||
acl_entry_t entry;
|
acl_entry_t entry;
|
||||||
acl_t acl_new;
|
acl_t acl_new;
|
||||||
acl_tag_t tag;
|
acl_tag_t tag;
|
||||||
int carried_error, entry_id;
|
int carried_error, entry_id, acl_brand, prev_acl_brand;
|
||||||
|
|
||||||
carried_error = 0;
|
carried_error = 0;
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS)
|
acl_get_brand_np(acl, &acl_brand);
|
||||||
acl_new = acl_dup(prev_acl[ACCESS_ACL]);
|
acl_get_brand_np(*prev_acl, &prev_acl_brand);
|
||||||
else
|
|
||||||
acl_new = acl_dup(prev_acl[DEFAULT_ACL]);
|
if (acl_brand != prev_acl_brand) {
|
||||||
|
warnx("%s: branding mismatch; existing ACL is %s, "
|
||||||
|
"entry to be removed is %s", filename,
|
||||||
|
prev_acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e",
|
||||||
|
acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
carried_error = 0;
|
||||||
|
|
||||||
|
acl_new = acl_dup(*prev_acl);
|
||||||
if (acl_new == NULL)
|
if (acl_new == NULL)
|
||||||
err(1, "acl_dup() failed");
|
err(1, "%s: acl_dup() failed", filename);
|
||||||
|
|
||||||
tag = ACL_UNDEFINED_TAG;
|
tag = ACL_UNDEFINED_TAG;
|
||||||
|
|
||||||
@ -64,23 +74,68 @@ remove_acl(acl_t acl, acl_t *prev_acl)
|
|||||||
while (acl_get_entry(acl, entry_id, &entry) == 1) {
|
while (acl_get_entry(acl, entry_id, &entry) == 1) {
|
||||||
entry_id = ACL_NEXT_ENTRY;
|
entry_id = ACL_NEXT_ENTRY;
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
if (acl_get_tag_type(entry, &tag) == -1)
|
||||||
err(1, "acl_get_tag_type() failed");
|
err(1, "%s: acl_get_tag_type() failed", filename);
|
||||||
if (tag == ACL_MASK)
|
if (tag == ACL_MASK)
|
||||||
have_mask++;
|
have_mask++;
|
||||||
if (acl_delete_entry(acl_new, entry) == -1) {
|
if (acl_delete_entry(acl_new, entry) == -1) {
|
||||||
carried_error++;
|
carried_error++;
|
||||||
warnx("cannot remove non-existent acl entry");
|
warnx("%s: cannot remove non-existent ACL entry",
|
||||||
|
filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS) {
|
acl_free(*prev_acl);
|
||||||
acl_free(prev_acl[ACCESS_ACL]);
|
*prev_acl = acl_new;
|
||||||
prev_acl[ACCESS_ACL] = acl_new;
|
|
||||||
} else {
|
if (carried_error)
|
||||||
acl_free(prev_acl[DEFAULT_ACL]);
|
return (-1);
|
||||||
prev_acl[DEFAULT_ACL] = acl_new;
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
remove_by_number(uint entry_number, acl_t *prev_acl, const char *filename)
|
||||||
|
{
|
||||||
|
acl_entry_t entry;
|
||||||
|
acl_t acl_new;
|
||||||
|
acl_tag_t tag;
|
||||||
|
int carried_error, entry_id;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
carried_error = 0;
|
||||||
|
|
||||||
|
acl_new = acl_dup(*prev_acl);
|
||||||
|
if (acl_new == NULL)
|
||||||
|
err(1, "%s: acl_dup() failed", filename);
|
||||||
|
|
||||||
|
tag = ACL_UNDEFINED_TAG;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find out whether we're removing the mask entry,
|
||||||
|
* to behave the same as the routine above.
|
||||||
|
*
|
||||||
|
* XXX: Is this loop actually needed?
|
||||||
|
*/
|
||||||
|
entry_id = ACL_FIRST_ENTRY;
|
||||||
|
i = 0;
|
||||||
|
while (acl_get_entry(acl_new, entry_id, &entry) == 1) {
|
||||||
|
entry_id = ACL_NEXT_ENTRY;
|
||||||
|
if (i != entry_number)
|
||||||
|
continue;
|
||||||
|
if (acl_get_tag_type(entry, &tag) == -1)
|
||||||
|
err(1, "%s: acl_get_tag_type() failed", filename);
|
||||||
|
if (tag == ACL_MASK)
|
||||||
|
have_mask++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (acl_delete_entry_np(acl_new, entry_number) == -1) {
|
||||||
|
carried_error++;
|
||||||
|
warn("%s: acl_delete_entry_np() failed", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
acl_free(*prev_acl);
|
||||||
|
*prev_acl = acl_new;
|
||||||
|
|
||||||
if (carried_error)
|
if (carried_error)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
@ -91,18 +146,14 @@ remove_acl(acl_t acl, acl_t *prev_acl)
|
|||||||
* remove default entries
|
* remove default entries
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
remove_default(acl_t *prev_acl)
|
remove_default(acl_t *prev_acl, const char *filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (prev_acl[1]) {
|
acl_free(*prev_acl);
|
||||||
acl_free(prev_acl[1]);
|
*prev_acl = acl_init(ACL_MAX_ENTRIES);
|
||||||
prev_acl[1] = acl_init(ACL_MAX_ENTRIES);
|
if (*prev_acl == NULL)
|
||||||
if (prev_acl[1] == NULL)
|
err(1, "%s: acl_init() failed", filename);
|
||||||
err(1, "acl_init() failed");
|
|
||||||
} else {
|
|
||||||
warn("cannot remove default ACL");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,71 +161,14 @@ remove_default(acl_t *prev_acl)
|
|||||||
* remove extended entries
|
* remove extended entries
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
remove_ext(acl_t *prev_acl)
|
remove_ext(acl_t *prev_acl, const char *filename)
|
||||||
{
|
{
|
||||||
acl_t acl_new, acl_old;
|
acl_t acl_new;
|
||||||
acl_entry_t entry, entry_new;
|
|
||||||
acl_permset_t perm;
|
|
||||||
acl_tag_t tag;
|
|
||||||
int entry_id, have_mask_entry;
|
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS)
|
acl_new = acl_strip_np(*prev_acl, !n_flag);
|
||||||
acl_old = acl_dup(prev_acl[ACCESS_ACL]);
|
|
||||||
else
|
|
||||||
acl_old = acl_dup(prev_acl[DEFAULT_ACL]);
|
|
||||||
if (acl_old == NULL)
|
|
||||||
err(1, "acl_dup() failed");
|
|
||||||
|
|
||||||
have_mask_entry = 0;
|
|
||||||
acl_new = acl_init(ACL_MAX_ENTRIES);
|
|
||||||
if (acl_new == NULL)
|
if (acl_new == NULL)
|
||||||
err(1, "acl_init() failed");
|
err(1, "%s: acl_strip_np() failed", filename);
|
||||||
tag = ACL_UNDEFINED_TAG;
|
|
||||||
|
|
||||||
/* only save the default user/group/other entries */
|
acl_free(*prev_acl);
|
||||||
entry_id = ACL_FIRST_ENTRY;
|
*prev_acl = acl_new;
|
||||||
while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
|
|
||||||
entry_id = ACL_NEXT_ENTRY;
|
|
||||||
|
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
|
||||||
err(1, "acl_get_tag_type() failed");
|
|
||||||
|
|
||||||
switch(tag) {
|
|
||||||
case ACL_USER_OBJ:
|
|
||||||
case ACL_GROUP_OBJ:
|
|
||||||
case ACL_OTHER:
|
|
||||||
if (acl_get_tag_type(entry, &tag) == -1)
|
|
||||||
err(1, "acl_get_tag_type() failed");
|
|
||||||
if (acl_get_permset(entry, &perm) == -1)
|
|
||||||
err(1, "acl_get_permset() failed");
|
|
||||||
if (acl_create_entry(&acl_new, &entry_new) == -1)
|
|
||||||
err(1, "acl_create_entry() failed");
|
|
||||||
if (acl_set_tag_type(entry_new, tag) == -1)
|
|
||||||
err(1, "acl_set_tag_type() failed");
|
|
||||||
if (acl_set_permset(entry_new, perm) == -1)
|
|
||||||
err(1, "acl_get_permset() failed");
|
|
||||||
if (acl_copy_entry(entry_new, entry) == -1)
|
|
||||||
err(1, "acl_copy_entry() failed");
|
|
||||||
break;
|
|
||||||
case ACL_MASK:
|
|
||||||
have_mask_entry = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (have_mask_entry && n_flag == 0) {
|
|
||||||
if (acl_calc_mask(&acl_new) == -1)
|
|
||||||
err(1, "acl_calc_mask() failed");
|
|
||||||
} else {
|
|
||||||
have_mask = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS) {
|
|
||||||
acl_free(prev_acl[ACCESS_ACL]);
|
|
||||||
prev_acl[ACCESS_ACL] = acl_new;
|
|
||||||
} else {
|
|
||||||
acl_free(prev_acl[DEFAULT_ACL]);
|
|
||||||
prev_acl[DEFAULT_ACL] = acl_new;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 7, 2001
|
.Dd September 5, 2009
|
||||||
.Dt SETFACL 1
|
.Dt SETFACL 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -34,9 +34,10 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl bdhkn
|
.Op Fl bdhkn
|
||||||
|
.Op Fl a Ar position entries
|
||||||
.Op Fl m Ar entries
|
.Op Fl m Ar entries
|
||||||
.Op Fl M Ar file
|
.Op Fl M Ar file
|
||||||
.Op Fl x Ar entries
|
.Op Fl x Ar entries | position
|
||||||
.Op Fl X Ar file
|
.Op Fl X Ar file
|
||||||
.Op Ar
|
.Op Ar
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
@ -50,9 +51,19 @@ the file names are taken from the standard input.
|
|||||||
.Pp
|
.Pp
|
||||||
The following options are available:
|
The following options are available:
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
|
.It Fl a Ar position entries
|
||||||
|
Modify the ACL on the specified files by inserting new
|
||||||
|
ACL entries
|
||||||
|
specified in
|
||||||
|
.Ar entries ,
|
||||||
|
starting at position
|
||||||
|
.Ar position ,
|
||||||
|
counting from zero.
|
||||||
|
This option is only applicable to NFSv4 ACLs.
|
||||||
.It Fl b
|
.It Fl b
|
||||||
Remove all ACL entries except for the three required entries.
|
Remove all ACL entries except for the three required entries
|
||||||
If the ACL contains a
|
(POSIX.1e ACLs) or six "canonical" entries (NFSv4 ACLs).
|
||||||
|
If the POSIX.1e ACL contains a
|
||||||
.Dq Li mask
|
.Dq Li mask
|
||||||
entry, the permissions of the
|
entry, the permissions of the
|
||||||
.Dq Li group
|
.Dq Li group
|
||||||
@ -66,7 +77,7 @@ entries of the current ACL.
|
|||||||
The operations apply to the default ACL entries instead of
|
The operations apply to the default ACL entries instead of
|
||||||
access ACL entries.
|
access ACL entries.
|
||||||
Currently only directories may have
|
Currently only directories may have
|
||||||
default ACL's.
|
default ACL's. This option is not applicable to NFSv4 ACLs.
|
||||||
.It Fl h
|
.It Fl h
|
||||||
If the target of the operation is a symbolic link, perform the operation
|
If the target of the operation is a symbolic link, perform the operation
|
||||||
on the symbolic link itself, rather than following the link.
|
on the symbolic link itself, rather than following the link.
|
||||||
@ -77,7 +88,7 @@ is not considered an error if the specified files do not have
|
|||||||
any default ACL entries.
|
any default ACL entries.
|
||||||
An error will be reported if any of
|
An error will be reported if any of
|
||||||
the specified files cannot have a default entry (i.e.\&
|
the specified files cannot have a default entry (i.e.\&
|
||||||
non-directories).
|
non-directories). This option is not applicable to NFSv4 ACLs.
|
||||||
.It Fl m Ar entries
|
.It Fl m Ar entries
|
||||||
Modify the ACL entries on the specified files by adding new
|
Modify the ACL entries on the specified files by adding new
|
||||||
entries and modifying existing ACL entries with the ACL entries
|
entries and modifying existing ACL entries with the ACL entries
|
||||||
@ -95,11 +106,15 @@ is
|
|||||||
the input is taken from stdin.
|
the input is taken from stdin.
|
||||||
.It Fl n
|
.It Fl n
|
||||||
Do not recalculate the permissions associated with the ACL
|
Do not recalculate the permissions associated with the ACL
|
||||||
mask entry.
|
mask entry. This option is not applicable to NFSv4 ACLs.
|
||||||
.It Fl x Ar entries
|
.It Fl x Ar entries | position
|
||||||
Remove the ACL entries specified in
|
If
|
||||||
.Ar entries
|
.Ar entries
|
||||||
|
is specified, remove the ACL entries specified there
|
||||||
from the access or default ACL of the specified files.
|
from the access or default ACL of the specified files.
|
||||||
|
Otherwise, remove entry at index
|
||||||
|
.Ar position ,
|
||||||
|
counting from zero.
|
||||||
.It Fl X Ar file
|
.It Fl X Ar file
|
||||||
Remove the ACL entries specified in the file
|
Remove the ACL entries specified in the file
|
||||||
.Ar file
|
.Ar file
|
||||||
@ -108,8 +123,8 @@ from the access or default ACL of the specified files.
|
|||||||
.Pp
|
.Pp
|
||||||
The above options are evaluated in the order specified
|
The above options are evaluated in the order specified
|
||||||
on the command-line.
|
on the command-line.
|
||||||
.Sh ACL ENTRIES
|
.Sh POSIX.1e ACL ENTRIES
|
||||||
An ACL entry contains three colon-separated fields:
|
A POSIX.1E ACL entry contains three colon-separated fields:
|
||||||
an ACL tag, an ACL qualifier, and discretionary access
|
an ACL tag, an ACL qualifier, and discretionary access
|
||||||
permissions:
|
permissions:
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
@ -223,7 +238,7 @@ previously specified; whitespace is ignored; any text after a
|
|||||||
.Ql #
|
.Ql #
|
||||||
is ignored (comments).
|
is ignored (comments).
|
||||||
.Pp
|
.Pp
|
||||||
When ACL entries are evaluated, the access check algorithm checks
|
When POSIX.1e ACL entries are evaluated, the access check algorithm checks
|
||||||
the ACL entries in the following order: file owner,
|
the ACL entries in the following order: file owner,
|
||||||
.Dq Li user
|
.Dq Li user
|
||||||
ACL entries, file owning group,
|
ACL entries, file owning group,
|
||||||
@ -243,13 +258,135 @@ ACL entries for user, group, other and mask must be set.
|
|||||||
For more details see the examples below.
|
For more details see the examples below.
|
||||||
Default ACLs can be created by using
|
Default ACLs can be created by using
|
||||||
.Fl d .
|
.Fl d .
|
||||||
|
.Sh NFSv4 ACL ENTRIES
|
||||||
|
An NFSv4 ACL entry contains four or five colon-separated fields: an ACL tag,
|
||||||
|
an ACL qualifier (only for
|
||||||
|
.Dq Li user
|
||||||
|
and
|
||||||
|
.Dq Li group
|
||||||
|
tags), discretionary access permissions, ACL inheritance flags, and ACL type:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Ar "ACL tag"
|
||||||
|
The ACL tag specifies the ACL entry type and consists of
|
||||||
|
one of the following:
|
||||||
|
.Dq Li user
|
||||||
|
or
|
||||||
|
.Ql u
|
||||||
|
specifying the access
|
||||||
|
granted to the specified user;
|
||||||
|
.Dq Li group
|
||||||
|
or
|
||||||
|
.Ql g
|
||||||
|
specifying the access granted to the specified group;
|
||||||
|
.Dq Li owner@
|
||||||
|
specifying the access granted to the owner of the file;
|
||||||
|
.Dq Li group@
|
||||||
|
specifying the access granted to the file owning group;
|
||||||
|
.Dq Li everyone@
|
||||||
|
specifying everyone. Note that
|
||||||
|
.Dq Li everyone@
|
||||||
|
is not the same as traditional Unix
|
||||||
|
.Dq Li other
|
||||||
|
- it means,
|
||||||
|
literally, everyone, including file owner and owning group.
|
||||||
|
.It Ar "ACL qualifier"
|
||||||
|
The ACL qualifier field describes the user or group associated with
|
||||||
|
the ACL entry.
|
||||||
|
It may consist of one of the following: uid or
|
||||||
|
user name, or gid or group name. In entries whose tag type is
|
||||||
|
one of
|
||||||
|
.Dq Li owner@ ,
|
||||||
|
.Dq Li group@ ,
|
||||||
|
or
|
||||||
|
.Dq Li everyone@ ,
|
||||||
|
this field is ommited altogether, including the trailing comma.
|
||||||
|
.It Ar "access permissions"
|
||||||
|
Access permissions may be specified in either short or long form.
|
||||||
|
Short and long forms may not be mixed.
|
||||||
|
Permissions in long form are separated by the
|
||||||
|
.Ql /
|
||||||
|
character; in short form, they are concatenated together.
|
||||||
|
Valid permissions are:
|
||||||
|
.Bl -tag -width ".Dv short"
|
||||||
|
.It Short
|
||||||
|
Long
|
||||||
|
.It r
|
||||||
|
read_data
|
||||||
|
.It w
|
||||||
|
write_data
|
||||||
|
.It x
|
||||||
|
execute
|
||||||
|
.It p
|
||||||
|
append_data
|
||||||
|
.It d
|
||||||
|
delete_child
|
||||||
|
.It D
|
||||||
|
delete
|
||||||
|
.It a
|
||||||
|
read_attributes
|
||||||
|
.It A
|
||||||
|
write_attributes
|
||||||
|
.It R
|
||||||
|
read_xattr
|
||||||
|
.It W
|
||||||
|
write_xattr
|
||||||
|
.It c
|
||||||
|
read_acl
|
||||||
|
.It C
|
||||||
|
write_acl
|
||||||
|
.It o
|
||||||
|
write_owner
|
||||||
|
.It S
|
||||||
|
synchronize
|
||||||
|
.El
|
||||||
|
.It Ar "ACL inheritance flags"
|
||||||
|
Inheritance flags may be specified in either short or long form.
|
||||||
|
Short and long forms may not be mixed.
|
||||||
|
Access flags in long form are separated by the
|
||||||
|
.Ql /
|
||||||
|
character; in short form, they are concatenated together.
|
||||||
|
Valid inheritance flags are:
|
||||||
|
.Bl -tag -width ".Dv short"
|
||||||
|
.It Short
|
||||||
|
Long
|
||||||
|
.It f
|
||||||
|
file_inherit
|
||||||
|
.It d
|
||||||
|
dir_inherit
|
||||||
|
.It i
|
||||||
|
inherit_only
|
||||||
|
.It n
|
||||||
|
no_propagate
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Inheritance flags may be only set on directories.
|
||||||
|
.It Ar "ACL type"
|
||||||
|
The ACL type field is either
|
||||||
|
.Dq Li allow
|
||||||
|
or
|
||||||
|
.Dq Li deny .
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
ACL entries applied from a file using the
|
||||||
|
.Fl M
|
||||||
|
or
|
||||||
|
.Fl X
|
||||||
|
options shall be of the following form: one ACL entry per line, as
|
||||||
|
previously specified; whitespace is ignored; any text after a
|
||||||
|
.Ql #
|
||||||
|
is ignored (comments).
|
||||||
|
.Pp
|
||||||
|
NFSv4 ACL entries are evaluated in their visible order.
|
||||||
|
.Pp
|
||||||
|
Multiple ACL entries specified on the command line are
|
||||||
|
separated by commas.
|
||||||
.Sh EXIT STATUS
|
.Sh EXIT STATUS
|
||||||
.Ex -std
|
.Ex -std
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
.Dl setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx dir
|
.Dl setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx dir
|
||||||
.Dl setfacl -d -m g:admins:rwx dir
|
.Dl setfacl -d -m g:admins:rwx dir
|
||||||
.Pp
|
.Pp
|
||||||
The first command sets the mandatory elements of the default ACL.
|
The first command sets the mandatory elements of the POSIX.1e default ACL.
|
||||||
The second command specifies that users in group admins can have read, write, and execute
|
The second command specifies that users in group admins can have read, write, and execute
|
||||||
permissions for directory named "dir".
|
permissions for directory named "dir".
|
||||||
It should be noted that any files or directories created underneath "dir" will
|
It should be noted that any files or directories created underneath "dir" will
|
||||||
@ -259,9 +396,13 @@ inherit these default ACLs upon creation.
|
|||||||
.Pp
|
.Pp
|
||||||
Sets read, write, and execute permissions for the
|
Sets read, write, and execute permissions for the
|
||||||
.Pa file
|
.Pa file
|
||||||
owner's ACL entry and read and write permissions for group mail on
|
owner's POSIX.1e ACL entry and read and write permissions for group mail on
|
||||||
.Pa file .
|
.Pa file .
|
||||||
.Pp
|
.Pp
|
||||||
|
.Dl setfacl -m owner@:rwxp::allow,g:mail:rwp::allow file
|
||||||
|
.Pp
|
||||||
|
Semantically equal to the example above, but for NFSv4 ACL.
|
||||||
|
.Pp
|
||||||
.Dl setfacl -M file1 file2
|
.Dl setfacl -M file1 file2
|
||||||
.Pp
|
.Pp
|
||||||
Sets/updates the ACL entries contained in
|
Sets/updates the ACL entries contained in
|
||||||
@ -271,10 +412,15 @@ on
|
|||||||
.Pp
|
.Pp
|
||||||
.Dl setfacl -x g:mail:rw file
|
.Dl setfacl -x g:mail:rw file
|
||||||
.Pp
|
.Pp
|
||||||
Remove the group mail ACL entry containing read/write permissions
|
Remove the group mail POSIX.1e ACL entry containing read/write permissions
|
||||||
from
|
from
|
||||||
.Pa file .
|
.Pa file .
|
||||||
.Pp
|
.Pp
|
||||||
|
.Dl setfacl -x0 file
|
||||||
|
.Pp
|
||||||
|
Remove the first entry from the NFSv4 ACL from
|
||||||
|
.Pa file .
|
||||||
|
.Pp
|
||||||
.Dl setfacl -bn file
|
.Dl setfacl -bn file
|
||||||
.Pp
|
.Pp
|
||||||
Remove all
|
Remove all
|
||||||
|
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -41,9 +42,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "setfacl.h"
|
#include "setfacl.h"
|
||||||
|
|
||||||
static void add_filename(const char *filename);
|
static void add_filename(const char *filename);
|
||||||
static acl_t *get_file_acls(const char *filename);
|
static void usage(void);
|
||||||
static void usage(void);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_filename(const char *filename)
|
add_filename(const char *filename)
|
||||||
@ -59,57 +59,28 @@ add_filename(const char *filename)
|
|||||||
TAILQ_INSERT_TAIL(&filelist, file, next);
|
TAILQ_INSERT_TAIL(&filelist, file, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static acl_t *
|
|
||||||
get_file_acls(const char *filename)
|
|
||||||
{
|
|
||||||
acl_t *acl;
|
|
||||||
struct stat sb;
|
|
||||||
|
|
||||||
if (stat(filename, &sb) == -1) {
|
|
||||||
warn("stat() of %s failed", filename);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
acl = zmalloc(sizeof(acl_t) * 2);
|
|
||||||
if (h_flag)
|
|
||||||
acl[ACCESS_ACL] = acl_get_link_np(filename, ACL_TYPE_ACCESS);
|
|
||||||
else
|
|
||||||
acl[ACCESS_ACL] = acl_get_file(filename, ACL_TYPE_ACCESS);
|
|
||||||
if (acl[ACCESS_ACL] == NULL)
|
|
||||||
err(1, "acl_get_file() failed");
|
|
||||||
if (S_ISDIR(sb.st_mode)) {
|
|
||||||
if (h_flag)
|
|
||||||
acl[DEFAULT_ACL] = acl_get_link_np(filename,
|
|
||||||
ACL_TYPE_DEFAULT);
|
|
||||||
else
|
|
||||||
acl[DEFAULT_ACL] = acl_get_file(filename,
|
|
||||||
ACL_TYPE_DEFAULT);
|
|
||||||
if (acl[DEFAULT_ACL] == NULL)
|
|
||||||
err(1, "acl_get_file() failed");
|
|
||||||
} else
|
|
||||||
acl[DEFAULT_ACL] = NULL;
|
|
||||||
|
|
||||||
return (acl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr, "usage: setfacl [-bdhkn] [-m entries] [-M file] "
|
fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
|
||||||
"[-x entries] [-X file] [file ...]\n");
|
"[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
acl_t *acl, final_acl;
|
acl_t acl;
|
||||||
|
acl_type_t acl_type;
|
||||||
char filename[PATH_MAX];
|
char filename[PATH_MAX];
|
||||||
int local_error, carried_error, ch, i;
|
int local_error, carried_error, ch, i, entry_number, ret;
|
||||||
|
int h_flag;
|
||||||
struct sf_file *file;
|
struct sf_file *file;
|
||||||
struct sf_entry *entry;
|
struct sf_entry *entry;
|
||||||
const char *fn_dup;
|
const char *fn_dup;
|
||||||
|
char *end;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
acl_type = ACL_TYPE_ACCESS;
|
acl_type = ACL_TYPE_ACCESS;
|
||||||
carried_error = local_error = 0;
|
carried_error = local_error = 0;
|
||||||
@ -118,13 +89,13 @@ main(int argc, char *argv[])
|
|||||||
TAILQ_INIT(&entrylist);
|
TAILQ_INIT(&entrylist);
|
||||||
TAILQ_INIT(&filelist);
|
TAILQ_INIT(&filelist);
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "M:X:bdhkm:nx:")) != -1)
|
while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case 'M':
|
case 'M':
|
||||||
entry = zmalloc(sizeof(struct sf_entry));
|
entry = zmalloc(sizeof(struct sf_entry));
|
||||||
entry->acl = get_acl_from_file(optarg);
|
entry->acl = get_acl_from_file(optarg);
|
||||||
if (entry->acl == NULL)
|
if (entry->acl == NULL)
|
||||||
err(1, "get_acl_from_file() failed");
|
err(1, "%s: get_acl_from_file() failed", optarg);
|
||||||
entry->op = OP_MERGE_ACL;
|
entry->op = OP_MERGE_ACL;
|
||||||
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
||||||
break;
|
break;
|
||||||
@ -134,6 +105,25 @@ main(int argc, char *argv[])
|
|||||||
entry->op = OP_REMOVE_ACL;
|
entry->op = OP_REMOVE_ACL;
|
||||||
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
entry = zmalloc(sizeof(struct sf_entry));
|
||||||
|
|
||||||
|
entry_number = strtol(optarg, &end, 10);
|
||||||
|
if (end - optarg != (int)strlen(optarg))
|
||||||
|
errx(1, "%s: invalid entry number", optarg);
|
||||||
|
if (entry_number < 0)
|
||||||
|
errx(1, "%s: entry number cannot be less than zero", optarg);
|
||||||
|
entry->entry_number = entry_number;
|
||||||
|
|
||||||
|
if (argv[optind] == NULL)
|
||||||
|
errx(1, "missing ACL");
|
||||||
|
entry->acl = acl_from_text(argv[optind]);
|
||||||
|
if (entry->acl == NULL)
|
||||||
|
err(1, "%s", argv[optind]);
|
||||||
|
optind++;
|
||||||
|
entry->op = OP_ADD_ACL;
|
||||||
|
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
||||||
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
entry = zmalloc(sizeof(struct sf_entry));
|
entry = zmalloc(sizeof(struct sf_entry));
|
||||||
entry->op = OP_REMOVE_EXT;
|
entry->op = OP_REMOVE_EXT;
|
||||||
@ -163,10 +153,18 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
entry = zmalloc(sizeof(struct sf_entry));
|
entry = zmalloc(sizeof(struct sf_entry));
|
||||||
entry->acl = acl_from_text(optarg);
|
entry_number = strtol(optarg, &end, 10);
|
||||||
if (entry->acl == NULL)
|
if (end - optarg == (int)strlen(optarg)) {
|
||||||
err(1, "%s", optarg);
|
if (entry_number < 0)
|
||||||
entry->op = OP_REMOVE_ACL;
|
errx(1, "%s: entry number cannot be less than zero", optarg);
|
||||||
|
entry->entry_number = entry_number;
|
||||||
|
entry->op = OP_REMOVE_BY_NUMBER;
|
||||||
|
} else {
|
||||||
|
entry->acl = acl_from_text(optarg);
|
||||||
|
if (entry->acl == NULL)
|
||||||
|
err(1, "%s", optarg);
|
||||||
|
entry->op = OP_REMOVE_ACL;
|
||||||
|
}
|
||||||
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
TAILQ_INSERT_TAIL(&entrylist, entry, next);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -199,16 +197,51 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* cycle through each file */
|
/* cycle through each file */
|
||||||
TAILQ_FOREACH(file, &filelist, next) {
|
TAILQ_FOREACH(file, &filelist, next) {
|
||||||
/* get our initial access and default ACL's */
|
local_error = 0;
|
||||||
acl = get_file_acls(file->filename);
|
|
||||||
if (acl == NULL)
|
if (stat(file->filename, &sb) == -1) {
|
||||||
continue;
|
warn("%s: stat() failed", file->filename);
|
||||||
if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) {
|
|
||||||
warnx("Default ACL not valid for %s", file->filename);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_error = 0;
|
if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) {
|
||||||
|
warnx("%s: default ACL may only be set on a directory",
|
||||||
|
file->filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h_flag)
|
||||||
|
ret = lpathconf(file->filename, _PC_ACL_NFS4);
|
||||||
|
else
|
||||||
|
ret = pathconf(file->filename, _PC_ACL_NFS4);
|
||||||
|
if (ret > 0) {
|
||||||
|
if (acl_type == ACL_TYPE_DEFAULT) {
|
||||||
|
warnx("%s: there are no default entries "
|
||||||
|
"in NFSv4 ACLs", file->filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
acl_type = ACL_TYPE_NFS4;
|
||||||
|
} else if (ret == 0) {
|
||||||
|
if (acl_type == ACL_TYPE_NFS4)
|
||||||
|
acl_type = ACL_TYPE_ACCESS;
|
||||||
|
} else if (ret < 0 && errno != EINVAL) {
|
||||||
|
warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
|
||||||
|
file->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h_flag)
|
||||||
|
acl = acl_get_link_np(file->filename, acl_type);
|
||||||
|
else
|
||||||
|
acl = acl_get_file(file->filename, acl_type);
|
||||||
|
if (acl == NULL) {
|
||||||
|
if (h_flag)
|
||||||
|
warn("%s: acl_get_link_np() failed",
|
||||||
|
file->filename);
|
||||||
|
else
|
||||||
|
warn("%s: acl_get_file() failed",
|
||||||
|
file->filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* cycle through each option */
|
/* cycle through each option */
|
||||||
TAILQ_FOREACH(entry, &entrylist, next) {
|
TAILQ_FOREACH(entry, &entrylist, next) {
|
||||||
@ -216,24 +249,44 @@ main(int argc, char *argv[])
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch(entry->op) {
|
switch(entry->op) {
|
||||||
|
case OP_ADD_ACL:
|
||||||
|
local_error += add_acl(entry->acl,
|
||||||
|
entry->entry_number, &acl, file->filename);
|
||||||
|
break;
|
||||||
case OP_MERGE_ACL:
|
case OP_MERGE_ACL:
|
||||||
local_error += merge_acl(entry->acl, acl);
|
local_error += merge_acl(entry->acl, &acl,
|
||||||
|
file->filename);
|
||||||
need_mask = 1;
|
need_mask = 1;
|
||||||
break;
|
break;
|
||||||
case OP_REMOVE_EXT:
|
case OP_REMOVE_EXT:
|
||||||
remove_ext(acl);
|
remove_ext(&acl, file->filename);
|
||||||
need_mask = 0;
|
need_mask = 0;
|
||||||
break;
|
break;
|
||||||
case OP_REMOVE_DEF:
|
case OP_REMOVE_DEF:
|
||||||
|
if (acl_type == ACL_TYPE_NFS4) {
|
||||||
|
warnx("%s: there are no default entries in NFSv4 ACLs; "
|
||||||
|
"cannot remove", file->filename);
|
||||||
|
local_error++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (acl_delete_def_file(file->filename) == -1) {
|
if (acl_delete_def_file(file->filename) == -1) {
|
||||||
warn("acl_delete_def_file() failed");
|
warn("%s: acl_delete_def_file() failed",
|
||||||
|
file->filename);
|
||||||
local_error++;
|
local_error++;
|
||||||
}
|
}
|
||||||
local_error += remove_default(acl);
|
if (acl_type == ACL_TYPE_DEFAULT)
|
||||||
|
local_error += remove_default(&acl,
|
||||||
|
file->filename);
|
||||||
need_mask = 0;
|
need_mask = 0;
|
||||||
break;
|
break;
|
||||||
case OP_REMOVE_ACL:
|
case OP_REMOVE_ACL:
|
||||||
local_error += remove_acl(entry->acl, acl);
|
local_error += remove_acl(entry->acl, &acl,
|
||||||
|
file->filename);
|
||||||
|
need_mask = 1;
|
||||||
|
break;
|
||||||
|
case OP_REMOVE_BY_NUMBER:
|
||||||
|
local_error += remove_by_number(entry->entry_number,
|
||||||
|
&acl, file->filename);
|
||||||
need_mask = 1;
|
need_mask = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -245,35 +298,27 @@ main(int argc, char *argv[])
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acl_type == ACL_TYPE_ACCESS) {
|
if (acl_type != ACL_TYPE_NFS4 && need_mask &&
|
||||||
final_acl = acl[ACCESS_ACL];
|
set_acl_mask(&acl, file->filename) == -1) {
|
||||||
acl_free(acl[DEFAULT_ACL]);
|
warnx("%s: failed to set ACL mask", file->filename);
|
||||||
} else {
|
|
||||||
final_acl = acl[DEFAULT_ACL];
|
|
||||||
acl_free(acl[ACCESS_ACL]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (need_mask && (set_acl_mask(&final_acl) == -1)) {
|
|
||||||
warnx("failed to set ACL mask on %s", file->filename);
|
|
||||||
carried_error++;
|
carried_error++;
|
||||||
} else if (h_flag) {
|
} else if (h_flag) {
|
||||||
if (acl_set_link_np(file->filename, acl_type,
|
if (acl_set_link_np(file->filename, acl_type,
|
||||||
final_acl) == -1) {
|
acl) == -1) {
|
||||||
carried_error++;
|
carried_error++;
|
||||||
warn("acl_set_link_np() failed for %s",
|
warn("%s: acl_set_link_np() failed",
|
||||||
file->filename);
|
file->filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (acl_set_file(file->filename, acl_type,
|
if (acl_set_file(file->filename, acl_type,
|
||||||
final_acl) == -1) {
|
acl) == -1) {
|
||||||
carried_error++;
|
carried_error++;
|
||||||
warn("acl_set_file() failed for %s",
|
warn("%s: acl_set_file() failed",
|
||||||
file->filename);
|
file->filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acl_free(final_acl);
|
acl_free(acl);
|
||||||
free(acl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (carried_error);
|
return (carried_error);
|
||||||
|
@ -38,15 +38,14 @@
|
|||||||
#define OP_REMOVE_DEF 0x01 /* remove default acl's (-k) */
|
#define OP_REMOVE_DEF 0x01 /* remove default acl's (-k) */
|
||||||
#define OP_REMOVE_EXT 0x02 /* remove extended acl's (-b) */
|
#define OP_REMOVE_EXT 0x02 /* remove extended acl's (-b) */
|
||||||
#define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */
|
#define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */
|
||||||
|
#define OP_REMOVE_BY_NUMBER 0x04 /* remove acl's (-xX) by acl entry number */
|
||||||
/* ACL types for the acl array */
|
#define OP_ADD_ACL 0x05 /* add acls entries at a given position */
|
||||||
#define ACCESS_ACL 0
|
|
||||||
#define DEFAULT_ACL 1
|
|
||||||
|
|
||||||
/* TAILQ entry for acl operations */
|
/* TAILQ entry for acl operations */
|
||||||
struct sf_entry {
|
struct sf_entry {
|
||||||
uint op;
|
uint op;
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
|
uint entry_number;
|
||||||
TAILQ_ENTRY(sf_entry) next;
|
TAILQ_ENTRY(sf_entry) next;
|
||||||
};
|
};
|
||||||
TAILQ_HEAD(, sf_entry) entrylist;
|
TAILQ_HEAD(, sf_entry) entrylist;
|
||||||
@ -61,21 +60,21 @@ TAILQ_HEAD(, sf_file) filelist;
|
|||||||
/* files.c */
|
/* files.c */
|
||||||
acl_t get_acl_from_file(const char *filename);
|
acl_t get_acl_from_file(const char *filename);
|
||||||
/* merge.c */
|
/* merge.c */
|
||||||
int merge_acl(acl_t acl, acl_t *prev_acl);
|
int merge_acl(acl_t acl, acl_t *prev_acl, const char *filename);
|
||||||
|
int add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, const char *filename);
|
||||||
/* remove.c */
|
/* remove.c */
|
||||||
int remove_acl(acl_t acl, acl_t *prev_acl);
|
int remove_acl(acl_t acl, acl_t *prev_acl, const char *filename);
|
||||||
int remove_default(acl_t *prev_acl);
|
int remove_by_number(uint entry_number, acl_t *prev_acl, const char *filename);
|
||||||
void remove_ext(acl_t *prev_acl);
|
int remove_default(acl_t *prev_acl, const char *filename);
|
||||||
|
void remove_ext(acl_t *prev_acl, const char *filename);
|
||||||
/* mask.c */
|
/* mask.c */
|
||||||
int set_acl_mask(acl_t *prev_acl);
|
int set_acl_mask(acl_t *prev_acl, const char *filename);
|
||||||
/* util.c */
|
/* util.c */
|
||||||
void *zmalloc(size_t size);
|
void *zmalloc(size_t size);
|
||||||
|
|
||||||
acl_type_t acl_type;
|
|
||||||
uint have_mask;
|
uint have_mask;
|
||||||
uint need_mask;
|
uint need_mask;
|
||||||
uint have_stdin;
|
uint have_stdin;
|
||||||
uint h_flag;
|
|
||||||
uint n_flag;
|
uint n_flag;
|
||||||
|
|
||||||
#endif /* _SETFACL_H */
|
#endif /* _SETFACL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user