From owner-svn-src-all@FreeBSD.ORG Fri May 22 15:56:44 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8E9C310656C1; Fri, 22 May 2009 15:56:44 +0000 (UTC) (envelope-from trasz@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7A2BA8FC19; Fri, 22 May 2009 15:56:44 +0000 (UTC) (envelope-from trasz@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n4MFuiQU011248; Fri, 22 May 2009 15:56:44 GMT (envelope-from trasz@svn.freebsd.org) Received: (from trasz@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4MFuhCd011230; Fri, 22 May 2009 15:56:43 GMT (envelope-from trasz@svn.freebsd.org) Message-Id: <200905221556.n4MFuhCd011230@svn.freebsd.org> From: Edward Tomasz Napierala Date: Fri, 22 May 2009 15:56:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r192586 - in head: bin/cp lib/libc/posix1e sbin/restore sys/kern sys/sys sys/ufs/ufs X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 May 2009 15:56:45 -0000 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 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include + +/* + * 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 +#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 #include +#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 -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 ***