Index: bin/Makefile
===================================================================
RCS file: /cvsroot/src/bin/Makefile,v
retrieving revision 1.22
diff -u -p -p -u -r1.22 Makefile
--- bin/Makefile	31 Dec 2007 15:31:24 -0000	1.22
+++ bin/Makefile	15 May 2020 16:56:38 -0000
@@ -1,8 +1,8 @@
 #	$NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $
 #	@(#)Makefile	8.1 (Berkeley) 5/31/93
 
-SUBDIR=	cat chio chmod cp csh date dd df domainname echo ed expr hostname \
-	kill ksh ln ls mkdir mt mv pax ps pwd rcp rcmd rm rmdir sh \
-	sleep stty sync test
+SUBDIR=	cat chio chmod cp csh date dd df domainname echo ed expr getfacl \
+	hostname kill ksh ln ls mkdir mt mv pax ps pwd rcp rcmd rm rmdir \
+	setfacl sh sleep stty sync test
 
 .include <bsd.subdir.mk>
Index: bin/cp/cp.c
===================================================================
RCS file: /cvsroot/src/bin/cp/cp.c,v
retrieving revision 1.59
diff -u -p -p -u -r1.59 cp.c
--- bin/cp/cp.c	5 Mar 2016 19:48:55 -0000	1.59
+++ bin/cp/cp.c	15 May 2020 16:56:38 -0000
@@ -499,9 +499,23 @@ copy(char *argv[], enum op type, int fts
                         	 * umask; arguably wrong, but it's been that way 
                         	 * forever.
 				 */
-				if (pflag && setfile(curr->fts_statp, 0))
-					this_failed = any_failed = 1;
-				else if ((dne = popdne()))
+				/*
+				 * If -p is in effect, set all the attributes.
+				 * Otherwise, set the correct permissions, limited
+				 * by the umask.  Optimise by avoiding a chmod()
+				 * if possible (which is usually the case if we
+				 * made the directory).  Note that mkdir() does not
+				 * honour setuid, setgid and sticky bits, but we
+				 * normally want to preserve them on directories.
+				 */
+				if (pflag) {
+					if (setfile(curr->fts_statp, 0))
+						this_failed = any_failed = 1;
+					if (preserve_dir_acls(curr->fts_statp,
+					    curr->fts_accpath, to.p_path) != 0)
+						this_failed = any_failed = 1;
+				}
+				if (this_failed && (dne = popdne()))
 					(void)chmod(to.p_path, 
 					    curr->fts_statp->st_mode);
 			}
Index: bin/cp/extern.h
===================================================================
RCS file: /cvsroot/src/bin/cp/extern.h,v
retrieving revision 1.17
diff -u -p -p -u -r1.17 extern.h
--- bin/cp/extern.h	4 Jan 2012 15:58:37 -0000	1.17
+++ bin/cp/extern.h	15 May 2020 16:56:38 -0000
@@ -55,6 +55,8 @@ int	copy_link(FTSENT *, int);
 int	copy_special(struct stat *, int);
 int	set_utimes(const char *, struct stat *);
 int	setfile(struct stat *, int);
+int	preserve_dir_acls(struct stat *, char *, char *);
+int	preserve_fd_acls(int, int);
 void	usage(void) __attribute__((__noreturn__));
 __END_DECLS
 
Index: bin/cp/utils.c
===================================================================
RCS file: /cvsroot/src/bin/cp/utils.c,v
retrieving revision 1.47
diff -u -p -p -u -r1.47 utils.c
--- bin/cp/utils.c	23 Sep 2019 18:01:09 -0000	1.47
+++ bin/cp/utils.c	15 May 2020 16:56:38 -0000
@@ -38,10 +38,12 @@ __RCSID("$NetBSD: utils.c,v 1.47 2019/09
 #endif
 #endif /* not lint */
 
+#define _ACL_PRIVATE
 #include <sys/mman.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/acl.h>
 #include <sys/extattr.h>
 
 #include <err.h>
@@ -254,6 +256,9 @@ copy_file(FTSENT *entp, int dne)
 	if (pflag && (fcpxattr(from_fd, to_fd) != 0))
 		warn("%s: error copying extended attributes", to.p_path);
 
+	if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
+		rval = 1;
+
 	(void)close(from_fd);
 
 	if (rval == 1) {
@@ -403,6 +408,145 @@ setfile(struct stat *fs, int fd)
 	return (rval);
 }
 
+int
+preserve_fd_acls(int source_fd, int dest_fd)
+{
+	acl_t acl;
+	acl_type_t acl_type;
+	int acl_supported = 0, ret, trivial;
+
+	ret = fpathconf(source_fd, _PC_ACL_NFS4);
+	if (ret > 0 ) {
+		acl_supported = 1;
+		acl_type = ACL_TYPE_NFS4;
+	} else if (ret < 0 && errno != EINVAL) {
+		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
+		return (1);
+	}
+	if (acl_supported == 0) {
+		ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
+		if (ret > 0 ) {
+			acl_supported = 1;
+			acl_type = ACL_TYPE_ACCESS;
+		} else if (ret < 0 && errno != EINVAL) {
+			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+			    to.p_path);
+			return (1);
+		}
+	}
+	if (acl_supported == 0)
+		return (0);
+
+	acl = acl_get_fd_np(source_fd, acl_type);
+	if (acl == NULL) {
+		warn("failed to get acl entries while setting %s", to.p_path);
+		return (1);
+	}
+	if (acl_is_trivial_np(acl, &trivial)) {
+		warn("acl_is_trivial() failed for %s", to.p_path);
+		acl_free(acl);
+		return (1);
+	}
+	if (trivial) {
+		acl_free(acl);
+		return (0);
+	}
+	if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
+		warn("failed to set acl entries for %s", to.p_path);
+		acl_free(acl);
+		return (1);
+	}
+	acl_free(acl);
+	return (0);
+}
+
+int
+preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
+{
+	acl_t (*aclgetf)(const char *, acl_type_t);
+	int (*aclsetf)(const char *, acl_type_t, acl_t);
+	struct acl *aclp;
+	acl_t acl;
+	acl_type_t acl_type;
+	int acl_supported = 0, ret, trivial;
+
+	ret = pathconf(source_dir, _PC_ACL_NFS4);
+	if (ret > 0) {
+		acl_supported = 1;
+		acl_type = ACL_TYPE_NFS4;
+	} else if (ret < 0 && errno != EINVAL) {
+		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
+		return (1);
+	}
+	if (acl_supported == 0) {
+		ret = pathconf(source_dir, _PC_ACL_EXTENDED);
+		if (ret > 0) {
+			acl_supported = 1;
+			acl_type = ACL_TYPE_ACCESS;
+		} else if (ret < 0 && errno != EINVAL) {
+			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+			    source_dir);
+			return (1);
+		}
+	}
+	if (acl_supported == 0)
+		return (0);
+
+	/*
+	 * If the file is a link we will not follow it.
+	 */
+	if (S_ISLNK(fs->st_mode)) {
+		aclgetf = acl_get_link_np;
+		aclsetf = acl_set_link_np;
+	} else {
+		aclgetf = acl_get_file;
+		aclsetf = acl_set_file;
+	}
+	if (acl_type == ACL_TYPE_ACCESS) {
+		/*
+		 * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
+		 * size ACL will be returned. So it is not safe to simply
+		 * check the pointer to see if the default ACL is present.
+		 */
+		acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
+		if (acl == NULL) {
+			warn("failed to get default acl entries on %s",
+			    source_dir);
+			return (1);
+		}
+		aclp = &acl->ats_acl;
+		if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
+		    ACL_TYPE_DEFAULT, acl) < 0) {
+			warn("failed to set default acl entries on %s",
+			    dest_dir);
+			acl_free(acl);
+			return (1);
+		}
+		acl_free(acl);
+	}
+	acl = aclgetf(source_dir, acl_type);
+	if (acl == NULL) {
+		warn("failed to get acl entries on %s", source_dir);
+		return (1);
+	}
+	if (acl_is_trivial_np(acl, &trivial)) {
+		warn("acl_is_trivial() failed on %s", source_dir);
+		acl_free(acl);
+		return (1);
+	}
+	if (trivial) {
+		acl_free(acl);
+		return (0);
+	}
+	if (aclsetf(dest_dir, acl_type, acl) < 0) {
+		warn("failed to set acl entries on %s", dest_dir);
+		acl_free(acl);
+		return (1);
+	}
+	acl_free(acl);
+	return (0);
+}
+
 void
 usage(void)
 {
Index: bin/getfacl/Makefile
===================================================================
RCS file: bin/getfacl/Makefile
diff -N bin/getfacl/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/getfacl/Makefile	15 May 2020 16:56:38 -0000
@@ -0,0 +1,6 @@
+# $NetBSD$
+# $FreeBSD: head/bin/getfacl/Makefile 298107 2016-04-16 07:45:30Z gjb $
+
+PROG=	getfacl
+
+.include <bsd.prog.mk>
Index: bin/getfacl/getfacl.1
===================================================================
RCS file: bin/getfacl/getfacl.1
diff -N bin/getfacl/getfacl.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/getfacl/getfacl.1	15 May 2020 16:56:38 -0000
@@ -0,0 +1,138 @@
+.\" $NetBSD$
+.\"-
+.\" Copyright (c) 2000, 2001, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/bin/getfacl/getfacl.1 240085 2012-09-04 12:02:23Z trasz $
+.\"
+.\" Developed by the TrustedBSD Project.
+.\" Support for POSIX.1e access control lists.
+.\"
+.Dd September 4, 2009
+.Dt GETFACL 1
+.Os
+.Sh NAME
+.Nm getfacl
+.Nd get ACL information
+.Sh SYNOPSIS
+.Nm
+.Op Fl dhinqv
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility writes discretionary access control information associated with
+the specified file(s) to standard output.
+If the
+.Xr getconf 1
+utility indicates that
+.Brq Va _POSIX_ACL_EXTENDED
+is not in effect for a
+.Ar file
+then the standard discretionary access permissions are interpreted as
+an ACL containing only the required ACL entries.
+.Pp
+The following option is available:
+.Bl -tag -width indent
+.It Fl d
+The operation applies to the default ACL of a directory instead of the
+access ACL.
+An error is generated if a default ACL cannot be associated with
+.Ar file .
+This option is not valid for NFSv4 ACLs.
+.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 i
+For NFSv4 ACLs, append numerical ID at the end of each entry containing
+user or group name.
+Ignored for POSIX.1e ACLs.
+.It Fl n
+Display user and group IDs numerically rather than converting to
+a user or group name.
+Ignored for POSIX.1e ACLs.
+.It Fl q
+Do not write commented information about file name and ownership.
+This is
+useful when dealing with filenames with unprintable characters.
+.It Fl v
+For NFSv4 ACLs, display access mask and flags in a verbose form.
+Ignored for POSIX.1e ACLs.
+.El
+.Pp
+The following operand is available:
+.Bl -tag -width indent
+.It Ar file
+A pathname of a file whose ACL shall be retrieved.
+If
+.Ar file
+is not specified, or a
+.Ar file
+is specified as
+.Fl ,
+then
+.Nm
+reads a list of pathnames, each terminated by one newline character,
+from the standard input.
+.El
+.Pp
+For an explanation of the ACL syntax, see the
+.Xr setfacl 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Dl getfacl /
+.Pp
+Retrieve ACL for the directory
+.Pa / .
+.Pp
+.Dl getfacl -d /
+.Pp
+Retrieve the default ACL for the directory
+.Pa / ,
+if any.
+.Sh SEE ALSO
+.Xr setfacl 1 ,
+.Xr acl 3 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr acl 9 ,
+.Xr extattr 9
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.Tn IEEE
+Std 1003.2c compliant.
+.Sh HISTORY
+Extended Attribute and Access Control List support was developed as part
+of the
+.Tn TrustedBSD
+Project and introduced in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Robert N M Watson
Index: bin/getfacl/getfacl.c
===================================================================
RCS file: bin/getfacl/getfacl.c
diff -N bin/getfacl/getfacl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/getfacl/getfacl.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,348 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 1999, 2001, 2002 Robert N M Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * getfacl -- POSIX.1e utility to extract ACLs from files and directories
+ * and send the results to stdout
+ */
+
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/bin/getfacl/getfacl.c 340014 2018-11-01 17:45:29Z markj $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int more_than_one = 0;
+
+static __dead void
+usage(void)
+{
+
+	fprintf(stderr, "Usage: %s [-dhnqv] [file ...]\n", getprogname());
+}
+
+static char *
+getuname(uid_t uid)
+{
+	struct passwd *pw;
+	static char uids[10];
+
+	if ((pw = getpwuid(uid)) == NULL) {
+		(void)snprintf(uids, sizeof(uids), "%u", uid);
+		return (uids);
+	} else
+		return (pw->pw_name);
+}
+
+static char *
+getgname(gid_t gid)
+{
+	struct group *gr;
+	static char gids[10];
+
+	if ((gr = getgrgid(gid)) == NULL) {
+		(void)snprintf(gids, sizeof(gids), "%u", gid);
+		return (gids);
+	} else
+		return (gr->gr_name);
+}
+
+/*
+ * return an ACL corresponding to the permissions
+ * contained in struct stat
+ */
+static acl_t
+acl_from_stat(const struct stat *sb)
+{
+	acl_t acl;
+	acl_entry_t entry;
+	acl_permset_t perms;
+
+	/* create the ACL */
+	acl = acl_init(3);
+	if (!acl)
+		return NULL;
+
+	/* First entry: ACL_USER_OBJ */
+	if (acl_create_entry(&acl, &entry) == -1)
+		return NULL;
+	if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
+		return NULL;
+
+	if (acl_get_permset(entry, &perms) == -1)
+		return NULL;
+	if (acl_clear_perms(perms) == -1)
+		return NULL;
+
+	/* calculate user mode */
+	if (sb->st_mode & S_IRUSR)
+		if (acl_add_perm(perms, ACL_READ) == -1)
+			return NULL;
+	if (sb->st_mode & S_IWUSR)
+		if (acl_add_perm(perms, ACL_WRITE) == -1)
+			return NULL;
+	if (sb->st_mode & S_IXUSR)
+		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
+			return NULL;
+	if (acl_set_permset(entry, perms) == -1)
+		return NULL;
+
+	/* Second entry: ACL_GROUP_OBJ */
+	if (acl_create_entry(&acl, &entry) == -1)
+		return NULL;
+	if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
+		return NULL;
+
+	if (acl_get_permset(entry, &perms) == -1)
+		return NULL;
+	if (acl_clear_perms(perms) == -1)
+		return NULL;
+
+	/* calculate group mode */
+	if (sb->st_mode & S_IRGRP)
+		if (acl_add_perm(perms, ACL_READ) == -1)
+			return NULL;
+	if (sb->st_mode & S_IWGRP)
+		if (acl_add_perm(perms, ACL_WRITE) == -1)
+			return NULL;
+	if (sb->st_mode & S_IXGRP)
+		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
+			return NULL;
+	if (acl_set_permset(entry, perms) == -1)
+		return NULL;
+
+	/* Third entry: ACL_OTHER */
+	if (acl_create_entry(&acl, &entry) == -1)
+		return NULL;
+	if (acl_set_tag_type(entry, ACL_OTHER) == -1)
+		return NULL;
+
+	if (acl_get_permset(entry, &perms) == -1)
+		return NULL;
+	if (acl_clear_perms(perms) == -1)
+		return NULL;
+
+	/* calculate other mode */
+	if (sb->st_mode & S_IROTH)
+		if (acl_add_perm(perms, ACL_READ) == -1)
+			return NULL;
+	if (sb->st_mode & S_IWOTH)
+		if (acl_add_perm(perms, ACL_WRITE) == -1)
+			return NULL;
+	if (sb->st_mode & S_IXOTH)
+		if (acl_add_perm(perms, ACL_EXECUTE) == -1)
+			return NULL;
+	if (acl_set_permset(entry, perms) == -1)
+		return NULL;
+
+	return(acl);
+}
+
+static int
+print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
+    int qflag, int vflag)
+{
+	struct stat	sb;
+	acl_t	acl;
+	char	*acl_text;
+	int	error, flags = 0, ret;
+
+	if (hflag)
+		error = lstat(path, &sb);
+	else
+		error = stat(path, &sb);
+	if (error == -1) {
+		warn("%s: stat() failed", path);
+		return(-1);
+	}
+
+	if (hflag)
+		ret = lpathconf(path, _PC_ACL_NFS4);
+	else
+		ret = pathconf(path, _PC_ACL_NFS4);
+	if (ret > 0) {
+		if (type == ACL_TYPE_DEFAULT) {
+			warnx("%s: there are no default entries in NFSv4 ACLs",
+			    path);
+			return (-1);
+		}
+		type = ACL_TYPE_NFS4;
+	} else if (ret < 0 && errno != EINVAL) {
+		warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
+		return (-1);
+	}
+
+	if (more_than_one)
+		printf("\n");
+	else
+		more_than_one++;
+
+	if (!qflag)
+		printf("# file: %s\n# owner: %s\n# group: %s\n", path,
+		    getuname(sb.st_uid), getgname(sb.st_gid));
+
+	if (hflag)
+		acl = acl_get_link_np(path, type);
+	else
+		acl = acl_get_file(path, type);
+	if (!acl) {
+		if (errno != EOPNOTSUPP) {
+			warn("%s", path);
+			return(-1);
+		}
+		errno = 0;
+		if (type == ACL_TYPE_DEFAULT)
+			return(0);
+		acl = acl_from_stat(&sb);
+		if (!acl) {
+			warn("%s: acl_from_stat() failed", path);
+			return(-1);
+		}
+	}
+
+	if (iflag)
+		flags |= ACL_TEXT_APPEND_ID;
+
+	if (nflag)
+		flags |= ACL_TEXT_NUMERIC_IDS;
+
+	if (vflag)
+		flags |= ACL_TEXT_VERBOSE;
+
+	acl_text = acl_to_text_np(acl, 0, flags);
+	if (!acl_text) {
+		warn("%s: acl_to_text_np() failed", path);
+		return(-1);
+	}
+
+	printf("%s", acl_text);
+
+	(void)acl_free(acl);
+	(void)acl_free(acl_text);
+
+	return(0);
+}
+
+static int
+print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
+    int qflag, int vflag)
+{
+	char	*p, pathname[PATH_MAX];
+	int	carried_error = 0;
+
+	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) {
+			carried_error = -1;
+		}
+	}
+
+	return(carried_error);
+}
+
+int
+main(int argc, char *argv[])
+{
+	acl_type_t	type = ACL_TYPE_ACCESS;
+	int	carried_error = 0;
+	int	ch, error, i;
+	int	hflag, iflag, qflag, nflag, vflag;
+
+	hflag = 0;
+	iflag = 0;
+	qflag = 0;
+	nflag = 0;
+	vflag = 0;
+	while ((ch = getopt(argc, argv, "dhinqv")) != -1)
+		switch(ch) {
+		case 'd':
+			type = ACL_TYPE_DEFAULT;
+			break;
+		case 'h':
+			hflag = 1;
+			break;
+		case 'i':
+			iflag = 1;
+			break;
+		case 'n':
+			nflag = 1;
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		default:
+			usage();
+			return(-1);
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0) {
+		error = print_acl_from_stdin(type, hflag, 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);
+			if (error == -1)
+				carried_error = -1;
+		} else {
+			error = print_acl(argv[i], type, hflag, iflag, nflag,
+			    qflag, vflag);
+			if (error == -1)
+				carried_error = -1;
+		}
+	}
+
+	return(carried_error ? 1 : 0);
+}
Index: bin/ls/ls.1
===================================================================
RCS file: /cvsroot/src/bin/ls/ls.1,v
retrieving revision 1.80
diff -u -p -p -u -r1.80 ls.1
--- bin/ls/ls.1	3 Jul 2017 21:33:23 -0000	1.80
+++ bin/ls/ls.1	15 May 2020 16:56:38 -0000
@@ -450,6 +450,20 @@ or
 .El
 .El
 .Pp
+The next field contains a
+plus
+.Pq Ql +
+character if the file has an ACL, or a
+space
+.Pq Ql " "
+if it does not.
+The
+.Nm
+utility does not show the actual ACL;
+use
+.Xr getfacl 1
+to do this.
+.Pp
 The number of bytes displayed for a directory is a function of the
 number of
 .Xr dirent 3
Index: bin/ls/print.c
===================================================================
RCS file: /cvsroot/src/bin/ls/print.c,v
retrieving revision 1.55
diff -u -p -p -u -r1.55 print.c
--- bin/ls/print.c	10 May 2014 09:39:18 -0000	1.55
+++ bin/ls/print.c	15 May 2020 16:56:38 -0000
@@ -43,6 +43,7 @@ __RCSID("$NetBSD: print.c,v 1.55 2014/05
 
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/acl.h>
 
 #include <err.h>
 #include <errno.h>
@@ -68,6 +69,7 @@ static void	printlink(FTSENT *);
 static void	printtime(time_t);
 static void	printtotal(DISPLAY *dp);
 static int	printtype(u_int);
+static void	aclmode(char *, const FTSENT *);
 
 static time_t	now;
 
@@ -154,6 +156,7 @@ printlong(DISPLAY *dp)
 			}
 		}
 		(void)strmode(sp->st_mode, buf);
+		aclmode(buf, p);
 		np = p->fts_pointer;
 		(void)printf("%s %*lu ", buf, dp->s_nlink,
 		    (unsigned long)sp->st_nlink);
@@ -495,3 +498,74 @@ printlink(FTSENT *p)
 	else
 		(void)printf("%s", path);
 }
+
+/*
+ * Add a + after the standard rwxrwxrwx mode if the file has an
+ * ACL. strmode() reserves space at the end of the string.
+ */
+static void
+aclmode(char *buf, const FTSENT *p)
+{
+	char name[MAXPATHLEN + 1];
+	int ret, trivial;
+	static dev_t previous_dev = NODEV;
+	static int supports_acls = -1;
+	static int type = ACL_TYPE_ACCESS;
+	acl_t facl;
+
+	/*
+	 * XXX: ACLs are not supported on whiteouts and device files
+	 * residing on UFS.
+	 */
+	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
+	    S_ISWHT(p->fts_statp->st_mode))
+		return;
+
+	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
+		return;
+
+	if (p->fts_level == FTS_ROOTLEVEL)
+		snprintf(name, sizeof(name), "%s", p->fts_name);
+	else
+		snprintf(name, sizeof(name), "%s/%s",
+		    p->fts_parent->fts_accpath, p->fts_name);
+
+	if (supports_acls == -1 || previous_dev != p->fts_statp->st_dev) {
+		previous_dev = p->fts_statp->st_dev;
+		supports_acls = 0;
+
+		ret = lpathconf(name, _PC_ACL_NFS4);
+		if (ret > 0) {
+			type = ACL_TYPE_NFS4;
+			supports_acls = 1;
+		} else if (ret < 0 && errno != EINVAL) {
+			warn("%s", name);
+			return;
+		}
+		if (supports_acls == 0) {
+			ret = lpathconf(name, _PC_ACL_EXTENDED);
+			if (ret > 0) {
+				type = ACL_TYPE_ACCESS;
+				supports_acls = 1;
+			} else if (ret < 0 && errno != EINVAL) {
+				warn("%s", name);
+				return;
+			}
+		}
+	}
+	if (supports_acls == 0)
+		return;
+	facl = acl_get_link_np(name, type);
+	if (facl == NULL) {
+		warn("%s", name);
+		return;
+	}
+	if (acl_is_trivial_np(facl, &trivial)) {
+		acl_free(facl);
+		warn("%s", name);
+		return;
+	}
+	if (!trivial)
+		buf[10] = '+';
+	acl_free(facl);
+}
Index: bin/setfacl/Makefile
===================================================================
RCS file: bin/setfacl/Makefile
diff -N bin/setfacl/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/Makefile	15 May 2020 16:56:38 -0000
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/setfacl/Makefile 298107 2016-04-16 07:45:30Z gjb $
+
+PACKAGE=runtime
+PROG=	setfacl
+SRCS=	file.c mask.c merge.c remove.c setfacl.c util.c
+
+.include <bsd.prog.mk>
Index: bin/setfacl/file.c
===================================================================
RCS file: bin/setfacl/file.c
diff -N bin/setfacl/file.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/file.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,82 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/file.c 333065 2018-04-27 15:25:24Z emaste $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "setfacl.h"
+
+/*
+ * read acl text from a file and return the corresponding acl
+ */
+acl_t
+get_acl_from_file(const char *filename)
+{
+	FILE *file;
+	size_t len;
+	char buf[BUFSIZ+1];
+
+	if (filename == NULL)
+		err(1, "(null) filename in get_acl_from_file()");
+
+	if (strcmp(filename, "-") == 0) {
+		if (have_stdin)
+			err(1, "cannot specify more than one stdin");
+		file = stdin;
+		have_stdin = true;
+	} else {
+		file = fopen(filename, "r");
+		if (file == NULL)
+			err(1, "fopen() %s failed", filename);
+	}
+
+	len = fread(buf, (size_t)1, sizeof(buf) - 1, file);
+	buf[len] = '\0';
+	if (ferror(file) != 0) {
+		fclose(file);
+		err(1, "error reading from %s", filename);
+	} else if (feof(file) == 0) {
+		fclose(file);
+		errx(1, "line too long in %s", filename);
+	}
+
+	fclose(file);
+
+	return (acl_from_text(buf));
+}
Index: bin/setfacl/mask.c
===================================================================
RCS file: bin/setfacl/mask.c
diff -N bin/setfacl/mask.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/mask.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,120 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/mask.c 333065 2018-04-27 15:25:24Z emaste $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "setfacl.h"
+
+/* set the appropriate mask the given ACL's */
+int
+set_acl_mask(acl_t *prev_acl, const char *filename)
+{
+	acl_entry_t entry;
+	acl_t acl;
+	acl_tag_t tag;
+	int entry_id;
+
+	entry = NULL;
+
+	/*
+	 * ... if a mask entry is specified, then the permissions of the mask
+	 * entry in the resulting ACL shall be set to the permissions in the
+	 * specified ACL mask entry.
+	 */
+	if (have_mask)
+		return (0);
+
+	acl = acl_dup(*prev_acl);
+	if (acl == NULL)
+		err(1, "%s: acl_dup() failed", filename);
+
+	if (!n_flag) {
+		/*
+		 * If no mask entry is specified and the -n option is not
+		 * specified, then the permissions of the resulting ACL mask
+		 * entry shall be set to the union of the permissions
+		 * associated with all entries which belong to the file group
+		 * class in the resulting ACL
+		 */
+		if (acl_calc_mask(&acl)) {
+			warn("%s: acl_calc_mask() failed", filename);
+			acl_free(acl);
+			return (-1);
+		}
+	} else {
+		/*
+		 * If no mask entry is specified and the -n option is
+		 * specified, then the permissions of the resulting ACL
+		 * mask entry shall remain unchanged ...
+		 */
+
+		entry_id = ACL_FIRST_ENTRY;
+
+		while (acl_get_entry(acl, entry_id, &entry) == 1) {
+			entry_id = ACL_NEXT_ENTRY;
+			if (acl_get_tag_type(entry, &tag) == -1)
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
+
+			if (tag == ACL_MASK) {
+				acl_free(acl);
+				return (0);
+			}
+		}
+
+		/*
+		 * If no mask entry is specified, the -n option is specified,
+		 * and no ACL mask entry exists in the ACL associated with the
+		 * file, then write an error message to standard error and
+		 * continue with the next file.
+		 */
+		warnx("%s: warning: no mask entry", filename);
+		acl_free(acl);
+		return (0);
+	}
+
+	acl_free(*prev_acl);
+	*prev_acl = acl_dup(acl);
+	acl_free(acl);
+
+	return (0);
+}
Index: bin/setfacl/merge.c
===================================================================
RCS file: bin/setfacl/merge.c
diff -N bin/setfacl/merge.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/merge.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,299 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/merge.c 333065 2018-04-27 15:25:24Z emaste $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+
+#include "setfacl.h"
+
+static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new,
+    int acl_brand);
+
+static int
+merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand)
+{
+	acl_permset_t permset;
+	acl_entry_type_t entry_type;
+	acl_flagset_t flagset;
+	int have_entry;
+	uid_t *id, *id_new;
+
+	have_entry = 0;
+
+	id = acl_get_qualifier(*entry);
+	if (id == NULL)
+		err(1, "acl_get_qualifier() failed");
+	id_new = acl_get_qualifier(*entry_new);
+	if (id_new == NULL)
+		err(1, "acl_get_qualifier() failed");
+	if (*id == *id_new) {
+		/* any other matches */
+		if (acl_get_permset(*entry, &permset) == -1)
+			err(1, "acl_get_permset() failed");
+		if (acl_set_permset(*entry_new, permset) == -1)
+			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;
+	}
+	acl_free(id);
+	acl_free(id_new);
+
+	return (have_entry);
+}
+
+/*
+ * merge an ACL into existing file's ACL
+ */
+int
+merge_acl(acl_t acl, acl_t *prev_acl, const char *filename)
+{
+	acl_entry_t entry, entry_new;
+	acl_permset_t permset;
+	acl_t acl_new;
+	acl_tag_t tag, tag_new;
+	acl_entry_type_t entry_type, entry_type_new;
+	acl_flagset_t flagset;
+	int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0;
+	int acl_brand, prev_acl_brand;
+
+	acl_get_brand_np(acl, &acl_brand);
+	acl_get_brand_np(*prev_acl, &prev_acl_brand);
+
+	if (branding_mismatch(acl_brand, prev_acl_brand)) {
+		warnx("%s: branding mismatch; existing ACL is %s, "
+		    "entry to be merged is %s", filename,
+		    brand_name(prev_acl_brand), brand_name(acl_brand));
+		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;
+		have_entry = 0;
+		had_entry = 0;
+
+		/* keep track of existing ACL_MASK entries */
+		if (acl_get_tag_type(entry, &tag) == -1)
+			err(1, "%s: acl_get_tag_type() failed - "
+			    "invalid ACL entry", filename);
+		if (tag == ACL_MASK)
+			have_mask = true;
+
+		/* check against the existing ACL entries */
+		entry_id_new = ACL_FIRST_ENTRY;
+		while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
+			entry_id_new = ACL_NEXT_ENTRY;
+
+			if (acl_get_tag_type(entry, &tag) == -1)
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
+			if (acl_get_tag_type(entry_new, &tag_new) == -1)
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
+			if (tag != tag_new)
+				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) {
+			case ACL_USER:
+			case ACL_GROUP:
+				have_entry = merge_user_group(&entry,
+				    &entry_new, acl_brand);
+				if (have_entry == 0)
+					break;
+				/* FALLTHROUGH */
+			case ACL_USER_OBJ:
+			case ACL_GROUP_OBJ:
+			case ACL_OTHER:
+			case ACL_MASK:
+			case ACL_EVERYONE:
+				if (acl_get_permset(entry, &permset) == -1)
+					err(1, "%s: acl_get_permset() failed",
+					    filename);
+				if (acl_set_permset(entry_new, permset) == -1)
+					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);
+				}
+				had_entry = have_entry = 1;
+				break;
+			default:
+				/* should never be here */
+				errx(1, "%s: invalid tag type: %i", filename, tag);
+				break;
+			}
+		}
+
+		/* if this entry has not been found, it must be new */
+		if (had_entry == 0) {
+
+			/*
+			 * 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)
+				err(1, "%s: acl_copy_entry() failed", filename);
+		}
+	}
+
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
+	return (0);
+}
+
+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 (branding_mismatch(acl_brand, ACL_BRAND_NFS4)) {
+		warnx("%s: branding mismatch; existing ACL is NFSv4, "
+		    "entry to be added is %s", filename,
+		    brand_name(acl_brand));
+		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);
+}
Index: bin/setfacl/remove.c
===================================================================
RCS file: bin/setfacl/remove.c
diff -N bin/setfacl/remove.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/remove.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,179 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/remove.c 333065 2018-04-27 15:25:24Z emaste $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "setfacl.h"
+
+/*
+ * remove ACL entries from an ACL
+ */
+int
+remove_acl(acl_t acl, acl_t *prev_acl, const char *filename)
+{
+	acl_entry_t	entry;
+	acl_t		acl_new;
+	acl_tag_t	tag;
+	int		carried_error, entry_id, acl_brand, prev_acl_brand;
+
+	carried_error = 0;
+
+	acl_get_brand_np(acl, &acl_brand);
+	acl_get_brand_np(*prev_acl, &prev_acl_brand);
+
+	if (branding_mismatch(acl_brand, prev_acl_brand)) {
+		warnx("%s: branding mismatch; existing ACL is %s, "
+		    "entry to be removed is %s", filename,
+		    brand_name(prev_acl_brand), brand_name(acl_brand));
+		return (-1);
+	}
+
+	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 and delete the entry */
+	entry_id = ACL_FIRST_ENTRY;
+	while (acl_get_entry(acl, entry_id, &entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+		if (acl_get_tag_type(entry, &tag) == -1)
+			err(1, "%s: acl_get_tag_type() failed", filename);
+		if (tag == ACL_MASK)
+			have_mask = true;
+		if (acl_delete_entry(acl_new, entry) == -1) {
+			carried_error++;
+			warnx("%s: cannot remove non-existent ACL entry",
+			    filename);
+		}
+	}
+
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
+	if (carried_error)
+		return (-1);
+
+	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 = true;
+	}
+
+	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)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * remove default entries
+ */
+int
+remove_default(acl_t *prev_acl, const char *filename)
+{
+
+	acl_free(*prev_acl);
+	*prev_acl = acl_init(ACL_MAX_ENTRIES);
+	if (*prev_acl == NULL)
+		err(1, "%s: acl_init() failed", filename);
+
+	return (0);
+}
+
+/*
+ * remove extended entries
+ */
+void
+remove_ext(acl_t *prev_acl, const char *filename)
+{
+	acl_t acl_new;
+
+	acl_new = acl_strip_np(*prev_acl, !n_flag);
+	if (acl_new == NULL)
+		err(1, "%s: acl_strip_np() failed", filename);
+
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+}
Index: bin/setfacl/setfacl.1
===================================================================
RCS file: bin/setfacl/setfacl.1
diff -N bin/setfacl/setfacl.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/setfacl.1	15 May 2020 16:56:38 -0000
@@ -0,0 +1,517 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" Copyright (c) 2011 Edward Tomasz Napierała
+.\" 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: head/bin/setfacl/setfacl.1 339793 2018-10-26 21:17:06Z markj $
+.\"
+.Dd October 26, 2018
+.Dt SETFACL 1
+.Os
+.Sh NAME
+.Nm setfacl
+.Nd set ACL information
+.Sh SYNOPSIS
+.Nm
+.Op Fl R Op Fl H | L | P
+.Op Fl bdhkn
+.Op Fl a Ar position entries
+.Op Fl m Ar entries
+.Op Fl M Ar file
+.Op Fl x Ar entries | position
+.Op Fl X Ar file
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility sets discretionary access control information on
+the specified file(s).
+If no files are specified, or the list consists of the only
+.Sq Fl ,
+the file names are taken from the standard input.
+.Pp
+The following options are available:
+.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
+Remove all ACL entries except for the ones synthesized
+from the file mode - the three mandatory entries in case
+of POSIX.1e ACL.
+If the POSIX.1e ACL contains a
+.Dq Li mask
+entry, the permissions of the
+.Dq Li group
+entry in the resulting ACL will be set to the permission
+associated with both the
+.Dq Li group
+and
+.Dq Li mask
+entries of the current ACL.
+.It Fl d
+The operations apply to the default ACL entries instead of
+access ACL entries.
+Currently only directories may have
+default ACL's.
+This option is not 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.
+.It Fl H
+If the
+.Fl R
+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 k
+Delete any default ACL entries on the specified files.
+It
+is not considered an error if the specified files do not have
+any default ACL entries.
+An error will be reported if any of
+the specified files cannot have a default entry (i.e.,
+non-directories).
+This option is not applicable to NFSv4 ACLs.
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl m Ar entries
+Modify the ACL on the specified file.
+New entries will be added, and existing entries will be modified
+according to the
+.Ar entries
+argument.
+For NFSv4 ACLs, it is recommended to use the
+.Fl a
+and
+.Fl x
+options instead.
+.It Fl M Ar file
+Modify the ACL entries on the specified files by adding new
+ACL entries and modifying existing ACL entries with the ACL
+entries specified in the file
+.Ar file .
+If
+.Ar file
+is
+.Fl ,
+the input is taken from stdin.
+.It Fl n
+Do not recalculate the permissions associated with the ACL
+mask entry.
+This option is not applicable to NFSv4 ACLs.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+This is the default.
+.It Fl R
+Perform the action recursively on any specified directories.
+When modifying or adding NFSv4 ACL entries, inheritance flags
+are applied only to directories.
+.It Fl x Ar entries | position
+If
+.Ar entries
+is specified, remove the ACL entries specified there
+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
+Remove the ACL entries specified in the file
+.Ar file
+from the access or default ACL of the specified files.
+.El
+.Pp
+The above options are evaluated in the order specified
+on the command-line.
+.Sh POSIX.1e ACL ENTRIES
+A POSIX.1E ACL entry contains three colon-separated fields:
+an ACL tag, an ACL qualifier, and discretionary access
+permissions:
+.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 owner of the file or a specified user;
+.Dq Li group
+or
+.Ql g
+specifying the access granted to the file owning group
+or a specified group;
+.Dq Li other
+or
+.Ql o
+specifying the access
+granted to any process that does not match any user or group
+ACL entry;
+.Dq Li mask
+or
+.Ql m
+specifying the maximum access
+granted to any ACL entry except the
+.Dq Li user
+ACL entry for the file owner and the
+.Dq Li other
+ACL entry.
+.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, gid or group name, or empty.
+For
+.Dq Li user
+ACL entries, an empty field specifies access granted to the
+file owner.
+For
+.Dq Li group
+ACL entries, an empty field specifies access granted to the
+file owning group.
+.Dq Li mask
+and
+.Dq Li other
+ACL entries do not use this field.
+.It Ar "access permissions"
+The access permissions field contains up to one of each of
+the following:
+.Ql r ,
+.Ql w ,
+and
+.Ql x
+to set read, write, and
+execute permissions, respectively.
+Each of these may be excluded
+or replaced with a
+.Ql -
+character to indicate no access.
+.El
+.Pp
+A
+.Dq Li mask
+ACL entry is required on a file with any ACL entries other than
+the default
+.Dq Li user ,
+.Dq Li group ,
+and
+.Dq Li other
+ACL entries.
+If the
+.Fl n
+option is not specified and no
+.Dq Li mask
+ACL entry was specified, the
+.Nm
+utility
+will apply a
+.Dq Li mask
+ACL entry consisting of the union of the permissions associated
+with all
+.Dq Li group
+ACL entries in the resulting ACL.
+.Pp
+Traditional POSIX interfaces acting on file system object modes have
+modified semantics in the presence of POSIX.1e extended ACLs.
+When a mask entry is present on the access ACL of an object, the mask
+entry is substituted for the group bits; this occurs in programs such
+as
+.Xr stat 1
+or
+.Xr ls 1 .
+When the mode is modified on an object that has a mask entry, the
+changes applied to the group bits will actually be applied to the
+mask entry.
+These semantics provide for greater application compatibility:
+applications modifying the mode instead of the ACL will see
+conservative behavior, limiting the effective rights granted by all
+of the additional user and group entries; this occurs in programs
+such as
+.Xr chmod 1 .
+.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
+When POSIX.1e ACL entries are evaluated, the access check algorithm checks
+the ACL entries in the following order: file owner,
+.Dq Li user
+ACL entries, file owning group,
+.Dq Li group
+ACL entries, and
+.Dq Li other
+ACL entry.
+.Pp
+Multiple ACL entries specified on the command line are
+separated by commas.
+.Pp
+It is possible for files and directories to inherit ACL entries from their
+parent directory.
+This is accomplished through the use of the default ACL.
+It should be noted that before you can specify a default ACL, the mandatory
+ACL entries for user, group, other and mask must be set.
+For more details see the examples below.
+Default ACLs can be created by using
+.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 omitted 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 modify_set"
+.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
+.Pp
+In addition, the following permission sets may be used:
+.Bl -tag -width ".Dv modify_set"
+.It Set
+Permissions
+.It full_set
+all permissions, as shown above
+.It modify_set
+all permissions except write_acl and write_owner
+.It read_set
+read_data, read_attributes, read_xattr and read_acl
+.It write_set
+write_data, append_data, write_attributes and write_xattr
+.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
+.It I
+inherited
+.El
+.Pp
+Other than the "inherited" flag, 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.
+.Pp
+Note that the file owner is always granted the read_acl, write_acl,
+read_attributes, and write_attributes permissions, even if the ACL
+would deny it.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Dl setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx dir
+.Dl setfacl -d -m g:admins:rwx dir
+.Pp
+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
+permissions for directory named "dir".
+It should be noted that any files or directories created underneath "dir" will
+inherit these default ACLs upon creation.
+.Pp
+.Dl setfacl -m u::rwx,g:mail:rw file
+.Pp
+Sets read, write, and execute permissions for the
+.Pa file
+owner's POSIX.1e ACL entry and read and write permissions for group mail on
+.Pa file .
+.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
+.Pp
+Sets/updates the ACL entries contained in
+.Pa file1
+on
+.Pa file2 .
+.Pp
+.Dl setfacl -x g:mail:rw file
+.Pp
+Remove the group mail POSIX.1e ACL entry containing read/write permissions
+from
+.Pa file .
+.Pp
+.Dl setfacl -x0 file
+.Pp
+Remove the first entry from the NFSv4 ACL from
+.Pa file .
+.Pp
+.Dl setfacl -bn file
+.Pp
+Remove all
+.Dq Li access
+ACL entries except for the three required from
+.Pa file .
+.Pp
+.Dl getfacl file1 | setfacl -b -n -M - file2
+.Pp
+Copy ACL entries from
+.Pa file1
+to
+.Pa file2 .
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr acl 3 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr acl 9 ,
+.Xr extattr 9
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.Tn IEEE
+Std 1003.2c compliant.
+.Sh HISTORY
+Extended Attribute and Access Control List support was developed
+as part of the
+.Tn TrustedBSD
+Project and introduced in
+.Fx 5.0 .
+NFSv4 ACL support was introduced in
+.Fx 8.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
+NFSv4 ACL support was implemented by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: bin/setfacl/setfacl.c
===================================================================
RCS file: bin/setfacl/setfacl.c
diff -N bin/setfacl/setfacl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/setfacl.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,511 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/setfacl.c 339793 2018-10-26 21:17:06Z markj $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "setfacl.h"
+
+/* file operations */
+#define	OP_MERGE_ACL		0x00	/* merge acl's (-mM) */
+#define	OP_REMOVE_DEF		0x01	/* remove default acl's (-k) */
+#define	OP_REMOVE_EXT		0x02	/* remove extended acl's (-b) */
+#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 */
+
+/* TAILQ entry for acl operations */
+struct sf_entry {
+	uint	op;
+	acl_t	acl;
+	uint	entry_number;
+	TAILQ_ENTRY(sf_entry) next;
+};
+static TAILQ_HEAD(, sf_entry) entrylist;
+
+bool have_mask;
+bool have_stdin;
+bool n_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 int	handle_file(FTS *ftsp, FTSENT *file);
+static acl_t	clear_inheritance_flags(acl_t acl);
+static char	**stdin_files(void);
+static void	usage(void);
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdhkn] "
+	    "[-a position entries] [-m entries] [-M file] "
+	    "[-x entries] [-X file] [file ...]\n");
+	exit(1);
+}
+
+static char **
+stdin_files(void)
+{
+	char **files_list;
+	char filename[PATH_MAX];
+	size_t fl_count, i;
+
+	if (have_stdin)
+		err(1, "cannot have more than one stdin");
+
+	i = 0;
+	have_stdin = true;
+	bzero(&filename, sizeof(filename));
+	/* Start with an array size sufficient for basic cases. */
+	fl_count = 1024;
+	files_list = zmalloc(fl_count * sizeof(char *));
+	while (fgets(filename, (int)sizeof(filename), stdin)) {
+		/* remove the \n */
+		filename[strlen(filename) - 1] = '\0';
+		files_list[i] = strdup(filename);
+		if (files_list[i] == NULL)
+			err(1, "strdup() failed");
+		/* Grow array if necessary. */
+		if (++i == fl_count) {
+			fl_count <<= 1;
+			if (fl_count > SIZE_MAX / sizeof(char *))
+				errx(1, "Too many input files");
+			files_list = zrealloc(files_list,
+					fl_count * sizeof(char *));
+		}
+	}
+
+	/* fts_open() requires the last array element to be NULL. */
+	files_list[i] = NULL;
+
+	return (files_list);
+}
+
+/*
+ * Remove any inheritance flags from NFSv4 ACLs when running in recursive
+ * mode.  This is to avoid files being assigned identical ACLs to their
+ * parent directory while also being set to inherit them.
+ *
+ * The acl argument is assumed to be valid.
+ */
+static acl_t
+clear_inheritance_flags(acl_t acl)
+{
+	acl_t nacl;
+	acl_entry_t acl_entry;
+	acl_flagset_t acl_flagset;
+	int acl_brand, entry_id;
+
+	(void)acl_get_brand_np(acl, &acl_brand);
+	if (acl_brand != ACL_BRAND_NFS4)
+		return (acl);
+
+	nacl = acl_dup(acl);
+	if (nacl == NULL) {
+		warn("acl_dup() failed");
+		return (acl);
+	}
+
+	entry_id = ACL_FIRST_ENTRY;
+	while (acl_get_entry(nacl, entry_id, &acl_entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+		if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
+			warn("acl_get_flagset_np() failed");
+			continue;
+		}
+		if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY) == 1) {
+			if (acl_delete_entry(nacl, acl_entry) != 0)
+				warn("acl_delete_entry() failed");
+			continue;
+		}
+		if (acl_delete_flag_np(acl_flagset,
+		    ACL_ENTRY_FILE_INHERIT |
+		    ACL_ENTRY_DIRECTORY_INHERIT |
+		    ACL_ENTRY_NO_PROPAGATE_INHERIT) != 0)
+			warn("acl_delete_flag_np() failed");
+	}
+
+	return (nacl);
+}
+
+static int
+handle_file(FTS *ftsp, FTSENT *file)
+{
+	acl_t acl, nacl;
+	acl_entry_t unused_entry;
+	int local_error, ret;
+	struct sf_entry *entry;
+	bool follow_symlink;
+
+	local_error = 0;
+	switch (file->fts_info) {
+	case FTS_D:
+		/* Do not recurse if -R not specified. */
+		if (!R_flag)
+			fts_set(ftsp, file, FTS_SKIP);
+		break;
+	case FTS_DP:
+		/* Skip the second visit to a directory. */
+		return (0);
+	case FTS_DNR:
+	case FTS_ERR:
+		warnx("%s: %s", file->fts_path, strerror(file->fts_errno));
+		return (0);
+	default:
+		break;
+	}
+
+	if (acl_type == ACL_TYPE_DEFAULT && file->fts_info != FTS_D) {
+		warnx("%s: default ACL may only be set on a directory",
+		    file->fts_path);
+		return (1);
+	}
+
+	follow_symlink = (!R_flag && !h_flag) || (R_flag && L_flag) ||
+	    (R_flag && H_flag && file->fts_level == FTS_ROOTLEVEL);
+
+	if (follow_symlink)
+		ret = pathconf(file->fts_accpath, _PC_ACL_NFS4);
+	else
+		ret = lpathconf(file->fts_accpath, _PC_ACL_NFS4);
+	if (ret > 0) {
+		if (acl_type == ACL_TYPE_DEFAULT) {
+			warnx("%s: there are no default entries in NFSv4 ACLs",
+			    file->fts_path);
+			return (1);
+		}
+		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 && errno != ENOENT) {
+		warn("%s: pathconf(_PC_ACL_NFS4) failed",
+		    file->fts_path);
+	}
+
+	if (follow_symlink)
+		acl = acl_get_file(file->fts_accpath, acl_type);
+	else
+		acl = acl_get_link_np(file->fts_accpath, acl_type);
+	if (acl == NULL) {
+		if (follow_symlink)
+			warn("%s: acl_get_file() failed", file->fts_path);
+		else
+			warn("%s: acl_get_link_np() failed", file->fts_path);
+		return (1);
+	}
+
+	/* Cycle through each option. */
+	TAILQ_FOREACH(entry, &entrylist, next) {
+		nacl = entry->acl;
+		switch (entry->op) {
+		case OP_ADD_ACL:
+			if (R_flag && file->fts_info != FTS_D &&
+			    acl_type == ACL_TYPE_NFS4)
+				nacl = clear_inheritance_flags(nacl);
+			local_error += add_acl(nacl, entry->entry_number, &acl,
+			    file->fts_path);
+			break;
+		case OP_MERGE_ACL:
+			if (R_flag && file->fts_info != FTS_D &&
+			    acl_type == ACL_TYPE_NFS4)
+				nacl = clear_inheritance_flags(nacl);
+			local_error += merge_acl(nacl, &acl, file->fts_path);
+			need_mask = true;
+			break;
+		case OP_REMOVE_EXT:
+			/*
+			 * Don't try to call remove_ext() for empty
+			 * default ACL.
+			 */
+			if (acl_type == ACL_TYPE_DEFAULT &&
+			    acl_get_entry(acl, ACL_FIRST_ENTRY,
+			    &unused_entry) == 0) {
+				local_error += remove_default(&acl,
+				    file->fts_path);
+				break;
+			}
+			remove_ext(&acl, file->fts_path);
+			need_mask = false;
+			break;
+		case OP_REMOVE_DEF:
+			if (acl_type == ACL_TYPE_NFS4) {
+				warnx("%s: there are no default entries in "
+				    "NFSv4 ACLs; cannot remove",
+				    file->fts_path);
+				local_error++;
+				break;
+			}
+			if (acl_delete_def_file(file->fts_accpath) == -1) {
+				warn("%s: acl_delete_def_file() failed",
+				    file->fts_path);
+				local_error++;
+			}
+			if (acl_type == ACL_TYPE_DEFAULT)
+				local_error += remove_default(&acl,
+				    file->fts_path);
+			need_mask = false;
+			break;
+		case OP_REMOVE_ACL:
+			local_error += remove_acl(nacl, &acl, file->fts_path);
+			need_mask = true;
+			break;
+		case OP_REMOVE_BY_NUMBER:
+			local_error += remove_by_number(entry->entry_number,
+			    &acl, file->fts_path);
+			need_mask = true;
+			break;
+		}
+
+		if (nacl != entry->acl) {
+			acl_free(nacl);
+			nacl = NULL;
+		}
+		if (local_error)
+			break;
+	}
+
+	ret = 0;
+
+	/*
+	 * Don't try to set an empty default ACL; it will always fail.
+	 * Use acl_delete_def_file(3) instead.
+	 */
+	if (acl_type == ACL_TYPE_DEFAULT &&
+	    acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
+		if (acl_delete_def_file(file->fts_accpath) == -1) {
+			warn("%s: acl_delete_def_file() failed",
+			    file->fts_path);
+			ret = 1;
+		}
+		goto out;
+	}
+
+	/* Don't bother setting the ACL if something is broken. */
+	if (local_error) {
+		ret = 1;
+	} else if (acl_type != ACL_TYPE_NFS4 && need_mask &&
+	    set_acl_mask(&acl, file->fts_path) == -1) {
+		warnx("%s: failed to set ACL mask", file->fts_path);
+		ret = 1;
+	} else if (follow_symlink) {
+		if (acl_set_file(file->fts_accpath, acl_type, acl) == -1) {
+			warn("%s: acl_set_file() failed", file->fts_path);
+			ret = 1;
+		}
+	} else {
+		if (acl_set_link_np(file->fts_accpath, acl_type, acl) == -1) {
+			warn("%s: acl_set_link_np() failed", file->fts_path);
+			ret = 1;
+		}
+	}
+
+out:
+	acl_free(acl);
+	return (ret);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int carried_error, ch, entry_number, fts_options;
+	FTS *ftsp;
+	FTSENT *file;
+	char **files_list;
+	struct sf_entry *entry;
+	char *end;
+
+	acl_type = ACL_TYPE_ACCESS;
+	carried_error = fts_options = 0;
+	have_mask = have_stdin = n_flag = false;
+
+	TAILQ_INIT(&entrylist);
+
+	while ((ch = getopt(argc, argv, "HLM:PRX:a:bdhkm:nx:")) != -1)
+		switch(ch) {
+		case 'H':
+			H_flag = true;
+			L_flag = false;
+			break;
+		case 'L':
+			L_flag = true;
+			H_flag = false;
+			break;
+		case 'M':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry->acl = get_acl_from_file(optarg);
+			if (entry->acl == NULL)
+				err(1, "%s: get_acl_from_file() failed",
+				    optarg);
+			entry->op = OP_MERGE_ACL;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			break;
+		case 'P':
+			H_flag = L_flag = false;
+			break;
+		case 'R':
+			R_flag = true;
+			break;
+		case 'X':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry->acl = get_acl_from_file(optarg);
+			entry->op = OP_REMOVE_ACL;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			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':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry->op = OP_REMOVE_EXT;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			break;
+		case 'd':
+			acl_type = ACL_TYPE_DEFAULT;
+			break;
+		case 'h':
+			h_flag = 1;
+			break;
+		case 'k':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry->op = OP_REMOVE_DEF;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			break;
+		case 'm':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry->acl = acl_from_text(optarg);
+			if (entry->acl == NULL)
+				err(1, "%s", optarg);
+			entry->op = OP_MERGE_ACL;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			break;
+		case 'n':
+			n_flag = true;
+			break;
+		case 'x':
+			entry = zmalloc(sizeof(struct sf_entry));
+			entry_number = strtol(optarg, &end, 10);
+			if (end - optarg == (int)strlen(optarg)) {
+				if (entry_number < 0)
+					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);
+			break;
+		default:
+			usage();
+			break;
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (!n_flag && TAILQ_EMPTY(&entrylist))
+		usage();
+
+	/* Take list of files from stdin. */
+	if (argc == 0 || strcmp(argv[0], "-") == 0) {
+		files_list = stdin_files();
+	} else
+		files_list = argv;
+
+	if (R_flag) {
+		if (h_flag)
+			errx(1, "the -R and -h options may not be "
+			    "specified together.");
+		if (L_flag) {
+			fts_options = FTS_LOGICAL;
+		} else {
+			fts_options = FTS_PHYSICAL;
+
+			if (H_flag) {
+				fts_options |= FTS_COMFOLLOW;
+			}
+		}
+	} else if (h_flag) {
+		fts_options = FTS_PHYSICAL;
+	} else {
+		fts_options = FTS_LOGICAL;
+	}
+
+	/* Open all files. */
+	if ((ftsp = fts_open(files_list, fts_options | FTS_NOSTAT, 0)) == NULL)
+		err(1, "fts_open");
+	while ((file = fts_read(ftsp)) != NULL)
+		carried_error += handle_file(ftsp, file);
+
+	return (carried_error);
+}
Index: bin/setfacl/setfacl.h
===================================================================
RCS file: bin/setfacl/setfacl.h
diff -N bin/setfacl/setfacl.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/setfacl.h	15 May 2020 16:56:38 -0000
@@ -0,0 +1,64 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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: head/bin/setfacl/setfacl.h 333065 2018-04-27 15:25:24Z emaste $
+ */
+
+#ifndef _SETFACL_H
+#define _SETFACL_H
+
+#include <stdbool.h>
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/queue.h>
+
+/* files.c */
+acl_t	 get_acl_from_file(const char *filename);
+/* merge.c */
+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 */
+int	 remove_acl(acl_t acl, acl_t *prev_acl, const char *filename);
+int	 remove_by_number(uint entry_number, acl_t *prev_acl,
+	    const char *filename);
+int	 remove_default(acl_t *prev_acl, const char *filename);
+void	 remove_ext(acl_t *prev_acl, const char *filename);
+/* mask.c */
+int	 set_acl_mask(acl_t *prev_acl, const char *filename);
+/* util.c */
+void	*zmalloc(size_t size);
+void	*zrealloc(void *ptr, size_t size);
+const char *brand_name(int brand);
+int	 branding_mismatch(int brand1, int brand2);
+
+extern bool have_mask;
+extern bool have_stdin;
+extern bool n_flag;
+
+#endif /* _SETFACL_H */
Index: bin/setfacl/util.c
===================================================================
RCS file: bin/setfacl/util.c
diff -N bin/setfacl/util.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bin/setfacl/util.c	15 May 2020 16:56:38 -0000
@@ -0,0 +1,85 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/bin/setfacl/util.c 332396 2018-04-10 23:29:57Z emaste $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "setfacl.h"
+
+void *
+zmalloc(size_t size)
+{
+	void *ptr;
+
+	ptr = calloc(1, size);
+	if (ptr == NULL)
+		err(1, "calloc() failed");
+	return (ptr);
+}
+
+void *
+zrealloc(void *ptr, size_t size)
+{
+	void *newptr;
+
+	newptr = realloc(ptr, size);
+	if (newptr == NULL)
+		err(1, "realloc() failed");
+	return (newptr);
+}
+
+const char *
+brand_name(int brand)
+{
+	switch (brand) {
+	case ACL_BRAND_NFS4:
+		return "NFSv4";
+	case ACL_BRAND_POSIX:
+		return "POSIX.1e";
+	default:
+		return "unknown";
+	}
+}
+
+int
+branding_mismatch(int brand1, int brand2)
+{
+	if (brand1 == ACL_BRAND_UNKNOWN || brand2 == ACL_BRAND_UNKNOWN)
+		return (0);
+	if (brand1 != brand2)
+		return (1);
+	return (0);
+}
Index: distrib/sets/lists/base/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/mi,v
retrieving revision 1.1242
diff -u -p -p -u -r1.1242 mi
--- distrib/sets/lists/base/mi	1 May 2020 22:25:18 -0000	1.1242
+++ distrib/sets/lists/base/mi	15 May 2020 16:56:39 -0000
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1242 2020/05/01 22:25:18 christos Exp $
+# $NetBSD: mi,v 1.1241 2020/04/25 12:18:47 kre Exp $
 #
 # Note:	Don't delete entries from here - mark them as "obsolete" instead,
 #	unless otherwise stated below.
@@ -33,6 +33,7 @@
 ./bin/echo					base-util-root
 ./bin/ed					base-util-root
 ./bin/expr					base-util-root
+./bin/getfacl					base-util-root
 ./bin/hostname					base-util-root
 ./bin/kill					base-util-root
 ./bin/ksh					base-util-root
@@ -51,6 +52,7 @@
 ./bin/rmail					base-obsolete		obsolete
 ./bin/rmdir					base-util-root
 ./bin/rump.dd					base-util-root		rump
+./bin/setfacl					base-util-root
 ./bin/sh					base-util-root
 ./bin/sleep					base-util-root
 ./bin/stty					base-util-root
Index: distrib/sets/lists/comp/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.2325
diff -u -p -p -u -r1.2325 mi
--- distrib/sets/lists/comp/mi	6 May 2020 16:17:36 -0000	1.2325
+++ distrib/sets/lists/comp/mi	15 May 2020 16:56:40 -0000
@@ -844,8 +844,8 @@
 ./usr/include/fcntl.h				comp-c-include
 ./usr/include/fenv.h				comp-c-include
 ./usr/include/fetch.h				comp-c-include
-./usr/include/fido.h				comp-c-include
 ./usr/include/fido				comp-c-include
+./usr/include/fido.h				comp-c-include
 ./usr/include/fido/bio.h			comp-c-include
 ./usr/include/fido/credman.h			comp-c-include
 ./usr/include/fido/eddsa.h			comp-c-include
@@ -2974,6 +2974,7 @@
 ./usr/include/strings.h				comp-c-include
 ./usr/include/struct.h				comp-c-include
 ./usr/include/sys/acct.h			comp-c-include
+./usr/include/sys/acl.h				comp-c-include
 ./usr/include/sys/agpio.h			comp-c-include
 ./usr/include/sys/aio.h				comp-c-include
 ./usr/include/sys/ansi.h			comp-c-include
@@ -3493,10 +3494,10 @@
 ./usr/lib/libexecinfo_p.a			comp-c-proflib		compatfile,profile
 ./usr/lib/libexpat.a				comp-c-lib		compatfile
 ./usr/lib/libexpat_p.a				comp-c-proflib		compatfile,profile
-./usr/lib/libfido2.a				comp-c-lib		compatfile
-./usr/lib/libfido2_p.a				comp-c-proflib		compatfile,profile
 ./usr/lib/libfetch.a				comp-c-lib		compatfile
 ./usr/lib/libfetch_p.a				comp-c-proflib		compatfile,profile
+./usr/lib/libfido2.a				comp-c-lib		compatfile
+./usr/lib/libfido2_p.a				comp-c-proflib		compatfile,profile
 ./usr/lib/libfl.a				comp-c-lib		compatfile
 ./usr/lib/libfl_p.a				comp-c-proflib		compatfile,profile
 ./usr/lib/libform.a				comp-c-lib		compatfile
@@ -5559,6 +5560,58 @@
 ./usr/share/man/cat3/a64l.0			comp-c-catman		.cat
 ./usr/share/man/cat3/abort.0			comp-c-catman		.cat
 ./usr/share/man/cat3/abs.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_add_flag_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_add_perm.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_calc_mask.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_clear_flags_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_clear_perms.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_copy_entry.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_create_entry.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_create_entry_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_def_file.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_entry.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_entry_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_fd_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_file_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_flag_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_delete_perm.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_dup.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_free.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_from_text.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_brand_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_entry.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_entry_type_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_fd.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_fd_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_file.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_flag_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_flagset_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_link_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_perm_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_permset.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_qualifier.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_get_tag_type.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_init.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_is_trivial_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_set.0			comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_entry_type_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_fd.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_fd_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_file.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_flagset_np.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_link_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_permset.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_qualifier.0	comp-c-catman		.cat
+./usr/share/man/cat3/acl_set_tag_type.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_strip_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_to_text.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_to_text_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_valid.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_valid_fd_np.0		comp-c-catman		.cat
+./usr/share/man/cat3/acl_valid_file_np.0	comp-c-catman		.cat
 ./usr/share/man/cat3/acos.0			comp-c-catman		.cat
 ./usr/share/man/cat3/acosf.0			comp-c-catman		.cat
 ./usr/share/man/cat3/acosh.0			comp-c-catman		.cat
@@ -8870,6 +8923,7 @@
 ./usr/share/man/cat3/popenve.0			comp-c-catman		.cat
 ./usr/share/man/cat3/pos_form_cursor.0		comp-c-catman		.cat
 ./usr/share/man/cat3/pos_menu_cursor.0		comp-c-catman		.cat
+./usr/share/man/cat3/posix1e.0			comp-c-catman		.cat
 ./usr/share/man/cat3/posix2time.0		comp-c-catman		.cat
 ./usr/share/man/cat3/posix2time_z.0		comp-c-catman		.cat
 ./usr/share/man/cat3/posix_memalign.0		comp-c-catman		.cat
@@ -13648,6 +13702,58 @@
 ./usr/share/man/html3/a64l.html			comp-c-htmlman		html
 ./usr/share/man/html3/abort.html		comp-c-htmlman		html
 ./usr/share/man/html3/abs.html			comp-c-htmlman		html
+./usr/share/man/html3/acl.html			comp-c-htmlman		html
+./usr/share/man/html3/acl_add_flag_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_add_perm.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_calc_mask.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_clear_flags_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_clear_perms.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_copy_entry.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_create_entry.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_create_entry_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_def_file.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_entry.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_entry_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_fd_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_file_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_flag_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_delete_perm.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_dup.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_free.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_from_text.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_get_brand_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_entry.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_entry_type_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_fd.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_get_fd_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_file.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_get_flag_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_flagset_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_link_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_perm_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_permset.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_qualifier.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_get_tag_type.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_init.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_is_trivial_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_set_entry_type_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_fd.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_set_fd_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_file.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_set_flagset_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_link_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_permset.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_qualifier.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_set_tag_type.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_strip_np.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_to_text.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_to_text_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_valid.html		comp-c-htmlman		html
+./usr/share/man/html3/acl_valid_fd_np.html	comp-c-htmlman		html
+./usr/share/man/html3/acl_valid_file_np.html	comp-c-htmlman		html
 ./usr/share/man/html3/acos.html			comp-c-htmlman		html
 ./usr/share/man/html3/acosf.html		comp-c-htmlman		html
 ./usr/share/man/html3/acosh.html		comp-c-htmlman		html
@@ -16900,6 +17006,7 @@
 ./usr/share/man/html3/popenve.html		comp-c-htmlman		html
 ./usr/share/man/html3/pos_form_cursor.html	comp-c-htmlman		html
 ./usr/share/man/html3/pos_menu_cursor.html	comp-c-htmlman		html
+./usr/share/man/html3/posix1e.html		comp-c-htmlman		html
 ./usr/share/man/html3/posix2time.html		comp-c-htmlman		html
 ./usr/share/man/html3/posix2time_z.html		comp-c-htmlman		html
 ./usr/share/man/html3/posix_memalign.html	comp-c-htmlman		html
@@ -21574,6 +21681,58 @@
 ./usr/share/man/man3/a64l.3			comp-c-man		.man
 ./usr/share/man/man3/abort.3			comp-c-man		.man
 ./usr/share/man/man3/abs.3			comp-c-man		.man
+./usr/share/man/man3/acl.3			comp-c-man		.man
+./usr/share/man/man3/acl_add_flag_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_add_perm.3		comp-c-man		.man
+./usr/share/man/man3/acl_calc_mask.3		comp-c-man		.man
+./usr/share/man/man3/acl_clear_flags_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_clear_perms.3		comp-c-man		.man
+./usr/share/man/man3/acl_copy_entry.3		comp-c-man		.man
+./usr/share/man/man3/acl_create_entry.3		comp-c-man		.man
+./usr/share/man/man3/acl_create_entry_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_delete.3		comp-c-man		.man
+./usr/share/man/man3/acl_delete_def_file.3	comp-c-man		.man
+./usr/share/man/man3/acl_delete_entry.3		comp-c-man		.man
+./usr/share/man/man3/acl_delete_entry_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_delete_fd_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_delete_file_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_delete_flag_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_delete_perm.3		comp-c-man		.man
+./usr/share/man/man3/acl_dup.3			comp-c-man		.man
+./usr/share/man/man3/acl_free.3			comp-c-man		.man
+./usr/share/man/man3/acl_from_text.3		comp-c-man		.man
+./usr/share/man/man3/acl_get.3			comp-c-man		.man
+./usr/share/man/man3/acl_get_brand_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_entry.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_entry_type_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_get_fd.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_fd_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_file.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_flag_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_flagset_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_get_link_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_perm_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_permset.3		comp-c-man		.man
+./usr/share/man/man3/acl_get_qualifier.3	comp-c-man		.man
+./usr/share/man/man3/acl_get_tag_type.3		comp-c-man		.man
+./usr/share/man/man3/acl_init.3			comp-c-man		.man
+./usr/share/man/man3/acl_is_trivial_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_set.3			comp-c-man		.man
+./usr/share/man/man3/acl_set_entry_type_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_set_fd.3		comp-c-man		.man
+./usr/share/man/man3/acl_set_fd_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_set_file.3		comp-c-man		.man
+./usr/share/man/man3/acl_set_flagset_np.3	comp-c-man		.man
+./usr/share/man/man3/acl_set_link_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_set_permset.3		comp-c-man		.man
+./usr/share/man/man3/acl_set_qualifier.3	comp-c-man		.man
+./usr/share/man/man3/acl_set_tag_type.3		comp-c-man		.man
+./usr/share/man/man3/acl_strip_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_to_text.3		comp-c-man		.man
+./usr/share/man/man3/acl_to_text_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_valid.3		comp-c-man		.man
+./usr/share/man/man3/acl_valid_fd_np.3		comp-c-man		.man
+./usr/share/man/man3/acl_valid_file_np.3	comp-c-man		.man
 ./usr/share/man/man3/acos.3			comp-c-man		.man
 ./usr/share/man/man3/acosf.3			comp-c-man		.man
 ./usr/share/man/man3/acosh.3			comp-c-man		.man
@@ -24920,6 +25079,7 @@
 ./usr/share/man/man3/popenve.3			comp-c-man		.man
 ./usr/share/man/man3/pos_form_cursor.3		comp-c-man		.man
 ./usr/share/man/man3/pos_menu_cursor.3		comp-c-man		.man
+./usr/share/man/man3/posix1e.3			comp-c-man		.man
 ./usr/share/man/man3/posix2time.3		comp-c-man		.man
 ./usr/share/man/man3/posix2time_z.3		comp-c-man		.man
 ./usr/share/man/man3/posix_memalign.3		comp-c-man		.man
@@ -26481,8 +26641,8 @@
 ./usr/share/man/man3/wdelch.3			comp-c-man		.man
 ./usr/share/man/man3/wdeleteln.3		comp-c-man		.man
 ./usr/share/man/man3/wechochar.3		comp-c-man		.man
-./usr/share/man/man3/werase.3			comp-c-man		.man
 ./usr/share/man/man3/wenclose.3			comp-c-man		.man
+./usr/share/man/man3/werase.3			comp-c-man		.man
 ./usr/share/man/man3/wgetch.3			comp-c-man		.man
 ./usr/share/man/man3/wgetnstr.3			comp-c-man		.man
 ./usr/share/man/man3/wgetstr.3			comp-c-man		.man
Index: distrib/sets/lists/debug/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/debug/mi,v
retrieving revision 1.309
diff -u -p -p -u -r1.309 mi
--- distrib/sets/lists/debug/mi	1 May 2020 17:14:28 -0000	1.309
+++ distrib/sets/lists/debug/mi	15 May 2020 16:56:40 -0000
@@ -286,6 +286,7 @@
 ./usr/libdata/debug/bin/echo.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/ed.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/expr.debug		comp-util-debug		debug
+./usr/libdata/debug/bin/getfacl.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/hostname.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/kill.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/ksh.debug		comp-util-debug		debug
@@ -302,6 +303,7 @@
 ./usr/libdata/debug/bin/rm.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/rmdir.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/rump.dd.debug		comp-util-debug		debug,rump
+./usr/libdata/debug/bin/setfacl.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/sh.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/sleep.debug		comp-util-debug		debug
 ./usr/libdata/debug/bin/stty.debug		comp-util-debug		debug
Index: distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1687
diff -u -p -p -u -r1.1687 mi
--- distrib/sets/lists/man/mi	12 Apr 2020 01:10:53 -0000	1.1687
+++ distrib/sets/lists/man/mi	15 May 2020 16:56:41 -0000
@@ -188,6 +188,7 @@
 ./usr/share/man/cat1/getconf.0			man-util-catman		.cat
 ./usr/share/man/cat1/getent.0			man-util-catman		.cat
 ./usr/share/man/cat1/getextattr.0		man-util-catman		.cat
+./usr/share/man/cat1/getfacl.0			man-util-catman		.cat
 ./usr/share/man/cat1/getopt.0			man-util-catman		.cat
 ./usr/share/man/cat1/gettext.0			man-locale-catman	.cat
 ./usr/share/man/cat1/gkermit.0			man-obsolete		.cat,obsolete
@@ -520,6 +521,7 @@
 ./usr/share/man/cat1/sendmail.0			man-postfix-catman	postfix,.cat
 ./usr/share/man/cat1/seq.0			man-util-catman		.cat
 ./usr/share/man/cat1/setextattr.0		man-util-catman		.cat
+./usr/share/man/cat1/setfacl.0			man-util-catman		.cat
 ./usr/share/man/cat1/sftp.0			man-secsh-catman	.cat
 ./usr/share/man/cat1/sh.0			man-util-catman		.cat
 ./usr/share/man/cat1/sha1.0			man-util-catman		.cat
@@ -3487,6 +3489,7 @@
 ./usr/share/man/html1/getconf.html		man-util-htmlman	html
 ./usr/share/man/html1/getent.html		man-util-htmlman	html
 ./usr/share/man/html1/getextattr.html		man-util-htmlman	html
+./usr/share/man/html1/getfacl.html		man-util-htmlman	html
 ./usr/share/man/html1/getopt.html		man-util-htmlman	html
 ./usr/share/man/html1/gettext.html		man-locale-htmlman	html
 ./usr/share/man/html1/gkermit.html		man-obsolete		html,obsolete
@@ -3801,6 +3804,7 @@
 ./usr/share/man/html1/sendmail.html		man-postfix-htmlman	postfix,html
 ./usr/share/man/html1/seq.html			man-util-htmlman	html
 ./usr/share/man/html1/setextattr.html		man-util-htmlman	html
+./usr/share/man/html1/setfacl.html		man-util-htmlman	html
 ./usr/share/man/html1/sftp.html			man-secsh-htmlman	html
 ./usr/share/man/html1/sh.html			man-util-htmlman	html
 ./usr/share/man/html1/sha1.html			man-util-htmlman	html
@@ -6402,6 +6406,7 @@
 ./usr/share/man/man1/getconf.1			man-util-man		.man
 ./usr/share/man/man1/getent.1			man-util-man		.man
 ./usr/share/man/man1/getextattr.1		man-util-man		.man
+./usr/share/man/man1/getfacl.1			man-util-man		.man
 ./usr/share/man/man1/getopt.1			man-util-man		.man
 ./usr/share/man/man1/gettext.1			man-locale-man		.man
 ./usr/share/man/man1/gkermit.1			man-obsolete		.man,obsolete
@@ -6734,6 +6739,7 @@
 ./usr/share/man/man1/sendmail.1			man-postfix-man		postfix,.man
 ./usr/share/man/man1/seq.1			man-util-man		.man
 ./usr/share/man/man1/setextattr.1		man-util-man		.man
+./usr/share/man/man1/setfacl.1			man-util-man		.man
 ./usr/share/man/man1/sftp.1			man-secsh-man		.man
 ./usr/share/man/man1/sh.1			man-util-man		.man
 ./usr/share/man/man1/sha1.1			man-util-man		.man
Index: external/bsd/libarchive/include/config_netbsd.h
===================================================================
RCS file: /cvsroot/src/external/bsd/libarchive/include/config_netbsd.h,v
retrieving revision 1.11
diff -u -p -p -u -r1.11 config_netbsd.h
--- external/bsd/libarchive/include/config_netbsd.h	24 Oct 2019 18:17:14 -0000	1.11
+++ external/bsd/libarchive/include/config_netbsd.h	15 May 2020 16:56:43 -0000
@@ -5,10 +5,10 @@
 /* #undef ARCHIVE_ACL_DARWIN */
 
 /* FreeBSD ACL support */
-/* #undef ARCHIVE_ACL_FREEBSD */
+#define ARCHIVE_ACL_FREEBSD 1
 
 /* FreeBSD NFSv4 ACL support */
-/* #undef ARCHIVE_ACL_FREEBSD_NFS4 */
+#define ARCHIVE_ACL_FREEBSD_NFS4 1
 
 /* Linux POSIX.1e ACL support via libacl */
 /* #undef ARCHIVE_ACL_LIBACL */
@@ -170,109 +170,109 @@
 /* #undef HAVE_ACLENT_T */
 
 /* Define to 1 if you have the `acl_add_flag_np' function. */
-/* #undef HAVE_ACL_ADD_FLAG_NP */
+#define HAVE_ACL_ADD_FLAG_NP 1
 
 /* Define to 1 if you have the `acl_add_perm' function. */
-/* #undef HAVE_ACL_ADD_PERM */
+#define HAVE_ACL_ADD_PERM 1
 
 /* Define to 1 if you have the `acl_clear_flags_np' function. */
-/* #undef HAVE_ACL_CLEAR_FLAGS_NP */
+#define HAVE_ACL_CLEAR_FLAGS_NP 1
 
 /* Define to 1 if you have the `acl_clear_perms' function. */
-/* #undef HAVE_ACL_CLEAR_PERMS */
+#define HAVE_ACL_CLEAR_PERMS 1
 
 /* Define to 1 if you have the `acl_create_entry' function. */
-/* #undef HAVE_ACL_CREATE_ENTRY */
+#define HAVE_ACL_CREATE_ENTRY 1
 
 /* Define to 1 if you have the `acl_delete_def_file' function. */
-/* #undef HAVE_ACL_DELETE_DEF_FILE */
+#define HAVE_ACL_DELETE_DEF_FILE 1
 
 /* Define to 1 if the system has the type `acl_entry_t'. */
-/* #undef HAVE_ACL_ENTRY_T */
+#define HAVE_ACL_ENTRY_T 1
 
 /* Define to 1 if you have the `acl_free' function. */
-/* #undef HAVE_ACL_FREE */
+#define HAVE_ACL_FREE 1
 
 /* Define to 1 if you have the `acl_get_brand_np' function. */
-/* #undef HAVE_ACL_GET_BRAND_NP */
+#define HAVE_ACL_GET_BRAND_NP 1
 
 /* Define to 1 if you have the `acl_get_entry' function. */
-/* #undef HAVE_ACL_GET_ENTRY */
+#define HAVE_ACL_GET_ENTRY 1
 
 /* Define to 1 if you have the `acl_get_entry_type_np' function. */
-/* #undef HAVE_ACL_GET_ENTRY_TYPE_NP */
+#define HAVE_ACL_GET_ENTRY_TYPE_NP 1
 
 /* Define to 1 if you have the `acl_get_fd' function. */
-/* #undef HAVE_ACL_GET_FD */
+#define HAVE_ACL_GET_FD 1
 
 /* Define to 1 if you have the `acl_get_fd_np' function. */
-/* #undef HAVE_ACL_GET_FD_NP */
+#define HAVE_ACL_GET_FD_NP 1
 
 /* Define to 1 if you have the `acl_get_file' function. */
-/* #undef HAVE_ACL_GET_FILE */
+#define HAVE_ACL_GET_FILE 1
 
 /* Define to 1 if you have the `acl_get_flagset_np' function. */
-/* #undef HAVE_ACL_GET_FLAGSET_NP */
+#define HAVE_ACL_GET_FLAGSET_NP 1
 
 /* Define to 1 if you have the `acl_get_flag_np' function. */
-/* #undef HAVE_ACL_GET_FLAG_NP */
+#define HAVE_ACL_GET_FLAG_NP 1
 
 /* Define to 1 if you have the `acl_get_link_np' function. */
-/* #undef HAVE_ACL_GET_LINK_NP */
+#define HAVE_ACL_GET_LINK_NP 1
 
 /* Define to 1 if you have the `acl_get_perm' function. */
 /* #undef HAVE_ACL_GET_PERM */
 
 /* Define to 1 if you have the `acl_get_permset' function. */
-/* #undef HAVE_ACL_GET_PERMSET */
+#define HAVE_ACL_GET_PERMSET 1
 
 /* Define to 1 if you have the `acl_get_perm_np' function. */
-/* #undef HAVE_ACL_GET_PERM_NP */
+#define HAVE_ACL_GET_PERM_NP 1
 
 /* Define to 1 if you have the `acl_get_qualifier' function. */
-/* #undef HAVE_ACL_GET_QUALIFIER */
+#define HAVE_ACL_GET_QUALIFIER 1
 
 /* Define to 1 if you have the `acl_get_tag_type' function. */
-/* #undef HAVE_ACL_GET_TAG_TYPE */
+#define HAVE_ACL_GET_TAG_TYPE 1
 
 /* Define to 1 if you have the `acl_init' function. */
-/* #undef HAVE_ACL_INIT */
+#define HAVE_ACL_INIT 1
 
 /* Define to 1 if you have the `acl_is_trivial_np' function. */
-/* #undef HAVE_ACL_IS_TRIVIAL_NP */
+#define HAVE_ACL_IS_TRIVIAL_NP 1
 
 /* Define to 1 if you have the <acl/libacl.h> header file. */
 /* #undef HAVE_ACL_LIBACL_H */
 
 /* Define to 1 if the system has the type `acl_permset_t'. */
-/* #undef HAVE_ACL_PERMSET_T */
+#define HAVE_ACL_PERMSET_T 1
 
 /* Define to 1 if you have the `acl_set_entry_type_np' function. */
-/* #undef HAVE_ACL_SET_ENTRY_TYPE_NP */
+#define HAVE_ACL_SET_ENTRY_TYPE_NP 1
 
 /* Define to 1 if you have the `acl_set_fd' function. */
-/* #undef HAVE_ACL_SET_FD */
+#define HAVE_ACL_SET_FD 1
 
 /* Define to 1 if you have the `acl_set_fd_np' function. */
-/* #undef HAVE_ACL_SET_FD_NP */
+#define HAVE_ACL_SET_FD_NP 1
 
 /* Define to 1 if you have the `acl_set_file' function. */
-/* #undef HAVE_ACL_SET_FILE */
+#define HAVE_ACL_SET_FILE 1
 
 /* Define to 1 if you have the `acl_set_link_np' function. */
-/* #undef HAVE_ACL_SET_LINK_NP */
+#define HAVE_ACL_SET_LINK_NP 1
 
 /* Define to 1 if you have the `acl_set_qualifier' function. */
-/* #undef HAVE_ACL_SET_QUALIFIER */
+#define HAVE_ACL_SET_QUALIFIER 1
 
 /* Define to 1 if you have the `acl_set_tag_type' function. */
-/* #undef HAVE_ACL_SET_TAG_TYPE */
+#define HAVE_ACL_SET_TAG_TYPE 1
 
 /* Define to 1 if the system has the type `acl_t'. */
-/* #undef HAVE_ACL_T */
+#define HAVE_ACL_T 1
 
 /* Define to 1 if the system has the type `acl_tag_t'. */
-/* #undef HAVE_ACL_TAG_T */
+#define HAVE_ACL_TAG_T 1
 
 /* Define to 1 if you have the `arc4random_buf' function. */
 #define HAVE_ARC4RANDOM_BUF 1
@@ -324,19 +324,19 @@
 
 /* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if
    you don't. */
-/* #undef HAVE_DECL_ACL_SYNCHRONIZE */
+#define HAVE_DECL_ACL_SYNCHRONIZE 1
 
 /* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if
    you don't. */
-/* #undef HAVE_DECL_ACL_TYPE_EXTENDED */
+#define HAVE_DECL_ACL_TYPE_EXTENDED 0
 
 /* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you
    don't. */
-/* #undef HAVE_DECL_ACL_TYPE_NFS4 */
+#define HAVE_DECL_ACL_TYPE_NFS4 1
 
 /* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you
    don't. */
-/* #undef HAVE_DECL_ACL_USER */
+#define HAVE_DECL_ACL_USER 1
 
 /* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to
    0 if you don't. */
@@ -920,7 +920,7 @@
 
 /* Define to 1 if `stat' has the bug that it succeeds when given the
    zero-length file name argument. */
-#define HAVE_STAT_EMPTY_STRING_BUG 1
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
 
 /* Define to 1 if you have the <stdarg.h> header file. */
 #define HAVE_STDARG_H 1
@@ -1013,7 +1013,7 @@
 #define HAVE_SYMLINK 1
 
 /* Define to 1 if you have the <sys/acl.h> header file. */
-/* #undef HAVE_SYS_ACL_H */
+#define HAVE_SYS_ACL_H 1
 
 /* Define to 1 if you have the <sys/cdefs.h> header file. */
 #define HAVE_SYS_CDEFS_H 1
Index: external/bsd/libarchive/lib/libarchive/Makefile
===================================================================
RCS file: /cvsroot/src/external/bsd/libarchive/lib/libarchive/Makefile,v
retrieving revision 1.11
diff -u -p -p -u -r1.11 Makefile
--- external/bsd/libarchive/lib/libarchive/Makefile	13 Oct 2019 07:28:06 -0000	1.11
+++ external/bsd/libarchive/lib/libarchive/Makefile	15 May 2020 16:56:43 -0000
@@ -20,6 +20,7 @@ SRCS=		archive_acl.c \
 		archive_cmdline.c \
 		archive_cryptor.c \
 		archive_digest.c \
+		archive_disk_acl_freebsd.c \
 		archive_entry.c \
 		archive_entry_copy_stat.c \
 		archive_entry_link_resolver.c \
Index: external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c
===================================================================
RCS file: /cvsroot/src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c,v
retrieving revision 1.11
diff -u -p -p -u -r1.11 zfs_ctldir.c
--- external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c	17 Jan 2020 20:08:06 -0000	1.11
+++ external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c	15 May 2020 16:56:46 -0000
@@ -1590,7 +1590,7 @@ sfs_access(void *v)
 	SFS_NODE_ASSERT(ap->a_vp);
 	ZFS_ENTER(zfsvfs);
 
-	if (ap->a_mode & FWRITE)
+	if (ap->a_accmode & FWRITE)
 		error = EACCES;
 
 	ZFS_EXIT(zfsvfs);
Index: external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c
===================================================================
RCS file: /cvsroot/src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c,v
retrieving revision 1.66
diff -u -p -p -u -r1.66 zfs_vnops.c
--- external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c	13 May 2020 05:52:54 -0000	1.66
+++ external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c	15 May 2020 16:56:46 -0000
@@ -5155,11 +5155,11 @@ zfs_netbsd_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
-	int mode = ap->a_mode;
+	accmode_t accmode = ap->a_accmode;
 	mode_t zfs_mode = 0;
 	kauth_cred_t cred = ap->a_cred;
 	int error;
@@ -5169,11 +5169,11 @@ zfs_netbsd_access(void *v)
 	 * and it exists only because of randomness in zfs_unix_to_v4
 	 * and zfs_zaccess_rwx in zfs_acl.c.
 	 */
-	if (mode & VREAD)
+	if (accmode & VREAD)
 		zfs_mode |= S_IROTH;
-	if (mode & VWRITE)
+	if (accmode & VWRITE)
 		zfs_mode |= S_IWOTH;
-	if (mode & VEXEC)
+	if (accmode & VEXEC)
 		zfs_mode |= S_IXOTH;
 	zfs_mode <<= 6;
 
@@ -5631,8 +5631,7 @@ zfs_netbsd_setattr(void *v)
 		}
 
 		error = kauth_authorize_vnode(cred, action, vp, NULL,
-		    genfs_can_chflags(cred, vp->v_type, zp->z_uid,
-		    changing_sysflags));
+		    genfs_can_chflags(vp, cred, zp->z_uid, changing_sysflags));
 		if (error)
 			return error;
 	}
@@ -5640,8 +5639,8 @@ zfs_netbsd_setattr(void *v)
 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
 	    vap->va_birthtime.tv_sec != VNOVAL) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		     NULL, genfs_can_chtimes(vp, vap->va_vaflags, zp->z_uid,
-		     cred));
+		     NULL, genfs_can_chtimes(vp, cred, zp->z_uid,
+		     vap->va_vaflags));
 		if (error)
 			return error;
 	}
@@ -6332,6 +6331,7 @@ const struct vnodeopv_entry_desc zfs_vno
 	{ &vop_open_desc,		zfs_netbsd_open },
 	{ &vop_close_desc,		zfs_netbsd_close },
 	{ &vop_access_desc,		zfs_netbsd_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		zfs_netbsd_getattr },
 	{ &vop_setattr_desc,		zfs_netbsd_setattr },
 	{ &vop_read_desc,		zfs_netbsd_read },
@@ -6377,6 +6377,7 @@ const struct vnodeopv_entry_desc zfs_spe
 	{ &vop_open_desc,		spec_open },
 	{ &vop_close_desc,		spec_close },
 	{ &vop_access_desc,		zfs_netbsd_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		zfs_netbsd_getattr },
 	{ &vop_setattr_desc,		zfs_netbsd_setattr },
 	{ &vop_read_desc,		/**/zfs_netbsd_read },
@@ -6424,6 +6425,7 @@ const struct vnodeopv_entry_desc zfs_fif
 	{ &vop_open_desc,		vn_fifo_bypass },
 	{ &vop_close_desc,		vn_fifo_bypass },
 	{ &vop_access_desc,		zfs_netbsd_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		zfs_netbsd_getattr },
 	{ &vop_setattr_desc,		zfs_netbsd_setattr },
 	{ &vop_read_desc,		/**/zfs_netbsd_read },
Index: external/cddl/osnet/sys/kern/policy.c
===================================================================
RCS file: /cvsroot/src/external/cddl/osnet/sys/kern/policy.c,v
retrieving revision 1.7
diff -u -p -p -u -r1.7 policy.c
--- external/cddl/osnet/sys/kern/policy.c	28 May 2018 21:05:09 -0000	1.7
+++ external/cddl/osnet/sys/kern/policy.c	15 May 2020 16:56:46 -0000
@@ -177,7 +177,7 @@ secpolicy_vnode_owner(vnode_t *vp, cred_
 
 int
 secpolicy_vnode_access(cred_t *cred, vnode_t *vp, uid_t owner,
-    int mode)
+    accmode_t mode)
 {
 
 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
Index: external/cddl/osnet/sys/sys/policy.h
===================================================================
RCS file: /cvsroot/src/external/cddl/osnet/sys/sys/policy.h,v
retrieving revision 1.8
diff -u -p -p -u -r1.8 policy.h
--- external/cddl/osnet/sys/sys/policy.h	28 May 2018 21:05:10 -0000	1.8
+++ external/cddl/osnet/sys/sys/policy.h	15 May 2020 16:56:46 -0000
@@ -40,8 +40,6 @@
 struct mount;
 struct vattr;
 
-typedef int accmode_t;
-
 int	secpolicy_nfs(cred_t *cr);
 int	secpolicy_zfs(cred_t *crd);
 int	secpolicy_sys_config(cred_t *cr, int checkonly);
Index: include/mntopts.h
===================================================================
RCS file: /cvsroot/src/include/mntopts.h,v
retrieving revision 1.18
diff -u -p -p -u -r1.18 mntopts.h
--- include/mntopts.h	9 Jan 2018 03:31:12 -0000	1.18
+++ include/mntopts.h	15 May 2020 16:56:50 -0000
@@ -43,6 +43,8 @@ struct mntopt {
 };
 
 /* User-visible MNT_ flags. */
+#define MOPT_ACLS		{ "acls",	0, MNT_ACLS, 0 }
+#define MOPT_POSIX1EACLS	{ "posix1eacls",0, MNT_POSIX1EACLS, 0 }
 #define MOPT_ASYNC		{ "async",	0, MNT_ASYNC, 0 }
 #define MOPT_NOCOREDUMP		{ "coredump",	1, MNT_NOCOREDUMP, 0 }
 #define MOPT_NODEV		{ "dev",	1, MNT_NODEV, 0 }
Index: include/unistd.h
===================================================================
RCS file: /cvsroot/src/include/unistd.h,v
retrieving revision 1.157
diff -u -p -p -u -r1.157 unistd.h
--- include/unistd.h	6 May 2020 16:17:36 -0000	1.157
+++ include/unistd.h	15 May 2020 16:56:50 -0000
@@ -361,6 +361,7 @@ __aconst char *getusershell(void);
 int	 initgroups(const char *, gid_t);
 int	 iruserok(uint32_t, int, const char *, const char *);
 int      issetugid(void);
+long	 lpathconf(const char *, int);
 int	 mkstemps(char *, int);
 int	 nfssvc(int, void *);
 int	 pipe2(int *, int);
Index: lib/libc/Makefile
===================================================================
RCS file: /cvsroot/src/lib/libc/Makefile,v
retrieving revision 1.172
diff -u -p -p -u -r1.172 Makefile
--- lib/libc/Makefile	3 Aug 2018 14:01:21 -0000	1.172
+++ lib/libc/Makefile	15 May 2020 16:56:50 -0000
@@ -80,6 +80,7 @@ CPPFLAGS+=	-D__BUILD_LEGACY
 .include "${.CURDIR}/net/Makefile.inc"
 .include "${.CURDIR}/nameser/Makefile.inc"
 .include "${.CURDIR}/nls/Makefile.inc"
+.include "${.CURDIR}/posix1e/Makefile.inc"
 .include "${.CURDIR}/regex/Makefile.inc"
 .include "${.CURDIR}/resolv/Makefile.inc"
 .include "${.CURDIR}/rpc/Makefile.inc"
Index: lib/libc/posix1e/Makefile.inc
===================================================================
RCS file: lib/libc/posix1e/Makefile.inc
diff -N lib/libc/posix1e/Makefile.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/Makefile.inc	15 May 2020 16:56:51 -0000
@@ -0,0 +1,89 @@
+# $FreeBSD: head/lib/libc/posix1e/Makefile.inc 338745 2018-09-18 01:40:37Z brd $
+
+.PATH: ${.CURDIR}/posix1e ${NETBSDSRCDIR}/sys/kern
+
+CPPFLAGS+=-D_ACL_PRIVATE
+
+SRCS+=	acl_branding.c			\
+	acl_calc_mask.c			\
+	acl_copy.c			\
+	acl_delete.c			\
+	acl_delete_entry.c		\
+	acl_entry.c			\
+	acl_flag.c			\
+	acl_free.c			\
+	acl_from_text.c			\
+	acl_from_text_nfs4.c            \
+	acl_get.c			\
+	acl_id_to_name.c		\
+	acl_init.c			\
+	acl_perm.c			\
+	acl_set.c			\
+	acl_strip.c			\
+	acl_support.c			\
+	acl_support_nfs4.c              \
+	acl_to_text.c			\
+	acl_to_text_nfs4.c              \
+	acl_valid.c			\
+	extattr.c			\
+	subr_acl_nfs4.c
+
+MAN+=	acl.3				\
+	acl_add_flag_np.3		\
+	acl_add_perm.3			\
+	acl_calc_mask.3			\
+	acl_clear_flags_np.3		\
+	acl_clear_perms.3		\
+	acl_copy_entry.3		\
+	acl_create_entry.3		\
+	acl_delete.3			\
+	acl_delete_entry.3		\
+	acl_delete_flag_np.3		\
+	acl_delete_perm.3		\
+	acl_dup.3			\
+	acl_free.3			\
+	acl_from_text.3			\
+	acl_get.3			\
+	acl_get_brand_np.3		\
+	acl_get_entry.3			\
+	acl_get_entry_type_np.3		\
+	acl_get_flagset_np.3		\
+	acl_get_flag_np.3		\
+	acl_get_permset.3		\
+	acl_get_perm_np.3		\
+	acl_get_qualifier.3		\
+	acl_get_tag_type.3		\
+	acl_init.3			\
+	acl_is_trivial_np.3		\
+	acl_set.3			\
+	acl_set_entry_type_np.3		\
+	acl_set_flagset_np.3		\
+	acl_set_permset.3		\
+	acl_set_qualifier.3		\
+	acl_set_tag_type.3		\
+	acl_strip_np.3			\
+	acl_to_text.3			\
+	acl_valid.3			\
+	extattr.3			\
+	posix1e.3
+
+MLINKS+=acl_create_entry.3 acl_create_entry_np.3 \
+	acl_delete.3 acl_delete_def_file.3	\
+	acl_delete.3 acl_delete_file_np.3	\
+	acl_delete.3 acl_delete_fd_np.3		\
+	acl_delete_entry.3 acl_delete_entry_np.3 \
+	acl_get.3 acl_get_file.3		\
+	acl_get.3 acl_get_fd.3			\
+	acl_get.3 acl_get_fd_np.3		\
+	acl_get.3 acl_get_link_np.3		\
+	acl_set.3 acl_set_file.3		\
+	acl_set.3 acl_set_fd.3			\
+	acl_set.3 acl_set_fd_np.3		\
+	acl_set.3 acl_set_link_np.3		\
+	acl_to_text.3 acl_to_text_np.3		\
+	acl_valid.3 acl_valid_file_np.3		\
+	acl_valid.3 acl_valid_fd_np.3		\
+
+
+#	extattr.3 extattr_namespace_to_string.3	\
+#	extattr.3 extattr_string_to_namespace.3
Index: lib/libc/posix1e/acl.3
===================================================================
RCS file: lib/libc/posix1e/acl.3
diff -N lib/libc/posix1e/acl.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,307 @@
+.\"-
+.\" Copyright (c) 2000, 2001, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl.3 296196 2016-02-29 16:52:06Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL 3
+.Os
+.Sh NAME
+.Nm acl
+.Nd introduction to the POSIX.1e/NFSv4 ACL security API
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Sh DESCRIPTION
+.Fx
+permits file systems to export Access Control Lists via the VFS, and
+provides a library for userland access to and manipulation of these ACLs.
+.Fx
+supports POSIX.1e and NFSv4 ACLs, but
+not all file systems provide support for ACLs, and some may require that
+ACL support be explicitly enabled by the administrator.
+The library calls include routines to allocate, duplicate, retrieve, set,
+and validate ACLs associated with file objects.
+As well as the POSIX.1e routines, there are a number of non-portable
+extensions defined that allow for ACL semantics alternative to
+POSIX.1e, such as NFSv4.
+Where routines are non-standard, they are suffixed with _np to indicate that
+they are not portable.
+.Pp
+POSIX.1e describes a set of ACL manipulation routines to manage the
+contents of ACLs, as well as their relationships with files; almost
+all of these support routines are implemented in
+.Fx .
+.Pp
+Available functions, sorted by behavior, include:
+.Bl -tag -width indent
+.It Fn acl_add_flag_np
+This function is described in
+.Xr acl_add_flag_np 3 ,
+and may be used to add flags to a flagset.
+.It Fn acl_add_perm
+This function is described in
+.Xr acl_add_perm 3 ,
+and may be used to add permissions to a permission set.
+.It Fn acl_calc_mask
+This function is described in
+.Xr acl_calc_mask 3 ,
+and may be used to calculate and set the permissions associated with
+the
+.Dv ACL_MASK
+entry.
+.It Fn acl_clear_flags_np
+This function is described in
+.Xr acl_clear_flags_np 3 ,
+and may be used to clear all flags from a flagset.
+.It Fn acl_clear_perms
+This function is described in
+.Xr acl_clear_perms 3 ,
+and may be used to clear all permissions from a permission set.
+.It Fn acl_copy_entry
+This function is described in
+.Xr acl_copy_entry 3 ,
+and may be used to copy the contents of an ACL entry.
+.It Xo
+.Fn acl_create_entry ,
+.Fn acl_create_entry_np
+.Xc
+These functions are described in
+.Xr acl_create_entry 3 ,
+and may be used to create an empty entry in an ACL.
+.It Xo
+.Fn acl_delete_def_file ,
+.Fn acl_delete_def_link_np ,
+.Fn acl_delete_fd_np ,
+.Fn acl_delete_file_np ,
+.Fn acl_delete_link_np
+.Xc
+These functions are described in
+.Xr acl_delete 3 ,
+and may be used to delete ACLs from file system objects.
+.It Xo
+.Fn acl_delete_entry ,
+.Fn acl_delete_entry_np ,
+.Xc
+This functions are described in
+.Xr acl_delete_entry 3 ,
+and may be used to delete an entry from an ACL.
+.It Fn acl_delete_flag_np
+This function is described in
+.Xr acl_delete_flag_np 3 ,
+and may be used to delete flags from a flagset.
+.It Fn acl_delete_perm
+This function is described in
+.Xr acl_delete_perm 3 ,
+and may be used to delete permissions from a permset.
+.It Fn acl_dup
+This function is described in
+.Xr acl_dup 3 ,
+and may be used to duplicate an ACL structure.
+.It Fn acl_free
+This function is described in
+.Xr acl_free 3 ,
+and may be used to free userland working ACL storage.
+.It Fn acl_from_text
+This function is described in
+.Xr acl_from_text 3 ,
+and may be used to convert a text-form ACL into working ACL state, if
+the ACL has POSIX.1e or NFSv4 semantics.
+.It Fn acl_get_brand_np
+This function is described in
+.Xr acl_get_brand_np 3
+and may be used to determine whether the ACL has POSIX.1e or NFSv4 semantics.
+.It Fn acl_get_entry
+This function is described in
+.Xr acl_get_entry 3 ,
+and may be used to retrieve a designated ACL entry from an ACL.
+.It Xo
+.Fn acl_get_fd ,
+.Fn acl_get_fd_np ,
+.Fn acl_get_file ,
+.Fn acl_get_link_np
+.Xc
+These functions are described in
+.Xr acl_get 3 ,
+and may be used to retrieve ACLs from file system objects.
+.It Fn acl_get_entry_type_np
+This function is described in
+.Xr acl_get_entry_type_np 3 ,
+and may be used to retrieve an ACL type from an ACL entry.
+.It Fn acl_get_flagset_np
+This function is described in
+.Xr acl_get_flagset_np 3 ,
+and may be used to retrieve a flagset from an ACL entry.
+.It Fn acl_get_permset
+This function is described in
+.Xr acl_get_permset 3 ,
+and may be used to retrieve a permset from an ACL entry.
+.It Fn acl_get_qualifier
+This function is described in
+.Xr acl_get_qualifier 3 ,
+and may be used to retrieve the qualifier from an ACL entry.
+.It Fn acl_get_tag_type
+This function is described in
+.Xr acl_get_tag_type 3 ,
+and may be used to retrieve the tag type from an ACL entry.
+.It Fn acl_init
+This function is described in
+.Xr acl_init 3 ,
+and may be used to allocate a fresh (empty) ACL structure.
+.It Fn acl_is_trivial_np
+This function is described in
+.Xr acl_is_trivial_np 3 ,
+and may be used to find out whether ACL is trivial.
+.It Xo
+.Fn acl_set_fd ,
+.Fn acl_set_fd_np ,
+.Fn acl_set_file ,
+.Fn acl_set_link_np
+.Xc
+These functions are described in
+.Xr acl_set 3 ,
+and may be used to assign an ACL to a file system object.
+.It Fn acl_set_entry_type_np
+This function is described in
+.Xr acl_set_entry_type_np 3 ,
+and may be used to set the ACL type of an ACL entry.
+.It Fn acl_set_flagset_np
+This function is described in
+.Xr acl_set_flagset_np 3 ,
+and may be used to set the flags of an ACL entry from a flagset.
+.It Fn acl_set_permset
+This function is described in
+.Xr acl_set_permset 3 ,
+and may be used to set the permissions of an ACL entry from a permset.
+.It Fn acl_set_qualifier
+This function is described in
+.Xr acl_set_qualifier 3 ,
+and may be used to set the qualifier of an ACL.
+.It Fn acl_set_tag_type
+This function is described in
+.Xr acl_set_tag_type 3 ,
+and may be used to set the tag type of an ACL.
+.It Fn acl_strip_np
+This function is described in
+.Xr acl_strip_np 3 ,
+and may be used to remove extended entries from an ACL.
+.It Xo
+.Fn acl_to_text ,
+.Fn acl_to_text_np
+.Xc
+These functions are described in
+.Xr acl_to_text 3 ,
+and may be used to generate a text-form of a POSIX.1e or NFSv4 semantics ACL.
+.It Xo
+.Fn acl_valid ,
+.Fn acl_valid_fd_np ,
+.Fn acl_valid_file_np ,
+.Fn acl_valid_link_np
+.Xc
+These functions are described in
+.Xr acl_valid 3 ,
+and may be used to validate an ACL as correct POSIX.1e-semantics, or
+as appropriate for a particular file system object regardless of semantics.
+.El
+.Pp
+Documentation of the internal kernel interfaces backing these calls may
+be found in
+.Xr acl 9 .
+The syscalls between the internal interfaces and the public library
+routines may change over time, and as such are not documented.
+They are not intended to be called directly without going through the
+library.
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr setfacl 1 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_calc_mask 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_copy_entry 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_free 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_entry_type_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr acl_init 3 ,
+.Xr acl_is_trivial_np 3 ,
+.Xr acl_set 3 ,
+.Xr acl_set_entry_type_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr acl_set_permset 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 3 ,
+.Xr acl_strip_np 3 ,
+.Xr acl_to_text 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3 ,
+.Xr acl 9
+.Sh STANDARDS
+POSIX.1e assigns security labels to all objects, extending the security
+functionality described in POSIX.1.
+These additional labels provide fine-grained discretionary access control,
+fine-grained capabilities, and labels necessary for mandatory access
+control.
+POSIX.2c describes a set of userland utilities for manipulating these
+labels.
+.Pp
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft continues on the cross-platform POSIX.1e
+implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ;
+.Fx 5.0
+was the first version to include a complete ACL implementation based
+on extended attributes for the UFS and UFS2 file systems.
+NFSv4 ACL support was introduced in
+.Fx 8.0 .
+.Pp
+The
+.Xr getfacl 1
+and
+.Xr setfacl 1
+utilities describe the user tools that permit direct manipulation of complete
+file ACLs.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_add_flag_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_add_flag_np.3
diff -N lib/libc/posix1e/acl_add_flag_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_add_flag_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_add_flag_np.3 287445 2015-09-04 00:14:20Z delphij $
+.\"
+.Dd September 4, 2015
+.Dt ACL_ADD_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_add_flag_np
+.Nd add flags to a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_add_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_add_flag_np
+function
+is a non-portable call that adds the NFSv4 ACL flags contained in
+.Fa flags
+to the flagset
+.Fa flagset_d .
+.Pp
+Note: it is not considered an error to attempt to add flags
+that already exist in the flagset.
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_ENTRY_NO_PROPAGATE_INHERIT"
+.It ACL_ENTRY_FILE_INHERIT Ta "Will be inherited by files."
+.It ACL_ENTRY_DIRECTORY_INHERIT Ta "Will be inherited by directories."
+.It ACL_ENTRY_NO_PROPAGATE_INHERIT Ta "Will not propagate."
+.It ACL_ENTRY_INHERIT_ONLY Ta "Inherit-only."
+.It ACL_ENTRY_INHERITED Ta "Inherited from parent"
+.El
+.Sh RETURN VALUES
+.Rv -std acl_add_flag_np
+.Sh ERRORS
+The
+.Fn acl_add_flag_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset within an ACL entry.
+Argument
+.Fa flag
+does not contain a valid
+.Vt acl_flag_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_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 .
+The
+.Fn acl_add_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_add_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_add_perm.3
===================================================================
RCS file: lib/libc/posix1e/acl_add_perm.3
diff -N lib/libc/posix1e/acl_add_perm.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_add_perm.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,129 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_add_perm.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_ADD_PERM 3
+.Os
+.Sh NAME
+.Nm acl_add_perm
+.Nd add permissions to a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_add_perm "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_add_perm
+function
+is a POSIX.1e call that adds the permission contained in
+.Fa perm
+to the permission set
+.Fa permset_d .
+.Pp
+Note: it is not considered an error to attempt to add permissions
+that already exist in the permission set.
+.Pp
+For POSIX.1e ACLs, valid values are:
+.Bl -column -offset 3n "ACL_WRITE_NAMED_ATTRS"
+.It ACL_EXECUTE	Execute permission
+.It ACL_WRITE	Write permission
+.It ACL_READ	Read permission
+.El
+.Pp
+For NFSv4 ACLs, valid values are:
+.Bl -column -offset 3n "ACL_WRITE_NAMED_ATTRS"
+.It ACL_READ_DATA Ta "Read permission"
+.It ACL_LIST_DIRECTORY Ta "Same as ACL_READ_DATA"
+.It ACL_WRITE_DATA Ta "Write permission, or permission to create files"
+.It ACL_ADD_FILE Ta "Same as ACL_READ_DATA"
+.It ACL_APPEND_DATA Ta "Permission to create directories.  Ignored for files"
+.It ACL_ADD_SUBDIRECTORY Ta "Same as ACL_APPEND_DATA"
+.It ACL_READ_NAMED_ATTRS Ta "Ignored"
+.It ACL_WRITE_NAMED_ATTRS Ta "Ignored"
+.It ACL_EXECUTE Ta "Execute permission"
+.It ACL_DELETE_CHILD Ta "Permission to delete files and subdirectories"
+.It ACL_READ_ATTRIBUTES Ta "Permission to read basic attributes"
+.It ACL_WRITE_ATTRIBUTES Ta "Permission to change basic attributes"
+.It ACL_DELETE Ta "Permission to delete the object this ACL is placed on"
+.It ACL_READ_ACL Ta "Permission to read ACL"
+.It ACL_WRITE_ACL Ta "Permission to change the ACL and file mode"
+.It ACL_SYNCHRONIZE Ta "Ignored"
+.El
+.Pp
+Calling
+.Fn acl_add_perm
+with
+.Fa perm
+equal to ACL_WRITE or ACL_READ brands the ACL as POSIX.
+Calling it with ACL_READ_DATA, ACL_LIST_DIRECTORY, ACL_WRITE_DATA,
+ACL_ADD_FILE, ACL_APPEND_DATA, ACL_ADD_SUBDIRECTORY, ACL_READ_NAMED_ATTRS,
+ACL_WRITE_NAMED_ATTRS, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES,
+ACL_WRITE_ATTRIBUTES, ACL_DELETE, ACL_READ_ACL, ACL_WRITE_ACL
+or ACL_SYNCHRONIZE brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_add_perm
+.Sh ERRORS
+The
+.Fn acl_add_perm
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set within an ACL entry.
+Argument
+.Fa perm
+does not contain a valid
+.Vt acl_perm_t
+value.
+ACL is already branded differently.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 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 .
+The
+.Fn acl_add_perm
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_add_perm
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_branding.c
===================================================================
RCS file: lib/libc/posix1e/acl_branding.c
diff -N lib/libc/posix1e/acl_branding.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_branding.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,175 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_branding.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+/*
+ * An ugly detail of the implementation - fortunately not visible
+ * to the API users - is the "branding": libc needs to keep track
+ * of what "brand" ACL is: NFSv4, POSIX.1e or unknown.  It happens
+ * automatically - for example, during acl_get_file(3) ACL gets
+ * branded according to the "type" argument; during acl_set_permset
+ * ACL, if its brand is unknown it gets branded as NFSv4 if any of the
+ * NFSv4 permissions that are not valid for POSIX.1e ACL are set etc.
+ * Branding information is used for printing out the ACL (acl_to_text(3)),
+ * veryfying acl_set_whatever arguments (checking against setting
+ * bits that are valid only for NFSv4 in ACL branded as POSIX.1e) etc.
+ */
+
+static acl_t
+entry2acl(acl_entry_t entry)
+{
+	acl_t aclp;
+
+	aclp = (acl_t)(((long)entry >> _ACL_T_ALIGNMENT_BITS) << _ACL_T_ALIGNMENT_BITS);
+
+	return (aclp);
+}
+
+/*
+ * Return brand of an ACL.
+ */
+int
+_acl_brand(const acl_t acl)
+{
+
+	return (acl->ats_brand);
+}
+
+int
+_entry_brand(const acl_entry_t entry)
+{
+
+	return (_acl_brand(entry2acl(entry)));
+}
+
+/*
+ * Return 1, iff branding ACL as "brand" is ok.
+ */
+int
+_acl_brand_may_be(const acl_t acl, int brand)
+{
+
+	if (_acl_brand(acl) == ACL_BRAND_UNKNOWN)
+		return (1);
+
+	if (_acl_brand(acl) == brand)
+		return (1);
+
+	return (0);
+}
+
+int
+_entry_brand_may_be(const acl_entry_t entry, int brand)
+{
+
+	return (_acl_brand_may_be(entry2acl(entry), brand));
+}
+
+/*
+ * Brand ACL as "brand".
+ */
+void
+_acl_brand_as(acl_t acl, int brand)
+{
+
+	assert(_acl_brand_may_be(acl, brand));
+
+	acl->ats_brand = brand;
+}
+
+void
+_entry_brand_as(const acl_entry_t entry, int brand)
+{
+
+	_acl_brand_as(entry2acl(entry), brand);
+}
+
+int
+_acl_type_not_valid_for_acl(const acl_t acl, acl_type_t type)
+{
+
+	switch (_acl_brand(acl)) {
+	case ACL_BRAND_NFS4:
+		if (type == ACL_TYPE_NFS4)
+			return (0);
+		break;
+
+	case ACL_BRAND_POSIX:
+		if (type == ACL_TYPE_ACCESS || type == ACL_TYPE_DEFAULT)
+			return (0);
+		break;
+
+	case ACL_BRAND_UNKNOWN:
+		return (0);
+	}
+
+	return (-1);
+}
+
+void
+_acl_brand_from_type(acl_t acl, acl_type_t type)
+{
+
+	switch (type) {
+	case ACL_TYPE_NFS4:
+		_acl_brand_as(acl, ACL_BRAND_NFS4);
+		break;
+	case ACL_TYPE_ACCESS:
+	case ACL_TYPE_DEFAULT:
+		_acl_brand_as(acl, ACL_BRAND_POSIX);
+		break;
+	default:
+		/* XXX: What to do here? */
+		break;
+	}
+}
+
+int
+acl_get_brand_np(acl_t acl, int *brand_p)
+{
+
+	if (acl == NULL || brand_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	*brand_p = _acl_brand(acl);
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_calc_mask.3
===================================================================
RCS file: lib/libc/posix1e/acl_calc_mask.3
diff -N lib/libc/posix1e/acl_calc_mask.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_calc_mask.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_calc_mask.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_CALC_MASK 3
+.Os
+.Sh NAME
+.Nm acl_calc_mask
+.Nd calculate and set ACL mask permissions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_calc_mask "acl_t *acl_p"
+.Sh DESCRIPTION
+The
+.Fn acl_calc_mask
+function
+is a POSIX.1e call that calculates and set the permissions
+associated with the
+.Dv ACL_MASK
+ACL entry of the ACL referred to by
+.Fa acl_p .
+.Pp
+The value of new permissions are the union of the permissions
+granted by the
+.Dv ACL_GROUP , ACL_GROUP_OBJ , ACL_USER
+tag types which
+match processes in the file group class contained in the ACL
+referred to by
+.Fa acl_p .
+.Pp
+If the ACL referred to by
+.Fa acl_p
+already contains an
+.Dv ACL_MASK
+entry, its permissions shall be
+overwritten; if it does not contain an
+.Dv ACL_MASK
+entry, one shall
+be added.
+.Sh RETURN VALUES
+.Rv -std acl_calc_mask
+.Sh ERRORS
+The
+.Fn acl_calc_mask
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl_p
+does not point to a pointer to a valid ACL.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_valid 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 .
+The
+.Fn acl_calc_mask
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_calc_mask
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_calc_mask.c
===================================================================
RCS file: lib/libc/posix1e/acl_calc_mask.c
diff -N lib/libc/posix1e/acl_calc_mask.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_calc_mask.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,136 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_calc_mask.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_calc_mask() (23.4.2): calculate and set the permissions
+ * associated with the ACL_MASK ACL entry.  If the ACL already
+ * contains an ACL_MASK entry, its permissions shall be
+ * overwritten; if not, one shall be added.
+ */
+int
+acl_calc_mask(acl_t *acl_p)
+{
+	struct acl	*acl_int, *acl_int_new;
+	acl_t		acl_new;
+	size_t		i;
+	int		mask_mode, mask_num;
+
+	/*
+	 * (23.4.2.4) requires acl_p to point to a pointer to a valid ACL.
+	 * Since one of the primary reasons to use this function would be
+	 * to calculate the appropriate mask to obtain a valid ACL, we only
+	 * perform sanity checks here and validate the ACL prior to
+	 * returning.
+	 */
+	if (acl_p == NULL || *acl_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (!_acl_brand_may_be(*acl_p, ACL_BRAND_POSIX)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	_acl_brand_as(*acl_p, ACL_BRAND_POSIX);
+
+	acl_int = &(*acl_p)->ats_acl;
+	if ((acl_int->acl_cnt < 3) || (acl_int->acl_cnt > ACL_MAX_ENTRIES)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	acl_new = acl_dup(*acl_p);
+	if (acl_new == NULL)
+		return (-1);
+	acl_int_new = &acl_new->ats_acl;
+
+	mask_mode = 0;
+	mask_num = -1;
+
+	/* gather permissions and find a mask entry */
+	for (i = 0; i < acl_int_new->acl_cnt; i++) {
+		switch(acl_int_new->acl_entry[i].ae_tag) {
+		case ACL_USER:
+		case ACL_GROUP:
+		case ACL_GROUP_OBJ:
+			mask_mode |=
+			    acl_int_new->acl_entry[i].ae_perm & ACL_PERM_BITS;
+			break;
+		case ACL_MASK:
+			mask_num = i;
+			break;
+		}
+	}
+
+	/* if a mask entry already exists, overwrite the perms */
+	if (mask_num != -1)
+		acl_int_new->acl_entry[mask_num].ae_perm = mask_mode;
+	else {
+		/* if no mask exists, check acl_cnt... */
+		if (acl_int_new->acl_cnt == ACL_MAX_ENTRIES) {
+			errno = ENOMEM;
+			acl_free(acl_new);
+			return (-1);
+		}
+		/* ...and add the mask entry */
+		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_tag = ACL_MASK;
+		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_id =
+		    ACL_UNDEFINED_ID;
+		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_perm =
+		    mask_mode;
+		acl_int_new->acl_cnt++;
+	}
+
+	if (acl_valid(acl_new) == -1) {
+		errno = EINVAL;
+		acl_free(acl_new);
+		return (-1);
+	}
+
+	**acl_p = *acl_new;
+	acl_free(acl_new);
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_clear_flags_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_clear_flags_np.3
diff -N lib/libc/posix1e/acl_clear_flags_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_clear_flags_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,79 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_clear_flags_np.3 273853 2014-10-30 10:49:50Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL_CLEAR_FLAGS_NP 3
+.Os
+.Sh NAME
+.Nm acl_clear_flags_np
+.Nd clear flags from a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_clear_flags_np "acl_flagset_t flagset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_clear_flags_np
+function
+is a non-portable call that clears all NFSv4 ACL flags from flagset
+.Fa flagset_d .
+.Sh RETURN VALUES
+.Rv -std acl_clear_flags_np
+.Sh ERRORS
+The
+.Fn acl_clear_flags_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_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 .
+The
+.Fn acl_clear_flags_np
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_clear_flags_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_clear_perms.3
===================================================================
RCS file: lib/libc/posix1e/acl_clear_perms.3
diff -N lib/libc/posix1e/acl_clear_perms.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_clear_perms.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,79 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_clear_perms.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_CLEAR_PERMS 3
+.Os
+.Sh NAME
+.Nm acl_clear_perms
+.Nd clear permissions from a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_clear_perms "acl_permset_t permset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_clear_perms
+function
+is a POSIX.1e call that clears all permissions from permissions set
+.Fa permset_d .
+.Sh RETURN VALUES
+.Rv -std acl_clear_perms
+.Sh ERRORS
+The
+.Fn acl_clear_perms
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 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 .
+The
+.Fn acl_clear_perms
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_clear_perms
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_compat.c
===================================================================
RCS file: lib/libc/posix1e/acl_compat.c
diff -N lib/libc/posix1e/acl_compat.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_compat.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,69 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_compat.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/acl.h>
+
+int __oldacl_get_perm_np(acl_permset_t, oldacl_perm_t);
+int __oldacl_add_perm(acl_permset_t, oldacl_perm_t);
+int __oldacl_delete_perm(acl_permset_t, oldacl_perm_t);
+
+/*
+ * Compatibility wrappers for applications compiled against libc from before
+ * NFSv4 ACLs were added.
+ */
+int
+__oldacl_get_perm_np(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+	return (acl_get_perm_np(permset_d, perm));
+}
+
+int
+__oldacl_add_perm(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+	return (acl_add_perm(permset_d, perm));
+}
+
+int
+__oldacl_delete_perm(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+	return (acl_delete_perm(permset_d, perm));
+}
+
+__sym_compat(acl_get_perm_np, __oldacl_get_perm_np, FBSD_1.0);
+__sym_compat(acl_add_perm, __oldacl_add_perm, FBSD_1.0);
+__sym_compat(acl_delete_perm, __oldacl_delete_perm, FBSD_1.0);
Index: lib/libc/posix1e/acl_copy.c
===================================================================
RCS file: lib/libc/posix1e/acl_copy.c
diff -N lib/libc/posix1e/acl_copy.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_copy.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,91 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_copy.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_copy_entry() (23.4.4): copy the contents of ACL entry src_d to
+ * ACL entry dest_d
+ */
+int
+acl_copy_entry(acl_entry_t dest_d, acl_entry_t src_d)
+{
+
+	if (src_d == NULL || dest_d == NULL || src_d == dest_d) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/*
+	 * Can we brand the new entry the same as the source entry?
+	 */
+	if (!_entry_brand_may_be(dest_d, _entry_brand(src_d))) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	_entry_brand_as(dest_d, _entry_brand(src_d));
+
+	dest_d->ae_tag = src_d->ae_tag;
+	dest_d->ae_id = src_d->ae_id;
+	dest_d->ae_perm = src_d->ae_perm;
+	dest_d->ae_entry_type = src_d->ae_entry_type;
+	dest_d->ae_flags = src_d->ae_flags;
+
+	return (0);
+}
+
+ssize_t
+acl_copy_ext(void *buf_p, acl_t acl, ssize_t size)
+{
+
+	errno = ENOSYS;
+	return (-1);
+}
+
+acl_t
+acl_copy_int(const void *buf_p)
+{
+
+	errno = ENOSYS;
+	return (NULL);
+}
Index: lib/libc/posix1e/acl_copy_entry.3
===================================================================
RCS file: lib/libc/posix1e/acl_copy_entry.3
diff -N lib/libc/posix1e/acl_copy_entry.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_copy_entry.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_copy_entry.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_COPY_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_copy_entry
+.Nd copy an ACL entry to another ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_copy_entry "acl_entry_t dest_d" "acl_entry_t src_d"
+.Sh DESCRIPTION
+The
+.Fn acl_copy_entry
+function
+is a POSIX.1e call that copies the contents of ACL entry
+.Fa src_d
+to ACL entry
+.Fa dest_d .
+.Sh RETURN VALUES
+.Rv -std acl_copy_entry
+.Sh ERRORS
+The
+.Fn acl_copy_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa src_d
+or
+.Fa dest_d
+is not a valid descriptor for an ACL entry, or
+arguments
+.Fa src_d
+and
+.Fa dest_d
+reference the same ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_entry 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 .
+The
+.Fn acl_copy_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_copy_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_create_entry.3
===================================================================
RCS file: lib/libc/posix1e/acl_create_entry.3
diff -N lib/libc/posix1e/acl_create_entry.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_create_entry.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_create_entry.3 318708 2017-05-23 07:11:15Z ngie $
+.\"
+.Dd June 25, 2009
+.Dt ACL_CREATE_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_create_entry ,
+.Nm acl_create_entry_np
+.Nd create a new ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_create_entry "acl_t *acl_p" "acl_entry_t *entry_p"
+.Ft int
+.Fn acl_create_entry_np "acl_t *acl_p" "acl_entry_t *entry_p" "int index"
+.Sh DESCRIPTION
+The
+.Fn acl_create_entry
+function
+is a POSIX.1e call that creates a new ACL entry in the ACL
+pointed to by
+.Fa acl_p .
+The
+.Fn acl_create_entry_np
+function is a non-portable version that creates the ACL entry
+at position
+.Fa index .
+Positions are numbered starting from zero, i.e. calling
+.Fn acl_create_entry_np
+with
+.Fa index
+argument equal to zero will prepend the entry to the ACL.
+.Sh RETURN VALUES
+.Rv -std acl_create_entry
+.Sh ERRORS
+The
+.Fn acl_create_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl_p
+does not point to a pointer to a valid ACL.
+Argument
+.Fa index
+is out of bounds.
+.It Bq Er ENOMEM
+The ACL working storage requires more memory than is
+allowed by the hardware or system-imposed memory
+management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_get_entry 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 .
+The
+.Fn acl_create_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_create_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_delete.3
===================================================================
RCS file: lib/libc/posix1e/acl_delete.3
diff -N lib/libc/posix1e/acl_delete.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,140 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_delete.3 131635 2004-07-05 17:12:53Z ru $
+.\"
+.Dd December 29, 2002
+.Dt ACL_DELETE 3
+.Os
+.Sh NAME
+.Nm acl_delete_def_file ,
+.Nm acl_delete_def_link_np ,
+.Nm acl_delete_fd_np ,
+.Nm acl_delete_file_np ,
+.Nm acl_delete_link_np
+.Nd delete an ACL from a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_def_file "const char *path_p"
+.Ft int
+.Fn acl_delete_def_link_np "const char *path_p"
+.Ft int
+.Fn acl_delete_fd_np "int filedes" "acl_type_t type"
+.Ft int
+.Fn acl_delete_file_np "const char *path_p" "acl_type_t type"
+.Ft int
+.Fn acl_delete_link_np "const char *path_p" "acl_type_t type"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_def_file ,
+.Fn acl_delete_def_link_np ,
+.Fn acl_delete_fd_np ,
+.Fn acl_delete_file_np ,
+and
+.Fn acl_delete_link_np
+each allow the deletion of an ACL from a file.
+The
+.Fn acl_delete_def_file
+function
+is a POSIX.1e call that deletes the default ACL from a file (normally a
+directory) by name; the remainder of the calls are non-portable extensions
+that permit the deletion of arbitrary ACL types from a file/directory
+either by path name or file descriptor.
+The
+.Fn _file
+variations follow a symlink if it occurs in the last segment of the
+path name; the
+.Fn _link
+variations operate on the symlink itself.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return -1
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The ACL type passed is invalid for this file object.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.Pp
+Argument
+.Va path_p
+must be a directory, and is not.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL deletion.
+.It Bq Er EPERM
+The process does not have appropriate privilege to perform the operation
+to delete an ACL.
+.It Bq Er EROFS
+The file system is read-only.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_delete.c
===================================================================
RCS file: lib/libc/posix1e/acl_delete.c
diff -N lib/libc/posix1e/acl_delete.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,84 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * acl_delete_def_file -- remove a default acl from a file
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_delete.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/errno.h>
+
+#include "acl_support.h"
+
+int
+acl_delete_def_file(const char *path_p)
+{
+
+	return (__acl_delete_file(path_p, ACL_TYPE_DEFAULT));
+}
+
+int
+acl_delete_def_link_np(const char *path_p)
+{
+
+	return (__acl_delete_link(path_p, ACL_TYPE_DEFAULT));
+}
+
+int
+acl_delete_file_np(const char *path_p, acl_type_t type)
+{
+
+	type = _acl_type_unold(type);
+	return (__acl_delete_file(path_p, type));
+}
+
+int
+acl_delete_link_np(const char *path_p, acl_type_t type)
+{
+
+	type = _acl_type_unold(type);
+	return (__acl_delete_link(path_p, type));
+}
+
+int
+acl_delete_fd_np(int filedes, acl_type_t type)
+{
+
+	type = _acl_type_unold(type);
+	return (__acl_delete_fd(filedes, type));
+}
Index: lib/libc/posix1e/acl_delete_entry.3
===================================================================
RCS file: lib/libc/posix1e/acl_delete_entry.3
diff -N lib/libc/posix1e/acl_delete_entry.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete_entry.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,101 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_delete_entry.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_DELETE_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_delete_entry ,
+.Nm acl_delete_entry_np
+.Nd delete an ACL entry from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_entry "acl_t acl" "acl_entry_t entry_d"
+.Ft int
+.Fn acl_delete_entry_np "acl_t acl" "int index"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_entry
+function
+is a POSIX.1e call that removes the ACL entry
+.Fa entry_d
+from ACL
+.Fa acl .
+The
+.Fn acl_delete_entry_np
+function is a non-portable version that removes the ACL entry
+at position
+.Fa index
+from ACL
+.Fa acl .
+Positions are numbered starting from zero, i.e. calling
+.Fn acl_delete_entry_np
+with
+.Fa index
+argument equal to zero will remove the first ACL entry.
+.Sh RETURN VALUES
+.Rv -std acl_delete_entry
+.Sh ERRORS
+The
+.Fn acl_delete_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry in
+.Fa acl .
+Argument
+.Fa index
+is out of bounds.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_copy_entry 3 ,
+.Xr acl_get_entry 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 .
+The
+.Fn acl_delete_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_delete_entry.c
===================================================================
RCS file: lib/libc/posix1e/acl_delete_entry.c
diff -N lib/libc/posix1e/acl_delete_entry.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete_entry.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,165 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_delete_entry.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "acl_support.h"
+
+static int
+_entry_matches(const acl_entry_t a, const acl_entry_t b)
+{
+	/*
+	 * There is a semantical difference here between NFSv4 and POSIX
+	 * draft ACLs.  In POSIX, there may be only one entry for the particular
+	 * user or group.  In NFSv4 ACL, there may be any number of them.  We're
+	 * trying to be more specific here in that case.
+	 */
+	switch (_entry_brand(a)) {
+	case ACL_BRAND_NFS4:
+		if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type)
+			return (0);
+
+		/* If ae_ids matter, compare them as well. */
+		if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
+			if (a->ae_id != b->ae_id)
+				return (0);
+		}
+
+		return (1);
+
+	default:
+		if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id))
+			return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d
+ * from acl.
+ */
+int
+acl_delete_entry(acl_t acl, acl_entry_t entry_d)
+{
+	struct acl_entry entry_int;
+	size_t i, j;
+	int found = 0;
+
+	if (acl == NULL || entry_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_entry_brand(entry_d) != _acl_brand(acl)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((acl->ats_acl.acl_cnt < 1) ||
+	    (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/* Use a local copy to prevent deletion of more than this entry */
+	entry_int = *entry_d;
+
+	for (i = 0; i < acl->ats_acl.acl_cnt;) {
+		if (_entry_matches(&(acl->ats_acl.acl_entry[i]), &entry_int)) {
+			/* ...shift the remaining entries... */
+			for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j)
+				acl->ats_acl.acl_entry[j] =
+				    acl->ats_acl.acl_entry[j+1];
+			/* ...drop the count and zero the unused entry... */
+			acl->ats_acl.acl_cnt--;
+			bzero(&acl->ats_acl.acl_entry[j],
+			    sizeof(struct acl_entry));
+			acl->ats_cur_entry = 0;
+			
+			/* Continue with the loop to remove all matching entries. */
+			found = 1;
+		} else
+			i++;
+	}
+
+	if (found)
+		return (0);
+
+	errno = EINVAL;
+	return (-1);
+}
+
+int
+acl_delete_entry_np(acl_t acl, int offset)
+{
+	struct acl *acl_int;
+	size_t i;
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	acl_int = &acl->ats_acl;
+
+	if (offset < 0 || (size_t)offset >= acl_int->acl_cnt) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((acl->ats_acl.acl_cnt < 1) ||
+	    (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/* ...shift the remaining entries... */
+	for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i)
+		acl->ats_acl.acl_entry[i] =
+		    acl->ats_acl.acl_entry[i+1];
+	/* ...drop the count and zero the unused entry... */
+	acl->ats_acl.acl_cnt--;
+	bzero(&acl->ats_acl.acl_entry[i],
+	    sizeof(struct acl_entry));
+	acl->ats_cur_entry = 0;
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_delete_flag_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_delete_flag_np.3
diff -N lib/libc/posix1e/acl_delete_flag_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete_flag_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,84 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_delete_flag_np.3 296196 2016-02-29 16:52:06Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL_DELETE_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_delete_flag_np
+.Nd delete flags from a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_flag_np
+function
+is a non-portable call that removes specific NFSv4 ACL flags from flagset
+.Fa flags .
+.Sh RETURN VALUES
+.Rv -std acl_delete_flag_np
+.Sh ERRORS
+The
+.Fn acl_delete_flag_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset.
+Argument
+.Fa flag
+does not contain a valid
+.Vt acl_flag_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_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 .
+The
+.Fn acl_delete_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_delete_perm.3
===================================================================
RCS file: lib/libc/posix1e/acl_delete_perm.3
diff -N lib/libc/posix1e/acl_delete_perm.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_delete_perm.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,84 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_delete_perm.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_DELETE_PERM 3
+.Os
+.Sh NAME
+.Nm acl_delete_perm
+.Nd delete permissions from a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_perm "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_perm
+function
+is a POSIX.1e call that removes specific permissions from permissions set
+.Fa perm .
+.Sh RETURN VALUES
+.Rv -std acl_delete_perm
+.Sh ERRORS
+The
+.Fn acl_delete_perm
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set.
+Argument
+.Fa perm
+does not contain a valid
+.Vt acl_perm_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 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 .
+The
+.Fn acl_delete_perm
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_perm
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_dup.3
===================================================================
RCS file: lib/libc/posix1e/acl_dup.3
diff -N lib/libc/posix1e/acl_dup.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_dup.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,110 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_dup.3 131504 2004-07-02 23:52:20Z ru $
+.\"
+.Dd January 28, 2000
+.Dt ACL_DUP 3
+.Os
+.Sh NAME
+.Nm acl_dup
+.Nd duplicate an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_dup "acl_t acl"
+.Sh DESCRIPTION
+The
+.Fn acl_dup
+function returns a pointer to a copy of the ACL pointed to by the argument
+.Va acl .
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Pp
+Any existing ACL pointers that refer to the ACL referred to by
+.Va acl
+shall continue to refer to the ACL.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+duplicate ACL.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_entry.c
===================================================================
RCS file: lib/libc/posix1e/acl_entry.c
diff -N lib/libc/posix1e/acl_entry.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_entry.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,151 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_entry.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * acl_create_entry() (23.4.7): create a new ACL entry in the ACL pointed
+ * to by acl_p.
+ */
+int
+acl_create_entry(acl_t *acl_p, acl_entry_t *entry_p)
+{
+	struct acl *acl_int;
+
+	if (acl_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	acl_int = &(*acl_p)->ats_acl;
+
+	/*
+	 * +1, because we are checking if there is space left for one more
+	 * entry.
+	 */
+	if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*entry_p = &acl_int->acl_entry[acl_int->acl_cnt++];
+
+	(**entry_p).ae_tag  = ACL_UNDEFINED_TAG;
+	(**entry_p).ae_id   = ACL_UNDEFINED_ID;
+	(**entry_p).ae_perm = ACL_PERM_NONE;
+	(**entry_p).ae_entry_type = 0;
+	(**entry_p).ae_flags = 0;
+
+	(*acl_p)->ats_cur_entry = 0;
+
+	return (0);
+}
+
+int
+acl_create_entry_np(acl_t *acl_p, acl_entry_t *entry_p, int offset)
+{
+	int i;
+	struct acl *acl_int;
+
+	if (acl_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	acl_int = &(*acl_p)->ats_acl;
+
+	if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (offset < 0 || (size_t)offset > acl_int->acl_cnt) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/* Make room for the new entry. */
+	for (i = acl_int->acl_cnt; i > offset; i--)
+		acl_int->acl_entry[i] = acl_int->acl_entry[i - 1];
+
+	acl_int->acl_cnt++;
+
+	*entry_p = &acl_int->acl_entry[offset];
+
+	(**entry_p).ae_tag  = ACL_UNDEFINED_TAG;
+	(**entry_p).ae_id   = ACL_UNDEFINED_ID;
+	(**entry_p).ae_perm = ACL_PERM_NONE;
+	(**entry_p).ae_entry_type = 0;
+	(**entry_p).ae_flags= 0;
+
+	(*acl_p)->ats_cur_entry = 0;
+
+	return (0);
+}
+
+/*
+ * acl_get_entry() (23.4.14): returns an ACL entry from an ACL
+ * indicated by entry_id.
+ */
+int
+acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p)
+{
+	struct acl *acl_int;
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	acl_int = &acl->ats_acl;
+
+	switch(entry_id) {
+	case ACL_FIRST_ENTRY:
+		acl->ats_cur_entry = 0;
+		/* FALLTHROUGH */
+	case ACL_NEXT_ENTRY:
+		if (acl->ats_cur_entry >= acl->ats_acl.acl_cnt)
+			return 0;
+		*entry_p = &acl_int->acl_entry[acl->ats_cur_entry++];
+		return (1);
+	}
+
+	errno = EINVAL;
+	return (-1);
+}
Index: lib/libc/posix1e/acl_flag.c
===================================================================
RCS file: lib/libc/posix1e/acl_flag.c
diff -N lib/libc/posix1e/acl_flag.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_flag.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,161 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_flag.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+static int
+_flag_is_invalid(acl_flag_t flag)
+{
+
+	if ((flag & ACL_FLAGS_BITS) == flag)
+		return (0);
+
+	errno = EINVAL;
+
+	return (1);
+}
+
+int
+acl_add_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+	if (flagset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_flag_is_invalid(flag))
+		return (-1);
+
+	*flagset_d |= flag;
+
+	return (0);
+}
+
+int
+acl_clear_flags_np(acl_flagset_t flagset_d)
+{
+
+	if (flagset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*flagset_d = 0;
+
+	return (0);
+}
+
+int
+acl_delete_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+	if (flagset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_flag_is_invalid(flag))
+		return (-1);
+
+	*flagset_d &= ~flag;
+
+	return (0);
+}
+
+int
+acl_get_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+	if (flagset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_flag_is_invalid(flag))
+		return (-1);
+
+	if (*flagset_d & flag)
+		return (1);
+
+	return (0);
+}
+
+int
+acl_get_flagset_np(acl_entry_t entry_d, acl_flagset_t *flagset_p)
+{
+
+	if (entry_d == NULL || flagset_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*flagset_p = &entry_d->ae_flags;
+
+	return (0);
+}
+
+int
+acl_set_flagset_np(acl_entry_t entry_d, acl_flagset_t flagset_d)
+{
+
+	if (entry_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	_entry_brand_as(entry_d, ACL_BRAND_NFS4);
+
+	if (_flag_is_invalid(*flagset_d))
+		return (-1);
+
+	entry_d->ae_flags = *flagset_d;
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_free.3
===================================================================
RCS file: lib/libc/posix1e/acl_free.3
diff -N lib/libc/posix1e/acl_free.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_free.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,89 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_free.3 131504 2004-07-02 23:52:20Z ru $
+.\"
+.Dd January 28, 2000
+.Dt ACL_FREE 3
+.Os
+.Sh NAME
+.Nm acl_free
+.Nd free ACL working state
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_free "void *obj_p"
+.Sh DESCRIPTION
+The
+.Fn acl_free
+call allows the freeing of ACL working space, such as is allocated by
+.Xr acl_dup 3 ,
+or
+.Xr acl_from_text 3 .
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std acl_free
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_free
+function shall return -1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Va obj_p
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get 3 ,
+.Xr acl_init 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_free.c
===================================================================
RCS file: lib/libc/posix1e/acl_free.c
diff -N lib/libc/posix1e/acl_free.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_free.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,59 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * acl_free -- free ACL objects from user memory
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_free.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/errno.h>
+#include <stdlib.h>
+
+/*
+ * acl_free() (23.4.12): free any releasable memory allocated to the
+ * ACL data object identified by obj_p.
+ */
+int
+acl_free(void *obj_p)
+{
+
+	if (obj_p) {
+		free(obj_p);
+		obj_p = NULL;
+	}
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_from_text.3
===================================================================
RCS file: lib/libc/posix1e/acl_from_text.3
diff -N lib/libc/posix1e/acl_from_text.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_from_text.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,130 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_from_text.3 131504 2004-07-02 23:52:20Z ru $
+.\"
+.Dd January 28, 2000
+.Dt ACL_FROM_TEXT 3
+.Os
+.Sh NAME
+.Nm acl_from_text
+.Nd create an ACL from text
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_from_text "const char *buf_p"
+.Sh DESCRIPTION
+The
+.Fn acl_from_text
+function converts the text form of an ACL referred to by
+.Va buf_p
+into the internal working structure for ACLs, appropriate for applying to
+files or manipulating.
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void *)acl_t
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the
+internal representation of the ACL in working storage.
+Otherwise, a value
+of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_from_text
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va buf_p
+cannot be translated into an ACL.
+.It Bq Er ENOMEM
+The ACL working storage requires more memory than is allowed by the
+hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr acl_to_text 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
+.Sh BUGS
+The
+.Fn acl_from_text
+and
+.Fn acl_to_text
+functions
+rely on the
+.Xr getpwent 3
+library calls to manage username and uid mapping, as well as the
+.Xr getgrent 3
+library calls to manage groupname and gid mapping.
+These calls are not
+thread safe, and so transitively, neither are
+.Fn acl_from_text
+and
+.Fn acl_to_text .
+These functions may also interfere with stateful
+calls associated with the
+.Fn getpwent
+and
+.Fn getgrent
+calls.
Index: lib/libc/posix1e/acl_from_text.c
===================================================================
RCS file: lib/libc/posix1e/acl_from_text.c
diff -N lib/libc/posix1e/acl_from_text.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_from_text.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,318 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * acl_from_text: Convert a text-form ACL from a string to an acl_t.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_from_text.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+static acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
+
+int _nfs4_acl_entry_from_text(acl_t aclp, char *entry);
+int _text_could_be_nfs4_acl(const char *entry);
+
+static acl_tag_t
+acl_string_to_tag(char *tag, char *qualifier)
+{
+
+	if (*qualifier == '\0') {
+		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
+			return (ACL_USER_OBJ);
+		} else
+		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
+			return (ACL_GROUP_OBJ);
+		} else
+		if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
+			return (ACL_MASK);
+		} else
+		if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
+			return (ACL_OTHER);
+		} else
+			return(-1);
+	} else {
+		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
+			return(ACL_USER);
+		} else
+		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
+			return(ACL_GROUP);
+		} else
+			return(-1);
+	}
+}
+
+static int
+_posix1e_acl_entry_from_text(acl_t aclp, char *entry)
+{
+	acl_tag_t	 t;
+	acl_perm_t	 p;
+	char		*tag, *qualifier, *permission;
+	uid_t		 id;
+	int		 error;
+
+	assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
+
+	/* Split into three ':' delimited fields. */
+	tag = strsep(&entry, ":");
+	if (tag == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	tag = string_skip_whitespace(tag);
+	if ((*tag == '\0') && (!entry)) {
+		/*
+		 * Is an entirely comment line, skip to next
+		 * comma.
+		 */
+		return (0);
+	}
+	string_trim_trailing_whitespace(tag);
+
+	qualifier = strsep(&entry, ":");
+	if (qualifier == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	qualifier = string_skip_whitespace(qualifier);
+	string_trim_trailing_whitespace(qualifier);
+
+	permission = strsep(&entry, ":");
+	if (permission == NULL || entry) {
+		errno = EINVAL;
+		return (-1);
+	}
+	permission = string_skip_whitespace(permission);
+	string_trim_trailing_whitespace(permission);
+
+	t = acl_string_to_tag(tag, qualifier);
+	if (t == (acl_tag_t)-1) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	error = _posix1e_acl_string_to_perm(permission, &p);
+	if (error == -1) {
+		errno = EINVAL;
+		return (-1);
+	}		
+
+	switch(t) {
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			if (*qualifier != '\0') {
+				errno = EINVAL;
+				return (-1);
+			}
+			id = 0;
+			break;
+
+		case ACL_USER:
+		case ACL_GROUP:
+			error = _acl_name_to_id(t, qualifier, &id);
+			if (error == -1)
+				return (-1);
+			break;
+
+		default:
+			errno = EINVAL;
+			return (-1);
+	}
+
+	error = _posix1e_acl_add_entry(aclp, t, id, p);
+	if (error == -1)
+		return (-1);
+
+	return (0);
+}
+
+static int
+_text_is_nfs4_entry(const char *entry)
+{
+	int count = 0;
+
+	assert(strlen(entry) > 0);
+
+	while (*entry != '\0') {
+		if (*entry == ':' || *entry == '@')
+			count++;
+		entry++;
+	}
+
+	if (count <= 2)
+		return (0);
+
+	return (1);
+}
+
+/*
+ * acl_from_text -- Convert a string into an ACL.
+ * Postpone most validity checking until the end and call acl_valid() to do
+ * that.
+ */
+acl_t
+acl_from_text(const char *buf_p)
+{
+	acl_t		 acl;
+	char		*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
+	int		 error;
+
+	/* Local copy we can mess up. */
+	mybuf_p = strdup(buf_p);
+	if (mybuf_p == NULL)
+		return(NULL);
+
+	acl = acl_init(3); /* XXX: WTF, 3? */
+	if (acl == NULL) {
+		free(mybuf_p);
+		return(NULL);
+	}
+
+	/* Outer loop: delimit at \n boundaries. */
+	cur = mybuf_p;
+	while ((line = strsep(&cur, "\n"))) {
+		/* Now split the line on the first # to strip out comments. */
+		comment = line;
+		notcomment = strsep(&comment, "#");
+
+		/* Inner loop: delimit at ',' boundaries. */
+		while ((entry = strsep(&notcomment, ","))) {
+
+			/* Skip empty lines. */
+			if (strlen(string_skip_whitespace(entry)) == 0)
+				continue;
+
+			if (_acl_brand(acl) == ACL_BRAND_UNKNOWN) {
+				if (_text_is_nfs4_entry(entry))
+					_acl_brand_as(acl, ACL_BRAND_NFS4);
+				else
+					_acl_brand_as(acl, ACL_BRAND_POSIX);
+			}
+
+			switch (_acl_brand(acl)) {
+			case ACL_BRAND_NFS4:
+				error = _nfs4_acl_entry_from_text(acl, entry);
+				break;
+
+			case ACL_BRAND_POSIX:
+				error = _posix1e_acl_entry_from_text(acl, entry);
+				break;
+
+			default:
+				error = EINVAL;
+				break;
+			}
+
+			if (error)
+				goto error_label;
+		}
+	}
+
+#if 0
+	/* XXX Should we only return ACLs valid according to acl_valid? */
+	/* Verify validity of the ACL we read in. */
+	if (acl_valid(acl) == -1) {
+		errno = EINVAL;
+		goto error_label;
+	}
+#endif
+
+	free(mybuf_p);
+	return(acl);
+
+error_label:
+	acl_free(acl);
+	free(mybuf_p);
+	return(NULL);
+}
+
+/*
+ * Given a username/groupname from a text form of an ACL, return the uid/gid
+ * XXX NOT THREAD SAFE, RELIES ON GETPWNAM, GETGRNAM
+ * XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
+ * MAY HAVE SIDE-EFFECTS
+ */
+int
+_acl_name_to_id(acl_tag_t tag, char *name, uid_t *id)
+{
+	struct group	*g;
+	struct passwd	*p;
+	unsigned long	l;
+	char 		*endp;
+
+	switch(tag) {
+	case ACL_USER:
+		p = getpwnam(name);
+		if (p == NULL) {
+			l = strtoul(name, &endp, 0);
+			if (*endp != '\0' || l != (unsigned long)(uid_t)l) {
+				errno = EINVAL;
+				return (-1);
+			}
+			*id = (uid_t)l;
+			return (0);
+		}
+		*id = p->pw_uid;
+		return (0);
+
+	case ACL_GROUP:
+		g = getgrnam(name);
+		if (g == NULL) {
+			l = strtoul(name, &endp, 0);
+			if (*endp != '\0' || l != (unsigned long)(gid_t)l) {
+				errno = EINVAL;
+				return (-1);
+			}
+			*id = (gid_t)l;
+			return (0);
+		}
+		*id = g->gr_gid;
+		return (0);
+
+	default:
+		return (EINVAL);
+	}
+}
Index: lib/libc/posix1e/acl_from_text_nfs4.c
===================================================================
RCS file: lib/libc/posix1e/acl_from_text_nfs4.c
diff -N lib/libc/posix1e/acl_from_text_nfs4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_from_text_nfs4.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,289 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_from_text_nfs4.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <err.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+#define MAX_ENTRY_LENGTH 512
+
+/*
+ * Parse the tag field of ACL entry passed as "str".  If qualifier
+ * needs to follow, then the variable referenced by "need_qualifier"
+ * is set to 1, otherwise it's set to 0.
+ */
+static int
+parse_tag(const char *str, acl_entry_t entry, int *need_qualifier)
+{
+
+	assert(need_qualifier != NULL);
+	*need_qualifier = 0;
+
+	if (strcmp(str, "owner@") == 0)
+		return (acl_set_tag_type(entry, ACL_USER_OBJ));
+	if (strcmp(str, "group@") == 0)
+		return (acl_set_tag_type(entry, ACL_GROUP_OBJ));
+	if (strcmp(str, "everyone@") == 0)
+		return (acl_set_tag_type(entry, ACL_EVERYONE));
+
+	*need_qualifier = 1;
+
+	if (strcmp(str, "user") == 0 || strcmp(str, "u") == 0)
+		return (acl_set_tag_type(entry, ACL_USER));
+	if (strcmp(str, "group") == 0 || strcmp(str, "g") == 0)
+		return (acl_set_tag_type(entry, ACL_GROUP));
+
+	warnx("malformed ACL: invalid \"tag\" field");
+
+	return (-1);
+}
+
+/*
+ * Parse the qualifier field of ACL entry passed as "str".
+ * If user or group name cannot be resolved, then the variable
+ * referenced by "need_qualifier" is set to 1; it will be checked
+ * later to figure out whether the appended_id is required.
+ */
+static int
+parse_qualifier(char *str, acl_entry_t entry, int *need_qualifier)
+{
+	int qualifier_length, error;
+	uid_t id;
+	acl_tag_t tag;
+
+	assert(need_qualifier != NULL);
+	*need_qualifier = 0;
+
+	qualifier_length = strlen(str);
+
+	if (qualifier_length == 0) {
+		warnx("malformed ACL: empty \"qualifier\" field");
+		return (-1);
+	}
+
+	error = acl_get_tag_type(entry, &tag);
+	if (error)
+		return (error);
+
+	error = _acl_name_to_id(tag, str, &id);
+	if (error) {
+		*need_qualifier = 1;
+		return (0);
+	}
+
+	return (acl_set_qualifier(entry, &id));
+}
+
+static int
+parse_access_mask(char *str, acl_entry_t entry)
+{
+	int error;
+	acl_perm_t perm;
+
+	error = _nfs4_parse_access_mask(str, &perm);
+	if (error)
+		return (error);
+
+	error = acl_set_permset(entry, &perm);
+
+	return (error);
+}
+
+static int
+parse_flags(char *str, acl_entry_t entry)
+{
+	int error;
+	acl_flag_t flags;
+
+	error = _nfs4_parse_flags(str, &flags);
+	if (error)
+		return (error);
+
+	error = acl_set_flagset_np(entry, &flags);
+
+	return (error);
+}
+
+static int
+parse_entry_type(const char *str, acl_entry_t entry)
+{
+
+	if (strcmp(str, "allow") == 0)
+		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALLOW));
+	if (strcmp(str, "deny") == 0)
+		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_DENY));
+	if (strcmp(str, "audit") == 0)
+		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_AUDIT));
+	if (strcmp(str, "alarm") == 0)
+		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALARM));
+
+	warnx("malformed ACL: invalid \"type\" field");
+
+	return (-1);
+}
+
+static int
+parse_appended_id(char *str, acl_entry_t entry)
+{
+	int qualifier_length;
+	char *end;
+	id_t id;
+
+	qualifier_length = strlen(str);
+	if (qualifier_length == 0) {
+		warnx("malformed ACL: \"appended id\" field present, "
+	           "but empty");
+		return (-1);
+	}
+
+	id = strtod(str, &end);
+	if (end - str != qualifier_length) {
+		warnx("malformed ACL: appended id is not a number");
+		return (-1);
+	}
+
+	return (acl_set_qualifier(entry, &id));
+}
+
+static int
+number_of_colons(const char *str)
+{
+	int count = 0;
+
+	while (*str != '\0') {
+		if (*str == ':')
+			count++;
+
+		str++;
+	}
+
+	return (count);
+}
+
+int
+_nfs4_acl_entry_from_text(acl_t aclp, char *str)
+{
+	int error, need_qualifier;
+	acl_entry_t entry;
+	char *field, *qualifier_field = NULL;
+
+	error = acl_create_entry(&aclp, &entry);
+	if (error)
+		return (error);
+
+	assert(_entry_brand(entry) == ACL_BRAND_NFS4);
+
+	if (str == NULL)
+		goto truncated_entry;
+	field = strsep(&str, ":");
+
+	field = string_skip_whitespace(field);
+	if ((*field == '\0') && (!str)) {
+		/*
+		 * Is an entirely comment line, skip to next
+		 * comma.
+		 */
+		return (0);
+	}
+
+	error = parse_tag(field, entry, &need_qualifier);
+	if (error)
+		goto malformed_field;
+
+	if (need_qualifier) {
+		if (str == NULL)
+			goto truncated_entry;
+		qualifier_field = field = strsep(&str, ":");
+		error = parse_qualifier(field, entry, &need_qualifier);
+		if (error)
+			goto malformed_field;
+	}
+
+	if (str == NULL)
+		goto truncated_entry;
+	field = strsep(&str, ":");
+	error = parse_access_mask(field, entry);
+	if (error)
+		goto malformed_field;
+
+	if (str == NULL)
+		goto truncated_entry;
+	/* Do we have "flags" field? */
+	if (number_of_colons(str) > 0) {
+		field = strsep(&str, ":");
+		error = parse_flags(field, entry);
+		if (error)
+			goto malformed_field;
+	}
+
+	if (str == NULL)
+		goto truncated_entry;
+	field = strsep(&str, ":");
+	error = parse_entry_type(field, entry);
+	if (error)
+		goto malformed_field;
+
+	if (need_qualifier) {
+		if (str == NULL) {
+			warnx("malformed ACL: unknown user or group name "
+			    "\"%s\"", qualifier_field);
+			goto truncated_entry;
+		}
+
+		error = parse_appended_id(str, entry);
+		if (error)
+			goto malformed_field;
+	}
+
+	return (0);
+
+truncated_entry:
+malformed_field:
+	acl_delete_entry(aclp, entry);
+	errno = EINVAL;
+	return (-1);
+}
Index: lib/libc/posix1e/acl_get.3
===================================================================
RCS file: lib/libc/posix1e/acl_get.3
diff -N lib/libc/posix1e/acl_get.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,168 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_get.3 213573 2010-10-08 12:40:16Z uqs $
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET 3
+.Os
+.Sh NAME
+.Nm acl_get_fd ,
+.Nm acl_get_fd_np ,
+.Nm acl_get_file ,
+.Nm acl_get_link_np
+.Nd get an ACL for a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_get_fd "int fd"
+.Ft acl_t
+.Fn acl_get_fd_np "int fd" "acl_type_t type"
+.Ft acl_t
+.Fn acl_get_file "const char *path_p" "acl_type_t type"
+.Ft acl_t
+.Fn acl_get_link_np "const char *path_p" "acl_type_t type"
+.Sh DESCRIPTION
+The
+.Fn acl_get_fd ,
+.Fn acl_get_file ,
+.Fn acl_get_link_np ,
+and
+.Fn acl_get_fd_np
+each allow the retrieval of an ACL from a file.
+The
+.Fn acl_get_fd
+is a POSIX.1e call that allows the retrieval of an ACL of type
+ACL_TYPE_ACCESS
+from a file descriptor.
+The
+.Fn acl_get_fd_np
+function
+is a non-portable form of
+.Fn acl_get_fd
+that allows the retrieval of any type of ACL from a file descriptor.
+The
+.Fn acl_get_file
+function is a POSIX.1e call that allows the retrieval of a
+specified type of ACL from a file by name;
+.Fn acl_get_link_np
+is a non-portable variation on
+.Fn acl_get_file
+which does not follow a symlink if the target of the call is a
+symlink.
+.Pp
+These functions may cause memory to be allocated.
+The caller should free
+any releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void *)acl_t
+as an argument.
+.Pp
+The ACL in the working storage is an independent copy of the ACL associated
+with the object referred to by
+.Va fd .
+The ACL in the working storage shall not participate in any access control
+decisions.
+.Pp
+Valid values for the
+.Va type
+argument are:
+.Bl -column -offset 3n "ACL_TYPE_DEFAULT"
+.It ACL_TYPE_ACCESS	POSIX.1e access ACL
+.It ACL_TYPE_DEFAULT	POSIX.1e default ACL
+.It ACL_TYPE_NFS4	NFSv4 ACL
+.El
+.Pp
+The ACL returned will be branded accordingly.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the ACL
+that was retrieved.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_fd
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The ACL type passed is invalid for this file object.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_get.c
===================================================================
RCS file: lib/libc/posix1e/acl_get.c
diff -N lib/libc/posix1e/acl_get.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,221 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * acl_get_fd - syscall wrapper for retrieving access ACL by fd
+ * acl_get_fd_np - syscall wrapper for retrieving ACL by fd (non-POSIX)
+ * acl_get_file - syscall wrapper for retrieving ACL by filename
+ * acl_get_link_np - syscall wrapper for retrieving ACL by filename (NOFOLLOW)
+ *                   (non-POSIX)
+ * acl_get_perm_np() checks if a permission is in the specified
+ *                   permset (non-POSIX)
+ * acl_get_permset() returns the permission set in the ACL entry
+ * acl_get_qualifier() retrieves the qualifier of the tag from the ACL entry
+ * acl_get_tag_type() returns the tag type for the ACL entry entry_d
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_get.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "acl_support.h"
+
+acl_t
+acl_get_file(const char *path_p, acl_type_t type)
+{
+	acl_t	aclp;
+	int	error;
+
+	aclp = acl_init(ACL_MAX_ENTRIES);
+	if (aclp == NULL)
+		return (NULL);
+
+	type = _acl_type_unold(type);
+	error = __acl_get_file(path_p, type, &aclp->ats_acl);
+	if (error) {
+		acl_free(aclp);
+		return (NULL);
+	}
+
+	aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+	_acl_brand_from_type(aclp, type);
+
+	return (aclp);
+}
+
+acl_t
+acl_get_link_np(const char *path_p, acl_type_t type)
+{
+	acl_t	aclp;
+	int	error;
+
+	aclp = acl_init(ACL_MAX_ENTRIES);
+	if (aclp == NULL)
+		return (NULL);
+
+	type = _acl_type_unold(type);
+	error = __acl_get_link(path_p, type, &aclp->ats_acl);
+	if (error) {
+		acl_free(aclp);
+		return (NULL);
+	}
+
+	aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+	_acl_brand_from_type(aclp, type);
+
+	return (aclp);
+}
+
+acl_t
+acl_get_fd(int fd)
+{
+	if (fpathconf(fd, _PC_ACL_NFS4) == 1)
+		return (acl_get_fd_np(fd, ACL_TYPE_NFS4));
+
+	return (acl_get_fd_np(fd, ACL_TYPE_ACCESS));
+}
+
+acl_t
+acl_get_fd_np(int fd, acl_type_t type)
+{
+	acl_t	aclp;
+	int	error;
+
+	aclp = acl_init(ACL_MAX_ENTRIES);
+	if (aclp == NULL)
+		return (NULL);
+
+	type = _acl_type_unold(type);
+	error = __acl_get_fd(fd, type, &aclp->ats_acl);
+	if (error) {
+		acl_free(aclp);
+		return (NULL);
+	}
+
+	aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+	_acl_brand_from_type(aclp, type);
+
+	return (aclp);
+}
+
+/*
+ * acl_get_permset() (23.4.17): return via permset_p a descriptor to
+ * the permission set in the ACL entry entry_d.
+ */
+int
+acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p)
+{
+
+	if (entry_d == NULL || permset_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*permset_p = &entry_d->ae_perm;
+
+	return (0);
+}
+
+/*
+ * acl_get_qualifier() (23.4.18): retrieve the qualifier of the tag
+ * for the ACL entry entry_d.
+ */
+void *
+acl_get_qualifier(acl_entry_t entry_d)
+{
+	uid_t *retval;
+
+	if (entry_d == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	switch(entry_d->ae_tag) {
+	case ACL_USER:
+	case ACL_GROUP:
+		retval = malloc(sizeof(uid_t));
+		if (retval == NULL)
+			return (NULL);
+		*retval = entry_d->ae_id;
+		return (retval);
+	}
+
+	errno = EINVAL;
+	return (NULL);
+}
+
+/*
+ * acl_get_tag_type() (23.4.19): return the tag type for the ACL
+ * entry entry_p.
+ */
+int
+acl_get_tag_type(acl_entry_t entry_d, acl_tag_t *tag_type_p)
+{
+
+	if (entry_d == NULL || tag_type_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*tag_type_p = entry_d->ae_tag;
+
+	return (0);
+}
+
+int
+acl_get_entry_type_np(acl_entry_t entry_d, acl_entry_type_t *entry_type_p)
+{
+
+	if (entry_d == NULL || entry_type_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*entry_type_p = entry_d->ae_entry_type;
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_get_brand_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_brand_np.3
diff -N lib/libc/posix1e/acl_get_brand_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_brand_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,86 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_get_brand_np.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET_BRAND_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_brand_np
+.Nd retrieve the ACL brand from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_brand_np "acl_t acl" "int *brand_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_brand_np
+function
+is a non-portable call that returns the ACL brand for the ACL
+.Fa acl .
+Upon successful completion, the location referred to by the argument
+.Fa brand_p
+will be set to the ACL brand of the ACL
+.Fa acl .
+.Pp
+Branding is an internal mechanism intended to prevent mixing POSIX.1e
+and NFSv4 entries by mistake.
+It's also used by the libc to determine how to print out the ACL.
+The first call to function that is specific for one particular brand - POSIX.1e
+or NFSv4 - "brands" the ACL.
+After that, calling function specific to another brand will result in error.
+.Sh RETURN VALUES
+.Rv -std acl_get_brand_np
+.Sh ERRORS
+The
+.Fn acl_get_brand_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+.El
+.Sh SEE ALSO
+.Xr acl 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 .
+The
+.Fn acl_get_brand_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_brand_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_get_entry.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_entry.3
diff -N lib/libc/posix1e/acl_get_entry.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_entry.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,145 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_get_entry.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd April 13, 2001
+.Dt ACL_GET_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_get_entry
+.Nd retrieve an ACL entry from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_entry "acl_t acl" "int entry_id" "acl_entry_t *entry_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_entry
+function
+is a POSIX.1e call that retrieves a descriptor for an ACL entry
+specified by the argument
+.Fa entry_d
+within the ACL indicated by the argument
+.Fa acl .
+.Pp
+If the value of
+.Fa entry_id
+is
+.Dv ACL_FIRST_ENTRY ,
+then the function will return in
+.Fa entry_p
+a descriptor for the first ACL entry within
+.Fa acl .
+If a call is made to
+.Fn acl_get_entry
+with
+.Fa entry_id
+set to
+.Dv ACL_NEXT_ENTRY
+when there has not been either an initial successful call to
+.Fn acl_get_entry ,
+or a previous successful call to
+.Fn acl_create_entry ,
+.Fn acl_delete_entry ,
+.Fn acl_dup ,
+.Fn acl_from_text ,
+.Fn acl_get_fd ,
+.Fn acl_get_file ,
+.Fn acl_set_fd ,
+.Fn acl_set_file ,
+or
+.Fn acl_valid ,
+then the result is unspecified.
+.Sh RETURN VALUES
+If the
+.Fn acl_get_entry
+function successfully obtains an ACL entry, a value of 1 is returned.
+If the ACL has no ACL entries, the
+.Fn acl_get_entry
+returns a value of 0.
+If the value of
+.Fa entry_id
+is
+.Dv ACL_NEXT_ENTRY
+and the last ACL entry in the ACL has already been returned by a
+previous call to
+.Fn acl_get_entry ,
+a value of 0 will be returned until a successful call with
+.Fa entry_id
+of
+.Dv ACL_FIRST_ENTRY
+is made.
+Otherwise, a value of -1 will be returned and
+the global variable
+.Va errno
+will be set to indicate the error.
+.Sh ERRORS
+The
+.Fn acl_get_entry
+fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+Argument
+.Fa entry_id
+is neither
+.Dv ACL_FIRST_ENTRY
+nor
+.Dv ACL_NEXT_ENTRY .
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_calc_mask 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get_fd 3 ,
+.Xr acl_get_file 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set_fd 3 ,
+.Xr acl_set_file 3 ,
+.Xr acl_valid 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 .
+The
+.Fn acl_get_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_get_entry_type_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_entry_type_np.3
diff -N lib/libc/posix1e/acl_get_entry_type_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_entry_type_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,80 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_get_entry_type_np.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET_ENTRY_TYPE_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_entry_type_np
+.Nd retrieve the ACL type from an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_entry_type_np "acl_entry_t entry_d" "acl_entry_type_t *entry_type_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_entry_type_np
+function
+is a non-portable call that returns the ACL type for the NFSv4 ACL entry
+.Fa entry_d .
+Upon successful completion, the location referred to by the argument
+.Fa entry_type_p
+will be set to the ACL type of the ACL entry
+.Fa entry_d .
+.Sh RETURN VALUES
+.Rv -std acl_get_entry_type_np
+.Sh ERRORS
+The
+.Fn acl_get_entry_type_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an NFSv4 ACL entry;
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_set_entry_type_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 .
+The
+.Fn acl_get_entry_type_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry_type_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_get_flag_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_flag_np.3
diff -N lib/libc/posix1e/acl_get_flag_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_flag_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_get_flag_np.3 273853 2014-10-30 10:49:50Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL_GET_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_flag_np
+.Nd check if a flag is set in a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_get_flag_np
+function
+is a non-portable function that checks if a NFSv4 ACL flag is set in
+a flagset.
+.Sh RETURN VALUES
+If the flag in
+.Fa flag
+is set in the flagset
+.Fa flagset_d ,
+a value of
+1
+is returned, otherwise a value of
+0
+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 flag
+does not contain a valid ACL flag or argument
+.Fa flagset_d
+is not a valid ACL flagset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_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 .
+The
+.Fn acl_get_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_get_flagset_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_flagset_np.3
diff -N lib/libc/posix1e/acl_get_flagset_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_flagset_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,83 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_get_flagset_np.3 273853 2014-10-30 10:49:50Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL_GET_FLAGSET_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_flagset_np
+.Nd retrieve flagset from an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_flagset_np "acl_entry_t entry_d" "acl_flagset_t *flagset_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_flagset_np
+function
+is a non-portable call that returns via
+.Fa flagset_np_p
+a descriptor to the flagset in the NFSv4 ACL entry
+.Fa entry_d .
+Subsequent operations using the returned flagset operate
+on the flagset within the ACL entry.
+.Sh RETURN VALUES
+.Rv -std acl_get_flagset_np
+.Sh ERRORS
+The
+.Fn acl_get_flagset_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_set_flagset_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 .
+The
+.Fn acl_get_flagset_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_flagset_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_get_perm_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_perm_np.3
diff -N lib/libc/posix1e/acl_get_perm_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_perm_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_get_perm_np.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd April 10, 2001
+.Dt ACL_GET_PERM_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_perm_np
+.Nd "check if a permission is set in a permission set"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_perm_np "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_get_perm_np
+function
+is a non-portable function that checks if a permission is set in
+a permission set.
+.Sh RETURN VALUES
+If the permission in
+.Fa perm
+is set in the permission set
+.Fa permset_d ,
+a value of
+1
+is returned, otherwise a value of
+0
+is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_perm_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 perm
+does not contain a valid ACL permission or argument
+.Fa permset_d
+is not a valid ACL permset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 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 .
+The
+.Fn acl_get_perm_np
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_perm_np
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_get_permset.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_permset.3
diff -N lib/libc/posix1e/acl_get_permset.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_permset.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,83 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_get_permset.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_GET_PERMSET 3
+.Os
+.Sh NAME
+.Nm acl_get_permset
+.Nd retrieve permission set from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_permset "acl_entry_t entry_d" "acl_permset_t *permset_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_permset
+function
+is a POSIX.1e call that returns via
+.Fa permset_p
+a descriptor to the permission set in the ACL entry
+.Fa entry_d .
+Subsequent operations using the returned permission set operate
+on the permission set within the ACL entry.
+.Sh RETURN VALUES
+.Rv -std acl_get_permset
+.Sh ERRORS
+The
+.Fn acl_get_permset
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_set_permset 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 .
+The
+.Fn acl_get_permset
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_permset
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_get_qualifier.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_qualifier.3
diff -N lib/libc/posix1e/acl_get_qualifier.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_qualifier.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,140 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_get_qualifier.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 13, 2001
+.Dt ACL_GET_QUALIFIER 3
+.Os
+.Sh NAME
+.Nm acl_get_qualifier
+.Nd retrieve the qualifier from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft void *
+.Fn acl_get_qualifier "acl_entry_t entry_d"
+.Sh DESCRIPTION
+The
+.Fn acl_get_qualifier
+function
+is a POSIX.1e call that retrieves the qualifier of the tag for
+the ACL entry indicated by the argument
+.Fa entry_d
+into working storage and returns a pointer to that storage.
+.Pp
+If the value of the tag type in the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_USER ,
+then the value returned by
+.Fn acl_get_qualifier
+will be a pointer to type
+.Vt uid_t .
+.Pp
+If the value of the tag type in
+the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_GROUP ,
+then the value returned by
+.Fn acl_get_qualifier
+will be a pointer to type
+.Vt gid_t .
+.Pp
+If the value of the tag type in the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_UNDEFINED_TAG , ACL_USER_OBJ , ACL_GROUP_OBJ ,
+.Dv ACL_OTHER , ACL_MASK ,
+or an implementation-defined value for which a qualifier
+is not supported, then
+.Fn acl_get_qualifier
+will return a value of
+.Vt ( void * ) Ns Dv NULL
+and the function will fail.
+.Pp
+This function may cause memory to be allocated.
+The caller should
+free any releasable memory, when the new qualifier is no longer
+required, by calling
+.Fn acl_free
+with
+.Vt void *
+as the argument.
+.Sh RETURN VALUES
+The
+.Fn acl_get_qualifier
+function returns a pointer to the allocated storage if successful;
+otherwise a
+.Dv NULL
+pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn acl_get_qualifier
+fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+does not point to a valid descriptor for an ACL entry.
+The
+value of the tag type in the ACL entry referenced by argument
+.Fa entry_d
+is not
+.Dv ACL_USER
+or
+.Dv ACL_GROUP .
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 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 .
+The
+.Fn acl_get_qualifier
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_qualifier
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_get_tag_type.3
===================================================================
RCS file: lib/libc/posix1e/acl_get_tag_type.3
diff -N lib/libc/posix1e/acl_get_tag_type.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_get_tag_type.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_get_tag_type.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_GET_TAG_TYPE 3
+.Os
+.Sh NAME
+.Nm acl_get_tag_type
+.Nd retrieve the tag type from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_tag_type "acl_entry_t entry_d" "acl_tag_t *tag_type_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_tag_type
+function
+is a POSIX.1e call that returns the tag type for the ACL entry
+.Fa entry_d .
+Upon successful completion, the location referred to by the argument
+.Fa tag_type_p
+will be set to the tag type of the ACL entry
+.Fa entry_d .
+.Sh RETURN VALUES
+.Rv -std acl_get_tag_type
+.Sh ERRORS
+The
+.Fn acl_get_tag_type
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry;
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 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 .
+The
+.Fn acl_get_tag_type
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_tag_type
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_id_to_name.c
===================================================================
RCS file: lib/libc/posix1e/acl_id_to_name.c
diff -N lib/libc/posix1e/acl_id_to_name.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_id_to_name.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,105 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2001, 2008 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_id_to_name.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+/*
+ * Given a uid/gid, return a username/groupname for the text form of an ACL.
+ * Note that we truncate user and group names, rather than error out, as
+ * this is consistent with other tools manipulating user and group names.
+ * XXX NOT THREAD SAFE, RELIES ON GETPWUID, GETGRGID
+ * XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
+ * MAY HAVE SIDE-EFFECTS
+ */
+int
+_posix1e_acl_id_to_name(acl_tag_t tag, uid_t id, ssize_t buf_len, char *buf,
+    int flags)
+{
+	struct group	*g;
+	struct passwd	*p;
+	int	i;
+
+	switch(tag) {
+	case ACL_USER:
+		if (flags & ACL_TEXT_NUMERIC_IDS)
+			p = NULL;
+		else
+			p = getpwuid(id);
+		if (!p)
+			i = snprintf(buf, buf_len, "%d", id);
+		else
+			i = snprintf(buf, buf_len, "%s", p->pw_name);
+
+		if (i < 0) {
+			errno = ENOMEM;
+			return (-1);
+		}
+		return (0);
+
+	case ACL_GROUP:
+		if (flags & ACL_TEXT_NUMERIC_IDS)
+			g = NULL;
+		else
+			g = getgrgid(id);
+		if (g == NULL)
+			i = snprintf(buf, buf_len, "%d", id);
+		else
+			i = snprintf(buf, buf_len, "%s", g->gr_name);
+
+		if (i < 0) {
+			errno = ENOMEM;
+			return (-1);
+		}
+		return (0);
+
+	default:
+		return (EINVAL);
+	}
+}
Index: lib/libc/posix1e/acl_init.3
===================================================================
RCS file: lib/libc/posix1e/acl_init.3
diff -N lib/libc/posix1e/acl_init.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_init.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,111 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_init.3 131504 2004-07-02 23:52:20Z ru $
+.\"
+.Dd January 28, 2000
+.Dt ACL_INIT 3
+.Os
+.Sh NAME
+.Nm acl_init
+.Nd initialize ACL working storage
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_init "int count"
+.Sh DESCRIPTION
+The
+.Fn acl_init
+function allocates and initializes the working storage for an ACL of at
+least
+.Va count
+ACL entries.
+A pointer to the working storage is returned.
+The working
+storage allocated to contain the ACL is freed by a call to
+.Xr acl_free 3 .
+When the area is first allocated, it shall contain an ACL that contains
+no ACL entries.
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+working storage.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of count is less than zero.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_init.c
===================================================================
RCS file: lib/libc/posix1e/acl_init.c
diff -N lib/libc/posix1e/acl_init.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_init.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,94 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * acl_init -- return a fresh acl structure
+ * acl_dup -- duplicate an acl and return the new copy
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_init.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+__CTASSERT(1 << _ACL_T_ALIGNMENT_BITS > sizeof(struct acl_t_struct));
+
+acl_t
+acl_init(int count)
+{
+	int error;
+	acl_t acl;
+
+	if (count > ACL_MAX_ENTRIES) {
+		errno = ENOMEM;
+		return (NULL);
+	}
+	if (count < 0) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	error = posix_memalign((void *)&acl, 1 << _ACL_T_ALIGNMENT_BITS,
+	    sizeof(struct acl_t_struct));
+	if (error) {
+		errno = error;
+		return (NULL);
+	}
+
+	bzero(acl, sizeof(struct acl_t_struct));
+	acl->ats_brand = ACL_BRAND_UNKNOWN;
+	acl->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+	return (acl);
+}
+
+acl_t
+acl_dup(acl_t acl)
+{
+	acl_t	acl_new;
+
+	acl_new = acl_init(ACL_MAX_ENTRIES);
+	if (acl_new != NULL) {
+		*acl_new = *acl;
+		acl->ats_cur_entry = 0;
+		acl_new->ats_cur_entry = 0;
+	}
+
+	return (acl_new);
+}
Index: lib/libc/posix1e/acl_is_trivial_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_is_trivial_np.3
diff -N lib/libc/posix1e/acl_is_trivial_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_is_trivial_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_is_trivial_np.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd November 12, 2013
+.Dt ACL_STRIP_NP 3
+.Os
+.Sh NAME
+.Nm acl_is_trivial_np
+.Nd determine whether ACL is trivial
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_is_trivial_np "const acl_t aclp" "int *trivialp"
+.Sh DESCRIPTION
+The
+.Fn acl_is_trivial
+function determines whether the ACL pointed to by the argument
+.Va acl
+is trivial.
+Upon successful completion, the location referred to by the argument
+.Fa trivialp
+will be set to 1, if the ACL
+.Fa aclp
+points to is trivial, or 0 if it's not.
+.Pp
+ACL is trivial if it can be fully expressed as a file mode without losing
+any access rules.
+For POSIX.1e ACLs, ACL is trivial if it has the three required entries,
+one for owner, one for owning group, and one for other.
+For NFSv4 ACLs, ACL is trivial if it is identical to the ACL generated by
+.Fn acl_strip_np 3 .
+Files that have non-trivial ACL have a plus sign appended after mode bits
+in "ls -l" output.
+.Sh RETURN VALUES
+.Rv -std acl_get_tag_type
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_is_trivial_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
Index: lib/libc/posix1e/acl_perm.c
===================================================================
RCS file: lib/libc/posix1e/acl_perm.c
diff -N lib/libc/posix1e/acl_perm.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_perm.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,133 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * 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 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_perm.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <string.h>
+
+static int
+_perm_is_invalid(acl_perm_t perm)
+{
+
+	/* Check if more than a single bit is set. */
+	if ((perm & -perm) == perm &&
+	    (perm & (ACL_POSIX1E_BITS | ACL_NFS4_PERM_BITS)) == perm)
+		return (0);
+
+	errno = EINVAL;
+
+	return (1);
+}
+
+/*
+ * acl_add_perm() (23.4.1): add the permission contained in perm to the
+ * permission set permset_d
+ */
+int
+acl_add_perm(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+	if (permset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_perm_is_invalid(perm))
+		return (-1);
+
+	*permset_d |= perm;
+
+	return (0);
+}
+
+/*
+ * acl_clear_perms() (23.4.3): clear all permisions from the permission
+ * set permset_d
+ */
+int
+acl_clear_perms(acl_permset_t permset_d)
+{
+
+	if (permset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	*permset_d = ACL_PERM_NONE;
+
+	return (0);
+}
+
+/*
+ * acl_delete_perm() (23.4.10): remove the permission in perm from the
+ * permission set permset_d
+ */
+int
+acl_delete_perm(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+	if (permset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_perm_is_invalid(perm))
+		return (-1);
+
+	*permset_d &= ~perm;
+
+	return (0);
+}
+
+int
+acl_get_perm_np(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+	if (permset_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (_perm_is_invalid(perm))
+		return (-1);
+
+	if (*permset_d & perm)
+		return (1);
+
+	return (0);
+}
Index: lib/libc/posix1e/acl_set.3
===================================================================
RCS file: lib/libc/posix1e/acl_set.3
diff -N lib/libc/posix1e/acl_set.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,157 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_set.3 213573 2010-10-08 12:40:16Z uqs $
+.\"
+.Dd June 25, 2009
+.Dt ACL_SET 3
+.Os
+.Sh NAME
+.Nm acl_set_fd ,
+.Nm acl_set_fd_np ,
+.Nm acl_set_file ,
+.Nm acl_set_link_np
+.Nd set an ACL for a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_fd "int fd" "acl_t acl"
+.Ft int
+.Fn acl_set_fd_np "int fd" "acl_t acl" "acl_type_t type"
+.Ft int
+.Fn acl_set_file "const char *path_p" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_set_link_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Sh DESCRIPTION
+The
+.Fn acl_set_fd ,
+.Fn acl_set_fd_np ,
+.Fn acl_set_file ,
+and
+.Fn acl_set_link_np
+each associate an ACL with an object referred to by
+.Va fd
+or
+.Va path_p .
+The
+.Fn acl_set_fd_np
+and
+.Fn acl_set_link_np
+functions are not POSIX.1e calls.
+The
+.Fn acl_set_fd
+function allows only the setting of ACLs of type ACL_TYPE_ACCESS
+where as
+.Fn acl_set_fd_np
+allows the setting of ACLs of any type.
+The
+.Fn acl_set_link_np
+function acts on a symlink rather than its target, if the target of the
+path is a symlink.
+.Pp
+Valid values for the
+.Va type
+argument are:
+.Bl -column -offset 3n "ACL_TYPE_DEFAULT"
+.It ACL_TYPE_ACCESS	POSIX.1e access ACL
+.It ACL_TYPE_DEFAULT	POSIX.1e default ACL
+.It ACL_TYPE_NFS4	NFSv4 ACL
+.El
+.Pp
+Trying to set ACL_TYPE_NFS4 with
+.Va acl
+branded as POSIX.1e, or ACL_TYPE_ACCESS or ACL_TYPE_DEFAULT with ACL
+branded as NFSv4, will result in error.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return
+-1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL for this object, or the ACL type
+specified in
+.Va type
+is invalid for this object, or there is branding mismatch.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er ENOSPC
+The directory or file system that would contain the new ACL cannot be
+extended, or the file system is out of file allocation resources.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.It Bq Er EROFS
+This function requires modification of a file system which is currently
+read-only.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_delete 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_set.c
===================================================================
RCS file: lib/libc/posix1e/acl_set.c
diff -N lib/libc/posix1e/acl_set.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,258 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * acl_set_file -- set a file/directory ACL by name
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_set.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "acl_support.h"
+
+/*
+ * For POSIX.1e-semantic ACLs, do a presort so the kernel doesn't have to
+ * (the POSIX.1e semantic code will reject unsorted ACL submission).  If it's
+ * not a semantic that the library knows about, just submit it flat and
+ * assume the caller knows what they're up to.
+ */
+int
+acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
+{
+
+	if (acl == NULL || path_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_acl_type_not_valid_for_acl(acl, type)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	acl->ats_cur_entry = 0;
+
+	return (__acl_set_file(path_p, type, &acl->ats_acl));
+}
+
+int
+acl_set_link_np(const char *path_p, acl_type_t type, acl_t acl)
+{
+
+	if (acl == NULL || path_p == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_acl_type_not_valid_for_acl(acl, type)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	acl->ats_cur_entry = 0;
+
+	return (__acl_set_link(path_p, type, &acl->ats_acl));
+}
+
+int
+acl_set_fd(int fd, acl_t acl)
+{
+
+	if (fpathconf(fd, _PC_ACL_NFS4) == 1)
+		return (acl_set_fd_np(fd, acl, ACL_TYPE_NFS4));
+
+	return (acl_set_fd_np(fd, acl, ACL_TYPE_ACCESS));
+}
+
+int
+acl_set_fd_np(int fd, acl_t acl, acl_type_t type)
+{
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_acl_type_not_valid_for_acl(acl, type)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	acl->ats_cur_entry = 0;
+
+	return (__acl_set_fd(fd, type, &acl->ats_acl));
+}
+
+/*
+ * acl_set_permset() (23.4.23): sets the permissions of ACL entry entry_d
+ * with the permissions in permset_d
+ */
+int
+acl_set_permset(acl_entry_t entry_d, acl_permset_t permset_d)
+{
+
+	if (!entry_d) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((*permset_d & ACL_POSIX1E_BITS) != *permset_d) {
+		if ((*permset_d & ACL_NFS4_PERM_BITS) != *permset_d) {
+			errno = EINVAL;
+			return (-1);
+		}
+		if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+			errno = EINVAL;
+			return (-1);
+		}
+		_entry_brand_as(entry_d, ACL_BRAND_NFS4);
+	}
+
+	entry_d->ae_perm = *permset_d;
+
+	return (0);
+}
+
+/*
+ * acl_set_qualifier() sets the qualifier (ae_id) of the tag for
+ * ACL entry entry_d to the value referred to by tag_qualifier_p
+ */
+int
+acl_set_qualifier(acl_entry_t entry_d, const void *tag_qualifier_p)
+{
+
+	if (!entry_d || !tag_qualifier_p) {
+		errno = EINVAL;
+		return (-1);
+	}
+	switch(entry_d->ae_tag) {
+	case ACL_USER:
+	case ACL_GROUP:
+		entry_d->ae_id = *(const uid_t *)tag_qualifier_p;
+		break;
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * acl_set_tag_type() sets the tag type for ACL entry entry_d to the
+ * value of tag_type
+ */
+int
+acl_set_tag_type(acl_entry_t entry_d, acl_tag_t tag_type)
+{
+
+	if (entry_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	switch(tag_type) {
+	case ACL_OTHER:
+	case ACL_MASK:
+		if (!_entry_brand_may_be(entry_d, ACL_BRAND_POSIX)) {
+			errno = EINVAL;
+			return (-1);
+		}
+		_entry_brand_as(entry_d, ACL_BRAND_POSIX);
+		break;
+	case ACL_EVERYONE:
+		if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+			errno = EINVAL;
+			return (-1);
+		}
+		_entry_brand_as(entry_d, ACL_BRAND_NFS4);
+		break;
+	}
+
+	switch(tag_type) {
+	case ACL_USER_OBJ:
+	case ACL_USER:
+	case ACL_GROUP_OBJ:
+	case ACL_GROUP:
+	case ACL_MASK:
+	case ACL_OTHER:
+	case ACL_EVERYONE:
+		entry_d->ae_tag = tag_type;
+		return (0);
+	}
+
+	errno = EINVAL;
+	return (-1);
+}
+
+int
+acl_set_entry_type_np(acl_entry_t entry_d, acl_entry_type_t entry_type)
+{
+
+	if (entry_d == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	_entry_brand_as(entry_d, ACL_BRAND_NFS4);
+
+	switch (entry_type) {
+	case ACL_ENTRY_TYPE_ALLOW:
+	case ACL_ENTRY_TYPE_DENY:
+	case ACL_ENTRY_TYPE_AUDIT:
+	case ACL_ENTRY_TYPE_ALARM:
+		entry_d->ae_entry_type = entry_type;
+		return (0);
+	}
+
+	errno = EINVAL;
+	return (-1);
+}
Index: lib/libc/posix1e/acl_set_entry_type_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_set_entry_type_np.3
diff -N lib/libc/posix1e/acl_set_entry_type_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set_entry_type_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_set_entry_type_np.3 273853 2014-10-30 10:49:50Z trasz $
+.\"
+.Dd October 30, 2014
+.Dt ACL_SET_ENTRY_TYPE_NP 3
+.Os
+.Sh NAME
+.Nm acl_set_entry_type_np
+.Nd set NFSv4 ACL entry type
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_entry_type_np "acl_entry_t entry_d" "acl_entry_type_t entry_type"
+.Sh DESCRIPTION
+The
+.Fn acl_set_entry_type_np
+function
+is a non-portable call that sets the type of the NFSv4 ACL entry
+.Fa entry_d
+to the value referred to by
+.Fa entry_type .
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_ENTRY_TYPE_ALLOW"
+.It ACL_ENTRY_TYPE_ALLOW Ta "allow" type entry
+.It ACL_ENTRY_TYPE_DENY Ta "deny" type entry
+.El
+.Pp
+This call brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_entry_type_np
+.Sh ERRORS
+The
+.Fn acl_set_entry_type_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+The value pointed to by
+.Fa entry_type
+is not valid.
+ACL is already branded as POSIX.1e.
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_entry_type_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 .
+The
+.Fn acl_get_entry_type_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry_type_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_set_flagset_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_set_flagset_np.3
diff -N lib/libc/posix1e/acl_set_flagset_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set_flagset_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" 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: head/lib/libc/posix1e/acl_set_flagset_np.3 276006 2014-12-21 12:36:36Z brueffer $
+.\"
+.Dd October 30, 2014
+.Dt ACL_SET_FLAGSET_NP 3
+.Os
+.Sh NAME
+.Nm acl_set_flagset_np
+.Nd set the flags of an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_flagset_np "acl_entry_t entry_d" "acl_flagset_t flagset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_set_flagset_np
+function
+is a non-portable call that sets the flags of NFSv4 ACL entry
+.Fa entry_d
+with the flags contained in
+.Fa flagset_d .
+.Pp
+This call brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_flagset_np
+.Sh ERRORS
+The
+.Fn acl_set_flagset_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+ACL is already branded as POSIX.1e.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_flagset_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 .
+The
+.Fn acl_set_flagset_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_flagset_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
Index: lib/libc/posix1e/acl_set_permset.3
===================================================================
RCS file: lib/libc/posix1e/acl_set_permset.3
diff -N lib/libc/posix1e/acl_set_permset.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set_permset.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,81 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_set_permset.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_SET_PERMSET 3
+.Os
+.Sh NAME
+.Nm acl_set_permset
+.Nd set the permissions of an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_permset "acl_entry_t entry_d" "acl_permset_t permset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_set_permset
+function
+is a POSIX.1e call that sets the permissions of ACL entry
+.Fa entry_d
+with the permissions contained in
+.Fa permset_d .
+.Sh RETURN VALUES
+.Rv -std acl_set_permset
+.Sh ERRORS
+The
+.Fn acl_set_permset
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 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 .
+The
+.Fn acl_set_permset
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_permset
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_set_qualifier.3
===================================================================
RCS file: lib/libc/posix1e/acl_set_qualifier.3
diff -N lib/libc/posix1e/acl_set_qualifier.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set_qualifier.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,91 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_set_qualifier.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd March 10, 2001
+.Dt ACL_SET_QUALIFIER 3
+.Os
+.Sh NAME
+.Nm acl_set_qualifier
+.Nd set ACL tag qualifier
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_qualifier "acl_entry_t entry_d" "const void *tag_qualifier_p"
+.Sh DESCRIPTION
+The
+.Fn acl_set_qualifier
+function
+is a POSIX.1e call that sets the qualifier of the tag for the ACL entry
+.Fa entry_d
+to the value referred to by
+.Fa tag_qualifier_p .
+.Sh RETURN VALUES
+.Rv -std acl_set_qualifier
+.Sh ERRORS
+The
+.Fn acl_set_qualifier
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+The tag type of the
+ACL entry
+.Fa entry_d
+is not
+.Dv ACL_USER
+or
+.Dv ACL_GROUP .
+The value pointed to by
+.Fa tag_qualifier_p
+is not valid.
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_qualifier 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 .
+The
+.Fn acl_get_qualifier
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_qualifier
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_set_tag_type.3
===================================================================
RCS file: lib/libc/posix1e/acl_set_tag_type.3
diff -N lib/libc/posix1e/acl_set_tag_type.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_set_tag_type.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,102 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" 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 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: head/lib/libc/posix1e/acl_set_tag_type.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_SET_TAG_TYPE 3
+.Os
+.Sh NAME
+.Nm acl_set_tag_type
+.Nd set the tag type of an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_tag_type "acl_entry_t entry_d" "acl_tag_t tag_type"
+.Sh DESCRIPTION
+The
+.Fn acl_set_tag_type
+function
+is a POSIX.1e call that sets the ACL tag type of ACL entry
+.Fa entry_d
+to the value of
+.Fa tag_type .
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_OTHER_OBJ"
+.It ACL_USER_OBJ Ta "Permissions apply to file owner"
+.It ACL_USER Ta "Permissions apply to additional user specified by qualifier"
+.It ACL_GROUP_OBJ Ta "Permissions apply to file group"
+.It ACL_GROUP Ta "Permissions apply to additional group specified by qualifier"
+.It ACL_MASK Ta "Permissions specify mask"
+.It ACL_OTHER Ta Permissions apply to "other"
+.It ACL_OTHER_OBJ Ta "Same as ACL_OTHER"
+.It ACL_EVERYONE Ta Permissions apply to "everyone@"
+.El
+.Pp
+Calling
+.Fn acl_set_tag_type
+with
+.Fa tag_type
+equal to ACL_MASK, ACL_OTHER or ACL_OTHER_OBJ brands the ACL as POSIX.1e.
+Calling it with ACL_EVERYONE brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_tag_type
+.Sh ERRORS
+The
+.Fn acl_set_tag_type
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+Argument
+.Fa tag_type
+is not a valid ACL tag type.
+ACL is already branded differently.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_tag_type 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 .
+The
+.Fn acl_set_tag_type
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_tag_type
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
Index: lib/libc/posix1e/acl_strip.c
===================================================================
RCS file: lib/libc/posix1e/acl_strip.c
diff -N lib/libc/posix1e/acl_strip.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_strip.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,222 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * 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>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_strip.c 344294 2019-02-19 19:15:15Z sef $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include "acl_support.h"
+
+static acl_t
+_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
+{
+	acl_t newacl;
+	mode_t mode = 0;
+
+	newacl = acl_init(ACL_MAX_ENTRIES);
+	if (newacl == NULL) {
+		errno = ENOMEM;
+		return (NULL);
+	}
+
+	_acl_brand_as(newacl, ACL_BRAND_NFS4);
+
+	__acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
+	__acl_nfs4_trivial_from_mode_libc(&(newacl->ats_acl), mode, canonical_six);
+
+	return (newacl);
+}
+
+static acl_t
+_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
+{
+	acl_t acl_new, acl_old;
+	acl_entry_t entry, entry_new;
+	acl_tag_t tag;
+	int entry_id, have_mask_entry;
+
+	assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
+
+	acl_old = acl_dup(aclp);
+	if (acl_old == NULL)
+		return (NULL);
+
+	assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
+
+	have_mask_entry = 0;
+	acl_new = acl_init(ACL_MAX_ENTRIES);
+	if (acl_new == NULL) {
+		acl_free(acl_old);
+		return (NULL);
+	}
+	tag = ACL_UNDEFINED_TAG;
+
+	/* only save the default user/group/other entries */
+	entry_id = ACL_FIRST_ENTRY;
+	while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+
+		assert(_entry_brand(entry) == ACL_BRAND_POSIX);
+
+		if (acl_get_tag_type(entry, &tag) == -1)
+			goto fail;
+
+		switch(tag) {
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_OTHER:
+			if (acl_create_entry(&acl_new, &entry_new) == -1)
+				goto fail;
+			if (acl_copy_entry(entry_new, entry) == -1)
+				goto fail;
+			assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
+			break;
+		case ACL_MASK:
+			have_mask_entry = 1;
+			break;
+		default:
+			break;
+		}
+	}
+
+	assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
+
+	if (have_mask_entry && recalculate_mask) {
+		if (acl_calc_mask(&acl_new) == -1)
+			goto fail;
+	}
+
+	return (acl_new);
+
+fail:
+	acl_free(acl_new);
+	acl_free(acl_old);
+
+	return (NULL);
+}
+
+acl_t
+acl_strip_np(const acl_t aclp, int recalculate_mask)
+{
+	switch (_acl_brand(aclp)) {
+	case ACL_BRAND_NFS4:
+		return (_nfs4_acl_strip_np(aclp, 0));
+
+	case ACL_BRAND_POSIX:
+		return (_posix1e_acl_strip_np(aclp, recalculate_mask));
+
+	default:
+		errno = EINVAL;
+		return (NULL);
+	}
+}
+
+/*
+ * Return 1, if ACL is trivial, 0 otherwise.
+ *
+ * ACL is trivial, iff its meaning could be fully expressed using just file
+ * mode.  In other words, ACL is trivial iff it doesn't have "+" to the right
+ * of the mode bits in "ls -l" output ;-)
+ */
+int
+acl_is_trivial_np(const acl_t aclp, int *trivialp)
+{
+	acl_t tmpacl;
+	int differs;
+
+	if (aclp == NULL || trivialp == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	switch (_acl_brand(aclp)) {
+	case ACL_BRAND_POSIX:
+		if (aclp->ats_acl.acl_cnt == 3)
+			*trivialp = 1;
+		else
+			*trivialp = 0;
+
+		return (0);
+
+	case ACL_BRAND_NFS4:
+		/*
+		 * If the ACL has more than canonical six entries,
+		 * it's non trivial by definition.
+		 */
+		if (aclp->ats_acl.acl_cnt > 6) {
+			*trivialp = 0;
+			return (0);
+		}
+			
+		/*
+		 * Calculate trivial ACL - using acl_strip_np(3) - and compare
+		 * with the original.
+		 */
+		tmpacl = _nfs4_acl_strip_np(aclp, 0);
+		if (tmpacl == NULL)
+			return (-1);
+
+		differs = _acl_differs(aclp, tmpacl);
+		acl_free(tmpacl);
+
+		if (differs == 0) {
+			*trivialp = 1;
+			return (0);
+		}
+
+		/*
+		 * Try again with an old-style, "canonical six" trivial ACL.
+		 */
+		tmpacl = _nfs4_acl_strip_np(aclp, 1);
+		if (tmpacl == NULL)
+			return (-1);
+
+		differs = _acl_differs(aclp, tmpacl);
+		acl_free(tmpacl);
+
+		if (differs)
+			*trivialp = 0;
+		else
+			*trivialp = 1;
+
+		return (0);
+
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+}
Index: lib/libc/posix1e/acl_strip_np.3
===================================================================
RCS file: lib/libc/posix1e/acl_strip_np.3
diff -N lib/libc/posix1e/acl_strip_np.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_strip_np.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,109 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_strip_np.3 267774 2014-06-23 08:25:03Z bapt $
+.\"
+.Dd June 25, 2009
+.Dt ACL_STRIP_NP 3
+.Os
+.Sh NAME
+.Nm acl_strip_np
+.Nd strip extended entries from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_strip_np "const acl_t acl" "int recalculate_mask"
+.Sh DESCRIPTION
+The
+.Fn acl_strip_np
+function returns a pointer to a trivial ACL computed from the ACL pointed
+to by the argument
+.Va acl .
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Pp
+Any existing ACL pointers that refer to the ACL referred to by
+.Va acl
+shall continue to refer to the ACL.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+newly allocated ACL.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_is_trivial_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_strip_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
Index: lib/libc/posix1e/acl_support.c
===================================================================
RCS file: lib/libc/posix1e/acl_support.c
diff -N lib/libc/posix1e/acl_support.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_support.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,423 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2001, 2008 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+#define ACL_STRING_PERM_WRITE   'w'
+#define ACL_STRING_PERM_READ    'r'
+#define ACL_STRING_PERM_EXEC    'x'
+#define ACL_STRING_PERM_NONE    '-'
+
+/*
+ * Return 0, if both ACLs are identical.
+ */
+int
+_acl_differs(const acl_t a, const acl_t b)
+{
+	size_t i;
+	struct acl_entry *entrya, *entryb;
+
+	assert(_acl_brand(a) == _acl_brand(b));
+	assert(_acl_brand(a) != ACL_BRAND_UNKNOWN);
+	assert(_acl_brand(b) != ACL_BRAND_UNKNOWN);
+
+	if (a->ats_acl.acl_cnt != b->ats_acl.acl_cnt)
+		return (1);
+
+	for (i = 0; i < b->ats_acl.acl_cnt; i++) {
+		entrya = &(a->ats_acl.acl_entry[i]);
+		entryb = &(b->ats_acl.acl_entry[i]);
+
+		if (entrya->ae_tag != entryb->ae_tag ||
+		    entrya->ae_id != entryb->ae_id ||
+		    entrya->ae_perm != entryb->ae_perm ||
+		    entrya->ae_entry_type != entryb->ae_entry_type ||
+		    entrya->ae_flags != entryb->ae_flags)
+			return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * _posix1e_acl_entry_compare -- compare two acl_entry structures to
+ * determine the order they should appear in.  Used by _posix1e_acl_sort to
+ * sort ACL entries into the kernel-desired order -- i.e., the order useful
+ * for evaluation and O(n) validity checking.  Beter to have an O(nlogn) sort
+ * in userland and an O(n) in kernel than to have both in kernel.
+ */
+typedef int (*compare)(const void *, const void *);
+static int
+_posix1e_acl_entry_compare(struct acl_entry *a, struct acl_entry *b)
+{
+
+	assert(_entry_brand(a) == ACL_BRAND_POSIX);
+	assert(_entry_brand(b) == ACL_BRAND_POSIX);
+
+	/*
+	 * First, sort between tags -- conveniently defined in the correct
+	 * order for verification.
+	 */
+	if (a->ae_tag < b->ae_tag)
+		return (-1);
+	if (a->ae_tag > b->ae_tag)
+		return (1);
+
+	/*
+	 * Next compare uids/gids on appropriate types.
+	 */
+
+	if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
+		if (a->ae_id < b->ae_id)
+			return (-1);
+		if (a->ae_id > b->ae_id)
+			return (1);
+
+		/* shouldn't be equal, fall through to the invalid case */
+	}
+
+	/*
+	 * Don't know how to sort multiple entries of the rest--either it's
+	 * a bad entry, or there shouldn't be more than one.  Ignore and the
+	 * validity checker can get it later.
+	 */
+	return (0);
+}
+
+/*
+ * _posix1e_acl_sort -- sort ACL entries in POSIX.1e-formatted ACLs.
+ */
+void
+_posix1e_acl_sort(acl_t acl)
+{
+	struct acl *acl_int;
+
+	acl_int = &acl->ats_acl;
+
+	qsort(&acl_int->acl_entry[0], acl_int->acl_cnt,
+	    sizeof(struct acl_entry), (compare) _posix1e_acl_entry_compare);
+}
+
+/*
+ * acl_posix1e -- in what situations should we acl_sort before submission?
+ * We apply posix1e ACL semantics for any ACL of type ACL_TYPE_ACCESS or
+ * ACL_TYPE_DEFAULT
+ */
+int
+_posix1e_acl(acl_t acl, acl_type_t type)
+{
+
+	if (_acl_brand(acl) != ACL_BRAND_POSIX)
+		return (0);
+
+	return ((type == ACL_TYPE_ACCESS) || (type == ACL_TYPE_DEFAULT));
+}
+
+/*
+ * _posix1e_acl_check -- given an ACL, check its validity.  This is mirrored
+ * from code in sys/kern/kern_acl.c, and if changes are made in one, they
+ * should be made in the other also.  This copy of acl_check is made
+ * available * in userland for the benefit of processes wanting to check ACLs
+ * for validity before submitting them to the kernel, or for performing
+ * in userland file system checking.  Needless to say, the kernel makes
+ * the real checks on calls to get/setacl.
+ *
+ * See the comments in kernel for explanation -- just briefly, it assumes
+ * an already sorted ACL, and checks based on that assumption.  The
+ * POSIX.1e interface, acl_valid(), will perform the sort before calling
+ * this.  Returns 0 on success, EINVAL on failure.
+ */
+int
+_posix1e_acl_check(acl_t acl)
+{
+	struct acl *acl_int;
+	struct acl_entry	*entry; 	/* current entry */
+	uid_t	highest_uid=0, highest_gid=0;
+	int	stage = ACL_USER_OBJ;
+	size_t	i = 0;
+	int	count_user_obj=0, count_user=0, count_group_obj=0,
+		count_group=0, count_mask=0, count_other=0;
+
+	acl_int = &acl->ats_acl;
+
+	/* printf("_posix1e_acl_check: checking acl with %d entries\n",
+	    acl->acl_cnt); */
+	while (i < acl_int->acl_cnt) {
+		entry = &acl_int->acl_entry[i];
+
+		if ((entry->ae_perm | ACL_PERM_BITS) != ACL_PERM_BITS)
+			return (EINVAL);
+
+		switch(entry->ae_tag) {
+		case ACL_USER_OBJ:
+			/* printf("_posix1e_acl_check: %d: ACL_USER_OBJ\n",
+			    i); */
+			if (stage > ACL_USER_OBJ)
+				return (EINVAL);
+			stage = ACL_USER;
+			count_user_obj++;
+			break;
+
+		case ACL_USER:
+			/* printf("_posix1e_acl_check: %d: ACL_USER\n", i); */
+			if (stage > ACL_USER)
+				return (EINVAL);
+			stage = ACL_USER;
+			if (count_user && (entry->ae_id <= highest_uid))
+				return (EINVAL);
+			highest_uid = entry->ae_id;
+			count_user++;
+			break;
+
+		case ACL_GROUP_OBJ:
+			/* printf("_posix1e_acl_check: %d: ACL_GROUP_OBJ\n",
+			    i); */
+			if (stage > ACL_GROUP_OBJ)
+				return (EINVAL);
+			stage = ACL_GROUP;
+			count_group_obj++;
+			break;
+
+		case ACL_GROUP:
+			/* printf("_posix1e_acl_check: %d: ACL_GROUP\n", i); */
+			if (stage > ACL_GROUP)
+				return (EINVAL);
+			stage = ACL_GROUP;
+			if (count_group && (entry->ae_id <= highest_gid))
+				return (EINVAL);
+			highest_gid = entry->ae_id;
+			count_group++;
+			break;
+
+		case ACL_MASK:
+			/* printf("_posix1e_acl_check: %d: ACL_MASK\n", i); */
+			if (stage > ACL_MASK)
+				return (EINVAL);
+			stage = ACL_MASK;
+			count_mask++;
+			break;
+
+		case ACL_OTHER:
+			/* printf("_posix1e_acl_check: %d: ACL_OTHER\n", i); */
+			if (stage > ACL_OTHER)
+				return (EINVAL);
+			stage = ACL_OTHER;
+			count_other++;
+			break;
+
+		default:
+			/* printf("_posix1e_acl_check: %d: INVALID\n", i); */
+			return (EINVAL);
+		}
+		i++;
+	}
+
+	if (count_user_obj != 1)
+		return (EINVAL);
+
+	if (count_group_obj != 1)
+		return (EINVAL);
+
+	if (count_mask != 0 && count_mask != 1)
+		return (EINVAL);
+
+	if (count_other != 1)
+		return (EINVAL);
+
+	return (0);
+}
+
+/*
+ * Given a right-shifted permission (i.e., direct ACL_PERM_* mask), fill
+ * in a string describing the permissions.
+ */
+int
+_posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len, char *buf)
+{
+
+	if (buf_len < _POSIX1E_ACL_STRING_PERM_MAXSIZE + 1) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	if ((perm | ACL_PERM_BITS) != ACL_PERM_BITS) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	buf[3] = 0;	/* null terminate */
+
+	if (perm & ACL_READ)
+		buf[0] = ACL_STRING_PERM_READ;
+	else
+		buf[0] = ACL_STRING_PERM_NONE;
+
+	if (perm & ACL_WRITE)
+		buf[1] = ACL_STRING_PERM_WRITE;
+	else
+		buf[1] = ACL_STRING_PERM_NONE;
+
+	if (perm & ACL_EXECUTE)
+		buf[2] = ACL_STRING_PERM_EXEC;
+	else
+		buf[2] = ACL_STRING_PERM_NONE;
+
+	return (0);
+}
+
+/*
+ * given a string, return a permission describing it
+ */
+int
+_posix1e_acl_string_to_perm(char *string, acl_perm_t *perm)
+{
+	acl_perm_t	myperm = ACL_PERM_NONE;
+	char	*ch;
+
+	ch = string;
+	while (*ch) {
+		switch(*ch) {
+		case ACL_STRING_PERM_READ:
+			myperm |= ACL_READ;
+			break;
+		case ACL_STRING_PERM_WRITE:
+			myperm |= ACL_WRITE;
+			break;
+		case ACL_STRING_PERM_EXEC:
+			myperm |= ACL_EXECUTE;
+			break;
+		case ACL_STRING_PERM_NONE:
+			break;
+		default:
+			return (EINVAL);
+		}
+		ch++;
+	}
+
+	*perm = myperm;
+	return (0);
+}
+
+/*
+ * Add an ACL entry without doing much checking, et al
+ */
+int
+_posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id, acl_perm_t perm)
+{
+	struct acl		*acl_int;
+	struct acl_entry	*e;
+
+	acl_int = &acl->ats_acl;
+
+	if (acl_int->acl_cnt >= ACL_MAX_ENTRIES) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	e = &(acl_int->acl_entry[acl_int->acl_cnt]);
+	e->ae_perm = perm;
+	e->ae_tag = tag;
+	e->ae_id = id;
+	acl_int->acl_cnt++;
+
+	return (0);
+}
+
+/*
+ * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
+ * counterpart.  It's necessary for the old (pre-NFSv4 ACLs) binaries
+ * to work with new libc and kernel.  Fixing 'type' for old binaries with
+ * old libc and new kernel is being done by kern/vfs_acl.c:type_unold().
+ */
+int
+_acl_type_unold(acl_type_t type)
+{
+
+	switch (type) {
+	case ACL_TYPE_ACCESS_OLD:
+		return (ACL_TYPE_ACCESS);
+	case ACL_TYPE_DEFAULT_OLD:
+		return (ACL_TYPE_DEFAULT);
+	default:
+		return (type);
+	}
+}
+
+char *
+string_skip_whitespace(char *string)
+{
+
+	while (*string && ((*string == ' ') || (*string == '\t')))
+		string++;
+
+	return (string);
+}
+
+void
+string_trim_trailing_whitespace(char *string)
+{
+	char	*end;
+
+	if (*string == '\0')
+		return;
+
+	end = string + strlen(string) - 1;
+
+	while (end != string) {
+		if ((*end == ' ') || (*end == '\t')) {
+			*end = '\0';
+			end--;
+		} else {
+			return;
+		}
+	}
+
+	return;
+}
Index: lib/libc/posix1e/acl_support.h
===================================================================
RCS file: lib/libc/posix1e/acl_support.h
diff -N lib/libc/posix1e/acl_support.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_support.h	15 May 2020 16:56:51 -0000
@@ -0,0 +1,70 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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: head/lib/libc/posix1e/acl_support.h 326193 2017-11-25 17:12:48Z pfg $
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+#ifndef _ACL_SUPPORT_H
+#define _ACL_SUPPORT_H
+
+#define _POSIX1E_ACL_STRING_PERM_MAXSIZE 3       /* read, write, exec */
+#define _ACL_T_ALIGNMENT_BITS		13
+
+int	_acl_type_unold(acl_type_t type);
+int	_acl_differs(const acl_t a, const acl_t b);
+int	_acl_type_not_valid_for_acl(const acl_t acl, acl_type_t type);
+void	_acl_brand_from_type(acl_t acl, acl_type_t type);
+int	_acl_brand(const acl_t acl);
+int	_entry_brand(const acl_entry_t entry);
+int	_acl_brand_may_be(const acl_t acl, int brand);
+int	_entry_brand_may_be(const acl_entry_t entry, int brand);
+void	_acl_brand_as(acl_t acl, int brand);
+void	_entry_brand_as(const acl_entry_t entry, int brand);
+int	_nfs4_acl_entry_from_text(acl_t, char *);
+char	*_nfs4_acl_to_text_np(const acl_t, ssize_t *, int);
+int	_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose);
+int	_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose);
+int	_nfs4_parse_flags(const char *str, acl_flag_t *var);
+int	_nfs4_parse_access_mask(const char *str, acl_perm_t *var);
+int	_posix1e_acl_check(acl_t acl);
+void	_posix1e_acl_sort(acl_t acl);
+int	_posix1e_acl(acl_t acl, acl_type_t type);
+int	_posix1e_acl_id_to_name(acl_tag_t tag, uid_t id, ssize_t buf_len,
+	    char *buf, int flags);
+int	_posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len,
+	    char *buf);
+int	_posix1e_acl_string_to_perm(char *string, acl_perm_t *perm);
+int	_posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id,
+	    acl_perm_t perm);
+char	*string_skip_whitespace(char *string);
+void	string_trim_trailing_whitespace(char *string);
+int	_acl_name_to_id(acl_tag_t tag, char *name, uid_t *id);
+
+#endif
Index: lib/libc/posix1e/acl_support_nfs4.c
===================================================================
RCS file: lib/libc/posix1e/acl_support_nfs4.c
diff -N lib/libc/posix1e/acl_support_nfs4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_support_nfs4.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,267 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_support_nfs4.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <err.h>
+#include <sys/acl.h>
+#include "acl_support.h"
+
+struct flagnames_struct {
+	uint32_t	flag;
+	const char	*name;
+	char		letter;
+};
+
+struct flagnames_struct a_flags[] =
+    {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
+     { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
+     { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
+     { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
+     { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
+     { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
+     { ACL_ENTRY_INHERITED, "inherited", 'I' },
+     /*
+      * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
+      * in the "flags" field.  There is no ACE_OWNER, ACE_GROUP or
+      * ACE_EVERYONE either, for obvious reasons.
+      */
+     { 0, 0, 0}};
+
+struct flagnames_struct a_access_masks[] =
+    {{ ACL_READ_DATA, "read_data", 'r'},
+     { ACL_WRITE_DATA, "write_data", 'w'},
+     { ACL_EXECUTE, "execute", 'x'},
+     { ACL_APPEND_DATA, "append_data", 'p'},
+     { ACL_DELETE_CHILD, "delete_child", 'D'},
+     { ACL_DELETE, "delete", 'd'},
+     { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
+     { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
+     { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
+     { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
+     { ACL_READ_ACL, "read_acl", 'c'},
+     { ACL_WRITE_ACL, "write_acl", 'C'},
+     { ACL_WRITE_OWNER, "write_owner", 'o'},
+     { ACL_SYNCHRONIZE, "synchronize", 's'},
+     { ACL_FULL_SET, "full_set", '\0'},
+     { ACL_MODIFY_SET, "modify_set", '\0'},
+     { ACL_READ_SET, "read_set", '\0'},
+     { ACL_WRITE_SET, "write_set", '\0'},
+     { 0, 0, 0}};
+
+static const char *
+format_flag(uint32_t *var, const struct flagnames_struct *flags)
+{
+
+	for (; flags->name != NULL; flags++) {
+		if ((flags->flag & *var) == 0)
+			continue;
+
+		*var &= ~flags->flag;
+		return (flags->name);
+	}
+
+	return (NULL);
+}
+
+static int
+format_flags_verbose(char *str, size_t size, uint32_t var,
+    const struct flagnames_struct *flags)
+{
+	size_t off = 0;
+	const char *tmp;
+
+	while ((tmp = format_flag(&var, flags)) != NULL) {
+		off += snprintf(str + off, size - off, "%s/", tmp);
+		assert (off < size);
+	}
+
+	/* If there were any flags added... */
+	if (off > 0) {
+		off--;
+		/* ... then remove the last slash. */
+		assert(str[off] == '/');
+	} 
+
+	str[off] = '\0';
+
+	return (0);
+}
+
+static int
+format_flags_compact(char *str, size_t size, uint32_t var,
+    const struct flagnames_struct *flags)
+{
+	size_t i;
+
+	for (i = 0; flags[i].letter != '\0'; i++) {
+		assert(i < size);
+		if ((flags[i].flag & var) == 0)
+			str[i] = '-';
+		else
+			str[i] = flags[i].letter;
+	}
+
+	str[i] = '\0';
+
+	return (0);
+}
+
+static int
+parse_flags_verbose(const char *strp, uint32_t *var,
+    const struct flagnames_struct *flags, const char *flags_name,
+    int *try_compact)
+{
+	int i, found, ever_found = 0;
+	char *str, *flag;
+
+	str = strdup(strp);
+	*try_compact = 0;
+	*var = 0;
+
+	while (str != NULL) {
+		flag = strsep(&str, "/:");
+
+		found = 0;
+		for (i = 0; flags[i].name != NULL; i++) {
+			if (strcmp(flags[i].name, flag) == 0) {
+				*var |= flags[i].flag;
+				found = 1;
+				ever_found = 1;
+			}
+		}
+
+		if (!found) {
+			if (ever_found)
+				warnx("malformed ACL: \"%s\" field contains "
+				    "invalid flag \"%s\"", flags_name, flag);
+			else
+				*try_compact = 1;
+			free(str);
+			return (-1);
+		}
+	}
+
+	free(str);
+	return (0);
+}
+
+static int
+parse_flags_compact(const char *str, uint32_t *var,
+    const struct flagnames_struct *flags, const char *flags_name)
+{
+	int i, j, found;
+
+	*var = 0;
+
+	for (i = 0;; i++) {
+		if (str[i] == '\0')
+			return (0);
+
+		/* Ignore minus signs. */
+		if (str[i] == '-')
+			continue;
+
+		found = 0;
+
+		for (j = 0; flags[j].name != NULL; j++) {
+			if (flags[j].letter == str[i]) {
+				*var |= flags[j].flag;
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			warnx("malformed ACL: \"%s\" field contains "
+			    "invalid flag \"%c\"", flags_name, str[i]);
+			return (-1);
+		}
+	}
+}
+
+int
+_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
+{
+
+	if (verbose)
+		return (format_flags_verbose(str, size, var, a_flags));
+
+	return (format_flags_compact(str, size, var, a_flags));
+}
+
+int
+_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
+{
+
+	if (verbose)
+		return (format_flags_verbose(str, size, var, a_access_masks));
+
+	return (format_flags_compact(str, size, var, a_access_masks));
+}
+
+int
+_nfs4_parse_flags(const char *str, acl_flag_t *flags)
+{
+	int error, try_compact;
+	unsigned int tmpflags;
+
+	error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
+	if (error && try_compact)
+		error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
+
+	*flags = tmpflags;
+
+	return (error);
+}
+
+int
+_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
+{
+	int error, try_compact;
+	unsigned int tmpperms;
+
+	error = parse_flags_verbose(str, &tmpperms, a_access_masks,
+	    "access permissions", &try_compact);
+	if (error && try_compact)
+		error = parse_flags_compact(str, &tmpperms,
+		    a_access_masks, "access permissions");
+
+	*perms = tmpperms;
+
+	return (error);
+}
Index: lib/libc/posix1e/acl_to_text.3
===================================================================
RCS file: lib/libc/posix1e/acl_to_text.3
diff -N lib/libc/posix1e/acl_to_text.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_to_text.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,159 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_to_text.3 318709 2017-05-23 07:12:31Z ngie $
+.\"
+.Dd June 25, 2009
+.Dt ACL_TO_TEXT 3
+.Os
+.Sh NAME
+.Nm acl_to_text ,
+.Nm acl_to_text_np
+.Nd convert an ACL to text
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft char *
+.Fn acl_to_text "acl_t acl" "ssize_t *len_p"
+.Ft char *
+.Fn acl_to_text_np "acl_t acl" "ssize_t *len_p" "int flags"
+.Sh DESCRIPTION
+The
+.Fn acl_to_text
+and
+.Fn acl_to_text_np
+functions translate the ACL pointed to by argument
+.Va acl
+into a NULL terminated character string.
+If the pointer
+.Va len_p
+is not NULL, then the function shall return the length of the string (not
+including the NULL terminator) in the location pointed to by
+.Va len_p .
+If the ACL is POSIX.1e, the format of the text string returned by
+.Fn acl_to_text
+shall be the POSIX.1e long ACL form.
+If the ACL is NFSv4, the format of the text string shall be the compact form, unless
+the
+.Va ACL_TEXT_VERBOSE
+flag is given.
+.Pp
+The flags specified are formed by
+.Em or Ns 'ing
+the following values
+.Bl -column -offset 3n "ACL_TEXT_NUMERIC_IDS"
+.It ACL_TEXT_VERBOSE Ta "Format ACL using verbose form"
+.It ACL_TEXT_NUMERIC_IDS Ta "Do not resolve IDs into user or group names"
+.It ACL_TEXT_APPEND_ID Ta "In addition to user and group names, append numeric IDs"
+.El
+.Pp
+This function allocates any memory necessary to contain the string and
+returns a pointer to the string.
+The caller should free any releasable
+memory, when the new string is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)char
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the
+long text form of an ACL.
+Otherwise, a value of
+.Va (char*)NULL
+shall be returned and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_to_text
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.Pp
+The ACL denoted by
+.Va acl
+contains one or more improperly formed ACL entries, or for some other
+reason cannot be translated into a text form of an ACL.
+.It Bq Er ENOMEM
+The character string to be returned requires more memory than is allowed
+by the hardware or software-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_from_text 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
+.Sh BUGS
+The
+.Fn acl_from_text
+and
+.Fn acl_to_text
+functions
+rely on the
+.Xr getpwent 3
+library calls to manage username and uid mapping, as well as the
+.Xr getgrent 3
+library calls to manage groupname and gid mapping.
+These calls are not
+thread safe, and so transitively, neither are
+.Fn acl_from_text
+and
+.Fn acl_to_text .
+These functions may also interfere with stateful
+calls associated with the
+.Fn getpwent
+and
+.Fn getgrent
+calls.
Index: lib/libc/posix1e/acl_to_text.c
===================================================================
RCS file: lib/libc/posix1e/acl_to_text.c
diff -N lib/libc/posix1e/acl_to_text.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_to_text.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,267 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * acl_to_text - return a text string with a text representation of the acl
+ * in it.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_to_text.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_to_text - generate a text form of an acl
+ * spec says nothing about output ordering, so leave in acl order
+ *
+ * This function will not produce nice results if it is called with
+ * a non-POSIX.1e semantics ACL.
+ */
+
+char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags);
+
+static char *
+_posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags)
+{
+	struct acl	*acl_int;
+	char		*buf, *tmpbuf;
+	char		 name_buf[MAXLOGNAME];
+	char		 perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1],
+			 effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1];
+	size_t		 i;
+	int		 error, len;
+	uid_t		 ae_id;
+	acl_tag_t	 ae_tag;
+	acl_perm_t	 ae_perm, effective_perm, mask_perm;
+
+	buf = strdup("");
+	if (buf == NULL)
+		return(NULL);
+
+	acl_int = &acl->ats_acl;
+
+	mask_perm = ACL_PERM_BITS;	/* effective is regular if no mask */
+	for (i = 0; i < acl_int->acl_cnt; i++)
+		if (acl_int->acl_entry[i].ae_tag == ACL_MASK) 
+			mask_perm = acl_int->acl_entry[i].ae_perm;
+
+	for (i = 0; i < acl_int->acl_cnt; i++) {
+		ae_tag = acl_int->acl_entry[i].ae_tag;
+		ae_id = acl_int->acl_entry[i].ae_id;
+		ae_perm = acl_int->acl_entry[i].ae_perm;
+
+		switch(ae_tag) {
+		case ACL_USER_OBJ:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+			len = asprintf(&tmpbuf, "%suser::%s\n", buf,
+			    perm_buf);
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		case ACL_USER:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+
+			error = _posix1e_acl_id_to_name(ae_tag, ae_id,
+			    MAXLOGNAME, name_buf, flags);
+			if (error)
+				goto error_label;
+
+			effective_perm = ae_perm & mask_perm;
+			if (effective_perm != ae_perm) {
+				error = _posix1e_acl_perm_to_string(
+				    effective_perm,
+				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+				    effective_perm_buf);
+				if (error)
+					goto error_label;
+				len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# "
+				    "effective: %s\n",
+				    buf, name_buf, perm_buf,
+				    effective_perm_buf);
+			} else {
+				len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf,
+				    name_buf, perm_buf);
+			}
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		case ACL_GROUP_OBJ:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+
+			effective_perm = ae_perm & mask_perm;
+			if (effective_perm != ae_perm) {
+				error = _posix1e_acl_perm_to_string(
+				    effective_perm,
+				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+				    effective_perm_buf);
+				if (error)
+					goto error_label;
+				len = asprintf(&tmpbuf, "%sgroup::%s\t\t# "
+				    "effective: %s\n",
+				    buf, perm_buf, effective_perm_buf);
+			} else {
+				len = asprintf(&tmpbuf, "%sgroup::%s\n", buf,
+				    perm_buf);
+			}
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		case ACL_GROUP:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+
+			error = _posix1e_acl_id_to_name(ae_tag, ae_id,
+			    MAXLOGNAME, name_buf, flags);
+			if (error)
+				goto error_label;
+
+			effective_perm = ae_perm & mask_perm;
+			if (effective_perm != ae_perm) {
+				error = _posix1e_acl_perm_to_string(
+				    effective_perm,
+				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+				    effective_perm_buf);
+				if (error)
+					goto error_label;
+				len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# "
+				    "effective: %s\n",
+				    buf, name_buf, perm_buf,
+				    effective_perm_buf);
+			} else {
+				len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf,
+				    name_buf, perm_buf);
+			}
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		case ACL_MASK:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+
+			len = asprintf(&tmpbuf, "%smask::%s\n", buf,
+			    perm_buf);
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		case ACL_OTHER:
+			error = _posix1e_acl_perm_to_string(ae_perm,
+			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+			if (error)
+				goto error_label;
+
+			len = asprintf(&tmpbuf, "%sother::%s\n", buf,
+			    perm_buf);
+			if (len == -1)
+				goto error_label;
+			free(buf);
+			buf = tmpbuf;
+			break;
+
+		default:
+			errno = EINVAL;
+			goto error_label;
+		}
+	}
+
+	if (len_p) {
+		*len_p = strlen(buf);
+	}
+	return (buf);
+
+error_label:
+	/* jump to here sets errno already, we just clean up */
+	if (buf) free(buf);
+	return (NULL);
+}
+
+char *
+acl_to_text_np(acl_t acl, ssize_t *len_p, int flags)
+{
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return(NULL);
+	}
+
+	switch (_acl_brand(acl)) {
+	case ACL_BRAND_POSIX:
+		return (_posix1e_acl_to_text(acl, len_p, flags));
+	case ACL_BRAND_NFS4:
+		return (_nfs4_acl_to_text_np(acl, len_p, flags));
+	default:
+		errno = EINVAL;
+		return (NULL);
+	}
+}
+
+char *
+acl_to_text(acl_t acl, ssize_t *len_p)
+{
+
+	return (acl_to_text_np(acl, len_p, 0));
+}
Index: lib/libc/posix1e/acl_to_text_nfs4.c
===================================================================
RCS file: lib/libc/posix1e/acl_to_text_nfs4.c
diff -N lib/libc/posix1e/acl_to_text_nfs4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_to_text_nfs4.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,271 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_to_text_nfs4.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+#define MAX_ENTRY_LENGTH 512
+
+static int
+format_who(char *str, size_t size, const acl_entry_t entry, int numeric)
+{
+	int error;
+	acl_tag_t tag;
+	struct passwd *pwd;
+	struct group *grp;
+	uid_t *id;
+
+	error = acl_get_tag_type(entry, &tag);
+	if (error)
+		return (error);
+
+	switch (tag) {
+	case ACL_USER_OBJ:
+		snprintf(str, size, "owner@");
+		break;
+
+	case ACL_USER:
+		id = (uid_t *)acl_get_qualifier(entry);
+		if (id == NULL)
+			return (-1);
+		/* XXX: Thread-unsafe. */
+		if (!numeric)
+			pwd = getpwuid(*id);
+		else
+			pwd = NULL;
+		if (pwd == NULL)
+			snprintf(str, size, "user:%d", (unsigned int)*id);
+		else
+			snprintf(str, size, "user:%s", pwd->pw_name);
+		break;
+
+	case ACL_GROUP_OBJ:
+		snprintf(str, size, "group@");
+		break;
+
+	case ACL_GROUP:
+		id = (uid_t *)acl_get_qualifier(entry);
+		if (id == NULL)
+			return (-1);
+		/* XXX: Thread-unsafe. */
+		if (!numeric)
+			grp = getgrgid(*id);
+		else
+			grp = NULL;
+		if (grp == NULL)
+			snprintf(str, size, "group:%d", (unsigned int)*id);
+		else
+			snprintf(str, size, "group:%s", grp->gr_name);
+		break;
+
+	case ACL_EVERYONE:
+		snprintf(str, size, "everyone@");
+		break;
+
+	default:
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int
+format_entry_type(char *str, size_t size, const acl_entry_t entry)
+{
+	int error;
+	acl_entry_type_t entry_type;
+
+	error = acl_get_entry_type_np(entry, &entry_type);
+	if (error)
+		return (error);
+
+	switch (entry_type) {
+	case ACL_ENTRY_TYPE_ALLOW:
+		snprintf(str, size, "allow");
+		break;
+	case ACL_ENTRY_TYPE_DENY:
+		snprintf(str, size, "deny");
+		break;
+	case ACL_ENTRY_TYPE_AUDIT:
+		snprintf(str, size, "audit");
+		break;
+	case ACL_ENTRY_TYPE_ALARM:
+		snprintf(str, size, "alarm");
+		break;
+	default:
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int
+format_additional_id(char *str, size_t size, const acl_entry_t entry)
+{
+	int error;
+	acl_tag_t tag;
+	uid_t *id;
+
+	error = acl_get_tag_type(entry, &tag);
+	if (error)
+		return (error);
+
+	switch (tag) {
+	case ACL_USER_OBJ:
+	case ACL_GROUP_OBJ:
+	case ACL_EVERYONE:
+		str[0] = '\0';
+		break;
+
+	default:
+		id = (uid_t *)acl_get_qualifier(entry);
+		if (id == NULL)
+			return (-1);
+		snprintf(str, size, ":%d", (unsigned int)*id);
+	}
+
+	return (0);
+}
+
+static int
+format_entry(char *str, size_t size, const acl_entry_t entry, int flags)
+{
+	size_t off = 0, min_who_field_length = 18;
+	acl_permset_t permset;
+	acl_flagset_t flagset;
+	int error;
+	unsigned int len;
+	char buf[MAX_ENTRY_LENGTH + 1];
+
+	assert(_entry_brand(entry) == ACL_BRAND_NFS4);
+
+	error = acl_get_flagset_np(entry, &flagset);
+	if (error)
+		return (error);
+
+	error = acl_get_permset(entry, &permset);
+	if (error)
+		return (error);
+
+	error = format_who(buf, sizeof(buf), entry,
+	    flags & ACL_TEXT_NUMERIC_IDS);
+	if (error)
+		return (error);
+	len = strlen(buf);
+	if (len < min_who_field_length)
+		len = min_who_field_length;
+	off += snprintf(str + off, size - off, "%*s:", len, buf);
+
+	error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
+	    flags & ACL_TEXT_VERBOSE);
+	if (error)
+		return (error);
+	off += snprintf(str + off, size - off, "%s:", buf);
+
+	error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
+	    flags & ACL_TEXT_VERBOSE);
+	if (error)
+		return (error);
+	off += snprintf(str + off, size - off, "%s:", buf);
+
+	error = format_entry_type(buf, sizeof(buf), entry);
+	if (error)
+		return (error);
+	off += snprintf(str + off, size - off, "%s", buf);
+
+	if (flags & ACL_TEXT_APPEND_ID) {
+		error = format_additional_id(buf, sizeof(buf), entry);
+		if (error)
+			return (error);
+		off += snprintf(str + off, size - off, "%s", buf);
+	}
+
+	off += snprintf(str + off, size - off, "\n");
+
+	/* Make sure we didn't truncate anything. */
+	assert (off < size);
+
+	return (0);
+}
+
+char *
+_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
+{
+	int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
+	char *str;
+	acl_entry_t entry;
+
+	if (aclp->ats_acl.acl_cnt == 0)
+		return strdup("");
+
+	size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
+	str = malloc(size);
+	if (str == NULL)
+		return (NULL);
+
+	while (acl_get_entry(aclp, entry_id, &entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+
+		assert(off < size);
+
+		error = format_entry(str + off, size - off, entry, flags);
+		if (error) {
+			free(str);
+			errno = EINVAL;
+			return (NULL);
+		}
+
+		off = strlen(str);
+	}
+
+	assert(off < size);
+	str[off] = '\0';
+
+	if (len_p != NULL)
+		*len_p = off;
+
+	return (str);
+}
Index: lib/libc/posix1e/acl_valid.3
===================================================================
RCS file: lib/libc/posix1e/acl_valid.3
diff -N lib/libc/posix1e/acl_valid.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_valid.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,170 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" 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: head/lib/libc/posix1e/acl_valid.3 140288 2005-01-15 12:21:03Z ru $
+.\"
+.Dd December 29, 2002
+.Dt ACL_VALID 3
+.Os
+.Sh NAME
+.Nm acl_valid ,
+.Nm acl_valid_fd_np ,
+.Nm acl_valid_file_np ,
+.Nm acl_valid_link_np
+.Nd validate an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_valid "acl_t acl"
+.Ft int
+.Fn acl_valid_fd_np "int fd" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_valid_file_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_valid_link_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Sh DESCRIPTION
+These functions check that the ACL referred to by the argument
+.Va acl
+is valid.
+The POSIX.1e routine,
+.Fn acl_valid ,
+checks this validity only with POSIX.1e ACL semantics, and irrespective
+of the context in which the ACL is to be used.
+The non-portable forms,
+.Fn acl_valid_fd_np ,
+.Fn acl_valid_file_np ,
+and
+.Fn acl_valid_link_np
+allow an ACL to be checked in the context of a specific acl type,
+.Va type ,
+and file system object.
+In environments where additional ACL types are
+supported than just POSIX.1e, this makes more sense.
+Whereas
+.Fn acl_valid_file_np
+will follow the symlink if the specified path is to a symlink,
+.Fn acl_valid_link_np
+will not.
+.Pp
+For POSIX.1e semantics, the checks include:
+.Bl -bullet
+.It
+The three required entries
+.Dv ( ACL_USER_OBJ , ACL_GROUP_OBJ ,
+and
+.Dv ACL_OTHER )
+shall exist exactly once in the ACL.
+If the ACL contains any
+.Dv ACL_USER , ACL_GROUP ,
+or any other
+implementation-defined entries in the file group class
+then one
+.Dv ACL_MASK
+entry shall also be required.
+The ACL shall contain at most one
+.Dv ACL_MASK
+entry.
+.It
+The qualifier field shall be unique among all entries of
+the same POSIX.1e ACL facility defined tag type.
+The
+tag type field shall contain valid values including any
+implementation-defined values.
+Validation of the values
+of the qualifier field is implementation-defined.
+.El
+.Pp
+The POSIX.1e
+.Fn acl_valid
+function may reorder the ACL for the purposes of verification; the
+non-portable validation functions will not.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return
+-1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.Pp
+One or more of the required ACL entries is not present in
+.Va acl .
+.Pp
+The ACL contains entries that are not unique.
+.Pp
+The file system rejects the ACL based on fs-specific semantics issues.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
Index: lib/libc/posix1e/acl_valid.c
===================================================================
RCS file: lib/libc/posix1e/acl_valid.c
diff -N lib/libc/posix1e/acl_valid.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/acl_valid.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,129 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * acl_valid -- POSIX.1e ACL check routine
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_valid.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_valid: accepts an ACL, returns 0 on valid ACL, -1 for invalid,
+ * and errno set to EINVAL.
+ *
+ * Implemented by calling the acl_check routine in acl_support, which
+ * requires ordering.  We call acl_support's _posix1e_acl_sort to make this
+ * true.  POSIX.1e allows acl_valid() to reorder the ACL as it sees fit.
+ *
+ * This call is deprecated, as it doesn't ask whether the ACL is valid
+ * for a particular target.  However, this call is standardized, unlike
+ * the other two forms.
+ */ 
+int
+acl_valid(acl_t acl)
+{
+	int	error;
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	if (!_acl_brand_may_be(acl, ACL_BRAND_POSIX)) {
+		errno = EINVAL;
+		return (-1);
+	}
+	_posix1e_acl_sort(acl);
+	error = _posix1e_acl_check(acl);
+	if (error) {
+		errno = error;
+		return (-1);
+	} else {
+		return (0);
+	}
+}
+
+int
+acl_valid_file_np(const char *pathp, acl_type_t type, acl_t acl)
+{
+
+	if (pathp == NULL || acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	return (__acl_aclcheck_file(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_link_np(const char *pathp, acl_type_t type, acl_t acl)
+{
+
+	if (pathp == NULL || acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	return (__acl_aclcheck_link(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_fd_np(int fd, acl_type_t type, acl_t acl)
+{
+
+	if (acl == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	type = _acl_type_unold(type);
+	if (_posix1e_acl(acl, type))
+		_posix1e_acl_sort(acl);
+
+	acl->ats_cur_entry = 0;
+
+	return (__acl_aclcheck_fd(fd, type, &acl->ats_acl));
+}
Index: lib/libc/posix1e/extattr.3
===================================================================
RCS file: lib/libc/posix1e/extattr.3
diff -N lib/libc/posix1e/extattr.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/extattr.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,100 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman <dd@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: head/lib/libc/posix1e/extattr.3 107788 2002-12-12 17:26:04Z ru $
+.\"
+.Dd June 24, 2001
+.Dt EXTATTR 3
+.Os
+.Sh NAME
+.Nm extattr_namespace_to_string ,
+.Nm extattr_string_to_namespace
+.Nd convert an extended attribute namespace identifier to a string and
+vice versa
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/extattr.h
+.In libutil.h
+.Ft int
+.Fn extattr_namespace_to_string "int attrnamespace" "char **string"
+.Ft int
+.Fn extattr_string_to_namespace "const char *string" "int *attrnamespace"
+.Sh DESCRIPTION
+The
+.Fn extattr_namespace_to_string
+function converts a VFS extended attribute identifier to a human-readable
+string;
+the
+.Fn extattr_string_to_namespace
+function undoes the aforementioned operation,
+and converts a human-readable string representing a namespace to a
+namespace identifier.
+Although a file system may implement arbitrary namespaces,
+these functions only support the
+.Dv EXTATTR_NAMESPACE_USER
+.Pq Dq user
+and
+.Dv EXTATTR_NAMESPACE_SYSTEM
+.Pq Dq system
+namespaces,
+which are defined in
+.Xr extattr 9 .
+.Pp
+These functions are meant to be used in error reporting and other
+interactive tasks.
+For example,
+instead of printing the integer identifying an extended attribute in
+an error message,
+a program might use
+.Fn extattr_namespace_to_string
+to obtain a human-readable representation.
+Likewise,
+instead of requiring a user to enter the integer representing a namespace,
+an interactive program might ask for a name and use
+.Fn extattr_string_to_namespace
+to get the desired identifier.
+.Sh RETURN VALUES
+If any of the calls are unsuccessful, the value \-1 is returned
+and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested namespace could not be identified.
+.El
+.Sh SEE ALSO
+.Xr extattr 2 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr extattr 9
+.Sh HISTORY
+Extended attribute support was developed as part of the
+.Tn TrustedBSD
+Project, and introduced in
+.Fx 5.0 .
+It was developed to support security extensions requiring additional labels
+to be associated with each file or directory.
Index: lib/libc/posix1e/extattr.c
===================================================================
RCS file: lib/libc/posix1e/extattr.c
diff -N lib/libc/posix1e/extattr.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/extattr.c	15 May 2020 16:56:51 -0000
@@ -0,0 +1,83 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001 Robert N. M. Watson
+ * 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.
+ */
+/*
+ * TrustedBSD: Utility functions for extended attributes.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/lib/libc/posix1e/extattr.c 326193 2017-11-25 17:12:48Z pfg $");
+#else
+__RCSID("$NetBSD$");
+#endif
+
+#include <sys/types.h>
+#include <sys/extattr.h>
+
+#include <errno.h>
+#include <libutil.h>
+#include <string.h>
+
+int
+extattr_namespace_to_string(int attrnamespace, char **string)
+{
+
+	switch(attrnamespace) {
+	case EXTATTR_NAMESPACE_USER:
+		if (string != NULL)
+			*string = strdup(EXTATTR_NAMESPACE_USER_STRING);
+		return (0);
+
+	case EXTATTR_NAMESPACE_SYSTEM:
+		if (string != NULL)
+			*string = strdup(EXTATTR_NAMESPACE_SYSTEM_STRING);
+		return (0);
+
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+}
+
+int
+extattr_string_to_namespace(const char *string, int *attrnamespace)
+{
+
+	if (!strcmp(string, EXTATTR_NAMESPACE_USER_STRING)) {
+		if (attrnamespace != NULL)
+			*attrnamespace = EXTATTR_NAMESPACE_USER;
+		return (0);
+	} else if (!strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING)) {
+		if (attrnamespace != NULL)
+			*attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+		return (0);
+	} else {
+		errno = EINVAL;
+		return (-1);
+	}
+}
Index: lib/libc/posix1e/posix1e.3
===================================================================
RCS file: lib/libc/posix1e/posix1e.3
diff -N lib/libc/posix1e/posix1e.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libc/posix1e/posix1e.3	15 May 2020 16:56:51 -0000
@@ -0,0 +1,118 @@
+.\"-
+.\" Copyright (c) 2000, 2009 Robert N. M. Watson
+.\" 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: head/lib/libc/posix1e/posix1e.3 318704 2017-05-23 07:05:34Z ngie $
+.\"
+.Dd February 25, 2016
+.Dt POSIX1E 3
+.Os
+.Sh NAME
+.Nm posix1e
+.Nd introduction to the POSIX.1e security API
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.In sys/mac.h
+.Sh DESCRIPTION
+POSIX.1e describes five security extensions to the POSIX.1 API: Access
+Control Lists (ACLs), Auditing, Capabilities, Mandatory Access Control, and
+Information Flow Labels.
+While IEEE POSIX.1e D17 specification has not been standardized, several of
+its interfaces are widely used.
+.Pp
+.Fx
+implements POSIX.1e interface for access control lists, described in
+.Xr acl 3 ,
+and supports ACLs on the
+.Xr ffs 7
+file system; ACLs must be administratively enabled using
+.Xr tunefs 8 .
+.Pp
+.Fx
+implements a POSIX.1e-like mandatory access control interface, described in
+.Xr mac 3 ,
+although with a number of extensions and important semantic differences.
+.Pp
+.Fx
+does not implement the POSIX.1e audit, privilege (capability), or information
+flow label APIs.
+However,
+.Fx
+does implement the
+.Xr libbsm 3
+audit API.
+It also provides
+.Xr capsicum 4 ,
+a lightweight OS capability and sandbox framework implementing a
+hybrid capability system model.
+.Sh ENVIRONMENT
+POSIX.1e assigns security attributes to all objects, extending the security
+functionality described in POSIX.1.
+These additional attributes store fine-grained discretionary access control
+information and mandatory access control labels; for files, they are stored
+in extended attributes, described in
+.Xr extattr 3 .
+.Pp
+POSIX.2c describes
+a set of userland utilities for manipulating these attributes, including
+.Xr getfacl 1
+and
+.Xr setfacl 1
+for access control lists, and
+.Xr getfmac 8
+and
+.Xr setfmac 8
+for mandatory access control labels.
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr setfacl 1 ,
+.Xr extattr 2 ,
+.Xr acl 3 ,
+.Xr extattr 3 ,
+.Xr libbsm 3 ,
+.Xr libcasper 3 ,
+.Xr mac 3 ,
+.Xr capsicum 4 ,
+.Xr ffs 7 ,
+.Xr getfmac 8 ,
+.Xr setfmac 8 ,
+.Xr tunefs 8 ,
+.Xr acl 9 ,
+.Xr extattr 9 ,
+.Xr mac 9
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ;
+most features were available as of
+.Fx 5.0 .
+.Sh AUTHORS
+.An Robert N M Watson
+.An Chris D. Faulhaber
+.An Thomas Moestl
+.An Ilmar S Habibulin
Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.242
diff -u -p -p -u -r1.242 Makefile.inc
--- lib/libc/sys/Makefile.inc	22 Sep 2019 22:59:38 -0000	1.242
+++ lib/libc/sys/Makefile.inc	15 May 2020 16:56:51 -0000
@@ -89,8 +89,13 @@ ASM_GLUE+= tmp___${glue:.c=}50.S
 .endfor
 
 # modules with default implementations on all architectures:
-ASM=	access.S acct.S \
-	bind.S \
+ASM=\
+    __acl_get_link.S __acl_set_link.S __acl_delete_link.S \
+    __acl_aclcheck_link.S __acl_get_file.S __acl_set_file.S __acl_get_fd.S \
+    __acl_set_fd.S __acl_delete_file.S __acl_delete_fd.S \
+    __acl_aclcheck_file.S __acl_aclcheck_fd.S \
+    access.S acct.S \
+	    bind.S \
 	chdir.S chflags.S chmod.S chown.S chroot.S clock_nanosleep.S \
 		clock_getcpuclockid2.S \
 		__clock_getres50.S __clock_gettime50.S \
@@ -118,6 +123,7 @@ ASM=	access.S acct.S \
 		_ksem_post.S _ksem_timedwait.S _ksem_trywait.S _ksem_unlink.S \
 		_ksem_wait.S _ksem_open.S \
 	lchflags.S lchmod.S lchown.S lfs_bmapv.S lfs_markv.S lfs_segclean.S \
+		lpathconf.S \
 		__lfs_segwait50.S link.S linkat.S listen.S __lstat50.S \
 		__lutimes50.S _lwp_create.S _lwp_exit.S _lwp_kill.S \
 		___lwp_park60.S _lwp_self.S _lwp_wait.S _lwp_unpark.S \
Index: lib/libc/sys/makelintstub
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/makelintstub,v
retrieving revision 1.26
diff -u -p -p -u -r1.26 makelintstub
--- lib/libc/sys/makelintstub	3 Apr 2016 00:48:29 -0000	1.26
+++ lib/libc/sys/makelintstub	15 May 2020 16:56:51 -0000
@@ -60,6 +60,7 @@ header()
 	 */
 
 	#include <sys/param.h>
+	#include <sys/acl.h>
 	#include <sys/aio.h>
 	#include <sys/time.h>
 	#include <sys/mount.h>
Index: sbin/mount_ffs/mount_ffs.c
===================================================================
RCS file: /cvsroot/src/sbin/mount_ffs/mount_ffs.c,v
retrieving revision 1.28
diff -u -p -p -u -r1.28 mount_ffs.c
--- sbin/mount_ffs/mount_ffs.c	19 Oct 2012 17:09:07 -0000	1.28
+++ sbin/mount_ffs/mount_ffs.c	15 May 2020 16:56:51 -0000
@@ -64,6 +64,8 @@ __dead static void	ffs_usage(void);
 
 static const struct mntopt mopts[] = {
 	MOPT_STDOPTS,
+	MOPT_ACLS,
+	MOPT_POSIX1EACLS,
 	MOPT_ASYNC,
 	MOPT_SYNC,
 	MOPT_UPDATE,
Index: sbin/tunefs/tunefs.8
===================================================================
RCS file: /cvsroot/src/sbin/tunefs/tunefs.8,v
retrieving revision 1.44
diff -u -p -p -u -r1.44 tunefs.8
--- sbin/tunefs/tunefs.8	9 Aug 2014 10:41:05 -0000	1.44
+++ sbin/tunefs/tunefs.8	15 May 2020 16:56:51 -0000
@@ -29,7 +29,7 @@
 .\"
 .\"     @(#)tunefs.8	8.3 (Berkeley) 5/3/95
 .\"
-.Dd August 9, 2014
+.Dd April 7, 2020
 .Dt TUNEFS 8
 .Os
 .Sh NAME
@@ -38,11 +38,13 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl AFN
+.Op Fl a Cm enable | disable
 .Op Fl e Ar maxbpg
 .Op Fl g Ar avgfilesize
 .Op Fl h Ar avgfpdir
 .Op Fl l Ar logsize
 .Op Fl m Ar minfree
+.Op Fl n Cm enable | disable
 .Op Fl o Ar optimize_preference
 .Op Fl q Ar quota
 .Op Fl S Ar sectorsize
@@ -78,6 +80,8 @@ will be accessed
 Display all the settable options
 (after any changes from the tuning options)
 but do not cause any of them to be changed.
+.It Fl a Cm enable | disable
+Turn on/off the administrative NFSv4 ACL enable flag.
 .It Fl e Ar maxbpg
 This indicates the maximum number of blocks any single file can
 allocate out of a cylinder group before it is forced to begin
@@ -130,6 +134,8 @@ running out of full sized blocks.
 For values of minfree greater than or equal to 5%,
 fragmentation is unlikely to be problematical, and
 the file system can be optimized for time.
+.It Fl p Cm enable | disable
+Turn on/off the administrative POSIX.1e ACL enable flag.
 .Pp
 .Ar optimize_preference
 can be specified as either
Index: sbin/tunefs/tunefs.c
===================================================================
RCS file: /cvsroot/src/sbin/tunefs/tunefs.c,v
retrieving revision 1.51
diff -u -p -p -u -r1.51 tunefs.c
--- sbin/tunefs/tunefs.c	9 Apr 2020 14:44:38 -0000	1.51
+++ sbin/tunefs/tunefs.c	15 May 2020 16:56:51 -0000
@@ -101,16 +101,18 @@ __dead static	void	usage(void);
 int
 main(int argc, char *argv[])
 {
-	int		i, ch, Aflag, Fflag, Nflag, openflags;
+	int		i, ch, aflag, pflag, Aflag, Fflag, Nflag, openflags;
 	const char	*special, *chg[2];
 	char		device[MAXPATHLEN];
 	int		maxbpg, minfree, optim, secsize;
 	int		avgfilesize, avgfpdir, active;
 	long long	logfilesize;
 	int		secshift, fsbtodb;
+	const char  	*avalue, *pvalue, *name;
 	struct statvfs	sfs;
 
-	Aflag = Fflag = Nflag = 0;
+	aflag = pflag = Aflag = Fflag = Nflag = 0;
+	avalue = pvalue = NULL;
 	maxbpg = minfree = optim = secsize = -1;
 	avgfilesize = avgfpdir = -1;
 	logfilesize = -1;
@@ -118,7 +120,7 @@ main(int argc, char *argv[])
 	chg[FS_OPTSPACE] = "space";
 	chg[FS_OPTTIME] = "time";
 
-	while ((ch = getopt(argc, argv, "AFNe:g:h:l:m:o:q:S:")) != -1) {
+	while ((ch = getopt(argc, argv, "AFNa:e:g:h:l:m:o:p:q:S:")) != -1) {
 		switch (ch) {
 
 		case 'A':
@@ -133,6 +135,17 @@ main(int argc, char *argv[])
 			Nflag++;
 			break;
 
+		case 'a':
+			name = "ACLs";
+			avalue = optarg;
+			if (strcmp(avalue, "enable") &&
+			    strcmp(avalue, "disable")) {
+				errx(10, "bad %s (options are %s)",
+				    name, "`enable' or `disable'");
+			}
+			aflag = 1;
+ 			break;
+
 		case 'e':
 			maxbpg = strsuftoll(
 			    "maximum blocks per file in a cylinder group",
@@ -170,6 +183,18 @@ main(int argc, char *argv[])
 				    "bad %s (options are `space' or `time')",
 				    "optimization preference");
 			break;
+
+		case 'p':
+			name = "POSIX1e ACLs";
+			pvalue = optarg;
+			if (strcmp(pvalue, "enable") &&
+			    strcmp(pvalue, "disable")) {
+				errx(10, "bad %s (options are %s)",
+				    name, "`enable' or `disable'");
+			}
+			pflag = 1;
+			break;
+
 		case 'q':
 			if      (strcmp(optarg, "user") == 0)
 				userquota = Q2_EN;
@@ -182,6 +207,7 @@ main(int argc, char *argv[])
 			else
 			    errx(11, "invalid quota type %s", optarg);
 			break;
+
 		case 'S':
 			secsize = strsuftoll("physical sector size",
 			    optarg, 0, INT_MAX);
@@ -189,6 +215,7 @@ main(int argc, char *argv[])
 			if (secsize != 0 && 1 << secshift != secsize)
 				errx(12, "sector size %d is not a power of two", secsize);
 			break;
+
 		default:
 			usage();
 		}
@@ -330,9 +357,55 @@ main(int argc, char *argv[])
 	 * if we disabled all quotas, FS_DOQUOTA2 and associated inode(s) will
 	 * be cleared by kernel or fsck.
 	 */
+	if (aflag) {
+		name = "ACLs";
+		if (strcmp(avalue, "enable") == 0) {
+			if (sblock.fs_flags & FS_ACLS) {
+				warnx("%s remains unchanged as enabled", name);
+			} else if (sblock.fs_flags & FS_POSIX1EACLS) {
+				warnx("%s and POSIX.1e ACLs are mutually "
+				    "exclusive", name);
+			} else {
+				sblock.fs_flags |= FS_ACLS;
+				printf("%s set\n", name);
+			}
+		} else if (strcmp(avalue, "disable") == 0) {
+			if ((~sblock.fs_flags & FS_ACLS) == FS_ACLS) {
+				warnx("%s remains unchanged as disabled",
+				    name);
+			} else {
+				sblock.fs_flags &= ~FS_ACLS;
+				printf("%s cleared\n", name);
+			}
+ 		}
+ 	}
+
+	if (pflag) {
+		name = "POSIX1e ACLs";
+		if (strcmp(pvalue, "enable") == 0) {
+			if (sblock.fs_flags & FS_POSIX1EACLS) {
+				warnx("%s remains unchanged as enabled", name);
+			} else if (sblock.fs_flags & FS_ACLS) {
+				warnx("%s and ACLs are mutually "
+				    "exclusive", name);
+			} else {
+				sblock.fs_flags |= FS_POSIX1EACLS;
+				printf("%s set", name);
+			}
+		} else if (strcmp(pvalue, "disable") == 0) {
+			if ((~sblock.fs_flags & FS_POSIX1EACLS) ==
+			    FS_POSIX1EACLS) {
+				warnx("%s remains unchanged as disabled",
+				    name);
+			} else {
+				sblock.fs_flags &= ~FS_POSIX1EACLS;
+				printf("%s cleared", name);
+			}
+		}
+	}
 
 	if (Nflag) {
-		printf("tunefs: current settings of %s\n", special);
+		printf("%s: current settings of %s\n", getprogname(), special);
 		printf("\tmaximum contiguous block count %d\n",
 		    sblock.fs_maxcontig);
 		printf("\tmaximum blocks per file in a cylinder group %d\n",
@@ -358,8 +431,12 @@ main(int argc, char *argv[])
 		} else {
 			printf(" disabled\n");
 		}
-		printf("tunefs: no changes made\n");
-		exit(0);
+		printf("\tPOSIX.1e ACLs %s\n",
+		    (sblock.fs_flags & FS_POSIX1EACLS) ? "enabled" : "disabled");
+		printf("\tACLs %s\n",
+		    (sblock.fs_flags & FS_ACLS) ? "enabled" : "disabled");
+		printf("%s: no changes made\n", getprogname());
+		return 0;
 	}
 
 	memcpy(&buf, (char *)&sblock, SBLOCKSIZE);
@@ -527,11 +604,13 @@ usage(void)
 
 	fprintf(stderr, "usage: tunefs [-AFN] tuneup-options special-device\n");
 	fprintf(stderr, "where tuneup-options are:\n");
+	fprintf(stderr, "\t-a ACLS: `enable' or `disable'\n");
 	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
 	fprintf(stderr, "\t-g average file size\n");
 	fprintf(stderr, "\t-h expected number of files per directory\n");
 	fprintf(stderr, "\t-l journal log file size (`0' to clear journal)\n");
 	fprintf(stderr, "\t-m minimum percentage of free space\n");
+	fprintf(stderr, "\t-p POSIX.1e ACLS: `enable' or `disable'\n");
 	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
 	fprintf(stderr, "\t-q quota type (`[no]user' or `[no]group')\n");
 	fprintf(stderr, "\t-S sector size\n");
Index: sys/arch/amd64/amd64/genassym.cf
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/genassym.cf,v
retrieving revision 1.84
diff -u -p -p -u -r1.84 genassym.cf
--- sys/arch/amd64/amd64/genassym.cf	2 May 2020 16:44:34 -0000	1.84
+++ sys/arch/amd64/amd64/genassym.cf	15 May 2020 16:56:51 -0000
@@ -82,6 +82,7 @@ include <sys/rwlock.h>
 include <sys/cpu_data.h>
 include <sys/evcnt.h>
 include <sys/cpu.h>
+include <sys/acl.h>
 
 include <netinet/in.h>
 include <netinet/in_systm.h>
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.567
diff -u -p -p -u -r1.567 GENERIC
--- sys/arch/amd64/conf/GENERIC	2 May 2020 16:44:35 -0000	1.567
+++ sys/arch/amd64/conf/GENERIC	15 May 2020 16:56:51 -0000
@@ -197,6 +197,7 @@ options 	WAPBL		# File system journaling
 # Note that UFS_DIRHASH is suspected of causing kernel memory corruption.
 # It is not recommended for general use.
 #options 	UFS_DIRHASH	# UFS Large Directory Hashing - Experimental
+options		UFS_ACL		# UFS Access Control Lists
 #options 	FFS_NO_SNAPSHOT	# No FFS snapshot support
 options 	UFS_EXTATTR	# Extended attribute support for UFS1
 # ext2fs
Index: sys/coda/coda_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/coda/coda_vnops.c,v
retrieving revision 1.111
diff -u -p -p -u -r1.111 coda_vnops.c
--- sys/coda/coda_vnops.c	13 Apr 2020 19:23:17 -0000	1.111
+++ sys/coda/coda_vnops.c	15 May 2020 16:56:52 -0000
@@ -106,6 +106,7 @@ const struct vnodeopv_entry_desc coda_vn
     { &vop_open_desc, coda_open },		/* open */
     { &vop_close_desc, coda_close },		/* close */
     { &vop_access_desc, coda_access },		/* access */
+    { &vop_accessx_desc, genfs_accessx },	/* access */
     { &vop_getattr_desc, coda_getattr },	/* getattr */
     { &vop_setattr_desc, coda_setattr },	/* setattr */
     { &vop_read_desc, coda_read },		/* read */
@@ -662,19 +663,20 @@ coda_access(void *v)
     struct vop_access_args *ap = v;
     vnode_t *vp = ap->a_vp;
     struct cnode *cp = VTOC(vp);
-    int mode = ap->a_mode;
+    accmode_t accmode = ap->a_accmode;
     kauth_cred_t cred = ap->a_cred;
 /* locals */
     int error;
 
     MARK_ENTRY(CODA_ACCESS_STATS);
 
+    KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
     /* Check for access of control object.  Only read access is
        allowed on it. */
     if (IS_CTL_VP(vp)) {
 	/* bogus hack - all will be marked as successes */
 	MARK_INT_SAT(CODA_ACCESS_STATS);
-	return(((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
+	return(((accmode & VREAD) && !(accmode & (VWRITE | VEXEC)))
 	       ? 0 : EACCES);
     }
 
@@ -684,7 +686,7 @@ coda_access(void *v)
      * lookup access to it.
      */
     if (coda_access_cache) {
-	if ((vp->v_type == VDIR) && (mode & VEXEC)) {
+	if ((vp->v_type == VDIR) && (accmode & VEXEC)) {
 	    if (coda_nc_lookup(cp, ".", 1, cred)) {
 		MARK_INT_SAT(CODA_ACCESS_STATS);
 		return(0);                     /* it was in the cache */
@@ -692,7 +694,7 @@ coda_access(void *v)
 	}
     }
 
-    error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, curlwp);
+    error = venus_access(vtomi(vp), &cp->c_fid, accmode, cred, curlwp);
 
     return(error);
 }
Index: sys/compat/netbsd32/files.netbsd32
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/files.netbsd32,v
retrieving revision 1.51
diff -u -p -p -u -r1.51 files.netbsd32
--- sys/compat/netbsd32/files.netbsd32	26 Apr 2020 18:53:33 -0000	1.51
+++ sys/compat/netbsd32/files.netbsd32	15 May 2020 16:56:52 -0000
@@ -10,6 +10,7 @@ define	compat_netbsd32
 
 #makeoptions	drmkms	CPPFLAGS+="-DNETBSD32_DRMKMS"
 
+file	compat/netbsd32/netbsd32_acl.c		compat_netbsd32
 file	compat/netbsd32/netbsd32_core.c		compat_netbsd32 & coredump
 file	compat/netbsd32/netbsd32_exec_elf32.c	compat_netbsd32 & exec_elf32
 file	compat/netbsd32/netbsd32_exec_aout.c	compat_netbsd32 & exec_aout
Index: sys/compat/netbsd32/netbsd32.h
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32.h,v
retrieving revision 1.132
diff -u -p -p -u -r1.132 netbsd32.h
--- sys/compat/netbsd32/netbsd32.h	24 Dec 2019 14:50:59 -0000	1.132
+++ sys/compat/netbsd32/netbsd32.h	15 May 2020 16:56:52 -0000
@@ -190,6 +190,7 @@ typedef netbsd32_pointer_t netbsd32_cadd
 typedef netbsd32_pointer_t netbsd32_lwpctlp;
 typedef netbsd32_pointer_t netbsd32_pid_tp;
 typedef netbsd32_pointer_t netbsd32_psetidp_t;
+typedef netbsd32_pointer_t netbsd32_aclp_t;
 
 /*
  * now, the compatibility structures and their fake pointer types.
Index: sys/compat/netbsd32/netbsd32_acl.c
===================================================================
RCS file: sys/compat/netbsd32/netbsd32_acl.c
diff -N sys/compat/netbsd32/netbsd32_acl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/compat/netbsd32/netbsd32_acl.c	15 May 2020 16:56:52 -0000
@@ -0,0 +1,216 @@
+/*	$NetBSD: netbsd32_acl.c,v 1.1 2020/04/26 18:53:33 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_acl.c,v 1.1 2020/04/26 18:53:33 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/lwp.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/acl.h>
+#include <sys/syscallargs.h>
+
+#include <compat/netbsd32/netbsd32.h>
+#include <compat/netbsd32/netbsd32_syscallargs.h>
+#include <compat/netbsd32/netbsd32_conv.h>
+
+/* Syscalls conversion */
+int
+netbsd32___acl_get_file(struct lwp *l,
+     const struct netbsd32___acl_get_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_get_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    SCARG_P32(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, get an ACL for it; don't follow links.
+ */
+int
+netbsd32___acl_get_link(struct lwp *l,
+    const struct netbsd32___acl_get_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_get_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    SCARG_P32(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, set an ACL for it.
+ */
+int
+netbsd32___acl_set_file(struct lwp *l,
+    const struct netbsd32___acl_set_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_set_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    SCARG_P32(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, set an ACL for it; don't follow links.
+ */
+int
+netbsd32___acl_set_link(struct lwp *l,
+    const struct netbsd32___acl_set_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_set_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    SCARG_P32(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file descriptor, get an ACL for it.
+ */
+int
+netbsd32___acl_get_fd(struct lwp *l,
+    const struct netbsd32___acl_get_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_get_acl(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG_P32(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file descriptor, set an ACL for it.
+ */
+int
+netbsd32___acl_set_fd(struct lwp *l,
+    const struct netbsd32___acl_set_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_set_acl(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG_P32(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file path, delete an ACL from it.
+ */
+int
+netbsd32___acl_delete_file(struct lwp *l,
+    const struct netbsd32___acl_delete_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_delete_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, delete an ACL from it; don't follow links.
+ */
+int
+netbsd32___acl_delete_link(struct lwp *l,
+    const struct netbsd32___acl_delete_link_args *uap, register_t *retval)
+{
+	return kern___acl_delete_path(l, SCARG_P32(uap, path), SCARG(uap, type),
+	    NSM_NOFOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, delete an ACL from it.
+ */
+int
+netbsd32___acl_delete_fd(struct lwp *l,
+    const struct netbsd32___acl_delete_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_delete(l, fp->f_vnode, SCARG(uap, type));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file path, check an ACL for it.
+ */
+int
+netbsd32___acl_aclcheck_file(struct lwp *l,
+    const struct netbsd32___acl_aclcheck_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_aclcheck_path(l, SCARG_P32(uap, path),
+	    SCARG(uap, type), SCARG_P32(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, check an ACL for it; don't follow links.
+ */
+int
+netbsd32___acl_aclcheck_link(struct lwp *l,
+    const struct netbsd32___acl_aclcheck_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_aclcheck_path(l, SCARG_P32(uap, path),
+	    SCARG(uap, type), SCARG_P32(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file descriptor, check an ACL for it.
+ */
+int
+netbsd32___acl_aclcheck_fd(struct lwp *l,
+    const struct netbsd32___acl_aclcheck_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_aclcheck(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG_P32(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
Index: sys/compat/netbsd32/netbsd32_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_netbsd.c,v
retrieving revision 1.228
diff -u -p -p -u -r1.228 netbsd32_netbsd.c
--- sys/compat/netbsd32/netbsd32_netbsd.c	20 Jun 2019 03:31:54 -0000	1.228
+++ sys/compat/netbsd32/netbsd32_netbsd.c	15 May 2020 16:56:52 -0000
@@ -1253,6 +1253,21 @@ netbsd32_seteuid(struct lwp *l, const st
 }
 
 int
+netbsd32_lpathconf(struct lwp *l, const struct netbsd32_lpathconf_args *uap, register_t *retval)
+{
+	/* {
+		syscallarg(netbsd32_charp) path;
+		syscallarg(int) name;
+	} */
+	struct sys_lpathconf_args ua;
+
+	NETBSD32TOP_UAP(path, const char);
+	NETBSD32TO64_UAP(name);
+
+	return sys_lpathconf(l, &ua, retval);
+}
+
+int
 netbsd32_pathconf(struct lwp *l, const struct netbsd32_pathconf_args *uap, register_t *retval)
 {
 	/* {
Index: sys/compat/netbsd32/netbsd32_syscall.h
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_syscall.h,v
retrieving revision 1.153
diff -u -p -p -u -r1.153 netbsd32_syscall.h
--- sys/compat/netbsd32/netbsd32_syscall.h	26 Apr 2020 19:18:52 -0000	1.153
+++ sys/compat/netbsd32/netbsd32_syscall.h	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_syscall.h,v 1.153 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call numbers.
@@ -1284,6 +1284,45 @@
 /* syscall: "netbsd32___fhstatvfs190" ret: "int" args: "netbsd32_voidp" "netbsd32_size_t" "netbsd32_statvfsp_t" "int" */
 #define	NETBSD32_SYS_netbsd32___fhstatvfs190	486
 
-#define	NETBSD32_SYS_MAXSYSCALL	487
+/* syscall: "netbsd32___acl_get_link" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_get_link	487
+
+/* syscall: "netbsd32___acl_set_link" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_set_link	488
+
+/* syscall: "netbsd32___acl_delete_link" ret: "int" args: "const netbsd32_charp" "acl_type_t" */
+#define	NETBSD32_SYS_netbsd32___acl_delete_link	489
+
+/* syscall: "netbsd32___acl_aclcheck_link" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_aclcheck_link	490
+
+/* syscall: "netbsd32___acl_get_file" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_get_file	491
+
+/* syscall: "netbsd32___acl_set_file" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_set_file	492
+
+/* syscall: "netbsd32___acl_get_fd" ret: "int" args: "int" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_get_fd	493
+
+/* syscall: "netbsd32___acl_set_fd" ret: "int" args: "int" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_set_fd	494
+
+/* syscall: "netbsd32___acl_delete_file" ret: "int" args: "const netbsd32_charp" "acl_type_t" */
+#define	NETBSD32_SYS_netbsd32___acl_delete_file	495
+
+/* syscall: "netbsd32___acl_delete_fd" ret: "int" args: "int" "acl_type_t" */
+#define	NETBSD32_SYS_netbsd32___acl_delete_fd	496
+
+/* syscall: "netbsd32___acl_aclcheck_file" ret: "int" args: "const netbsd32_charp" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_aclcheck_file	497
+
+/* syscall: "netbsd32___acl_aclcheck_fd" ret: "int" args: "int" "acl_type_t" "netbsd32_aclp_t" */
+#define	NETBSD32_SYS_netbsd32___acl_aclcheck_fd	498
+
+/* syscall: "netbsd32_lpathconf" ret: "long" args: "const netbsd32_charp" "int" */
+#define	NETBSD32_SYS_netbsd32_lpathconf	499
+
+#define	NETBSD32_SYS_MAXSYSCALL	500
 #define	NETBSD32_SYS_NSYSENT	512
 #endif /* _NETBSD32_SYS_SYSCALL_H_ */
Index: sys/compat/netbsd32/netbsd32_syscallargs.h
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_syscallargs.h,v
retrieving revision 1.152
diff -u -p -p -u -r1.152 netbsd32_syscallargs.h
--- sys/compat/netbsd32/netbsd32_syscallargs.h	26 Apr 2020 19:18:52 -0000	1.152
+++ sys/compat/netbsd32/netbsd32_syscallargs.h	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_syscallargs.h,v 1.152 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument lists.
@@ -2669,6 +2669,93 @@ struct netbsd32___fhstatvfs190_args {
 };
 check_syscall_args(netbsd32___fhstatvfs190)
 
+struct netbsd32___acl_get_link_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_get_link)
+
+struct netbsd32___acl_set_link_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_set_link)
+
+struct netbsd32___acl_delete_link_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(netbsd32___acl_delete_link)
+
+struct netbsd32___acl_aclcheck_link_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_aclcheck_link)
+
+struct netbsd32___acl_get_file_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_get_file)
+
+struct netbsd32___acl_set_file_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_set_file)
+
+struct netbsd32___acl_get_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_get_fd)
+
+struct netbsd32___acl_set_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_set_fd)
+
+struct netbsd32___acl_delete_file_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(netbsd32___acl_delete_file)
+
+struct netbsd32___acl_delete_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(netbsd32___acl_delete_fd)
+
+struct netbsd32___acl_aclcheck_file_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_aclcheck_file)
+
+struct netbsd32___acl_aclcheck_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(netbsd32_aclp_t) aclp;
+};
+check_syscall_args(netbsd32___acl_aclcheck_fd)
+
+struct netbsd32_lpathconf_args {
+	syscallarg(const netbsd32_charp) path;
+	syscallarg(int) name;
+};
+check_syscall_args(netbsd32_lpathconf)
+
 /*
  * System call prototypes.
  */
@@ -3503,4 +3590,30 @@ int	netbsd32___fstatvfs190(struct lwp *,
 
 int	netbsd32___fhstatvfs190(struct lwp *, const struct netbsd32___fhstatvfs190_args *, register_t *);
 
+int	netbsd32___acl_get_link(struct lwp *, const struct netbsd32___acl_get_link_args *, register_t *);
+
+int	netbsd32___acl_set_link(struct lwp *, const struct netbsd32___acl_set_link_args *, register_t *);
+
+int	netbsd32___acl_delete_link(struct lwp *, const struct netbsd32___acl_delete_link_args *, register_t *);
+
+int	netbsd32___acl_aclcheck_link(struct lwp *, const struct netbsd32___acl_aclcheck_link_args *, register_t *);
+
+int	netbsd32___acl_get_file(struct lwp *, const struct netbsd32___acl_get_file_args *, register_t *);
+
+int	netbsd32___acl_set_file(struct lwp *, const struct netbsd32___acl_set_file_args *, register_t *);
+
+int	netbsd32___acl_get_fd(struct lwp *, const struct netbsd32___acl_get_fd_args *, register_t *);
+
+int	netbsd32___acl_set_fd(struct lwp *, const struct netbsd32___acl_set_fd_args *, register_t *);
+
+int	netbsd32___acl_delete_file(struct lwp *, const struct netbsd32___acl_delete_file_args *, register_t *);
+
+int	netbsd32___acl_delete_fd(struct lwp *, const struct netbsd32___acl_delete_fd_args *, register_t *);
+
+int	netbsd32___acl_aclcheck_file(struct lwp *, const struct netbsd32___acl_aclcheck_file_args *, register_t *);
+
+int	netbsd32___acl_aclcheck_fd(struct lwp *, const struct netbsd32___acl_aclcheck_fd_args *, register_t *);
+
+int	netbsd32_lpathconf(struct lwp *, const struct netbsd32_lpathconf_args *, register_t *);
+
 #endif /* _NETBSD32_SYS_SYSCALLARGS_H_ */
Index: sys/compat/netbsd32/netbsd32_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_syscalls.c,v
retrieving revision 1.152
diff -u -p -p -u -r1.152 netbsd32_syscalls.c
--- sys/compat/netbsd32/netbsd32_syscalls.c	26 Apr 2020 19:18:52 -0000	1.152
+++ sys/compat/netbsd32/netbsd32_syscalls.c	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_syscalls.c,v 1.152 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call names.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_syscalls.c,v 1.152 2020/04/26 19:18:52 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #if defined(_KERNEL_OPT)
@@ -525,19 +525,19 @@ const char *const netbsd32_syscallnames[
 	/* 484 */	"netbsd32___statvfs190",
 	/* 485 */	"netbsd32___fstatvfs190",
 	/* 486 */	"netbsd32___fhstatvfs190",
-	/* 487 */	"# filler",
-	/* 488 */	"# filler",
-	/* 489 */	"# filler",
-	/* 490 */	"# filler",
-	/* 491 */	"# filler",
-	/* 492 */	"# filler",
-	/* 493 */	"# filler",
-	/* 494 */	"# filler",
-	/* 495 */	"# filler",
-	/* 496 */	"# filler",
-	/* 497 */	"# filler",
-	/* 498 */	"# filler",
-	/* 499 */	"# filler",
+	/* 487 */	"netbsd32___acl_get_link",
+	/* 488 */	"netbsd32___acl_set_link",
+	/* 489 */	"netbsd32___acl_delete_link",
+	/* 490 */	"netbsd32___acl_aclcheck_link",
+	/* 491 */	"netbsd32___acl_get_file",
+	/* 492 */	"netbsd32___acl_set_file",
+	/* 493 */	"netbsd32___acl_get_fd",
+	/* 494 */	"netbsd32___acl_set_fd",
+	/* 495 */	"netbsd32___acl_delete_file",
+	/* 496 */	"netbsd32___acl_delete_fd",
+	/* 497 */	"netbsd32___acl_aclcheck_file",
+	/* 498 */	"netbsd32___acl_aclcheck_fd",
+	/* 499 */	"netbsd32_lpathconf",
 	/* 500 */	"# filler",
 	/* 501 */	"# filler",
 	/* 502 */	"# filler",
@@ -1050,19 +1050,19 @@ const char *const altnetbsd32_syscallnam
 	/* 484 */	"statvfs1",
 	/* 485 */	"fstatvfs1",
 	/* 486 */	"fhstatvfs1",
-	/* 487 */	NULL, /* filler */
-	/* 488 */	NULL, /* filler */
-	/* 489 */	NULL, /* filler */
-	/* 490 */	NULL, /* filler */
-	/* 491 */	NULL, /* filler */
-	/* 492 */	NULL, /* filler */
-	/* 493 */	NULL, /* filler */
-	/* 494 */	NULL, /* filler */
-	/* 495 */	NULL, /* filler */
-	/* 496 */	NULL, /* filler */
-	/* 497 */	NULL, /* filler */
-	/* 498 */	NULL, /* filler */
-	/* 499 */	NULL, /* filler */
+	/* 487 */	"__acl_get_link",
+	/* 488 */	"__acl_set_link",
+	/* 489 */	"__acl_delete_link",
+	/* 490 */	"__acl_aclcheck_link",
+	/* 491 */	"__acl_get_file",
+	/* 492 */	"__acl_set_file",
+	/* 493 */	"__acl_get_fd",
+	/* 494 */	"__acl_set_fd",
+	/* 495 */	"__acl_delete_file",
+	/* 496 */	"__acl_delete_fd",
+	/* 497 */	"__acl_aclcheck_file",
+	/* 498 */	"__acl_aclcheck_fd",
+	/* 499 */	"lpathconf",
 	/* 500 */	NULL, /* filler */
 	/* 501 */	NULL, /* filler */
 	/* 502 */	NULL, /* filler */
Index: sys/compat/netbsd32/netbsd32_syscalls_autoload.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_syscalls_autoload.c,v
retrieving revision 1.32
diff -u -p -p -u -r1.32 netbsd32_syscalls_autoload.c
--- sys/compat/netbsd32/netbsd32_syscalls_autoload.c	26 Apr 2020 19:18:52 -0000	1.32
+++ sys/compat/netbsd32/netbsd32_syscalls_autoload.c	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_syscalls_autoload.c,v 1.32 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call autoload table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_syscalls_autoload.c,v 1.32 2020/04/26 19:18:52 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
Index: sys/compat/netbsd32/netbsd32_sysent.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_sysent.c,v
retrieving revision 1.151
diff -u -p -p -u -r1.151 netbsd32_sysent.c
--- sys/compat/netbsd32/netbsd32_sysent.c	26 Apr 2020 19:18:52 -0000	1.151
+++ sys/compat/netbsd32/netbsd32_sysent.c	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_sysent.c,v 1.151 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call switch table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_sysent.c,v 1.151 2020/04/26 19:18:52 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -2009,44 +2009,57 @@ struct sysent netbsd32_sysent[] = {
 		.sy_call = (sy_call_t *)netbsd32___fhstatvfs190
 	},		/* 486 = netbsd32___fhstatvfs190 */
 	{
-		.sy_call = sys_nosys,
-	},		/* 487 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 488 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 489 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 490 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 491 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 492 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 493 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 494 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 495 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 496 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 497 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 498 = filler */
-	{
-		.sy_call = sys_nosys,
-	},		/* 499 = filler */
+		ns(struct netbsd32___acl_get_link_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_get_link
+	},		/* 487 = netbsd32___acl_get_link */
+	{
+		ns(struct netbsd32___acl_set_link_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_set_link
+	},		/* 488 = netbsd32___acl_set_link */
+	{
+		ns(struct netbsd32___acl_delete_link_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_delete_link
+	},		/* 489 = netbsd32___acl_delete_link */
+	{
+		ns(struct netbsd32___acl_aclcheck_link_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_aclcheck_link
+	},		/* 490 = netbsd32___acl_aclcheck_link */
+	{
+		ns(struct netbsd32___acl_get_file_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_get_file
+	},		/* 491 = netbsd32___acl_get_file */
+	{
+		ns(struct netbsd32___acl_set_file_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_set_file
+	},		/* 492 = netbsd32___acl_set_file */
+	{
+		ns(struct netbsd32___acl_get_fd_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_get_fd
+	},		/* 493 = netbsd32___acl_get_fd */
+	{
+		ns(struct netbsd32___acl_set_fd_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_set_fd
+	},		/* 494 = netbsd32___acl_set_fd */
+	{
+		ns(struct netbsd32___acl_delete_file_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_delete_file
+	},		/* 495 = netbsd32___acl_delete_file */
+	{
+		ns(struct netbsd32___acl_delete_fd_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_delete_fd
+	},		/* 496 = netbsd32___acl_delete_fd */
+	{
+		ns(struct netbsd32___acl_aclcheck_file_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_aclcheck_file
+	},		/* 497 = netbsd32___acl_aclcheck_file */
+	{
+		ns(struct netbsd32___acl_aclcheck_fd_args),
+		.sy_call = (sy_call_t *)netbsd32___acl_aclcheck_fd
+	},		/* 498 = netbsd32___acl_aclcheck_fd */
+	{
+		ns(struct netbsd32_lpathconf_args),
+		.sy_call = (sy_call_t *)netbsd32_lpathconf
+	},		/* 499 = netbsd32_lpathconf */
 	{
 		.sy_call = sys_nosys,
 	},		/* 500 = filler */
Index: sys/compat/netbsd32/netbsd32_systrace_args.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_systrace_args.c,v
retrieving revision 1.43
diff -u -p -p -u -r1.43 netbsd32_systrace_args.c
--- sys/compat/netbsd32/netbsd32_systrace_args.c	26 Apr 2020 19:18:52 -0000	1.43
+++ sys/compat/netbsd32/netbsd32_systrace_args.c	15 May 2020 16:56:52 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_systrace_args.c,v 1.43 2020/04/26 19:18:52 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument to DTrace register array converstion.
@@ -3548,6 +3548,119 @@ systrace_args(register_t sysnum, const v
 		*n_args = 4;
 		break;
 	}
+	/* netbsd32___acl_get_link */
+	case 487: {
+		const struct netbsd32___acl_get_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_set_link */
+	case 488: {
+		const struct netbsd32___acl_set_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_delete_link */
+	case 489: {
+		const struct netbsd32___acl_delete_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* netbsd32___acl_aclcheck_link */
+	case 490: {
+		const struct netbsd32___acl_aclcheck_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_get_file */
+	case 491: {
+		const struct netbsd32___acl_get_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_set_file */
+	case 492: {
+		const struct netbsd32___acl_set_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_get_fd */
+	case 493: {
+		const struct netbsd32___acl_get_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_set_fd */
+	case 494: {
+		const struct netbsd32___acl_set_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_delete_file */
+	case 495: {
+		const struct netbsd32___acl_delete_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* netbsd32___acl_delete_fd */
+	case 496: {
+		const struct netbsd32___acl_delete_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* netbsd32___acl_aclcheck_file */
+	case 497: {
+		const struct netbsd32___acl_aclcheck_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32___acl_aclcheck_fd */
+	case 498: {
+		const struct netbsd32___acl_aclcheck_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp).i32; /* netbsd32_aclp_t */
+		*n_args = 3;
+		break;
+	}
+	/* netbsd32_lpathconf */
+	case 499: {
+		const struct netbsd32_lpathconf_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path).i32; /* const netbsd32_charp */
+		iarg[1] = SCARG(p, name); /* int */
+		*n_args = 2;
+		break;
+	}
 	default:
 		*n_args = 0;
 		break;
@@ -9597,6 +9710,202 @@ systrace_entry_setargdesc(int sysnum, in
 			break;
 		};
 		break;
+	/* netbsd32___acl_get_link */
+	case 487:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_set_link */
+	case 488:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_delete_link */
+	case 489:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_aclcheck_link */
+	case 490:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_get_file */
+	case 491:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_set_file */
+	case 492:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_get_fd */
+	case 493:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_set_fd */
+	case 494:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_delete_file */
+	case 495:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_delete_fd */
+	case 496:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_aclcheck_file */
+	case 497:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32___acl_aclcheck_fd */
+	case 498:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "netbsd32_aclp_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* netbsd32_lpathconf */
+	case 499:
+		switch(ndx) {
+		case 0:
+			p = "const netbsd32_charp";
+			break;
+		case 1:
+			p = "int";
+			break;
+		default:
+			break;
+		};
+		break;
 	default:
 		break;
 	};
@@ -11599,6 +11908,71 @@ systrace_return_setargdesc(int sysnum, i
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;
+	/* netbsd32___acl_get_link */
+	case 487:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_set_link */
+	case 488:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_delete_link */
+	case 489:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_aclcheck_link */
+	case 490:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_get_file */
+	case 491:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_set_file */
+	case 492:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_get_fd */
+	case 493:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_set_fd */
+	case 494:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_delete_file */
+	case 495:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_delete_fd */
+	case 496:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_aclcheck_file */
+	case 497:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32___acl_aclcheck_fd */
+	case 498:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* netbsd32_lpathconf */
+	case 499:
+		if (ndx == 0 || ndx == 1)
+			p = "long";
+		break;
 	default:
 		break;
 	};
Index: sys/compat/netbsd32/syscalls.master
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/syscalls.master,v
retrieving revision 1.137
diff -u -p -p -u -r1.137 syscalls.master
--- sys/compat/netbsd32/syscalls.master	26 Apr 2020 19:18:36 -0000	1.137
+++ sys/compat/netbsd32/syscalls.master	15 May 2020 16:56:52 -0000
@@ -1172,3 +1172,37 @@
 486	STD 		{ int|netbsd32|90|fhstatvfs1(netbsd32_voidp fhp, \
 			    netbsd32_size_t fh_size, netbsd32_statvfsp_t buf, \
 			    int flags); }
+487	STD		{ int|netbsd32||__acl_get_link( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+488	STD		{ int|netbsd32||__acl_set_link( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+489	STD		{ int|netbsd32||__acl_delete_link( \
+			    const netbsd32_charp path, \
+			    acl_type_t type); }
+490	STD		{ int|netbsd32||__acl_aclcheck_link( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+491	STD		{ int|netbsd32||__acl_get_file( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+492	STD		{ int|netbsd32||__acl_set_file( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+493	STD		{ int|netbsd32||__acl_get_fd(int filedes, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+494	STD		{ int|netbsd32||__acl_set_fd(int filedes, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+495	STD		{ int|netbsd32||__acl_delete_file( \
+			    const netbsd32_charp path, \
+			    acl_type_t type); }
+496	STD		{ int|netbsd32||__acl_delete_fd(int filedes, \
+			    acl_type_t type); }
+497	STD		{ int|netbsd32||__acl_aclcheck_file( \
+			    const netbsd32_charp path, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+498	STD		{ int|netbsd32||__acl_aclcheck_fd(int filedes, \
+			    acl_type_t type, netbsd32_aclp_t aclp); }
+499	STD		{ long|netbsd32||lpathconf(const netbsd32_charp path, \
+			    int name); }
Index: sys/fs/adosfs/advnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/adosfs/advnops.c,v
retrieving revision 1.53
diff -u -p -p -u -r1.53 advnops.c
--- sys/fs/adosfs/advnops.c	23 Apr 2020 21:47:07 -0000	1.53
+++ sys/fs/adosfs/advnops.c	15 May 2020 16:56:52 -0000
@@ -101,6 +101,7 @@ const struct vnodeopv_entry_desc adosfs_
 	{ &vop_open_desc, adosfs_open },		/* open */
 	{ &vop_close_desc, adosfs_close },		/* close */
 	{ &vop_access_desc, adosfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, adosfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, adosfs_setattr },		/* setattr */
 	{ &vop_read_desc, adosfs_read },		/* read */
@@ -749,7 +750,7 @@ reterr:
 }
 
 static int
-adosfs_check_possible(struct vnode *vp, struct anode *ap, mode_t mode)
+adosfs_check_possible(struct vnode *vp, struct anode *ap, accmode_t accmode)
 {
 
 	/*
@@ -757,7 +758,7 @@ adosfs_check_possible(struct vnode *vp, 
 	 * fifo, or a block or character device resident on the
 	 * file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -772,14 +773,14 @@ adosfs_check_possible(struct vnode *vp, 
 }
 
 static int
-adosfs_check_permitted(struct vnode *vp, struct anode *ap, mode_t mode,
+adosfs_check_permitted(struct vnode *vp, struct anode *ap, accmode_t accmode,
     kauth_cred_t cred)
 {
 	mode_t file_mode = adunixprot(ap->adprot) & ap->amp->mask;
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    file_mode, ap->uid, ap->gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp,
+	    cred, ap->uid, ap->gid, file_mode, NULL, accmode));
 }
 
 int
@@ -787,7 +788,7 @@ adosfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *sp = v;
 	struct anode *ap;
@@ -806,11 +807,11 @@ adosfs_access(void *v)
 	}
 #endif
 
-	error = adosfs_check_possible(vp, ap, sp->a_mode);
+	error = adosfs_check_possible(vp, ap, sp->a_accmode);
 	if (error)
 		return error;
 
-	error = adosfs_check_permitted(vp, ap, sp->a_mode, sp->a_cred);
+	error = adosfs_check_permitted(vp, ap, sp->a_accmode, sp->a_cred);
 
 #ifdef ADOSFS_DIAGNOSTIC
 	printf(" %d)", error);
Index: sys/fs/autofs/autofs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/autofs/autofs_vnops.c,v
retrieving revision 1.5
diff -u -p -p -u -r1.5 autofs_vnops.c
--- sys/fs/autofs/autofs_vnops.c	17 Jan 2020 20:08:07 -0000	1.5
+++ sys/fs/autofs/autofs_vnops.c	15 May 2020 16:56:52 -0000
@@ -591,6 +591,7 @@ static const struct vnodeopv_entry_desc 
 	{ &vop_open_desc,	autofs_open },
 	{ &vop_close_desc,	autofs_close },
 	{ &vop_access_desc,	autofs_access },
+	{ &vop_accessx_desc,	genfs_accessx },
 	{ &vop_getattr_desc,	autofs_getattr },
 	{ &vop_fsync_desc,	autofs_fsync },
 	{ &vop_mkdir_desc,	autofs_mkdir },
Index: sys/fs/cd9660/cd9660_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/cd9660/cd9660_vnops.c,v
retrieving revision 1.56
diff -u -p -p -u -r1.56 cd9660_vnops.c
--- sys/fs/cd9660/cd9660_vnops.c	23 Apr 2020 21:47:07 -0000	1.56
+++ sys/fs/cd9660/cd9660_vnops.c	15 May 2020 16:56:52 -0000
@@ -85,7 +85,7 @@ int	iso_uiodir(struct isoreaddir *, stru
 int	iso_shipdir(struct isoreaddir *);
 
 static int
-cd9660_check_possible(struct vnode *vp, struct iso_node *ip, mode_t mode)
+cd9660_check_possible(struct vnode *vp, struct iso_node *ip, accmode_t accmode)
 {
 
 	/*
@@ -93,7 +93,7 @@ cd9660_check_possible(struct vnode *vp, 
 	 * fifo, or a block or character device resident on the
 	 * file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -113,14 +113,14 @@ cd9660_check_possible(struct vnode *vp, 
  * super user is granted all permissions.
  */
 static int
-cd9660_check_permitted(struct vnode *vp, struct iso_node *ip, mode_t mode,
+cd9660_check_permitted(struct vnode *vp, struct iso_node *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    vp->v_type, ip->inode.iso_mode & ALLPERMS), vp, NULL,
-	    genfs_can_access(vp->v_type, ip->inode.iso_mode & ALLPERMS,
-	    ip->inode.iso_uid, ip->inode.iso_gid, mode, cred));
+	    genfs_can_access(vp, cred, ip->inode.iso_uid, ip->inode.iso_gid,
+	    ip->inode.iso_mode & ALLPERMS, NULL, accmode));
 }
 
 int
@@ -128,18 +128,18 @@ cd9660_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct iso_node *ip = VTOI(vp);
 	int error;
 
-	error = cd9660_check_possible(vp, ip, ap->a_mode);
+	error = cd9660_check_possible(vp, ip, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = cd9660_check_permitted(vp, ip, ap->a_mode, ap->a_cred);
+	error = cd9660_check_permitted(vp, ip, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -855,6 +855,7 @@ const struct vnodeopv_entry_desc cd9660_
 	{ &vop_open_desc, cd9660_open },		/* open */
 	{ &vop_close_desc, cd9660_close },		/* close */
 	{ &vop_access_desc, cd9660_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, cd9660_getattr },		/* getattr */
 	{ &vop_setattr_desc, cd9660_setattr },		/* setattr */
 	{ &vop_read_desc, cd9660_read },		/* read */
@@ -907,6 +908,7 @@ const struct vnodeopv_entry_desc cd9660_
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, spec_close },		/* close */
 	{ &vop_access_desc, cd9660_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, cd9660_getattr },		/* getattr */
 	{ &vop_setattr_desc, cd9660_setattr },		/* setattr */
 	{ &vop_read_desc, spec_read },			/* read */
@@ -957,6 +959,7 @@ const struct vnodeopv_entry_desc cd9660_
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
 	{ &vop_access_desc, cd9660_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, cd9660_getattr },		/* getattr */
 	{ &vop_setattr_desc, cd9660_setattr },		/* setattr */
 	{ &vop_read_desc, vn_fifo_bypass },		/* read */
Index: sys/fs/efs/efs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/efs/efs_vnops.c,v
retrieving revision 1.39
diff -u -p -p -u -r1.39 efs_vnops.c
--- sys/fs/efs/efs_vnops.c	23 Apr 2020 21:47:07 -0000	1.39
+++ sys/fs/efs/efs_vnops.c	15 May 2020 16:56:52 -0000
@@ -115,10 +115,10 @@ efs_lookup(void *v)
 }
 
 static int
-efs_check_possible(struct vnode *vp, struct efs_inode *eip, mode_t mode)
+efs_check_possible(struct vnode *vp, struct efs_inode *eip, accmode_t accmode)
 {
 
-	if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
+	if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
 		return (EROFS);
 
 	return 0;
@@ -131,13 +131,13 @@ efs_check_possible(struct vnode *vp, str
  * Returns 0 on success.
  */
 static int
-efs_check_permitted(struct vnode *vp, struct efs_inode *eip, mode_t mode,
+efs_check_permitted(struct vnode *vp, struct efs_inode *eip, accmode_t accmode,
     kauth_cred_t cred)
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, eip->ei_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    eip->ei_mode, eip->ei_uid, eip->ei_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, eip->ei_mode), vp, NULL, genfs_can_access(vp,
+	    cred, eip->ei_uid, eip->ei_gid, eip->ei_mode, NULL, accmode));
 }
 
 static int
@@ -146,18 +146,18 @@ efs_access(void *v)
 	struct vop_access_args /* {
 		const struct vnodeop_desc *a_desc;
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		struct ucred *a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct efs_inode *eip = EFS_VTOI(vp);
 	int error;
 
-	error = efs_check_possible(vp, eip, ap->a_mode);
+	error = efs_check_possible(vp, eip, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = efs_check_permitted(vp, eip, ap->a_mode, ap->a_cred);
+	error = efs_check_permitted(vp, eip, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -789,6 +789,7 @@ const struct vnodeopv_entry_desc efs_vno
 	{ &vop_open_desc,	genfs_nullop	},	/* open */
 	{ &vop_close_desc,	genfs_nullop	},	/* close */
 	{ &vop_access_desc,	efs_access	},	/* access */
+	{ &vop_accessx_desc,	genfs_accessx	},	/* accessx */
 	{ &vop_getattr_desc,	efs_getattr	},	/* getattr */
 	{ &vop_setattr_desc,	genfs_eopnotsupp},	/* setattr */
 	{ &vop_read_desc,	efs_read	},	/* read */
@@ -847,6 +848,7 @@ const struct vnodeopv_entry_desc efs_spe
 	{ &vop_open_desc,	spec_open	},	/* open */
 	{ &vop_close_desc,	spec_close	},	/* close */
 	{ &vop_access_desc,	efs_access	},	/* access */
+	{ &vop_accessx_desc,	genfs_accessx	},	/* accessx */
 	{ &vop_getattr_desc,	efs_getattr	},	/* getattr */
 	{ &vop_setattr_desc,	genfs_eopnotsupp},	/* setattr */
 	{ &vop_read_desc,	spec_read	},	/* read */
@@ -905,6 +907,7 @@ const struct vnodeopv_entry_desc efs_fif
 	{ &vop_open_desc,	vn_fifo_bypass	},	/* open */
 	{ &vop_close_desc,	vn_fifo_bypass	},	/* close */
 	{ &vop_access_desc,	efs_access	},	/* access */
+	{ &vop_accessx_desc,	genfs_accessx	},	/* accessx */
 	{ &vop_getattr_desc,	efs_getattr	},	/* getattr */
 	{ &vop_setattr_desc,	genfs_eopnotsupp},	/* setattr */
 	{ &vop_read_desc,	vn_fifo_bypass	},	/* read */
Index: sys/fs/filecorefs/filecore_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/filecorefs/filecore_vnops.c,v
retrieving revision 1.45
diff -u -p -p -u -r1.45 filecore_vnops.c
--- sys/fs/filecorefs/filecore_vnops.c	23 Apr 2020 21:47:07 -0000	1.45
+++ sys/fs/filecorefs/filecore_vnops.c	15 May 2020 16:56:52 -0000
@@ -122,14 +122,14 @@ filecore_check_possible(struct vnode *vp
  */
 static int
 filecore_check_permitted(struct vnode *vp, struct filecore_node *ip,
-    mode_t mode, kauth_cred_t cred)
+    accmode_t accmode, kauth_cred_t cred)
 {
 	struct filecore_mnt *fcmp = ip->i_mnt;
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    vp->v_type, filecore_mode(ip)), vp, NULL,
-	    genfs_can_access(vp->v_type, filecore_mode(ip), fcmp->fc_uid,
-	    fcmp->fc_gid, mode, cred));
+	    genfs_can_access(vp, cred, fcmp->fc_uid, fcmp->fc_gid,
+	    filecore_mode(ip), NULL, accmode));
 }
 
 int
@@ -137,18 +137,18 @@ filecore_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct filecore_node *ip = VTOI(vp);
 	int error;
 
-	error = filecore_check_possible(vp, ip, ap->a_mode);
+	error = filecore_check_possible(vp, ip, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = filecore_check_permitted(vp, ip, ap->a_mode, ap->a_cred);
+	error = filecore_check_permitted(vp, ip, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -560,6 +560,7 @@ const struct vnodeopv_entry_desc filecor
 	{ &vop_open_desc, filecore_open },		/* open */
 	{ &vop_close_desc, filecore_close },		/* close */
 	{ &vop_access_desc, filecore_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, filecore_getattr },	/* getattr */
 	{ &vop_setattr_desc, filecore_setattr },	/* setattr */
 	{ &vop_read_desc, filecore_read },		/* read */
Index: sys/fs/hfs/hfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/hfs/hfs_vnops.c,v
retrieving revision 1.35
diff -u -p -p -u -r1.35 hfs_vnops.c
--- sys/fs/hfs/hfs_vnops.c	23 Apr 2020 21:47:07 -0000	1.35
+++ sys/fs/hfs/hfs_vnops.c	15 May 2020 16:56:52 -0000
@@ -162,6 +162,7 @@ const struct vnodeopv_entry_desc hfs_vno
 	{ &vop_open_desc, hfs_vop_open },		/* open */
 	{ &vop_close_desc, hfs_vop_close },		/* close */
 	{ &vop_access_desc, hfs_vop_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
 	{ &vop_read_desc, hfs_vop_read },		/* read */
@@ -218,6 +219,7 @@ const struct vnodeopv_entry_desc hfs_spe
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, spec_close },		/* close */
 	{ &vop_access_desc, hfs_vop_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
 	{ &vop_read_desc, spec_read },			/* read */
@@ -276,6 +278,7 @@ const struct vnodeopv_entry_desc hfs_fif
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
 	{ &vop_access_desc, hfs_vop_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
 	{ &vop_read_desc, vn_fifo_bypass },		/* read */
@@ -531,7 +534,7 @@ hfs_vop_close(void *v)
 }
 
 static int
-hfs_check_possible(struct vnode *vp, mode_t mode)
+hfs_check_possible(struct vnode *vp, accmode_t accmode)
 {
 
 	/*
@@ -539,7 +542,7 @@ hfs_check_possible(struct vnode *vp, mod
 	 * since we have no write support yet.
 	 */
 
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -554,13 +557,13 @@ hfs_check_possible(struct vnode *vp, mod
 }
 
 static int
-hfs_check_permitted(vnode_t *vp, struct vattr *va, mode_t mode,
+hfs_check_permitted(vnode_t *vp, struct vattr *va, accmode_t accmode,
     kauth_cred_t cred)
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    va->va_type, va->va_mode), vp, NULL,  genfs_can_access(va->va_type,
-	    va->va_mode, va->va_uid, va->va_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    va->va_type, va->va_mode), vp, NULL,  genfs_can_access(vp, cred,
+	    va->va_uid, va->va_gid, va->va_mode, NULL, accmode));
 }
 
 int
@@ -568,7 +571,7 @@ hfs_vop_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		int a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vattr va;
@@ -576,14 +579,14 @@ hfs_vop_access(void *v)
 
 	DPRINTF(("VOP = hfs_vop_access()\n"));
 
-	error = hfs_check_possible(ap->a_vp, ap->a_mode);
+	error = hfs_check_possible(ap->a_vp, ap->a_accmode);
 	if (error)
 		return error;
 
 	if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
 		return error;
 
-	error = hfs_check_permitted(ap->a_vp, &va, ap->a_mode, ap->a_cred);
+	error = hfs_check_permitted(ap->a_vp, &va, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
Index: sys/fs/msdosfs/msdosfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_vnops.c,v
retrieving revision 1.102
diff -u -p -p -u -r1.102 msdosfs_vnops.c
--- sys/fs/msdosfs/msdosfs_vnops.c	23 Apr 2020 21:47:07 -0000	1.102
+++ sys/fs/msdosfs/msdosfs_vnops.c	15 May 2020 16:56:52 -0000
@@ -180,7 +180,7 @@ msdosfs_close(void *v)
 }
 
 static int
-msdosfs_check_possible(struct vnode *vp, struct denode *dep, mode_t mode)
+msdosfs_check_possible(struct vnode *vp, struct denode *dep, accmode_t accmode)
 {
 
 	/*
@@ -188,7 +188,7 @@ msdosfs_check_possible(struct vnode *vp,
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -204,7 +204,7 @@ msdosfs_check_possible(struct vnode *vp,
 }
 
 static int
-msdosfs_check_permitted(struct vnode *vp, struct denode *dep, mode_t mode,
+msdosfs_check_permitted(struct vnode *vp, struct denode *dep, accmode_t accmode,
     kauth_cred_t cred)
 {
 	struct msdosfsmount *pmp = dep->de_pmp;
@@ -217,9 +217,9 @@ msdosfs_check_permitted(struct vnode *vp
 
 	file_mode &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask);
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    file_mode, pmp->pm_uid, pmp->pm_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp, cred,
+	    pmp->pm_uid, pmp->pm_gid, file_mode, NULL, accmode));
 }
 
 int
@@ -227,18 +227,18 @@ msdosfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct denode *dep = VTODE(vp);
 	int error;
 
-	error = msdosfs_check_possible(vp, dep, ap->a_mode);
+	error = msdosfs_check_possible(vp, dep, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = msdosfs_check_permitted(vp, dep, ap->a_mode, ap->a_cred);
+	error = msdosfs_check_permitted(vp, dep, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -371,8 +371,8 @@ msdosfs_setattr(void *v)
 			goto bad;
 		}
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES,
-		    ap->a_vp, NULL, genfs_can_chtimes(ap->a_vp, vap->va_vaflags,
-		    pmp->pm_uid, cred));
+		    ap->a_vp, NULL, genfs_can_chtimes(ap->a_vp, cred,
+			pmp->pm_uid, vap->va_vaflags));
 		if (error)
 			goto bad;
 		if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
@@ -395,7 +395,7 @@ msdosfs_setattr(void *v)
 			goto bad;
 		}
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp,
-		    NULL, genfs_can_chflags(cred, vp->v_type, pmp->pm_uid, false));
+		    NULL, genfs_can_chflags(vp, cred, pmp->pm_uid, false));
 		if (error)
 			goto bad;
 		/* We ignore the read and execute bits. */
@@ -415,7 +415,7 @@ msdosfs_setattr(void *v)
 			goto bad;
 		}
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp,
-		    NULL, genfs_can_chflags(cred, vp->v_type, pmp->pm_uid, false));
+		    NULL, genfs_can_chflags(vp, cred, pmp->pm_uid, false));
 		if (error)
 			goto bad;
 		if (vap->va_flags & SF_ARCHIVED)
@@ -1847,6 +1847,7 @@ const struct vnodeopv_entry_desc msdosfs
 	{ &vop_open_desc, genfs_nullop },		/* open */
 	{ &vop_close_desc, msdosfs_close },		/* close */
 	{ &vop_access_desc, msdosfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, msdosfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, msdosfs_setattr },		/* setattr */
 	{ &vop_read_desc, msdosfs_read },		/* read */
Index: sys/fs/nilfs/nilfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/nilfs/nilfs_vnops.c,v
retrieving revision 1.40
diff -u -p -p -u -r1.40 nilfs_vnops.c
--- sys/fs/nilfs/nilfs_vnops.c	23 Apr 2020 21:47:07 -0000	1.40
+++ sys/fs/nilfs/nilfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -987,7 +987,7 @@ nilfs_close(void *v)
 /* --------------------------------------------------------------------- */
 
 static int
-nilfs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode)
+nilfs_check_possible(struct vnode *vp, struct vattr *vap, accmode_t accmode)
 {
 	int flags;
 
@@ -1000,7 +1000,7 @@ nilfs_check_possible(struct vnode *vp, s
 		 * normal nodes: check if we're on a read-only mounted
 		 * filingsystem and bomb out if we're trying to write.
 		 */
-		if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
+		if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
 			return EROFS;
 		break;
 	case VBLK:
@@ -1020,21 +1020,21 @@ nilfs_check_possible(struct vnode *vp, s
 	/* noone may write immutable files */
 	/* TODO: get chflags(2) flags */
 	flags = 0;
-	if ((mode & VWRITE) && (flags & IMMUTABLE))
+	if ((accmode & VWRITE) && (flags & IMMUTABLE))
 		return EPERM;
 
 	return 0;
 }
 
 static int
-nilfs_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode,
+nilfs_check_permitted(struct vnode *vp, struct vattr *vap, accmode_t accmode,
     kauth_cred_t cred)
 {
 
 	/* ask the generic genfs_can_access to advice on security */
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    vap->va_mode, vap->va_uid, vap->va_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp, cred,
+	    vap->va_uid, vap->va_gid, vap->va_mode, NULL, accmode));
 }
 
 int
@@ -1042,12 +1042,12 @@ nilfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 		struct proc *a_p;
 	} */ *ap = v;
 	struct vnode    *vp   = ap->a_vp;
-	mode_t	         mode = ap->a_mode;
+	accmode_t        accmode = ap->a_accmode;
 	kauth_cred_t     cred = ap->a_cred;
 	/* struct nilfs_node *nilfs_node = VTOI(vp); */
 	struct vattr vap;
@@ -1059,11 +1059,11 @@ nilfs_access(void *v)
 	if (error)
 		return error;
 
-	error = nilfs_check_possible(vp, &vap, mode);
+	error = nilfs_check_possible(vp, &vap, accmode);
 	if (error)
 		return error;
 
-	error = nilfs_check_permitted(vp, &vap, mode, cred);
+	error = nilfs_check_permitted(vp, &vap, accmode, cred);
 
 	return error;
 }
@@ -1549,6 +1549,7 @@ const struct vnodeopv_entry_desc nilfs_v
 	{ &vop_open_desc, nilfs_open },		/* open */
 	{ &vop_close_desc, nilfs_close },	/* close */
 	{ &vop_access_desc, nilfs_access },	/* access */
+	{ &vop_accessx_desc, genfs_accessx },	/* accessx */
 	{ &vop_getattr_desc, nilfs_getattr },	/* getattr */
 	{ &vop_setattr_desc, nilfs_setattr },	/* setattr */	/* TODO chflags */
 	{ &vop_read_desc, nilfs_read },		/* read */
Index: sys/fs/ntfs/ntfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ntfs/ntfs_vnops.c,v
retrieving revision 1.63
diff -u -p -p -u -r1.63 ntfs_vnops.c
--- sys/fs/ntfs/ntfs_vnops.c	26 May 2017 14:34:20 -0000	1.63
+++ sys/fs/ntfs/ntfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -399,7 +399,7 @@ ntfs_write(void *v)
 }
 
 static int
-ntfs_check_possible(struct vnode *vp, struct ntnode *ip, mode_t mode)
+ntfs_check_possible(struct vnode *vp, struct ntnode *ip, accmode_t accmode)
 {
 
 	/*
@@ -407,7 +407,7 @@ ntfs_check_possible(struct vnode *vp, st
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch ((int)vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -422,16 +422,16 @@ ntfs_check_possible(struct vnode *vp, st
 }
 
 static int
-ntfs_check_permitted(struct vnode *vp, struct ntnode *ip, mode_t mode,
+ntfs_check_permitted(struct vnode *vp, struct ntnode *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 	mode_t file_mode;
 
 	file_mode = ip->i_mp->ntm_mode | (S_IXUSR|S_IXGRP|S_IXOTH);
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
-	    file_mode), vp, NULL, genfs_can_access(vp->v_type, file_mode,
-	    ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp, cred,
+	    ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, file_mode, NULL, accmode));
 }
 
 int
@@ -439,7 +439,7 @@ ntfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
@@ -448,11 +448,11 @@ ntfs_access(void *v)
 
 	dprintf(("ntfs_access: %llu\n", (unsigned long long)ip->i_number));
 
-	error = ntfs_check_possible(vp, ip, ap->a_mode);
+	error = ntfs_check_possible(vp, ip, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = ntfs_check_permitted(vp, ip, ap->a_mode, ap->a_cred);
+	error = ntfs_check_permitted(vp, ip, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -814,6 +814,7 @@ const struct vnodeopv_entry_desc ntfs_vn
 	{ &vop_open_desc, (vop_t *) ntfs_open },	/* open */
 	{ &vop_close_desc,(vop_t *)  ntfs_close },	/* close */
 	{ &vop_access_desc, (vop_t *) ntfs_access },	/* access */
+	{ &vop_accessx_desc, (vop_t *) genfs_accessx },	/* accessx */
 	{ &vop_getattr_desc, (vop_t *) ntfs_getattr },	/* getattr */
 	{ &vop_setattr_desc, genfs_eopnotsupp },	/* setattr */
 	{ &vop_read_desc, (vop_t *) ntfs_read },	/* read */
Index: sys/fs/ptyfs/ptyfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ptyfs/ptyfs_vnops.c,v
retrieving revision 1.58
diff -u -p -p -u -r1.58 ptyfs_vnops.c
--- sys/fs/ptyfs/ptyfs_vnops.c	13 Apr 2020 19:23:18 -0000	1.58
+++ sys/fs/ptyfs/ptyfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -172,6 +172,7 @@ const struct vnodeopv_entry_desc ptyfs_v
 	{ &vop_open_desc, ptyfs_open },			/* open */
 	{ &vop_close_desc, ptyfs_close },		/* close */
 	{ &vop_access_desc, ptyfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ptyfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ptyfs_setattr },		/* setattr */
 	{ &vop_read_desc, ptyfs_read },			/* read */
@@ -435,7 +436,7 @@ ptyfs_setattr(void *v)
 		}
 
 		error = kauth_authorize_vnode(cred, action, vp, NULL,
-		    genfs_can_chflags(cred, vp->v_type, ptyfs->ptyfs_uid,
+		    genfs_can_chflags(vp, cred, ptyfs->ptyfs_uid,
 		    changing_sysflags));
 		if (error)
 			return error;
@@ -469,8 +470,8 @@ ptyfs_setattr(void *v)
 		if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
 			return EPERM;
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags,
-		    ptyfs->ptyfs_uid, cred));
+		    NULL, genfs_can_chtimes(vp, cred, ptyfs->ptyfs_uid,
+		    vap->va_vaflags));
 		if (error)
 			return (error);
 		if (vap->va_atime.tv_sec != VNOVAL)
@@ -516,8 +517,8 @@ ptyfs_chmod(struct vnode *vp, mode_t mod
 	int error;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, ptyfs->ptyfs_uid,
-	    ptyfs->ptyfs_gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid,
+	    mode));
 	if (error)
 		return (error);
 
@@ -543,7 +544,7 @@ ptyfs_chown(struct vnode *vp, uid_t uid,
 		gid = ptyfs->ptyfs_gid;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid,
+	    NULL, genfs_can_chown(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid,
 	    uid, gid));
 	if (error)
 		return (error);
@@ -567,7 +568,7 @@ ptyfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vattr va;
@@ -577,9 +578,9 @@ ptyfs_access(void *v)
 		return error;
 
 	return kauth_authorize_vnode(ap->a_cred,
-	    KAUTH_ACCESS_ACTION(ap->a_mode, ap->a_vp->v_type, va.va_mode),
-	    ap->a_vp, NULL, genfs_can_access(va.va_type, va.va_mode, va.va_uid,
-	    va.va_gid, ap->a_mode, ap->a_cred));
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode),
+	    ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred, va.va_uid,
+	    va.va_gid, va.va_mode, NULL, ap->a_accmode));
 }
 
 /*
Index: sys/fs/puffs/puffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_vnops.c,v
retrieving revision 1.215
diff -u -p -p -u -r1.215 puffs_vnops.c
--- sys/fs/puffs/puffs_vnops.c	23 Apr 2020 21:47:07 -0000	1.215
+++ sys/fs/puffs/puffs_vnops.c	15 May 2020 16:56:53 -0000
@@ -111,6 +111,7 @@ const struct vnodeopv_entry_desc puffs_v
         { &vop_open_desc, puffs_vnop_open },		/* REAL open */
         { &vop_close_desc, puffs_vnop_checkop },	/* close */
         { &vop_access_desc, puffs_vnop_access },	/* REAL access */
+        { &vop_accessx_desc, genfs_accessx },		/* accessx */
         { &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
         { &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
         { &vop_read_desc, puffs_vnop_checkop },		/* read */
@@ -168,6 +169,7 @@ const struct vnodeopv_entry_desc puffs_s
 	{ &vop_open_desc, spec_open },			/* spec_open */
 	{ &vop_close_desc, spec_close },		/* spec_close */
 	{ &vop_access_desc, puffs_vnop_checkop },	/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
 	{ &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
 	{ &vop_read_desc, puffs_vnop_spec_read },	/* update, read */
@@ -227,6 +229,7 @@ const struct vnodeopv_entry_desc puffs_f
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
 	{ &vop_access_desc, puffs_vnop_checkop },	/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
 	{ &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
 	{ &vop_read_desc, puffs_vnop_fifo_read },	/* read, update */
@@ -285,6 +288,7 @@ const struct vnodeopv_entry_desc puffs_m
         { &vop_open_desc, puffs_vnop_open },		/* open */
         { &vop_close_desc, puffs_vnop_close },		/* close */
         { &vop_access_desc, puffs_vnop_access },	/* access */
+        { &vop_accessx_desc, genfs_accessx },		/* accessx */
         { &vop_getattr_desc, puffs_vnop_getattr },	/* getattr */
         { &vop_setattr_desc, puffs_vnop_setattr },	/* setattr */
         { &vop_read_desc, puffs_vnop_read },		/* read */
@@ -959,16 +963,16 @@ puffs_vnop_access(void *v)
 	struct vop_access_args /* {
 		const struct vnodeop_desc *a_desc;
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	PUFFS_MSG_VARS(vn, access);
 	struct vnode *vp = ap->a_vp;
 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
-	int mode = ap->a_mode;
+	accmode_t accmode = ap->a_accmode;
 	int error;
 
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -986,7 +990,7 @@ puffs_vnop_access(void *v)
 		return 0;
 
 	PUFFS_MSG_ALLOC(vn, access);
-	access_msg->pvnr_mode = ap->a_mode;
+	access_msg->pvnr_mode = ap->a_accmode;
 	puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
 	puffs_msg_setinfo(park_access, PUFFSOP_VN,
 	    PUFFS_VN_ACCESS, VPTOPNC(vp));
Index: sys/fs/sysvbfs/sysvbfs.c
===================================================================
RCS file: /cvsroot/src/sys/fs/sysvbfs/sysvbfs.c,v
retrieving revision 1.17
diff -u -p -p -u -r1.17 sysvbfs.c
--- sys/fs/sysvbfs/sysvbfs.c	28 May 2018 21:04:37 -0000	1.17
+++ sys/fs/sysvbfs/sysvbfs.c	15 May 2020 16:56:53 -0000
@@ -55,6 +55,7 @@ const struct vnodeopv_entry_desc sysvbfs
 	{ &vop_open_desc, sysvbfs_open },		/* open */
 	{ &vop_close_desc, sysvbfs_close },		/* close */
 	{ &vop_access_desc, sysvbfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, sysvbfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, sysvbfs_setattr },		/* setattr */
 	{ &vop_read_desc, sysvbfs_read },		/* read */
Index: sys/fs/sysvbfs/sysvbfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/sysvbfs/sysvbfs_vnops.c,v
retrieving revision 1.65
diff -u -p -p -u -r1.65 sysvbfs_vnops.c
--- sys/fs/sysvbfs/sysvbfs_vnops.c	23 Apr 2020 21:47:08 -0000	1.65
+++ sys/fs/sysvbfs/sysvbfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -249,13 +249,13 @@ sysvbfs_check_possible(struct vnode *vp,
 
 static int
 sysvbfs_check_permitted(struct vnode *vp, struct sysvbfs_node *bnode,
-    mode_t mode, kauth_cred_t cred)
+    accmode_t accmode, kauth_cred_t cred)
 {
 	struct bfs_fileattr *attr = &bnode->inode->attr;
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, attr->mode), vp, NULL, genfs_can_access(vp->v_type,
-	    attr->mode, attr->uid, attr->gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, attr->mode), vp, NULL, genfs_can_access(vp, cred,
+	    attr->uid, attr->gid, attr->mode, NULL, accmode));
 }
 
 int
@@ -263,7 +263,7 @@ sysvbfs_access(void *arg)
 {
 	struct vop_access_args /* {
 		struct vnode	*a_vp;
-		int		a_mode;
+		accmode_t	a_accmode;
 		kauth_cred_t	a_cred;
 	} */ *ap = arg;
 	struct vnode *vp = ap->a_vp;
@@ -272,11 +272,11 @@ sysvbfs_access(void *arg)
 
 	DPRINTF("%s:\n", __func__);
 
-	error = sysvbfs_check_possible(vp, bnode, ap->a_mode);
+	error = sysvbfs_check_possible(vp, bnode, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = sysvbfs_check_permitted(vp, bnode, ap->a_mode, ap->a_cred);
+	error = sysvbfs_check_permitted(vp, bnode, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -359,7 +359,7 @@ sysvbfs_setattr(void *arg)
 		    (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->gid;
 		error = kauth_authorize_vnode(cred,
 		    KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
-		    genfs_can_chown(cred, attr->uid, attr->gid, uid, gid));
+		    genfs_can_chown(vp, cred, attr->uid, attr->gid, uid, gid));
 		if (error)
 			return error;
 		attr->uid = uid;
@@ -386,7 +386,7 @@ sysvbfs_setattr(void *arg)
 	if (vap->va_mode != (mode_t)VNOVAL) {
 		mode_t mode = vap->va_mode;
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
-		    vp, NULL, genfs_can_chmod(vp->v_type, cred, attr->uid,
+		    vp, NULL, genfs_can_chmod(vp, cred, attr->uid,
 		    attr->gid, mode));
 		if (error)
 			return error;
@@ -397,8 +397,8 @@ sysvbfs_setattr(void *arg)
 	    (vap->va_mtime.tv_sec != VNOVAL) ||
 	    (vap->va_ctime.tv_sec != VNOVAL)) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, attr->uid,
-		    cred));
+		    NULL, genfs_can_chtimes(vp, cred, attr->uid,
+			vap->va_vaflags));
 		if (error)
 			return error;
 
Index: sys/fs/tmpfs/tmpfs_fifoops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_fifoops.c,v
retrieving revision 1.11
diff -u -p -p -u -r1.11 tmpfs_fifoops.c
--- sys/fs/tmpfs/tmpfs_fifoops.c	25 Jul 2014 08:20:52 -0000	1.11
+++ sys/fs/tmpfs/tmpfs_fifoops.c	15 May 2020 16:56:53 -0000
@@ -55,6 +55,7 @@ const struct vnodeopv_entry_desc tmpfs_f
 	{ &vop_open_desc,		tmpfs_fifo_open },
 	{ &vop_close_desc,		tmpfs_fifo_close },
 	{ &vop_access_desc,		tmpfs_fifo_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		tmpfs_fifo_getattr },
 	{ &vop_setattr_desc,		tmpfs_fifo_setattr },
 	{ &vop_read_desc,		tmpfs_fifo_read },
Index: sys/fs/tmpfs/tmpfs_specops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_specops.c,v
retrieving revision 1.12
diff -u -p -p -u -r1.12 tmpfs_specops.c
--- sys/fs/tmpfs/tmpfs_specops.c	25 Jul 2014 08:20:52 -0000	1.12
+++ sys/fs/tmpfs/tmpfs_specops.c	15 May 2020 16:56:53 -0000
@@ -58,6 +58,7 @@ const struct vnodeopv_entry_desc tmpfs_s
 	{ &vop_open_desc,		tmpfs_spec_open },
 	{ &vop_close_desc,		tmpfs_spec_close },
 	{ &vop_access_desc,		tmpfs_spec_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		tmpfs_spec_getattr },
 	{ &vop_setattr_desc,		tmpfs_spec_setattr },
 	{ &vop_read_desc,		tmpfs_spec_read },
Index: sys/fs/tmpfs/tmpfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_subr.c,v
retrieving revision 1.110
diff -u -p -p -u -r1.110 tmpfs_subr.c
--- sys/fs/tmpfs/tmpfs_subr.c	12 May 2020 23:17:41 -0000	1.110
+++ sys/fs/tmpfs/tmpfs_subr.c	15 May 2020 16:56:53 -0000
@@ -988,8 +988,7 @@ tmpfs_chflags(vnode_t *vp, int flags, ka
 	}
 
 	error = kauth_authorize_vnode(cred, action, vp, NULL,
-	    genfs_can_chflags(cred, vp->v_type, node->tn_uid,
-	    changing_sysflags));
+	    genfs_can_chflags(vp, cred, node->tn_uid, changing_sysflags));
 	if (error)
 		return error;
 
@@ -1034,7 +1033,7 @@ tmpfs_chmod(vnode_t *vp, mode_t mode, ka
 		return EPERM;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, node->tn_uid, node->tn_gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, node->tn_uid, node->tn_gid, mode));
 	if (error) {
 		return error;
 	}
@@ -1077,7 +1076,7 @@ tmpfs_chown(vnode_t *vp, uid_t uid, gid_
 		return EPERM;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, node->tn_uid, node->tn_gid, uid,
+	    NULL, genfs_can_chown(vp, cred, node->tn_uid, node->tn_gid, uid,
 	    gid));
 	if (error) {
 		return error;
@@ -1164,7 +1163,7 @@ tmpfs_chtimes(vnode_t *vp, const struct 
 		return EPERM;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, NULL,
-	    genfs_can_chtimes(vp, vaflags, node->tn_uid, cred));
+	    genfs_can_chtimes(vp, cred, node->tn_uid, vaflags));
 	if (error)
 		return error;
 
Index: sys/fs/tmpfs/tmpfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_vnops.c,v
retrieving revision 1.136
diff -u -p -p -u -r1.136 tmpfs_vnops.c
--- sys/fs/tmpfs/tmpfs_vnops.c	23 Apr 2020 21:47:08 -0000	1.136
+++ sys/fs/tmpfs/tmpfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -70,6 +70,7 @@ const struct vnodeopv_entry_desc tmpfs_v
 	{ &vop_open_desc,		tmpfs_open },
 	{ &vop_close_desc,		tmpfs_close },
 	{ &vop_access_desc,		tmpfs_access },
+	{ &vop_accessx_desc,		genfs_accessx },
 	{ &vop_getattr_desc,		tmpfs_getattr },
 	{ &vop_setattr_desc,		tmpfs_setattr },
 	{ &vop_read_desc,		tmpfs_read },
@@ -269,7 +270,7 @@ tmpfs_lookup(void *v)
 		if ((dnode->tn_mode & S_ISTXT) != 0) {
 			error = kauth_authorize_vnode(cnp->cn_cred,
 			    KAUTH_VNODE_DELETE, tnode->tn_vnode,
-			    dnode->tn_vnode, genfs_can_sticky(cnp->cn_cred,
+			    dnode->tn_vnode, genfs_can_sticky(dvp, cnp->cn_cred,
 			    dnode->tn_uid, tnode->tn_uid));
 			if (error) {
 				error = EPERM;
@@ -377,14 +378,14 @@ tmpfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode	*a_vp;
-		int		a_mode;
+		accmode_t	a_accmode;
 		kauth_cred_t	a_cred;
 	} */ *ap = v;
 	vnode_t *vp = ap->a_vp;
-	mode_t mode = ap->a_mode;
+	accmode_t accmode = ap->a_accmode;
 	kauth_cred_t cred = ap->a_cred;
 	tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
-	const bool writing = (mode & VWRITE) != 0;
+	const bool writing = (accmode & VWRITE) != 0;
 
 	KASSERT(VOP_ISLOCKED(vp));
 
@@ -409,9 +410,9 @@ tmpfs_access(void *v)
 		return EPERM;
 	}
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, node->tn_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    node->tn_mode, node->tn_uid, node->tn_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, node->tn_mode), vp, NULL, genfs_can_access(vp, cred,
+	    node->tn_uid, node->tn_gid, node->tn_mode, NULL, accmode));
 }
 
 int
Index: sys/fs/udf/udf_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/udf/udf_vnops.c,v
retrieving revision 1.112
diff -u -p -p -u -r1.112 udf_vnops.c
--- sys/fs/udf/udf_vnops.c	23 Apr 2020 21:47:08 -0000	1.112
+++ sys/fs/udf/udf_vnops.c	15 May 2020 16:56:53 -0000
@@ -826,7 +826,7 @@ udf_lookup(void *v)
 			udf_getownership(dir_node, &d_uid, &d_gid);
 			error = kauth_authorize_vnode(cnp->cn_cred,
 			    KAUTH_VNODE_DELETE, res_node->vnode,
-			    dir_node->vnode, genfs_can_sticky(cnp->cn_cred,
+			    dir_node->vnode, genfs_can_sticky(dvp, cnp->cn_cred,
 			    d_uid, d_uid));
 			if (error) {
 				error = EPERM;
@@ -1041,7 +1041,7 @@ udf_chown(struct vnode *vp, uid_t new_ui
 
 	/* check permissions */
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP,
-	    vp, NULL, genfs_can_chown(cred, uid, gid, new_uid, new_gid));
+	    vp, NULL, genfs_can_chown(vp, cred, uid, gid, new_uid, new_gid));
 	if (error)
 		return (error);
 
@@ -1078,7 +1078,7 @@ udf_chmod(struct vnode *vp, mode_t mode,
 
 	/* check permissions */
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, uid, gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, uid, gid, mode));
 	if (error)
 		return (error);
 
@@ -1187,7 +1187,7 @@ udf_chtimes(struct vnode *vp,
 
 	/* check permissions */
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-	    NULL, genfs_can_chtimes(vp, setattrflags, uid, cred));
+	    NULL, genfs_can_chtimes(vp, cred, uid, setattrflags));
 	if (error)
 		return (error);
 
@@ -1437,13 +1437,13 @@ udf_check_possible(struct vnode *vp, str
 }
 
 static int
-udf_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode,
+udf_check_permitted(struct vnode *vp, struct vattr *vap, accmode_t accmode,
     kauth_cred_t cred)
 {
 	/* ask the generic genfs_can_access to advice on security */
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    vap->va_mode, vap->va_uid, vap->va_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp, cred,
+	    vap->va_uid, vap->va_gid, vap->va_mode, NULL, accmode));
 }
 
 int
@@ -1451,12 +1451,12 @@ udf_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 		struct proc *a_p;
 	} */ *ap = v;
 	struct vnode    *vp   = ap->a_vp;
-	mode_t	         mode = ap->a_mode;
+	accmode_t	 accmode = ap->a_accmode;
 	kauth_cred_t     cred = ap->a_cred;
 	/* struct udf_node *udf_node = VTOI(vp); */
 	struct vattr vap;
@@ -1468,11 +1468,11 @@ udf_access(void *v)
 	if (error)
 		return error;
 
-	error = udf_check_possible(vp, &vap, mode);
+	error = udf_check_possible(vp, &vap, accmode);
 	if (error)
 		return error;
 
-	error = udf_check_permitted(vp, &vap, mode, cred);
+	error = udf_check_permitted(vp, &vap, accmode, cred);
 
 	return error;
 }
@@ -2179,6 +2179,7 @@ const struct vnodeopv_entry_desc udf_vno
 	{ &vop_open_desc, udf_open },		/* open */
 	{ &vop_close_desc, udf_close },		/* close */
 	{ &vop_access_desc, udf_access },	/* access */
+	{ &vop_accessx_desc, genfs_accessx },	/* accessx */
 	{ &vop_getattr_desc, udf_getattr },	/* getattr */
 	{ &vop_setattr_desc, udf_setattr },	/* setattr */	/* TODO chflags */
 	{ &vop_read_desc, udf_read },		/* read */
Index: sys/fs/union/union_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/union/union_vnops.c,v
retrieving revision 1.72
diff -u -p -p -u -r1.72 union_vnops.c
--- sys/fs/union/union_vnops.c	23 Feb 2020 15:46:41 -0000	1.72
+++ sys/fs/union/union_vnops.c	15 May 2020 16:56:53 -0000
@@ -151,6 +151,7 @@ const struct vnodeopv_entry_desc union_v
 	{ &vop_open_desc, union_open },			/* open */
 	{ &vop_close_desc, union_close },		/* close */
 	{ &vop_access_desc, union_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, union_getattr },		/* getattr */
 	{ &vop_setattr_desc, union_setattr },		/* setattr */
 	{ &vop_read_desc, union_read },			/* read */
@@ -708,7 +709,7 @@ union_access(void *v)
 	struct vop_access_args /* {
 		struct vnodeop_desc *a_desc;
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
@@ -721,7 +722,7 @@ union_access(void *v)
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (ap->a_mode & VWRITE) {
+	if (ap->a_accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
Index: sys/fs/unionfs/unionfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/unionfs/unionfs_vnops.c,v
retrieving revision 1.13
diff -u -p -p -u -r1.13 unionfs_vnops.c
--- sys/fs/unionfs/unionfs_vnops.c	23 Feb 2020 15:46:41 -0000	1.13
+++ sys/fs/unionfs/unionfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -1821,6 +1821,7 @@ const struct vnodeopv_entry_desc unionfs
 	{ &vop_open_desc, unionfs_open },		/* open */
 	{ &vop_close_desc, unionfs_close },		/* close */
 	{ &vop_access_desc, unionfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, unionfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, unionfs_setattr },		/* setattr */
 	{ &vop_read_desc, unionfs_read },		/* read */
Index: sys/fs/v7fs/v7fs_extern.c
===================================================================
RCS file: /cvsroot/src/sys/fs/v7fs/v7fs_extern.c,v
retrieving revision 1.6
diff -u -p -p -u -r1.6 v7fs_extern.c
--- sys/fs/v7fs/v7fs_extern.c	28 May 2018 21:04:38 -0000	1.6
+++ sys/fs/v7fs/v7fs_extern.c	15 May 2020 16:56:53 -0000
@@ -61,6 +61,7 @@ const struct vnodeopv_entry_desc v7fs_vn
 	{ &vop_open_desc, v7fs_open },			/* open */
 	{ &vop_close_desc, v7fs_close },		/* close */
 	{ &vop_access_desc, v7fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, v7fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, v7fs_setattr },		/* setattr */
 	{ &vop_read_desc, v7fs_read },			/* read */
@@ -110,6 +111,7 @@ const struct vnodeopv_entry_desc v7fs_sp
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, spec_close },		/* close */
 	{ &vop_access_desc, v7fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, v7fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, v7fs_setattr },		/* setattr */
 	{ &vop_read_desc, spec_read },			/* read */
@@ -158,6 +160,7 @@ const struct vnodeopv_entry_desc v7fs_fi
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
 	{ &vop_access_desc, v7fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, v7fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, v7fs_setattr },		/* setattr */
 	{ &vop_read_desc, vn_fifo_bypass },		/* read */
Index: sys/fs/v7fs/v7fs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/v7fs/v7fs_vnops.c,v
retrieving revision 1.29
diff -u -p -p -u -r1.29 v7fs_vnops.c
--- sys/fs/v7fs/v7fs_vnops.c	23 Apr 2020 21:47:08 -0000	1.29
+++ sys/fs/v7fs/v7fs_vnops.c	15 May 2020 16:56:53 -0000
@@ -372,33 +372,33 @@ v7fs_check_possible(struct vnode *vp, st
 
 static int
 v7fs_check_permitted(struct vnode *vp, struct v7fs_node *v7node,
-    mode_t mode, kauth_cred_t cred)
+    accmode_t accmode, kauth_cred_t cred)
 {
 
 	struct v7fs_inode *inode = &v7node->inode;
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, inode->mode), vp, NULL, genfs_can_access(vp->v_type,
-	    inode->mode, inode->uid, inode->gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, inode->mode), vp, NULL, genfs_can_access(vp, cred,
+	    inode->uid, inode->gid, inode->mode, NULL, accmode));
 }
 
 int
 v7fs_access(void *v)
 {
 	struct vop_access_args /* {
-				  struct vnode	*a_vp;
-				  int		a_mode;
-				  kauth_cred_t	a_cred;
-				  } */ *ap = v;
+		struct vnode	*a_vp;
+		accmode_t	a_accmode;
+		kauth_cred_t	a_cred;
+	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct v7fs_node *v7node = vp->v_data;
 	int error;
 
-	error = v7fs_check_possible(vp, v7node, ap->a_mode);
+	error = v7fs_check_possible(vp, v7node, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = v7fs_check_permitted(vp, v7node, ap->a_mode, ap->a_cred);
+	error = v7fs_check_permitted(vp, v7node, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -492,7 +492,7 @@ v7fs_setattr(void *v)
 	/* File pointer mode. */
 	if (vap->va_flags != VNOVAL) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS,
-		    vp, NULL, genfs_can_chflags(cred, vp->v_type, inode->uid,
+		    vp, NULL, genfs_can_chflags(vp, cred, inode->uid,
 		    false));
 		if (error)
 			return error;
@@ -515,7 +515,7 @@ v7fs_setattr(void *v)
 		uid = vap->va_uid;
 		error = kauth_authorize_vnode(cred,
 		    KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
-		    genfs_can_chown(cred, inode->uid, inode->gid, uid,
+		    genfs_can_chown(vp, cred, inode->uid, inode->gid, uid,
 		    gid));
 		if (error)
 			return error;
@@ -525,7 +525,7 @@ v7fs_setattr(void *v)
 		gid = vap->va_gid;
 		error = kauth_authorize_vnode(cred,
 		    KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
-		    genfs_can_chown(cred, inode->uid, inode->gid, uid,
+		    genfs_can_chown(vp, cred, inode->uid, inode->gid, uid,
 		    gid));
 		if (error)
 			return error;
@@ -534,7 +534,7 @@ v7fs_setattr(void *v)
 	if (vap->va_mode != (mode_t)VNOVAL) {
 		mode_t mode = vap->va_mode;
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
-		    vp, NULL, genfs_can_chmod(vp->v_type, cred, inode->uid, inode->gid,
+		    vp, NULL, genfs_can_chmod(vp, cred, inode->uid, inode->gid,
 		    mode));
 		if (error) {
 			return error;
@@ -545,8 +545,8 @@ v7fs_setattr(void *v)
 	    (vap->va_mtime.tv_sec != VNOVAL) ||
 	    (vap->va_ctime.tv_sec != VNOVAL)) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, inode->uid,
-		    cred));
+		    NULL, genfs_can_chtimes(vp, cred, inode->uid,
+		    vap->va_vaflags));
 		if (error)
 			return error;
 
Index: sys/kern/files.kern
===================================================================
RCS file: /cvsroot/src/sys/kern/files.kern,v
retrieving revision 1.47
diff -u -p -p -u -r1.47 files.kern
--- sys/kern/files.kern	30 Apr 2020 03:28:18 -0000	1.47
+++ sys/kern/files.kern	15 May 2020 16:56:53 -0000
@@ -96,6 +96,8 @@ file	kern/kern_uuid.c		kern
 file	kern/kgdb_stub.c		kgdb
 file	kern/sched_4bsd.c		sched_4bsd
 file	kern/sched_m2.c			sched_m2
+file	kern/subr_acl_posix1e.c		kern
+file	kern/subr_acl_nfs4.c		kern
 file	kern/subr_asan.c		kasan
 file	kern/subr_autoconf.c		kern
 file	kern/subr_blist.c		vmswap
@@ -192,6 +194,7 @@ file	kern/uipc_syscalls.c		kern
 file	kern/uipc_usrreq.c		kern
 
 define	vfs: kern
+file	kern/vfs_acl.c			vfs
 file	kern/vfs_bio.c			vfs
 file	kern/vfs_cache.c		vfs
 file	kern/vfs_cwd.c			vfs
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvsroot/src/sys/kern/init_sysent.c,v
retrieving revision 1.331
diff -u -p -p -u -r1.331 init_sysent.c
--- sys/kern/init_sysent.c	26 Apr 2020 19:16:36 -0000	1.331
+++ sys/kern/init_sysent.c	15 May 2020 16:56:53 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: init_sysent.c,v 1.331 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call switch table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_sysent.c,v 1.331 2020/04/26 19:16:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #ifdef _KERNEL_OPT
 #include "opt_modular.h"
@@ -23,6 +23,7 @@ __KERNEL_RCSID(0, "$NetBSD: init_sysent.
 #include <sys/sched.h>
 #include <sys/idtype.h>
 #include <sys/syscallargs.h>
+#include <sys/acl.h>
 
 #ifdef COMPAT_43
 #define	compat_43(func) __CONCAT(compat_43_,func)
@@ -2365,44 +2366,69 @@ struct sysent sysent[] = {
 		.sy_call = (sy_call_t *)sys___fhstatvfs190
 	},		/* 486 = __fhstatvfs190 */
 	{
-		.sy_call = sys_nosys,
-	},		/* 487 = filler */
+		ns(struct sys___acl_get_link_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_get_link
+	},		/* 487 = __acl_get_link */
 	{
-		.sy_call = sys_nosys,
-	},		/* 488 = filler */
+		ns(struct sys___acl_set_link_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_set_link
+	},		/* 488 = __acl_set_link */
 	{
-		.sy_call = sys_nosys,
-	},		/* 489 = filler */
+		ns(struct sys___acl_delete_link_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_delete_link
+	},		/* 489 = __acl_delete_link */
 	{
-		.sy_call = sys_nosys,
-	},		/* 490 = filler */
+		ns(struct sys___acl_aclcheck_link_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_aclcheck_link
+	},		/* 490 = __acl_aclcheck_link */
 	{
-		.sy_call = sys_nosys,
-	},		/* 491 = filler */
+		ns(struct sys___acl_get_file_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_get_file
+	},		/* 491 = __acl_get_file */
 	{
-		.sy_call = sys_nosys,
-	},		/* 492 = filler */
+		ns(struct sys___acl_set_file_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_set_file
+	},		/* 492 = __acl_set_file */
 	{
-		.sy_call = sys_nosys,
-	},		/* 493 = filler */
+		ns(struct sys___acl_get_fd_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_get_fd
+	},		/* 493 = __acl_get_fd */
 	{
-		.sy_call = sys_nosys,
-	},		/* 494 = filler */
+		ns(struct sys___acl_set_fd_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_set_fd
+	},		/* 494 = __acl_set_fd */
 	{
-		.sy_call = sys_nosys,
-	},		/* 495 = filler */
+		ns(struct sys___acl_delete_file_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_delete_file
+	},		/* 495 = __acl_delete_file */
 	{
-		.sy_call = sys_nosys,
-	},		/* 496 = filler */
+		ns(struct sys___acl_delete_fd_args),
+		.sy_call = (sy_call_t *)sys___acl_delete_fd
+	},		/* 496 = __acl_delete_fd */
 	{
-		.sy_call = sys_nosys,
-	},		/* 497 = filler */
+		ns(struct sys___acl_aclcheck_file_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_aclcheck_file
+	},		/* 497 = __acl_aclcheck_file */
 	{
-		.sy_call = sys_nosys,
-	},		/* 498 = filler */
+		ns(struct sys___acl_aclcheck_fd_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys___acl_aclcheck_fd
+	},		/* 498 = __acl_aclcheck_fd */
 	{
-		.sy_call = sys_nosys,
-	},		/* 499 = filler */
+		ns(struct sys_lpathconf_args),
+		.sy_flags = SYCALL_ARG_PTR,
+		.sy_call = (sy_call_t *)sys_lpathconf
+	},		/* 499 = lpathconf */
 	{
 		.sy_call = sys_nosys,
 	},		/* 500 = filler */
Index: sys/kern/kern_auth.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_auth.c,v
retrieving revision 1.77
diff -u -p -p -u -r1.77 kern_auth.c
--- sys/kern/kern_auth.c	3 Sep 2018 16:29:35 -0000	1.77
+++ sys/kern/kern_auth.c	15 May 2020 16:56:53 -0000
@@ -1090,18 +1090,19 @@ kauth_authorize_device_passthru(kauth_cr
 }
 
 kauth_action_t
-kauth_mode_to_action(mode_t mode)
+kauth_accmode_to_action(accmode_t accmode)
 {
 	kauth_action_t action = 0;
 
-	if (mode & VREAD)
+	// XXX: Revisit we need to have a richer set of kauth primitives
+	// We also get only the Unix perms here sometimes
+	if (accmode & (VSTAT_PERMS|VREAD))
 		action |= KAUTH_VNODE_READ_DATA;
-	if (mode & VWRITE)
+	if (accmode & (VMODIFY_PERMS|VADMIN_PERMS))
 		action |= KAUTH_VNODE_WRITE_DATA;
-	if (mode & VEXEC)
+	if (accmode & VEXEC)
 		action |= KAUTH_VNODE_EXECUTE;
-
-	return action;
+	return action == 0 ? KAUTH_VNODE_ACCESS : action;
 }
 
 kauth_action_t
Index: sys/kern/subr_acl_nfs4.c
===================================================================
RCS file: sys/kern/subr_acl_nfs4.c
diff -N sys/kern/subr_acl_nfs4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/kern/subr_acl_nfs4.c	15 May 2020 16:56:53 -0000
@@ -0,0 +1,614 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008-2010 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.
+ */
+
+/*
+ * ACL support routines specific to NFSv4 access control lists.  These are
+ * utility routines for code common across file systems implementing NFSv4
+ * ACLs.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/sys/kern/subr_acl_nfs4.c 341827 2018-12-11 19:32:16Z mjg $");
+#endif
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/acl.h>
+#include <sys/kauth.h>
+
+static void	acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
+
+
+#else
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+#define KASSERT(a) assert(a)
+
+#endif /* !_KERNEL */
+
+#if 0
+static int
+_acl_entry_matches(struct acl_entry *ae, acl_tag_t tag, acl_perm_t perm,
+    acl_entry_type_t entry_type)
+{
+	if (ae->ae_tag != tag)
+		return (0);
+
+	if (ae->ae_id != ACL_UNDEFINED_ID)
+		return (0);
+
+	if (ae->ae_perm != perm)
+		return (0);
+
+	if (ae->ae_entry_type != entry_type)
+		return (0);
+
+	if (ae->ae_flags != 0)
+		return (0);
+
+	return (1);
+}
+#endif
+
+static struct acl_entry *
+_acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm,
+    acl_entry_type_t entry_type)
+{
+	struct acl_entry *ae;
+
+	KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
+
+	ae = &(aclp->acl_entry[aclp->acl_cnt]);
+	aclp->acl_cnt++;
+
+	ae->ae_tag = tag;
+	ae->ae_id = ACL_UNDEFINED_ID;
+	ae->ae_perm = perm;
+	ae->ae_entry_type = entry_type;
+	ae->ae_flags = 0;
+
+	return (ae);
+}
+
+#if 0
+static struct acl_entry *
+_acl_duplicate_entry(struct acl *aclp, unsigned int entry_index)
+{
+	size_t i;
+
+	KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
+
+	for (i = aclp->acl_cnt; i > entry_index; i--)
+		aclp->acl_entry[i] = aclp->acl_entry[i - 1];
+
+	aclp->acl_cnt++;
+
+	return (&(aclp->acl_entry[entry_index + 1]));
+}
+#endif
+
+
+#ifdef _KERNEL
+void
+acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
+    int file_owner_id)
+{
+
+	acl_nfs4_trivial_from_mode(aclp, mode);
+}
+#endif /* _KERNEL */
+
+void
+__acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp)
+{
+	size_t i;
+	mode_t old_mode = *_mode, mode = 0, seen = 0;
+	const struct acl_entry *ae;
+
+	KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES);
+
+	/*
+	 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
+	 *
+	 * 3.16.6.1. Recomputing mode upon SETATTR of ACL
+	 */
+
+	for (i = 0; i < aclp->acl_cnt; i++) {
+		ae = &(aclp->acl_entry[i]);
+
+		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
+		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
+			continue;
+
+		if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY)
+			continue;
+
+		if (ae->ae_tag == ACL_USER_OBJ) {
+			if ((ae->ae_perm & ACL_READ_DATA) &&
+			    ((seen & S_IRUSR) == 0)) {
+				seen |= S_IRUSR;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IRUSR;
+			}
+			if ((ae->ae_perm & ACL_WRITE_DATA) &&
+			     ((seen & S_IWUSR) == 0)) {
+				seen |= S_IWUSR;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IWUSR;
+			}
+			if ((ae->ae_perm & ACL_EXECUTE) &&
+			    ((seen & S_IXUSR) == 0)) {
+				seen |= S_IXUSR;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IXUSR;
+			}
+		} else if (ae->ae_tag == ACL_GROUP_OBJ) {
+			if ((ae->ae_perm & ACL_READ_DATA) &&
+			    ((seen & S_IRGRP) == 0)) {
+				seen |= S_IRGRP;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IRGRP;
+			}
+			if ((ae->ae_perm & ACL_WRITE_DATA) &&
+			    ((seen & S_IWGRP) == 0)) {
+				seen |= S_IWGRP;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IWGRP;
+			}
+			if ((ae->ae_perm & ACL_EXECUTE) &&
+			    ((seen & S_IXGRP) == 0)) {
+				seen |= S_IXGRP;
+				if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+					mode |= S_IXGRP;
+			}
+		} else if (ae->ae_tag == ACL_EVERYONE) {
+			if (ae->ae_perm & ACL_READ_DATA) {
+				if ((seen & S_IRUSR) == 0) {
+					seen |= S_IRUSR;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IRUSR;
+				}
+				if ((seen & S_IRGRP) == 0) {
+					seen |= S_IRGRP;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IRGRP;
+				}
+				if ((seen & S_IROTH) == 0) {
+					seen |= S_IROTH;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IROTH;
+				}
+			}
+			if (ae->ae_perm & ACL_WRITE_DATA) {
+				if ((seen & S_IWUSR) == 0) {
+					seen |= S_IWUSR;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IWUSR;
+				}
+				if ((seen & S_IWGRP) == 0) {
+					seen |= S_IWGRP;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IWGRP;
+				}
+				if ((seen & S_IWOTH) == 0) {
+					seen |= S_IWOTH;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IWOTH;
+				}
+			}
+			if (ae->ae_perm & ACL_EXECUTE) {
+				if ((seen & S_IXUSR) == 0) {
+					seen |= S_IXUSR;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IXUSR;
+				}
+				if ((seen & S_IXGRP) == 0) {
+					seen |= S_IXGRP;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IXGRP;
+				}
+				if ((seen & S_IXOTH) == 0) {
+					seen |= S_IXOTH;
+					if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
+						mode |= S_IXOTH;
+				}
+			}
+		}
+	}
+
+	*_mode = mode | (old_mode & ACL_PRESERVE_MASK);
+}
+
+/*
+ * Populate the ACL with entries inherited from parent_aclp.
+ */
+static void		
+acl_nfs4_inherit_entries(const struct acl *parent_aclp,
+    struct acl *child_aclp, mode_t mode, int file_owner_id,
+    int is_directory)
+{
+	int flags, tag;
+	size_t i;
+	const struct acl_entry *parent_entry;
+	struct acl_entry *ae;
+
+	KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES);
+
+	for (i = 0; i < parent_aclp->acl_cnt; i++) {
+		parent_entry = &(parent_aclp->acl_entry[i]);
+		flags = parent_entry->ae_flags;
+		tag = parent_entry->ae_tag;
+
+		/*
+		 * Don't inherit owner@, group@, or everyone@ entries.
+		 */
+		if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ ||
+		    tag == ACL_EVERYONE)
+			continue;
+
+		/*
+		 * Entry is not inheritable at all.
+		 */
+		if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT |
+		    ACL_ENTRY_FILE_INHERIT)) == 0)
+			continue;
+
+		/*
+		 * We're creating a file, but ae is not inheritable
+		 * by files.
+		 */
+		if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0)
+			continue;
+
+		/*
+		 * Entry is inheritable only by files, but has NO_PROPAGATE
+		 * flag set, and we're creating a directory, so it wouldn't
+		 * propagate to any file in that directory anyway.
+		 */
+		if (is_directory &&
+		    (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 &&
+		    (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT))
+			continue;
+
+		/*
+		 * Entry qualifies for being inherited.
+		 */
+		KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES);
+		ae = &(child_aclp->acl_entry[child_aclp->acl_cnt]);
+		*ae = *parent_entry;
+		child_aclp->acl_cnt++;
+
+		ae->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY;
+		ae->ae_flags |= ACL_ENTRY_INHERITED;
+
+		/*
+		 * If the type of the ACE is neither ALLOW nor DENY,
+		 * then leave it as it is and proceed to the next one.
+		 */
+		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
+		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
+			continue;
+
+		/*
+		 * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if
+		 * the object being created is not a directory, then clear
+		 * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT,
+		 * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT,
+		 * ACL_ENTRY_INHERIT_ONLY.
+		 */
+		if (ae->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT ||
+		    !is_directory) {
+			ae->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT |
+			ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT |
+			ACL_ENTRY_INHERIT_ONLY);
+		}
+
+		/*
+		 * If the object is a directory and ACL_ENTRY_FILE_INHERIT
+		 * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure
+		 * that ACL_ENTRY_INHERIT_ONLY is set.
+		 */
+		if (is_directory &&
+		    (ae->ae_flags & ACL_ENTRY_FILE_INHERIT) &&
+		    ((ae->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) {
+			ae->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
+		}
+
+		if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW &&
+		    (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) {
+			/*
+			 * Some permissions must never be inherited.
+			 */
+			ae->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER |
+			    ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES);
+
+			/*
+			 * Others must be masked according to the file mode.
+			 */
+			if ((mode & S_IRGRP) == 0)
+				ae->ae_perm &= ~ACL_READ_DATA;
+			if ((mode & S_IWGRP) == 0)
+				ae->ae_perm &=
+				    ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
+			if ((mode & S_IXGRP) == 0)
+				ae->ae_perm &= ~ACL_EXECUTE;
+		}
+	}
+}
+
+/*
+ * Calculate inherited ACL in a manner compatible with PSARC/2010/029.
+ * It's also being used to calculate a trivial ACL, by inheriting from
+ * a NULL ACL.
+ */
+static void		
+acl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp,
+    struct acl *aclp, mode_t mode, int file_owner_id, int is_directory)
+{
+	acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0;
+	acl_perm_t user_allow, group_allow, everyone_allow;
+
+	KASSERT(aclp->acl_cnt == 0);
+
+	user_allow = group_allow = everyone_allow = ACL_READ_ACL |
+	    ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE;
+	user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
+	    ACL_WRITE_NAMED_ATTRS;
+
+	if (mode & S_IRUSR)
+		user_allow |= ACL_READ_DATA;
+	if (mode & S_IWUSR)
+		user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+	if (mode & S_IXUSR)
+		user_allow |= ACL_EXECUTE;
+
+	if (mode & S_IRGRP)
+		group_allow |= ACL_READ_DATA;
+	if (mode & S_IWGRP)
+		group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+	if (mode & S_IXGRP)
+		group_allow |= ACL_EXECUTE;
+
+	if (mode & S_IROTH)
+		everyone_allow |= ACL_READ_DATA;
+	if (mode & S_IWOTH)
+		everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+	if (mode & S_IXOTH)
+		everyone_allow |= ACL_EXECUTE;
+
+	user_deny = ((group_allow | everyone_allow) & ~user_allow);
+	group_deny = everyone_allow & ~group_allow;
+	user_allow_first = group_deny & ~user_deny;
+
+	if (user_allow_first != 0)
+		_acl_append(aclp, ACL_USER_OBJ, user_allow_first,
+		    ACL_ENTRY_TYPE_ALLOW);
+	if (user_deny != 0)
+		_acl_append(aclp, ACL_USER_OBJ, user_deny,
+		    ACL_ENTRY_TYPE_DENY);
+	if (group_deny != 0)
+		_acl_append(aclp, ACL_GROUP_OBJ, group_deny,
+		    ACL_ENTRY_TYPE_DENY);
+
+	if (parent_aclp != NULL)
+		acl_nfs4_inherit_entries(parent_aclp, aclp, mode,
+		    file_owner_id, is_directory);
+
+	_acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW);
+	_acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW);
+	_acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW);
+}
+
+#ifdef _KERNEL
+void		
+acl_nfs4_compute_inherited_acl(const struct acl *parent_aclp,
+    struct acl *child_aclp, mode_t mode, int file_owner_id,
+    int is_directory)
+{
+
+	acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp,
+	    mode, file_owner_id, is_directory);
+}
+#endif /* _KERNEL */
+
+/*
+ * Calculate trivial ACL in a manner compatible with PSARC/2010/029.
+ * Note that this results in an ACL different from (but semantically
+ * equal to) the "canonical six" trivial ACL computed using algorithm
+ * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2.
+ */
+static void
+acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode)
+{
+
+	aclp->acl_cnt = 0;
+	acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1);
+}
+
+#ifndef _KERNEL
+/*
+ * This routine is used by libc to implement acl_strip_np(3)
+ * and acl_is_trivial_np(3).
+ */
+void
+__acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six)
+{
+
+	aclp->acl_cnt = 0;
+	acl_nfs4_trivial_from_mode(aclp, mode);
+}
+#endif /* !_KERNEL */
+
+#ifdef _KERNEL
+static int
+_acls_are_equal(const struct acl *a, const struct acl *b)
+{
+	int i;
+	const struct acl_entry *entrya, *entryb;
+
+	if (a->acl_cnt != b->acl_cnt)
+		return (0);
+
+	for (i = 0; i < b->acl_cnt; i++) {
+		entrya = &(a->acl_entry[i]);
+		entryb = &(b->acl_entry[i]);
+
+		if (entrya->ae_tag != entryb->ae_tag ||
+		    entrya->ae_id != entryb->ae_id ||
+		    entrya->ae_perm != entryb->ae_perm ||
+		    entrya->ae_entry_type != entryb->ae_entry_type ||
+		    entrya->ae_flags != entryb->ae_flags)
+			return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * This routine is used to determine whether to remove extended attribute
+ * that stores ACL contents.
+ */
+int
+acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id)
+{
+	int trivial;
+	mode_t tmpmode = 0;
+	struct acl *tmpaclp;
+
+	if (aclp->acl_cnt > 6)
+		return (0);
+
+	/*
+	 * Compute the mode from the ACL, then compute new ACL from that mode.
+	 * If the ACLs are identical, then the ACL is trivial.
+	 *
+	 * XXX: I guess there is a faster way to do this.  However, even
+	 *      this slow implementation significantly speeds things up
+	 *      for files that don't have non-trivial ACLs - it's critical
+	 *      for performance to not use EA when they are not needed.
+	 *
+	 * First try the PSARC/2010/029 semantics.
+	 */
+	tmpaclp = acl_alloc(KM_SLEEP);
+	__acl_nfs4_sync_mode_from_acl(&tmpmode, aclp);
+	acl_nfs4_trivial_from_mode(tmpaclp, tmpmode);
+	trivial = _acls_are_equal(aclp, tmpaclp);
+	if (trivial) {
+		acl_free(tmpaclp);
+		return (trivial);
+	}
+
+	/*
+	 * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL.
+	 */
+	acl_free(tmpaclp);
+
+	return (trivial);
+}
+
+int
+acl_nfs4_check(const struct acl *aclp, int is_directory)
+{
+	size_t i;
+	const struct acl_entry *ae;
+
+	/*
+	 * The spec doesn't seem to say anything about ACL validity.
+	 * It seems there is not much to do here.  There is even no need
+	 * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE)
+	 * entries, as there can be several of them and that's perfectly
+	 * valid.  There can be none of them too.  Really.
+	 */
+
+	if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0)
+		return (EINVAL);
+
+	for (i = 0; i < aclp->acl_cnt; i++) {
+		ae = &(aclp->acl_entry[i]);
+
+		switch (ae->ae_tag) {
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_EVERYONE:
+			if (ae->ae_id != ACL_UNDEFINED_ID)
+				return (EINVAL);
+			break;
+
+		case ACL_USER:
+		case ACL_GROUP:
+			if (ae->ae_id == ACL_UNDEFINED_ID)
+				return (EINVAL);
+			break;
+
+		default:
+			return (EINVAL);
+		}
+
+		if ((ae->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS)
+			return (EINVAL);
+
+		/*
+		 * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now.
+		 */
+		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
+		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
+			return (EINVAL);
+
+		if ((ae->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS)
+			return (EINVAL);
+
+		/* Disallow unimplemented flags. */
+		if (ae->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS |
+		    ACL_ENTRY_FAILED_ACCESS))
+			return (EINVAL);
+
+		/* Disallow flags not allowed for ordinary files. */
+		if (!is_directory) {
+			if (ae->ae_flags & (ACL_ENTRY_FILE_INHERIT |
+			    ACL_ENTRY_DIRECTORY_INHERIT |
+			    ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY))
+				return (EINVAL);
+		}
+	}
+
+	return (0);
+}
+#endif
Index: sys/kern/subr_acl_posix1e.c
===================================================================
RCS file: sys/kern/subr_acl_posix1e.c
diff -N sys/kern/subr_acl_posix1e.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/kern/subr_acl_posix1e.c	15 May 2020 16:56:53 -0000
@@ -0,0 +1,338 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2006 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * ACL support routines specific to POSIX.1e access control lists.  These are
+ * utility routines for code common across file systems implementing POSIX.1e
+ * ACLs.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/sys/kern/subr_acl_posix1e.c 341827 2018-12-11 19:32:16Z mjg $");
+#endif
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/kauth.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+
+/*
+ * For the purposes of filesystems maintaining the _OBJ entries in an inode
+ * with a mode_t field, this routine converts a mode_t entry to an
+ * acl_perm_t.
+ */
+acl_perm_t
+acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
+{
+	acl_perm_t	perm = 0;
+
+	switch(tag) {
+	case ACL_USER_OBJ:
+		if (mode & S_IXUSR)
+			perm |= ACL_EXECUTE;
+		if (mode & S_IRUSR)
+			perm |= ACL_READ;
+		if (mode & S_IWUSR)
+			perm |= ACL_WRITE;
+		return (perm);
+
+	case ACL_GROUP_OBJ:
+		if (mode & S_IXGRP)
+			perm |= ACL_EXECUTE;
+		if (mode & S_IRGRP)
+			perm |= ACL_READ;
+		if (mode & S_IWGRP)
+			perm |= ACL_WRITE;
+		return (perm);
+
+	case ACL_OTHER:
+		if (mode & S_IXOTH)
+			perm |= ACL_EXECUTE;
+		if (mode & S_IROTH)
+			perm |= ACL_READ;
+		if (mode & S_IWOTH)
+			perm |= ACL_WRITE;
+		return (perm);
+
+	default:
+		printf("%s: invalid tag (%u)\n", __func__, tag);
+		return (0);
+	}
+}
+
+/*
+ * Given inode information (uid, gid, mode), return an acl entry of the
+ * appropriate type.
+ */
+struct acl_entry
+acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
+{
+	struct acl_entry	acl_entry;
+
+	acl_entry.ae_tag = tag;
+	acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
+	acl_entry.ae_entry_type = 0;
+	acl_entry.ae_flags = 0;
+	switch(tag) {
+	case ACL_USER_OBJ:
+		acl_entry.ae_id = uid;
+		break;
+
+	case ACL_GROUP_OBJ:
+		acl_entry.ae_id = gid;
+		break;
+
+	case ACL_OTHER:
+		acl_entry.ae_id = ACL_UNDEFINED_ID;
+		break;
+
+	default:
+		acl_entry.ae_id = ACL_UNDEFINED_ID;
+		printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
+	}
+
+	return (acl_entry);
+}
+
+/*
+ * Utility function to generate a file mode given appropriate ACL entries.
+ */
+mode_t
+acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
+    struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
+{
+	mode_t	mode;
+
+	mode = 0;
+	if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
+		mode |= S_IXUSR;
+	if (acl_user_obj_entry->ae_perm & ACL_READ)
+		mode |= S_IRUSR;
+	if (acl_user_obj_entry->ae_perm & ACL_WRITE)
+		mode |= S_IWUSR;
+	if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
+		mode |= S_IXGRP;
+	if (acl_group_obj_entry->ae_perm & ACL_READ)
+		mode |= S_IRGRP;
+	if (acl_group_obj_entry->ae_perm & ACL_WRITE)
+		mode |= S_IWGRP;
+	if (acl_other_entry->ae_perm & ACL_EXECUTE)
+		mode |= S_IXOTH;
+	if (acl_other_entry->ae_perm & ACL_READ)
+		mode |= S_IROTH;
+	if (acl_other_entry->ae_perm & ACL_WRITE)
+		mode |= S_IWOTH;
+
+	return (mode);
+}
+
+/*
+ * Utility function to generate a file mode given a complete POSIX.1e access
+ * ACL.  Note that if the ACL is improperly formed, this may result in a
+ * panic.
+ */
+mode_t
+acl_posix1e_acl_to_mode(struct acl *acl)
+{
+	struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
+	int i;
+
+	/*
+	 * Find the ACL entries relevant to a POSIX permission mode.
+	 */
+	acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
+	for (i = 0; i < acl->acl_cnt; i++) {
+		switch (acl->acl_entry[i].ae_tag) {
+		case ACL_USER_OBJ:
+			acl_user_obj = &acl->acl_entry[i];
+			break;
+
+		case ACL_GROUP_OBJ:
+			acl_group_obj = &acl->acl_entry[i];
+			break;
+
+		case ACL_OTHER:
+			acl_other = &acl->acl_entry[i];
+			break;
+
+		case ACL_MASK:
+			acl_mask = &acl->acl_entry[i];
+			break;
+
+		case ACL_USER:
+		case ACL_GROUP:
+			break;
+
+		default:
+			panic("acl_posix1e_acl_to_mode: bad ae_tag");
+		}
+	}
+
+	if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
+		panic("acl_posix1e_acl_to_mode: missing base ae_tags");
+
+	/*
+	 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
+	 * the mode "group" bits with its permissions.  If there isn't, we
+	 * use the ACL_GROUP_OBJ permissions.
+	 */
+	if (acl_mask != NULL)
+		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
+		    acl_other));
+	else
+		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
+		    acl_other));
+}
+
+/*
+ * Perform a syntactic check of the ACL, sufficient to allow an implementing
+ * filesystem to determine if it should accept this and rely on the POSIX.1e
+ * ACL properties.
+ */
+int
+acl_posix1e_check(struct acl *acl)
+{
+	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
+	int num_acl_mask, num_acl_other, i;
+
+	/*
+	 * Verify that the number of entries does not exceed the maximum
+	 * defined for acl_t.
+	 *
+	 * Verify that the correct number of various sorts of ae_tags are
+	 * present:
+	 *   Exactly one ACL_USER_OBJ
+	 *   Exactly one ACL_GROUP_OBJ
+	 *   Exactly one ACL_OTHER
+	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
+	 *   ACL_MASK entry must also appear.
+	 *
+	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
+	 *
+	 * Verify all ae_tag entries are understood by this implementation.
+	 *
+	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
+	 */
+	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
+	    num_acl_mask = num_acl_other = 0;
+	if (acl->acl_cnt > ACL_MAX_ENTRIES)
+		return (EINVAL);
+	for (i = 0; i < acl->acl_cnt; i++) {
+		struct acl_entry *ae = &acl->acl_entry[i];
+		/*
+		 * Check for a valid tag.
+		 */
+		switch(ae->ae_tag) {
+		case ACL_USER_OBJ:
+			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
+			if (ae->ae_id != ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_user_obj++;
+			break;
+		case ACL_GROUP_OBJ:
+			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
+			if (ae->ae_id != ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_group_obj++;
+			break;
+		case ACL_USER:
+			if (ae->ae_id == ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_user++;
+			break;
+		case ACL_GROUP:
+			if (ae->ae_id == ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_group++;
+			break;
+		case ACL_OTHER:
+			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
+			if (ae->ae_id != ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_other++;
+			break;
+		case ACL_MASK:
+			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
+			if (ae->ae_id != ACL_UNDEFINED_ID)
+				return (EINVAL);
+			num_acl_mask++;
+			break;
+		default:
+			return (EINVAL);
+		}
+		/*
+		 * Check for valid perm entries.
+		 */
+		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
+		    ACL_PERM_BITS)
+			return (EINVAL);
+	}
+	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
+	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
+		return (EINVAL);
+	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
+	    (num_acl_mask != 1))
+		return (EINVAL);
+	return (0);
+}
+
+/*
+ * Given a requested mode for a new object, and a default ACL, combine the
+ * two to produce a new mode.  Be careful not to clear any bits that aren't
+ * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
+ * take the cmask as an argument, if we push that down into
+ * per-filesystem-code.
+ */
+mode_t
+acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
+{
+	mode_t mode;
+
+	mode = cmode;
+	/*
+	 * The current composition policy is that a permission bit must be
+	 * set in *both* the ACL and the requested creation mode for it to
+	 * appear in the resulting mode/ACL.  First clear any possibly
+	 * effected bits, then reconstruct.
+	 */
+	mode &= ACL_PRESERVE_MASK;
+	mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
+
+	return (mode);
+}
Index: sys/kern/sys_mqueue.c
===================================================================
RCS file: /cvsroot/src/sys/kern/sys_mqueue.c,v
retrieving revision 1.46
diff -u -p -p -u -r1.46 sys_mqueue.c
--- sys/kern/sys_mqueue.c	16 Mar 2020 21:20:10 -0000	1.46
+++ sys/kern/sys_mqueue.c	15 May 2020 16:56:53 -0000
@@ -393,17 +393,17 @@ mq_close_fop(file_t *fp)
 static int
 mqueue_access(mqueue_t *mq, int access, kauth_cred_t cred)
 {
-	mode_t acc_mode = 0;
+	accmode_t accmode = 0;
 
 	/* Note the difference between VREAD/VWRITE and FREAD/FWRITE. */
 	if (access & FREAD) {
-		acc_mode |= VREAD;
+		accmode |= VREAD;
 	}
 	if (access & FWRITE) {
-		acc_mode |= VWRITE;
+		accmode |= VWRITE;
 	}
-	if (genfs_can_access(VNON, mq->mq_mode, mq->mq_euid,
-	    mq->mq_egid, acc_mode, cred)) {
+	if (genfs_can_access(NULL, cred, mq->mq_euid, mq->mq_egid,
+	    mq->mq_mode, NULL, accmode)) {
 		return EACCES;
 	}
 	return 0;
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/syscalls.c,v
retrieving revision 1.319
diff -u -p -p -u -r1.319 syscalls.c
--- sys/kern/syscalls.c	26 Apr 2020 19:16:36 -0000	1.319
+++ sys/kern/syscalls.c	15 May 2020 16:56:53 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls.c,v 1.319 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call names.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls.c,v 1.319 2020/04/26 19:16:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #ifdef _KERNEL_OPT
@@ -24,6 +24,7 @@ __KERNEL_RCSID(0, "$NetBSD: syscalls.c,v
 #include <sys/sched.h>
 #include <sys/idtype.h>
 #include <sys/syscallargs.h>
+#include <sys/acl.h>
 #else /* _KERNEL_OPT */
 #include <sys/null.h>
 #endif /* _KERNEL_OPT */
@@ -536,19 +537,19 @@ const char *const syscallnames[] = {
 	/* 484 */	"__statvfs190",
 	/* 485 */	"__fstatvfs190",
 	/* 486 */	"__fhstatvfs190",
-	/* 487 */	"# filler",
-	/* 488 */	"# filler",
-	/* 489 */	"# filler",
-	/* 490 */	"# filler",
-	/* 491 */	"# filler",
-	/* 492 */	"# filler",
-	/* 493 */	"# filler",
-	/* 494 */	"# filler",
-	/* 495 */	"# filler",
-	/* 496 */	"# filler",
-	/* 497 */	"# filler",
-	/* 498 */	"# filler",
-	/* 499 */	"# filler",
+	/* 487 */	"__acl_get_link",
+	/* 488 */	"__acl_set_link",
+	/* 489 */	"__acl_delete_link",
+	/* 490 */	"__acl_aclcheck_link",
+	/* 491 */	"__acl_get_file",
+	/* 492 */	"__acl_set_file",
+	/* 493 */	"__acl_get_fd",
+	/* 494 */	"__acl_set_fd",
+	/* 495 */	"__acl_delete_file",
+	/* 496 */	"__acl_delete_fd",
+	/* 497 */	"__acl_aclcheck_file",
+	/* 498 */	"__acl_aclcheck_fd",
+	/* 499 */	"lpathconf",
 	/* 500 */	"# filler",
 	/* 501 */	"# filler",
 	/* 502 */	"# filler",
@@ -1073,19 +1074,19 @@ const char *const altsyscallnames[] = {
 	/* 484 */	"statvfs1",
 	/* 485 */	"fstatvfs1",
 	/* 486 */	"fhstatvfs1",
-	/* 487 */	NULL, /* filler */
-	/* 488 */	NULL, /* filler */
-	/* 489 */	NULL, /* filler */
-	/* 490 */	NULL, /* filler */
-	/* 491 */	NULL, /* filler */
-	/* 492 */	NULL, /* filler */
-	/* 493 */	NULL, /* filler */
-	/* 494 */	NULL, /* filler */
-	/* 495 */	NULL, /* filler */
-	/* 496 */	NULL, /* filler */
-	/* 497 */	NULL, /* filler */
-	/* 498 */	NULL, /* filler */
-	/* 499 */	NULL, /* filler */
+	/* 487 */	NULL, /* __acl_get_link */
+	/* 488 */	NULL, /* __acl_set_link */
+	/* 489 */	NULL, /* __acl_delete_link */
+	/* 490 */	NULL, /* __acl_aclcheck_link */
+	/* 491 */	NULL, /* __acl_get_file */
+	/* 492 */	NULL, /* __acl_set_file */
+	/* 493 */	NULL, /* __acl_get_fd */
+	/* 494 */	NULL, /* __acl_set_fd */
+	/* 495 */	NULL, /* __acl_delete_file */
+	/* 496 */	NULL, /* __acl_delete_fd */
+	/* 497 */	NULL, /* __acl_aclcheck_file */
+	/* 498 */	NULL, /* __acl_aclcheck_fd */
+	/* 499 */	NULL, /* lpathconf */
 	/* 500 */	NULL, /* filler */
 	/* 501 */	NULL, /* filler */
 	/* 502 */	NULL, /* filler */
Index: sys/kern/syscalls.conf
===================================================================
RCS file: /cvsroot/src/sys/kern/syscalls.conf,v
retrieving revision 1.30
diff -u -p -p -u -r1.30 syscalls.conf
--- sys/kern/syscalls.conf	22 Sep 2019 22:59:39 -0000	1.30
+++ sys/kern/syscalls.conf	15 May 2020 16:56:53 -0000
@@ -5,7 +5,7 @@ sysnumhdr="../sys/syscall.h"
 syssw="init_sysent.c"
 systrace="systrace_args.c"
 sysarghdr="../sys/syscallargs.h"
-sysarghdrextra='#ifndef RUMP_CLIENT\n#include <sys/idtype.h>\n#include <sys/mount.h>\n#include <sys/sched.h>\n#endif\n\n#include <sys/socket.h>\n\n'
+sysarghdrextra='#ifndef RUMP_CLIENT\n#include <sys/idtype.h>\n#include <sys/mount.h>\n#include <sys/sched.h>\n#include <sys/acl.h>\n#endif\n\n#include <sys/socket.h>\n\n'
 sysautoload="syscalls_autoload.c"
 sysalign=1
 rumpcalls="../rump/librump/rumpkern/rump_syscalls.c"
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvsroot/src/sys/kern/syscalls.master,v
retrieving revision 1.304
diff -u -p -p -u -r1.304 syscalls.master
--- sys/kern/syscalls.master	26 Apr 2020 19:15:55 -0000	1.304
+++ sys/kern/syscalls.master	15 May 2020 16:56:53 -0000
@@ -59,6 +59,7 @@
 #include <sys/sched.h>
 #include <sys/idtype.h>
 #include <sys/syscallargs.h>
+#include <sys/acl.h>
 
 %%
 
@@ -1019,3 +1020,28 @@
 			    struct statvfs *buf, int flags); }
 486	STD	RUMP	{ int|sys|90|fhstatvfs1(const void *fhp, \
 			    size_t fh_size, struct statvfs *buf, int flags); }
+487	STD		{ int|sys||__acl_get_link(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+488	STD		{ int|sys||__acl_set_link(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+489	STD		{ int|sys||__acl_delete_link(const char *path, \
+			    acl_type_t type); }
+490	STD		{ int|sys||__acl_aclcheck_link(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+491	STD		{ int|sys||__acl_get_file(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+492	STD		{ int|sys||__acl_set_file(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+493	STD		{ int|sys||__acl_get_fd(int filedes, acl_type_t type, \
+			     struct acl *aclp); }
+494	STD		{ int|sys||__acl_set_fd(int filedes, acl_type_t type, \
+			     struct acl *aclp); }
+495	STD		{ int|sys||__acl_delete_file(const char *path, \
+			    acl_type_t type); }
+496	STD		{ int|sys||__acl_delete_fd(int filedes, \
+			    acl_type_t type); }
+497	STD		{ int|sys||__acl_aclcheck_file(const char *path, \
+			    acl_type_t type, struct acl *aclp); }
+498	STD		{ int|sys||__acl_aclcheck_fd(int filedes, \
+			    acl_type_t type, struct acl *aclp); }
+499	STD	RUMP	{ long|sys||lpathconf(const char *path, int name); }
Index: sys/kern/syscalls_autoload.c
===================================================================
RCS file: /cvsroot/src/sys/kern/syscalls_autoload.c,v
retrieving revision 1.36
diff -u -p -p -u -r1.36 syscalls_autoload.c
--- sys/kern/syscalls_autoload.c	26 Apr 2020 19:16:36 -0000	1.36
+++ sys/kern/syscalls_autoload.c	15 May 2020 16:56:53 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls_autoload.c,v 1.36 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call autoload table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls_autoload.c,v 1.36 2020/04/26 19:16:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #ifdef _KERNEL_OPT
 #include "opt_modular.h"
@@ -23,6 +23,7 @@ __KERNEL_RCSID(0, "$NetBSD: syscalls_aut
 #include <sys/sched.h>
 #include <sys/idtype.h>
 #include <sys/syscallargs.h>
+#include <sys/acl.h>
 static struct sc_autoload netbsd_syscalls_autoload[] = {
 	    { SYS_compat_50_wait4, "compat_50" },
 	    { SYS_compat_43_ocreat, "compat_43" },
Index: sys/kern/systrace_args.c
===================================================================
RCS file: /cvsroot/src/sys/kern/systrace_args.c,v
retrieving revision 1.38
diff -u -p -p -u -r1.38 systrace_args.c
--- sys/kern/systrace_args.c	26 Apr 2020 19:16:36 -0000	1.38
+++ sys/kern/systrace_args.c	15 May 2020 16:56:53 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: systrace_args.c,v 1.38 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument to DTrace register array converstion.
@@ -3731,6 +3731,119 @@ systrace_args(register_t sysnum, const v
 		*n_args = 4;
 		break;
 	}
+	/* sys___acl_get_link */
+	case 487: {
+		const struct sys___acl_get_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_set_link */
+	case 488: {
+		const struct sys___acl_set_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_delete_link */
+	case 489: {
+		const struct sys___acl_delete_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* sys___acl_aclcheck_link */
+	case 490: {
+		const struct sys___acl_aclcheck_link_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_get_file */
+	case 491: {
+		const struct sys___acl_get_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_set_file */
+	case 492: {
+		const struct sys___acl_set_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_get_fd */
+	case 493: {
+		const struct sys___acl_get_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_set_fd */
+	case 494: {
+		const struct sys___acl_set_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_delete_file */
+	case 495: {
+		const struct sys___acl_delete_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* sys___acl_delete_fd */
+	case 496: {
+		const struct sys___acl_delete_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		*n_args = 2;
+		break;
+	}
+	/* sys___acl_aclcheck_file */
+	case 497: {
+		const struct sys___acl_aclcheck_file_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys___acl_aclcheck_fd */
+	case 498: {
+		const struct sys___acl_aclcheck_fd_args *p = params;
+		iarg[0] = SCARG(p, filedes); /* int */
+		iarg[1] = SCARG(p, type); /* acl_type_t */
+		uarg[2] = (intptr_t) SCARG(p, aclp); /* struct acl * */
+		*n_args = 3;
+		break;
+	}
+	/* sys_lpathconf */
+	case 499: {
+		const struct sys_lpathconf_args *p = params;
+		uarg[0] = (intptr_t) SCARG(p, path); /* const char * */
+		iarg[1] = SCARG(p, name); /* int */
+		*n_args = 2;
+		break;
+	}
 	default:
 		*n_args = 0;
 		break;
@@ -10066,6 +10179,202 @@ systrace_entry_setargdesc(int sysnum, in
 			break;
 		};
 		break;
+	/* sys___acl_get_link */
+	case 487:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_set_link */
+	case 488:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_delete_link */
+	case 489:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_aclcheck_link */
+	case 490:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_get_file */
+	case 491:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_set_file */
+	case 492:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_get_fd */
+	case 493:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_set_fd */
+	case 494:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_delete_file */
+	case 495:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_delete_fd */
+	case 496:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_aclcheck_file */
+	case 497:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys___acl_aclcheck_fd */
+	case 498:
+		switch(ndx) {
+		case 0:
+			p = "int";
+			break;
+		case 1:
+			p = "acl_type_t";
+			break;
+		case 2:
+			p = "struct acl *";
+			break;
+		default:
+			break;
+		};
+		break;
+	/* sys_lpathconf */
+	case 499:
+		switch(ndx) {
+		case 0:
+			p = "const char *";
+			break;
+		case 1:
+			p = "int";
+			break;
+		default:
+			break;
+		};
+		break;
 	default:
 		break;
 	};
@@ -12178,6 +12487,71 @@ systrace_return_setargdesc(int sysnum, i
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;
+	/* sys___acl_get_link */
+	case 487:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_set_link */
+	case 488:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_delete_link */
+	case 489:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_aclcheck_link */
+	case 490:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_get_file */
+	case 491:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_set_file */
+	case 492:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_get_fd */
+	case 493:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_set_fd */
+	case 494:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_delete_file */
+	case 495:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_delete_fd */
+	case 496:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_aclcheck_file */
+	case 497:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys___acl_aclcheck_fd */
+	case 498:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* sys_lpathconf */
+	case 499:
+		if (ndx == 0 || ndx == 1)
+			p = "long";
+		break;
 	default:
 		break;
 	};
Index: sys/kern/vfs_acl.c
===================================================================
RCS file: sys/kern/vfs_acl.c
diff -N sys/kern/vfs_acl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/kern/vfs_acl.c	15 May 2020 16:56:53 -0000
@@ -0,0 +1,542 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2006, 2016-2017 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Portions of this software were developed by BAE Systems, the University of
+ * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
+ * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
+ * Computing (TC) research program.
+ *
+ * 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.
+ */
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * ACL system calls and other functions common across different ACL types.
+ * Type-specific routines go into subr_acl_<type>.c.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/sys/kern/vfs_acl.c 356337 2020-01-03 22:29:58Z mjg $");
+#endif
+__KERNEL_RCSID(0, "$NetBSD: vfs_acl.c,v 1.545 2020/04/04 20:49:30 ad Exp $");
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/proc.h>
+#include <sys/acl.h>
+
+#include <sys/syscallargs.h>
+
+__CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
+
+
+int
+acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
+{
+	int i;
+
+	if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
+		return EINVAL;
+	
+	memset(dest, 0, sizeof(*dest));
+
+	dest->acl_cnt = source->acl_cnt;
+	dest->acl_maxcnt = ACL_MAX_ENTRIES;
+
+	for (i = 0; i < dest->acl_cnt; i++) {
+		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
+		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
+		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
+	}
+
+	return 0;
+}
+
+int
+acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
+{
+	int i;
+
+	if (source->acl_cnt > OLDACL_MAX_ENTRIES)
+		return EINVAL;
+
+	memset(dest, 0, sizeof(*dest));
+
+	dest->acl_cnt = source->acl_cnt;
+
+	for (i = 0; i < dest->acl_cnt; i++) {
+		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
+		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
+		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
+	}
+
+	return 0;
+}
+
+/*
+ * At one time, "struct ACL" was extended in order to add support for NFSv4
+ * ACLs.  Instead of creating compatibility versions of all the ACL-related
+ * syscalls, they were left intact.  It's possible to find out what the code
+ * calling these syscalls (libc) expects basing on "type" argument - if it's
+ * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
+ * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
+ * oldacl".  If it's something else, then it's the new "struct acl".  In the
+ * latter case, the routines below just copyin/copyout the contents.  In the
+ * former case, they copyin the "struct oldacl" and convert it to the new
+ * format.
+ */
+static int
+acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
+{
+	int error;
+	struct oldacl old;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS_OLD:
+	case ACL_TYPE_DEFAULT_OLD:
+		error = copyin(user_acl, &old, sizeof(old));
+		if (error != 0)
+			break;
+		acl_copy_oldacl_into_acl(&old, kernel_acl);
+		break;
+
+	default:
+		error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
+		if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
+			return EINVAL;
+	}
+
+	return error;
+}
+
+static int
+acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type)
+{
+	uint32_t am;
+	int error;
+	struct oldacl old;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS_OLD:
+	case ACL_TYPE_DEFAULT_OLD:
+		error = acl_copy_acl_into_oldacl(kernel_acl, &old);
+		if (error != 0)
+			break;
+
+		error = copyout(&old, user_acl, sizeof(old));
+		break;
+
+	default:
+		error = ufetch_32((const uint32_t *)
+		    (const void *)((const char *)user_acl +
+		    offsetof(struct acl, acl_maxcnt)), &am);
+		if (error)
+			return error;
+		if (am != ACL_MAX_ENTRIES)
+			return EINVAL;
+
+		error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
+	}
+
+	return error;
+}
+
+/*
+ * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
+ * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
+ * with new kernel.  Fixing 'type' for old binaries with new libc
+ * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
+ */
+static int
+acl_type_unold(int type)
+{
+	switch (type) {
+	case ACL_TYPE_ACCESS_OLD:
+		return ACL_TYPE_ACCESS;
+
+	case ACL_TYPE_DEFAULT_OLD:
+		return ACL_TYPE_DEFAULT;
+
+	default:
+		return type;
+	}
+}
+
+/*
+ * These calls wrap the real vnode operations, and are called by the syscall
+ * code once the syscall has converted the path or file descriptor to a vnode
+ * (unlocked).  The aclp pointer is assumed still to point to userland, so
+ * this should not be consumed within the kernel except by syscall code.
+ * Other code should directly invoke VOP_{SET,GET}ACL.
+ */
+
+/*
+ * Given a vnode, set its ACL.
+ */
+int
+vacl_set_acl(struct lwp *l, struct vnode *vp, acl_type_t type,
+    const struct acl *aclp)
+{
+	struct acl *inkernelacl;
+	int error;
+
+	inkernelacl = acl_alloc(KM_SLEEP);
+	error = acl_copyin(aclp, inkernelacl, type);
+	if (error != 0)
+		goto out;
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, l->l_cred);
+	VOP_UNLOCK(vp);
+out:
+	acl_free(inkernelacl);
+	return error;
+}
+
+/*
+ * Given a vnode, get its ACL.
+ */
+int
+vacl_get_acl(struct lwp *l, struct vnode *vp, acl_type_t type,
+    struct acl *aclp)
+{
+	struct acl *inkernelacl;
+	int error;
+
+	inkernelacl = acl_alloc(KM_SLEEP);
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, l->l_cred);
+
+	VOP_UNLOCK(vp);
+	if (error == 0)
+		error = acl_copyout(inkernelacl, aclp, type);
+	acl_free(inkernelacl);
+	return error;
+}
+
+/*
+ * Given a vnode, delete its ACL.
+ */
+int
+vacl_delete(struct lwp *l, struct vnode *vp, acl_type_t type)
+{
+	int error;
+
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	error = VOP_SETACL(vp, acl_type_unold(type), 0, l->l_cred);
+	VOP_UNLOCK(vp);
+	return error;
+}
+
+/*
+ * Given a vnode, check whether an ACL is appropriate for it
+ *
+ * XXXRW: No vnode lock held so can't audit vnode state...?
+ */
+int
+vacl_aclcheck(struct lwp *l, struct vnode *vp, acl_type_t type,
+    const struct acl *aclp)
+{
+	struct acl *inkernelacl;
+	int error;
+
+	inkernelacl = acl_alloc(KM_SLEEP);
+	error = acl_copyin(aclp, inkernelacl, type);
+	if (error != 0)
+		goto out;
+	error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
+	    l->l_cred);
+out:
+	acl_free(inkernelacl);
+	return error;
+}
+
+/*
+ * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
+ * need to lock, as the vacl_ code will get/release any locks required.
+ */
+
+/*
+ * Given a file path, get an ACL for it
+ */
+int
+sys___acl_get_file(struct lwp *l,
+     const struct sys___acl_get_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_get_path(l, SCARG(uap, path), SCARG(uap, type),
+	    SCARG(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, get an ACL for it; don't follow links.
+ */
+int
+sys___acl_get_link(struct lwp *l,
+    const struct sys___acl_get_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_get_path(l, SCARG(uap, path), SCARG(uap, type),
+	    SCARG(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+int
+kern___acl_get_path(struct lwp *l, const char *path, acl_type_t type,
+    struct acl *aclp, namei_simple_flags_t flags)
+{
+	struct vnode *path_vp;
+	int error;
+
+	error = namei_simple_user(path, flags, &path_vp);
+	if (error == 0) {
+		error = vacl_get_acl(l, path_vp, type, aclp);
+		vrele(path_vp);
+	}
+	return error;
+}
+
+/*
+ * Given a file path, set an ACL for it.
+ */
+int
+sys___acl_set_file(struct lwp *l,
+    const struct sys___acl_set_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_set_path(l, SCARG(uap, path), SCARG(uap, type),
+	    SCARG(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, set an ACL for it; don't follow links.
+ */
+int
+sys___acl_set_link(struct lwp *l,
+    const struct sys___acl_set_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_set_path(l, SCARG(uap, path), SCARG(uap, type),
+	    SCARG(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+int
+kern___acl_set_path(struct lwp *l, const char *path,
+    acl_type_t type, const struct acl *aclp, namei_simple_flags_t flags)
+{
+	struct vnode *path_vp;
+	int error;
+
+	error = namei_simple_user(path, flags, &path_vp);
+	if (error == 0) {
+		error = vacl_set_acl(l, path_vp, type, aclp);
+		vrele(path_vp);
+	}
+	return error;
+}
+
+/*
+ * Given a file descriptor, get an ACL for it.
+ */
+int
+sys___acl_get_fd(struct lwp *l, const struct sys___acl_get_fd_args *uap,
+    register_t *retval)
+{
+	struct file *fp;
+	int error;
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_get_acl(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file descriptor, set an ACL for it.
+ */
+int
+sys___acl_set_fd(struct lwp *l, const struct sys___acl_set_fd_args *uap,
+    register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_set_acl(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file path, delete an ACL from it.
+ */
+int
+sys___acl_delete_file(struct lwp *l,
+    const struct sys___acl_delete_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_delete_path(l, SCARG(uap, path), SCARG(uap, type),
+	    NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, delete an ACL from it; don't follow links.
+ */
+int
+sys___acl_delete_link(struct lwp *l,
+    const struct sys___acl_delete_link_args *uap, register_t *retval)
+{
+
+	return kern___acl_delete_path(l, SCARG(uap, path), SCARG(uap, type),
+	    NSM_NOFOLLOW_NOEMULROOT);
+}
+
+int
+kern___acl_delete_path(struct lwp *l, const char *path,
+    acl_type_t type, namei_simple_flags_t flags)
+{
+	struct vnode *path_vp;
+	int error;
+
+	error = namei_simple_user(path, flags, &path_vp);
+	if (error == 0) {
+		error = vacl_delete(l, path_vp, type);
+		vrele(path_vp);
+	}
+	return error;
+}
+
+/*
+ * Given a file path, delete an ACL from it.
+ */
+int
+sys___acl_delete_fd(struct lwp *l,
+    const struct sys___acl_delete_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_delete(l, fp->f_vnode, SCARG(uap, type));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+/*
+ * Given a file path, check an ACL for it.
+ */
+int
+sys___acl_aclcheck_file(struct lwp *l,
+    const struct sys___acl_aclcheck_file_args *uap, register_t *retval)
+{
+
+	return kern___acl_aclcheck_path(l, SCARG(uap, path), SCARG(uap, type),
+	    SCARG(uap, aclp), NSM_FOLLOW_NOEMULROOT);
+}
+
+/*
+ * Given a file path, check an ACL for it; don't follow links.
+ */
+int
+sys___acl_aclcheck_link(struct lwp *l,
+    const struct sys___acl_aclcheck_link_args *uap, register_t *retval)
+{
+	return kern___acl_aclcheck_path(l, SCARG(uap, path),
+	    SCARG(uap, type), SCARG(uap, aclp), NSM_NOFOLLOW_NOEMULROOT);
+}
+
+int
+kern___acl_aclcheck_path(struct lwp *l, const char *path, acl_type_t type,
+    struct acl *aclp, namei_simple_flags_t flags)
+{
+	struct vnode *path_vp;
+	int error;
+
+	error = namei_simple_user(path, flags, &path_vp);
+	if (error == 0) {
+		error = vacl_aclcheck(l, path_vp, type, aclp);
+		vrele(path_vp);
+
+	}
+	return error;
+}
+
+/*
+ * Given a file descriptor, check an ACL for it.
+ */
+int
+sys___acl_aclcheck_fd(struct lwp *l,
+    const struct sys___acl_aclcheck_fd_args *uap, register_t *retval)
+{
+	struct file *fp;
+	int error;
+
+	error = fd_getvnode(SCARG(uap, filedes), &fp);
+	if (error == 0) {
+		error = vacl_aclcheck(l, fp->f_vnode, SCARG(uap, type),
+		    SCARG(uap, aclp));
+		fd_putfile(SCARG(uap, filedes));
+	}
+	return error;
+}
+
+struct acl *
+acl_alloc(int flags)
+{
+	struct acl *aclp;
+
+	aclp = kmem_zalloc(sizeof(*aclp), flags);
+	if (aclp == NULL)
+		return NULL;
+
+	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
+
+	return aclp;
+}
+
+void
+acl_free(struct acl *aclp)
+{
+
+	kmem_free(aclp, sizeof(*aclp));
+}
Index: sys/kern/vfs_cache.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_cache.c,v
retrieving revision 1.142
diff -u -p -p -u -r1.142 vfs_cache.c
--- sys/kern/vfs_cache.c	12 May 2020 23:17:41 -0000	1.142
+++ sys/kern/vfs_cache.c	15 May 2020 16:56:53 -0000
@@ -689,8 +689,8 @@ cache_lookup_linked(struct vnode *dvp, c
 	KASSERT(dvi->vi_nc_uid != VNOVAL && dvi->vi_nc_gid != VNOVAL);
 	error = kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(VEXEC,
 	    dvp->v_type, dvi->vi_nc_mode & ALLPERMS), dvp, NULL,
-	    genfs_can_access(dvp->v_type, dvi->vi_nc_mode & ALLPERMS,
-	    dvi->vi_nc_uid, dvi->vi_nc_gid, VEXEC, cred));
+	    genfs_can_access(dvp, cred, dvi->vi_nc_uid, dvi->vi_nc_gid,
+	    dvi->vi_nc_mode & ALLPERMS, NULL, VEXEC));
 	if (error != 0) {
 		COUNT(ncs_denied);
 		return false;
@@ -741,7 +741,7 @@ cache_lookup_linked(struct vnode *dvp, c
  */
 int
 cache_revlookup(struct vnode *vp, struct vnode **dvpp, char **bpp, char *bufp,
-    bool checkaccess, int perms)
+    bool checkaccess, accmode_t accmode)
 {
 	vnode_impl_t *vi = VNODE_TO_VIMPL(vp);
 	struct namecache *ncp;
@@ -772,9 +772,9 @@ cache_revlookup(struct vnode *vp, struct
 		KASSERT(vi->vi_nc_uid != VNOVAL && vi->vi_nc_gid != VNOVAL);
 		error = kauth_authorize_vnode(curlwp->l_cred,
 		    KAUTH_ACCESS_ACTION(VEXEC, vp->v_type, vi->vi_nc_mode &
-		    ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
-		    vi->vi_nc_mode & ALLPERMS, vi->vi_nc_uid, vi->vi_nc_gid,
-		    perms, curlwp->l_cred));
+		    ALLPERMS), vp, NULL, genfs_can_access(vp, curlwp->l_cred,
+		    vi->vi_nc_uid, vi->vi_nc_gid, vi->vi_nc_mode & ALLPERMS,
+		    NULL, accmode));
 		    if (error != 0) {
 		    	rw_exit(&vi->vi_nc_listlock);
 			COUNT(ncs_denied);
Index: sys/kern/vfs_getcwd.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_getcwd.c,v
retrieving revision 1.59
diff -u -p -p -u -r1.59 vfs_getcwd.c
--- sys/kern/vfs_getcwd.c	21 Apr 2020 21:42:47 -0000	1.59
+++ sys/kern/vfs_getcwd.c	15 May 2020 16:56:53 -0000
@@ -277,7 +277,7 @@ getcwd_common(struct vnode *lvp, struct 
 	struct vnode *uvp = NULL;
 	char *bp = NULL;
 	int error;
-	int perms = VEXEC;
+	accmode_t accmode = VEXEC;
 
 	error = 0;
 	if (rvp == NULL) {
@@ -325,7 +325,7 @@ getcwd_common(struct vnode *lvp, struct 
 		if (lvp->v_vflag & VV_ROOT) {
 			vn_lock(lvp, LK_SHARED | LK_RETRY);
 			if (chkaccess) {
-				error = VOP_ACCESS(lvp, perms, cred);
+				error = VOP_ACCESS(lvp, accmode, cred);
 				if (error) {
 					VOP_UNLOCK(lvp);
 					goto out;
@@ -361,7 +361,7 @@ getcwd_common(struct vnode *lvp, struct 
 		if (chkaccess && !cache_have_id(lvp)) {
 			/* Need exclusive for UFS VOP_GETATTR (itimes) & VOP_LOOKUP. */
 			vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
-			error = VOP_ACCESS(lvp, perms, cred);
+			error = VOP_ACCESS(lvp, accmode, cred);
 			if (error) {
 				VOP_UNLOCK(lvp);
 				goto out;
@@ -375,7 +375,7 @@ getcwd_common(struct vnode *lvp, struct 
 		 * directory..
 		 */
 		error = cache_revlookup(lvp, &uvp, &bp, bufp, chkaccess,
-		    perms);
+		    accmode);
 		if (error == -1) {
 			if (!locked) {
 				locked = true;
@@ -398,7 +398,7 @@ getcwd_common(struct vnode *lvp, struct 
 			panic("getcwd: oops, went back too far");
 		}
 #endif
-		perms = VEXEC | VREAD;
+		accmode = VEXEC | VREAD;
 		if (bp)
 			*(--bp) = '/';
 		vrele(lvp);
Index: sys/kern/vfs_init.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_init.c,v
retrieving revision 1.50
diff -u -p -p -u -r1.50 vfs_init.c
--- sys/kern/vfs_init.c	21 Feb 2020 00:26:22 -0000	1.50
+++ sys/kern/vfs_init.c	15 May 2020 16:56:53 -0000
@@ -377,10 +377,10 @@ mount_listener_cb(kauth_cred_t cred, kau
 		result = KAUTH_RESULT_ALLOW;
 	else if (req == KAUTH_REQ_SYSTEM_MOUNT_DEVICE) {
 		vnode_t *devvp = arg2;
-		mode_t access_mode = (mode_t)(unsigned long)arg3;
+		accmode_t accmode = (accmode_t)(unsigned long)arg3;
 		int error;
 
-		error = VOP_ACCESS(devvp, access_mode, cred);
+		error = VOP_ACCESS(devvp, accmode, cred);
 		if (!error)
 			result = KAUTH_RESULT_ALLOW;
 	}
Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.486
diff -u -p -p -u -r1.486 vfs_subr.c
--- sys/kern/vfs_subr.c	21 Apr 2020 21:42:47 -0000	1.486
+++ sys/kern/vfs_subr.c	15 May 2020 16:56:53 -0000
@@ -1138,21 +1138,6 @@ vprint(const char *label, struct vnode *
 	}
 }
 
-/* Deprecated. Kept for KPI compatibility. */
-int
-vaccess(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
-    mode_t acc_mode, kauth_cred_t cred)
-{
-
-#ifdef DIAGNOSTIC
-	printf("vaccess: deprecated interface used.\n");
-#endif /* DIAGNOSTIC */
-
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(acc_mode,
-	    type, file_mode), NULL /* This may panic. */, NULL,
-	    genfs_can_access(type, file_mode, uid, gid, acc_mode, cred));
-}
-
 /*
  * Given a file system name, look up the vfsops for that
  * file system, or return NULL if file system isn't present
@@ -1278,6 +1263,53 @@ vfs_timestamp(struct timespec *ts)
 	nanotime(ts);
 }
 
+/*
+ * The purpose of this routine is to remove granularity from accmode_t,
+ * reducing it into standard unix access bits - VEXEC, VREAD, VWRITE,
+ * VADMIN and VAPPEND.
+ *
+ * If it returns 0, the caller is supposed to continue with the usual
+ * access checks using 'accmode' as modified by this routine.  If it
+ * returns nonzero value, the caller is supposed to return that value
+ * as errno.
+ *
+ * Note that after this routine runs, accmode may be zero.
+ */
+int
+vfs_unixify_accmode(accmode_t *accmode)
+{
+	/*
+	 * There is no way to specify explicit "deny" rule using
+	 * file mode or POSIX.1e ACLs.
+	 */
+	if (*accmode & VEXPLICIT_DENY) {
+		*accmode = 0;
+		return (0);
+	}
+
+	/*
+	 * None of these can be translated into usual access bits.
+	 * Also, the common case for NFSv4 ACLs is to not contain
+	 * either of these bits. Caller should check for VWRITE
+	 * on the containing directory instead.
+	 */
+	if (*accmode & (VDELETE_CHILD | VDELETE))
+		return (EPERM);
+
+	if (*accmode & VADMIN_PERMS) {
+		*accmode &= ~VADMIN_PERMS;
+		*accmode |= VADMIN;
+	}
+
+	/*
+	 * There is no way to deny VREAD_ATTRIBUTES, VREAD_ACL
+	 * or VSYNCHRONIZE using file mode or POSIX.1e ACL.
+	 */
+	*accmode &= ~(VSTAT_PERMS | VSYNCHRONIZE);
+
+	return (0);
+}
+
 time_t	rootfstime;			/* recorded root fs time, if known */
 void
 setrootfstime(time_t t)
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.547
diff -u -p -p -u -r1.547 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	21 Apr 2020 21:42:47 -0000	1.547
+++ sys/kern/vfs_syscalls.c	15 May 2020 16:56:53 -0000
@@ -3232,34 +3232,55 @@ sys_fstatat(struct lwp *l, const struct 
 	return copyout(&sb, SCARG(uap, buf), sizeof(sb));
 }
 
-/*
- * Get configurable pathname variables.
- */
-/* ARGSUSED */
-int
-sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval)
+static int
+kern_pathconf(register_t *retval, const char *path, int name, int flag)
 {
-	/* {
-		syscallarg(const char *) path;
-		syscallarg(int) name;
-	} */
 	int error;
 	struct pathbuf *pb;
 	struct nameidata nd;
 
-	error = pathbuf_copyin(SCARG(uap, path), &pb);
+	error = pathbuf_copyin(path, &pb);
 	if (error) {
 		return error;
 	}
-	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
+	NDINIT(&nd, LOOKUP, flag | LOCKLEAF | TRYEMULROOT, pb);
 	if ((error = namei(&nd)) != 0) {
 		pathbuf_destroy(pb);
-		return (error);
+		return error;
 	}
-	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
+	error = VOP_PATHCONF(nd.ni_vp, name, retval);
 	vput(nd.ni_vp);
 	pathbuf_destroy(pb);
-	return (error);
+	return error;
+}
+
+/*
+ * Get configurable pathname variables.
+ */
+/* ARGSUSED */
+int
+sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap,
+    register_t *retval)
+{
+	/* {
+		syscallarg(const char *) path;
+		syscallarg(int) name;
+	} */
+	return kern_pathconf(retval, SCARG(uap, path), SCARG(uap, name), 
+	    FOLLOW);
+}
+
+/* ARGSUSED */
+int
+sys_lpathconf(struct lwp *l, const struct sys_lpathconf_args *uap,
+    register_t *retval)
+{
+	/* {
+		syscallarg(const char *) path;
+		syscallarg(int) name;
+	} */
+	return kern_pathconf(retval, SCARG(uap, path), SCARG(uap, name), 
+	    NOFOLLOW);
 }
 
 /*
@@ -4393,6 +4414,8 @@ do_sys_renameat(struct lwp *l, int fromf
 	KASSERT(tdvp != NULL);
 	KASSERT((tdvp == tvp) || (VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE));
 
+	if (fvp->v_type == VDIR)
+		tnd.ni_cnd.cn_flags |= WILLBEDIR;
 	/*
 	 * Make sure neither tdvp nor tvp is locked.
 	 */
@@ -4683,6 +4706,7 @@ do_sys_mkdirat(struct lwp *l, int fdat, 
 	vattr.va_type = VDIR;
 	/* We will read cwdi->cwdi_cmask unlocked. */
 	vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
+	nd.ni_cnd.cn_flags |= WILLBEDIR;
 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
 	if (!error)
 		vrele(nd.ni_vp);
Index: sys/kern/vfs_xattr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_xattr.c,v
retrieving revision 1.34
diff -u -p -p -u -r1.34 vfs_xattr.c
--- sys/kern/vfs_xattr.c	20 Apr 2020 00:34:58 -0000	1.34
+++ sys/kern/vfs_xattr.c	15 May 2020 16:56:53 -0000
@@ -96,7 +96,7 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,
  * NOTE: Vnode must be locked.
  */
 int
-extattr_check_cred(struct vnode *vp, const char *attr, kauth_cred_t cred,
+extattr_check_cred(struct vnode *vp, int attrspace, kauth_cred_t cred,
     int access)
 {
 
@@ -104,7 +104,7 @@ extattr_check_cred(struct vnode *vp, con
 		return (0);
 
 	return kauth_authorize_vnode(cred, kauth_extattr_action(access), vp,
-	    NULL, genfs_can_extattr(cred, access, vp, attr));
+	    NULL, genfs_can_extattr(vp, cred, access, attrspace));
 }
 
 /*
Index: sys/kern/vnode_if.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.c,v
retrieving revision 1.110
diff -u -p -p -u -r1.110 vnode_if.c
--- sys/kern/vnode_if.c	23 Feb 2020 22:15:19 -0000	1.110
+++ sys/kern/vnode_if.c	15 May 2020 16:56:53 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnode_if.c,v 1.110 2020/02/23 22:15:19 ad Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnode_if.c,v 1.110 2020/02/23 22:15:19 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
@@ -349,7 +349,7 @@ const struct vnodeop_desc vop_access_des
 };
 int
 VOP_ACCESS(struct vnode *vp,
-    int mode,
+    accmode_t accmode,
     kauth_cred_t cred)
 {
 	int error;
@@ -358,7 +358,7 @@ VOP_ACCESS(struct vnode *vp,
 	struct mount *mp;
 	a.a_desc = VDESC(vop_access);
 	a.a_vp = vp;
-	a.a_mode = mode;
+	a.a_accmode = accmode;
 	a.a_cred = cred;
 	error = vop_pre(vp, &mp, &mpsafe, FST_NO);
 	if (error)
@@ -368,6 +368,40 @@ VOP_ACCESS(struct vnode *vp,
 	return error;
 }
 
+const int vop_accessx_vp_offsets[] = {
+	VOPARG_OFFSETOF(struct vop_accessx_args,a_vp),
+	VDESC_NO_OFFSET
+};
+const struct vnodeop_desc vop_accessx_desc = {
+	VOP_ACCESSX_DESCOFFSET,
+	"vop_accessx",
+	0,
+	vop_accessx_vp_offsets,
+	VDESC_NO_OFFSET,
+	VOPARG_OFFSETOF(struct vop_accessx_args, a_cred),
+	VDESC_NO_OFFSET,
+};
+int
+VOP_ACCESSX(struct vnode *vp,
+    accmode_t accmode,
+    kauth_cred_t cred)
+{
+	int error;
+	bool mpsafe;
+	struct vop_accessx_args a;
+	struct mount *mp;
+	a.a_desc = VDESC(vop_accessx);
+	a.a_vp = vp;
+	a.a_accmode = accmode;
+	a.a_cred = cred;
+	error = vop_pre(vp, &mp, &mpsafe, FST_NO);
+	if (error)
+		return error;
+	error = (VCALL(vp, VOFFSET(vop_accessx), &a));
+	vop_post(vp, mp, mpsafe, FST_NO);
+	return error;
+}
+
 const int vop_getattr_vp_offsets[] = {
 	VOPARG_OFFSETOF(struct vop_getattr_args,a_vp),
 	VDESC_NO_OFFSET
@@ -1634,6 +1668,114 @@ VOP_PUTPAGES(struct vnode *vp,
 	return error;
 }
 
+const int vop_getacl_vp_offsets[] = {
+	VOPARG_OFFSETOF(struct vop_getacl_args,a_vp),
+	VDESC_NO_OFFSET
+};
+const struct vnodeop_desc vop_getacl_desc = {
+	VOP_GETACL_DESCOFFSET,
+	"vop_getacl",
+	0,
+	vop_getacl_vp_offsets,
+	VDESC_NO_OFFSET,
+	VOPARG_OFFSETOF(struct vop_getacl_args, a_cred),
+	VDESC_NO_OFFSET,
+};
+int
+VOP_GETACL(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    kauth_cred_t cred)
+{
+	int error;
+	bool mpsafe;
+	struct vop_getacl_args a;
+	struct mount *mp;
+	a.a_desc = VDESC(vop_getacl);
+	a.a_vp = vp;
+	a.a_type = type;
+	a.a_aclp = aclp;
+	a.a_cred = cred;
+	error = vop_pre(vp, &mp, &mpsafe, FST_YES);
+	if (error)
+		return error;
+	error = (VCALL(vp, VOFFSET(vop_getacl), &a));
+	vop_post(vp, mp, mpsafe, FST_YES);
+	return error;
+}
+
+const int vop_setacl_vp_offsets[] = {
+	VOPARG_OFFSETOF(struct vop_setacl_args,a_vp),
+	VDESC_NO_OFFSET
+};
+const struct vnodeop_desc vop_setacl_desc = {
+	VOP_SETACL_DESCOFFSET,
+	"vop_setacl",
+	0,
+	vop_setacl_vp_offsets,
+	VDESC_NO_OFFSET,
+	VOPARG_OFFSETOF(struct vop_setacl_args, a_cred),
+	VDESC_NO_OFFSET,
+};
+int
+VOP_SETACL(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    kauth_cred_t cred)
+{
+	int error;
+	bool mpsafe;
+	struct vop_setacl_args a;
+	struct mount *mp;
+	a.a_desc = VDESC(vop_setacl);
+	a.a_vp = vp;
+	a.a_type = type;
+	a.a_aclp = aclp;
+	a.a_cred = cred;
+	error = vop_pre(vp, &mp, &mpsafe, FST_YES);
+	if (error)
+		return error;
+	error = (VCALL(vp, VOFFSET(vop_setacl), &a));
+	vop_post(vp, mp, mpsafe, FST_YES);
+	return error;
+}
+
+const int vop_aclcheck_vp_offsets[] = {
+	VOPARG_OFFSETOF(struct vop_aclcheck_args,a_vp),
+	VDESC_NO_OFFSET
+};
+const struct vnodeop_desc vop_aclcheck_desc = {
+	VOP_ACLCHECK_DESCOFFSET,
+	"vop_aclcheck",
+	0,
+	vop_aclcheck_vp_offsets,
+	VDESC_NO_OFFSET,
+	VOPARG_OFFSETOF(struct vop_aclcheck_args, a_cred),
+	VDESC_NO_OFFSET,
+};
+int
+VOP_ACLCHECK(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    kauth_cred_t cred)
+{
+	int error;
+	bool mpsafe;
+	struct vop_aclcheck_args a;
+	struct mount *mp;
+	a.a_desc = VDESC(vop_aclcheck);
+	a.a_vp = vp;
+	a.a_type = type;
+	a.a_aclp = aclp;
+	a.a_cred = cred;
+	error = vop_pre(vp, &mp, &mpsafe, FST_YES);
+	if (error)
+		return error;
+	error = (VCALL(vp, VOFFSET(vop_aclcheck), &a));
+	vop_post(vp, mp, mpsafe, FST_YES);
+	return error;
+}
+
 const int vop_closeextattr_vp_offsets[] = {
 	VOPARG_OFFSETOF(struct vop_closeextattr_args,a_vp),
 	VDESC_NO_OFFSET
@@ -1864,6 +2006,7 @@ const struct vnodeop_desc * const vfs_op
 	&vop_open_desc,
 	&vop_close_desc,
 	&vop_access_desc,
+	&vop_accessx_desc,
 	&vop_getattr_desc,
 	&vop_setattr_desc,
 	&vop_read_desc,
@@ -1900,6 +2043,9 @@ const struct vnodeop_desc * const vfs_op
 	&vop_whiteout_desc,
 	&vop_getpages_desc,
 	&vop_putpages_desc,
+	&vop_getacl_desc,
+	&vop_setacl_desc,
+	&vop_aclcheck_desc,
 	&vop_closeextattr_desc,
 	&vop_getextattr_desc,
 	&vop_listextattr_desc,
Index: sys/kern/vnode_if.sh
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.sh,v
retrieving revision 1.69
diff -u -p -p -u -r1.69 vnode_if.sh
--- sys/kern/vnode_if.sh	23 Feb 2020 22:14:04 -0000	1.69
+++ sys/kern/vnode_if.sh	15 May 2020 16:56:53 -0000
@@ -269,6 +269,8 @@ BEGIN	{
 		printf("struct flock;\n");
 		printf("struct knote;\n");
 		printf("struct vm_page;\n");
+		printf("struct acl;\n");
+		printf("\n#include <sys/acl.h>\n");
 	}
 	printf("\n#ifndef _KERNEL\n#include <stdbool.h>\n#endif\n");
 	if (rump)
Index: sys/kern/vnode_if.src
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.src,v
retrieving revision 1.78
diff -u -p -p -u -r1.78 vnode_if.src
--- sys/kern/vnode_if.src	11 Oct 2019 08:04:52 -0000	1.78
+++ sys/kern/vnode_if.src	15 May 2020 16:56:53 -0000
@@ -128,7 +128,16 @@ vop_close {
 #
 vop_access {
 	IN LOCKED=YES struct vnode *vp;
-	IN int mode;
+	IN accmode_t accmode;
+	IN kauth_cred_t cred;
+};
+
+#
+#% accessx    vp      L L L
+#
+vop_accessx {
+	IN LOCKED=YES struct vnode *vp;
+	IN accmode_t accmode;
 	IN kauth_cred_t cred;
 };
 
@@ -517,6 +526,36 @@ vop_putpages {
 };
 
 #
+#% getacl	vp L L L
+#
+vop_getacl {
+	IN struct vnode *vp;
+	IN acl_type_t type;
+	OUT struct acl *aclp;
+	IN kauth_cred_t cred;
+};
+
+#
+#% setacl	vp L L L
+#
+vop_setacl {
+	IN struct vnode *vp;
+	IN acl_type_t type;
+	IN struct acl *aclp;
+	IN kauth_cred_t cred;
+};
+
+#
+#% aclcheck	vp = = =
+#
+vop_aclcheck {
+	IN struct vnode *vp;
+	IN acl_type_t type;
+	IN struct acl *aclp;
+	IN kauth_cred_t cred;
+};
+
+#
 #% closeextattr	vp L L L
 #
 vop_closeextattr {
Index: sys/miscfs/fdesc/fdesc_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/fdesc/fdesc_vnops.c,v
retrieving revision 1.132
diff -u -p -p -u -r1.132 fdesc_vnops.c
--- sys/miscfs/fdesc/fdesc_vnops.c	1 Feb 2020 02:23:04 -0000	1.132
+++ sys/miscfs/fdesc/fdesc_vnops.c	15 May 2020 16:56:53 -0000
@@ -125,6 +125,7 @@ const struct vnodeopv_entry_desc fdesc_v
 	{ &vop_open_desc, fdesc_open },			/* open */
 	{ &vop_close_desc, fdesc_close },		/* close */
 	{ &vop_access_desc, fdesc_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, fdesc_getattr },		/* getattr */
 	{ &vop_setattr_desc, fdesc_setattr },		/* setattr */
 	{ &vop_read_desc, fdesc_read },			/* read */
Index: sys/miscfs/fifofs/fifo_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/fifofs/fifo_vnops.c,v
retrieving revision 1.79
diff -u -p -p -u -r1.79 fifo_vnops.c
--- sys/miscfs/fifofs/fifo_vnops.c	25 Oct 2017 08:12:39 -0000	1.79
+++ sys/miscfs/fifofs/fifo_vnops.c	15 May 2020 16:56:53 -0000
@@ -637,6 +637,7 @@ const struct vnodeopv_entry_desc fifo_vn
 	{ &vop_open_desc, fifo_open },			/* open */
 	{ &vop_close_desc, fifo_close },		/* close */
 	{ &vop_access_desc, genfs_ebadf },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, genfs_ebadf },		/* getattr */
 	{ &vop_setattr_desc, genfs_ebadf },		/* setattr */
 	{ &vop_read_desc, fifo_read },			/* read */
Index: sys/miscfs/genfs/genfs.h
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs.h,v
retrieving revision 1.33
diff -u -p -p -u -r1.33 genfs.h
--- sys/miscfs/genfs/genfs.h	17 Feb 2017 08:31:25 -0000	1.33
+++ sys/miscfs/genfs/genfs.h	15 May 2020 16:56:53 -0000
@@ -8,7 +8,10 @@
 
 struct componentname;
 struct mount;
+struct acl;
 
+int	genfs_access(void *);
+int	genfs_accessx(void *);
 int	genfs_badop(void *);
 int	genfs_nullop(void *);
 int	genfs_enoioctl(void *);
@@ -48,14 +51,19 @@ void	genfs_renamelock_exit(struct mount 
 
 int	genfs_suspendctl(struct mount *, int);
 
-int	genfs_can_access(enum vtype, mode_t, uid_t, gid_t, mode_t,
-	    kauth_cred_t);
-int	genfs_can_chmod(enum vtype, kauth_cred_t, uid_t, gid_t, mode_t);
-int	genfs_can_chown(kauth_cred_t, uid_t, gid_t, uid_t, gid_t);
-int	genfs_can_chtimes(vnode_t *, u_int, uid_t, kauth_cred_t);
-int	genfs_can_chflags(kauth_cred_t, enum vtype, uid_t, bool);
-int	genfs_can_sticky(kauth_cred_t, uid_t, uid_t);
-int	genfs_can_extattr(kauth_cred_t, int, vnode_t *, const char *);
+int	genfs_can_access(struct vnode *, kauth_cred_t, uid_t, gid_t, mode_t,
+    struct acl *, accmode_t);
+int	genfs_can_access_acl_posix1e(struct vnode *, kauth_cred_t, uid_t,
+    gid_t, mode_t, struct acl *, accmode_t);
+int	genfs_can_access_acl_nfs4(struct vnode *, kauth_cred_t, uid_t, gid_t,
+    mode_t, struct acl *, accmode_t);
+int	genfs_can_chmod(struct vnode *, kauth_cred_t, uid_t, gid_t, mode_t);
+int	genfs_can_chown(struct vnode *, kauth_cred_t, uid_t, gid_t, uid_t,
+    gid_t);
+int	genfs_can_chtimes(struct vnode *, kauth_cred_t, uid_t, u_int);
+int	genfs_can_chflags(struct vnode *, kauth_cred_t, uid_t, bool);
+int	genfs_can_sticky(struct vnode *, kauth_cred_t, uid_t, uid_t);
+int	genfs_can_extattr(struct vnode *, kauth_cred_t, int, int);
 
 /*
  * Rename is complicated.  Sorry.
Index: sys/miscfs/genfs/genfs_rename.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_rename.c,v
retrieving revision 1.3
diff -u -p -p -u -r1.3 genfs_rename.c
--- sys/miscfs/genfs/genfs_rename.c	30 Mar 2017 09:11:12 -0000	1.3
+++ sys/miscfs/genfs/genfs_rename.c	15 May 2020 16:56:53 -0000
@@ -1148,7 +1148,7 @@ genfs_ufslike_check_sticky(kauth_cred_t 
 {
 
 	if ((dmode & S_ISTXT) && (vp != NULL))
-		return genfs_can_sticky(cred, duid, uid);
+		return genfs_can_sticky(vp, cred, duid, uid);
 
 	return 0;
 }
Index: sys/miscfs/genfs/genfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_vnops.c,v
retrieving revision 1.203
diff -u -p -p -u -r1.203 genfs_vnops.c
--- sys/miscfs/genfs/genfs_vnops.c	25 Apr 2020 22:28:47 -0000	1.203
+++ sys/miscfs/genfs/genfs_vnops.c	15 May 2020 16:56:53 -0000
@@ -74,6 +74,7 @@ __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.
 #include <sys/file.h>
 #include <sys/kauth.h>
 #include <sys/stat.h>
+#include <sys/extattr.h>
 
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/genfs/genfs_node.h>
@@ -668,53 +669,519 @@ genfs_node_wrlocked(struct vnode *vp)
 	return rw_write_held(&gp->g_glock);
 }
 
+static int
+groupmember(gid_t gid, kauth_cred_t cred)
+{
+	int ismember;
+	int error = kauth_cred_ismember_gid(cred, gid, &ismember);
+	if (error)
+		return error;
+	if (kauth_cred_getegid(cred) == gid || ismember)
+		return 0;
+	return -1;
+}
+
 /*
- * Do the usual access checking.
- * file_mode, uid and gid are from the vnode in question,
- * while acc_mode and cred are from the VOP_ACCESS parameter list
+ * Common filesystem object access control check routine.  Accepts a
+ * vnode, cred, uid, gid, mode, acl, requested access mode.
+ * Returns 0 on success, or an errno on failure.
  */
 int
-genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
-    mode_t acc_mode, kauth_cred_t cred)
+genfs_can_access(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, gid_t file_gid,
+    mode_t file_mode, struct acl *acl, accmode_t accmode)
 {
-	mode_t mask;
-	int error, ismember;
+	accmode_t dac_granted;
+	int error;
+
+	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
+	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
+
+	/*
+	 * Look for a normal, non-privileged way to access the file/directory
+	 * as requested.  If it exists, go with that.
+	 */
 
-	mask = 0;
+	dac_granted = 0;
 
-	/* Otherwise, check the owner. */
-	if (kauth_cred_geteuid(cred) == uid) {
-		if (acc_mode & VEXEC)
-			mask |= S_IXUSR;
-		if (acc_mode & VREAD)
-			mask |= S_IRUSR;
-		if (acc_mode & VWRITE)
-			mask |= S_IWUSR;
-		return ((file_mode & mask) == mask ? 0 : EACCES);
+	/* Check the owner. */
+	if (kauth_cred_geteuid(cred) == file_uid) {
+		dac_granted |= VADMIN;
+		if (file_mode & S_IXUSR)
+			dac_granted |= VEXEC;
+		if (file_mode & S_IRUSR)
+			dac_granted |= VREAD;
+		if (file_mode & S_IWUSR)
+			dac_granted |= (VWRITE | VAPPEND);
+
+		return (accmode & dac_granted) == accmode ? 0 : EPERM;
 	}
 
+	/* Otherwise, check the groups (first match) */
 	/* Otherwise, check the groups. */
-	error = kauth_cred_ismember_gid(cred, gid, &ismember);
-	if (error)
-		return (error);
-	if (kauth_cred_getegid(cred) == gid || ismember) {
-		if (acc_mode & VEXEC)
-			mask |= S_IXGRP;
-		if (acc_mode & VREAD)
-			mask |= S_IRGRP;
-		if (acc_mode & VWRITE)
-			mask |= S_IWGRP;
-		return ((file_mode & mask) == mask ? 0 : EACCES);
+	error = groupmember(file_gid, cred);
+	if (error > 0)
+		return error;
+	if (error == 0) {
+		if (file_mode & S_IXGRP)
+			dac_granted |= VEXEC;
+		if (file_mode & S_IRGRP)
+			dac_granted |= VREAD;
+		if (file_mode & S_IWGRP)
+			dac_granted |= (VWRITE | VAPPEND);
+
+		return (accmode & dac_granted) == accmode ? 0 : EACCES;
 	}
 
 	/* Otherwise, check everyone else. */
-	if (acc_mode & VEXEC)
-		mask |= S_IXOTH;
-	if (acc_mode & VREAD)
-		mask |= S_IROTH;
-	if (acc_mode & VWRITE)
-		mask |= S_IWOTH;
-	return ((file_mode & mask) == mask ? 0 : EACCES);
+	if (file_mode & S_IXOTH)
+		dac_granted |= VEXEC;
+	if (file_mode & S_IROTH)
+		dac_granted |= VREAD;
+	if (file_mode & S_IWOTH)
+		dac_granted |= (VWRITE | VAPPEND);
+	return (accmode & dac_granted) == accmode ? 0 : EACCES;
+		return (0);
+}
+
+/*
+ * Implement a version of genfs_can_access() that understands POSIX.1e ACL
+ * semantics;
+ * the access ACL has already been prepared for evaluation by the file system
+ * and is passed via 'uid', 'gid', and 'acl'.  Return 0 on success, else an
+ * errno value.
+ */
+int
+genfs_can_access_acl_posix1e(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
+    gid_t file_gid, mode_t file_mode, struct acl *acl, accmode_t accmode)
+{
+	struct acl_entry *acl_other, *acl_mask;
+	accmode_t dac_granted;
+	accmode_t acl_mask_granted;
+	int group_matched, i;
+	int error;
+
+	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
+	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
+
+	/*
+	 * The owner matches if the effective uid associated with the
+	 * credential matches that of the ACL_USER_OBJ entry.  While we're
+	 * doing the first scan, also cache the location of the ACL_MASK and
+	 * ACL_OTHER entries, preventing some future iterations.
+	 */
+	acl_mask = acl_other = NULL;
+	for (i = 0; i < acl->acl_cnt; i++) {
+		struct acl_entry *ae = &acl->acl_entry[i];
+		switch (ae->ae_tag) {
+		case ACL_USER_OBJ:
+			if (kauth_cred_geteuid(cred) != file_uid)
+				break;
+			dac_granted = 0;
+			dac_granted |= VADMIN;
+			if (ae->ae_perm & ACL_EXECUTE)
+				dac_granted |= VEXEC;
+			if (ae->ae_perm & ACL_READ)
+				dac_granted |= VREAD;
+			if (ae->ae_perm & ACL_WRITE)
+				dac_granted |= (VWRITE | VAPPEND);
+			goto out;
+
+		case ACL_MASK:
+			acl_mask = ae;
+			break;
+
+		case ACL_OTHER:
+			acl_other = ae;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * An ACL_OTHER entry should always exist in a valid access ACL.  If
+	 * it doesn't, then generate a serious failure.	 For now, this means
+	 * a debugging message and EPERM, but in the future should probably
+	 * be a panic.
+	 */
+	if (acl_other == NULL) {
+		/*
+		 * XXX This should never happen
+		 */
+		printf("%s: ACL_OTHER missing\n", __func__);
+		return EPERM;
+	}
+
+	/*
+	 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
+	 * masked by an ACL_MASK entry, if any.	 As such, first identify the
+	 * ACL_MASK field, then iterate through identifying potential user
+	 * matches, then group matches.	 If there is no ACL_MASK, assume that
+	 * the mask allows all requests to succeed.
+	 */
+	if (acl_mask != NULL) {
+		acl_mask_granted = 0;
+		if (acl_mask->ae_perm & ACL_EXECUTE)
+			acl_mask_granted |= VEXEC;
+		if (acl_mask->ae_perm & ACL_READ)
+			acl_mask_granted |= VREAD;
+		if (acl_mask->ae_perm & ACL_WRITE)
+			acl_mask_granted |= (VWRITE | VAPPEND);
+	} else
+		acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
+
+	/*
+	 * Check ACL_USER ACL entries.	There will either be one or no
+	 * matches; if there is one, we accept or rejected based on the
+	 * match; otherwise, we continue on to groups.
+	 */
+	for (i = 0; i < acl->acl_cnt; i++) {
+		struct acl_entry *ae = &acl->acl_entry[i];
+		switch (ae->ae_tag) {
+		case ACL_USER:
+			if (kauth_cred_geteuid(cred) != ae->ae_id)
+				break;
+			dac_granted = 0;
+			if (ae->ae_perm & ACL_EXECUTE)
+				dac_granted |= VEXEC;
+			if (ae->ae_perm & ACL_READ)
+				dac_granted |= VREAD;
+			if (ae->ae_perm & ACL_WRITE)
+				dac_granted |= (VWRITE | VAPPEND);
+			dac_granted &= acl_mask_granted;
+			goto out;
+		}
+	}
+
+	/*
+	 * Group match is best-match, not first-match, so find a "best"
+	 * match.  Iterate across, testing each potential group match.	Make
+	 * sure we keep track of whether we found a match or not, so that we
+	 * know if we should try again with any available privilege, or if we
+	 * should move on to ACL_OTHER.
+	 */
+	group_matched = 0;
+	for (i = 0; i < acl->acl_cnt; i++) {
+		struct acl_entry *ae = &acl->acl_entry[i];
+		switch (ae->ae_tag) {
+		case ACL_GROUP_OBJ:
+			error = groupmember(file_gid, cred);
+			if (error > 0)
+				return error;
+			if (error)
+				break;
+			dac_granted = 0;
+			if (ae->ae_perm & ACL_EXECUTE)
+				dac_granted |= VEXEC;
+			if (ae->ae_perm & ACL_READ)
+				dac_granted |= VREAD;
+			if (ae->ae_perm & ACL_WRITE)
+				dac_granted |= (VWRITE | VAPPEND);
+			dac_granted  &= acl_mask_granted;
+
+			if ((accmode & dac_granted) == accmode)
+				return 0;
+
+			group_matched = 1;
+			break;
+
+		case ACL_GROUP:
+			error = groupmember(ae->ae_id, cred);
+			if (error > 0)
+				return error;
+			if (error)
+				break;
+			dac_granted = 0;
+			if (ae->ae_perm & ACL_EXECUTE)
+				dac_granted |= VEXEC;
+			if (ae->ae_perm & ACL_READ)
+				dac_granted |= VREAD;
+			if (ae->ae_perm & ACL_WRITE)
+				dac_granted |= (VWRITE | VAPPEND);
+			dac_granted  &= acl_mask_granted;
+
+			if ((accmode & dac_granted) == accmode)
+				return 0;
+
+			group_matched = 1;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (group_matched == 1) {
+		/*
+		 * There was a match, but it did not grant rights via pure
+		 * DAC.	 Try again, this time with privilege.
+		 */
+		for (i = 0; i < acl->acl_cnt; i++) {
+			struct acl_entry *ae = &acl->acl_entry[i];
+			switch (ae->ae_tag) {
+			case ACL_GROUP_OBJ:
+				error = groupmember(file_gid, cred);
+				if (error > 0)
+					return error;
+				if (error)
+					break;
+				dac_granted = 0;
+				if (ae->ae_perm & ACL_EXECUTE)
+					dac_granted |= VEXEC;
+				if (ae->ae_perm & ACL_READ)
+					dac_granted |= VREAD;
+				if (ae->ae_perm & ACL_WRITE)
+					dac_granted |= (VWRITE | VAPPEND);
+				dac_granted &= acl_mask_granted;
+				goto out;
+
+			case ACL_GROUP:
+				error = groupmember(ae->ae_id, cred);
+				if (error > 0)
+					return error;
+				if (error)
+					break;
+				dac_granted = 0;
+				if (ae->ae_perm & ACL_EXECUTE)
+				dac_granted |= VEXEC;
+				if (ae->ae_perm & ACL_READ)
+					dac_granted |= VREAD;
+				if (ae->ae_perm & ACL_WRITE)
+					dac_granted |= (VWRITE | VAPPEND);
+				dac_granted &= acl_mask_granted;
+
+				goto out;
+			default:
+				break;
+			}
+		}
+		/*
+		 * Even with privilege, group membership was not sufficient.
+		 * Return failure.
+		 */
+		dac_granted = 0;
+		goto out;
+	}
+		
+	/*
+	 * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
+	 */
+	dac_granted = 0;
+	if (acl_other->ae_perm & ACL_EXECUTE)
+		dac_granted |= VEXEC;
+	if (acl_other->ae_perm & ACL_READ)
+		dac_granted |= VREAD;
+	if (acl_other->ae_perm & ACL_WRITE)
+		dac_granted |= (VWRITE | VAPPEND);
+
+out:
+	if ((accmode & dac_granted) == accmode)
+		return 0;
+	return (accmode & VADMIN) ? EPERM : EACCES;
+}
+
+static struct {
+	accmode_t accmode;
+	int mask;
+} accmode2mask[] = {
+	{ VREAD, ACL_READ_DATA },
+	{ VWRITE, ACL_WRITE_DATA },
+	{ VAPPEND, ACL_APPEND_DATA },
+	{ VEXEC, ACL_EXECUTE },
+	{ VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS },
+	{ VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS },
+	{ VDELETE_CHILD, ACL_DELETE_CHILD },
+	{ VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES },
+	{ VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES },
+	{ VDELETE, ACL_DELETE },
+	{ VREAD_ACL, ACL_READ_ACL },
+	{ VWRITE_ACL, ACL_WRITE_ACL },
+	{ VWRITE_OWNER, ACL_WRITE_OWNER },
+	{ VSYNCHRONIZE, ACL_SYNCHRONIZE },
+	{ 0, 0 },
+};
+
+static int
+_access_mask_from_accmode(accmode_t accmode)
+{
+	int access_mask = 0, i;
+
+	for (i = 0; accmode2mask[i].accmode != 0; i++) {
+		if (accmode & accmode2mask[i].accmode)
+			access_mask |= accmode2mask[i].mask;
+	}
+
+	/*
+	 * VAPPEND is just a modifier for VWRITE; if the caller asked
+	 * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only.
+	 */
+	if (access_mask & ACL_APPEND_DATA)
+		access_mask &= ~ACL_WRITE_DATA;
+
+	return (access_mask);
+}
+
+/*
+ * Return 0, iff access is allowed, 1 otherwise.
+ */
+static int
+_acl_denies(const struct acl *aclp, int access_mask, kauth_cred_t cred,
+    int file_uid, int file_gid, int *denied_explicitly)
+{
+	int i, error;
+	const struct acl_entry *ae;
+
+	if (denied_explicitly != NULL)
+		*denied_explicitly = 0;
+
+	KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES);
+
+	for (i = 0; i < aclp->acl_cnt; i++) {
+		ae = &(aclp->acl_entry[i]);
+
+		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
+		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
+			continue;
+		if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY)
+			continue;
+		switch (ae->ae_tag) {
+		case ACL_USER_OBJ:
+			if (kauth_cred_geteuid(cred) != file_uid)
+				continue;
+			break;
+		case ACL_USER:
+			if (kauth_cred_geteuid(cred) != ae->ae_id)
+				continue;
+			break;
+		case ACL_GROUP_OBJ:
+			error = groupmember(file_gid, cred);
+			if (error > 0)
+				return error;
+			if (error != 0)
+				continue;
+			break;
+		case ACL_GROUP:
+			error = groupmember(ae->ae_id, cred);
+			if (error > 0)
+				return error;
+			if (error != 0)
+				continue;
+			break;
+		default:
+			KASSERT(ae->ae_tag == ACL_EVERYONE);
+		}
+
+		if (ae->ae_entry_type == ACL_ENTRY_TYPE_DENY) {
+			if (ae->ae_perm & access_mask) {
+				if (denied_explicitly != NULL)
+					*denied_explicitly = 1;
+				return (1);
+			}
+		}
+
+		access_mask &= ~(ae->ae_perm);
+		if (access_mask == 0)
+			return (0);
+	}
+
+	if (access_mask == 0)
+		return (0);
+
+	return (1);
+}
+
+int
+genfs_can_access_acl_nfs4(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
+    gid_t file_gid, mode_t file_mode, struct acl *aclp, accmode_t accmode)
+{
+	int denied, explicitly_denied, access_mask, is_directory,
+	    must_be_owner = 0;
+	file_mode = 0;
+
+	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND |
+	    VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS |
+	    VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE |
+	    VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0);
+	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
+
+#ifdef ACL_DEBUG
+	char buf[128];
+	snprintb(buf, sizeof(buf), __VNODE_PERM_BITS, accmode);
+	printf("%s: %s uid=%d gid=%d\n", __func__, buf, file_uid, file_gid);
+#endif
+
+	if (accmode & VADMIN)
+		must_be_owner = 1;
+
+	/*
+	 * Ignore VSYNCHRONIZE permission.
+	 */
+	accmode &= ~VSYNCHRONIZE;
+
+	access_mask = _access_mask_from_accmode(accmode);
+
+	if (vp && vp->v_type == VDIR)
+		is_directory = 1;
+	else
+		is_directory = 0;
+
+	/*
+	 * File owner is always allowed to read and write the ACL
+	 * and basic attributes.  This is to prevent a situation
+	 * where user would change ACL in a way that prevents him
+	 * from undoing the change.
+	 */
+	if (kauth_cred_geteuid(cred) == file_uid)
+		access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL |
+		    ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES);
+
+	/*
+	 * Ignore append permission for regular files; use write
+	 * permission instead.
+	 */
+	if (!is_directory && (access_mask & ACL_APPEND_DATA)) {
+		access_mask &= ~ACL_APPEND_DATA;
+		access_mask |= ACL_WRITE_DATA;
+	}
+
+	denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid,
+	    &explicitly_denied);
+
+	if (must_be_owner) {
+		if (kauth_cred_geteuid(cred) != file_uid)
+			denied = EPERM;
+	}
+
+	/*
+	 * For VEXEC, ensure that at least one execute bit is set for
+	 * non-directories. We have to check the mode here to stay
+	 * consistent with execve(2). See the test in
+	 * exec_check_permissions().
+	 */
+	__acl_nfs4_sync_mode_from_acl(&file_mode, aclp);
+	if (!denied && !is_directory && (accmode & VEXEC) &&
+	    (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
+		denied = EACCES;
+
+	if (!denied)
+		return (0);
+
+	/*
+	 * Access failed.  Iff it was not denied explicitly and
+	 * VEXPLICIT_DENY flag was specified, allow access.
+	 */
+	if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0)
+		return (0);
+
+	accmode &= ~VEXPLICIT_DENY;
+
+	if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE))
+		denied = EPERM;
+	else
+		denied = EACCES;
+
+	return (denied);
 }
 
 /*
@@ -724,29 +1191,32 @@ genfs_can_access(enum vtype type, mode_t
  *   - You must own the file, and
  *     - You must not set the "sticky" bit (meaningless, see chmod(2))
  *     - You must be a member of the group if you're trying to set the
- *       SGIDf bit
+ *	 SGIDf bit
  *
- * cred - credentials of the invoker
  * vp - vnode of the file-system object
+ * cred - credentials of the invoker
  * cur_uid, cur_gid - current uid/gid of the file-system object
  * new_mode - new mode for the file-system object
  *
  * Returns 0 if the change is allowed, or an error value otherwise.
  */
 int
-genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid,
+genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
     gid_t cur_gid, mode_t new_mode)
 {
 	int error;
 
-	/* The user must own the file. */
-	if (kauth_cred_geteuid(cred) != cur_uid)
-		return (EPERM);
+	/*
+	 * To modify the permissions on a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0)
+		return (error);
 
 	/*
 	 * Unprivileged users can't set the sticky bit on files.
 	 */
-	if ((type != VDIR) && (new_mode & S_ISTXT))
+	if ((vp->v_type != VDIR) && (new_mode & S_ISTXT))
 		return (EFTYPE);
 
 	/*
@@ -762,6 +1232,12 @@ genfs_can_chmod(enum vtype type, kauth_c
 			return (EPERM);
 	}
 
+	/*
+	 * Deny setting setuid if we are not the file owner.
+	 */
+	if ((new_mode & S_ISUID) && cur_uid != kauth_cred_geteuid(cred))
+		return (EPERM);
+
 	return (0);
 }
 
@@ -773,6 +1249,7 @@ genfs_can_chmod(enum vtype type, kauth_c
  *     - You must not try to change ownership, and
  *     - You must be member of the new group
  *
+ * vp - vnode
  * cred - credentials of the invoker
  * cur_uid, cur_gid - current uid/gid of the file-system object
  * new_uid, new_gid - target uid/gid of the file-system object
@@ -780,12 +1257,19 @@ genfs_can_chmod(enum vtype type, kauth_c
  * Returns 0 if the change is allowed, or an error value otherwise.
  */
 int	
-genfs_can_chown(kauth_cred_t cred, uid_t cur_uid,
+genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
     gid_t cur_gid, uid_t new_uid, gid_t new_gid)
 {
 	int error, ismember;
 
 	/*
+	 * To modify the ownership of a file, must possess VADMIN for that
+	 * file.
+	 */
+	if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0)
+		return (error);
+
+	/*
 	 * You can only change ownership of a file if:
 	 * You own the file and...
 	 */
@@ -822,10 +1306,23 @@ genfs_can_chown(kauth_cred_t cred, uid_t
 }
 
 int
-genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid,
-    kauth_cred_t cred)
+genfs_can_chtimes(vnode_t *vp, kauth_cred_t cred, uid_t owner_uid,
+    u_int vaflags)
 {
 	int error;
+	/*
+	 * Grant permission if the caller is the owner of the file, or
+	 * the super-user, or has ACL_WRITE_ATTRIBUTES permission on
+	 * on the file.	 If the time pointer is null, then write
+	 * permission on the file is also sufficient.
+	 *
+	 * From NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes: 
+	 * A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES
+	 * will be allowed to set the times [..] to the current 
+	 * server time.
+	 */
+	if ((error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred)) != 0)
+		return (error);
 
 	/* Must be owner, or... */
 	if (kauth_cred_geteuid(cred) == owner_uid)
@@ -851,13 +1348,14 @@ genfs_can_chtimes(vnode_t *vp, u_int vaf
  *   - You must not change system flags, and
  *   - You must not change flags on character/block devices.
  *
+ * vp - vnode
  * cred - credentials of the invoker
  * owner_uid - uid of the file-system object
  * changing_sysflags - true if the invoker wants to change system flags
  */
 int
-genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid,
-    bool changing_sysflags)
+genfs_can_chflags(vnode_t *vp, kauth_cred_t cred,
+     uid_t owner_uid, bool changing_sysflags)
 {
 
 	/* The user must own the file. */
@@ -873,7 +1371,7 @@ genfs_can_chflags(kauth_cred_t cred, enu
 	 * Unprivileged users cannot change the flags on devices, even if they
 	 * own them.
 	 */
-	if (type == VCHR || type == VBLK) {
+	if (vp->v_type == VCHR || vp->v_type == VBLK) {
 		return EPERM;
 	}
 
@@ -891,7 +1389,7 @@ genfs_can_chflags(kauth_cred_t cred, enu
  *   directory or the file being deleted.
  */
 int
-genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
+genfs_can_sticky(vnode_t *vp, kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
 {
 	if (kauth_cred_geteuid(cred) != dir_uid &&
 	    kauth_cred_geteuid(cred) != file_uid)
@@ -901,16 +1399,49 @@ genfs_can_sticky(kauth_cred_t cred, uid_
 }
 
 int
-genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp,
-    const char *attr)
+genfs_can_extattr(vnode_t *vp, kauth_cred_t cred, int accmode,
+    int attrnamespace)
 {
 	/*
-	 * This string comparison is bogus: see xattr_native in vfs_xattr.c;
-	 * it is going to go away soon.
+	 * Kernel-invoked always succeeds.
 	 */
-	if (strncasecmp(attr, "system.", 7) == 0)
-	       return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR,
-		   0, vp->v_mount, NULL, NULL);
+	if (cred == NOCRED)
+		return 0;
+
+	switch (attrnamespace) {
+	case EXTATTR_NAMESPACE_SYSTEM:
+		return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR,
+		    0, vp->v_mount, NULL, NULL);
+	case EXTATTR_NAMESPACE_USER:
+		return VOP_ACCESS(vp, accmode, cred);
+	default:
+		return EPERM;
+	}
+}
+
+int
+genfs_access(void *v)
+{
+	struct vop_access_args *ap = v;
+
+	KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN |
+	    VAPPEND)) == 0);
+
+	return VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred);
+}
+
+int
+genfs_accessx(void *v)
+{
+	struct vop_accessx_args *ap = v;
+	int error;
+	accmode_t accmode = ap->a_accmode;
+	error = vfs_unixify_accmode(&accmode);
+	if (error != 0)
+		return error;
+
+	if (accmode == 0)
+		return 0;
 
-	return VOP_ACCESS(vp, access_mode, cred);
+	return VOP_ACCESS(ap->a_vp, accmode, ap->a_cred);
 }
Index: sys/miscfs/genfs/layer_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/layer_vnops.c,v
retrieving revision 1.70
diff -u -p -p -u -r1.70 layer_vnops.c
--- sys/miscfs/genfs/layer_vnops.c	13 Apr 2020 19:23:19 -0000	1.70
+++ sys/miscfs/genfs/layer_vnops.c	15 May 2020 16:56:53 -0000
@@ -466,19 +466,19 @@ layer_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 		struct lwp *a_l;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
-	mode_t mode = ap->a_mode;
+	accmode_t accmode = ap->a_accmode;
 
 	/*
 	 * Disallow write attempts on read-only layers;
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
Index: sys/miscfs/kernfs/kernfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/kernfs/kernfs_vnops.c,v
retrieving revision 1.164
diff -u -p -p -u -r1.164 kernfs_vnops.c
--- sys/miscfs/kernfs/kernfs_vnops.c	24 Feb 2020 20:44:25 -0000	1.164
+++ sys/miscfs/kernfs/kernfs_vnops.c	15 May 2020 16:56:54 -0000
@@ -188,6 +188,7 @@ const struct vnodeopv_entry_desc kernfs_
 	{ &vop_open_desc, kernfs_open },		/* open */
 	{ &vop_close_desc, kernfs_close },		/* close */
 	{ &vop_access_desc, kernfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, kernfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, kernfs_setattr },		/* setattr */
 	{ &vop_read_desc, kernfs_read },		/* read */
@@ -236,6 +237,7 @@ const struct vnodeopv_entry_desc kernfs_
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, spec_close },		/* close */
 	{ &vop_access_desc, kernfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, kernfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, kernfs_setattr },		/* setattr */
 	{ &vop_read_desc, spec_read },			/* read */
@@ -640,7 +642,7 @@ kernfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vattr va;
@@ -650,9 +652,9 @@ kernfs_access(void *v)
 		return (error);
 
 	return kauth_authorize_vnode(ap->a_cred,
-	    KAUTH_ACCESS_ACTION(ap->a_mode, ap->a_vp->v_type, va.va_mode),
-	    ap->a_vp, NULL, genfs_can_access(va.va_type, va.va_mode,
-	    va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode),
+	    ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred,
+	    va.va_uid, va.va_gid, va.va_mode, NULL, ap->a_accmode));
 }
 
 static int
Index: sys/miscfs/nullfs/null_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/nullfs/null_vnops.c,v
retrieving revision 1.42
diff -u -p -p -u -r1.42 null_vnops.c
--- sys/miscfs/nullfs/null_vnops.c	4 Jun 2017 08:02:26 -0000	1.42
+++ sys/miscfs/nullfs/null_vnops.c	15 May 2020 16:56:54 -0000
@@ -103,6 +103,7 @@ const struct vnodeopv_entry_desc null_vn
 	{ &vop_setattr_desc,	layer_setattr },
 	{ &vop_getattr_desc,	layer_getattr },
 	{ &vop_access_desc,	layer_access },
+	{ &vop_accessx_desc,	genfs_accessx },
 	{ &vop_fsync_desc,	layer_fsync },
 	{ &vop_inactive_desc,	layer_inactive },
 	{ &vop_reclaim_desc,	layer_reclaim },
Index: sys/miscfs/overlay/overlay_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/overlay/overlay_vnops.c,v
retrieving revision 1.24
diff -u -p -p -u -r1.24 overlay_vnops.c
--- sys/miscfs/overlay/overlay_vnops.c	4 Jun 2017 08:02:26 -0000	1.24
+++ sys/miscfs/overlay/overlay_vnops.c	15 May 2020 16:56:54 -0000
@@ -151,6 +151,7 @@ const struct vnodeopv_entry_desc overlay
 	{ &vop_setattr_desc,  layer_setattr },
 	{ &vop_getattr_desc,  layer_getattr },
 	{ &vop_access_desc,   layer_access },
+	{ &vop_accessx_desc,  genfs_accessx },
 	{ &vop_fsync_desc,    layer_fsync },
 	{ &vop_inactive_desc, layer_inactive },
 	{ &vop_reclaim_desc,  layer_reclaim },
Index: sys/miscfs/procfs/procfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_vnops.c,v
retrieving revision 1.212
diff -u -p -p -u -r1.212 procfs_vnops.c
--- sys/miscfs/procfs/procfs_vnops.c	29 Apr 2020 01:56:54 -0000	1.212
+++ sys/miscfs/procfs/procfs_vnops.c	15 May 2020 16:56:54 -0000
@@ -261,6 +261,7 @@ const struct vnodeopv_entry_desc procfs_
 	{ &vop_open_desc, procfs_open },		/* open */
 	{ &vop_close_desc, procfs_close },		/* close */
 	{ &vop_access_desc, procfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, procfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, procfs_setattr },		/* setattr */
 	{ &vop_read_desc, procfs_read },		/* read */
@@ -969,7 +970,7 @@ procfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int a_mode;
+		accmode_t a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vattr va;
@@ -979,9 +980,9 @@ procfs_access(void *v)
 		return (error);
 
 	return kauth_authorize_vnode(ap->a_cred,
-	    KAUTH_ACCESS_ACTION(ap->a_mode, ap->a_vp->v_type, va.va_mode),
-	    ap->a_vp, NULL, genfs_can_access(va.va_type, va.va_mode,
-	    va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode),
+	    ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred,
+	    va.va_uid, va.va_gid, va.va_mode, NULL, ap->a_accmode));
 }
 
 /*
Index: sys/miscfs/specfs/spec_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v
retrieving revision 1.177
diff -u -p -p -u -r1.177 spec_vnops.c
--- sys/miscfs/specfs/spec_vnops.c	13 Apr 2020 20:02:27 -0000	1.177
+++ sys/miscfs/specfs/spec_vnops.c	15 May 2020 16:56:54 -0000
@@ -121,6 +121,7 @@ const struct vnodeopv_entry_desc spec_vn
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, spec_close },		/* close */
 	{ &vop_access_desc, spec_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, spec_getattr },		/* getattr */
 	{ &vop_setattr_desc, spec_setattr },		/* setattr */
 	{ &vop_read_desc, spec_read },			/* read */
Index: sys/miscfs/umapfs/umap_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/umapfs/umap_vnops.c,v
retrieving revision 1.60
diff -u -p -p -u -r1.60 umap_vnops.c
--- sys/miscfs/umapfs/umap_vnops.c	4 Jun 2017 08:02:26 -0000	1.60
+++ sys/miscfs/umapfs/umap_vnops.c	15 May 2020 16:56:54 -0000
@@ -92,6 +92,7 @@ const struct vnodeopv_entry_desc umap_vn
 	{ &vop_close_desc,	layer_close },
 	{ &vop_setattr_desc,	layer_setattr },
 	{ &vop_access_desc,	layer_access },
+	{ &vop_accessx_desc,	genfs_accessx },
 	{ &vop_remove_desc,	layer_remove },
 	{ &vop_revoke_desc,	layer_revoke },
 	{ &vop_rmdir_desc,	layer_rmdir },
Index: sys/modules/compat_netbsd32/Makefile
===================================================================
RCS file: /cvsroot/src/sys/modules/compat_netbsd32/Makefile,v
retrieving revision 1.34
diff -u -p -p -u -r1.34 Makefile
--- sys/modules/compat_netbsd32/Makefile	2 May 2020 22:19:47 -0000	1.34
+++ sys/modules/compat_netbsd32/Makefile	15 May 2020 16:56:54 -0000
@@ -29,6 +29,7 @@ CPPFLAGS+=	-I${NETBSDSRCDIR}/sys/externa
 .if ${NETBSD32_DRMKMS:Uno} == "yes"
 SRCS+=	netbsd32_drm.c
 .endif
+SRCS+=	netbsd32_acl.c
 SRCS+=	netbsd32_core.c		netbsd32_event.c
 SRCS+=	netbsd32_exec_elf32.c	netbsd32_execve.c
 SRCS+=	netbsd32_fd.c		netbsd32_fs.c
Index: sys/modules/ffs/Makefile
===================================================================
RCS file: /cvsroot/src/sys/modules/ffs/Makefile,v
retrieving revision 1.14
diff -u -p -p -u -r1.14 Makefile
--- sys/modules/ffs/Makefile	18 Apr 2020 19:18:33 -0000	1.14
+++ sys/modules/ffs/Makefile	15 May 2020 16:56:54 -0000
@@ -6,7 +6,7 @@
 
 KMOD=	ffs
 CPPFLAGS+=      -DUFS_DIRHASH -DFFS_EI -DWAPBL -DAPPLE_UFS -DQUOTA -DQUOTA2
-CPPFLAGS+=	-DUFS_EXTATTR
+CPPFLAGS+=	-DUFS_EXTATTR -DUFS_ACL
 
 CWARNFLAGS.clang=	-Wno-conversion
 
Index: sys/modules/ufs/Makefile
===================================================================
RCS file: /cvsroot/src/sys/modules/ufs/Makefile,v
retrieving revision 1.3
diff -u -p -p -u -r1.3 Makefile
--- sys/modules/ufs/Makefile	12 Apr 2020 01:39:57 -0000	1.3
+++ sys/modules/ufs/Makefile	15 May 2020 16:56:54 -0000
@@ -5,12 +5,12 @@
 KMOD=	ufs
 
 CPPFLAGS+=      -DUFS_DIRHASH -DFFS_EI -DWAPBL -DAPPLE_UFS -DQUOTA -DQUOTA2
-CPPFLAGS+=	-DUFS_EXTATTR
+CPPFLAGS+=	-DUFS_EXTATTR -DUFS_ACL
 
 CWARNFLAGS.clang=	-Wno-conversion
 
 .PATH:	${S}/ufs/ufs
-SRCS=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c \
+SRCS=	ufs_acl.c ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c \
 	ufs_lookup.c ufs_quota.c ufs_quota1.c ufs_quota2.c ufs_rename.c \
 	ufs_vfsops.c ufs_vnops.c quota1_subr.c quota2_subr.c
 
Index: sys/nfs/nfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.314
diff -u -p -p -u -r1.314 nfs_vnops.c
--- sys/nfs/nfs_vnops.c	13 Apr 2020 19:23:20 -0000	1.314
+++ sys/nfs/nfs_vnops.c	15 May 2020 16:56:54 -0000
@@ -103,6 +103,7 @@ const struct vnodeopv_entry_desc nfsv2_v
 	{ &vop_open_desc, nfs_open },			/* open */
 	{ &vop_close_desc, nfs_close },			/* close */
 	{ &vop_access_desc, nfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, nfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, nfs_setattr },		/* setattr */
 	{ &vop_read_desc, nfs_read },			/* read */
@@ -156,6 +157,7 @@ const struct vnodeopv_entry_desc spec_nf
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, nfsspec_close },		/* close */
 	{ &vop_access_desc, nfsspec_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, nfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, nfs_setattr },		/* setattr */
 	{ &vop_read_desc, nfsspec_read },		/* read */
@@ -206,6 +208,7 @@ const struct vnodeopv_entry_desc fifo_nf
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, nfsfifo_close },		/* close */
 	{ &vop_access_desc, nfsspec_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, nfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, nfs_setattr },		/* setattr */
 	{ &vop_read_desc, nfsfifo_read },		/* read */
@@ -316,7 +319,7 @@ nfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
@@ -344,9 +347,9 @@ nfs_access(void *v)
 	 */
 	if (cachevalid) {
 		if (!np->n_accerror) {
-			if  ((np->n_accmode & ap->a_mode) == ap->a_mode)
+			if  ((np->n_accmode & ap->a_accmode) == ap->a_accmode)
 				return np->n_accerror;
-		} else if ((np->n_accmode & ap->a_mode) == np->n_accmode)
+		} else if ((np->n_accmode & ap->a_accmode) == np->n_accmode)
 			return np->n_accerror;
 	}
 
@@ -364,20 +367,20 @@ nfs_access(void *v)
 		nfsm_reqhead(np, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
 		nfsm_fhtom(np, v3);
 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
-		if (ap->a_mode & VREAD)
+		if (ap->a_accmode & VREAD)
 			mode = NFSV3ACCESS_READ;
 		else
 			mode = 0;
 		if (vp->v_type != VDIR) {
-			if (ap->a_mode & VWRITE)
+			if (ap->a_accmode & VWRITE)
 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
-			if (ap->a_mode & VEXEC)
+			if (ap->a_accmode & VEXEC)
 				mode |= NFSV3ACCESS_EXECUTE;
 		} else {
-			if (ap->a_mode & VWRITE)
+			if (ap->a_accmode & VWRITE)
 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
 					 NFSV3ACCESS_DELETE);
-			if (ap->a_mode & VEXEC)
+			if (ap->a_accmode & VEXEC)
 				mode |= NFSV3ACCESS_LOOKUP;
 		}
 		*tl = txdr_unsigned(mode);
@@ -404,7 +407,7 @@ nfs_access(void *v)
 	 * unless the file is a socket, fifo, or a block or character
 	 * device resident on the filesystem.
 	 */
-	if (!error && (ap->a_mode & VWRITE) &&
+	if (!error && (ap->a_accmode & VWRITE) &&
 	    (vp->v_mount->mnt_flag & MNT_RDONLY)) {
 		switch (vp->v_type) {
 		case VREG:
@@ -425,13 +428,13 @@ nfs_access(void *v)
 		if (cachevalid && np->n_accstamp != -1 &&
 		    error == np->n_accerror) {
 			if (!error)
-				np->n_accmode |= ap->a_mode;
-			else if ((np->n_accmode & ap->a_mode) == ap->a_mode)
-				np->n_accmode = ap->a_mode;
+				np->n_accmode |= ap->a_accmode;
+			else if ((np->n_accmode & ap->a_accmode) == ap->a_accmode)
+				np->n_accmode = ap->a_accmode;
 		} else {
 			np->n_accstamp = time_uptime;
 			np->n_accuid = kauth_cred_geteuid(ap->a_cred);
-			np->n_accmode = ap->a_mode;
+			np->n_accmode = ap->a_accmode;
 			np->n_accerror = error;
 		}
 	}
@@ -3346,7 +3349,7 @@ nfsspec_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 		struct lwp *a_l;
 	} */ *ap = v;
@@ -3363,7 +3366,7 @@ nfsspec_access(void *v)
 	 * unless the file is a socket, fifo, or a block or character
 	 * device resident on the filesystem.
 	 */
-	if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+	if ((ap->a_accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
 		switch (vp->v_type) {
 		case VREG:
 		case VDIR:
@@ -3374,9 +3377,10 @@ nfsspec_access(void *v)
 		}
 	}
 
-	return kauth_authorize_vnode(ap->a_cred, KAUTH_ACCESS_ACTION(ap->a_mode,
-	    va.va_type, va.va_mode), vp, NULL, genfs_can_access(va.va_type,
-	    va.va_mode, va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
+	return kauth_authorize_vnode(ap->a_cred, KAUTH_ACCESS_ACTION(
+	    ap->a_accmode, va.va_type, va.va_mode), vp, NULL, genfs_can_access(
+	    vp, ap->a_cred, va.va_uid, va.va_gid, va.va_mode, NULL,
+	    ap->a_accmode));
 }
 
 /*
Index: sys/rump/rump.sysmap
===================================================================
RCS file: /cvsroot/src/sys/rump/rump.sysmap,v
retrieving revision 1.6
diff -u -p -p -u -r1.6 rump.sysmap
--- sys/rump/rump.sysmap	22 Sep 2019 23:03:20 -0000	1.6
+++ sys/rump/rump.sysmap	15 May 2020 16:56:54 -0000
@@ -217,3 +217,4 @@
 484  sys___statvfs190       __statvfs190       rump___sysimpl_statvfs190
 485  sys___fstatvfs190      __fstatvfs190      rump___sysimpl_fstatvfs190
 486  sys___fhstatvfs190     __fhstatvfs190     rump___sysimpl_fhstatvfs190
+499  sys_lpathconf          lpathconf          rump___sysimpl_lpathconf
Index: sys/rump/fs/lib/libffs/Makefile
===================================================================
RCS file: /cvsroot/src/sys/rump/fs/lib/libffs/Makefile,v
retrieving revision 1.19
diff -u -p -p -u -r1.19 Makefile
--- sys/rump/fs/lib/libffs/Makefile	25 Apr 2020 15:42:15 -0000	1.19
+++ sys/rump/fs/lib/libffs/Makefile	15 May 2020 16:56:54 -0000
@@ -10,12 +10,12 @@ SRCS=	ffs_alloc.c ffs_appleufs.c ffs_bal
 	ffs_snapshot.c ffs_subr.c ffs_tables.c ffs_vfsops.c ffs_vnops.c	\
 	ffs_wapbl.c ffs_quota2.c ffs_extattr.c
 
-SRCS+=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c	\
-	ufs_lookup.c ufs_rename.c ufs_vfsops.c ufs_vnops.c	\
-	ufs_quota.c ufs_quota2.c quota2_subr.c
+SRCS+=	ufs_acl.c ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c	\
+	ufs_lookup.c ufs_rename.c ufs_vfsops.c ufs_vnops.c ufs_quota.c	\
+	ufs_quota2.c quota2_subr.c
 
 CPPFLAGS+=	-DFFS_EI -DUFS_DIRHASH -DWAPBL -DAPPLE_UFS -DUFS_EXTATTR \
-		-DQUOTA2
+		-DQUOTA2 -DUFS_ACL
 
 .include <bsd.lib.mk>
 .include <bsd.klinks.mk>
Index: sys/rump/include/rump/rump_syscalls.h
===================================================================
RCS file: /cvsroot/src/sys/rump/include/rump/rump_syscalls.h,v
retrieving revision 1.118
diff -u -p -p -u -r1.118 rump_syscalls.h
--- sys/rump/include/rump/rump_syscalls.h	26 Apr 2020 19:16:36 -0000	1.118
+++ sys/rump/include/rump/rump_syscalls.h	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rump_syscalls.h,v 1.118 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call protos in rump namespace.
@@ -224,6 +224,10 @@
 #define RUMP_SYS_RENAME_EXTATTR_SET_LINK rump___sysimpl_extattr_set_link
 #endif
 
+#ifndef RUMP_SYS_RENAME_LPATHCONF
+#define RUMP_SYS_RENAME_LPATHCONF rump___sysimpl_lpathconf
+#endif
+
 #ifndef RUMP_SYS_RENAME_TIMER_CREATE
 #define RUMP_SYS_RENAME_TIMER_CREATE rump___sysimpl_timer_create
 #endif
@@ -1063,6 +1067,7 @@ int rump_sys_getvfsstat(struct statvfs *
 int rump_sys_statvfs1(const char *, struct statvfs *, int) __RENAME(RUMP_SYS_RENAME_STATVFS1);
 int rump_sys_fstatvfs1(int, struct statvfs *, int) __RENAME(RUMP_SYS_RENAME_FSTATVFS1);
 int rump_sys_fhstatvfs1(const void *, size_t, struct statvfs *, int) __RENAME(RUMP_SYS_RENAME_FHSTATVFS1);
+long rump_sys_lpathconf(const char *, int) __RENAME(RUMP_SYS_RENAME_LPATHCONF);
 int rump_sys_pipe(int *);
 
 #endif /* _RUMP_RUMP_SYSCALLS_H_ */
Index: sys/rump/include/rump/rumpvnode_if.h
===================================================================
RCS file: /cvsroot/src/sys/rump/include/rump/rumpvnode_if.h,v
retrieving revision 1.33
diff -u -p -p -u -r1.33 rumpvnode_if.h
--- sys/rump/include/rump/rumpvnode_if.h	23 Feb 2020 22:15:19 -0000	1.33
+++ sys/rump/include/rump/rumpvnode_if.h	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rumpvnode_if.h,v 1.33 2020/02/23 22:15:19 ad Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -46,6 +46,9 @@ struct buf;
 struct flock;
 struct knote;
 struct vm_page;
+struct acl;
+
+#include <sys/acl.h>
 
 #ifndef _KERNEL
 #include <stdbool.h>
@@ -59,7 +62,8 @@ int RUMP_VOP_MKNOD(struct vnode *, struc
     struct vattr *);
 int RUMP_VOP_OPEN(struct vnode *, int, struct kauth_cred *);
 int RUMP_VOP_CLOSE(struct vnode *, int, struct kauth_cred *);
-int RUMP_VOP_ACCESS(struct vnode *, int, struct kauth_cred *);
+int RUMP_VOP_ACCESS(struct vnode *, accmode_t, struct kauth_cred *);
+int RUMP_VOP_ACCESSX(struct vnode *, accmode_t, struct kauth_cred *);
 int RUMP_VOP_GETATTR(struct vnode *, struct vattr *, struct kauth_cred *);
 int RUMP_VOP_SETATTR(struct vnode *, struct vattr *, struct kauth_cred *);
 int RUMP_VOP_READ(struct vnode *, struct uio *, int, struct kauth_cred *);
@@ -101,6 +105,12 @@ int RUMP_VOP_WHITEOUT(struct vnode *, st
 int RUMP_VOP_GETPAGES(struct vnode *, off_t, struct vm_page **, int *, int, 
     int, int, int);
 int RUMP_VOP_PUTPAGES(struct vnode *, off_t, off_t, int);
+int RUMP_VOP_GETACL(struct vnode *, acl_type_t, struct acl *, 
+    struct kauth_cred *);
+int RUMP_VOP_SETACL(struct vnode *, acl_type_t, struct acl *, 
+    struct kauth_cred *);
+int RUMP_VOP_ACLCHECK(struct vnode *, acl_type_t, struct acl *, 
+    struct kauth_cred *);
 int RUMP_VOP_CLOSEEXTATTR(struct vnode *, int, struct kauth_cred *);
 int RUMP_VOP_GETEXTATTR(struct vnode *, int, const char *, struct uio *, 
     size_t *, struct kauth_cred *);
Index: sys/rump/librump/rumpkern/rump_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpkern/rump_syscalls.c,v
retrieving revision 1.149
diff -u -p -p -u -r1.149 rump_syscalls.c
--- sys/rump/librump/rumpkern/rump_syscalls.c	26 Apr 2020 19:16:36 -0000	1.149
+++ sys/rump/librump/rumpkern/rump_syscalls.c	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rump_syscalls.c,v 1.149 2020/04/26 19:16:36 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call vector and marshalling for rump.
@@ -15,7 +15,7 @@
 
 #ifdef __NetBSD__
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rump_syscalls.c,v 1.149 2020/04/26 19:16:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #include <sys/fstypes.h>
 #include <sys/proc.h>
@@ -6523,6 +6523,35 @@ __weak_alias(___fhstatvfs190,rump___sysi
 __strong_alias(_sys___fhstatvfs190,rump___sysimpl_fhstatvfs190);
 #endif /* RUMP_KERNEL_IS_LIBC */
 
+long rump___sysimpl_lpathconf(const char *, int);
+long
+rump___sysimpl_lpathconf(const char * path, int name)
+{
+	register_t retval[2];
+	int error = 0;
+	long rv = -1;
+	struct sys_lpathconf_args callarg;
+
+	memset(&callarg, 0, sizeof(callarg));
+	SPARG(&callarg, path) = path;
+	SPARG(&callarg, name) = name;
+
+	error = rsys_syscall(SYS_lpathconf, &callarg, sizeof(callarg), retval);
+	rsys_seterrno(error);
+	if (error == 0) {
+		if (sizeof(long) > sizeof(register_t))
+			rv = *(long *)retval;
+		else
+			rv = *retval;
+	}
+	return rv;
+}
+#ifdef RUMP_KERNEL_IS_LIBC
+__weak_alias(lpathconf,rump___sysimpl_lpathconf);
+__weak_alias(_lpathconf,rump___sysimpl_lpathconf);
+__strong_alias(_sys_lpathconf,rump___sysimpl_lpathconf);
+#endif /* RUMP_KERNEL_IS_LIBC */
+
 int rump_sys_pipe(int *);
 int
 rump_sys_pipe(int *fd)
@@ -8445,57 +8474,45 @@ struct sysent rump_sysent[] = {
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
 	},		/* 486 = __fhstatvfs190 */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 487 = filler */
+},		/* 487 = __acl_get_link */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 488 = filler */
+},		/* 488 = __acl_set_link */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 489 = filler */
+},		/* 489 = __acl_delete_link */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 490 = filler */
+},		/* 490 = __acl_aclcheck_link */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 491 = filler */
+},		/* 491 = __acl_get_file */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 492 = filler */
+},		/* 492 = __acl_set_file */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 493 = filler */
+},		/* 493 = __acl_get_fd */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 494 = filler */
+},		/* 494 = __acl_set_fd */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 495 = filler */
+},		/* 495 = __acl_delete_file */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 496 = filler */
+},		/* 496 = __acl_delete_fd */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 497 = filler */
+},		/* 497 = __acl_aclcheck_file */
 	{
-		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 498 = filler */
+},		/* 498 = __acl_aclcheck_fd */
 	{
-		.sy_flags = SYCALL_NOSYS,
+		ns(struct sys_lpathconf_args),
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
-	},		/* 499 = filler */
+	},		/* 499 = lpathconf */
 	{
 		.sy_flags = SYCALL_NOSYS,
 		.sy_call = (sy_call_t *)(void *)rumpns_enosys,
Index: sys/rump/librump/rumpvfs/Makefile.rumpvfs
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpvfs/Makefile.rumpvfs,v
retrieving revision 1.49
diff -u -p -p -u -r1.49 Makefile.rumpvfs
--- sys/rump/librump/rumpvfs/Makefile.rumpvfs	26 Jan 2016 23:12:18 -0000	1.49
+++ sys/rump/librump/rumpvfs/Makefile.rumpvfs	15 May 2020 16:56:54 -0000
@@ -31,10 +31,10 @@ SRCS+=	rumpvfs_syscalls.c
 SRCS+=	kern_physio.c
 
 # sys/kern vfs
-SRCS+=	vfs_bio.c vfs_cache.c vfs_cwd.c vfs_dirhash.c vfs_getcwd.c	\
-	vfs_hooks.c vfs_init.c vfs_lockf.c vfs_lookup.c vfs_mount.c	\
-	vfs_subr.c vfs_syscalls.c vfs_trans.c vfs_vnode.c vfs_vnops.c	\
-	vfs_wapbl.c vfs_xattr.c
+SRCS+=	vfs_acl.c vfs_bio.c vfs_cache.c vfs_cwd.c vfs_dirhash.c 	\
+	vfs_getcwd.c vfs_hooks.c vfs_init.c vfs_lockf.c vfs_lookup.c	\
+	vfs_mount.c  vfs_subr.c vfs_syscalls.c vfs_trans.c vfs_vnode.c	\
+	vfs_vnops.c vfs_wapbl.c vfs_xattr.c
 
 # sys/kern module support
 SRCS+=	kern_module_vfs.c subr_kobj_vfs.c
@@ -48,6 +48,9 @@ SRCS+=	dead_vfsops.c dead_vnops.c
 # sys/miscfs
 SRCS+=	genfs_io.c genfs_rename.c genfs_vfsops.c genfs_vnops.c spec_vnops.c
 
+# sys/kern acl
+SRCS+=	subr_acl_nfs4.c subr_acl_posix1e.c
+
 # sys/kern bufq
 SRCS+=	subr_bufq.c bufq_disksort.c bufq_fcfs.c bufq_priocscan.c	\
 	bufq_readprio.c
Index: sys/rump/librump/rumpvfs/rumpfs.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpvfs/rumpfs.c,v
retrieving revision 1.160
diff -u -p -p -u -r1.160 rumpfs.c
--- sys/rump/librump/rumpvfs/rumpfs.c	15 May 2020 00:04:02 -0000	1.160
+++ sys/rump/librump/rumpvfs/rumpfs.c	15 May 2020 16:56:54 -0000
@@ -111,6 +111,7 @@ const struct vnodeopv_entry_desc rump_vn
 	{ &vop_symlink_desc, rump_vop_symlink },
 	{ &vop_readlink_desc, rump_vop_readlink },
 	{ &vop_access_desc, rump_vop_access },
+	{ &vop_accessx_desc, genfs_accessx },
 	{ &vop_readdir_desc, rump_vop_readdir },
 	{ &vop_read_desc, rump_vop_read },
 	{ &vop_write_desc, rump_vop_write },
@@ -825,13 +826,13 @@ rump_check_possible(struct vnode *vp, st
 
 static int
 rump_check_permitted(struct vnode *vp, struct rumpfs_node *rnode,
-    mode_t mode, kauth_cred_t cred)
+    accmode_t accmode, kauth_cred_t cred)
 {
 	struct vattr *attr = &rnode->rn_va;
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
-	    vp->v_type, attr->va_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    attr->va_mode, attr->va_uid, attr->va_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, attr->va_mode), vp, NULL, genfs_can_access(vp, cred,
+	    attr->va_uid, attr->va_gid, attr->va_mode, NULL, accmode));
 }
 
 int
@@ -847,11 +848,11 @@ rump_vop_access(void *v)
 	struct rumpfs_node *rn = vp->v_data;
 	int error;
 
-	error = rump_check_possible(vp, rn, ap->a_mode);
+	error = rump_check_possible(vp, rn, ap->a_accmode);
 	if (error)
 		return error;
 
-	error = rump_check_permitted(vp, rn, ap->a_mode, ap->a_cred);
+	error = rump_check_permitted(vp, rn, ap->a_accmode, ap->a_cred);
 
 	return error;
 }
@@ -900,8 +901,8 @@ rump_vop_setattr(void *v)
 	    CHANGED(va_mtime.tv_nsec, long) ||
 	    CHANGED(va_birthtime.tv_nsec, long)) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, attr->va_uid,
-		    cred));
+		    NULL, genfs_can_chtimes(vp, cred, attr->va_uid,
+		    vap->va_vaflags));
 		if (error)
 			return error;
 	}
@@ -929,8 +930,7 @@ rump_vop_setattr(void *v)
 	if (CHANGED(va_flags, u_long)) {
 		/* XXX Can we handle system flags here...? */
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp,
-		    NULL, genfs_can_chflags(cred, vp->v_type, attr->va_uid,
-		    false));
+		    NULL, genfs_can_chflags(vp, cred, attr->va_uid, false));
 		if (error)
 			return error;
 	}
@@ -946,7 +946,7 @@ rump_vop_setattr(void *v)
 		    (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->va_gid;
 		error = kauth_authorize_vnode(cred,
 		    KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
-		    genfs_can_chown(cred, attr->va_uid, attr->va_gid, uid,
+		    genfs_can_chown(vp, cred, attr->va_uid, attr->va_gid, uid,
 		    gid));
 		if (error)
 			return error;
@@ -957,7 +957,7 @@ rump_vop_setattr(void *v)
 	if (vap->va_mode != (mode_t)VNOVAL) {
 		mode_t mode = vap->va_mode;
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
-		    vp, NULL, genfs_can_chmod(vp->v_type, cred, attr->va_uid,
+		    vp, NULL, genfs_can_chmod(vp, cred, attr->va_uid,
 		    attr->va_gid, mode));
 		if (error)
 			return error;
Index: sys/rump/librump/rumpvfs/rumpvnode_if.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpvfs/rumpvnode_if.c,v
retrieving revision 1.33
diff -u -p -p -u -r1.33 rumpvnode_if.c
--- sys/rump/librump/rumpvfs/rumpvnode_if.c	23 Feb 2020 22:15:19 -0000	1.33
+++ sys/rump/librump/rumpvfs/rumpvnode_if.c	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rumpvnode_if.c,v 1.33 2020/02/23 22:15:19 ad Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rumpvnode_if.c,v 1.33 2020/02/23 22:15:19 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
@@ -137,13 +137,27 @@ RUMP_VOP_CLOSE(struct vnode *vp,
 
 int
 RUMP_VOP_ACCESS(struct vnode *vp,
-    int mode,
+    accmode_t accmode,
+    struct kauth_cred *cred)
+{
+	int error;
+
+	rump_schedule();
+	error = VOP_ACCESS(vp, accmode, cred);
+	rump_unschedule();
+
+	return error;
+}
+
+int
+RUMP_VOP_ACCESSX(struct vnode *vp,
+    accmode_t accmode,
     struct kauth_cred *cred)
 {
 	int error;
 
 	rump_schedule();
-	error = VOP_ACCESS(vp, mode, cred);
+	error = VOP_ACCESSX(vp, accmode, cred);
 	rump_unschedule();
 
 	return error;
@@ -667,6 +681,51 @@ RUMP_VOP_PUTPAGES(struct vnode *vp,
 }
 
 int
+RUMP_VOP_GETACL(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    struct kauth_cred *cred)
+{
+	int error;
+
+	rump_schedule();
+	error = VOP_GETACL(vp, type, aclp, cred);
+	rump_unschedule();
+
+	return error;
+}
+
+int
+RUMP_VOP_SETACL(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    struct kauth_cred *cred)
+{
+	int error;
+
+	rump_schedule();
+	error = VOP_SETACL(vp, type, aclp, cred);
+	rump_unschedule();
+
+	return error;
+}
+
+int
+RUMP_VOP_ACLCHECK(struct vnode *vp,
+    acl_type_t type,
+    struct acl *aclp,
+    struct kauth_cred *cred)
+{
+	int error;
+
+	rump_schedule();
+	error = VOP_ACLCHECK(vp, type, aclp, cred);
+	rump_unschedule();
+
+	return error;
+}
+
+int
 RUMP_VOP_CLOSEEXTATTR(struct vnode *vp,
     int commit,
     struct kauth_cred *cred)
Index: sys/sys/Makefile
===================================================================
RCS file: /cvsroot/src/sys/sys/Makefile,v
retrieving revision 1.173
diff -u -p -p -u -r1.173 Makefile
--- sys/sys/Makefile	26 Apr 2020 18:53:33 -0000	1.173
+++ sys/sys/Makefile	15 May 2020 16:56:54 -0000
@@ -4,7 +4,7 @@
 
 INCSDIR= /usr/include/sys
 
-INCS=	acct.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h \
+INCS=	acct.h acl.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h \
 	audioio.h \
 	bitops.h bootblock.h bswap.h buf.h \
 	callback.h callout.h cdbr.h cdefs.h cdefs_aout.h \
Index: sys/sys/acl.h
===================================================================
RCS file: sys/sys/acl.h
diff -N sys/sys/acl.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/sys/acl.h	15 May 2020 16:56:54 -0000
@@ -0,0 +1,440 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2001 Robert N. M. Watson
+ * Copyright (c) 2008 Edward Tomasz Napierała <trasz@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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: head/sys/sys/acl.h 326256 2017-11-27 15:01:59Z pfg $
+ */
+/* 
+ * Developed by the TrustedBSD Project.
+ * Support for POSIX.1e and NFSv4 access control lists.
+ */
+
+#ifndef _SYS_ACL_H_
+#define	_SYS_ACL_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+/*
+ * POSIX.1e and NFSv4 ACL types and related constants.
+ */
+
+typedef uint32_t	acl_tag_t;
+typedef uint32_t	acl_perm_t;
+typedef uint16_t	acl_entry_type_t;
+typedef uint16_t	acl_flag_t;
+typedef int		acl_type_t;
+typedef uint32_t	*acl_permset_t;
+typedef uint16_t	*acl_flagset_t;
+
+/*
+ * With 254 entries, "struct acl_t_struct" is exactly one 4kB page big.
+ * Note that with NFSv4 ACLs, the maximum number of ACL entries one
+ * may set on file or directory is about half of ACL_MAX_ENTRIES.
+ *
+ * If you increase this, you might also need to increase
+ * _ACL_T_ALIGNMENT_BITS in lib/libc/posix1e/acl_support.h.
+ *
+ * The maximum number of POSIX.1e ACLs is controlled
+ * by OLDACL_MAX_ENTRIES.  Changing that one will break binary
+ * compatibility with pre-8.0 userland and change on-disk ACL layout.
+ */
+#define	ACL_MAX_ENTRIES				254
+
+#if defined(_KERNEL) || defined(_ACL_PRIVATE) || defined(_MODULE)
+
+#define	POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE	EXTATTR_NAMESPACE_SYSTEM
+#define	POSIX1E_ACL_ACCESS_EXTATTR_NAME		"posix1e.acl_access"
+#define	POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE	EXTATTR_NAMESPACE_SYSTEM
+#define	POSIX1E_ACL_DEFAULT_EXTATTR_NAME	"posix1e.acl_default"
+#define	NFS4_ACL_EXTATTR_NAMESPACE		EXTATTR_NAMESPACE_SYSTEM
+#define	NFS4_ACL_EXTATTR_NAME			"nfs4.acl"
+#define	OLDACL_MAX_ENTRIES			32
+
+/*
+ * "struct oldacl" is used in compatibility ACL syscalls and for on-disk
+ * storage of POSIX.1e ACLs.
+ */
+typedef int	oldacl_tag_t;
+typedef mode_t	oldacl_perm_t;
+
+struct oldacl_entry {
+	oldacl_tag_t	ae_tag;
+	uid_t		ae_id;
+	oldacl_perm_t	ae_perm;
+};
+typedef struct oldacl_entry	*oldacl_entry_t;
+
+struct oldacl {
+	int			acl_cnt;
+	struct oldacl_entry	acl_entry[OLDACL_MAX_ENTRIES];
+};
+
+/*
+ * Current "struct acl".
+ */
+struct acl_entry {
+	acl_tag_t		ae_tag;
+	uid_t			ae_id;
+	acl_perm_t		ae_perm;
+	/* NFSv4 entry type, "allow" or "deny".  Unused in POSIX.1e ACLs. */
+	acl_entry_type_t	ae_entry_type;
+	/* NFSv4 ACL inheritance.  Unused in POSIX.1e ACLs. */
+	acl_flag_t		ae_flags;
+};
+typedef struct acl_entry	*acl_entry_t;
+
+/*
+ * Internal ACL structure, used in libc, kernel APIs and for on-disk
+ * storage of NFSv4 ACLs.  POSIX.1e ACLs use "struct oldacl" for on-disk
+ * storage.
+ */
+struct acl {
+	unsigned int		acl_maxcnt;
+	unsigned int		acl_cnt;
+	/* Will be required e.g. to implement NFSv4.1 ACL inheritance. */
+	int			acl_spare[4];
+	struct acl_entry	acl_entry[ACL_MAX_ENTRIES];
+};
+
+/*
+ * ACL structure internal to libc.
+ */
+struct acl_t_struct {
+	struct acl		ats_acl;
+	unsigned int		ats_cur_entry;
+	/*
+	 * ats_brand is for libc internal bookkeeping only.
+	 * Applications should use acl_get_brand_np(3).
+	 * Kernel code should use the "type" argument passed
+	 * to VOP_SETACL, VOP_GETACL or VOP_ACLCHECK calls;
+	 * ACL_TYPE_ACCESS or ACL_TYPE_DEFAULT mean POSIX.1e
+	 * ACL, ACL_TYPE_NFS4 means NFSv4 ACL.
+	 */
+	int			ats_brand;
+};
+typedef struct acl_t_struct *acl_t;
+
+#else /* _KERNEL || _ACL_PRIVATE */
+
+typedef void *acl_entry_t;
+typedef void *acl_t;
+
+#endif /* !_KERNEL && !_ACL_PRIVATE */
+
+/*
+ * Possible valid values for ats_brand field.
+ */
+#define	ACL_BRAND_UNKNOWN	0
+#define	ACL_BRAND_POSIX		1
+#define	ACL_BRAND_NFS4		2
+
+/*
+ * Possible valid values for ae_tag field.  For explanation, see acl(9).
+ */
+#define	ACL_UNDEFINED_TAG	0x00000000
+#define	ACL_USER_OBJ		0x00000001
+#define	ACL_USER		0x00000002
+#define	ACL_GROUP_OBJ		0x00000004
+#define	ACL_GROUP		0x00000008
+#define	ACL_MASK		0x00000010
+#define	ACL_OTHER		0x00000020
+#define	ACL_OTHER_OBJ		ACL_OTHER
+#define	ACL_EVERYONE		0x00000040
+
+/*
+ * Possible valid values for ae_entry_type field, valid only for NFSv4 ACLs.
+ */
+#define	ACL_ENTRY_TYPE_ALLOW	0x0100
+#define	ACL_ENTRY_TYPE_DENY	0x0200
+#define	ACL_ENTRY_TYPE_AUDIT	0x0400
+#define	ACL_ENTRY_TYPE_ALARM	0x0800
+
+/*
+ * Possible valid values for acl_type_t arguments.  First two
+ * are provided only for backwards binary compatibility.
+ */
+#define	ACL_TYPE_ACCESS_OLD	0x00000000
+#define	ACL_TYPE_DEFAULT_OLD	0x00000001
+#define	ACL_TYPE_ACCESS		0x00000002
+#define	ACL_TYPE_DEFAULT	0x00000003
+#define	ACL_TYPE_NFS4		0x00000004
+
+/*
+ * Possible bits in ae_perm field for POSIX.1e ACLs.  Note
+ * that ACL_EXECUTE may be used in both NFSv4 and POSIX.1e ACLs.
+ */
+#define	ACL_EXECUTE		0x0001
+#define	ACL_WRITE		0x0002
+#define	ACL_READ		0x0004
+#define	ACL_PERM_NONE		0x0000
+#define	ACL_PERM_BITS		(ACL_EXECUTE | ACL_WRITE | ACL_READ)
+#define	ACL_POSIX1E_BITS	(ACL_EXECUTE | ACL_WRITE | ACL_READ)
+
+/*
+ * Possible bits in ae_perm field for NFSv4 ACLs.
+ */
+#define	ACL_READ_DATA		0x00000008
+#define	ACL_LIST_DIRECTORY	0x00000008
+#define	ACL_WRITE_DATA		0x00000010
+#define	ACL_ADD_FILE		0x00000010
+#define	ACL_APPEND_DATA		0x00000020
+#define	ACL_ADD_SUBDIRECTORY	0x00000020
+#define	ACL_READ_NAMED_ATTRS	0x00000040
+#define	ACL_WRITE_NAMED_ATTRS	0x00000080
+/* ACL_EXECUTE is defined above. */
+#define	ACL_DELETE_CHILD	0x00000100
+#define	ACL_READ_ATTRIBUTES	0x00000200
+#define	ACL_WRITE_ATTRIBUTES	0x00000400
+#define	ACL_DELETE		0x00000800
+#define	ACL_READ_ACL		0x00001000
+#define	ACL_WRITE_ACL		0x00002000
+#define	ACL_WRITE_OWNER		0x00004000
+#define	ACL_SYNCHRONIZE		0x00008000
+
+#define	ACL_FULL_SET		(ACL_READ_DATA | ACL_WRITE_DATA | \
+    ACL_APPEND_DATA | ACL_READ_NAMED_ATTRS | ACL_WRITE_NAMED_ATTRS | \
+    ACL_EXECUTE | ACL_DELETE_CHILD | ACL_READ_ATTRIBUTES | \
+    ACL_WRITE_ATTRIBUTES | ACL_DELETE | ACL_READ_ACL | ACL_WRITE_ACL | \
+    ACL_WRITE_OWNER | ACL_SYNCHRONIZE)
+
+#define	ACL_MODIFY_SET		(ACL_FULL_SET & \
+    ~(ACL_WRITE_ACL | ACL_WRITE_OWNER))
+
+#define	ACL_READ_SET		(ACL_READ_DATA | ACL_READ_NAMED_ATTRS | \
+    ACL_READ_ATTRIBUTES | ACL_READ_ACL)
+
+#define	ACL_WRITE_SET		(ACL_WRITE_DATA | ACL_APPEND_DATA | \
+    ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES)
+
+#define	ACL_NFS4_PERM_BITS	ACL_FULL_SET
+
+/*
+ * Possible entry_id values for acl_get_entry(3).
+ */
+#define	ACL_FIRST_ENTRY		0
+#define	ACL_NEXT_ENTRY		1
+
+/*
+ * Possible values in ae_flags field; valid only for NFSv4 ACLs.
+ */
+#define	ACL_ENTRY_FILE_INHERIT		0x0001
+#define	ACL_ENTRY_DIRECTORY_INHERIT	0x0002
+#define	ACL_ENTRY_NO_PROPAGATE_INHERIT	0x0004
+#define	ACL_ENTRY_INHERIT_ONLY		0x0008
+#define	ACL_ENTRY_SUCCESSFUL_ACCESS	0x0010
+#define	ACL_ENTRY_FAILED_ACCESS		0x0020
+#define	ACL_ENTRY_INHERITED		0x0080
+
+#define	ACL_FLAGS_BITS			(ACL_ENTRY_FILE_INHERIT | \
+    ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_NO_PROPAGATE_INHERIT | \
+    ACL_ENTRY_INHERIT_ONLY | ACL_ENTRY_SUCCESSFUL_ACCESS | \
+    ACL_ENTRY_FAILED_ACCESS | ACL_ENTRY_INHERITED)
+
+/*
+ * Undefined value in ae_id field.  ae_id should be set to this value
+ * iff ae_tag is ACL_USER_OBJ, ACL_GROUP_OBJ, ACL_OTHER or ACL_EVERYONE.
+ */
+#define	ACL_UNDEFINED_ID	((uid_t)-1)
+
+/*
+ * Possible values for _flags parameter in acl_to_text_np(3).
+ */
+#define	ACL_TEXT_VERBOSE	0x01
+#define	ACL_TEXT_NUMERIC_IDS	0x02
+#define	ACL_TEXT_APPEND_ID	0x04
+
+/*
+ * POSIX.1e ACLs are capable of expressing the read, write, and execute bits
+ * of the POSIX mode field.  We provide two masks: one that defines the bits
+ * the ACL will replace in the mode, and the other that defines the bits that
+ * must be preseved when an ACL is updating a mode.
+ */
+#define	ACL_OVERRIDE_MASK	(S_IRWXU | S_IRWXG | S_IRWXO)
+#define	ACL_PRESERVE_MASK	(~ACL_OVERRIDE_MASK)
+
+#ifdef _KERNEL
+
+/*
+ * Filesystem-independent code to move back and forth between POSIX mode and
+ * POSIX.1e ACL representations.
+ */
+acl_perm_t		acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode);
+struct acl_entry	acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid,
+			    gid_t gid, mode_t mode);
+mode_t			acl_posix1e_perms_to_mode(
+			    struct acl_entry *acl_user_obj_entry,
+			    struct acl_entry *acl_group_obj_entry,
+			    struct acl_entry *acl_other_entry);
+mode_t			acl_posix1e_acl_to_mode(struct acl *acl);
+mode_t			acl_posix1e_newfilemode(mode_t cmode,
+			    struct acl *dacl);
+struct acl		*acl_alloc(int flags);
+void			acl_free(struct acl *aclp);
+
+void			acl_nfs4_sync_acl_from_mode(struct acl *aclp,
+			    mode_t mode, int file_owner_id);
+void			__acl_nfs4_sync_mode_from_acl(mode_t *mode,
+			    const struct acl *aclp);
+int			acl_nfs4_is_trivial(const struct acl *aclp,
+			    int file_owner_id);
+void			acl_nfs4_compute_inherited_acl(
+			    const struct acl *parent_aclp,
+			    struct acl *child_aclp, mode_t mode,
+			    int file_owner_id, int is_directory);
+int			acl_copy_oldacl_into_acl(const struct oldacl *source,
+			    struct acl *dest);
+int			acl_copy_acl_into_oldacl(const struct acl *source,
+			    struct oldacl *dest);
+
+/*
+ * Filesystem-independent syntax check for a POSIX.1e ACL.
+ */
+int			acl_posix1e_check(struct acl *acl);
+int 			acl_nfs4_check(const struct acl *aclp, int is_directory);
+
+/* for compat32 */
+#include <sys/namei.h>
+
+int	kern___acl_aclcheck_path(struct lwp *, const char *, acl_type_t,
+    struct acl *, namei_simple_flags_t);
+int	kern___acl_delete_path(struct lwp *, const char *, acl_type_t,
+    namei_simple_flags_t);
+int	kern___acl_get_path(struct lwp *, const char *, acl_type_t,
+    struct acl *, namei_simple_flags_t);
+int	kern___acl_set_path(struct lwp *, const char *, acl_type_t,
+    const struct acl *, namei_simple_flags_t);
+int	vacl_set_acl(struct lwp *, struct vnode *, acl_type_t,
+    const struct acl *);
+int	vacl_get_acl(struct lwp *, struct vnode *, acl_type_t, struct acl *);
+int	vacl_aclcheck(struct lwp *, struct vnode *, acl_type_t,
+    const struct acl *);
+int	vacl_delete(struct lwp *, struct vnode *, acl_type_t);
+
+#else /* !_KERNEL */
+
+#if defined(_ACL_PRIVATE)
+
+/*
+ * Syscall interface -- use the library calls instead as the syscalls have
+ * strict ACL entry ordering requirements.
+ */
+__BEGIN_DECLS
+int	__acl_aclcheck_fd(int _filedes, acl_type_t _type, struct acl *_aclp);
+int	__acl_aclcheck_file(const char *_path, acl_type_t _type,
+	    struct acl *_aclp);
+int	__acl_aclcheck_link(const char *_path, acl_type_t _type,
+	    struct acl *_aclp);
+int	__acl_delete_fd(int _filedes, acl_type_t _type);
+int	__acl_delete_file(const char *_path_p, acl_type_t _type);
+int	__acl_delete_link(const char *_path_p, acl_type_t _type);
+int	__acl_get_fd(int _filedes, acl_type_t _type, struct acl *_aclp);
+int	__acl_get_file(const char *_path, acl_type_t _type, struct acl *_aclp);
+int	__acl_get_link(const char *_path, acl_type_t _type, struct acl *_aclp);
+int	__acl_set_fd(int _filedes, acl_type_t _type, struct acl *_aclp);
+int	__acl_set_file(const char *_path, acl_type_t _type, struct acl *_aclp);
+int	__acl_set_link(const char *_path, acl_type_t _type, struct acl *_aclp);
+
+/*
+ * These routines from sys/kern/subr_acl_nfs4.c are used by both kernel
+ * and libc.
+ */
+void	__acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *_aclp);
+void	__acl_nfs4_trivial_from_mode_libc(struct acl *_aclp, int _file_owner_id,
+	    int _canonical_six);
+__END_DECLS
+
+#endif /* _ACL_PRIVATE */
+
+/*
+ * Supported POSIX.1e ACL manipulation and assignment/retrieval API _np calls
+ * are local extensions that reflect an environment capable of opening file
+ * descriptors of directories, and allowing additional ACL type for different
+ * filesystems (i.e., AFS).
+ */
+__BEGIN_DECLS
+int	acl_add_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag);
+int	acl_add_perm(acl_permset_t _permset_d, acl_perm_t _perm);
+int	acl_calc_mask(acl_t *_acl_p);
+int	acl_clear_flags_np(acl_flagset_t _flagset_d);
+int	acl_clear_perms(acl_permset_t _permset_d);
+int	acl_copy_entry(acl_entry_t _dest_d, acl_entry_t _src_d);
+ssize_t	acl_copy_ext(void *_buf_p, acl_t _acl, ssize_t _size);
+acl_t	acl_copy_int(const void *_buf_p);
+int	acl_create_entry(acl_t *_acl_p, acl_entry_t *_entry_p);
+int	acl_create_entry_np(acl_t *_acl_p, acl_entry_t *_entry_p, int _index);
+int	acl_delete_entry(acl_t _acl, acl_entry_t _entry_d);
+int	acl_delete_entry_np(acl_t _acl, int _index);
+int	acl_delete_fd_np(int _filedes, acl_type_t _type);
+int	acl_delete_file_np(const char *_path_p, acl_type_t _type);
+int	acl_delete_link_np(const char *_path_p, acl_type_t _type);
+int	acl_delete_def_file(const char *_path_p);
+int	acl_delete_def_link_np(const char *_path_p);
+int	acl_delete_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag);
+int	acl_delete_perm(acl_permset_t _permset_d, acl_perm_t _perm);
+acl_t	acl_dup(acl_t _acl);
+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_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);
+acl_t	acl_get_file(const char *_path_p, acl_type_t _type);
+int	acl_get_entry_type_np(acl_entry_t _entry_d, acl_entry_type_t *_entry_type_p);
+acl_t	acl_get_link_np(const char *_path_p, acl_type_t _type);
+void	*acl_get_qualifier(acl_entry_t _entry_d);
+int	acl_get_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag);
+int	acl_get_perm_np(acl_permset_t _permset_d, acl_perm_t _perm);
+int	acl_get_flagset_np(acl_entry_t _entry_d, acl_flagset_t *_flagset_p);
+int	acl_get_permset(acl_entry_t _entry_d, acl_permset_t *_permset_p);
+int	acl_get_tag_type(acl_entry_t _entry_d, acl_tag_t *_tag_type_p);
+acl_t	acl_init(int _count);
+int	acl_set_fd(int _fd, acl_t _acl);
+int	acl_set_fd_np(int _fd, acl_t _acl, acl_type_t _type);
+int	acl_set_file(const char *_path_p, acl_type_t _type, acl_t _acl);
+int	acl_set_entry_type_np(acl_entry_t _entry_d, acl_entry_type_t _entry_type);
+int	acl_set_link_np(const char *_path_p, acl_type_t _type, acl_t _acl);
+int	acl_set_flagset_np(acl_entry_t _entry_d, acl_flagset_t _flagset_d);
+int	acl_set_permset(acl_entry_t _entry_d, acl_permset_t _permset_d);
+int	acl_set_qualifier(acl_entry_t _entry_d, const void *_tag_qualifier_p);
+int	acl_set_tag_type(acl_entry_t _entry_d, acl_tag_t _tag_type);
+ssize_t	acl_size(acl_t _acl);
+char	*acl_to_text(acl_t _acl, ssize_t *_len_p);
+char	*acl_to_text_np(acl_t _acl, ssize_t *_len_p, int _flags);
+int	acl_valid(acl_t _acl);
+int	acl_valid_fd_np(int _fd, acl_type_t _type, acl_t _acl);
+int	acl_valid_file_np(const char *_path_p, acl_type_t _type, acl_t _acl);
+int	acl_valid_link_np(const char *_path_p, acl_type_t _type, acl_t _acl);
+int	acl_is_trivial_np(const acl_t _acl, int *_trivialp);
+acl_t	acl_strip_np(const acl_t _acl, int recalculate_mask);
+__END_DECLS
+
+#endif /* !_KERNEL */
+
+#endif /* !_SYS_ACL_H_ */
Index: sys/sys/ansi.h
===================================================================
RCS file: /cvsroot/src/sys/sys/ansi.h,v
retrieving revision 1.14
diff -u -p -p -u -r1.14 ansi.h
--- sys/sys/ansi.h	17 Jul 2011 20:54:54 -0000	1.14
+++ sys/sys/ansi.h	15 May 2020 16:56:54 -0000
@@ -39,6 +39,7 @@ typedef __uint32_t	__gid_t;	/* group id 
 typedef __uint32_t	__in_addr_t;	/* IP(v4) address */
 typedef __uint16_t	__in_port_t;	/* "Internet" port number */
 typedef __uint32_t	__mode_t;	/* file permissions */
+typedef __uint32_t	__accmode_t;	/* access permissions */
 typedef __int64_t	__off_t;	/* file offset */
 typedef __int32_t	__pid_t;	/* process id */
 typedef __uint8_t	__sa_family_t;	/* socket address family */
Index: sys/sys/extattr.h
===================================================================
RCS file: /cvsroot/src/sys/sys/extattr.h,v
retrieving revision 1.9
diff -u -p -p -u -r1.9 extattr.h
--- sys/sys/extattr.h	13 Mar 2012 18:41:02 -0000	1.9
+++ sys/sys/extattr.h	15 May 2020 16:56:54 -0000
@@ -60,7 +60,7 @@
 #define	EXTATTR_MAXNAMELEN	KERNEL_NAME_MAX
 struct lwp;
 struct vnode;
-int	extattr_check_cred(struct vnode *, const char *, kauth_cred_t, int);
+int	extattr_check_cred(struct vnode *, int, kauth_cred_t, int);
 
 #else
 
Index: sys/sys/fstypes.h
===================================================================
RCS file: /cvsroot/src/sys/sys/fstypes.h,v
retrieving revision 1.38
diff -u -p -p -u -r1.38 fstypes.h
--- sys/sys/fstypes.h	4 Apr 2020 20:49:31 -0000	1.38
+++ sys/sys/fstypes.h	15 May 2020 16:56:54 -0000
@@ -83,7 +83,6 @@ typedef struct fhandle	fhandle_t;
  * one of the __MNT_UNUSED flags.
  */
 
-#define	__MNT_UNUSED1	0x00200000
 
 #define	MNT_RDONLY	0x00000001	/* read only filesystem */
 #define	MNT_SYNCHRONOUS	0x00000002	/* file system written synchronously */
@@ -95,6 +94,7 @@ typedef struct fhandle	fhandle_t;
 #define	MNT_NOCOREDUMP	0x00008000	/* don't write core dumps to this FS */
 #define	MNT_RELATIME	0x00020000	/* only update access time if mod/ch */
 #define	MNT_IGNORE	0x00100000	/* don't show entry in df */
+#define	MNT_ACLS	0x00200000	/* uses Access Control Lists */
 #define	MNT_DISCARD	0x00800000	/* use DISCARD/TRIM if supported */
 #define	MNT_EXTATTR	0x01000000	/* enable extended attributes */
 #define	MNT_LOG		0x02000000	/* Use logging */
@@ -103,10 +103,13 @@ typedef struct fhandle	fhandle_t;
 #define	MNT_SYMPERM	0x20000000	/* recognize symlink permission */
 #define	MNT_NODEVMTIME	0x40000000	/* Never update mod times for devs */
 #define	MNT_SOFTDEP	0x80000000	/* Use soft dependencies */
+#define	MNT_POSIX1EACLS	0x00000800	/* shared with EXKERB */
 
 #define	__MNT_BASIC_FLAGS \
 	{ MNT_ASYNC,		0,	"asynchronous" }, \
 	{ MNT_AUTOMOUNTED,	0,	"automounted" }, \
+	{ MNT_ACLS,		0,	"acls" }, \
+	{ MNT_POSIX1EACLS,	0,	"posix1eacls" }, \
 	{ MNT_DISCARD,		0,	"discard" }, \
 	{ MNT_EXTATTR,		0,	"extattr" }, \
 	{ MNT_IGNORE,		0,	"hidden" }, \
@@ -127,7 +130,8 @@ typedef struct fhandle	fhandle_t;
 #define MNT_BASIC_FLAGS (MNT_ASYNC | MNT_AUTOMOUNTED | MNT_DISCARD | \
     MNT_EXTATTR | MNT_LOG | MNT_NOATIME | MNT_NOCOREDUMP | MNT_NODEV | \
     MNT_NODEVMTIME | MNT_NOEXEC | MNT_NOSUID | MNT_RDONLY | MNT_RELATIME | \
-    MNT_SOFTDEP | MNT_SYMPERM | MNT_SYNCHRONOUS | MNT_UNION)
+    MNT_SOFTDEP | MNT_SYMPERM | MNT_SYNCHRONOUS | MNT_UNION | MNT_ACLS | \
+    MNT_POSIX1EACLS)
 /*
  * exported mount flags.
  */
@@ -170,6 +174,7 @@ typedef struct fhandle	fhandle_t;
      MNT_NOSUID | \
      MNT_NODEV | \
      MNT_UNION | \
+     MNT_ACLS | \
      MNT_ASYNC | \
      MNT_NOCOREDUMP | \
      MNT_IGNORE | \
@@ -189,6 +194,7 @@ typedef struct fhandle	fhandle_t;
      MNT_QUOTA | \
      MNT_ROOTFS | \
      MNT_LOG | \
+     MNT_POSIX1EACLS | \
      MNT_EXTATTR | \
      MNT_AUTOMOUNTED)
 
@@ -245,7 +251,7 @@ typedef struct fhandle	fhandle_t;
 	"\31MNT_EXTATTR" \
 	"\30MNT_DISCARD" \
 	"\27MNT_GETARGS" \
-	"\26MNT_UNUSED" \
+	"\26MNT_ACL" \
 	"\25MNT_IGNORE" \
 	"\24MNT_FORCE" \
 	"\23MNT_RELOAD" \
@@ -255,7 +261,7 @@ typedef struct fhandle	fhandle_t;
 	"\17MNT_ROOTFS" \
 	"\16MNT_QUOTA" \
 	"\15MNT_LOCAL" \
-	"\14MNT_EXKERB" \
+	"\14MNT_EXKERB|MNT_POSIX1EACLS" \
 	"\13MNT_EXPORTANON" \
 	"\12MNT_DEFEXPORTED" \
 	"\11MNT_EXPORTED" \
Index: sys/sys/kauth.h
===================================================================
RCS file: /cvsroot/src/sys/sys/kauth.h,v
retrieving revision 1.84
diff -u -p -p -u -r1.84 kauth.h
--- sys/sys/kauth.h	29 Apr 2020 05:54:37 -0000	1.84
+++ sys/sys/kauth.h	15 May 2020 16:56:54 -0000
@@ -525,11 +525,11 @@ int kauth_cred_uucmp(kauth_cred_t, const
 void kauth_cred_toucred(kauth_cred_t, struct ki_ucred *);
 void kauth_cred_topcred(kauth_cred_t, struct ki_pcred *);
 
-kauth_action_t kauth_mode_to_action(mode_t);
+kauth_action_t kauth_accmode_to_action(accmode_t);
 kauth_action_t kauth_extattr_action(mode_t);
 
 #define KAUTH_ACCESS_ACTION(access_mode, vn_vtype, file_mode)	\
-	(kauth_mode_to_action(access_mode) |			\
+	(kauth_accmode_to_action(access_mode) |			\
 	(FS_OBJECT_CAN_EXEC(vn_vtype, file_mode) ? KAUTH_VNODE_IS_EXEC : 0))
 
 kauth_cred_t kauth_cred_get(void);
Index: sys/sys/namei.h
===================================================================
RCS file: /cvsroot/src/sys/sys/namei.h,v
retrieving revision 1.109
diff -u -p -p -u -r1.109 namei.h
--- sys/sys/namei.h	12 May 2020 23:18:03 -0000	1.109
+++ sys/sys/namei.h	15 May 2020 16:56:54 -0000
@@ -45,7 +45,7 @@
 #include <sys/queue.h>
 #include <sys/mutex.h>
 
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_MODULE)
 #include <sys/kauth.h>
 #include <sys/rwlock.h>
 
@@ -171,11 +171,12 @@ struct nameidata {
 #define	ISDOTDOT	0x0002000	/* current component name is .. */
 #define	MAKEENTRY	0x0004000	/* entry is to be added to name cache */
 #define	ISLASTCN	0x0008000	/* this is last component of pathname */
+#define	WILLBEDIR	0x0010000	/* new files will be dirs; */
 #define	ISWHITEOUT	0x0020000	/* found whiteout */
 #define	DOWHITEOUT	0x0040000	/* do whiteouts */
 #define	REQUIREDIR	0x0080000	/* must be a directory */
 #define	CREATEDIR	0x0200000	/* trailing slashes are ok */
-#define	PARAMASK	0x02ef800	/* mask of parameter descriptors */
+#define	PARAMASK	0x02ff800	/* mask of parameter descriptors */
 
 /*
  * Initialization of a nameidata structure.
@@ -298,7 +299,7 @@ bool	cache_lookup_raw(struct vnode *, co
 bool	cache_lookup_linked(struct vnode *, const char *, size_t,
 			    struct vnode **, krwlock_t **, kauth_cred_t);
 int	cache_revlookup(struct vnode *, struct vnode **, char **, char *,
-			bool, int);
+			bool, accmode_t);
 int	cache_diraccess(struct vnode *, int);
 void	cache_enter(struct vnode *, struct vnode *,
 			const char *, size_t, uint32_t);
Index: sys/sys/namei.src
===================================================================
RCS file: /cvsroot/src/sys/sys/namei.src,v
retrieving revision 1.54
diff -u -p -p -u -r1.54 namei.src
--- sys/sys/namei.src	12 May 2020 23:17:41 -0000	1.54
+++ sys/sys/namei.src	15 May 2020 16:56:54 -0000
@@ -37,7 +37,7 @@
 #include <sys/queue.h>
 #include <sys/mutex.h>
 
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_MODULE)
 #include <sys/kauth.h>
 #include <sys/rwlock.h>
 
Index: sys/sys/statvfs.h
===================================================================
RCS file: /cvsroot/src/sys/sys/statvfs.h,v
retrieving revision 1.19
diff -u -p -p -u -r1.19 statvfs.h
--- sys/sys/statvfs.h	22 Sep 2019 22:59:40 -0000	1.19
+++ sys/sys/statvfs.h	15 May 2020 16:56:54 -0000
@@ -113,6 +113,7 @@ struct statvfs {
 #define	ST_NODEV	MNT_NODEV
 #define	ST_UNION	MNT_UNION
 #define	ST_ASYNC	MNT_ASYNC
+#define	ST_ACLS		MNT_ACLS
 #define	ST_NOCOREDUMP	MNT_NOCOREDUMP
 #define	ST_RELATIME	MNT_RELATIME
 #define	ST_IGNORE	MNT_IGNORE
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvsroot/src/sys/sys/syscall.h,v
retrieving revision 1.313
diff -u -p -p -u -r1.313 syscall.h
--- sys/sys/syscall.h	26 Apr 2020 19:16:35 -0000	1.313
+++ sys/sys/syscall.h	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscall.h,v 1.313 2020/04/26 19:16:35 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call numbers.
@@ -1350,6 +1350,45 @@
 /* syscall: "__fhstatvfs190" ret: "int" args: "const void *" "size_t" "struct statvfs *" "int" */
 #define	SYS___fhstatvfs190	486
 
-#define	SYS_MAXSYSCALL	487
+/* syscall: "__acl_get_link" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_get_link	487
+
+/* syscall: "__acl_set_link" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_set_link	488
+
+/* syscall: "__acl_delete_link" ret: "int" args: "const char *" "acl_type_t" */
+#define	SYS___acl_delete_link	489
+
+/* syscall: "__acl_aclcheck_link" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_aclcheck_link	490
+
+/* syscall: "__acl_get_file" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_get_file	491
+
+/* syscall: "__acl_set_file" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_set_file	492
+
+/* syscall: "__acl_get_fd" ret: "int" args: "int" "acl_type_t" "struct acl *" */
+#define	SYS___acl_get_fd	493
+
+/* syscall: "__acl_set_fd" ret: "int" args: "int" "acl_type_t" "struct acl *" */
+#define	SYS___acl_set_fd	494
+
+/* syscall: "__acl_delete_file" ret: "int" args: "const char *" "acl_type_t" */
+#define	SYS___acl_delete_file	495
+
+/* syscall: "__acl_delete_fd" ret: "int" args: "int" "acl_type_t" */
+#define	SYS___acl_delete_fd	496
+
+/* syscall: "__acl_aclcheck_file" ret: "int" args: "const char *" "acl_type_t" "struct acl *" */
+#define	SYS___acl_aclcheck_file	497
+
+/* syscall: "__acl_aclcheck_fd" ret: "int" args: "int" "acl_type_t" "struct acl *" */
+#define	SYS___acl_aclcheck_fd	498
+
+/* syscall: "lpathconf" ret: "long" args: "const char *" "int" */
+#define	SYS_lpathconf	499
+
+#define	SYS_MAXSYSCALL	500
 #define	SYS_NSYSENT	512
 #endif /* _SYS_SYSCALL_H_ */
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /cvsroot/src/sys/sys/syscallargs.h,v
retrieving revision 1.297
diff -u -p -p -u -r1.297 syscallargs.h
--- sys/sys/syscallargs.h	26 Apr 2020 19:16:35 -0000	1.297
+++ sys/sys/syscallargs.h	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscallargs.h,v 1.297 2020/04/26 19:16:35 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument lists.
@@ -14,6 +14,7 @@
 #include <sys/idtype.h>
 #include <sys/mount.h>
 #include <sys/sched.h>
+#include <sys/acl.h>
 #endif
 
 #include <sys/socket.h>
@@ -3205,6 +3206,117 @@ struct sys___fhstatvfs190_args {
 };
 check_syscall_args(sys___fhstatvfs190)
 
+#ifndef RUMP_CLIENT
+struct sys___acl_get_link_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_get_link)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_set_link_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_set_link)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_delete_link_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(sys___acl_delete_link)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_aclcheck_link_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_aclcheck_link)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_get_file_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_get_file)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_set_file_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_set_file)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_get_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_get_fd)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_set_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_set_fd)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_delete_file_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(sys___acl_delete_file)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_delete_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+};
+check_syscall_args(sys___acl_delete_fd)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_aclcheck_file_args {
+	syscallarg(const char *) path;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_aclcheck_file)
+#endif /* !RUMP_CLIENT */
+
+#ifndef RUMP_CLIENT
+struct sys___acl_aclcheck_fd_args {
+	syscallarg(int) filedes;
+	syscallarg(acl_type_t) type;
+	syscallarg(struct acl *) aclp;
+};
+check_syscall_args(sys___acl_aclcheck_fd)
+#endif /* !RUMP_CLIENT */
+
+struct sys_lpathconf_args {
+	syscallarg(const char *) path;
+	syscallarg(int) name;
+};
+check_syscall_args(sys_lpathconf)
+
 /*
  * System call prototypes.
  */
@@ -4093,5 +4205,31 @@ int	sys___fstatvfs190(struct lwp *, cons
 
 int	sys___fhstatvfs190(struct lwp *, const struct sys___fhstatvfs190_args *, register_t *);
 
+int	sys___acl_get_link(struct lwp *, const struct sys___acl_get_link_args *, register_t *);
+
+int	sys___acl_set_link(struct lwp *, const struct sys___acl_set_link_args *, register_t *);
+
+int	sys___acl_delete_link(struct lwp *, const struct sys___acl_delete_link_args *, register_t *);
+
+int	sys___acl_aclcheck_link(struct lwp *, const struct sys___acl_aclcheck_link_args *, register_t *);
+
+int	sys___acl_get_file(struct lwp *, const struct sys___acl_get_file_args *, register_t *);
+
+int	sys___acl_set_file(struct lwp *, const struct sys___acl_set_file_args *, register_t *);
+
+int	sys___acl_get_fd(struct lwp *, const struct sys___acl_get_fd_args *, register_t *);
+
+int	sys___acl_set_fd(struct lwp *, const struct sys___acl_set_fd_args *, register_t *);
+
+int	sys___acl_delete_file(struct lwp *, const struct sys___acl_delete_file_args *, register_t *);
+
+int	sys___acl_delete_fd(struct lwp *, const struct sys___acl_delete_fd_args *, register_t *);
+
+int	sys___acl_aclcheck_file(struct lwp *, const struct sys___acl_aclcheck_file_args *, register_t *);
+
+int	sys___acl_aclcheck_fd(struct lwp *, const struct sys___acl_aclcheck_fd_args *, register_t *);
+
+int	sys_lpathconf(struct lwp *, const struct sys_lpathconf_args *, register_t *);
+
 #endif /* !RUMP_CLIENT */
 #endif /* _SYS_SYSCALLARGS_H_ */
Index: sys/sys/types.h
===================================================================
RCS file: /cvsroot/src/sys/sys/types.h,v
retrieving revision 1.104
diff -u -p -p -u -r1.104 types.h
--- sys/sys/types.h	28 Jan 2020 16:40:27 -0000	1.104
+++ sys/sys/types.h	15 May 2020 16:56:54 -0000
@@ -171,6 +171,11 @@ typedef	__mode_t	mode_t;		/* permissions
 #define	mode_t		__mode_t
 #endif
 
+#ifndef	accmode_t
+typedef	__accmode_t	accmode_t;	/* access permissions */
+#define	accmode_t	__accmode_t
+#endif
+
 typedef	uint32_t	nlink_t;	/* link count */
 
 #ifndef	off_t
Index: sys/sys/unistd.h
===================================================================
RCS file: /cvsroot/src/sys/sys/unistd.h,v
retrieving revision 1.62
diff -u -p -p -u -r1.62 unistd.h
--- sys/sys/unistd.h	16 Oct 2019 20:43:18 -0000	1.62
+++ sys/sys/unistd.h	15 May 2020 16:56:54 -0000
@@ -217,6 +217,11 @@
 /* From OpenSolaris, used by SEEK_DATA/SEEK_HOLE. */
 #define	_PC_MIN_HOLE_SIZE	15
 
+#ifdef _NETBSD_SOURCE
+#define _PC_ACL_PATH_MAX        16
+#define _PC_ACL_NFS4            17
+#endif
+
 /* configurable system variables; use as argument to sysconf(3) */
 /*
  * XXX The value of _SC_CLK_TCK is embedded in <time.h>.
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.295
diff -u -p -p -u -r1.295 vnode.h
--- sys/sys/vnode.h	13 Apr 2020 19:23:20 -0000	1.295
+++ sys/sys/vnode.h	15 May 2020 16:56:54 -0000
@@ -66,6 +66,7 @@
 #include <sys/rwlock.h>
 #include <sys/mutex.h>
 #include <sys/time.h>
+#include <sys/acl.h>
 
 /* XXX: clean up includes later */
 #include <uvm/uvm_param.h>	/* XXX */
@@ -201,6 +202,7 @@ typedef struct vnode vnode_t;
 #define	VV_MAPPED	0x00000008	/* vnode might have user mappings */
 #define	VV_MPSAFE	0x00000010	/* file system code is MP safe */
 #define	VV_LOCKSWORK	0x00000020	/* FS supports locking discipline */
+#define	VV_HASACL	0x00000040	/* vnode has ACLS */
 
 /*
  * The second set are locked by vp->v_interlock.  VI_TEXT and VI_EXECMAP are
@@ -292,11 +294,72 @@ struct vattr {
 #define	IO_ADV_DECODE(ioflag)	(((ioflag) & IO_ADV_MASK) >> IO_ADV_SHIFT)
 
 /*
- *  Modes.
+ * Flags for accmode_t.
  */
-#define	VREAD	00004		/* read, write, execute permissions */
-#define	VWRITE	00002
-#define	VEXEC	00001
+#define	VEXEC			000000000100 /* execute/search permission */
+#define	VWRITE			000000000200 /* write permission */
+#define	VREAD			000000000400 /* read permission */
+#define	VADMIN			000000010000 /* being the file owner */
+#define	VAPPEND			000000040000 /* permission to write/append */
+
+/*
+ * VEXPLICIT_DENY makes VOP_ACCESSX(9) return EPERM or EACCES only
+ * if permission was denied explicitly, by a "deny" rule in NFSv4 ACL,
+ * and 0 otherwise.  This never happens with ordinary unix access rights
+ * or POSIX.1e ACLs.  Obviously, VEXPLICIT_DENY must be OR-ed with
+ * some other V* constant.
+ */
+#define	VEXPLICIT_DENY		000000100000
+#define	VREAD_NAMED_ATTRS 	000000200000 /* not used */
+#define	VWRITE_NAMED_ATTRS 	000000400000 /* not used */
+#define	VDELETE_CHILD	 	000001000000
+#define	VREAD_ATTRIBUTES 	000002000000 /* permission to stat(2) */
+#define	VWRITE_ATTRIBUTES 	000004000000 /* change {m,c,a}time */
+#define	VDELETE		 	000010000000
+#define	VREAD_ACL	 	000020000000 /* read ACL and file mode */
+#define	VWRITE_ACL	 	000040000000 /* change ACL and/or file mode */
+#define	VWRITE_OWNER	 	000100000000 /* change file owner */
+#define	VSYNCHRONIZE	 	000200000000 /* not used */
+#define	VCREAT			000400000000 /* creating new file */
+#define	VVERIFY			001000000000 /* verification required */
+
+#define __VNODE_PERM_BITS	\
+	"\10"			\
+	"\07VEXEC"		\
+	"\10VWRITE"		\
+	"\11VREAD"		\
+	"\15VADMIN"		\
+	"\17VAPPEND"		\
+	"\20VEXPLICIT_DENY"	\
+	"\21VREAD_NAMED_ATTRS"	\
+	"\22VWRITE_NAMED_ATTRS"	\
+	"\23VDELETE_CHILD"	\
+	"\24VREAD_ATTRIBUTES"	\
+	"\25VWRITE_ATTRIBUTES"	\
+	"\26VDELETE"		\
+	"\27VREAD_ACL"		\
+	"\30VWRITE_ACL"		\
+	"\31VWRITE_OWNER"	\
+	"\32VSYNCHRONIZE"	\
+	"\33VCREAT"		\
+	"\34VVERIFY"
+
+/*
+ * Permissions that were traditionally granted only to the file owner.
+ */
+#define VADMIN_PERMS	(VADMIN | VWRITE_ATTRIBUTES | VWRITE_ACL | \
+    VWRITE_OWNER)
+
+/*
+ * Permissions that were traditionally granted to everyone.
+ */
+#define VSTAT_PERMS	(VREAD_ATTRIBUTES | VREAD_ACL)
+
+/*
+ * Permissions that allow to change the state of the file in any way.
+ */
+#define VMODIFY_PERMS	(VWRITE | VAPPEND | VADMIN_PERMS | VDELETE_CHILD | \
+    VDELETE)
 
 /*
  * Token indicating no attribute value yet assigned.
@@ -580,6 +643,7 @@ int	rawdev_mounted(struct vnode *, struc
 uint8_t	vtype2dt(enum vtype);
 
 /* see vfssubr(9) */
+int	vfs_unixify_accmode(accmode_t *);
 void	vfs_getnewfsid(struct mount *);
 void	vfs_timestamp(struct timespec *);
 #if defined(DDB) || defined(DEBUGPRINT)
Index: sys/sys/vnode_if.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode_if.h,v
retrieving revision 1.104
diff -u -p -p -u -r1.104 vnode_if.h
--- sys/sys/vnode_if.h	23 Feb 2020 22:15:18 -0000	1.104
+++ sys/sys/vnode_if.h	15 May 2020 16:56:54 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnode_if.h,v 1.104 2020/02/23 22:15:18 ad Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -117,13 +117,23 @@ int VOP_CLOSE(struct vnode *, int, kauth
 struct vop_access_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
-	int a_mode;
+	accmode_t a_accmode;
 	kauth_cred_t a_cred;
 };
 extern const struct vnodeop_desc vop_access_desc;
-int VOP_ACCESS(struct vnode *, int, kauth_cred_t);
+int VOP_ACCESS(struct vnode *, accmode_t, kauth_cred_t);
+
+#define VOP_ACCESSX_DESCOFFSET 8
+struct vop_accessx_args {
+	const struct vnodeop_desc *a_desc;
+	struct vnode *a_vp;
+	accmode_t a_accmode;
+	kauth_cred_t a_cred;
+};
+extern const struct vnodeop_desc vop_accessx_desc;
+int VOP_ACCESSX(struct vnode *, accmode_t, kauth_cred_t);
 
-#define VOP_GETATTR_DESCOFFSET 8
+#define VOP_GETATTR_DESCOFFSET 9
 struct vop_getattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -133,7 +143,7 @@ struct vop_getattr_args {
 extern const struct vnodeop_desc vop_getattr_desc;
 int VOP_GETATTR(struct vnode *, struct vattr *, kauth_cred_t);
 
-#define VOP_SETATTR_DESCOFFSET 9
+#define VOP_SETATTR_DESCOFFSET 10
 struct vop_setattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -143,7 +153,7 @@ struct vop_setattr_args {
 extern const struct vnodeop_desc vop_setattr_desc;
 int VOP_SETATTR(struct vnode *, struct vattr *, kauth_cred_t);
 
-#define VOP_READ_DESCOFFSET 10
+#define VOP_READ_DESCOFFSET 11
 struct vop_read_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -154,7 +164,7 @@ struct vop_read_args {
 extern const struct vnodeop_desc vop_read_desc;
 int VOP_READ(struct vnode *, struct uio *, int, kauth_cred_t);
 
-#define VOP_WRITE_DESCOFFSET 11
+#define VOP_WRITE_DESCOFFSET 12
 struct vop_write_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -165,7 +175,7 @@ struct vop_write_args {
 extern const struct vnodeop_desc vop_write_desc;
 int VOP_WRITE(struct vnode *, struct uio *, int, kauth_cred_t);
 
-#define VOP_FALLOCATE_DESCOFFSET 12
+#define VOP_FALLOCATE_DESCOFFSET 13
 struct vop_fallocate_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -175,7 +185,7 @@ struct vop_fallocate_args {
 extern const struct vnodeop_desc vop_fallocate_desc;
 int VOP_FALLOCATE(struct vnode *, off_t, off_t);
 
-#define VOP_FDISCARD_DESCOFFSET 13
+#define VOP_FDISCARD_DESCOFFSET 14
 struct vop_fdiscard_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -185,7 +195,7 @@ struct vop_fdiscard_args {
 extern const struct vnodeop_desc vop_fdiscard_desc;
 int VOP_FDISCARD(struct vnode *, off_t, off_t);
 
-#define VOP_IOCTL_DESCOFFSET 14
+#define VOP_IOCTL_DESCOFFSET 15
 struct vop_ioctl_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -197,7 +207,7 @@ struct vop_ioctl_args {
 extern const struct vnodeop_desc vop_ioctl_desc;
 int VOP_IOCTL(struct vnode *, u_long, void *, int, kauth_cred_t);
 
-#define VOP_FCNTL_DESCOFFSET 15
+#define VOP_FCNTL_DESCOFFSET 16
 struct vop_fcntl_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -209,7 +219,7 @@ struct vop_fcntl_args {
 extern const struct vnodeop_desc vop_fcntl_desc;
 int VOP_FCNTL(struct vnode *, u_int, void *, int, kauth_cred_t);
 
-#define VOP_POLL_DESCOFFSET 16
+#define VOP_POLL_DESCOFFSET 17
 struct vop_poll_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -218,7 +228,7 @@ struct vop_poll_args {
 extern const struct vnodeop_desc vop_poll_desc;
 int VOP_POLL(struct vnode *, int);
 
-#define VOP_KQFILTER_DESCOFFSET 17
+#define VOP_KQFILTER_DESCOFFSET 18
 struct vop_kqfilter_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -227,7 +237,7 @@ struct vop_kqfilter_args {
 extern const struct vnodeop_desc vop_kqfilter_desc;
 int VOP_KQFILTER(struct vnode *, struct knote *);
 
-#define VOP_REVOKE_DESCOFFSET 18
+#define VOP_REVOKE_DESCOFFSET 19
 struct vop_revoke_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -236,7 +246,7 @@ struct vop_revoke_args {
 extern const struct vnodeop_desc vop_revoke_desc;
 int VOP_REVOKE(struct vnode *, int);
 
-#define VOP_MMAP_DESCOFFSET 19
+#define VOP_MMAP_DESCOFFSET 20
 struct vop_mmap_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -246,7 +256,7 @@ struct vop_mmap_args {
 extern const struct vnodeop_desc vop_mmap_desc;
 int VOP_MMAP(struct vnode *, vm_prot_t, kauth_cred_t);
 
-#define VOP_FSYNC_DESCOFFSET 20
+#define VOP_FSYNC_DESCOFFSET 21
 struct vop_fsync_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -258,7 +268,7 @@ struct vop_fsync_args {
 extern const struct vnodeop_desc vop_fsync_desc;
 int VOP_FSYNC(struct vnode *, kauth_cred_t, int, off_t, off_t);
 
-#define VOP_SEEK_DESCOFFSET 21
+#define VOP_SEEK_DESCOFFSET 22
 struct vop_seek_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -269,7 +279,7 @@ struct vop_seek_args {
 extern const struct vnodeop_desc vop_seek_desc;
 int VOP_SEEK(struct vnode *, off_t, off_t, kauth_cred_t);
 
-#define VOP_REMOVE_DESCOFFSET 22
+#define VOP_REMOVE_DESCOFFSET 23
 struct vop_remove_v2_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -279,7 +289,7 @@ struct vop_remove_v2_args {
 extern const struct vnodeop_desc vop_remove_desc;
 int VOP_REMOVE(struct vnode *, struct vnode *, struct componentname *);
 
-#define VOP_LINK_DESCOFFSET 23
+#define VOP_LINK_DESCOFFSET 24
 struct vop_link_v2_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -289,7 +299,7 @@ struct vop_link_v2_args {
 extern const struct vnodeop_desc vop_link_desc;
 int VOP_LINK(struct vnode *, struct vnode *, struct componentname *);
 
-#define VOP_RENAME_DESCOFFSET 24
+#define VOP_RENAME_DESCOFFSET 25
 struct vop_rename_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_fdvp;
@@ -303,7 +313,7 @@ extern const struct vnodeop_desc vop_ren
 int VOP_RENAME(struct vnode *, struct vnode *, struct componentname *, 
     struct vnode *, struct vnode *, struct componentname *);
 
-#define VOP_MKDIR_DESCOFFSET 25
+#define VOP_MKDIR_DESCOFFSET 26
 struct vop_mkdir_v3_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -315,7 +325,7 @@ extern const struct vnodeop_desc vop_mkd
 int VOP_MKDIR(struct vnode *, struct vnode **, struct componentname *, 
     struct vattr *);
 
-#define VOP_RMDIR_DESCOFFSET 26
+#define VOP_RMDIR_DESCOFFSET 27
 struct vop_rmdir_v2_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -325,7 +335,7 @@ struct vop_rmdir_v2_args {
 extern const struct vnodeop_desc vop_rmdir_desc;
 int VOP_RMDIR(struct vnode *, struct vnode *, struct componentname *);
 
-#define VOP_SYMLINK_DESCOFFSET 27
+#define VOP_SYMLINK_DESCOFFSET 28
 struct vop_symlink_v3_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -338,7 +348,7 @@ extern const struct vnodeop_desc vop_sym
 int VOP_SYMLINK(struct vnode *, struct vnode **, struct componentname *, 
     struct vattr *, char *);
 
-#define VOP_READDIR_DESCOFFSET 28
+#define VOP_READDIR_DESCOFFSET 29
 struct vop_readdir_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -352,7 +362,7 @@ extern const struct vnodeop_desc vop_rea
 int VOP_READDIR(struct vnode *, struct uio *, kauth_cred_t, int *, off_t **, 
     int *);
 
-#define VOP_READLINK_DESCOFFSET 29
+#define VOP_READLINK_DESCOFFSET 30
 struct vop_readlink_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -362,7 +372,7 @@ struct vop_readlink_args {
 extern const struct vnodeop_desc vop_readlink_desc;
 int VOP_READLINK(struct vnode *, struct uio *, kauth_cred_t);
 
-#define VOP_ABORTOP_DESCOFFSET 30
+#define VOP_ABORTOP_DESCOFFSET 31
 struct vop_abortop_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -371,7 +381,7 @@ struct vop_abortop_args {
 extern const struct vnodeop_desc vop_abortop_desc;
 int VOP_ABORTOP(struct vnode *, struct componentname *);
 
-#define VOP_INACTIVE_DESCOFFSET 31
+#define VOP_INACTIVE_DESCOFFSET 32
 struct vop_inactive_v2_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -380,7 +390,7 @@ struct vop_inactive_v2_args {
 extern const struct vnodeop_desc vop_inactive_desc;
 int VOP_INACTIVE(struct vnode *, bool *);
 
-#define VOP_RECLAIM_DESCOFFSET 32
+#define VOP_RECLAIM_DESCOFFSET 33
 struct vop_reclaim_v2_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -388,7 +398,7 @@ struct vop_reclaim_v2_args {
 extern const struct vnodeop_desc vop_reclaim_desc;
 int VOP_RECLAIM(struct vnode *);
 
-#define VOP_LOCK_DESCOFFSET 33
+#define VOP_LOCK_DESCOFFSET 34
 struct vop_lock_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -397,7 +407,7 @@ struct vop_lock_args {
 extern const struct vnodeop_desc vop_lock_desc;
 int VOP_LOCK(struct vnode *, int);
 
-#define VOP_UNLOCK_DESCOFFSET 34
+#define VOP_UNLOCK_DESCOFFSET 35
 struct vop_unlock_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -405,7 +415,7 @@ struct vop_unlock_args {
 extern const struct vnodeop_desc vop_unlock_desc;
 int VOP_UNLOCK(struct vnode *);
 
-#define VOP_BMAP_DESCOFFSET 35
+#define VOP_BMAP_DESCOFFSET 36
 struct vop_bmap_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -417,7 +427,7 @@ struct vop_bmap_args {
 extern const struct vnodeop_desc vop_bmap_desc;
 int VOP_BMAP(struct vnode *, daddr_t, struct vnode **, daddr_t *, int *);
 
-#define VOP_STRATEGY_DESCOFFSET 36
+#define VOP_STRATEGY_DESCOFFSET 37
 struct vop_strategy_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -426,7 +436,7 @@ struct vop_strategy_args {
 extern const struct vnodeop_desc vop_strategy_desc;
 int VOP_STRATEGY(struct vnode *, struct buf *);
 
-#define VOP_PRINT_DESCOFFSET 37
+#define VOP_PRINT_DESCOFFSET 38
 struct vop_print_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -434,7 +444,7 @@ struct vop_print_args {
 extern const struct vnodeop_desc vop_print_desc;
 int VOP_PRINT(struct vnode *);
 
-#define VOP_ISLOCKED_DESCOFFSET 38
+#define VOP_ISLOCKED_DESCOFFSET 39
 struct vop_islocked_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -442,7 +452,7 @@ struct vop_islocked_args {
 extern const struct vnodeop_desc vop_islocked_desc;
 int VOP_ISLOCKED(struct vnode *);
 
-#define VOP_PATHCONF_DESCOFFSET 39
+#define VOP_PATHCONF_DESCOFFSET 40
 struct vop_pathconf_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -452,7 +462,7 @@ struct vop_pathconf_args {
 extern const struct vnodeop_desc vop_pathconf_desc;
 int VOP_PATHCONF(struct vnode *, int, register_t *);
 
-#define VOP_ADVLOCK_DESCOFFSET 40
+#define VOP_ADVLOCK_DESCOFFSET 41
 struct vop_advlock_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -464,7 +474,7 @@ struct vop_advlock_args {
 extern const struct vnodeop_desc vop_advlock_desc;
 int VOP_ADVLOCK(struct vnode *, void *, int, struct flock *, int);
 
-#define VOP_WHITEOUT_DESCOFFSET 41
+#define VOP_WHITEOUT_DESCOFFSET 42
 struct vop_whiteout_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_dvp;
@@ -474,7 +484,7 @@ struct vop_whiteout_args {
 extern const struct vnodeop_desc vop_whiteout_desc;
 int VOP_WHITEOUT(struct vnode *, struct componentname *, int);
 
-#define VOP_GETPAGES_DESCOFFSET 42
+#define VOP_GETPAGES_DESCOFFSET 43
 struct vop_getpages_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -490,7 +500,7 @@ extern const struct vnodeop_desc vop_get
 int VOP_GETPAGES(struct vnode *, voff_t, struct vm_page **, int *, int, 
     vm_prot_t, int, int);
 
-#define VOP_PUTPAGES_DESCOFFSET 43
+#define VOP_PUTPAGES_DESCOFFSET 44
 struct vop_putpages_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -501,7 +511,40 @@ struct vop_putpages_args {
 extern const struct vnodeop_desc vop_putpages_desc;
 int VOP_PUTPAGES(struct vnode *, voff_t, voff_t, int);
 
-#define VOP_CLOSEEXTATTR_DESCOFFSET 44
+#define VOP_GETACL_DESCOFFSET 45
+struct vop_getacl_args {
+	const struct vnodeop_desc *a_desc;
+	struct vnode *a_vp;
+	acl_type_t a_type;
+	struct acl *a_aclp;
+	kauth_cred_t a_cred;
+};
+extern const struct vnodeop_desc vop_getacl_desc;
+int VOP_GETACL(struct vnode *, acl_type_t, struct acl *, kauth_cred_t);
+
+#define VOP_SETACL_DESCOFFSET 46
+struct vop_setacl_args {
+	const struct vnodeop_desc *a_desc;
+	struct vnode *a_vp;
+	acl_type_t a_type;
+	struct acl *a_aclp;
+	kauth_cred_t a_cred;
+};
+extern const struct vnodeop_desc vop_setacl_desc;
+int VOP_SETACL(struct vnode *, acl_type_t, struct acl *, kauth_cred_t);
+
+#define VOP_ACLCHECK_DESCOFFSET 47
+struct vop_aclcheck_args {
+	const struct vnodeop_desc *a_desc;
+	struct vnode *a_vp;
+	acl_type_t a_type;
+	struct acl *a_aclp;
+	kauth_cred_t a_cred;
+};
+extern const struct vnodeop_desc vop_aclcheck_desc;
+int VOP_ACLCHECK(struct vnode *, acl_type_t, struct acl *, kauth_cred_t);
+
+#define VOP_CLOSEEXTATTR_DESCOFFSET 48
 struct vop_closeextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -511,7 +554,7 @@ struct vop_closeextattr_args {
 extern const struct vnodeop_desc vop_closeextattr_desc;
 int VOP_CLOSEEXTATTR(struct vnode *, int, kauth_cred_t);
 
-#define VOP_GETEXTATTR_DESCOFFSET 45
+#define VOP_GETEXTATTR_DESCOFFSET 49
 struct vop_getextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -525,7 +568,7 @@ extern const struct vnodeop_desc vop_get
 int VOP_GETEXTATTR(struct vnode *, int, const char *, struct uio *, 
     size_t *, kauth_cred_t);
 
-#define VOP_LISTEXTATTR_DESCOFFSET 46
+#define VOP_LISTEXTATTR_DESCOFFSET 50
 struct vop_listextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -539,7 +582,7 @@ extern const struct vnodeop_desc vop_lis
 int VOP_LISTEXTATTR(struct vnode *, int, struct uio *, size_t *, int, 
     kauth_cred_t);
 
-#define VOP_OPENEXTATTR_DESCOFFSET 47
+#define VOP_OPENEXTATTR_DESCOFFSET 51
 struct vop_openextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -548,7 +591,7 @@ struct vop_openextattr_args {
 extern const struct vnodeop_desc vop_openextattr_desc;
 int VOP_OPENEXTATTR(struct vnode *, kauth_cred_t);
 
-#define VOP_DELETEEXTATTR_DESCOFFSET 48
+#define VOP_DELETEEXTATTR_DESCOFFSET 52
 struct vop_deleteextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -559,7 +602,7 @@ struct vop_deleteextattr_args {
 extern const struct vnodeop_desc vop_deleteextattr_desc;
 int VOP_DELETEEXTATTR(struct vnode *, int, const char *, kauth_cred_t);
 
-#define VOP_SETEXTATTR_DESCOFFSET 49
+#define VOP_SETEXTATTR_DESCOFFSET 53
 struct vop_setextattr_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
@@ -572,6 +615,6 @@ extern const struct vnodeop_desc vop_set
 int VOP_SETEXTATTR(struct vnode *, int, const char *, struct uio *, 
     kauth_cred_t);
 
-#define VNODE_OPS_COUNT	50
+#define VNODE_OPS_COUNT	54
 
 #endif /* !_SYS_VNODE_IF_H_ */
Index: sys/ufs/files.ufs
===================================================================
RCS file: /cvsroot/src/sys/ufs/files.ufs,v
retrieving revision 1.47
diff -u -p -p -u -r1.47 files.ufs
--- sys/ufs/files.ufs	18 Apr 2020 19:18:33 -0000	1.47
+++ sys/ufs/files.ufs	15 May 2020 16:56:54 -0000
@@ -7,7 +7,7 @@ deffs					LFS
 deffs					CHFS
 
 defflag	opt_ffs.h			FFS_EI FFS_NO_SNAPSHOT APPLE_UFS
-					UFS_DIRHASH UFS_EXTATTR
+					UFS_DIRHASH UFS_EXTATTR UFS_ACL
 
 defflag	opt_lfs.h			LFS_EI LFS_KERNEL_RFW
 					LFS_DIRHASH LFS_EXTATTR
@@ -99,6 +99,7 @@ file	ufs/mfs/mfs_vnops.c		mfs
 file	ufs/mfs/mfs_miniroot.c
 
 define	ufs: vfs
+file	ufs/ufs/ufs_acl.c		ufs & (ffs | mfs | ext2fs | chfs)
 file	ufs/ufs/ufs_bmap.c		ufs & (ffs | mfs | ext2fs | chfs)
 file	ufs/ufs/ufs_dirhash.c		(ffs | mfs | ext2fs | chfs) & ufs_dirhash
 file	ufs/ufs/ufs_extattr.c		(ffs | mfs) & ufs_extattr
Index: sys/ufs/chfs/chfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/chfs/chfs_subr.c,v
retrieving revision 1.12
diff -u -p -p -u -r1.12 chfs_subr.c
--- sys/ufs/chfs/chfs_subr.c	23 Apr 2020 21:47:08 -0000	1.12
+++ sys/ufs/chfs/chfs_subr.c	15 May 2020 16:56:54 -0000
@@ -279,7 +279,7 @@ chfs_chflags(struct vnode *vp, int flags
 	}
 
 	error = kauth_authorize_vnode(cred, action, vp, NULL,
-	    genfs_can_chflags(cred, CHTTOVT(ip->ch_type), ip->uid, changing_sysflags));
+	    genfs_can_chflags(vp, cred, ip->uid, changing_sysflags));
 	if (error)
 		return error;
 
Index: sys/ufs/chfs/chfs_vnode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/chfs/chfs_vnode.c,v
retrieving revision 1.18
diff -u -p -p -u -r1.18 chfs_vnode.c
--- sys/ufs/chfs/chfs_vnode.c	17 Jan 2020 20:08:10 -0000	1.18
+++ sys/ufs/chfs/chfs_vnode.c	15 May 2020 16:56:54 -0000
@@ -251,9 +251,9 @@ chfs_makeinode(int mode, struct vnode *d
 
 	/* authorize setting SGID if needed */
 	if (ip->mode & ISGID) {
-		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
-		    vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid,
-		    ip->gid, mode));
+		error = kauth_authorize_vnode(cnp->cn_cred,
+		    KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp,
+		    cnp->cn_cred, ip->uid, ip->gid, mode));
 		if (error)
 			ip->mode &= ~ISGID;
 	}
Index: sys/ufs/chfs/chfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/chfs/chfs_vnops.c,v
retrieving revision 1.38
diff -u -p -p -u -r1.38 chfs_vnops.c
--- sys/ufs/chfs/chfs_vnops.c	23 Apr 2020 21:47:08 -0000	1.38
+++ sys/ufs/chfs/chfs_vnops.c	15 May 2020 16:56:54 -0000
@@ -371,13 +371,13 @@ int
 chfs_access(void *v)
 {
 	struct vnode *vp = ((struct vop_access_args *) v)->a_vp;
-	int mode = ((struct vop_access_args *) v)->a_mode;
+	accmode_t accmode = ((struct vop_access_args *) v)->a_accmode;
 	kauth_cred_t cred = ((struct vop_access_args *) v)->a_cred;
 
 	dbg("access()\n");
 	struct chfs_inode *ip = VTOI(vp);
 
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VLNK:
 		case VDIR:
@@ -395,12 +395,12 @@ chfs_access(void *v)
 		}
 	}
 
-	if (mode & VWRITE && ip->flags & IMMUTABLE)
+	if (accmode & VWRITE && ip->flags & IMMUTABLE)
 		return (EPERM);
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
-	    ip->mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
-	    ip->mode & ALLPERMS, ip->uid, ip->gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, ip->mode & ALLPERMS), vp, NULL, genfs_can_access(vp,
+	    cred, ip->uid, ip->gid, ip->mode & ALLPERMS, NULL, accmode));
 }
 
 /* --------------------------------------------------------------------- */
@@ -510,7 +510,8 @@ chfs_setattr(void *v)
 	/* set time */
 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->uid, cred));
+		    NULL, genfs_can_chtimes(vp, cred, ip->uid,
+		    vap->va_vaflags));
 		if (error)
 			return error;
 		if (vap->va_atime.tv_sec != VNOVAL)
@@ -539,7 +540,7 @@ chfs_chmod(struct vnode *vp, int mode, k
 	dbg("chmod\n");
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, ip->uid, ip->gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, ip->uid, ip->gid, mode));
 	if (error)
 		return error;
 	ip->mode &= ~ALLPERMS;
@@ -566,7 +567,7 @@ chfs_chown(struct vnode *vp, uid_t uid, 
 		gid = ip->gid;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, ip->uid, ip->gid, uid, gid));
+	    NULL, genfs_can_chown(vp, cred, ip->uid, ip->gid, uid, gid));
 	if (error)
 		return error;
 
@@ -1603,6 +1604,7 @@ const struct vnodeopv_entry_desc chfs_vn
 		{ &vop_open_desc, chfs_open },
 		{ &vop_close_desc, chfs_close },
 		{ &vop_access_desc, chfs_access },
+		{ &vop_accessx_desc, genfs_accessx },
 		{ &vop_getattr_desc, chfs_getattr },
 		{ &vop_setattr_desc, chfs_setattr },
 		{ &vop_read_desc, chfs_read },
@@ -1661,6 +1663,7 @@ const struct vnodeopv_entry_desc chfs_sp
 		{ &vop_open_desc, spec_open },
 		{ &vop_close_desc, ufsspec_close },
 		{ &vop_access_desc, chfs_access },
+		{ &vop_accessx_desc, genfs_access },
 		{ &vop_getattr_desc, chfs_getattr },
 		{ &vop_setattr_desc, chfs_setattr },
 		{ &vop_read_desc, chfs_read },
@@ -1717,6 +1720,7 @@ const struct vnodeopv_entry_desc chfs_fi
 		{ &vop_open_desc, vn_fifo_bypass },
 		{ &vop_close_desc, ufsfifo_close },
 		{ &vop_access_desc, chfs_access },
+		{ &vop_accessx_desc, genfs_access },
 		{ &vop_getattr_desc, chfs_getattr },
 		{ &vop_setattr_desc, chfs_setattr },
 		{ &vop_read_desc, ufsfifo_read },
Index: sys/ufs/ext2fs/ext2fs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_lookup.c,v
retrieving revision 1.90
diff -u -p -p -u -r1.90 ext2fs_lookup.c
--- sys/ufs/ext2fs/ext2fs_lookup.c	4 Apr 2020 20:49:31 -0000	1.90
+++ sys/ufs/ext2fs/ext2fs_lookup.c	15 May 2020 16:56:54 -0000
@@ -661,7 +661,7 @@ found:
 		 */
 		if (dp->i_e2fs_mode & ISVTX) {
 			error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE,
-			    tdp, vdp, genfs_can_sticky(cred, dp->i_uid,
+			    tdp, vdp, genfs_can_sticky(vdp, cred, dp->i_uid,
 			    VTOI(tdp)->i_uid));
 			if (error) {
 				vrele(tdp);
Index: sys/ufs/ext2fs/ext2fs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vfsops.c,v
retrieving revision 1.218
diff -u -p -p -u -r1.218 ext2fs_vfsops.c
--- sys/ufs/ext2fs/ext2fs_vfsops.c	4 Apr 2020 20:49:31 -0000	1.218
+++ sys/ufs/ext2fs/ext2fs_vfsops.c	15 May 2020 16:56:54 -0000
@@ -1148,8 +1148,8 @@ ext2fs_newvnode(struct mount *mp, struct
 	/* Authorize setting SGID if needed. */
 	if (ip->i_e2fs_mode & ISGID) {
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
-		    vp, NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid,
-		    ip->i_gid, mode));
+		    vp, NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid,
+		    mode));
 		if (error)
 			ip->i_e2fs_mode &= ~ISGID;
 	}
Index: sys/ufs/ext2fs/ext2fs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vnops.c,v
retrieving revision 1.131
diff -u -p -p -u -r1.131 ext2fs_vnops.c
--- sys/ufs/ext2fs/ext2fs_vnops.c	8 Mar 2020 17:38:12 -0000	1.131
+++ sys/ufs/ext2fs/ext2fs_vnops.c	15 May 2020 16:56:54 -0000
@@ -226,13 +226,14 @@ ext2fs_check_possible(struct vnode *vp, 
 }
 
 static int
-ext2fs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
+ext2fs_check_permitted(struct vnode *vp, struct inode *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
-	    ip->i_e2fs_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
-	    ip->i_e2fs_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, ip->i_e2fs_mode & ALLPERMS), vp, NULL,
+	    genfs_can_access(vp, cred, ip->i_uid, ip->i_gid,
+	    ip->i_e2fs_mode & ALLPERMS, NULL, accmode));
 }
 
 int
@@ -240,12 +241,12 @@ ext2fs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode *a_vp;
-		int  a_mode;
+		accmode_t  a_accmode;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct inode *ip = VTOI(vp);
-	mode_t mode = ap->a_mode;
+	accmode_t mode = ap->a_accmode;
 	int error;
 
 	error = ext2fs_check_possible(vp, ip, mode);
@@ -367,8 +368,7 @@ ext2fs_setattr(void *v)
 #endif /* EXT2FS_SYSTEM_FLAGS */
 
 		error = kauth_authorize_vnode(cred, action, vp, NULL,
-		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
-		    changing_sysflags));
+		    genfs_can_chflags(vp, cred, ip->i_uid, changing_sysflags));
 		if (error)
 			return error;
 
@@ -425,8 +425,8 @@ ext2fs_setattr(void *v)
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 			return EROFS;
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid,
-		    cred));
+		    NULL, genfs_can_chtimes(vp, cred, ip->i_uid,
+		    vap->va_vaflags));
 		if (error)
 			return error;
 		if (vap->va_atime.tv_sec != VNOVAL)
@@ -468,8 +468,7 @@ ext2fs_chmod(struct vnode *vp, int mode,
 	int error;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid,
-	    mode));
+	    NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode));
 	if (error)
 		return error;
 
@@ -498,7 +497,7 @@ ext2fs_chown(struct vnode *vp, uid_t uid
 		gid = ip->i_gid;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
+	    NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid));
 	if (error)
 		return error;
 
@@ -1101,6 +1100,7 @@ const struct vnodeopv_entry_desc ext2fs_
 	{ &vop_open_desc, ext2fs_open },		/* open */
 	{ &vop_close_desc, ufs_close },			/* close */
 	{ &vop_access_desc, ext2fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ext2fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ext2fs_setattr },		/* setattr */
 	{ &vop_read_desc, ext2fs_read },		/* read */
@@ -1155,6 +1155,7 @@ const struct vnodeopv_entry_desc ext2fs_
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, ufsspec_close },		/* close */
 	{ &vop_access_desc, ext2fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ext2fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ext2fs_setattr },		/* setattr */
 	{ &vop_read_desc, ufsspec_read },		/* read */
@@ -1209,6 +1210,7 @@ const struct vnodeopv_entry_desc ext2fs_
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, ufsfifo_close },		/* close */
 	{ &vop_access_desc, ext2fs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ext2fs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ext2fs_setattr },		/* setattr */
 	{ &vop_read_desc, ufsfifo_read },		/* read */
Index: sys/ufs/ext2fs/ext2fs_xattr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_xattr.c,v
retrieving revision 1.4
diff -u -p -p -u -r1.4 ext2fs_xattr.c
--- sys/ufs/ext2fs/ext2fs_xattr.c	23 Aug 2016 06:40:54 -0000	1.4
+++ sys/ufs/ext2fs/ext2fs_xattr.c	15 May 2020 16:56:54 -0000
@@ -205,19 +205,13 @@ ext2fs_getextattr(void *v)
 	        kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct inode *ip = VTOI(ap->a_vp);
-	char namebuf[EXT2FS_XATTR_NAME_LEN_MAX + 1];
 	int error;
 	const char *prefix, *name;
 	uint8_t name_index;
 	size_t name_match, valuesize = 0;
 
-	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_USER)
-		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_USER];
-	else
-		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_SYSTEM];
-	snprintf(namebuf, sizeof(namebuf), "%s%s", prefix, ap->a_name);
-
-        error = extattr_check_cred(ap->a_vp, namebuf, ap->a_cred, VREAD);
+        error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
+	    VREAD);
         if (error)
                 return error;
 
@@ -408,7 +402,6 @@ ext2fs_listextattr(void *v)
 	} */ *ap = v;
 	struct inode *ip = VTOI(ap->a_vp);
 	int error;
-	const char *prefix;
 	size_t listsize = 0;
 
 	if (!EXT2F_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXTATTR)) {
@@ -416,15 +409,8 @@ ext2fs_listextattr(void *v)
 		goto out;
 	}
 
-        /*
-         * XXX: We can move this inside the loop and iterate on individual
-         *      attributes.
-         */
-	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_USER)
-		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_USER];
-	else
-		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_SYSTEM];
-        error = extattr_check_cred(ap->a_vp, prefix, ap->a_cred, VREAD);
+        error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
+	    VREAD);
         if (error)
                 return error;
 
Index: sys/ufs/ffs/ffs_extattr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_extattr.c,v
retrieving revision 1.4
diff -u -p -p -u -r1.4 ffs_extattr.c
--- sys/ufs/ffs/ffs_extattr.c	2 May 2020 22:11:16 -0000	1.4
+++ sys/ufs/ffs/ffs_extattr.c	15 May 2020 16:56:54 -0000
@@ -134,34 +134,6 @@ typedef daddr_t ufs_lbn_t;
 #define vfs_bio_set_flags(bp, ioflag) 	__nothing
 
 /*
- * Credential check based on process requesting service, and per-attribute
- * permissions.
- */
-static int
-ffs_extattr_check_cred(struct vnode *vp, int attrnamespace, kauth_cred_t cred,
-    accmode_t accmode)
-{
-	/*
-	 * Kernel-invoked always succeeds.
-	 */
-	if (cred == NOCRED)
-		return 0;
-
-	/*
-	 * Do not allow privileged processes in jail to directly manipulate
-	 * system attributes.
-	 */
-	switch (attrnamespace) {
-	case EXTATTR_NAMESPACE_SYSTEM:
-		return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR,
-		    0, vp->v_mount, NULL, NULL);
-	case EXTATTR_NAMESPACE_USER:
-		return VOP_ACCESS(vp, accmode, cred);
-	default:
-		return EPERM;
-	}
-}
-/*
  * Extended attribute area reading.
  */
 static int
@@ -683,7 +655,7 @@ ffs_getextattr(void *v)
 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
 		return (EOPNOTSUPP);
 
-	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
 	    ap->a_cred, VREAD);
 	if (error)
 		return (error);
@@ -757,7 +729,7 @@ ffs_setextattr(void *v)
 	if (ealen < 0 || ealen > lblktosize(fs, UFS_NXADDR))
 		return (EINVAL);
 
-	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
 	    ap->a_cred, VWRITE);
 	if (error) {
 
@@ -862,7 +834,7 @@ ffs_listextattr(void *v)
 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
 		return (EOPNOTSUPP);
 
-	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
 	    ap->a_cred, VREAD);
 	if (error)
 		return (error);
@@ -932,7 +904,7 @@ ffs_deleteextattr(void *v)
 	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
 		return (EROFS);
 
-	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
 	    ap->a_cred, VWRITE);
 	if (error) {
 		/*
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.368
diff -u -p -p -u -r1.368 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	12 May 2020 23:17:41 -0000	1.368
+++ sys/ufs/ffs/ffs_vfsops.c	15 May 2020 16:56:54 -0000
@@ -394,6 +394,52 @@ ffs_mountroot(void)
 	return (0);
 }
 
+static void
+ffs_acls(struct mount *mp, int fs_flags)
+{
+	if ((fs_flags & FS_ACLS) != 0) {
+#ifdef UFS_ACL
+		if (mp->mnt_flag & MNT_POSIX1EACLS)
+			printf("WARNING: %s: ACLs flag on fs conflicts with "
+			    "\"posix1eacls\" mount option; option ignored\n",
+			    mp->mnt_stat.f_mntonname);
+		mp->mnt_flag &= ~MNT_ACLS;
+		mp->mnt_flag |= MNT_POSIX1EACLS;
+
+#else
+		printf("WARNING: %s: ACLs flag on fs but no ACLs support\n",
+		    mp->mnt_stat.f_mntonname);
+#endif
+	}
+	if ((fs_flags & FS_POSIX1EACLS) != 0) {
+#ifdef UFS_ACL
+		if (mp->mnt_flag & MNT_ACLS)
+			printf("WARNING: %s: NFSv4 ACLs flag on fs conflicts "
+			    "with \"acls\" mount option; option ignored\n",
+			    mp->mnt_stat.f_mntonname);
+		mp->mnt_flag &= ~MNT_POSIX1EACLS;
+		mp->mnt_flag |= MNT_ACLS;
+#else
+		printf("WARNING: %s: POSIX.1e ACLs flag on fs but no "
+		    "ACLs support\n", mp->mnt_stat.f_mntonname);
+#endif
+	}
+
+	if ((mp->mnt_flag & (MNT_ACLS | MNT_POSIX1EACLS))
+	    == (MNT_ACLS | MNT_POSIX1EACLS))
+	{
+		printf("WARNING: %s: posix1eacl conflicts "
+		    "with \"acls\" mount option; option ignored\n",
+		    mp->mnt_stat.f_mntonname);
+		mp->mnt_flag &= ~MNT_POSIX1EACLS;
+	}
+
+	if (mp->mnt_flag & (MNT_ACLS | MNT_POSIX1EACLS))
+		mp->mnt_iflag &= ~IMNT_SHRLOOKUP;
+	else
+		mp->mnt_iflag |= IMNT_SHRLOOKUP;
+}
+
 /*
  * VFS Operations.
  *
@@ -612,6 +658,8 @@ ffs_mount(struct mount *mp, const char *
 				DPRINTF("ffs_reload returned %d", error);
 				return error;
 			}
+		} else {
+			ffs_acls(mp, 0);
 		}
 
 		if (fs->fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) {
@@ -854,6 +902,8 @@ ffs_reload(struct mount *mp, kauth_cred_
 	}
 	ffs_oldfscompat_read(fs, ump, sblockloc);
 
+	ffs_acls(mp, 0);
+
 	mutex_enter(&ump->um_lock);
 	ump->um_maxfilesize = fs->fs_maxfilesize;
 	if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
@@ -865,6 +915,7 @@ ffs_reload(struct mount *mp, kauth_cred_
 			return (EINVAL);
 		}
 	}
+
 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
 		fs->fs_pendingblocks = 0;
 		fs->fs_pendinginodes = 0;
@@ -1460,6 +1511,7 @@ ffs_mountfs(struct vnode *devvp, struct 
 	if (needswap)
 		ump->um_flags |= UFS_NEEDSWAP;
 #endif
+	ffs_acls(mp, fs->fs_flags);
 	ump->um_mountp = mp;
 	ump->um_dev = dev;
 	ump->um_devvp = devvp;
@@ -2084,7 +2136,8 @@ ffs_loadvnode(struct mount *mp, struct v
 		ip->i_gid = ip->i_ffs1_ogid;			/* XXX */
 	}							/* XXX */
 	uvm_vnp_setsize(vp, ip->i_size);
-	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, true);
+	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, 
+	    !(vp->v_vflag & VV_HASACL));
 	*new_key = &ip->i_number;
 	return 0;
 }
@@ -2206,7 +2259,8 @@ ffs_newvnode(struct mount *mp, struct vn
 	}
 
 	uvm_vnp_setsize(vp, ip->i_size);
-	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, true);
+	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid,
+	    !(vp->v_vflag & VV_HASACL));
 	*new_key = &ip->i_number;
 	return 0;
 }
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v
retrieving revision 1.131
diff -u -p -p -u -r1.131 ffs_vnops.c
--- sys/ufs/ffs/ffs_vnops.c	18 Apr 2020 19:18:34 -0000	1.131
+++ sys/ufs/ffs/ffs_vnops.c	15 May 2020 16:56:54 -0000
@@ -88,6 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/specfs/specdev.h>
 
+#include <ufs/ufs/acl.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/ufs_extern.h>
@@ -109,7 +110,8 @@ const struct vnodeopv_entry_desc ffs_vno
 	{ &vop_mknod_desc, ufs_mknod },			/* mknod */
 	{ &vop_open_desc, ufs_open },			/* open */
 	{ &vop_close_desc, ufs_close },			/* close */
-	{ &vop_access_desc, ufs_access },		/* access */
+	{ &vop_access_desc, genfs_access },		/* access */
+	{ &vop_accessx_desc, ufs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
 	{ &vop_read_desc, ffs_read },			/* read */
@@ -152,6 +154,9 @@ const struct vnodeopv_entry_desc ffs_vno
 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
+	{ &vop_getacl_desc, ufs_getacl },		/* getacl */
+	{ &vop_setacl_desc, ufs_setacl },		/* setacl */
+	{ &vop_aclcheck_desc, ufs_aclcheck },		/* aclcheck */
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
@@ -165,7 +170,8 @@ const struct vnodeopv_entry_desc ffs_spe
 	{ &vop_mknod_desc, spec_mknod },		/* mknod */
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, ufsspec_close },		/* close */
-	{ &vop_access_desc, ufs_access },		/* access */
+	{ &vop_access_desc, genfs_access },		/* access */
+	{ &vop_accessx_desc, ufs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
 	{ &vop_read_desc, ufsspec_read },		/* read */
@@ -208,6 +214,9 @@ const struct vnodeopv_entry_desc ffs_spe
 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
+	{ &vop_getacl_desc, ufs_getacl },		/* getacl */
+	{ &vop_setacl_desc, ufs_setacl },		/* setacl */
+	{ &vop_aclcheck_desc, ufs_aclcheck },		/* aclcheck */
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc ffs_specop_opv_desc =
@@ -221,7 +230,8 @@ const struct vnodeopv_entry_desc ffs_fif
 	{ &vop_mknod_desc, vn_fifo_bypass },		/* mknod */
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, ufsfifo_close },		/* close */
-	{ &vop_access_desc, ufs_access },		/* access */
+	{ &vop_access_desc, genfs_access },		/* access */
+	{ &vop_accessx_desc, ufs_accessx },		/* accessx */
 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
 	{ &vop_read_desc, ufsfifo_read },		/* read */
@@ -263,6 +273,9 @@ const struct vnodeopv_entry_desc ffs_fif
 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
+	{ &vop_getacl_desc, ufs_getacl },		/* getacl */
+	{ &vop_setacl_desc, ufs_setacl },		/* setacl */
+	{ &vop_aclcheck_desc, ufs_aclcheck },		/* aclcheck */
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc ffs_fifoop_opv_desc =
Index: sys/ufs/ffs/fs.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/fs.h,v
retrieving revision 1.67
diff -u -p -p -u -r1.67 fs.h
--- sys/ufs/ffs/fs.h	18 Apr 2020 19:18:34 -0000	1.67
+++ sys/ufs/ffs/fs.h	15 May 2020 16:56:54 -0000
@@ -418,23 +418,31 @@ struct fs {
 
 /*
  * File system flags
+ *
+ * FS_POSIX1EACLS indicates that POSIX.1e ACLs are administratively enabled
+ * for the file system, so they should be loaded from extended attributes,
+ * observed for access control purposes, and be administered by object
+ * owners.  FS_ACLS indicates that NFSv4 ACLs are administratively
+ * enabled.  This flag is mutually exclusive with FS_POSIX1EACLS.
  */
 #define	FS_UNCLEAN	0x001	/* file system not clean at mount (unused) */
 #define	FS_DOSOFTDEP	0x002	/* file system using soft dependencies */
 #define	FS_NEEDSFSCK	0x004	/* needs sync fsck (FreeBSD compat, unused) */
 #define	FS_SUJ		0x008	/* file system using journaled softupdates */
-#define	FS_ACLS		0x010	/* file system has ACLs enabled */
+#define	FS_POSIX1EACLS	0x010	/* file system has POSIX.1e ACLs enabled */
 #define	FS_MULTILABEL	0x020	/* file system is MAC multi-label */
 #define	FS_GJOURNAL	0x40	/* gjournaled file system */
 #define	FS_FLAGS_UPDATED 0x80	/* flags have been moved to new location */
 #define	FS_DOWAPBL	0x100	/* Write ahead physical block logging */
-/*     	FS_NFS4ACLS	0x100	   file system has NFSv4 ACLs enabled (FBSD) */
+/*	FS_NFS4ACLS	0x100	   file system has NFSv4 ACLs enabled (FBSD) */
 #define	FS_DOQUOTA2	0x200	/* in-filesystem quotas */
 /*     	FS_INDEXDIRS	0x200	   kernel supports indexed directories (FBSD)*/
 #define	FS_TRIM		0x400	/* discard deleted blocks in storage layer */
+#define FS_ACLS		0x800	/* file system has NFSv4 ACLs enabled */
 
 /* File system flags that are ok for NetBSD if set in fs_flags */
-#define	FS_KNOWN_FLAGS	(FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
+#define	FS_KNOWN_FLAGS	(FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2 | \
+	FS_POSIX1EACLS | FS_ACLS)
 
 /*
  * File system internal flags, also in fs_flags.
Index: sys/ufs/lfs/lfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vnops.c,v
retrieving revision 1.332
diff -u -p -p -u -r1.332 lfs_vnops.c
--- sys/ufs/lfs/lfs_vnops.c	13 Apr 2020 19:23:20 -0000	1.332
+++ sys/ufs/lfs/lfs_vnops.c	15 May 2020 16:56:54 -0000
@@ -192,6 +192,7 @@ const struct vnodeopv_entry_desc lfs_vno
 	{ &vop_open_desc, ulfs_open },			/* open */
 	{ &vop_close_desc, lfs_close },			/* close */
 	{ &vop_access_desc, ulfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, lfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
 	{ &vop_read_desc, lfs_read },			/* read */
@@ -248,6 +249,7 @@ const struct vnodeopv_entry_desc lfs_spe
 	{ &vop_open_desc, spec_open },			/* open */
 	{ &vop_close_desc, lfsspec_close },		/* close */
 	{ &vop_access_desc, ulfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, lfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
 	{ &vop_read_desc, ulfsspec_read },		/* read */
@@ -304,6 +306,7 @@ const struct vnodeopv_entry_desc lfs_fif
 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
 	{ &vop_close_desc, lfsfifo_close },		/* close */
 	{ &vop_access_desc, ulfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, lfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
 	{ &vop_read_desc, ulfsfifo_read },		/* read */
@@ -381,8 +384,9 @@ lfs_makeinode(struct vattr *vap, struct 
 
 	/* Authorize setting SGID if needed. */
 	if (ip->i_mode & ISGID) {
-		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
-		    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
+		error = kauth_authorize_vnode(cnp->cn_cred,
+		    KAUTH_VNODE_WRITE_SECURITY,
+		    tvp, NULL, genfs_can_chmod(tvp, cnp->cn_cred, ip->i_uid,
 		    ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode)));
 		if (error) {
 			ip->i_mode &= ~ISGID;
Index: sys/ufs/lfs/ulfs_extattr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/ulfs_extattr.c,v
retrieving revision 1.15
diff -u -p -p -u -r1.15 ulfs_extattr.c
--- sys/ufs/lfs/ulfs_extattr.c	17 Jan 2020 20:08:10 -0000	1.15
+++ sys/ufs/lfs/ulfs_extattr.c	15 May 2020 16:56:54 -0000
@@ -108,58 +108,6 @@ static int	ulfs_extattr_get_header(struc
 		    struct ulfs_extattr_header *, off_t *);
 
 /*
- * Convert a FreeBSD extended attribute and namespace to a consistent string
- * representation.
- *
- * The returned value, if not NULL, is guaranteed to be an allocated object
- * of its size as returned by strlen() + 1 and must be freed by the caller.
- */
-static char *
-from_freebsd_extattr(int attrnamespace, const char *attrname)
-{
-	const char *namespace;
-	char *attr;
-	size_t len;
-
-	if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
-		namespace = "system";
-	else if (attrnamespace == EXTATTR_NAMESPACE_USER)
-		namespace = "user";
-	else
-		return NULL;
-
-	/* <namespace>.<attrname>\0 */
-	len = strlen(namespace) + 1 + strlen(attrname) + 1;
-
-	attr = kmem_alloc(len, KM_SLEEP);
-
-	snprintf(attr, len, "%s.%s", namespace, attrname);
-
-	return attr;
-}
-
-/*
- * Internal wrapper around a conversion-check-free sequence.
- */
-static int
-internal_extattr_check_cred(vnode_t *vp, int attrnamespace, const char *name,
-    kauth_cred_t cred, int access_mode)
-{
-	char *attr;
-	int error;
-
-	attr = from_freebsd_extattr(attrnamespace, name);
-	if (attr == NULL)
-		return EINVAL;
-
-	error = extattr_check_cred(vp, attr, cred, access_mode);
-
-	kmem_free(attr, strlen(attr) + 1);
-
-	return error;
-}
-
-/*
  * Per-FS attribute lock protecting attribute operations.
  * XXX Right now there is a lot of lock contention due to having a single
  * lock per-FS; really, this should be far more fine-grained.
@@ -1141,8 +1089,7 @@ ulfs_extattr_get(struct vnode *vp, int a
 	if (strlen(name) == 0)
 		return (EINVAL);
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VREAD);
+	error = extattr_check_cred(vp, attrnamespace, cred, VREAD);
 	if (error)
 		return (error);
 
@@ -1260,8 +1207,7 @@ ulfs_extattr_list(struct vnode *vp, int 
 	 * XXX: We can move this inside the loop and iterate on individual
 	 *	attributes.
 	 */
-	error = internal_extattr_check_cred(vp, attrnamespace, "", cred,
-	    VREAD);
+	error = extattr_check_cred(vp, attrnamespace, cred, VREAD);
 	if (error)
 		return (error);
 
@@ -1431,8 +1377,7 @@ ulfs_extattr_set(struct vnode *vp, int a
 	if (!ulfs_extattr_valid_attrname(attrnamespace, name))
 		return (EINVAL);
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VWRITE);
+	error = extattr_check_cred(vp, attrnamespace, cred, VWRITE);
 	if (error)
 		return (error);
 
@@ -1550,8 +1495,7 @@ ulfs_extattr_rm(struct vnode *vp, int at
 	if (!ulfs_extattr_valid_attrname(attrnamespace, name))
 		return (EINVAL);
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VWRITE);
+	error = extattr_check_cred(vp, attrnamespace, cred, VWRITE);
 	if (error)
 		return (error);
 
Index: sys/ufs/lfs/ulfs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/ulfs_lookup.c,v
retrieving revision 1.43
diff -u -p -p -u -r1.43 ulfs_lookup.c
--- sys/ufs/lfs/ulfs_lookup.c	4 Apr 2020 20:49:31 -0000	1.43
+++ sys/ufs/lfs/ulfs_lookup.c	15 May 2020 16:56:55 -0000
@@ -574,7 +574,7 @@ found:
 		 */
 		if (dp->i_mode & ISVTX) {
 			error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE,
-			    tdp, vdp, genfs_can_sticky(cred, dp->i_uid,
+			    tdp, vdp, genfs_can_sticky(vdp, cred, dp->i_uid,
 			    VTOI(tdp)->i_uid));
 			if (error) {
 				vrele(tdp);
Index: sys/ufs/lfs/ulfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/ulfs_vnops.c,v
retrieving revision 1.52
diff -u -p -p -u -r1.52 ulfs_vnops.c
--- sys/ufs/lfs/ulfs_vnops.c	28 Oct 2017 00:37:13 -0000	1.52
+++ sys/ufs/lfs/ulfs_vnops.c	15 May 2020 16:56:55 -0000
@@ -140,7 +140,7 @@ ulfs_open(void *v)
 }
 
 static int
-ulfs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
+ulfs_check_possible(struct vnode *vp, struct inode *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
@@ -152,7 +152,7 @@ ulfs_check_possible(struct vnode *vp, st
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VWRITE) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
@@ -180,20 +180,21 @@ ulfs_check_possible(struct vnode *vp, st
 	if ((ip->i_flags & SF_SNAPSHOT))
 		return (EPERM);
 	/* If immutable bit set, nobody gets to write it. */
-	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
+	if ((accmode & VWRITE) && (ip->i_flags & IMMUTABLE))
 		return (EPERM);
 
 	return 0;
 }
 
 static int
-ulfs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
+ulfs_check_permitted(struct vnode *vp, struct inode *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
-	    ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
-	    ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(
+	    vp, cred, ip->i_uid, ip->i_gid, ip->i_mode & ALLPERMS,
+	    NULL, accmode));
 }
 
 int
@@ -201,26 +202,26 @@ ulfs_access(void *v)
 {
 	struct vop_access_args /* {
 		struct vnode	*a_vp;
-		int		a_mode;
+		accmode_t	a_accmode;
 		kauth_cred_t	a_cred;
 	} */ *ap = v;
 	struct vnode	*vp;
 	struct inode	*ip;
-	mode_t		mode;
+	accmode_t	accmode;
 	int		error;
 
 	vp = ap->a_vp;
-	mode = ap->a_mode;
+	accmode = ap->a_accmode;
 
 	KASSERT(VOP_ISLOCKED(vp));
 
 	ip = VTOI(vp);
 
-	error = ulfs_check_possible(vp, ip, mode, ap->a_cred);
+	error = ulfs_check_possible(vp, ip, accmode, ap->a_cred);
 	if (error)
 		return error;
 
-	error = ulfs_check_permitted(vp, ip, mode, ap->a_cred);
+	error = ulfs_check_permitted(vp, ip, accmode, ap->a_cred);
 
 	return error;
 }
@@ -292,7 +293,7 @@ ulfs_setattr(void *v)
 		}
 
 		error = kauth_authorize_vnode(cred, action, vp, NULL,
-		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
+		    genfs_can_chflags(vp, cred, ip->i_uid,
 		    changing_sysflags));
 		if (error)
 			goto out;
@@ -371,7 +372,8 @@ ulfs_setattr(void *v)
 			goto out;
 		}
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
+		    NULL, genfs_can_chtimes(vp, cred, ip->i_uid,
+		    vap->va_vaflags));
 		if (error)
 			goto out;
 		if (vap->va_atime.tv_sec != VNOVAL)
@@ -424,7 +426,7 @@ ulfs_chmod(struct vnode *vp, int mode, k
 	ip = VTOI(vp);
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode));
 	if (error)
 		return (error);
 
@@ -462,7 +464,7 @@ ulfs_chown(struct vnode *vp, uid_t uid, 
 		gid = ip->i_gid;
 
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
+	    NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid));
 	if (error)
 		return (error);
 
Index: sys/ufs/mfs/mfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/mfs/mfs_vnops.c,v
retrieving revision 1.60
diff -u -p -p -u -r1.60 mfs_vnops.c
--- sys/ufs/mfs/mfs_vnops.c	13 Apr 2020 19:23:20 -0000	1.60
+++ sys/ufs/mfs/mfs_vnops.c	15 May 2020 16:56:55 -0000
@@ -64,6 +64,7 @@ const struct vnodeopv_entry_desc mfs_vno
 	{ &vop_open_desc, mfs_open },			/* open */
 	{ &vop_close_desc, mfs_close },			/* close */
 	{ &vop_access_desc, mfs_access },		/* access */
+	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
 	{ &vop_getattr_desc, mfs_getattr },		/* getattr */
 	{ &vop_setattr_desc, mfs_setattr },		/* setattr */
 	{ &vop_read_desc, mfs_read },			/* read */
Index: sys/ufs/ufs/README.acls
===================================================================
RCS file: sys/ufs/ufs/README.acls
diff -N sys/ufs/ufs/README.acls
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/ufs/ufs/README.acls	15 May 2020 16:56:55 -0000
@@ -0,0 +1,79 @@
+$FreeBSD: head/sys/ufs/ufs/README.acls 105456 2002-10-19 16:09:16Z rwatson $
+
+  UFS Access Control Lists Copyright
+
+The UFS Access Control Lists implementation is copyright Robert Watson,
+and is made available under a Berkeley-style license.
+
+  About UFS Access Control Lists (ACLs)
+
+Access control lists allow the association of fine-grained discretionary
+access control information with files and directories, extending the
+base UNIX permission model in a (mostly) compatible way.  This
+implementation largely follows the POSIX.1e model, and relies on the
+availability of extended attributes to store extended components of
+the ACL, while maintaining the base permission information in the inode.
+
+  Using UFS Access Control Lists (ACLs)
+
+Support for UFS access control lists may be enabled by adding:
+
+	options UFS_ACL
+
+to your kernel configuration.  As ACLs rely on the availability of extended
+attributes, your file systems must have support for extended attributes.
+For UFS2, this is supported natively, so no further configuration is
+necessary.  For UFS1, you must also enable the optional extended attributes
+support documented in README.extattr.  A summary of the instructions
+and ACL-specific information follows.
+
+To enable support for ACLs on a file system, the 'acls' mount flag
+must be set for the file system.  This may be set using the tunefs
+'-a' flag:
+
+	tunefs -a enable /dev/md0a
+
+Or by using the mount-time flag:
+
+	mount -o acls /dev/md0a /mnt
+
+The flag may also be set in /etc/fstab.  Note that mounting a file
+system previously configured for ACLs without ACL-support will result
+in incorrect application of discretionary protections.  Likewise,
+mounting an ACL-enabled file system without kernel support for ACLs
+will result in incorrect application of discretionary protections.  If
+the kernel is not configured for ACL support, a warning will be
+printed by the kernel at mount-time.  For reliability purposes, it
+is recommended that the superblock flag be used instead of the
+mount-time flag, as this will avoid re-mount isses with the root file
+system.  For reliability and performance reasons, the use of ACLs on
+UFS1 is discouraged; UFS2 extended attributes provide a more reliable
+storage mechanism for ACLs.
+
+Currently, support for ACLs on UFS1 requires the use of UFS1 EAs, which may
+be enabled by adding:
+
+	options UFS_EXTATTR
+
+to your kernel configuration file and rebuilding.  Because of filesystem
+mount atomicity requirements, it is also recommended that:
+
+	options UFS_EXTATTR_AUTOSTART
+
+be added to the kernel so as to support the atomic enabling of the
+required extended attributes with the filesystem mount operation.  To
+enable ACLs, two extended attributes must be available in the
+EXTATTR_NAMESPACE_SYSTEM namespace: "posix1e.acl_access", which holds
+the access ACL, and "posix1e.acl_default" which holds the default ACL
+for directories.  If you're using UFS1 Extended Attributes, the following
+commands may be used to create the necessary EA backing files for
+ACLs in the filesystem root of each filesystem.  In these examples,
+the root filesystem is used; see README.extattr for more details.
+
+  mkdir -p /.attribute/system
+  cd /.attribute/system
+  extattrctl initattr -p / 388 posix1e.acl_access
+  extattrctl initattr -p / 388 posix1e.acl_default
+
+On the next mount of the root filesystem, the attributes will be
+automatically started, and ACLs will be enabled.
Index: sys/ufs/ufs/acl.h
===================================================================
RCS file: sys/ufs/ufs/acl.h
diff -N sys/ufs/ufs/acl.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/ufs/ufs/acl.h	15 May 2020 16:56:55 -0000
@@ -0,0 +1,62 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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: head/sys/ufs/ufs/acl.h 326272 2017-11-27 15:23:17Z pfg $
+ */
+/*
+ * Developed by the TrustedBSD Project.
+ * Support for POSIX.1e access control lists.
+ */
+
+#ifndef _UFS_UFS_ACL_H_
+#define	_UFS_UFS_ACL_H_
+
+#ifdef _KERNEL
+
+struct inode;
+int	ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct lwp *l);
+int	ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct lwp *l, bool lock);
+int	ufs_setacl_posix1e(struct vnode *vp, int type, struct acl *aclp,
+    kauth_cred_t cred, struct lwp *l);
+void	ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl);
+void	ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip);
+
+#ifdef UFS_ACL
+int	ufs_getacl(void *);
+int	ufs_setacl(void *);
+int	ufs_aclcheck(void *);
+#else
+#define	ufs_getacl	genfs_eopnotsupp
+#define	ufs_setacl	genfs_eopnotsupp
+#define	ufs_aclcheck	genfs_eopnotsupp
+#endif
+
+#endif /* !_KERNEL */
+
+#endif /* !_UFS_UFS_ACL_H_ */
Index: sys/ufs/ufs/ufs_acl.c
===================================================================
RCS file: sys/ufs/ufs/ufs_acl.c
diff -N sys/ufs/ufs/ufs_acl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/ufs/ufs/ufs_acl.c	15 May 2020 16:56:55 -0000
@@ -0,0 +1,698 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999-2003 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ */
+
+/*
+ * Support for POSIX.1e access control lists: UFS-specific support functions.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/sys/ufs/ufs/ufs_acl.c 356669 2020-01-13 02:31:51Z mjg $");
+#endif
+__KERNEL_RCSID(0, "$NetBSD: ufs_wapbl.c,v 1.25 2019/12/22 19:47:35 ad Exp $");
+
+#if defined(_KERNEL_OPT) 
+#include "opt_ffs.h"
+#include "opt_quota.h"
+#include "opt_wapbl.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/wapbl.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/event.h>
+#include <sys/extattr.h>
+#include <sys/proc.h>
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/acl.h>
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/ufs_extern.h>
+#include <ufs/ufs/ufs_wapbl.h>
+
+#include <ufs/ffs/fs.h>
+
+#ifdef UFS_ACL
+
+/*
+ * Synchronize an ACL and an inode by copying over appropriate inode fields
+ * to the passed ACL.  Assumes an ACL that would satisfy acl_posix1e_check(),
+ * and may panic if not.
+ */
+void
+ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl)
+{
+	struct acl_entry	*acl_mask, *acl_group_obj;
+	int	i;
+
+	/*
+	 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK
+	 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is
+	 * present.
+	 */
+	acl_mask = NULL;
+	acl_group_obj = NULL;
+	for (i = 0; i < acl->acl_cnt; i++) {
+		switch (acl->acl_entry[i].ae_tag) {
+		case ACL_USER_OBJ:
+			acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
+			    ACL_USER_OBJ, ip->i_mode);
+			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+			break;
+	
+		case ACL_GROUP_OBJ:
+			acl_group_obj = &acl->acl_entry[i];
+			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+			break;
+
+		case ACL_OTHER:
+			acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
+			    ACL_OTHER, ip->i_mode);
+			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+			break;
+
+		case ACL_MASK:
+			acl_mask = &acl->acl_entry[i];
+			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+			break;
+
+		case ACL_USER:
+		case ACL_GROUP:
+			break;
+	
+		default:
+			panic("ufs_sync_acl_from_inode(): bad ae_tag");
+		}
+	}
+
+	if (acl_group_obj == NULL)
+		panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ");
+
+	if (acl_mask == NULL) {
+		/*
+		 * There is no ACL_MASK, so update ACL_GROUP_OBJ.
+		 */
+		acl_group_obj->ae_perm = acl_posix1e_mode_to_perm(
+		    ACL_GROUP_OBJ, ip->i_mode);
+	} else {
+		/*
+		 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ.
+		 */
+		acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ,
+		    ip->i_mode);
+	}
+}
+
+/*
+ * Calculate what the inode mode should look like based on an authoritative
+ * ACL for the inode.  Replace only the fields in the inode that the ACL
+ * can represent.
+ */
+void
+ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
+{
+
+	ip->i_mode &= ACL_PRESERVE_MASK;
+	ip->i_mode |= acl_posix1e_acl_to_mode(acl);
+	DIP_ASSIGN(ip, mode, ip->i_mode);
+}
+
+/*
+ * Retrieve NFSv4 ACL, skipping access checks.  Must be used in UFS code
+ * instead of VOP_GETACL() when we don't want to be restricted by the user
+ * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL
+ * or in ufs_vnops.c:ufs_accessx().
+ */
+int
+ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct lwp *l)
+{
+	int error;
+	size_t len;
+	struct inode *ip = VTOI(vp);
+
+	len = sizeof(*aclp);
+	bzero(aclp, len);
+
+	error = vn_extattr_get(vp, IO_NODELOCKED,
+	    NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, &len, aclp, l);
+	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
+	if (error == ENOATTR) {
+		/*
+		 * Legitimately no ACL set on object, purely
+		 * emulate it through the inode.
+		 */
+		acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid);
+
+		return (0);
+	}
+
+	if (error)
+		return (error);
+
+	if (len != sizeof(*aclp)) {
+		/*
+		 * A short (or long) read, meaning that for
+		 * some reason the ACL is corrupted.  Return
+		 * EPERM since the object DAC protections
+		 * are unsafe.
+		 */
+		printf("%s: Loaded invalid ACL ("
+		    "%zu bytes), inumber %ju on %s\n", __func__, len,
+		    (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt);
+
+		return (EPERM);
+	}
+
+	error = acl_nfs4_check(aclp, vp->v_type == VDIR);
+	if (error) {
+		printf("%s: Loaded invalid ACL "
+		    "(failed acl_nfs4_check), inumber %ju on %s\n", __func__,
+		    (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt);
+
+		return (EPERM);
+	}
+
+	return (0);
+}
+
+static int
+ufs_getacl_nfs4(struct vop_getacl_args *ap, struct lwp *l)
+{
+	int error;
+
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
+		return (EINVAL);
+
+	error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_cred);
+	if (error)
+		return (error);
+
+	error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, l);
+
+	return (error);
+}
+
+/*
+ * Read POSIX.1e ACL from an EA.  Return error if its not found
+ * or if any other error has occurred.
+ */
+static int
+ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp,
+    struct lwp *l)
+{
+	int error;
+	size_t len;
+	struct inode *ip = VTOI(vp);
+
+	len = sizeof(*old);
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		error = vn_extattr_get(vp, IO_NODELOCKED,
+		    POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+		    POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, old, l);
+		break;
+	case ACL_TYPE_DEFAULT:
+		if (vp->v_type != VDIR)
+			return (EINVAL);
+		error = vn_extattr_get(vp, IO_NODELOCKED,
+		    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+		    POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, old, l);
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	if (error != 0)
+		return (error);
+
+	if (len != sizeof(*old)) {
+		/*
+		 * A short (or long) read, meaning that for some reason
+		 * the ACL is corrupted.  Return EPERM since the object
+		 * DAC protections are unsafe.
+		 */
+		printf("%s: Loaded invalid ACL "
+		    "(len = %zu), inumber %ju on %s\n", __func__, len,
+		    (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt);
+		return (EPERM);
+	}
+
+	return (0);
+}
+
+/*
+ * Retrieve the ACL on a file.
+ *
+ * As part of the ACL is stored in the inode, and the rest in an EA,
+ * assemble both into a final ACL product.  Right now this is not done
+ * very efficiently.
+ */
+static int
+ufs_getacl_posix1e(struct vop_getacl_args *ap, struct lwp *l)
+{
+	struct inode *ip = VTOI(ap->a_vp);
+	int error;
+	struct oldacl *old;
+
+	/*
+	 * XXX: If ufs_getacl() should work on file systems not supporting
+	 * ACLs, remove this check.
+	 */
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0)
+		return (EINVAL);
+
+	old = kmem_zalloc(sizeof(*old), KM_SLEEP);
+
+	/*
+	 * Attempt to retrieve the ACL from the extended attributes.
+	 */
+	error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, l);
+	switch (error) {
+	/*
+	 * XXX: If ufs_getacl() should work on filesystems
+	 * without the EA configured, add case EOPNOTSUPP here.
+	 */
+	case ENOATTR:
+		switch (ap->a_type) {
+		case ACL_TYPE_ACCESS:
+			/*
+			 * Legitimately no ACL set on object, purely
+			 * emulate it through the inode.  These fields will
+			 * be updated when the ACL is synchronized with
+			 * the inode later.
+			 */
+			old->acl_cnt = 3;
+			old->acl_entry[0].ae_tag = ACL_USER_OBJ;
+			old->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
+			old->acl_entry[0].ae_perm = ACL_PERM_NONE;
+			old->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
+			old->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
+			old->acl_entry[1].ae_perm = ACL_PERM_NONE;
+			old->acl_entry[2].ae_tag = ACL_OTHER;
+			old->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
+			old->acl_entry[2].ae_perm = ACL_PERM_NONE;
+			break;
+
+		case ACL_TYPE_DEFAULT:
+			/*
+			 * Unlike ACL_TYPE_ACCESS, there is no relationship
+			 * between the inode contents and the ACL, and it is
+			 * therefore possible for the request for the ACL
+			 * to fail since the ACL is undefined.  In this
+			 * situation, return success and an empty ACL,
+			 * as required by POSIX.1e.
+			 */
+			old->acl_cnt = 0;
+			break;
+		}
+		/* FALLTHROUGH */
+	case 0:
+		error = acl_copy_oldacl_into_acl(old, ap->a_aclp);
+		if (error != 0)
+			break;
+
+		if (ap->a_type == ACL_TYPE_ACCESS)
+			ufs_sync_acl_from_inode(ip, ap->a_aclp);
+	default:
+		break;
+	}
+
+	kmem_free(old, sizeof(*old));
+	return (error);
+}
+
+int
+ufs_getacl(void *v)
+{
+	struct vop_getacl_args *ap = v;
+
+	if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_ACLS)) == 0)
+		return (EOPNOTSUPP);
+
+	if (ap->a_type == ACL_TYPE_NFS4)
+		return (ufs_getacl_nfs4(ap, curlwp));
+
+	return (ufs_getacl_posix1e(ap, curlwp));
+}
+
+/*
+ * Set NFSv4 ACL without doing any access checking.  This is required
+ * e.g. by the UFS code that implements ACL inheritance, or from
+ * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped
+ * in that case, and others are redundant.
+ */
+int
+ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp,
+    struct lwp *l, bool lock)
+{
+	int error;
+	mode_t mode;
+	struct inode *ip = VTOI(vp);
+
+	KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0);
+
+	if (acl_nfs4_is_trivial(aclp, ip->i_uid)) {
+		error = vn_extattr_rm(vp, IO_NODELOCKED,
+		    NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, l);
+		/*
+		 * An attempt to remove ACL from a file that didn't have
+		 * any extended entries is not an error.
+		 */
+		if (error == ENOATTR)
+			error = 0;
+
+	} else {
+		error = vn_extattr_set(vp, IO_NODELOCKED,
+		    NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME,
+		    sizeof(*aclp), aclp, l);
+	}
+
+	/*
+	 * Map lack of attribute definition in UFS_EXTATTR into lack of
+	 * support for ACLs on the filesystem.
+	 */
+	if (error == ENOATTR)
+		return (EOPNOTSUPP);
+
+	if (error)
+		return (error);
+
+	mode = ip->i_mode;
+
+	__acl_nfs4_sync_mode_from_acl(&mode, aclp);
+
+	if (lock && (error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0)
+		return error;
+
+	ip->i_mode &= ACL_PRESERVE_MASK;
+	ip->i_mode |= mode;
+	DIP_ASSIGN(ip, mode, ip->i_mode);
+	ip->i_flag |= IN_CHANGE;
+
+	KNOTE(&vp->v_klist, NOTE_REVOKE);
+
+	error = UFS_UPDATE(vp, NULL, NULL, 0);
+	if (lock)
+		UFS_WAPBL_END(vp->v_mount);
+
+	return (error);
+}
+
+static int
+ufs_setacl_nfs4(struct vop_setacl_args *ap, struct lwp *l)
+{
+	int error;
+	struct inode *ip = VTOI(ap->a_vp);
+
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
+		return (EINVAL);
+
+	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
+		return (EROFS);
+
+	if (ap->a_aclp == NULL)
+		return (EINVAL);
+
+	error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred);
+	if (error)
+		return (error);
+
+	/*
+	 * Authorize the ACL operation.
+	 */
+	if (ip->i_flags & (IMMUTABLE | APPEND))
+		return (EPERM);
+
+	/*
+	 * Must hold VWRITE_ACL or have appropriate privilege.
+	 */
+	if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, l->l_cred)))
+		return (error);
+
+	/*
+	 * With NFSv4 ACLs, chmod(2) may need to add additional entries.
+	 * Make sure it has enough room for that - splitting every entry
+	 * into two and appending "canonical six" entries at the end.
+	 */
+	if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
+		return (ENOSPC);
+
+	error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, l, true);
+
+	return (error);
+}
+
+/*
+ * Set the ACL on a file.
+ *
+ * As part of the ACL is stored in the inode, and the rest in an EA,
+ * this is necessarily non-atomic, and has complex authorization.
+ * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(),
+ * a fair number of different access checks may be required to go ahead
+ * with the operation at all.
+ */
+int
+ufs_setacl_posix1e(struct vnode *vp, int type, struct acl *aclp,
+    kauth_cred_t cred, struct lwp *l)
+{
+	struct inode *ip = VTOI(vp);
+	int error;
+	struct oldacl *old;
+
+	if ((vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0)
+		return (EINVAL);
+
+	/*
+	 * If this is a set operation rather than a delete operation,
+	 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is
+	 * valid for the target.  This will include a check on ap->a_type.
+	 */
+	if (aclp != NULL) {
+		/*
+		 * Set operation.
+		 */
+		error = VOP_ACLCHECK(vp, type, aclp, cred);
+		if (error != 0)
+			return (error);
+	} else {
+		/*
+		 * Delete operation.
+		 * POSIX.1e allows only deletion of the default ACL on a
+		 * directory (ACL_TYPE_DEFAULT).
+		 */
+		if (type != ACL_TYPE_DEFAULT)
+			return (EINVAL);
+		if (vp->v_type != VDIR)
+			return (ENOTDIR);
+	}
+
+	if (vp->v_mount->mnt_flag & MNT_RDONLY)
+		return (EROFS);
+
+	/*
+	 * Authorize the ACL operation.
+	 */
+	if (ip->i_flags & (IMMUTABLE | APPEND))
+		return (EPERM);
+
+	/*
+	 * Must hold VADMIN (be file owner) or have appropriate privilege.
+	 */
+	if ((error = VOP_ACCESS(vp, VADMIN, cred)))
+		return (error);
+
+	switch(type) {
+	case ACL_TYPE_ACCESS:
+		old = kmem_zalloc(sizeof(*old), KM_SLEEP);
+		error = acl_copy_acl_into_oldacl(aclp, old);
+		if (error == 0) {
+			error = vn_extattr_set(vp, IO_NODELOCKED,
+			    POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+			    POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old),
+			    old, l);
+		}
+		kmem_free(old, sizeof(*old));
+		break;
+
+	case ACL_TYPE_DEFAULT:
+		if (aclp == NULL) {
+			error = vn_extattr_rm(vp, IO_NODELOCKED,
+			    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+			    POSIX1E_ACL_DEFAULT_EXTATTR_NAME, l);
+			/*
+			 * Attempting to delete a non-present default ACL
+			 * will return success for portability purposes.
+			 * (TRIX)
+			 *
+			 * XXX: Note that since we can't distinguish
+			 * "that EA is not supported" from "that EA is not
+			 * defined", the success case here overlaps the
+			 * the ENOATTR->EOPNOTSUPP case below.
+		 	 */
+			if (error == ENOATTR)
+				error = 0;
+		} else {
+			old = kmem_zalloc(sizeof(*old), KM_SLEEP);
+			error = acl_copy_acl_into_oldacl(aclp, old);
+			if (error == 0) {
+				error = vn_extattr_set(vp, IO_NODELOCKED,
+				    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+				    POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
+				    sizeof(*old), (char *) old, l);
+			}
+			kmem_free(old, sizeof(*old));
+		}
+		break;
+
+	default:
+		error = EINVAL;
+	}
+	/*
+	 * Map lack of attribute definition in UFS_EXTATTR into lack of
+	 * support for ACLs on the filesystem.
+	 */
+	if (error == ENOATTR)
+		return (EOPNOTSUPP);
+	if (error != 0)
+		return (error);
+
+	if (type == ACL_TYPE_ACCESS) {
+		/*
+		 * Now that the EA is successfully updated, update the
+		 * inode and mark it as changed.
+		 */
+		if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0)
+			return error;
+
+		ufs_sync_inode_from_acl(aclp, ip);
+		ip->i_flag |= IN_CHANGE;
+		error = UFS_UPDATE(vp, NULL, NULL, 0);
+
+		UFS_WAPBL_END(vp->v_mount);
+	}
+
+	KNOTE(&vp->v_klist, NOTE_ATTRIB);
+	return (error);
+}
+
+int
+ufs_setacl(void *v)
+{
+	struct vop_setacl_args *ap = v;
+	if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_ACLS)) == 0)
+		return (EOPNOTSUPP);
+
+	if (ap->a_type == ACL_TYPE_NFS4)
+		return ufs_setacl_nfs4(ap, curlwp);
+
+	return ufs_setacl_posix1e(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred,
+	    curlwp);
+}
+
+static int
+ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap, struct lwp *l)
+{
+	int is_directory = 0;
+
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
+		return (EINVAL);
+
+	/*
+	 * With NFSv4 ACLs, chmod(2) may need to add additional entries.
+	 * Make sure it has enough room for that - splitting every entry
+	 * into two and appending "canonical six" entries at the end.
+	 */
+	if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
+		return (ENOSPC);
+
+	if (ap->a_vp->v_type == VDIR)
+		is_directory = 1;
+
+	return (acl_nfs4_check(ap->a_aclp, is_directory));
+}
+
+static int
+ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap, struct lwp *l)
+{
+
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0)
+		return (EINVAL);
+
+	/*
+	 * Verify we understand this type of ACL, and that it applies
+	 * to this kind of object.
+	 * Rely on the acl_posix1e_check() routine to verify the contents.
+	 */
+	switch(ap->a_type) {
+	case ACL_TYPE_ACCESS:
+		break;
+
+	case ACL_TYPE_DEFAULT:
+		if (ap->a_vp->v_type != VDIR)
+			return (EINVAL);
+		break;
+
+	default:
+		return (EINVAL);
+	}
+
+	if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES)
+		return (EINVAL);
+
+	return (acl_posix1e_check(ap->a_aclp));
+}
+
+/*
+ * Check the validity of an ACL for a file.
+ */
+int
+ufs_aclcheck(void *v)
+{
+	struct vop_aclcheck_args *ap = v;
+
+	if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_ACLS)) == 0)
+		return (EOPNOTSUPP);
+
+	if (ap->a_type == ACL_TYPE_NFS4)
+		return ufs_aclcheck_nfs4(ap, curlwp);
+
+	return ufs_aclcheck_posix1e(ap, curlwp);
+}
+
+#endif /* !UFS_ACL */
Index: sys/ufs/ufs/ufs_extattr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extattr.c,v
retrieving revision 1.51
diff -u -p -p -u -r1.51 ufs_extattr.c
--- sys/ufs/ufs/ufs_extattr.c	17 Jan 2020 20:08:10 -0000	1.51
+++ sys/ufs/ufs/ufs_extattr.c	15 May 2020 16:56:55 -0000
@@ -107,57 +107,6 @@ static int	ufs_extattr_get_header(struct
 		    struct ufs_extattr_list_entry *, 
 		    struct ufs_extattr_header *, off_t *);
 
-/*
- * Convert a FreeBSD extended attribute and namespace to a consistent string
- * representation.
- *
- * The returned value, if not NULL, is guaranteed to be an allocated object
- * of its size as returned by strlen() + 1 and must be freed by the caller.
- */
-static char *
-from_freebsd_extattr(int attrnamespace, const char *attrname)
-{
-	const char *namespace;
-	char *attr;
-	size_t len;
-
-	if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
-		namespace = "system";
-	else if (attrnamespace == EXTATTR_NAMESPACE_USER)
-		namespace = "user";
-	else
-		return NULL;
-
-	/* <namespace>.<attrname>\0 */
-	len = strlen(namespace) + 1 + strlen(attrname) + 1;
-
-	attr = kmem_alloc(len, KM_SLEEP);
-
-	snprintf(attr, len, "%s.%s", namespace, attrname);
-
-	return attr;
-}
-
-/*
- * Internal wrapper around a conversion-check-free sequence.
- */
-static int
-internal_extattr_check_cred(vnode_t *vp, int attrnamespace, const char *name,
-    kauth_cred_t cred, int access_mode)
-{
-	char *attr;
-	int error;
-
-	attr = from_freebsd_extattr(attrnamespace, name);
-	if (attr == NULL)
-		return EINVAL;
-
-	error = extattr_check_cred(vp, attr, cred, access_mode);
-
-	kmem_free(attr, strlen(attr) + 1);
-
-	return error;
-}
 
 /*
  * Per-FS attribute lock protecting attribute operations.
@@ -1130,8 +1079,7 @@ ufs_extattr_get(struct vnode *vp, int at
 	if (strlen(name) == 0)
 		return EINVAL;
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VREAD);
+	error = extattr_check_cred(vp, attrnamespace, cred, VREAD);
 	if (error)
 		return error;
 
@@ -1249,8 +1197,7 @@ ufs_extattr_list(struct vnode *vp, int a
 	 * XXX: We can move this inside the loop and iterate on individual
 	 *	attributes.
 	 */
-	error = internal_extattr_check_cred(vp, attrnamespace, "", cred,
-	    VREAD);
+	error = extattr_check_cred(vp, attrnamespace, cred, VREAD);
 	if (error)
 		return error;
 
@@ -1420,8 +1367,7 @@ ufs_extattr_set(struct vnode *vp, int at
 	if (!ufs_extattr_valid_attrname(attrnamespace, name))
 		return EINVAL;
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VWRITE);
+	error = extattr_check_cred(vp, attrnamespace, cred, VWRITE);
 	if (error)
 		return error;
 
@@ -1539,8 +1485,7 @@ ufs_extattr_rm(struct vnode *vp, int att
 	if (!ufs_extattr_valid_attrname(attrnamespace, name))
 		return EINVAL;
 
-	error = internal_extattr_check_cred(vp, attrnamespace, name, cred,
-	    VWRITE);
+	error = extattr_check_cred(vp, attrnamespace, cred, VWRITE);
 	if (error)
 		return error;
 
Index: sys/ufs/ufs/ufs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extern.h,v
retrieving revision 1.85
diff -u -p -p -u -r1.85 ufs_extern.h
--- sys/ufs/ufs/ufs_extern.h	18 Apr 2020 19:18:34 -0000	1.85
+++ sys/ufs/ufs/ufs_extern.h	15 May 2020 16:56:55 -0000
@@ -61,7 +61,7 @@ extern pool_cache_t ufs_direct_cache;	/*
 
 __BEGIN_DECLS
 #define	ufs_abortop	genfs_abortop
-int	ufs_access(void *);
+int	ufs_accessx(void *);
 int	ufs_advlock(void *);
 int	ufs_bmap(void *);
 int	ufs_close(void *);
Index: sys/ufs/ufs/ufs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_lookup.c,v
retrieving revision 1.152
diff -u -p -p -u -r1.152 ufs_lookup.c
--- sys/ufs/ufs/ufs_lookup.c	4 Apr 2020 20:49:31 -0000	1.152
+++ sys/ufs/ufs/ufs_lookup.c	15 May 2020 16:56:55 -0000
@@ -211,6 +211,38 @@ ufs_can_delete(struct vnode *tdp, struct
     kauth_cred_t cred)
 {
 	int error;
+
+#ifdef UFS_ACL
+	/*
+	 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
+	 *
+	 * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD
+	 */
+
+	/*
+	 * XXX: Is this check required?
+	 */
+	error = VOP_ACCESS(vdp, VEXEC, cred);
+	if (error)
+		goto out;
+
+#if 0
+	/* Moved to ufs_remove, ufs_rmdir because they hold the lock */
+	error = VOP_ACCESSX(tdp, VDELETE, cred);
+	if (error == 0)
+		return (0);
+#endif
+
+	error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred);
+	if (error == 0)
+		return (0);
+
+	error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred);
+	if (error)
+		goto out;
+
+#endif /* !UFS_ACL */
+
 	/*
 	 * Write access to directory required to delete files.
 	 */
@@ -228,7 +260,7 @@ ufs_can_delete(struct vnode *tdp, struct
 	 * implements append-only directories.
 	 */
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, tdp, vdp,
-	    genfs_can_sticky(cred, ip->i_uid, VTOI(tdp)->i_uid));
+	    genfs_can_sticky(vdp, cred, ip->i_uid, VTOI(tdp)->i_uid));
 	if (error) {
 		error = EPERM;	// Why override?
 		goto out;
@@ -590,7 +622,10 @@ notfound:
 		 * Access for write is interpreted as allowing
 		 * creation of files in the directory.
 		 */
-		error = VOP_ACCESS(vdp, VWRITE, cred);
+		if (flags & WILLBEDIR)
+			error = VOP_ACCESS(vdp, VWRITE | VAPPEND, cred);
+		else
+			error = VOP_ACCESS(vdp, VWRITE, cred);
 		if (error)
 			goto out;
 		error = slot_estimate(&slot, dirblksiz, nameiop,
@@ -675,7 +710,11 @@ found:
 	 * regular file, or empty directory.
 	 */
 	if (nameiop == RENAME && (flags & ISLASTCN)) {
-		if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0)
+		if (flags & WILLBEDIR)
+			error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred);
+		else
+			error = VOP_ACCESS(vdp, VWRITE, cred);
+		if (error)
 			goto out;
 		/*
 		 * Careful about locking second inode.
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.253
diff -u -p -p -u -r1.253 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c	12 May 2020 23:17:41 -0000	1.253
+++ sys/ufs/ufs/ufs_vnops.c	15 May 2020 16:56:55 -0000
@@ -95,6 +95,7 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,
 #include <miscfs/fifofs/fifo.h>
 #include <miscfs/genfs/genfs.h>
 
+#include <ufs/ufs/acl.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/ufsmount.h>
@@ -256,7 +257,7 @@ ufs_close(void *v)
 }
 
 static int
-ufs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
+ufs_check_possible(struct vnode *vp, struct inode *ip, accmode_t accmode,
     kauth_cred_t cred)
 {
 #if defined(QUOTA) || defined(QUOTA2)
@@ -268,13 +269,13 @@ ufs_check_possible(struct vnode *vp, str
 	 * unless the file is a socket, fifo, or a block or
 	 * character device resident on the file system.
 	 */
-	if (mode & VWRITE) {
+	if (accmode & VMODIFY_PERMS) {
 		switch (vp->v_type) {
 		case VDIR:
 		case VLNK:
 		case VREG:
 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
-				return (EROFS);
+				return EROFS;
 #if defined(QUOTA) || defined(QUOTA2)
 			error = chkdq(ip, 0, cred, 0);
 			if (error != 0)
@@ -294,48 +295,96 @@ ufs_check_possible(struct vnode *vp, str
 
 	/* If it is a snapshot, nobody gets access to it. */
 	if ((ip->i_flags & SF_SNAPSHOT))
-		return (EPERM);
-	/* If immutable bit set, nobody gets to write it. */
-	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
-		return (EPERM);
+		return EPERM;
+	/*
+	 * If immutable bit set, nobody gets to write it.  "& ~VADMIN_PERMS"
+	 * permits the owner of the file to remove the IMMUTABLE flag.
+	 */
+	if ((accmode & (VMODIFY_PERMS & ~VADMIN_PERMS)) &&
+	    (ip->i_flags & IMMUTABLE))
+		return EPERM;
 
 	return 0;
 }
 
 static int
-ufs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
-    kauth_cred_t cred)
+ufs_check_permitted(struct vnode *vp, struct inode *ip,
+    struct acl *acl, accmode_t accmode, kauth_cred_t cred,
+    int (*func)(struct vnode *, kauth_cred_t, uid_t, gid_t, mode_t,
+    struct acl *, accmode_t))
 {
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
-	    ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
-	    ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
+	    vp->v_type, ip->i_mode & ALLPERMS), vp, NULL, (*func)(vp, cred,
+	    ip->i_uid, ip->i_gid, ip->i_mode & ALLPERMS, acl, accmode));
 }
 
 int
-ufs_access(void *v)
+ufs_accessx(void *v)
 {
-	struct vop_access_args /* {
-		struct vnode	*a_vp;
-		int		a_mode;
-		kauth_cred_t	a_cred;
+	struct vop_accessx_args /* {
+		struct vnode *a_vp;
+		accmode_t a_accmode;
+		kauth_cred_t a_cred;
 	} */ *ap = v;
-	struct vnode	*vp;
-	struct inode	*ip;
-	mode_t		mode;
-	int		error;
-
-	vp = ap->a_vp;
-	ip = VTOI(vp);
-	mode = ap->a_mode;
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	accmode_t accmode = ap->a_accmode;
+	int error;
+#ifdef UFS_ACL
+	struct acl *acl;
+	acl_type_t type;
+#endif
 
-	error = ufs_check_possible(vp, ip, mode, ap->a_cred);
+	error = ufs_check_possible(vp, ip, accmode, ap->a_cred);
 	if (error)
 		return error;
 
-	error = ufs_check_permitted(vp, ip, mode, ap->a_cred);
+#ifdef UFS_ACL
+	if ((vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_ACLS)) != 0) {
+		if (vp->v_mount->mnt_flag & MNT_ACLS)
+			type = ACL_TYPE_NFS4;
+		else
+			type = ACL_TYPE_ACCESS;
 
-	return error;
+		acl = acl_alloc(KM_SLEEP);
+		if (type == ACL_TYPE_NFS4)
+			error = ufs_getacl_nfs4_internal(vp, acl, curlwp);
+		else
+			error = VOP_GETACL(vp, type, acl, ap->a_cred);
+		if (!error) {
+			vp->v_vflag |= VV_HASACL;
+			if (type == ACL_TYPE_NFS4) {
+				error = ufs_check_permitted(vp,
+				    ip, acl, accmode, ap->a_cred,
+				    genfs_can_access_acl_nfs4);
+			} else {
+				error = vfs_unixify_accmode(&accmode);
+				if (error == 0)
+					error = ufs_check_permitted(vp,
+					    ip, acl, accmode, ap->a_cred,
+					    genfs_can_access_acl_posix1e);
+			}
+			acl_free(acl);
+			return error;
+		}
+		vp->v_vflag &= ~VV_HASACL;
+		if (error != EOPNOTSUPP)
+			printf("%s: Error retrieving ACL: %d\n",
+			    __func__, error);
+		/*
+		 * XXX: Fall back until debugged.  Should
+		 * eventually possibly log an error, and return
+		 * EPERM for safety.
+		 */
+		acl_free(acl);
+	}
+#endif /* !UFS_ACL */
+	error = vfs_unixify_accmode(&accmode);
+	if (error)
+		return error;
+	return ufs_check_permitted(vp, ip,
+	    NULL, accmode, ap->a_cred, genfs_can_access);
 }
 
 /* ARGSUSED */
@@ -486,8 +535,7 @@ ufs_setattr(void *v)
 		}
 
 		error = kauth_authorize_vnode(cred, action, vp, NULL,
-		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
-		    changing_sysflags));
+		    genfs_can_chflags(vp, cred, ip->i_uid, changing_sysflags));
 		if (error)
 			goto out;
 
@@ -577,7 +625,8 @@ ufs_setattr(void *v)
 			goto out;
 		}
 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
-		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
+		    NULL, genfs_can_chtimes(vp, cred, ip->i_uid,
+		    vap->va_vaflags));
 		if (error)
 			goto out;
 		error = UFS_WAPBL_BEGIN(vp->v_mount);
@@ -621,10 +670,37 @@ ufs_setattr(void *v)
 	}
 	VN_KNOTE(vp, NOTE_ATTRIB);
 out:
-	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, true);
+	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid,
+	    !(vp->v_vflag & VV_HASACL));
 	return (error);
 }
 
+#ifdef UFS_ACL
+static int
+ufs_update_nfs4_acl_after_mode_change(struct vnode *vp, int mode,
+    int file_owner_id, kauth_cred_t cred, struct lwp *l)
+{
+	int error;
+	struct acl *aclp;
+
+	aclp = acl_alloc(KM_SLEEP);
+	error = ufs_getacl_nfs4_internal(vp, aclp, l);
+	/*
+	 * We don't have to handle EOPNOTSUPP here, as the filesystem claims
+	 * it supports ACLs.
+	 */
+	if (error)
+		goto out;
+
+	acl_nfs4_sync_acl_from_mode(aclp, mode, file_owner_id);
+	error = ufs_setacl_nfs4_internal(vp, aclp, l, false);
+
+out:
+	acl_free(aclp);
+	return (error);
+}
+#endif /* UFS_ACL */
+
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
@@ -639,17 +715,35 @@ ufs_chmod(struct vnode *vp, int mode, ka
 
 	ip = VTOI(vp);
 
+#ifdef UFS_ACL
+	/*
+	 * To modify the permissions on a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0)
+		return error;
+#endif
+
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
-	    NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode));
+	    NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode));
 	if (error)
 		return (error);
 
+#ifdef UFS_ACL
+	if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) {
+		error = ufs_update_nfs4_acl_after_mode_change(vp, mode,
+		    ip->i_uid, cred, l);
+		if (error)
+			return error;
+	}
+#endif
 	ip->i_mode &= ~ALLPERMS;
 	ip->i_mode |= (mode & ALLPERMS);
 	ip->i_flag |= IN_CHANGE;
 	DIP_ASSIGN(ip, mode, ip->i_mode);
 	UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
-	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, true);
+	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid,
+	    !(vp->v_vflag & VV_HASACL));
 	return (0);
 }
 
@@ -676,8 +770,17 @@ ufs_chown(struct vnode *vp, uid_t uid, g
 	if (gid == (gid_t)VNOVAL)
 		gid = ip->i_gid;
 
+#ifdef UFS_ACL
+	/*
+	 * To modify the ownership of a file, must possess VADMIN for that
+	 * file.
+	 */
+	if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0)
+		return error;
+#endif
+
 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
-	    NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
+	    NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid));
 	if (error)
 		return (error);
 
@@ -710,7 +813,8 @@ ufs_chown(struct vnode *vp, uid_t uid, g
 #endif /* QUOTA || QUOTA2 */
 	ip->i_flag |= IN_CHANGE;
 	UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
-	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid, true);
+	cache_enter_id(vp, ip->i_mode, ip->i_uid, ip->i_gid,
+	    !(vp->v_vflag & VV_HASACL));
 	return (0);
 }
 
@@ -734,6 +838,17 @@ ufs_remove(void *v)
 	mp = dvp->v_mount;
 	KASSERT(mp == vp->v_mount); /* XXX Not stable without lock.  */
 
+#ifdef UFS_ACL
+#ifdef notyet
+	/* We don't do this because if the filesystem is mounted without ACLs
+	 * this goes through vfs_unixify_accmode() and we get EPERM.
+	 */
+	error = VOP_ACCESSX(vp, VDELETE, ap->a_cnp->cn_cred);
+	if (error)
+		goto err;
+#endif
+#endif
+
 	/* XXX should handle this material another way */
 	ulr = &VTOI(dvp)->i_crap;
 	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
@@ -751,6 +866,9 @@ ufs_remove(void *v)
 	}
 	VN_KNOTE(vp, NOTE_DELETE);
 	VN_KNOTE(dvp, NOTE_WRITE);
+#ifdef notyet
+err:
+#endif
 	if (dvp == vp)
 		vrele(vp);
 	else
@@ -906,6 +1024,193 @@ ufs_whiteout(void *v)
 	return (error);
 }
 
+#ifdef UFS_ACL
+static int
+ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp,
+    mode_t dmode, kauth_cred_t cred, struct lwp *l)
+{
+	int error;
+	struct inode *ip = VTOI(tvp);
+	struct acl *dacl, *acl;
+
+	acl = acl_alloc(KM_SLEEP);
+	dacl = acl_alloc(KM_SLEEP);
+
+	/*
+	 * Retrieve default ACL from parent, if any.
+	 */
+	error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred);
+	switch (error) {
+	case 0:
+		/*
+		 * Retrieved a default ACL, so merge mode and ACL if
+		 * necessary.  If the ACL is empty, fall through to
+		 * the "not defined or available" case.
+		 */
+		if (acl->acl_cnt != 0) {
+			dmode = acl_posix1e_newfilemode(dmode, acl);
+			ip->i_mode = dmode;
+			DIP_ASSIGN(ip, mode, dmode);
+			*dacl = *acl;
+			ufs_sync_acl_from_inode(ip, acl);
+			break;
+		}
+		/* FALLTHROUGH */
+
+	case EOPNOTSUPP:
+		/*
+		 * Just use the mode as-is.
+		 */
+		ip->i_mode = dmode;
+		DIP_ASSIGN(ip, mode, dmode);
+		error = 0;
+		goto out;
+	
+	default:
+		goto out;
+	}
+
+	/*
+	 * XXX: If we abort now, will Soft Updates notify the extattr
+	 * code that the EAs for the file need to be released?
+	 */
+	UFS_WAPBL_END(tvp->v_mount);
+	error = ufs_setacl_posix1e(tvp, ACL_TYPE_ACCESS, acl, cred, l);
+	if (error == 0)
+		error = ufs_setacl_posix1e(tvp, ACL_TYPE_DEFAULT, dacl, cred,
+		    l);
+	UFS_WAPBL_BEGIN(tvp->v_mount);
+	switch (error) {
+	case 0:
+		break;
+
+	case EOPNOTSUPP:
+		/*
+		 * XXX: This should not happen, as EOPNOTSUPP above
+		 * was supposed to free acl.
+		 */
+		printf("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()\n");
+		/*
+		panic("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()");
+		 */
+		break;
+
+	default:
+		goto out;
+	}
+
+out:
+	acl_free(acl);
+	acl_free(dacl);
+
+	return (error);
+}
+
+static int
+ufs_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp,
+    mode_t mode, kauth_cred_t cred, struct lwp *l)
+{
+	int error;
+	struct inode *ip = VTOI(tvp);
+	struct acl *acl;
+
+	acl = acl_alloc(KM_SLEEP);
+
+	/*
+	 * Retrieve default ACL for parent, if any.
+	 */
+	error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred);
+	switch (error) {
+	case 0:
+		/*
+		 * Retrieved a default ACL, so merge mode and ACL if
+		 * necessary.
+		 */
+		if (acl->acl_cnt != 0) {
+			/*
+			 * Two possible ways for default ACL to not
+			 * be present.  First, the EA can be
+			 * undefined, or second, the default ACL can
+			 * be blank.  If it's blank, fall through to
+			 * the it's not defined case.
+			 */
+			mode = acl_posix1e_newfilemode(mode, acl);
+			ip->i_mode = mode;
+			DIP_ASSIGN(ip, mode, mode);
+			ufs_sync_acl_from_inode(ip, acl);
+			break;
+		}
+		/* FALLTHROUGH */
+
+	case EOPNOTSUPP:
+		/*
+		 * Just use the mode as-is.
+		 */
+		ip->i_mode = mode;
+		DIP_ASSIGN(ip, mode, mode);
+		error = 0;
+		goto out;
+
+	default:
+		goto out;
+	}
+
+	UFS_WAPBL_END(tvp->v_mount);
+	/*
+	 * XXX: If we abort now, will Soft Updates notify the extattr
+	 * code that the EAs for the file need to be released?
+	 */
+	error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred);
+	UFS_WAPBL_BEGIN(tvp->v_mount);
+	switch (error) {
+	case 0:
+		break;
+
+	case EOPNOTSUPP:
+		/*
+		 * XXX: This should not happen, as EOPNOTSUPP above was
+		 * supposed to free acl.
+		 */
+		printf("%s: VOP_GETACL() but no VOP_SETACL()\n", __func__);
+		/* panic("%s: VOP_GETACL() but no VOP_SETACL()", __func__); */
+		break;
+
+	default:
+		goto out;
+	}
+
+out:
+	acl_free(acl);
+
+	return (error);
+}
+
+static int
+ufs_do_nfs4_acl_inheritance(struct vnode *dvp, struct vnode *tvp,
+    mode_t child_mode, kauth_cred_t cred, struct lwp *l)
+{
+	int error;
+	struct acl *parent_aclp, *child_aclp;
+
+	parent_aclp = acl_alloc(KM_SLEEP);
+	child_aclp = acl_alloc(KM_SLEEP);
+
+	error = ufs_getacl_nfs4_internal(dvp, parent_aclp, l);
+	if (error)
+		goto out;
+	acl_nfs4_compute_inherited_acl(parent_aclp, child_aclp,
+	    child_mode, VTOI(tvp)->i_uid, tvp->v_type == VDIR);
+	error = ufs_setacl_nfs4_internal(tvp, child_aclp, l, false);
+	if (error)
+		goto out;
+out:
+	acl_free(parent_aclp);
+	acl_free(child_aclp);
+
+	return (error);
+}
+#endif
+
 int
 ufs_mkdir(void *v)
 {
@@ -979,6 +1284,23 @@ ufs_mkdir(void *v)
 	if ((error = UFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
 		goto bad;
 
+#ifdef UFS_ACL
+	mode_t dmode = (vap->va_mode & 0777) | IFDIR;
+	struct lwp *l = curlwp;
+	if (dvp->v_mount->mnt_flag & MNT_POSIX1EACLS) {
+
+		error = ufs_do_posix1e_acl_inheritance_dir(dvp, tvp, dmode,
+		    cnp->cn_cred, l);
+		if (error)
+			goto bad;
+	} else if (dvp->v_mount->mnt_flag & MNT_ACLS) {
+		error = ufs_do_nfs4_acl_inheritance(dvp, tvp, dmode,
+		    cnp->cn_cred, l);
+		if (error)
+			goto bad;
+	}
+#endif /* !UFS_ACL */
+
 	/*
 	 * Initialize directory with "." and ".." from static template.
 	 */
@@ -1071,6 +1393,17 @@ ufs_rmdir(void *v)
 	ip = VTOI(vp);
 	dp = VTOI(dvp);
 
+#ifdef UFS_ACL
+#ifdef notyet
+	/* We don't do this because if the filesystem is mounted without ACLs
+	 * this goes through vfs_unixify_accmode() and we get EPERM.
+	 */
+	error = VOP_ACCESSX(vp, VDELETE, cnp->cn_cred);
+	if (error)
+		goto err;
+#endif
+#endif
+
 	/* XXX should handle this material another way */
 	ulr = &dp->i_crap;
 	UFS_CHECK_CRAPCOUNTER(dp);
@@ -1079,11 +1412,8 @@ ufs_rmdir(void *v)
 	 * No rmdir "." or of mounted directories please.
 	 */
 	if (dp == ip || vp->v_mountedhere != NULL) {
-		if (dp == ip)
-			vrele(vp);
-		else
-			vput(vp);
-		return (EINVAL);
+		error = EINVAL;
+		goto err;
 	}
 
 	/*
@@ -1144,7 +1474,13 @@ ufs_rmdir(void *v)
  out:
 	VN_KNOTE(vp, NOTE_DELETE);
 	vput(vp);
-	return (error);
+	return error;
+ err:
+	if (dp == ip)
+		vrele(vp);
+	else
+		vput(vp);
+	return error;
 }
 
 /*
@@ -1766,6 +2102,30 @@ ufs_pathconf(void *v)
 	case _PC_NO_TRUNC:
 		*ap->a_retval = 1;
 		return (0);
+#ifdef UFS_ACL
+	case _PC_ACL_EXTENDED:
+		if (ap->a_vp->v_mount->mnt_flag & MNT_POSIX1EACLS)
+			*ap->a_retval = 1;
+		else
+			*ap->a_retval = 0;
+		return 0;
+	case _PC_ACL_NFS4:
+		if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
+			*ap->a_retval = 1;
+		else
+			*ap->a_retval = 0;
+		return 0;
+#endif
+	case _PC_ACL_PATH_MAX:
+#ifdef UFS_ACL
+		if (ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_ACLS))
+			*ap->a_retval = ACL_MAX_ENTRIES;
+		else
+			*ap->a_retval = 3;
+#else
+		*ap->a_retval = 3;
+#endif
+		return 0;
 	case _PC_SYNC_IO:
 		*ap->a_retval = 1;
 		return (0);
@@ -1890,8 +2250,9 @@ ufs_makeinode(struct vattr *vap, struct 
 
 	/* Authorize setting SGID if needed. */
 	if (ip->i_mode & ISGID) {
-		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
-		    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
+		error = kauth_authorize_vnode(cnp->cn_cred,
+		    KAUTH_VNODE_WRITE_SECURITY,
+		    tvp, NULL, genfs_can_chmod(tvp, cnp->cn_cred, ip->i_uid,
 		    ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode)));
 		if (error) {
 			ip->i_mode &= ~ISGID;
@@ -1909,6 +2270,20 @@ ufs_makeinode(struct vattr *vap, struct 
 	 */
 	if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
 		goto bad;
+#ifdef UFS_ACL
+	struct lwp *l = curlwp;
+	if (dvp->v_mount->mnt_flag & MNT_POSIX1EACLS) {
+		error = ufs_do_posix1e_acl_inheritance_file(dvp, tvp,
+		    ip->i_mode, cnp->cn_cred, l);
+		if (error)
+			goto bad;
+	} else if (dvp->v_mount->mnt_flag & MNT_ACLS) {
+		error = ufs_do_nfs4_acl_inheritance(dvp, tvp, ip->i_mode,
+		    cnp->cn_cred, l);
+		if (error)
+			goto bad;
+	}
+#endif /* !UFS_ACL */
 	newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
 	ufs_makedirentry(ip, cnp, newdir);
 	error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, NULL);