Date: Mon, 28 Jul 2008 20:31:08 GMT From: Edward Tomasz Napierala <trasz@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 146156 for review Message-ID: <200807282031.m6SKV8X1073061@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=146156 Change 146156 by trasz@trasz_traszkan on 2008/07/28 20:30:29 Implement ACL_DELETE and ACL_DELETE_CHILD. Note - it should be reviewed by someone who understands ufs_lookup(). Affected files ... .. //depot/projects/soc2008/trasz_nfs4acl/TODO#17 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_nfs4.c#10 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#4 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_lookup.c#6 edit Differences ... ==== //depot/projects/soc2008/trasz_nfs4acl/TODO#17 (text+ko) ==== @@ -22,26 +22,6 @@ acl_set_extended_np, acl_set_flagset_np, acl_to_text_np, acl_is_trivial_np, acl_strip_np. -- Make access control more granular. The following are done: - - ACL_READ_DATA - ACL_WRITE_DATA - ACL_APPEND_DATA - ACL_EXECUTE - ACL_READ_ATTRIBUTES - ACL_WRITE_ATTRIBUTES - ACL_READ_NAMED_ATTRS (implemented, #ifdefed out for SunOS compatibility) - ACL_WRITE_NAMED_ATTRS (implemented, #ifdefed out for SunOS compatibility) - ACL_READ_ACL - ACL_WRITE_ACL - ACL_WRITE_OWNER - ACL_SYNCHRONIZE (not used) - - The following are left: - - ACL_DELETE_CHILD - ACL_DELETE - - Add granular access control to ZFS. - Write code to do the same operations on UFS and ZFS and compare results. ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_nfs4.c#10 (text+ko) ==== @@ -88,18 +88,19 @@ } /* - * Return 1, if access is explicitly denied, -1, if its implicitly - * denied (not allowed), or 0, if allowed. + * Return 0, iff access is allowed, 1 otherwise. * - * XXX: There just cannot be a worse name than this one. */ static int -_match_acl(const struct acl *aclp, int needed_bits, struct ucred *cred, - int file_uid, int file_gid) +_acl_denies(const struct acl *aclp, int needed_bits, struct ucred *cred, + int file_uid, int file_gid, int *denied_explicitly) { int i; const struct acl_entry *entry; + if (denied_explicitly) + *denied_explicitly = 0; + for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); @@ -134,8 +135,12 @@ } if (entry->ae_extended == ACL_EXTENDED_DENY) { - if (entry->ae_perm & needed_bits) + if (entry->ae_perm & needed_bits) { + if (denied_explicitly) + *denied_explicitly = 1; + return (1); + } } needed_bits &= ~(entry->ae_perm); @@ -144,7 +149,7 @@ return (0); } - return (-1); + return (1); } int @@ -153,7 +158,7 @@ int *privused) { mode_t priv_granted = 0; - int denied, is_directory; + int denied, explicitly_denied, is_directory; if (privused != NULL) *privused = 0; @@ -174,10 +179,16 @@ needed_bits &= ~(ACL_READ_ACL | ACL_WRITE_ACL | ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES); - denied = _match_acl(aclp, needed_bits, cred, file_uid, file_gid); + denied = _acl_denies(aclp, needed_bits, cred, file_uid, file_gid, + &explicitly_denied); if (!denied) return (0); + if ((acc_mode & VEXPLICIT_DENY) && explicitly_denied == 0) + return (0); + + acc_mode &= ~VEXPLICIT_DENY; + /* * If we want to append data to the file, either one of ACL_APPEND_DATA * or ACL_WRITE_DATA is sufficient. We just tested for the former @@ -187,7 +198,8 @@ needed_bits |= ACL_WRITE_DATA; needed_bits &= ~ACL_APPEND_DATA; - denied = _match_acl(aclp, needed_bits, cred, file_uid, file_gid); + denied = _acl_denies(aclp, needed_bits, cred, file_uid, + file_gid, NULL); if (!denied) return (0); } ==== //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#4 (text+ko) ==== @@ -310,15 +310,16 @@ /* * Modes. Some values same as Ixxx entries from inode.h for now. */ -#define VEXEC 000100 /* execute/search permission */ -#define VWRITE 000200 /* write permission */ -#define VREAD 000400 /* read permission */ -#define VSVTX 001000 /* save swapped text even after use */ -#define VSGID 002000 /* set group id on execution */ -#define VSUID 004000 /* set user id on execution */ -#define VADMIN 010000 /* permission to administer */ -#define VSTAT 020000 /* permission to retrieve attrs */ -#define VAPPEND 040000 /* permission to write/append */ +#define VEXEC 0000100 /* execute/search permission */ +#define VWRITE 0000200 /* write permission */ +#define VREAD 0000400 /* read permission */ +#define VSVTX 0001000 /* save swapped text even after use */ +#define VSGID 0002000 /* set group id on execution */ +#define VSUID 0004000 /* set user id on execution */ +#define VADMIN 0010000 /* permission to administer */ +#define VSTAT 0020000 /* permission to retrieve attrs */ +#define VAPPEND 0040000 /* permission to write/append */ +#define VEXPLICIT_DENY 0100000 /* return EPERM only if permission was denied explicitly */ #define VALLPERM (VEXEC | VWRITE | VREAD | VADMIN | VSTAT | VAPPEND) /* ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_lookup.c#6 (text+ko) ==== @@ -77,6 +77,59 @@ /* true if old FS format...*/ #define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) +static int +ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, + struct thread *td) +{ + int error; + + /* + * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt + * + * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD + */ + + /* + * XXX: Is this check required? + */ + error = VOP_GRANULAR(vdp, VEXEC, ACL_EXECUTE, cred, td); + if (error) + return (error); + + error = VOP_GRANULAR(tdp, VADMIN, ACL_DELETE, cred, td); + if (error == 0) + return (0); + + error = VOP_GRANULAR(vdp, VWRITE, ACL_DELETE_CHILD, cred, td); + if (error == 0) + return (0); + + error = VOP_GRANULAR(vdp, VWRITE | VEXPLICIT_DENY, ACL_DELETE_CHILD, + cred, td); + if (error) + return (error); + + /* + * Standard Unix access control - delete access requires VWRITE. + */ + error = VOP_GRANULAR(vdp, VWRITE, ACL_WRITE_DATA, cred, td); + if (error) + return (error); + + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. + */ + if ((VTOI(vdp)->i_mode & ISVTX) && + VOP_ACCESS(vdp, VADMIN, cred, td) && + VOP_ACCESS(tdp, VADMIN, cred, td)) + return (EPERM); + + return (0); +} + /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. @@ -495,12 +548,17 @@ */ if (nameiop == DELETE && (flags & ISLASTCN)) { ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); - /* - * Write access to directory required to delete files. - */ - error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); - if (error) + if ((error = VFS_VGET(vdp->v_mount, ino, + LK_EXCLUSIVE, &tdp)) != 0) + return (error); + + error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); + if (error) { + vput(tdp); return (error); + } + + /* * Return pointer to current entry in dp->i_offset, * and distance past previous entry (if there @@ -514,23 +572,10 @@ if (dp->i_number == ino) { VREF(vdp); *vpp = vdp; + vput(tdp); return (0); } - if ((error = VFS_VGET(vdp->v_mount, ino, - LK_EXCLUSIVE, &tdp)) != 0) - return (error); - /* - * If directory is "sticky", then user must own - * the directory, or the file in it, else she - * may not delete it (unless she's root). This - * implements append-only directories. - */ - if ((dp->i_mode & ISVTX) && - VOP_ACCESS(vdp, VADMIN, cred, cnp->cn_thread) && - VOP_ACCESS(tdp, VADMIN, cred, cnp->cn_thread)) { - vput(tdp); - return (EPERM); - } + *vpp = tdp; return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200807282031.m6SKV8X1073061>