From owner-freebsd-bugs@FreeBSD.ORG Tue Mar 1 17:00:18 2011 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6C9C7106566C for ; Tue, 1 Mar 2011 17:00:18 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 20ED98FC17 for ; Tue, 1 Mar 2011 17:00:18 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p21H0H5l060444 for ; Tue, 1 Mar 2011 17:00:18 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p21H0HEx060420; Tue, 1 Mar 2011 17:00:17 GMT (envelope-from gnats) Resent-Date: Tue, 1 Mar 2011 17:00:17 GMT Resent-Message-Id: <201103011700.p21H0HEx060420@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Shawn Webb Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 55558106564A for ; Tue, 1 Mar 2011 16:55:49 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 441458FC13 for ; Tue, 1 Mar 2011 16:55:49 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p21GtnMq000662 for ; Tue, 1 Mar 2011 16:55:49 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id p21Gtm1U000661; Tue, 1 Mar 2011 16:55:48 GMT (envelope-from nobody) Message-Id: <201103011655.p21Gtm1U000661@red.freebsd.org> Date: Tue, 1 Mar 2011 16:55:48 GMT From: Shawn Webb To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: misc/155163: Add Recursive Functionality to setfacl X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Mar 2011 17:00:18 -0000 >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@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 #include #include +#include +#include #include #include @@ -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: