Page MenuHomeFreeBSD

D26028.diff
No OneTemporary

D26028.diff

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

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)

Event Timeline