Skip site navigation (1)Skip section navigation (2)
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>