Index: bin/Makefile
===================================================================
RCS file: /cvsroot/src/bin/Makefile,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 Makefile
--- bin/Makefile	31 Dec 2007 15:31:24 -0000	1.22
+++ bin/Makefile	24 Apr 2020 14:00:06 -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 -u -p -r1.59 cp.c
--- bin/cp/cp.c	5 Mar 2016 19:48:55 -0000	1.59
+++ bin/cp/cp.c	24 Apr 2020 14:00:06 -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 -u -p -r1.17 extern.h
--- bin/cp/extern.h	4 Jan 2012 15:58:37 -0000	1.17
+++ bin/cp/extern.h	24 Apr 2020 14:00:06 -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 -u -p -r1.47 utils.c
--- bin/cp/utils.c	23 Sep 2019 18:01:09 -0000	1.47
+++ bin/cp/utils.c	24 Apr 2020 14:00:06 -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	24 Apr 2020 14:00:06 -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	24 Apr 2020 14:00:06 -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	24 Apr 2020 14:00:06 -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 -u -p -r1.80 ls.1
--- bin/ls/ls.1	3 Jul 2017 21:33:23 -0000	1.80
+++ bin/ls/ls.1	24 Apr 2020 14:00:06 -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 -u -p -r1.55 print.c
--- bin/ls/print.c	10 May 2014 09:39:18 -0000	1.55
+++ bin/ls/print.c	24 Apr 2020 14:00:06 -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 (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: distrib/sets/lists/base/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/mi,v
retrieving revision 1.1240
diff -u -p -u -p -r1.1240 mi
--- distrib/sets/lists/base/mi	14 Apr 2020 03:16:26 -0000	1.1240
+++ distrib/sets/lists/base/mi	24 Apr 2020 14:00:07 -0000
@@ -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/base/shl.mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/shl.mi,v
retrieving revision 1.884
diff -u -p -u -p -r1.884 shl.mi
--- distrib/sets/lists/base/shl.mi	4 Apr 2020 19:26:51 -0000	1.884
+++ distrib/sets/lists/base/shl.mi	24 Apr 2020 14:00:07 -0000
@@ -21,7 +21,7 @@
 ./lib/libblacklist.so.0.0			base-sys-shlib		dynamicroot
 ./lib/libc.so					base-sys-shlib		dynamicroot
 ./lib/libc.so.12				base-sys-shlib		dynamicroot
-./lib/libc.so.12.215				base-sys-shlib		dynamicroot
+./lib/libc.so.12.216				base-sys-shlib		dynamicroot
 ./lib/libcrypt.so				base-sys-shlib		dynamicroot
 ./lib/libcrypt.so.1				base-sys-shlib		dynamicroot
 ./lib/libcrypt.so.1.0				base-sys-shlib		dynamicroot
@@ -249,7 +249,7 @@
 ./usr/lib/libc++.so.1.0				base-sys-shlib		compatfile,libcxx
 ./usr/lib/libc.so				base-sys-shlib		compatfile
 ./usr/lib/libc.so.12				base-sys-shlib		compatfile
-./usr/lib/libc.so.12.215			base-sys-shlib		compatfile
+./usr/lib/libc.so.12.216			base-sys-shlib		compatfile
 ./usr/lib/libcbor.so				base-sys-shlib		compatfile
 ./usr/lib/libcbor.so.0				base-sys-shlib		compatfile
 ./usr/lib/libcbor.so.0.5			base-sys-shlib		compatfile
Index: distrib/sets/lists/comp/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.2321
diff -u -p -u -p -r1.2321 mi
--- distrib/sets/lists/comp/mi	4 Apr 2020 19:26:51 -0000	1.2321
+++ distrib/sets/lists/comp/mi	24 Apr 2020 14:00:09 -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
@@ -3492,10 +3493,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
@@ -5558,6 +5559,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
@@ -8868,6 +8921,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
@@ -13645,6 +13699,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
@@ -16896,6 +17002,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
@@ -21569,6 +21676,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
@@ -24914,6 +25073,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
@@ -26475,8 +26635,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.306
diff -u -p -u -p -r1.306 mi
--- distrib/sets/lists/debug/mi	11 Apr 2020 01:51:14 -0000	1.306
+++ distrib/sets/lists/debug/mi	24 Apr 2020 14:00:09 -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/debug/shl.mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/debug/shl.mi,v
retrieving revision 1.245
diff -u -p -u -p -r1.245 shl.mi
--- distrib/sets/lists/debug/shl.mi	4 Apr 2020 19:26:51 -0000	1.245
+++ distrib/sets/lists/debug/shl.mi	24 Apr 2020 14:00:09 -0000
@@ -3,7 +3,7 @@
 ./usr/libdata/debug/lib						base-sys-usr	debug,dynamicroot,compatdir
 ./usr/libdata/debug/lib/libavl.so.0.0.debug			comp-zfs-debug	debug,dynamicroot,zfs
 ./usr/libdata/debug/lib/libblacklist.so.0.0.debug		comp-sys-debug	debug,dynamicroot
-./usr/libdata/debug/lib/libc.so.12.215.debug			comp-sys-debug	debug,dynamicroot
+./usr/libdata/debug/lib/libc.so.12.216.debug			comp-sys-debug	debug,dynamicroot
 ./usr/libdata/debug/lib/libcrypt.so.1.0.debug			comp-sys-debug	debug,dynamicroot
 ./usr/libdata/debug/lib/libcrypto.so.12.0.debug			comp-sys-debug	debug,dynamicroot,openssl=10
 ./usr/libdata/debug/lib/libcrypto.so.14.0.debug			comp-sys-debug	debug,dynamicroot,openssl=11
@@ -82,7 +82,7 @@
 ./usr/libdata/debug/usr/lib/libbsdmalloc.so.0.0.debug		comp-sys-debug	debug,compatfile
 ./usr/libdata/debug/usr/lib/libbz2.so.1.1.debug			comp-sys-debug	debug,compatfile
 ./usr/libdata/debug/usr/lib/libc++.so.1.0.debug			comp-sys-debug	debug,compatfile,libcxx
-./usr/libdata/debug/usr/lib/libc.so.12.215.debug		comp-sys-debug	debug,compatfile
+./usr/libdata/debug/usr/lib/libc.so.12.216.debug		comp-sys-debug	debug,compatfile
 ./usr/libdata/debug/usr/lib/libcbor.so.0.5.debug		comp-sys-debug	debug,compatfile
 ./usr/libdata/debug/usr/lib/libcom_err.so.8.0.debug		comp-krb5-debug	debug,compatfile,kerberos
 ./usr/libdata/debug/usr/lib/libcrypt.so.1.0.debug		comp-sys-debug	debug,compatfile
Index: distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1687
diff -u -p -u -p -r1.1687 mi
--- distrib/sets/lists/man/mi	12 Apr 2020 01:10:53 -0000	1.1687
+++ distrib/sets/lists/man/mi	24 Apr 2020 14:00:09 -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 -u -p -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	24 Apr 2020 14:00:12 -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 -u -p -r1.11 Makefile
--- external/bsd/libarchive/lib/libarchive/Makefile	13 Oct 2019 07:28:06 -0000	1.11
+++ external/bsd/libarchive/lib/libarchive/Makefile	24 Apr 2020 14:00:12 -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 -u -p -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	24 Apr 2020 14:00:16 -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.64
diff -u -p -u -p -r1.64 zfs_vnops.c
--- external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c	14 Mar 2020 20:45:23 -0000	1.64
+++ external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c	24 Apr 2020 14:00:16 -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;
 
@@ -6307,6 +6307,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 },
@@ -6352,6 +6353,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 },
@@ -6399,6 +6401,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 -u -p -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	24 Apr 2020 14:00:16 -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 -u -p -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	24 Apr 2020 14:00:16 -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 -u -p -r1.18 mntopts.h
--- include/mntopts.h	9 Jan 2018 03:31:12 -0000	1.18
+++ include/mntopts.h	24 Apr 2020 14:00:23 -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.156
diff -u -p -u -p -r1.156 unistd.h
--- include/unistd.h	31 Mar 2020 16:50:31 -0000	1.156
+++ include/unistd.h	24 Apr 2020 14:00:23 -0000
@@ -360,6 +360,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 -u -p -r1.172 Makefile
--- lib/libc/Makefile	3 Aug 2018 14:01:21 -0000	1.172
+++ lib/libc/Makefile	24 Apr 2020 14:00:23 -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/shlib_version
===================================================================
RCS file: /cvsroot/src/lib/libc/shlib_version,v
retrieving revision 1.286
diff -u -p -u -p -r1.286 shlib_version
--- lib/libc/shlib_version	8 Mar 2020 22:27:38 -0000	1.286
+++ lib/libc/shlib_version	24 Apr 2020 14:00:23 -0000
@@ -54,4 +54,4 @@
 # - move statfs() to libcompat since we have statvfs()
 # - the syscall stubs for the (obsolete) lfs syscalls should be removed
 major=12
-minor=215
+minor=216
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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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	24 Apr 2020 14:00:23 -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 -u -p -r1.242 Makefile.inc
--- lib/libc/sys/Makefile.inc	22 Sep 2019 22:59:38 -0000	1.242
+++ lib/libc/sys/Makefile.inc	24 Apr 2020 14:00:23 -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 -u -p -r1.26 makelintstub
--- lib/libc/sys/makelintstub	3 Apr 2016 00:48:29 -0000	1.26
+++ lib/libc/sys/makelintstub	24 Apr 2020 14:00:23 -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 -u -p -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	24 Apr 2020 14:00:23 -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 -u -p -r1.44 tunefs.8
--- sbin/tunefs/tunefs.8	9 Aug 2014 10:41:05 -0000	1.44
+++ sbin/tunefs/tunefs.8	24 Apr 2020 14:00:23 -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 POSIX.1e 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
@@ -120,6 +124,8 @@ threshold.
 Note that if the value is raised above the current usage level,
 users will be unable to allocate files until enough files have
 been deleted to get under the higher threshold.
+.It Fl n Cm enable | disable
+Turn on/off the administrative NFSv4 ACL enable flag.
 .It Fl o Ar optimize_preference
 The file system can either try to minimize the time spent
 allocating blocks, or it can attempt to minimize the space
Index: sbin/tunefs/tunefs.c
===================================================================
RCS file: /cvsroot/src/sbin/tunefs/tunefs.c,v
retrieving revision 1.51
diff -u -p -u -p -r1.51 tunefs.c
--- sbin/tunefs/tunefs.c	9 Apr 2020 14:44:38 -0000	1.51
+++ sbin/tunefs/tunefs.c	24 Apr 2020 14:00:23 -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'");
 	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'");
 	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.82
diff -u -p -u -p -r1.82 genassym.cf
--- sys/arch/amd64/amd64/genassym.cf	17 Feb 2020 09:09:48 -0000	1.82
+++ sys/arch/amd64/amd64/genassym.cf	24 Apr 2020 14:00:23 -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.565
diff -u -p -u -p -r1.565 GENERIC
--- sys/arch/amd64/conf/GENERIC	15 Apr 2020 17:16:22 -0000	1.565
+++ sys/arch/amd64/conf/GENERIC	24 Apr 2020 14:00:23 -0000
@@ -187,6 +187,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 -u -p -r1.111 coda_vnops.c
--- sys/coda/coda_vnops.c	13 Apr 2020 19:23:17 -0000	1.111
+++ sys/coda/coda_vnops.c	24 Apr 2020 14:00:24 -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/fs/adosfs/advnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/adosfs/advnops.c,v
retrieving revision 1.53
diff -u -p -u -p -r1.53 advnops.c
--- sys/fs/adosfs/advnops.c	23 Apr 2020 21:47:07 -0000	1.53
+++ sys/fs/adosfs/advnops.c	24 Apr 2020 14:00:24 -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 */
@@ -779,7 +780,7 @@ adosfs_check_permitted(struct vnode *vp,
 
 	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));
+	    file_mode, ap->uid, ap->gid, NULL, mode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -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));
+	    ip->inode.iso_uid, ip->inode.iso_gid, NULL, accmode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    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));
+	    eip->ei_mode, eip->ei_uid, eip->ei_gid, NULL, accmode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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));
+	    fcmp->fc_gid, NULL, accmode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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 */
@@ -560,7 +563,7 @@ hfs_check_permitted(vnode_t *vp, struct 
 
 	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));
+	    va->va_mode, va->va_uid, va->va_gid, NULL, mode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp->v_type,
-	    file_mode, pmp->pm_uid, pmp->pm_gid, mode, cred));
+	    file_mode, pmp->pm_uid, pmp->pm_gid, NULL, accmode, cred));
 }
 
 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;
 }
@@ -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 -u -p -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	24 Apr 2020 14:00:24 -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,7 +1020,7 @@ 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;
@@ -1034,7 +1034,7 @@ nilfs_check_permitted(struct vnode *vp, 
 	/* 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));
+	    vap->va_mode, vap->va_uid, vap->va_gid, NULL, mode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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,17 @@ 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->v_type,
+	    file_mode, ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, NULL, accmode,
+	    cred));
 }
 
 int
@@ -439,7 +440,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 +449,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 +815,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 -u -p -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	24 Apr 2020 14:00:24 -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 */
@@ -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),
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, 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));
+	    va.va_gid, NULL, ap->a_accmode, ap->a_cred));
 }
 
 /*
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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -r1.17 sysvbfs.c
--- sys/fs/sysvbfs/sysvbfs.c	28 May 2018 21:04:37 -0000	1.17
+++ sys/fs/sysvbfs/sysvbfs.c	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -0000
@@ -255,7 +255,7 @@ sysvbfs_check_permitted(struct vnode *vp
 
 	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));
+	    attr->mode, attr->uid, attr->gid, NULL, mode, cred));
 }
 
 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;
 }
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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -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_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_vnops.c,v
retrieving revision 1.136
diff -u -p -u -p -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	24 Apr 2020 14:00:24 -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_access },
 	{ &vop_getattr_desc,		tmpfs_getattr },
 	{ &vop_setattr_desc,		tmpfs_setattr },
 	{ &vop_read_desc,		tmpfs_read },
@@ -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,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    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));
+	    node->tn_mode, node->tn_uid, node->tn_gid, NULL, accmode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -0000
@@ -1443,7 +1443,7 @@ udf_check_permitted(struct vnode *vp, st
 	/* 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));
+	    vap->va_mode, vap->va_uid, vap->va_gid, NULL, mode, cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -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 -u -p -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	24 Apr 2020 14:00:24 -0000
@@ -379,26 +379,26 @@ v7fs_check_permitted(struct vnode *vp, s
 
 	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));
+	    inode->mode, inode->uid, inode->gid, NULL, mode, cred));
 }
 
 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;
 }
Index: sys/gdbscripts/kernhist
===================================================================
RCS file: /cvsroot/src/sys/gdbscripts/kernhist,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 kernhist
--- sys/gdbscripts/kernhist	12 May 2016 00:35:10 -0000	1.2
+++ sys/gdbscripts/kernhist	24 Apr 2020 14:00:24 -0000
@@ -15,8 +15,15 @@ define kernhist
 		set $e = $hist->e[$lcv]
 		set $fmt = $e.fmt
 
+		if ($e.v[2] !=  0xffff8fbe5f7604a0l)
+			set $lcv = ($lcv + 1) % $histn
+			if ($lcv == $histf)
+				loop_break
+			end
+			loop_continue
+		end
 		if ($fmt)
-			printf "%06lx.%06d ", $e.tv.tv_sec, $e.tv.tv_usec
+			printf "%ld ", $e.bt.sec
 			printf "%s#%ld@%d: ", $e.fn, $e.call, $e.cpunum
 			printf "%s: %lx %lx %lx %lx\n", $fmt, $e.v[0], $e.v[1], $e.v[2], $e.v[3]
 			set $lcv = ($lcv + 1) % $histn
Index: sys/kern/files.kern
===================================================================
RCS file: /cvsroot/src/sys/kern/files.kern,v
retrieving revision 1.45
diff -u -p -u -p -r1.45 files.kern
--- sys/kern/files.kern	22 Apr 2020 09:18:42 -0000	1.45
+++ sys/kern/files.kern	24 Apr 2020 14:00:24 -0000
@@ -98,6 +98,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
@@ -193,6 +195,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.329
diff -u -p -u -p -r1.329 init_sysent.c
--- sys/kern/init_sysent.c	22 Apr 2020 21:25:17 -0000	1.329
+++ sys/kern/init_sysent.c	24 Apr 2020 14:00:24 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: init_sysent.c,v 1.329 2020/04/22 21:25:17 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call switch table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_sysent.c,v 1.329 2020/04/22 21:25:17 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)
@@ -2359,44 +2360,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 -u -p -r1.77 kern_auth.c
--- sys/kern/kern_auth.c	3 Sep 2018 16:29:35 -0000	1.77
+++ sys/kern/kern_auth.c	24 Apr 2020 14:00:24 -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	24 Apr 2020 14:00:24 -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	24 Apr 2020 14:00:24 -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 -u -p -r1.46 sys_mqueue.c
--- sys/kern/sys_mqueue.c	16 Mar 2020 21:20:10 -0000	1.46
+++ sys/kern/sys_mqueue.c	24 Apr 2020 14:00:24 -0000
@@ -403,7 +403,7 @@ mqueue_access(mqueue_t *mq, int access, 
 		acc_mode |= VWRITE;
 	}
 	if (genfs_can_access(VNON, mq->mq_mode, mq->mq_euid,
-	    mq->mq_egid, acc_mode, cred)) {
+	    mq->mq_egid, NULL, acc_mode, cred)) {
 		return EACCES;
 	}
 	return 0;
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/syscalls.c,v
retrieving revision 1.317
diff -u -p -u -p -r1.317 syscalls.c
--- sys/kern/syscalls.c	22 Apr 2020 21:25:17 -0000	1.317
+++ sys/kern/syscalls.c	24 Apr 2020 14:00:24 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls.c,v 1.317 2020/04/22 21:25:17 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call names.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls.c,v 1.317 2020/04/22 21:25:17 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 -u -p -r1.30 syscalls.conf
--- sys/kern/syscalls.conf	22 Sep 2019 22:59:39 -0000	1.30
+++ sys/kern/syscalls.conf	24 Apr 2020 14:00:24 -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.302
diff -u -p -u -p -r1.302 syscalls.master
--- sys/kern/syscalls.master	22 Apr 2020 21:22:21 -0000	1.302
+++ sys/kern/syscalls.master	24 Apr 2020 14:00:24 -0000
@@ -59,6 +59,7 @@
 #include <sys/sched.h>
 #include <sys/idtype.h>
 #include <sys/syscallargs.h>
+#include <sys/acl.h>
 
 %%
 
@@ -1015,3 +1016,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.34
diff -u -p -u -p -r1.34 syscalls_autoload.c
--- sys/kern/syscalls_autoload.c	22 Apr 2020 21:25:17 -0000	1.34
+++ sys/kern/syscalls_autoload.c	24 Apr 2020 14:00:24 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls_autoload.c,v 1.34 2020/04/22 21:25:17 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call autoload table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls_autoload.c,v 1.34 2020/04/22 21:25:17 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.36
diff -u -p -u -p -r1.36 systrace_args.c
--- sys/kern/systrace_args.c	22 Apr 2020 21:25:17 -0000	1.36
+++ sys/kern/systrace_args.c	24 Apr 2020 14:00:25 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: systrace_args.c,v 1.36 2020/04/22 21:25:17 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument to DTrace register array converstion.
@@ -3701,6 +3701,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;
@@ -9979,6 +10092,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;
 	};
@@ -12076,6 +12385,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	24 Apr 2020 14:00:25 -0000
@@ -0,0 +1,556 @@
+/*-
+ * 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);
+
+static int	kern___acl_aclcheck_path(struct lwp *l, const char *path,
+    acl_type_t type, struct acl *aclp, namei_simple_flags_t flags);
+static int	kern___acl_delete_path(struct lwp *l, const char *path,
+    acl_type_t type, namei_simple_flags_t flags);
+static int	kern___acl_get_path(struct lwp *l, const char *path,
+    acl_type_t type, struct acl *aclp, namei_simple_flags_t flags);
+static int	kern___acl_set_path(struct lwp *l, const char *path,
+    acl_type_t type, const struct acl *aclp, namei_simple_flags_t flags);
+static int	vacl_set_acl(struct lwp *l, struct vnode *vp,
+    acl_type_t type, const struct acl *aclp);
+static int	vacl_get_acl(struct lwp *l, struct vnode *vp,
+    acl_type_t type, struct acl *aclp);
+static int	vacl_aclcheck(struct lwp *l, struct vnode *vp,
+    acl_type_t type, const struct acl *aclp);
+
+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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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...?
+ */
+static 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);
+}
+
+static 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);
+}
+
+static 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);
+}
+
+static 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);
+}
+
+static 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.141
diff -u -p -u -p -r1.141 vfs_cache.c
--- sys/kern/vfs_cache.c	23 Apr 2020 22:58:36 -0000	1.141
+++ sys/kern/vfs_cache.c	24 Apr 2020 14:00:25 -0000
@@ -688,7 +688,7 @@ cache_lookup_linked(struct vnode *dvp, c
 	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));
+	    dvi->vi_nc_uid, dvi->vi_nc_gid, NULL, VEXEC, cred));
 	if (error != 0) {
 		COUNT(ncs_denied);
 		return false;
@@ -769,7 +769,7 @@ cache_revlookup(struct vnode *vp, struct
 		    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));
+		    NULL, perms, curlwp->l_cred));
 		    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 -u -p -r1.59 vfs_getcwd.c
--- sys/kern/vfs_getcwd.c	21 Apr 2020 21:42:47 -0000	1.59
+++ sys/kern/vfs_getcwd.c	24 Apr 2020 14:00:25 -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 -u -p -r1.50 vfs_init.c
--- sys/kern/vfs_init.c	21 Feb 2020 00:26:22 -0000	1.50
+++ sys/kern/vfs_init.c	24 Apr 2020 14:00:25 -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 -u -p -r1.486 vfs_subr.c
--- sys/kern/vfs_subr.c	21 Apr 2020 21:42:47 -0000	1.486
+++ sys/kern/vfs_subr.c	24 Apr 2020 14:00:25 -0000
@@ -1141,16 +1141,16 @@ 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)
+    accmode_t accmode, kauth_cred_t cred)
 {
 
 #ifdef DIAGNOSTIC
 	printf("vaccess: deprecated interface used.\n");
 #endif /* DIAGNOSTIC */
 
-	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(acc_mode,
+	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
 	    type, file_mode), NULL /* This may panic. */, NULL,
-	    genfs_can_access(type, file_mode, uid, gid, acc_mode, cred));
+	    genfs_can_access(type, file_mode, uid, gid, NULL, accmode, cred));
 }
 
 /*
@@ -1278,6 +1278,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 -u -p -r1.547 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	21 Apr 2020 21:42:47 -0000	1.547
+++ sys/kern/vfs_syscalls.c	24 Apr 2020 14:00:25 -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);
 }
 
 /*
Index: sys/kern/vnode_if.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.c,v
retrieving revision 1.110
diff -u -p -u -p -r1.110 vnode_if.c
--- sys/kern/vnode_if.c	23 Feb 2020 22:15:19 -0000	1.110
+++ sys/kern/vnode_if.c	24 Apr 2020 14:00:25 -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 -u -p -r1.69 vnode_if.sh
--- sys/kern/vnode_if.sh	23 Feb 2020 22:14:04 -0000	1.69
+++ sys/kern/vnode_if.sh	24 Apr 2020 14:00:25 -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 -u -p -r1.78 vnode_if.src
--- sys/kern/vnode_if.src	11 Oct 2019 08:04:52 -0000	1.78
+++ sys/kern/vnode_if.src	24 Apr 2020 14:00:25 -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 -u -p -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	24 Apr 2020 14:00:25 -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 -u -p -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	24 Apr 2020 14:00:25 -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 -u -p -r1.33 genfs.h
--- sys/miscfs/genfs/genfs.h	17 Feb 2017 08:31:25 -0000	1.33
+++ sys/miscfs/genfs/genfs.h	24 Apr 2020 14:00:25 -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,8 +51,12 @@ 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_access(enum vtype, mode_t, uid_t, gid_t,
+    struct acl *, accmode_t, kauth_cred_t);
+int	genfs_can_access_acl_posix1e(enum vtype, mode_t, uid_t, gid_t,
+    struct acl *, accmode_t, kauth_cred_t);
+int	genfs_can_access_acl_nfs4(enum vtype, mode_t, uid_t, gid_t,
+    struct acl *, accmode_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);
Index: sys/miscfs/genfs/genfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_vnops.c,v
retrieving revision 1.202
diff -u -p -u -p -r1.202 genfs_vnops.c
--- sys/miscfs/genfs/genfs_vnops.c	23 Feb 2020 22:14:04 -0000	1.202
+++ sys/miscfs/genfs/genfs_vnops.c	24 Apr 2020 14:00:25 -0000
@@ -668,53 +668,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's type, "mode", uid and gid, requested access mode, credentials.
+ * 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(enum vtype type, mode_t file_mode, uid_t file_uid,
+    gid_t file_gid, struct acl *acl, accmode_t accmode, kauth_cred_t cred)
 {
-	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));
 
-	mask = 0;
+	/*
+	 * Look for a normal, non-privileged way to access the file/directory
+	 * as requested.  If it exists, go with that.
+	 */
 
-	/* 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);
+	dac_granted = 0;
+
+	/* 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(enum vtype type, mode_t file_mode, uid_t file_uid,
+    gid_t file_gid, struct acl *acl, accmode_t accmode, kauth_cred_t cred)
+{
+	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(enum vtype type, mode_t file_mode, uid_t file_uid,
+    gid_t file_gid, struct acl *aclp, accmode_t accmode, kauth_cred_t cred)
+{
+	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\n", __func__, buf);
+#endif
+
+	if (accmode & VADMIN)
+		must_be_owner = 1;
+
+	/*
+	 * Ignore VSYNCHRONIZE permission.
+	 */
+	accmode &= ~VSYNCHRONIZE;
+
+	access_mask = _access_mask_from_accmode(accmode);
+
+	if (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);
 }
 
 /*
@@ -739,10 +1205,6 @@ genfs_can_chmod(enum vtype type, kauth_c
 {
 	int error;
 
-	/* The user must own the file. */
-	if (kauth_cred_geteuid(cred) != cur_uid)
-		return (EPERM);
-
 	/*
 	 * Unprivileged users can't set the sticky bit on files.
 	 */
@@ -762,6 +1224,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);
 }
 
@@ -904,9 +1372,39 @@ int
 genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp,
     const char *attr)
 {
+	if (cred == NOCRED)
+		return 0;
+
 	/* We can't allow privileged namespaces. */
 	if (strncasecmp(attr, "system", 6) == 0)
 		return EPERM;
 
 	return VOP_ACCESS(vp, access_mode, cred);
 }
+
+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(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 -u -p -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	24 Apr 2020 14:00:25 -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 -u -p -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	24 Apr 2020 14:00:25 -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),
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, 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));
+	    va.va_uid, va.va_gid, NULL, ap->a_accmode, ap->a_cred));
 }
 
 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 -u -p -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	24 Apr 2020 14:00:25 -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 -u -p -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	24 Apr 2020 14:00:25 -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.211
diff -u -p -u -p -r1.211 procfs_vnops.c
--- sys/miscfs/procfs/procfs_vnops.c	21 Apr 2020 21:42:47 -0000	1.211
+++ sys/miscfs/procfs/procfs_vnops.c	24 Apr 2020 14:00:25 -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 */
@@ -965,7 +966,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;
@@ -975,9 +976,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),
+	    KAUTH_ACCESS_ACTION(ap->a_accmode, 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));
+	    va.va_uid, va.va_gid, NULL, ap->a_accmode, ap->a_cred));
 }
 
 /*
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 -u -p -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	24 Apr 2020 14:00:25 -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 -u -p -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	24 Apr 2020 14:00:25 -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/ffs/Makefile
===================================================================
RCS file: /cvsroot/src/sys/modules/ffs/Makefile,v
retrieving revision 1.14
diff -u -p -u -p -r1.14 Makefile
--- sys/modules/ffs/Makefile	18 Apr 2020 19:18:33 -0000	1.14
+++ sys/modules/ffs/Makefile	24 Apr 2020 14:00:25 -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 -u -p -r1.3 Makefile
--- sys/modules/ufs/Makefile	12 Apr 2020 01:39:57 -0000	1.3
+++ sys/modules/ufs/Makefile	24 Apr 2020 14:00:25 -0000
@@ -5,7 +5,7 @@
 KMOD=	ufs
 
 CPPFLAGS+=      -DUFS_DIRHASH -DFFS_EI -DWAPBL -DAPPLE_UFS -DQUOTA -DQUOTA2
-CPPFLAGS+=	-DUFS_EXTATTR
+CPPFLAGS+=	-DUFS_EXTATTR -DUFS_ACL
 
 CWARNFLAGS.clang=	-Wno-conversion
 
Index: sys/nfs/nfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.314
diff -u -p -u -p -r1.314 nfs_vnops.c
--- sys/nfs/nfs_vnops.c	13 Apr 2020 19:23:20 -0000	1.314
+++ sys/nfs/nfs_vnops.c	24 Apr 2020 14:00:25 -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(
+	    va.va_type, va.va_mode, va.va_uid, va.va_gid, NULL,
+	    ap->a_accmode, ap->a_cred));
 }
 
 /*
Index: sys/rump/rump.sysmap
===================================================================
RCS file: /cvsroot/src/sys/rump/rump.sysmap,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 rump.sysmap
--- sys/rump/rump.sysmap	22 Sep 2019 23:03:20 -0000	1.6
+++ sys/rump/rump.sysmap	24 Apr 2020 14:00:25 -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.18
diff -u -p -u -p -r1.18 Makefile
--- sys/rump/fs/lib/libffs/Makefile	18 Apr 2020 19:18:33 -0000	1.18
+++ sys/rump/fs/lib/libffs/Makefile	24 Apr 2020 14:00:25 -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.115
diff -u -p -u -p -r1.115 rump_syscalls.h
--- sys/rump/include/rump/rump_syscalls.h	22 Apr 2020 21:25:17 -0000	1.115
+++ sys/rump/include/rump/rump_syscalls.h	24 Apr 2020 14:00:25 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rump_syscalls.h,v 1.115 2020/04/22 21:25:17 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 -u -p -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	24 Apr 2020 14:00:25 -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.146
diff -u -p -u -p -r1.146 rump_syscalls.c
--- sys/rump/librump/rumpkern/rump_syscalls.c	22 Apr 2020 21:25:17 -0000	1.146
+++ sys/rump/librump/rumpkern/rump_syscalls.c	24 Apr 2020 14:00:25 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rump_syscalls.c,v 1.146 2020/04/22 21:25:17 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.146 2020/04/22 21:25:17 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)
@@ -8448,57 +8477,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 -u -p -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	24 Apr 2020 14:00:25 -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.157
diff -u -p -u -p -r1.157 rumpfs.c
--- sys/rump/librump/rumpvfs/rumpfs.c	23 Apr 2020 21:47:08 -0000	1.157
+++ sys/rump/librump/rumpvfs/rumpfs.c	24 Apr 2020 14:00:25 -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 },
@@ -831,7 +832,7 @@ rump_check_permitted(struct vnode *vp, s
 
 	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));
+	    attr->va_mode, attr->va_uid, attr->va_gid, NULL, mode, cred));
 }
 
 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;
 }
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 -u -p -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	24 Apr 2020 14:00:25 -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.172
diff -u -p -u -p -r1.172 Makefile
--- sys/sys/Makefile	22 Mar 2020 14:27:33 -0000	1.172
+++ sys/sys/Makefile	24 Apr 2020 14:00:25 -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	24 Apr 2020 14:00:25 -0000
@@ -0,0 +1,422 @@
+/*-
+ * 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)
+
+#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);
+
+#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 -u -p -r1.14 ansi.h
--- sys/sys/ansi.h	17 Jul 2011 20:54:54 -0000	1.14
+++ sys/sys/ansi.h	24 Apr 2020 14:00:25 -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/fstypes.h
===================================================================
RCS file: /cvsroot/src/sys/sys/fstypes.h,v
retrieving revision 1.38
diff -u -p -u -p -r1.38 fstypes.h
--- sys/sys/fstypes.h	4 Apr 2020 20:49:31 -0000	1.38
+++ sys/sys/fstypes.h	24 Apr 2020 14:00:25 -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.83
diff -u -p -u -p -r1.83 kauth.h
--- sys/sys/kauth.h	14 Feb 2020 04:36:33 -0000	1.83
+++ sys/sys/kauth.h	24 Apr 2020 14:00:25 -0000
@@ -520,11 +520,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/statvfs.h
===================================================================
RCS file: /cvsroot/src/sys/sys/statvfs.h,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 statvfs.h
--- sys/sys/statvfs.h	22 Sep 2019 22:59:40 -0000	1.19
+++ sys/sys/statvfs.h	24 Apr 2020 14:00:25 -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.311
diff -u -p -u -p -r1.311 syscall.h
--- sys/sys/syscall.h	22 Apr 2020 21:25:17 -0000	1.311
+++ sys/sys/syscall.h	24 Apr 2020 14:00:25 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscall.h,v 1.311 2020/04/22 21:25:17 thorpej Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call numbers.
@@ -1341,6 +1341,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.295
diff -u -p -u -p -r1.295 syscallargs.h
--- sys/sys/syscallargs.h	22 Apr 2020 21:25:17 -0000	1.295
+++ sys/sys/syscallargs.h	24 Apr 2020 14:00:26 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscallargs.h,v 1.295 2020/04/22 21:25:17 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>
@@ -3175,6 +3176,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.
  */
@@ -4057,5 +4169,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 -u -p -r1.104 types.h
--- sys/sys/types.h	28 Jan 2020 16:40:27 -0000	1.104
+++ sys/sys/types.h	24 Apr 2020 14:00:26 -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 -u -p -r1.62 unistd.h
--- sys/sys/unistd.h	16 Oct 2019 20:43:18 -0000	1.62
+++ sys/sys/unistd.h	24 Apr 2020 14:00:26 -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 -u -p -r1.295 vnode.h
--- sys/sys/vnode.h	13 Apr 2020 19:23:20 -0000	1.295
+++ sys/sys/vnode.h	24 Apr 2020 14:00:26 -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 */
@@ -292,11 +293,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 +642,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 -u -p -r1.104 vnode_if.h
--- sys/sys/vnode_if.h	23 Feb 2020 22:15:18 -0000	1.104
+++ sys/sys/vnode_if.h	24 Apr 2020 14:00:26 -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 -u -p -r1.47 files.ufs
--- sys/ufs/files.ufs	18 Apr 2020 19:18:33 -0000	1.47
+++ sys/ufs/files.ufs	24 Apr 2020 14:00:26 -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_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/chfs/chfs_vnops.c,v
retrieving revision 1.38
diff -u -p -u -p -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	24 Apr 2020 14:00:26 -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,13 @@ 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->v_type, ip->mode & ALLPERMS, ip->uid, ip->gid, NULL, accmode,
+	    cred));
 }
 
 /* --------------------------------------------------------------------- */
@@ -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_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vnops.c,v
retrieving revision 1.131
diff -u -p -u -p -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	24 Apr 2020 14:00:26 -0000
@@ -232,7 +232,8 @@ ext2fs_check_permitted(struct vnode *vp,
 
 	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));
+	    ip->i_e2fs_mode & ALLPERMS, ip->i_uid, ip->i_gid, NULL, mode,
+	    cred));
 }
 
 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);
@@ -1101,6 +1102,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 +1157,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 +1212,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/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.367
diff -u -p -u -p -r1.367 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	4 Apr 2020 20:49:31 -0000	1.367
+++ sys/ufs/ffs/ffs_vfsops.c	24 Apr 2020 14:00:26 -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;
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 -u -p -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	24 Apr 2020 14:00:26 -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 -u -p -r1.67 fs.h
--- sys/ufs/ffs/fs.h	18 Apr 2020 19:18:34 -0000	1.67
+++ sys/ufs/ffs/fs.h	24 Apr 2020 14:00:26 -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 -u -p -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	24 Apr 2020 14:00:26 -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 */
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 -u -p -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	24 Apr 2020 14:00:26 -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->v_type, ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, NULL,
+	    accmode, cred));
 }
 
 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;
 }
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 -u -p -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	24 Apr 2020 14:00:26 -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	24 Apr 2020 14:00:26 -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	24 Apr 2020 14:00:26 -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	24 Apr 2020 14:00:26 -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_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extern.h,v
retrieving revision 1.85
diff -u -p -u -p -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	24 Apr 2020 14:00:26 -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 -u -p -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	24 Apr 2020 14:00:26 -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.
 	 */
@@ -590,7 +622,12 @@ notfound:
 		 * Access for write is interpreted as allowing
 		 * creation of files in the directory.
 		 */
-		error = VOP_ACCESS(vdp, VWRITE, cred);
+#ifdef notyet
+		if (flags & WILLBEDIR)
+			error = VOP_ACCESS(vdp, VWRITE | VAPPEND, cred);
+		else
+#endif
+			error = VOP_ACCESS(vdp, VWRITE, cred);
 		if (error)
 			goto out;
 		error = slot_estimate(&slot, dirblksiz, nameiop,
@@ -675,7 +712,13 @@ found:
 	 * regular file, or empty directory.
 	 */
 	if (nameiop == RENAME && (flags & ISLASTCN)) {
-		if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0)
+#ifdef notyet
+		if (flags & WILLBEDIR)
+			error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred);
+		else
+#endif
+			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.252
diff -u -p -u -p -r1.252 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c	18 Apr 2020 19:18:34 -0000	1.252
+++ sys/ufs/ufs/ufs_vnops.c	24 Apr 2020 14:00:26 -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,94 @@ 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)(enum vtype, mode_t, uid_t, gid_t, struct acl *, accmode_t,
+    kauth_cred_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->v_type,
+	    ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, acl, accmode, cred));
 }
 
 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) {
+			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;
+		}
+		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 */
@@ -639,6 +686,15 @@ 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));
 	if (error)
@@ -676,6 +732,15 @@ 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));
 	if (error)
@@ -734,6 +799,14 @@ ufs_remove(void *v)
 	mp = dvp->v_mount;
 	KASSERT(mp == vp->v_mount); /* XXX Not stable without lock.  */
 
+#ifdef UFS_ACL
+#ifdef notyet
+	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 +824,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 +982,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 +1242,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 +1351,14 @@ ufs_rmdir(void *v)
 	ip = VTOI(vp);
 	dp = VTOI(dvp);
 
+#ifdef UFS_ACL
+#ifdef notyet
+	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 +1367,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 +1429,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 +2057,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);
@@ -1909,6 +2224,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);