Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151588906
D26028.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
35 KB
Referenced Files
None
Subscribers
None
D26028.diff
View Options
Index: bin/getfacl/getfacl.1
===================================================================
--- bin/getfacl/getfacl.1
+++ bin/getfacl/getfacl.1
@@ -65,6 +65,9 @@
.It Fl h
If the target of the operation is a symbolic link, return the ACL from
the symbolic link itself rather than following the link.
+.It Fl f
+For NFSv4 ACLs, add commented infomration about ACL flags.
+Ignored for POSIX.1e ACLs.
.It Fl i
For NFSv4 ACLs, append numerical ID at the end of each entry containing
user or group name.
@@ -74,7 +77,8 @@
a user or group name.
Ignored for POSIX.1e ACLs.
.It Fl q
-Do not write commented information about file name and ownership.
+Do not write commented information about file name, ownership,
+and ACL flags.
This is
useful when dealing with filenames with unprintable characters.
.It Fl v
Index: bin/getfacl/getfacl.c
===================================================================
--- bin/getfacl/getfacl.c
+++ bin/getfacl/getfacl.c
@@ -175,11 +175,12 @@
}
static int
-print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
- int qflag, int vflag)
+print_acl(char *path, acl_type_t type, int hflag, int fflag, int iflag,
+ int nflag, int qflag, int vflag)
{
struct stat sb;
acl_t acl;
+ acl_aclflag_t aclflag;
char *acl_text;
int error, flags = 0, ret;
@@ -236,6 +237,24 @@
}
}
+ if (!qflag && fflag) {
+ ret = acl_get_aclflag_np(acl, &aclflag);
+ printf("# acl_flag: ");
+ switch(aclflag) {
+ case ACL_ACLFLAG_AUTO_INHERIT:
+ printf("auto-inherit\n");
+ break;
+ case ACL_ACLFLAG_PROTECTED:
+ printf("protected\n");
+ break;
+ case ACL_ACLFLAG_DEFAULTED:
+ printf("defaulted\n");
+ break;
+ default:
+ printf("None\n");
+ }
+ }
+
if (iflag)
flags |= ACL_TEXT_APPEND_ID;
@@ -260,8 +279,8 @@
}
static int
-print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
- int qflag, int vflag)
+print_acl_from_stdin(acl_type_t type, int hflag, int fflag, int iflag,
+ int nflag, int qflag, int vflag)
{
char *p, pathname[PATH_MAX];
int carried_error = 0;
@@ -269,8 +288,8 @@
while (fgets(pathname, (int)sizeof(pathname), stdin)) {
if ((p = strchr(pathname, '\n')) != NULL)
*p = '\0';
- if (print_acl(pathname, type, hflag, iflag, nflag,
- qflag, vflag) == -1) {
+ if (print_acl(pathname, type, hflag, fflag, iflag,
+ nflag, qflag, vflag) == -1) {
carried_error = -1;
}
}
@@ -284,14 +303,15 @@
acl_type_t type = ACL_TYPE_ACCESS;
int carried_error = 0;
int ch, error, i;
- int hflag, iflag, qflag, nflag, vflag;
+ int hflag, iflag, qflag, nflag, vflag, fflag;
hflag = 0;
iflag = 0;
qflag = 0;
nflag = 0;
vflag = 0;
- while ((ch = getopt(argc, argv, "dhinqv")) != -1)
+ fflag = 0;
+ while ((ch = getopt(argc, argv, "dfhinqv")) != -1)
switch(ch) {
case 'd':
type = ACL_TYPE_DEFAULT;
@@ -299,6 +319,9 @@
case 'h':
hflag = 1;
break;
+ case 'f':
+ fflag = 1;
+ break;
case 'i':
iflag = 1;
break;
@@ -319,20 +342,20 @@
argv += optind;
if (argc == 0) {
- error = print_acl_from_stdin(type, hflag, iflag, nflag,
+ error = print_acl_from_stdin(type, hflag, fflag, iflag, nflag,
qflag, vflag);
return(error ? 1 : 0);
}
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "-")) {
- error = print_acl_from_stdin(type, hflag, iflag, nflag,
- qflag, vflag);
+ error = print_acl_from_stdin(type, hflag, fflag, iflag,
+ nflag, qflag, vflag);
if (error == -1)
carried_error = -1;
} else {
- error = print_acl(argv[i], type, hflag, iflag, nflag,
- qflag, vflag);
+ error = print_acl(argv[i], type, hflag, fflag, iflag,
+ nflag, qflag, vflag);
if (error == -1)
carried_error = -1;
}
Index: bin/setfacl/Makefile
===================================================================
--- bin/setfacl/Makefile
+++ bin/setfacl/Makefile
@@ -2,6 +2,6 @@
PACKAGE=runtime
PROG= setfacl
-SRCS= file.c mask.c merge.c remove.c setfacl.c util.c
+SRCS= auto_inherit.c file.c mask.c merge.c remove.c setfacl.c util.c
.include <bsd.prog.mk>
Index: bin/setfacl/auto_inherit.c
===================================================================
--- /dev/null
+++ bin/setfacl/auto_inherit.c
@@ -0,0 +1,379 @@
+/*-
+ * Copyright (c) 2020 Andrew Walker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "setfacl.h"
+
+bool
+auto_inherit_check(char **fl)
+{
+ bool ok = true;
+ uint i;
+ int rv;
+ acl_aclflag_t acl_flag;
+ acl_t acl;
+
+ for (i = 0; i < ARRAY_SIZE(fl); i++) {
+ rv = pathconf(fl[i], _PC_ACL_NFS4);
+ if (rv == 0) {
+ warnx("%s: underlying filesystem does not support "
+ "NFSv4 ACLs", fl[i]);
+ ok = false;
+ continue;
+ }
+
+ if (f_flag) {
+ /*
+ * Flag is set to bypass check for PROTECTED.
+ */
+ continue;
+ }
+
+ acl = acl_get_file(fl[i], ACL_TYPE_NFS4);
+ if (acl == NULL) {
+ warnx("%s: acl_get_file() failed.", fl[i]);
+ ok = false;
+ continue;
+ }
+
+ rv = acl_get_aclflag_np(acl, &acl_flag);
+ if (rv != 0) {
+ warnx("%s: acl_acl_getaclflag_np() failed.", fl[i]);
+ ok = false;
+ acl_free(acl);
+ continue;
+ }
+
+ if (acl_flag != ACL_ACLFLAG_PROTECTED) {
+ warnx("%s: file does not have 'protected' ACL flag set. "
+ "auto-inheritance not permitted without -f flag.",
+ fl[i]);
+ ok = false;
+ acl_free(acl);
+ continue;
+ }
+
+ acl_free(acl);
+ }
+ return ok;
+}
+
+/*
+ * Setting PROTECTED flag is permitted if INHERITED is not present or if the
+ * -f flag is specified. In case -f flag is specified, then INHERITED flag will
+ * be stripped from the ACL to mimic behavior of icacls.exe for disabling inheritance
+ * and replacing inherited ACLs with non-inherited ones.
+ */
+int
+set_aclflag(acl_t acl, acl_aclflag_t new_flag) {
+ int acl_brand, entry_id;
+ acl_entry_t entry;
+ acl_flagset_t acl_flagset;
+ int has_inherited = 0;
+
+ if (new_flag != ACL_ACLFLAG_PROTECTED) {
+ return acl_set_aclflag_np(acl, new_flag);
+ }
+
+ acl_get_brand_np(acl, &acl_brand);
+ if (acl_brand != ACL_BRAND_NFS4) {
+ warnx("%0x08x: ACL branding mismatch", acl_brand);
+ return -1;
+ }
+
+ entry_id = ACL_FIRST_ENTRY;
+ while (acl_get_entry(acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ if (acl_get_flagset_np(entry, &acl_flagset) != 0) {
+ warn("acl_get_flagset_np() failed");
+ return -1;
+ }
+ has_inherited = acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERITED);
+ if (has_inherited && !f_flag) {
+ warnx("ACL contains inherited entries and -f flag "
+ "not specified.");
+ return -1;
+ }
+ if (acl_delete_flag_np(acl_flagset, ACL_ENTRY_INHERITED) != 0) {
+ warn("acl_delete_flag_np() failed");
+ return -1;
+ }
+ }
+ return acl_set_aclflag_np(acl, new_flag);
+}
+
+/*
+ * Creates new ACL with INHERITED entries removed.
+ */
+static acl_t
+remove_inherited_entries(acl_t acl, int *cntp)
+{
+ acl_entry_t entry, new_entry;
+ int entry_id;
+ acl_flagset_t flagset;
+ int has_inherited, acl_count;
+ acl_t new_acl;
+ new_acl = acl_init(ACL_MAX_ENTRIES);
+
+ entry_id = ACL_FIRST_ENTRY;
+ acl_count = 0;
+ while (acl_get_entry(acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ has_inherited = 0;
+ if (acl_get_flagset_np(entry, &flagset) != 0) {
+ err(1, "acl_get_flagset_np() failed");
+ }
+ has_inherited = acl_get_flag_np(flagset, ACL_ENTRY_INHERITED);
+ if (has_inherited) {
+ continue;
+ }
+ if (acl_create_entry_np(&new_acl, &new_entry, acl_count) == -1) {
+ err(1, "acl_create_entry() failed");
+ }
+ if (acl_copy_entry(new_entry, entry) == -1) {
+ err(1, "acl_copy_entry() failed");
+ }
+ acl_count++;
+ }
+ *cntp = acl_count;
+ return new_acl;
+}
+
+
+static bool
+update_flagset(acl_flagset_t *flagset, bool is_dir) {
+ /* Entry is not inheritable at all. Skip. */
+ int has_inherit, has_np, has_io, rv;
+ has_inherit = acl_get_flag_np(*flagset, ACL_ENTRY_DIRECTORY_INHERIT |
+ ACL_ENTRY_FILE_INHERIT);
+ if (has_inherit == 0){
+ return false;
+ }
+
+ /*
+ * Skip if the ACE has NO_PROPAGATE flag set and does not have
+ * INHERIT_ONLY flag.
+ * Also skip if this is a directory and flags on parent are "fin".
+ */
+ has_np = acl_get_flag_np(*flagset, ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ if (has_np == 1) {
+ has_io = acl_get_flag_np(*flagset, ACL_ENTRY_INHERIT_ONLY);
+ if (has_io == 0) {
+ return false;
+ }
+ rv = acl_get_flag_np(*flagset, ACL_ENTRY_DIRECTORY_INHERIT);
+ if ((rv == 0) && !is_dir) {
+ return false;
+ }
+ }
+
+ rv = acl_get_flag_np(*flagset, ACL_ENTRY_FILE_INHERIT);
+ if (rv == 0 && !is_dir) {
+ return false;
+ }
+
+ /*
+ * At this point the entry should be inherited.
+ * Strip inherit only from the flagset and set
+ * ACL_ENTRY_INHERITED.
+ */
+ acl_delete_flag_np(*flagset, ACL_ENTRY_INHERIT_ONLY);
+ acl_add_flag_np(*flagset, ACL_ENTRY_INHERITED);
+ return true;
+}
+
+static void
+add_new_entry(acl_t *new_acl,
+ acl_entry_t *entry,
+ acl_flagset_t flagset,
+ int new_entry_id,
+ bool is_dir)
+{
+ int rv;
+ acl_flagset_t new_flags;
+ acl_entry_t new_entry;
+
+ rv = acl_create_entry_np(new_acl, &new_entry, new_entry_id);
+ if (rv == -1) {
+ err(1, "acl_create_entry() failed");
+ }
+ rv = acl_copy_entry(new_entry, *entry);
+ if (rv == -1) {
+ err(1, "acl_create_entry() failed");
+ }
+
+ rv = acl_get_flagset_np(new_entry, &new_flags);
+ if (rv == -1) {
+ err(1, "acl_get_flagset_np() failed");
+ }
+
+ if (!is_dir) {
+ rv = acl_delete_flag_np(new_flags,
+ ACL_ENTRY_FILE_INHERIT |
+ ACL_ENTRY_DIRECTORY_INHERIT |
+ ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ if (rv == -1) {
+ err(1, "acl_delete_flag_np() failed");
+ }
+ return;
+ }
+
+ rv = acl_get_flag_np(flagset, ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ if (rv == 1) {
+ rv = acl_delete_flag_np(new_flags,
+ ACL_ENTRY_FILE_INHERIT |
+ ACL_ENTRY_DIRECTORY_INHERIT |
+ ACL_ENTRY_NO_PROPAGATE_INHERIT);
+ if (rv == -1) {
+ err(1, "acl_delete_flag_np() failed");
+ }
+ }
+}
+
+/*
+ * Returns entries inherited from parent_acl. NULL is returned if no
+ * inheritable entries are present in parent_acl.
+ */
+static acl_t
+calculate_inherited_acl(char *parent, bool is_dir)
+{
+ acl_t parent_acl, new_acl;
+ acl_entry_t entry;
+ acl_flagset_t flagset;
+ int entry_id, new_entry_id;
+ entry_id = ACL_FIRST_ENTRY;
+ bool ok;
+ new_entry_id = 0;
+
+ parent_acl = acl_get_file(parent, ACL_TYPE_NFS4);
+ if (parent_acl == NULL) {
+ err(1, "%s: acl_get_file() failed.", parent);
+ }
+
+ new_acl = acl_init(ACL_MAX_ENTRIES);
+ if (new_acl == NULL) {
+ err(1, "acl_init() failed");
+ }
+
+ while (acl_get_entry(parent_acl, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ if (acl_get_flagset_np(entry, &flagset)) {
+ err(1, "acl_get_flagset_np() failed");
+ }
+ ok = update_flagset(&flagset, is_dir);
+ if (!ok) {
+ continue;
+ }
+ add_new_entry(&new_acl, &entry, flagset, new_entry_id, is_dir);
+ new_entry_id++;
+ }
+ acl_free(parent_acl);
+ if (new_entry_id == 0) {
+ warnx("Calculated invalid ACL with no inherited entries.");
+ acl_free(new_acl);
+ return (NULL);
+ }
+ return (new_acl);
+}
+
+static void
+append_acls(acl_t to_add, int index, acl_t *target, bool is_dir)
+{
+ acl_entry_t entry;
+ int entry_id;
+ entry_id = ACL_FIRST_ENTRY;
+
+ while (acl_get_entry(to_add, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+ add_new_entry(target, &entry, 0, index, is_dir);
+ index++;
+ }
+
+ if (is_dir) {
+ acl_set_aclflag_np(*target, ACL_ACLFLAG_AUTO_INHERIT);
+ }
+}
+
+int
+auto_inherit_propagate(acl_t *old_acl, FTSENT *file) {
+ acl_t to_inherit, new_acl;
+ int naces;
+ char parent[PATH_MAX] = {0};
+ bool is_dir;
+ is_dir = (file->fts_info == FTS_D);
+
+ if (file->fts_parent == NULL) {
+ warnx("fts_parent for [%s] is NULL\n", file->fts_accpath);
+ return (-1);
+ }
+ /*
+ * fts(3) will chdir into the parent directory of the current FTSENT
+ * unless FTS_NOCHDIR is set. Hence, retrieving parent directory is
+ * simply a matter of calling getcwd(3). This reliance on getcwd(3) is
+ * not symlink safe (it is possible for end-user to create to auto-
+ * inherit heads for the same path through symlink-following). At
+ * present this safety net is removed, but in the future a call to
+ * realpath(3) for file->fts_accpath may warranted in order to ensure
+ * that inherited ACL is always calculated based on the actual parent
+ * directory.
+ */
+ if (getcwd(parent, sizeof(parent)) == NULL) {
+ err(1, "%s: getcwd() failed.", file->fts_accpath);
+ }
+
+ to_inherit = calculate_inherited_acl(parent, is_dir);
+ if (to_inherit == NULL) {
+ warnx("parent directory of [%s] does not contain inheritable "
+ "entries.", file->fts_accpath);
+ return (-1);
+ }
+
+ new_acl = remove_inherited_entries(*old_acl, &naces);
+ if (new_acl == NULL) {
+ warnx("failed to strip inherited entries from [%s].",
+ file->fts_accpath);
+ acl_free(to_inherit);
+ return (-1);
+ }
+ append_acls(to_inherit, naces, &new_acl, is_dir);
+ acl_free(*old_acl);
+ acl_free(to_inherit);
+ *old_acl = new_acl;
+ return (0);
+}
Index: bin/setfacl/setfacl.h
===================================================================
--- bin/setfacl/setfacl.h
+++ bin/setfacl/setfacl.h
@@ -30,10 +30,12 @@
#define _SETFACL_H
#include <stdbool.h>
+#include <fts.h>
#include <sys/types.h>
#include <sys/acl.h>
#include <sys/queue.h>
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
/* files.c */
acl_t get_acl_from_file(const char *filename);
@@ -54,9 +56,15 @@
void *zrealloc(void *ptr, size_t size);
const char *brand_name(int brand);
int branding_mismatch(int brand1, int brand2);
+/* auto_inherit.c */
+bool auto_inherit_check(char **files_list);
+int set_aclflag(acl_t acl, acl_aclflag_t new_flag);
+int auto_inherit_propagate(acl_t *old_acl, FTSENT *file);
+
extern bool have_mask;
extern bool have_stdin;
extern bool n_flag;
+extern bool f_flag;
#endif /* _SETFACL_H */
Index: bin/setfacl/setfacl.1
===================================================================
--- bin/setfacl/setfacl.1
+++ bin/setfacl/setfacl.1
@@ -82,6 +82,11 @@
Currently only directories may have
default ACL's.
This option is not applicable to NFSv4 ACLs.
+.It Fl f
+Force an NFSv4 aclflag change.
+This bypasses checks for safety to change the flag.
+If forced, inherited flag will be removed from all ACL entries.
+This option is only applicable to NFSv4 ACLs.
.It Fl h
If the target of the operation is a symbolic link, perform the operation
on the symbolic link itself, rather than following the link.
@@ -91,6 +96,14 @@
option is specified, symbolic links on the command line are followed
and hence unaffected by the command.
(Symbolic links encountered during tree traversal are not followed.)
+.It Fl i Ar aclflag
+Change the NFSv41 acl inheritance flag on the given directory.
+Supported options for
+.Ar aclflag
+are "auto-inherit", "protected", "default", "none".
+Directories with the "protected" flag will be bypassed during ACL
+auto-inheritance operations.
+This option is only applicable to NFSv4 ACLs.
.It Fl k
Delete any default ACL entries on the specified files.
It
@@ -129,6 +142,17 @@
Do not recalculate the permissions associated with the ACL
mask entry.
This option is not applicable to NFSv4 ACLs.
+.It Fl p
+Propagate NFSv41 ACL auto-inheritance on the given paths.
+May not be mixed with other flags that modify NFSv4 ACLs.
+Implies recursive -R flag.
+Directories with PROTECTED flag set are skipped / removed
+from the fts tree.
+During auto-inheritance propogation, all inherited ACL
+entries will be removed from the child ACL and replaced
+with newly calculated ACLs based on parent directory.
+Root-level directory ACLs will not be altered.
+This option is only applicable to NFSv4 ACLs.
.It Fl P
If the
.Fl R
Index: bin/setfacl/setfacl.c
===================================================================
--- bin/setfacl/setfacl.c
+++ bin/setfacl/setfacl.c
@@ -50,6 +50,8 @@
#define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */
#define OP_REMOVE_BY_NUMBER 0x04 /* remove acl's (-xX) by acl entry number */
#define OP_ADD_ACL 0x05 /* add acls entries at a given position */
+#define OP_SET_FLAG 0x06 /* set the ACL flag - V4 only*/
+#define OP_AI_PROPAGATE 0x07 /* propagate ACL based on auto-inheritence rules - V4 only*/
/* TAILQ entry for acl operations */
struct sf_entry {
@@ -63,12 +65,14 @@
bool have_mask;
bool have_stdin;
bool n_flag;
+bool f_flag;
static bool h_flag;
static bool H_flag;
static bool L_flag;
static bool R_flag;
static bool need_mask;
static acl_type_t acl_type = ACL_TYPE_ACCESS;
+static acl_aclflag_t acl_flag = 0;
static int handle_file(FTS *ftsp, FTSENT *file);
static acl_t clear_inheritance_flags(acl_t acl);
@@ -79,12 +83,23 @@
usage(void)
{
- fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdhkn] "
- "[-a position entries] [-m entries] [-M file] "
+ fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdfhkn] "
+ "[-a position entries] [-m entries] [-M file] [-i flag] "
"[-x entries] [-X file] [file ...]\n");
exit(1);
}
+static const struct {
+ acl_aclflag_t flag;
+ const char *flagstr;
+} acl_flag_str[] = {
+ { ACL_ACLFLAG_AUTO_INHERIT, "auto-inherit" },
+ { ACL_ACLFLAG_PROTECTED, "protected" },
+ { ACL_ACLFLAG_DEFAULTED, "defaulted" },
+ { 0, "none" },
+};
+
+
static char **
stdin_files(void)
{
@@ -297,6 +312,26 @@
&acl, file->fts_path);
need_mask = true;
break;
+ case OP_SET_FLAG:
+ local_error += set_aclflag(acl, acl_flag);
+ break;
+ case OP_AI_PROPAGATE:
+ /*
+ * No changes made at root level and branches with
+ * PROTECTED set are pruned.
+ */
+ if (file->fts_level == FTS_ROOTLEVEL) {
+ acl_free(acl);
+ return (0);
+ }
+ local_error += acl_get_aclflag_np(acl, &acl_flag);
+ if (acl_flag == ACL_ACLFLAG_PROTECTED) {
+ fts_set(ftsp, file, FTS_SKIP);
+ acl_free(acl);
+ return (0);
+ }
+ local_error += auto_inherit_propagate(&acl, file);
+ break;
}
if (nacl != entry->acl) {
@@ -351,6 +386,8 @@
main(int argc, char *argv[])
{
int carried_error, ch, entry_number, fts_options;
+ uint i;
+ bool flag_is_valid, ok, has_autoinherit;
FTS *ftsp;
FTSENT *file;
char **files_list;
@@ -359,11 +396,12 @@
acl_type = ACL_TYPE_ACCESS;
carried_error = fts_options = 0;
- have_mask = have_stdin = n_flag = false;
+ have_mask = have_stdin = f_flag = n_flag = false;
+ ok = flag_is_valid = has_autoinherit = false;
TAILQ_INIT(&entrylist);
- while ((ch = getopt(argc, argv, "HLM:PRX:a:bdhkm:nx:")) != -1)
+ while ((ch = getopt(argc, argv, "HLM:PRX:a:fi:bdhkpm:nx:")) != -1)
switch(ch) {
case 'H':
H_flag = true;
@@ -423,9 +461,30 @@
case 'd':
acl_type = ACL_TYPE_DEFAULT;
break;
+ case 'f':
+ f_flag = true;
+ break;
case 'h':
h_flag = 1;
break;
+ case 'i':
+ entry = zmalloc(sizeof(struct sf_entry));
+ for (i = 0; i < ARRAY_SIZE(acl_flag_str); i++) {
+ if (strcmp(optarg, acl_flag_str[i].flagstr) == 0) {
+ acl_flag = acl_flag_str[i].flag;
+ flag_is_valid = true;
+ break;
+ }
+ }
+ if (!flag_is_valid) {
+ errno = EINVAL;
+ err(1, "%s is not a valid ACL flag. "
+ "Supported flags are: auto-inherit, "
+ "protected, defaulted, and none.", optarg);
+ }
+ entry->op = OP_SET_FLAG;
+ TAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
case 'k':
entry = zmalloc(sizeof(struct sf_entry));
entry->op = OP_REMOVE_DEF;
@@ -442,6 +501,12 @@
case 'n':
n_flag = true;
break;
+ case 'p':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->op = OP_AI_PROPAGATE;
+ TAILQ_INSERT_TAIL(&entrylist, entry, next);
+ has_autoinherit = true;
+ break;
case 'x':
entry = zmalloc(sizeof(struct sf_entry));
entry_number = strtol(optarg, &end, 10);
@@ -476,6 +541,20 @@
} else
files_list = argv;
+ if (has_autoinherit) {
+ ok = auto_inherit_check(files_list);
+ TAILQ_FOREACH(entry, &entrylist, next) {
+ if (entry->op != OP_AI_PROPAGATE) {
+ errx(1, "mixing auto-inherit with other ACL operations. "
+ "is not permitted.");
+ }
+ }
+ if (!ok) {
+ errx(1, "auto-inheritance safety check failed.");
+ }
+ R_flag = true;
+ }
+
if (R_flag) {
if (h_flag)
errx(1, "the -R and -h options may not be "
Index: lib/libc/posix1e/Symbol.map
===================================================================
--- lib/libc/posix1e/Symbol.map
+++ lib/libc/posix1e/Symbol.map
@@ -77,6 +77,8 @@
acl_get_entry_type_np;
acl_get_flag_np;
acl_get_flagset_np;
+ acl_get_aclflag_np;
+ acl_set_aclflag_np;
acl_get_perm_np;
acl_is_trivial_np;
acl_set_entry_type_np;
Index: lib/libc/posix1e/acl_flag.c
===================================================================
--- lib/libc/posix1e/acl_flag.c
+++ lib/libc/posix1e/acl_flag.c
@@ -155,3 +155,47 @@
return (0);
}
+
+int
+acl_get_aclflag_np(acl_t acl, acl_aclflag_t *aclflag_p)
+{
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_acl_brand(acl) != ACL_BRAND_NFS4) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *aclflag_p = acl->ats_acl.acl_flag;
+ return (0);
+}
+
+int
+acl_set_aclflag_np(acl_t acl, acl_aclflag_t aclflag)
+{
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_acl_brand(acl) != ACL_BRAND_NFS4) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(aclflag) {
+ case ACL_ACLFLAG_AUTO_INHERIT:
+ acl->ats_acl.acl_flag = ACL_ACLFLAG_AUTO_INHERIT;
+ return (0);
+ case ACL_ACLFLAG_PROTECTED:
+ acl->ats_acl.acl_flag = ACL_ACLFLAG_PROTECTED;
+ return (0);
+ case ACL_ACLFLAG_DEFAULTED:
+ acl->ats_acl.acl_flag = ACL_ACLFLAG_DEFAULTED;
+ return (0);
+ default:
+ errno = EINVAL;
+ }
+ return (-1);
+}
Index: lib/libc/posix1e/acl_get_aclflag_np.3
===================================================================
--- /dev/null
+++ lib/libc/posix1e/acl_get_aclflag_np.3
@@ -0,0 +1,71 @@
+.\"-
+.\" Copyright (c) 2020 Andrew Walker
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 08, 2020
+.Dt ACL_GET_ACLFLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_aclflag_np
+.Nd return ACL inheritance flag (auto-inherit, protected, defaulted) for an ACL.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_aclflag_np "acl_t acl" "acl_aclflag_t *aclflag_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_aclflag_np
+function
+is a non-portable function that retrieves the ACL inheritance flag from an ACL.
+.Sh RETURN VALUES
+0 on success
+is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_flag_np
+function will return a value of
+\-1
+and set global variable
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not contain a valid ACL or ACL has wrong branding (not NFSv4).
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_set_aclflags_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
Index: lib/libc/posix1e/acl_set_aclflag_np.3
===================================================================
--- /dev/null
+++ lib/libc/posix1e/acl_set_aclflag_np.3
@@ -0,0 +1,73 @@
+.\"-
+.\" Copyright (c) 2020 Andrew Walker
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 08, 2020
+.Dt ACL_SET_ACLFLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_set_aclflag_np
+.Nd set an ACL inheritance flag (auto-inherit, protected, defaulted) on an ACL.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_aclflag_np "acl_t acl" "acl_aclflag_t aclflag"
+.Sh DESCRIPTION
+The
+.Fn acl_set_aclflag_np
+function
+is a non-portable function that sets an ACL inheritance flag on an ACL.
+.Sh RETURN VALUES
+0 on success
+is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_flag_np
+function will return a value of
+\-1
+and set global variable
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not contain a valid ACL or ACL has wrong branding (not NFSv4).
+.Fa acl_flag
+is not a valid ACL aclflag.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_set_aclflags_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -5833,7 +5833,7 @@
if (ap->a_type != ACL_TYPE_NFS4)
return (EINVAL);
- vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
if (error = zfs_getsecattr(ap->a_vp, &vsecattr, 0, ap->a_cred, NULL))
return (error);
@@ -5841,6 +5841,8 @@
if (vsecattr.vsa_aclentp != NULL)
kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz);
+ ap->a_aclp->acl_flag = (acl_aclflag_t)(vsecattr.vsa_aclflags & ACL_ACLFLAGS_ALL);
+
return (error);
}
@@ -5884,6 +5886,14 @@
vsecattr.vsa_mask = VSA_ACE;
aclbsize = ap->a_aclp->acl_cnt * sizeof(ace_t);
vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP);
+ /*
+ * Map acl flags (auto-inherit, protected, defaulted) to vsecattr
+ * flags and set appropriate mask.
+ */
+ if (ap->a_aclp->acl_flag) {
+ vsecattr.vsa_aclflags = ap->a_aclp->acl_flag & ACL_FLAGS_ALL;
+ vsecattr.vsa_mask |= VSA_ACE_ACLFLAGS;
+ }
aaclp = vsecattr.vsa_aclentp;
vsecattr.vsa_aclentsz = aclbsize;
Index: sys/sys/acl.h
===================================================================
--- sys/sys/acl.h
+++ sys/sys/acl.h
@@ -53,6 +53,7 @@
typedef int acl_type_t;
typedef int *acl_permset_t;
typedef uint16_t *acl_flagset_t;
+typedef int acl_aclflag_t;
/*
* With 254 entries, "struct acl_t_struct" is exactly one 4kB page big.
@@ -120,7 +121,8 @@
unsigned int acl_maxcnt;
unsigned int acl_cnt;
/* Will be required e.g. to implement NFSv4.1 ACL inheritance. */
- int acl_spare[4];
+ int acl_spare[3];
+ acl_aclflag_t acl_flag;
struct acl_entry acl_entry[ACL_MAX_ENTRIES];
};
@@ -187,6 +189,15 @@
#define ACL_TYPE_DEFAULT 0x00000003
#define ACL_TYPE_NFS4 0x00000004
+/*
+ * Possible valid values for acl_aclflag_t arguments.
+ */
+#define ACL_ACLFLAG_AUTO_INHERIT 0x00000001
+#define ACL_ACLFLAG_PROTECTED 0x00000002
+#define ACL_ACLFLAG_DEFAULTED 0x00000004
+#define ACL_ACLFLAGS_ALL (ACL_ACLFLAG_AUTO_INHERIT|ACL_ACLFLAG_PROTECTED| \
+ ACL_ACLFLAG_DEFAULTED)
+
/*
* Possible bits in ae_perm field for POSIX.1e ACLs. Note
* that ACL_EXECUTE may be used in both NFSv4 and POSIX.1e ACLs.
@@ -381,6 +392,8 @@
int acl_free(void *_obj_p);
acl_t acl_from_text(const char *_buf_p);
int acl_get_brand_np(acl_t _acl, int *_brand_p);
+int acl_get_aclflag_np(acl_t _acl, acl_aclflag_t *_aclflag_p);
+int acl_set_aclflag_np(acl_t _acl, acl_aclflag_t _aclflag_p);
int acl_get_entry(acl_t _acl, int _entry_id, acl_entry_t *_entry_p);
acl_t acl_get_fd(int _fd);
acl_t acl_get_fd_np(int fd, acl_type_t _type);
Index: tests/sys/acl/tools-nfs4-auto-inherit.test
===================================================================
--- /dev/null
+++ tests/sys/acl/tools-nfs4-auto-inherit.test
@@ -0,0 +1,135 @@
+# Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# This is a tools-level test for NFSv4.1 ACL auto-inheritance.
+# Run it as root using ACL-enabled kernel on ZFS dataset with following properties:
+# aclmode = passthrough, aclinherit = passthrough
+#
+# /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-nfs4-auto-inherit.test
+#
+# WARNING: Creates files in unsafe way.
+
+$ whoami
+> root
+$ umask 022
+
+# test setting "protected" flag
+$ mkdir test
+$ setfacl -m owner@:full_set:fd:allow,group@:full_set:fd:allow -x 2 test
+$ setfacl -i protected test
+$ getfacl -f test
+># file: test
+># owner: root
+># group: wheel
+># acl_flag: protected
+> owner@:rwxpDdaARWcCos:fd-----:allow
+> group@:rwxpDdaARWcCos:fd-----:allow
+
+# verify that files are created with no flag set.
+$ mkdir -p test/sub1/sub2
+$ touch test/testfile1 test/sub1/testfile2 test/sub1/sub2/testfile3
+$ getfacl -f test/sub1/sub2/testfile3
+># file: test/sub1/sub2/testfile3
+># owner: root
+># group: wheel
+># acl_flag: None
+> owner@:rwxpDdaARWcCos:------I:allow
+> group@:rwxpDdaARWcCos:------I:allow
+
+# verify that "protected" can be set with "-f" flag
+# This is also prep step for later test of "setfacl -p"
+$ setfacl -f -i protected test/sub1/sub2
+$ getfacl -f test/sub1/sub2
+># file: test/sub1/sub2
+># owner: root
+># group: wheel
+># acl_flag: protected
+> owner@:rwxpDdaARWcCos:fd-----:allow
+> group@:rwxpDdaARWcCos:fd-----:allow
+
+# Add new ACE to force recalculation of inherited ACL
+$ setfacl -a 0 u:0:full_set:fd:allow test
+$ getfacl -f test
+># file: test
+># owner: root
+># group: wheel
+># acl_flag: protected
+> user:root:rwxpDdaARWcCos:fd-----:allow
+> owner@:rwxpDdaARWcCos:fd-----:allow
+> group@:rwxpDdaARWcCos:fd-----:allow
+
+# Verify that root ACL unchanged after "setfacl -p"
+$ setfacl -p test
+$ getfacl -f test
+># file: test
+># owner: root
+># group: wheel
+># acl_flag: protected
+> user:root:rwxpDdaARWcCos:fd-----:allow
+> owner@:rwxpDdaARWcCos:fd-----:allow
+> group@:rwxpDdaARWcCos:fd-----:allow
+
+# Verify that subdirectory 1 received ACL and
+# "auto-inherit" is set.
+$ getfacl -f test/sub1
+># file: test/sub1
+># owner: root
+># group: wheel
+># acl_flag: auto-inherit
+> user:root:rwxpDdaARWcCos:fd----I:allow
+> owner@:rwxpDdaARWcCos:fd----I:allow
+> group@:rwxpDdaARWcCos:fd----I:allow
+
+# Verify that subdirectoy 2 was protected from ACL change
+$ getfacl -f test/sub1/sub2/
+># file: test/sub1/sub2/
+># owner: root
+># group: wheel
+># acl_flag: protected
+> owner@:rwxpDdaARWcCos:fd-----:allow
+> group@:rwxpDdaARWcCos:fd-----:allow
+
+# Verify that contents of subdirectory 2 was protected.
+$ getfacl -f test/sub1/sub2/testfile3
+># file: test/sub1/sub2/testfile3
+># owner: root
+># group: wheel
+># acl_flag: None
+> owner@:rwxpDdaARWcCos:------I:allow
+> group@:rwxpDdaARWcCos:------I:allow
+
+root@:/zroot/TEST # getfacl -f test/testfile1
+# file: test/testfile1
+# owner: root
+# group: wheel
+# acl_flag: None
+ user:root:rwxpDdaARWcCos:------I:allow
+ owner@:rwxpDdaARWcCos:------I:allow
+ group@:rwxpDdaARWcCos:------I:allow
+
+
+$ rm -r test
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 10, 9:00 AM (13 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31215464
Default Alt Text
D26028.diff (35 KB)
Attached To
Mode
D26028: Expose NFSv41 ACL automatic inheritance flags
Attached
Detach File
Event Timeline
Log In to Comment