aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEdward Tomasz Napierala <trasz@FreeBSD.org>2009-05-22 15:56:43 +0000
committerEdward Tomasz Napierala <trasz@FreeBSD.org>2009-05-22 15:56:43 +0000
commitae1add4e55214610068712ef35b5787f01fcae53 (patch)
treec4c23f9c8441dec7c3000e786fd64356cf1e6e07 /sys
parent682eec57c4d5bf357744d47e2f23bb0ee8829b39 (diff)
Make 'struct acl' larger, as required to support NFSv4 ACLs. Provide
compatibility interfaces in both kernel and libc. Reviewed by: rwatson
Notes
Notes: svn path=/head/; revision=192586
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/subr_acl_posix1e.c2
-rw-r--r--sys/kern/vfs_acl.c147
-rw-r--r--sys/sys/acl.h119
-rw-r--r--sys/ufs/ufs/ufs_acl.c288
4 files changed, 405 insertions, 151 deletions
diff --git a/sys/kern/subr_acl_posix1e.c b/sys/kern/subr_acl_posix1e.c
index 1c6b14830e9f..e0016e7e7673 100644
--- a/sys/kern/subr_acl_posix1e.c
+++ b/sys/kern/subr_acl_posix1e.c
@@ -409,6 +409,8 @@ acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
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;
diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c
index e8618c8840cc..dfbff09bf3e7 100644
--- a/sys/kern/vfs_acl.c
+++ b/sys/kern/vfs_acl.c
@@ -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 *td, struct vnode *vp,
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 vnode *vp, acl_type_t type,
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 vnode *vp, acl_type_t type,
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 vnode *vp, acl_type_t type,
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 vnode *vp, acl_type_t type)
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 vnode *vp, acl_type_t type,
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);
}
diff --git a/sys/sys/acl.h b/sys/sys/acl.h
index 6e4a7317ba3f..c14423a554bf 100644
--- a/sys/sys/acl.h
+++ b/sys/sys/acl.h
@@ -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
-typedef int acl_type_t;
-typedef int acl_tag_t;
-typedef mode_t acl_perm_t;
-typedef mode_t *acl_permset_t;
+/*
+ * "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;
+ /* "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 cmode,
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, acl_type_t _type, struct acl *_aclp);
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
diff --git a/sys/ufs/ufs/ufs_acl.c b/sys/ufs/ufs/ufs_acl.c
index 89488c7995fb..c04a5d2ffaac 100644
--- a/sys/ufs/ufs/ufs_acl.c
+++ b/sys/ufs/ufs/ufs_acl.c
@@ -141,24 +141,68 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
}
/*
+ * 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)
* a fair number of different access checks may be required to go ahead
* with the operation at all.
*/
-int
-ufs_setacl(ap)
- struct vop_setacl_args /* {
- struct vnode *vp;
- acl_type_t type;
- struct acl *aclp;
- struct ucred *cred;
- struct proc *p;
- } */ *ap;
+static int
+ufs_setacl_posix1e(struct vop_setacl_args *ap)
{
struct inode *ip = VTOI(ap->a_vp);
int error;
+ struct oldacl *old;
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -349,10 +349,15 @@ ufs_setacl(ap)
switch(ap->a_type) {
case ACL_TYPE_ACCESS:
- error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
- POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp),
- (char *) ap->a_aclp, ap->a_td);
+ old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+ error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
+ if (error == 0) {
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old),
+ (char *) old, ap->a_td);
+ }
+ free(old, M_ACL);
break;
case ACL_TYPE_DEFAULT:
@@ -372,11 +377,17 @@ ufs_setacl(ap)
*/
if (error == ENOATTR)
error = 0;
- } else
- error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
- sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td);
+ } else {
+ old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+ error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
+ if (error == 0) {
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
+ sizeof(*old), (char *) old, ap->a_td);
+ }
+ free(old, M_ACL);
+ }
break;
default:
@@ -404,12 +415,9 @@ ufs_setacl(ap)
return (0);
}
-/*
- * Check the validity of an ACL for a file.
- */
int
-ufs_aclcheck(ap)
- struct vop_aclcheck_args /* {
+ufs_setacl(ap)
+ struct vop_setacl_args /* {
struct vnode *vp;
acl_type_t type;
struct acl *aclp;
@@ -418,6 +426,13 @@ ufs_aclcheck(ap)
} */ *ap;
{
+ return (ufs_setacl_posix1e(ap));
+}
+
+static int
+ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap)
+{
+
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -438,7 +453,28 @@ ufs_aclcheck(ap)
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(ap)
+ struct vop_aclcheck_args /* {
+ struct vnode *vp;
+ acl_type_t type;
+ struct acl *aclp;
+ struct ucred *cred;
+ struct thread *td;
+ } */ *ap;
+{
+
+ return (ufs_aclcheck_posix1e(ap));
+}
+
#endif /* !UFS_ACL */