svn commit: r192586 - in head: bin/cp lib/libc/posix1e sbin/restore sys/kern sys/sys sys/ufs/ufs

Edward Tomasz Napierala trasz at FreeBSD.org
Fri May 22 15:56:45 UTC 2009


Author: trasz
Date: Fri May 22 15:56:43 2009
New Revision: 192586
URL: http://svn.freebsd.org/changeset/base/192586

Log:
  Make 'struct acl' larger, as required to support NFSv4 ACLs.  Provide
  compatibility interfaces in both kernel and libc.
  
  Reviewed by:	rwatson

Added:
  head/lib/libc/posix1e/acl_compat.c   (contents, props changed)
Modified:
  head/bin/cp/Makefile
  head/lib/libc/posix1e/Makefile.inc
  head/lib/libc/posix1e/Symbol.map
  head/lib/libc/posix1e/acl_delete.c
  head/lib/libc/posix1e/acl_entry.c
  head/lib/libc/posix1e/acl_get.c
  head/lib/libc/posix1e/acl_init.c
  head/lib/libc/posix1e/acl_set.c
  head/lib/libc/posix1e/acl_support.c
  head/lib/libc/posix1e/acl_support.h
  head/lib/libc/posix1e/acl_valid.c
  head/sbin/restore/Makefile
  head/sys/kern/subr_acl_posix1e.c
  head/sys/kern/vfs_acl.c
  head/sys/sys/acl.h
  head/sys/ufs/ufs/ufs_acl.c

Modified: head/bin/cp/Makefile
==============================================================================
--- head/bin/cp/Makefile	Fri May 22 15:08:12 2009	(r192585)
+++ head/bin/cp/Makefile	Fri May 22 15:56:43 2009	(r192586)
@@ -3,6 +3,6 @@
 
 PROG=	cp
 SRCS=	cp.c utils.c
-CFLAGS+= -DVM_AND_BUFFER_CACHE_SYNCHRONIZED
+CFLAGS+= -DVM_AND_BUFFER_CACHE_SYNCHRONIZED -D_ACL_PRIVATE
 
 .include <bsd.prog.mk>

Modified: head/lib/libc/posix1e/Makefile.inc
==============================================================================
--- head/lib/libc/posix1e/Makefile.inc	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/Makefile.inc	Fri May 22 15:56:43 2009	(r192586)
@@ -2,8 +2,11 @@
 
 .PATH: ${.CURDIR}/posix1e
 
+CFLAGS+=-D_ACL_PRIVATE
+
 SRCS+=	acl_calc_mask.c			\
 	acl_copy.c			\
+	acl_compat.c			\
 	acl_delete.c			\
 	acl_delete_entry.c		\
 	acl_entry.c			\

Modified: head/lib/libc/posix1e/Symbol.map
==============================================================================
--- head/lib/libc/posix1e/Symbol.map	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/Symbol.map	Fri May 22 15:56:43 2009	(r192586)
@@ -21,15 +21,12 @@ FBSD_1.0 {
 	acl_get_link_np;
 	acl_get_fd;
 	acl_get_fd_np;
-	acl_get_perm_np;
 	acl_get_permset;
 	acl_get_qualifier;
 	acl_get_tag_type;
 	acl_init;
 	acl_dup;
-	acl_add_perm;
 	acl_clear_perms;
-	acl_delete_perm;
 	acl_set_file;
 	acl_set_link_np;
 	acl_set_fd;
@@ -67,3 +64,9 @@ FBSD_1.0 {
 	mac_set_link;
 	mac_set_proc;
 };
+
+FBSD_1.1 {
+	acl_add_perm;
+	acl_delete_perm;
+	acl_get_perm_np;
+};

Added: head/lib/libc/posix1e/acl_compat.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/posix1e/acl_compat.c	Fri May 22 15:56:43 2009	(r192586)
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2008 Edward Tomasz Napierała <trasz at 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.
+ *
+ * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
+ * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/acl.h>
+
+/*
+ * 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);

Modified: head/lib/libc/posix1e/acl_delete.c
==============================================================================
--- head/lib/libc/posix1e/acl_delete.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_delete.c	Fri May 22 15:56:43 2009	(r192586)
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
 #include "un-namespace.h"
 #include <sys/errno.h>
 
+#include "acl_support.h"
+
 int
 acl_delete_def_file(const char *path_p)
 {
@@ -56,6 +58,7 @@ 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));
 }
 
@@ -63,13 +66,14 @@ 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));
 }

Modified: head/lib/libc/posix1e/acl_entry.c
==============================================================================
--- head/lib/libc/posix1e/acl_entry.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_entry.c	Fri May 22 15:56:43 2009	(r192586)
@@ -61,6 +61,8 @@ acl_create_entry(acl_t *acl_p, acl_entry
 	(**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;
 

Modified: head/lib/libc/posix1e/acl_get.c
==============================================================================
--- head/lib/libc/posix1e/acl_get.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_get.c	Fri May 22 15:56:43 2009	(r192586)
@@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
 #include <stdlib.h>
 #include <string.h>
 
+#include "acl_support.h"
+
 acl_t
 acl_get_file(const char *path_p, acl_type_t type)
 {
@@ -60,6 +62,7 @@ acl_get_file(const char *path_p, acl_typ
 	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);
@@ -79,6 +82,7 @@ acl_get_link_np(const char *path_p, acl_
 	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);
@@ -117,6 +121,7 @@ acl_get_fd_np(int fd, acl_type_t type)
 	if (aclp == NULL)
 		return (NULL);
 
+	type = _acl_type_unold(type);
 	error = ___acl_get_fd(fd, type, &aclp->ats_acl);
 	if (error) {
 		acl_free(aclp);

Modified: head/lib/libc/posix1e/acl_init.c
==============================================================================
--- head/lib/libc/posix1e/acl_init.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_init.c	Fri May 22 15:56:43 2009	(r192586)
@@ -54,8 +54,10 @@ acl_init(int count)
 	}
 
 	acl = malloc(sizeof(struct acl_t_struct));
-	if (acl != NULL)
+	if (acl != NULL) {
 		bzero(acl, sizeof(struct acl_t_struct));
+		acl->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+	}
 
 	return (acl);
 }

Modified: head/lib/libc/posix1e/acl_set.c
==============================================================================
--- head/lib/libc/posix1e/acl_set.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_set.c	Fri May 22 15:56:43 2009	(r192586)
@@ -58,6 +58,7 @@ acl_set_file(const char *path_p, acl_typ
 		errno = EINVAL;
 		return (-1);
 	}
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {
@@ -80,6 +81,7 @@ acl_set_link_np(const char *path_p, acl_
 		errno = EINVAL;
 		return (-1);
 	}
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {
@@ -114,6 +116,7 @@ acl_set_fd_np(int fd, acl_t acl, acl_typ
 {
 	int	error;
 
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {

Modified: head/lib/libc/posix1e/acl_support.c
==============================================================================
--- head/lib/libc/posix1e/acl_support.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_support.c	Fri May 22 15:56:43 2009	(r192586)
@@ -376,3 +376,24 @@ _posix1e_acl_add_entry(acl_t acl, acl_ta
 
 	return (0);
 }
+
+/*
+ * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
+ * counterpart.  It's neccessary for the old (pre-NFS4 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);
+	}
+}

Modified: head/lib/libc/posix1e/acl_support.h
==============================================================================
--- head/lib/libc/posix1e/acl_support.h	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_support.h	Fri May 22 15:56:43 2009	(r192586)
@@ -34,6 +34,7 @@
 
 #define _POSIX1E_ACL_STRING_PERM_MAXSIZE 3       /* read, write, exec */
 
+int	_acl_type_unold(acl_type_t type);
 int	_posix1e_acl_check(acl_t acl);
 int	_posix1e_acl_sort(acl_t acl);
 int	_posix1e_acl(acl_t acl, acl_type_t type);

Modified: head/lib/libc/posix1e/acl_valid.c
==============================================================================
--- head/lib/libc/posix1e/acl_valid.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/lib/libc/posix1e/acl_valid.c	Fri May 22 15:56:43 2009	(r192586)
@@ -81,6 +81,7 @@ acl_valid_file_np(const char *pathp, acl
 		errno = EINVAL;
 		return (-1);
 	}
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {
@@ -101,6 +102,7 @@ acl_valid_link_np(const char *pathp, acl
 		errno = EINVAL;
 		return (-1);
 	}
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {
@@ -121,6 +123,7 @@ acl_valid_fd_np(int fd, acl_type_t type,
 		errno = EINVAL;
 		return (-1);
 	}
+	type = _acl_type_unold(type);
 	if (_posix1e_acl(acl, type)) {
 		error = _posix1e_acl_sort(acl);
 		if (error) {
@@ -131,6 +134,5 @@ acl_valid_fd_np(int fd, acl_type_t type,
 
 	acl->ats_cur_entry = 0;
 
-
 	return (___acl_aclcheck_fd(fd, type, &acl->ats_acl));
 }

Modified: head/sbin/restore/Makefile
==============================================================================
--- head/sbin/restore/Makefile	Fri May 22 15:08:12 2009	(r192585)
+++ head/sbin/restore/Makefile	Fri May 22 15:56:43 2009	(r192586)
@@ -5,7 +5,7 @@
 
 PROG=	restore
 LINKS=	${BINDIR}/restore ${BINDIR}/rrestore
-CFLAGS+=-DRRESTORE
+CFLAGS+=-DRRESTORE -D_ACL_PRIVATE
 WARNS?=	0
 SRCS=	main.c interactive.c restore.c dirs.c symtab.c tape.c utilities.c \
 	dumprmt.c

Modified: head/sys/kern/subr_acl_posix1e.c
==============================================================================
--- head/sys/kern/subr_acl_posix1e.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/sys/kern/subr_acl_posix1e.c	Fri May 22 15:56:43 2009	(r192586)
@@ -409,6 +409,8 @@ acl_posix1e_mode_to_entry(acl_tag_t tag,
 
 	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;

Modified: head/sys/kern/vfs_acl.c
==============================================================================
--- head/sys/kern/vfs_acl.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/sys/kern/vfs_acl.c	Fri May 22 15:56:43 2009	(r192586)
@@ -56,7 +56,9 @@ __FBSDID("$FreeBSD$");
 
 #include <security/mac/mac_framework.h>
 
-static MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
+CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
+
+MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
 
 static int	vacl_set_acl(struct thread *td, struct vnode *vp,
 		    acl_type_t type, struct acl *aclp);
@@ -65,6 +67,133 @@ static int	vacl_get_acl(struct thread *t
 static int	vacl_aclcheck(struct thread *td, struct vnode *vp,
 		    acl_type_t type, 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);
+	
+	bzero(dest, 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 < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
+		return (EINVAL);
+
+	bzero(dest, 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(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(struct acl *kernel_acl, void *user_acl, acl_type_t type)
+{
+	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:
+		if (fuword((char *)user_acl +
+		    offsetof(struct acl, acl_maxcnt)) != 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-NFS4 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
@@ -85,7 +214,7 @@ vacl_set_acl(struct thread *td, struct v
 	int error;
 
 	inkernelacl = acl_alloc(M_WAITOK);
-	error = copyin(aclp, inkernelacl, sizeof(struct acl));
+	error = acl_copyin(aclp, inkernelacl, type);
 	if (error)
 		goto out;
 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
@@ -97,7 +226,8 @@ vacl_set_acl(struct thread *td, struct v
 	if (error != 0)
 		goto out_unlock;
 #endif
-	error = VOP_SETACL(vp, type, inkernelacl, td->td_ucred, td);
+	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
+	    td->td_ucred, td);
 #ifdef MAC
 out_unlock:
 #endif
@@ -125,13 +255,15 @@ vacl_get_acl(struct thread *td, struct v
 	if (error != 0)
 		goto out;
 #endif
-	error = VOP_GETACL(vp, type, inkernelacl, td->td_ucred, td);
+	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
+	    td->td_ucred, td);
+
 #ifdef MAC
 out:
 #endif
 	VOP_UNLOCK(vp, 0);
 	if (error == 0)
-		error = copyout(inkernelacl, aclp, sizeof(struct acl));
+		error = acl_copyout(inkernelacl, aclp, type);
 	acl_free(inkernelacl);
 	return (error);
 }
@@ -154,7 +286,7 @@ vacl_delete(struct thread *td, struct vn
 	if (error)
 		goto out;
 #endif
-	error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
+	error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
 #ifdef MAC
 out:
 #endif
@@ -174,7 +306,7 @@ vacl_aclcheck(struct thread *td, struct 
 	int error;
 
 	inkernelacl = acl_alloc(M_WAITOK);
-	error = copyin(aclp, inkernelacl, sizeof(struct acl));
+	error = acl_copyin(aclp, inkernelacl, type);
 	if (error)
 		goto out;
 	error = VOP_ACLCHECK(vp, type, inkernelacl, td->td_ucred, td);
@@ -430,6 +562,7 @@ acl_alloc(int flags)
 	struct acl *aclp;
 
 	aclp = malloc(sizeof(*aclp), M_ACL, flags);
+	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
 
 	return (aclp);
 }

Modified: head/sys/sys/acl.h
==============================================================================
--- head/sys/sys/acl.h	Fri May 22 15:08:12 2009	(r192585)
+++ head/sys/sys/acl.h	Fri May 22 15:56:43 2009	(r192586)
@@ -43,39 +43,104 @@
  * POSIX.1e 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 int		*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 NFS4 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	ACL_MAX_ENTRIES		32 /* maximum entries in an ACL */
+#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;
 
-typedef int	acl_type_t;
-typedef int	acl_tag_t;
-typedef mode_t	acl_perm_t;
-typedef mode_t *acl_permset_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;
+	/* "allow" or "deny".  Unused in POSIX ACLs. */
+	acl_entry_type_t	ae_entry_type;
+	/* Flags control inheritance.  Unused in POSIX ACLs. */
+	acl_flag_t	ae_flags;
 };
 typedef struct acl_entry	*acl_entry_t;
 
-/* internal ACL structure */
+/*
+ * Internal ACL structure, used in libc, kernel APIs and for on-disk
+ * storage of NFS4 ACLs.  POSIX.1e ACLs use "struct oldacl" for on-disk
+ * storage.
+ */
 struct acl {
-	int			acl_cnt;
+	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];
 };
 
-/* external ACL structure */
+/*
+ * ACL structure internal to libc.
+ */
 struct acl_t_struct {
 	struct acl		ats_acl;
 	int			ats_cur_entry;
+	/* Will be used for ACL branding. */
+	int			ats_spare;
 };
 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 ae_tag field.
+ * Possible valid values for ae_tag field.  For explanation, see acl(9).
  */
 #define	ACL_UNDEFINED_TAG	0x00000000
 #define	ACL_USER_OBJ		0x00000001
@@ -87,13 +152,17 @@ typedef struct acl_t_struct *acl_t;
 #define	ACL_OTHER_OBJ		ACL_OTHER
 
 /*
- * Possible valid values for acl_type_t arguments.
+ * Possible valid values for acl_type_t arguments.  First two
+ * are provided only for backwards binary compatibility.
  */
-#define	ACL_TYPE_ACCESS		0x00000000
-#define	ACL_TYPE_DEFAULT	0x00000001
+#define	ACL_TYPE_ACCESS_OLD	0x00000000
+#define	ACL_TYPE_DEFAULT_OLD	0x00000001
+#define	ACL_TYPE_ACCESS		0x00000002
+#define	ACL_TYPE_DEFAULT	0x00000003
 
 /*
- * Possible flags in ae_perm field.
+ * Possible flags 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
@@ -103,13 +172,14 @@ typedef struct acl_t_struct *acl_t;
 #define	ACL_POSIX1E_BITS	(ACL_EXECUTE | ACL_WRITE | ACL_READ)
 
 /*
- * Possible entry_id values for acl_get_entry()
+ * Possible entry_id values for acl_get_entry(3).
  */
 #define	ACL_FIRST_ENTRY		0
 #define	ACL_NEXT_ENTRY		1
 
 /*
- * Undefined value in ae_id field
+ * 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)
 
@@ -126,7 +196,7 @@ typedef struct acl_t_struct *acl_t;
 #define	ACL_PRESERVE_MASK	(~ACL_OVERRIDE_MASK)
 
 /*
- * File system independent code to move back and forth between POSIX mode and
+ * 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);
@@ -141,17 +211,28 @@ mode_t			acl_posix1e_newfilemode(mode_t 
 			    struct acl *dacl);
 struct acl		*acl_alloc(int flags);
 void			acl_free(struct acl *aclp);
+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);
 
 /*
- * File system independent syntax check for a POSIX.1e ACL.
+ * To allocate 'struct acl', use acl_alloc()/acl_free() instead of this.
+ */
+MALLOC_DECLARE(M_ACL);
+
+/*
+ * Filesystem-independent syntax check for a POSIX.1e ACL.
  */
 int			acl_posix1e_check(struct acl *acl);
 
 #else /* !_KERNEL */
 
+#if defined(_ACL_PRIVATE)
+
 /*
  * Syscall interface -- use the library calls instead as the syscalls have
- * strict acl entry ordering requirements.
+ * strict ACL entry ordering requirements.
  */
 __BEGIN_DECLS
 int	__acl_aclcheck_fd(int _filedes, acl_type_t _type, struct acl *_aclp);
@@ -170,6 +251,8 @@ int	__acl_set_file(const char *_path, ac
 int	__acl_set_link(const char *_path, acl_type_t _type, struct acl *_aclp);
 __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

Modified: head/sys/ufs/ufs/ufs_acl.c
==============================================================================
--- head/sys/ufs/ufs/ufs_acl.c	Fri May 22 15:08:12 2009	(r192585)
+++ head/sys/ufs/ufs/ufs_acl.c	Fri May 22 15:56:43 2009	(r192586)
@@ -141,24 +141,68 @@ ufs_sync_inode_from_acl(struct acl *acl,
 }
 
 /*
+ * Read POSIX.1e ACL from an EA.  Return error if its not found
+ * or if any other error has occured.
+ */
+static int
+ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp,
+    struct thread *td)
+{
+	int error, 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, (char *) old,
+		    td);
+		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, (char *) old,
+		    td);
+		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("ufs_get_oldacl(): Loaded invalid ACL "
+		    "(len = %d), inumber %d on %s\n", len,
+		    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.
  */
-int
-ufs_getacl(ap)
-	struct vop_getacl_args /* {
-		struct vnode *vp;
-		struct acl_type_t type;
-		struct acl *aclp;
-		struct ucred *cred;
-		struct thread *td;
-	} */ *ap;
+static int
+ufs_getacl_posix1e(struct vop_getacl_args *ap)
 {
 	struct inode *ip = VTOI(ap->a_vp);
-	int error, len;
+	int error;
+	struct oldacl *old;
 
 	/*
 	 * XXX: If ufs_getacl() should work on file systems not supporting
@@ -167,121 +211,83 @@ ufs_getacl(ap)
 	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
 		return (EOPNOTSUPP);
 
+	old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+
 	/*
-	 * Attempt to retrieve the ACL based on the ACL type.
+	 * Attempt to retrieve the ACL from the extended attributes.
 	 */
-	bzero(ap->a_aclp, sizeof(*ap->a_aclp));
-	len = sizeof(*ap->a_aclp);
-	switch(ap->a_type) {
-	case ACL_TYPE_ACCESS:
-		/*
-		 * ACL_TYPE_ACCESS ACLs may or may not be stored in the
-		 * EA, as they are in fact a combination of the inode
-		 * ownership/permissions and the EA contents.  If the
-		 * EA is present, merge the two in a temporary ACL
-		 * storage, otherwise just return the inode contents.
-		 */
-		error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
-		    POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
-		    POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
-		    ap->a_td);
-		switch (error) {
-		/* XXX: If ufs_getacl() should work on filesystems without
-		 * the EA configured, add case EOPNOTSUPP here. */
-		case ENOATTR:
+	error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td);
+	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.
 			 */
-			ap->a_aclp->acl_cnt = 3;
-			ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
-			ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
-			ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
-			ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
-			ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
-			ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
-			ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
-			ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
-			ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
-			ufs_sync_acl_from_inode(ip, ap->a_aclp);
-			error = 0;
-			break;
-
-		case 0:
-			if (len != sizeof(*ap->a_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("ufs_getacl(): Loaded invalid ACL ("
-				    "%d bytes), inumber %d on %s\n", len,
-				    ip->i_number, ip->i_fs->fs_fsmnt);
-				return (EPERM);
-			}
-			ufs_sync_acl_from_inode(ip, ap->a_aclp);
-			break;
-
-		default:
+			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;
-		}
-		break;
 
-	case ACL_TYPE_DEFAULT:
-		if (ap->a_vp->v_type != VDIR) {
-			error = EINVAL;
+		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;
 		}
-		error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
-		    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
-		    POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len,
-		    (char *) ap->a_aclp, ap->a_td);
-		/*
-		 * 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.
-		 */
-		switch (error) {
-		/* XXX: If ufs_getacl() should work on filesystems without
-		 * the EA configured, add case EOPNOTSUPP here. */
-		case ENOATTR:
-			bzero(ap->a_aclp, sizeof(*ap->a_aclp));
-			ap->a_aclp->acl_cnt = 0;
-			error = 0;
-			break;
 
-		case 0:
-			if (len != sizeof(*ap->a_aclp)) {
-				/*
-				 * A short (or long) read, meaning that for
-				 * some reason the ACL is corrupted.  Return
-				 * EPERM since the object default DAC
-				 * protections are unsafe.
-				 */
-				printf("ufs_getacl(): Loaded invalid ACL ("
-				    "%d bytes), inumber %d on %s\n", len,
-				    ip->i_number, ip->i_fs->fs_fsmnt);
-				return (EPERM);
-			}
-			break;
+		error = 0;
 
-		default:
+		/* FALLTHROUGH */
+	case 0:
+		error = acl_copy_oldacl_into_acl(old, ap->a_aclp);
+		if (error != 0)
 			break;
-		}
-		break;
 
+		if (ap->a_type == ACL_TYPE_ACCESS)
+			ufs_sync_acl_from_inode(ip, ap->a_aclp);
 	default:
-		error = EINVAL;
+		break;
 	}
 
+	free(old, M_ACL);
 	return (error);
 }
 
+int
+ufs_getacl(ap)
+	struct vop_getacl_args /* {
+		struct vnode *vp;
+		acl_type_t type;
+		struct acl *aclp;
+		struct ucred *cred;
+		struct thread *td;
+	} */ *ap;
+{
+
+	return (ufs_getacl_posix1e(ap));
+}
+
 /*
  * Set the ACL on a file.
  *
@@ -291,18 +297,12 @@ ufs_getacl(ap)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list