From owner-p4-projects@FreeBSD.ORG Mon Jul 28 20:31:08 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 8B61F1065676; Mon, 28 Jul 2008 20:31:08 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4F7F01065675 for ; Mon, 28 Jul 2008 20:31:08 +0000 (UTC) (envelope-from trasz@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 31BBA8FC1D for ; Mon, 28 Jul 2008 20:31:08 +0000 (UTC) (envelope-from trasz@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.2/8.14.2) with ESMTP id m6SKV88d073063 for ; Mon, 28 Jul 2008 20:31:08 GMT (envelope-from trasz@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m6SKV8X1073061 for perforce@freebsd.org; Mon, 28 Jul 2008 20:31:08 GMT (envelope-from trasz@freebsd.org) Date: Mon, 28 Jul 2008 20:31:08 GMT Message-Id: <200807282031.m6SKV8X1073061@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to trasz@freebsd.org using -f From: Edward Tomasz Napierala To: Perforce Change Reviews Cc: Subject: PERFORCE change 146156 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Jul 2008 20:31:08 -0000 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); }