Index: kern/kern_acl.c =================================================================== RCS file: /data/ncvs/src/sys/kern/kern_acl.c,v retrieving revision 1.42 diff -u -r1.42 kern_acl.c --- kern/kern_acl.c 22 Jun 2003 08:41:42 -0000 1.42 +++ kern/kern_acl.c 29 Jul 2003 16:45:40 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson + * Copyright (c) 1999, 2000, 2001, 2002, 2003 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. @@ -473,6 +473,64 @@ } /* + * 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. @@ -557,6 +615,31 @@ (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/acl.h =================================================================== RCS file: /data/ncvs/src/sys/sys/acl.h,v retrieving revision 1.25 diff -u -r1.25 acl.h --- sys/acl.h 29 Dec 2002 20:30:00 -0000 1.25 +++ sys/acl.h 29 Jul 2003 16:39:09 -0000 @@ -117,18 +117,40 @@ #ifdef _KERNEL /* + * 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) + +/* * Storage for ACLs and support structures. */ #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_ACL); #endif -acl_perm_t acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode); +/* + * File system 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); -int acl_posix1e_check(struct acl *acl); + 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); + +/* + * File system independent syntax check for a POSIX.1e ACL. + */ +int acl_posix1e_check(struct acl *acl); #else /* !_KERNEL */ Index: ufs/ufs/acl.h =================================================================== RCS file: /data/ncvs/src/sys/ufs/ufs/acl.h,v retrieving revision 1.4 diff -u -r1.4 acl.h --- ufs/ufs/acl.h 19 Mar 2002 22:40:48 -0000 1.4 +++ ufs/ufs/acl.h 29 Jul 2003 16:00:15 -0000 @@ -38,8 +38,7 @@ #ifdef _KERNEL void ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl); -void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip, - mode_t preserve_mask); +void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip); int ufs_getacl(struct vop_getacl_args *); int ufs_setacl(struct vop_setacl_args *); Index: ufs/ufs/ufs_acl.c =================================================================== RCS file: /data/ncvs/src/sys/ufs/ufs/ufs_acl.c,v retrieving revision 1.17 diff -u -r1.17 ufs_acl.c --- ufs/ufs/ufs_acl.c 11 Jun 2003 06:34:30 -0000 1.17 +++ ufs/ufs/ufs_acl.c 29 Jul 2003 15:57:22 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2001 Robert N. M. Watson + * Copyright (c) 1999-2001, 2003 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. @@ -126,83 +126,16 @@ } /* - * Synchronize an inode and an ACL by copying over appropriate ACL fields to - * the passed inode. Assumes an ACL that would satisfy acl_posix1e_check(), - * and may panic if not. This code will preserve existing use of the - * sticky, setugid, and non-permission bits in the mode field. It may - * be that the caller wishes to have previously authorized these changes, - * and may also want to clear the setugid bits in some situations. + * 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, - mode_t preserve_mask) +ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) { - struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj; - struct acl_entry *acl_other; - mode_t preserve_mode; - int i; - - /* - * Preserve old mode so we can restore appropriate bits of it. - */ - preserve_mode = (ip->i_mode & preserve_mask); - - /* - * Identify the ACL_MASK and all other entries appearing in the - * inode mode. - */ - acl_user_obj = NULL; - acl_group_obj = NULL; - acl_other = NULL; - 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("ufs_sync_inode_from_acl(): bad ae_tag"); - } - } - - if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL) - panic("ufs_sync_inode_from_acl(): missing ae_tags"); - - if (acl_mask == NULL) { - /* - * There is no ACL_MASK, so use the ACL_GROUP_OBJ entry. - */ - ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); - ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj, - acl_group_obj, acl_other); - DIP(ip, i_mode) = ip->i_mode; - } else { - /* - * Use the ACL_MASK entry. - */ - ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); - ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj, - acl_mask, acl_other); - DIP(ip, i_mode) = ip->i_mode; - } - ip->i_mode |= preserve_mode; + ip->i_mode &= ACL_PRESERVE_MASK; + ip->i_mode |= acl_posix1e_acl_to_mode(acl); DIP(ip, i_mode) = ip->i_mode; } @@ -366,7 +299,6 @@ } */ *ap; { struct inode *ip = VTOI(ap->a_vp); - mode_t old_mode, preserve_mask; int error; if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) @@ -461,9 +393,7 @@ * Now that the EA is successfully updated, update the * inode and mark it as changed. */ - old_mode = ip->i_mode; - preserve_mask = ISVTX | ISGID | ISUID; - ufs_sync_inode_from_acl(ap->a_aclp, ip, preserve_mask); + ufs_sync_inode_from_acl(ap->a_aclp, ip); ip->i_flag |= IN_CHANGE; } Index: ufs/ufs/ufs_vnops.c =================================================================== RCS file: /data/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.229 diff -u -r1.229 ufs_vnops.c --- ufs/ufs/ufs_vnops.c 4 Jul 2003 12:16:33 -0000 1.229 +++ ufs/ufs/ufs_vnops.c 29 Jul 2003 16:41:00 -0000 @@ -1454,16 +1454,11 @@ case 0: /* * Retrieved a default ACL, so merge mode and ACL if - * necessary. + * necessary. If the ACL is empty, fall through to + * the "not defined or available" case. */ 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. - */ + dmode = acl_posix1e_newfilemode(dmode, acl); ip->i_mode = dmode; DIP(ip, i_mode) = dmode; *dacl = *acl; @@ -2445,6 +2440,7 @@ * 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(ip, i_mode) = mode; ufs_sync_acl_from_inode(ip, acl);