misc/155163: Add Recursive Functionality to setfacl
Shawn Webb
lattera at gmail.com
Tue Mar 1 17:00:18 UTC 2011
>Number: 155163
>Category: misc
>Synopsis: Add Recursive Functionality to setfacl
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Tue Mar 01 17:00:17 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: Shawn Webb
>Release: 8.2
>Organization:
HotlinkHR
>Environment:
FreeBSD shawnwork 8.2-RELEASE FreeBSD 8.2-RELEASE #1 r218738=2ec1cbd-dirty: Tue Feb 22 15:05:26 MST 2011 shawn at shawnwork:/usr/obj/usr/src/sys/GENERIC amd64
>Description:
The setfacl command is missing recursive functionality. The proposed and attached patch implements said functionality.
Included in the patch is also an enhancement to the -k switch. Solaris allows for zero-number ACL entries on objects stored in ZFS datasets via `chmod A= /path/to/file". FreeBSD does not support zero-number ACL entries so I give owner@ full permissions. This enhancement depends upon another bug report I sent that allows use of ACL sets (read_set, write_set, modify_set, full_set) in ZFS NFSv4 ACLs.
>How-To-Repeat:
>Fix:
Patch included.
Patch attached with submission follows:
diff --git a/bin/setfacl/setfacl.c b/bin/setfacl/setfacl.c
index a0f937c..2532188 100644
--- a/bin/setfacl/setfacl.c
+++ b/bin/setfacl/setfacl.c
@@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/acl.h>
#include <sys/queue.h>
+#include <fts.h>
+#include <dirent.h>
#include <err.h>
#include <errno.h>
@@ -44,6 +46,8 @@ __FBSDID("$FreeBSD$");
static void add_filename(const char *filename);
static void usage(void);
+static void recurse_directory(char *const *paths, int r_flag, int l_flag, int big_h_flag);
+static acl_t remove_invalid_inherit(const char *path, acl_t acl, int l_flag);
static void
add_filename(const char *filename)
@@ -62,34 +66,112 @@ add_filename(const char *filename)
static void
usage(void)
{
-
- fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
+ fprintf(stderr, "usage: setfacl [-bdhkLnR] [-a position entries] "
"[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
exit(1);
}
+static void
+recurse_directory(char *const *paths, int r_flag, int l_flag, int big_h_flag)
+{
+ FTS *ftsp;
+ FTSENT *p, *chp;
+ int fts_options = FTS_NOCHDIR;
+ unsigned int i;
+
+ fts_options |= (l_flag == 1) ? FTS_LOGICAL : FTS_PHYSICAL;
+ if (big_h_flag)
+ fts_options |= FTS_COMFOLLOW;
+
+ if (r_flag)
+ {
+ ftsp = fts_open(paths, fts_options, NULL);
+ if (ftsp == NULL)
+ return;
+
+ chp = fts_children(ftsp, 0);
+ if (chp == NULL)
+ return;
+
+ while ((p = fts_read(ftsp)) != NULL) {
+ if (l_flag == 0 && p->fts_info & FTS_D)
+ continue;
+ else if (l_flag == 1 && p->fts_info & FTS_DP)
+ continue;
+
+ add_filename(strdup(p->fts_path));
+ }
+
+ fts_close(ftsp);
+ } else
+ for (i = 0; paths[i] != NULL; i++)
+ add_filename(paths[i]);
+}
+
+static acl_t
+remove_invalid_inherit(const char *path, acl_t acl, int l_flag)
+{
+ acl_t acl_new;
+ int acl_brand;
+ acl_entry_t entry;
+ int entry_id;
+ acl_flagset_t flagset;
+ struct stat sb;
+
+ acl_get_brand_np(acl, &acl_brand);
+ if (acl_brand != ACL_BRAND_NFS4)
+ return acl;
+
+ if (l_flag == 1) {
+ if (stat(path, &sb) == -1)
+ return acl;
+ } else
+ if (lstat(path, &sb) == -1)
+ return acl;
+
+ if (S_ISDIR(sb.st_mode) != 0)
+ return acl;
+
+ acl_new = acl_dup(acl);
+
+ entry_id = ACL_FIRST_ENTRY;
+ while (acl_get_entry(acl_new, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ acl_get_flagset_np(entry, &flagset);
+ if (acl_get_flag_np(flagset, ACL_ENTRY_INHERIT_ONLY)) {
+ acl_delete_entry(acl_new, entry);
+ continue;
+ }
+ acl_delete_flag_np(flagset, ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ }
+
+ return acl_new;
+}
+
int
main(int argc, char *argv[])
{
- acl_t acl;
+ acl_t acl, acl_backup;
acl_type_t acl_type;
char filename[PATH_MAX];
- int local_error, carried_error, ch, i, entry_number, ret;
- int h_flag;
+ int local_error, carried_error, ch, entry_number, ret;
+ int h_flag, r_flag, l_flag, big_h_flag;
struct sf_file *file;
struct sf_entry *entry;
- const char *fn_dup;
+ char *fn_dup;
char *end;
+ char **files=NULL;
+ unsigned int numfiles=0;
struct stat sb;
acl_type = ACL_TYPE_ACCESS;
carried_error = local_error = 0;
- h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
+ h_flag = have_mask = have_stdin = n_flag = need_mask = r_flag = l_flag = big_h_flag = 0;
TAILQ_INIT(&entrylist);
TAILQ_INIT(&filelist);
- while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
+ while ((ch = getopt(argc, argv, "HLRM:X:a:bdhkm:nx:")) != -1)
switch(ch) {
case 'M':
entry = zmalloc(sizeof(struct sf_entry));
@@ -167,6 +249,15 @@ main(int argc, char *argv[])
}
TAILQ_INSERT_TAIL(&entrylist, entry, next);
break;
+ case 'R':
+ r_flag = 1;
+ break;
+ case 'L':
+ l_flag = 1;
+ break;
+ case 'H':
+ big_h_flag = 1;
+ break;
default:
usage();
break;
@@ -189,11 +280,18 @@ main(int argc, char *argv[])
fn_dup = strdup(filename);
if (fn_dup == NULL)
err(1, "strdup() failed");
- add_filename(fn_dup);
+ files = realloc(files, ++numfiles * sizeof(char **));
+ if (files == NULL)
+ err(1, "realloc() failed");
+ files[numfiles-1] = (char *)fn_dup;
}
+
+ files = realloc(files, ++numfiles * sizeof(char **));
+ files[numfiles-1] = NULL;
} else
- for (i = 0; i < argc; i++)
- add_filename(argv[i]);
+ files = argv;
+
+ recurse_directory(files, r_flag, l_flag, big_h_flag);
/* cycle through each file */
TAILQ_FOREACH(file, &filelist, next) {
@@ -201,14 +299,12 @@ main(int argc, char *argv[])
if (stat(file->filename, &sb) == -1) {
warn("%s: stat() failed", file->filename);
- carried_error++;
continue;
}
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);
- carried_error++;
continue;
}
@@ -220,7 +316,6 @@ main(int argc, char *argv[])
if (acl_type == ACL_TYPE_DEFAULT) {
warnx("%s: there are no default entries "
"in NFSv4 ACLs", file->filename);
- carried_error++;
continue;
}
acl_type = ACL_TYPE_NFS4;
@@ -243,7 +338,6 @@ main(int argc, char *argv[])
else
warn("%s: acl_get_file() failed",
file->filename);
- carried_error++;
continue;
}
@@ -254,12 +348,24 @@ main(int argc, char *argv[])
switch(entry->op) {
case OP_ADD_ACL:
+ acl_backup = entry->acl;
+ entry->acl = remove_invalid_inherit(file->filename, entry->acl, l_flag);
local_error += add_acl(entry->acl,
entry->entry_number, &acl, file->filename);
+ if (entry->acl != acl_backup) {
+ acl_free(entry->acl);
+ entry->acl = acl_backup;
+ }
break;
case OP_MERGE_ACL:
+ acl_backup = entry->acl;
+ entry->acl = remove_invalid_inherit(file->filename, entry->acl, l_flag);
local_error += merge_acl(entry->acl, &acl,
file->filename);
+ if (entry->acl != acl_backup) {
+ acl_free(entry->acl);
+ entry->acl = acl_backup;
+ }
need_mask = 1;
break;
case OP_REMOVE_EXT:
@@ -267,20 +373,20 @@ main(int argc, char *argv[])
need_mask = 0;
break;
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) {
- warn("%s: acl_delete_def_file() failed",
- file->filename);
- local_error++;
+ if (acl_type != ACL_TYPE_NFS4) {
+ if (acl_delete_def_file(file->filename) == -1) {
+ warn("%s: acl_delete_def_file() failed",
+ file->filename);
+ local_error++;
+ }
+ if (acl_type == ACL_TYPE_DEFAULT)
+ local_error += remove_default(&acl,
+ file->filename);
+ } else {
+ /* FreeBSD does not support a zero amount of ACL entries like Solaris, give owner@ full permissions */
+ acl_free(acl);
+ acl = acl_from_text("owner@:full_set::allow");
}
- if (acl_type == ACL_TYPE_DEFAULT)
- local_error += remove_default(&acl,
- file->filename);
need_mask = 0;
break;
case OP_REMOVE_ACL:
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list