usr/src/uts/common/fs/zfs/zfs_acl.c
changeset 2604 b2fb13f56fe7
parent 2113 0510bb40c993
child 2638 4f583dfeae92
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Thu Aug 24 03:08:38 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Thu Aug 24 07:46:56 2006 -0700
@@ -1432,6 +1432,20 @@
 	return (zfs_zaccess(zp, v4_mode, cr));
 }
 
+static int
+zfs_delete_final_check(znode_t *zp, znode_t *dzp, cred_t *cr)
+{
+	int error;
+
+	error = secpolicy_vnode_access(cr, ZTOV(zp),
+	    dzp->z_phys->zp_uid, S_IWRITE|S_IEXEC);
+
+	if (error == 0)
+		error = zfs_sticky_remove_access(dzp, zp, cr);
+
+	return (error);
+}
+
 /*
  * Determine whether Access should be granted/deny, without
  * consulting least priv subsystem.
@@ -1473,14 +1487,13 @@
 	int dzp_working_mode = 0;
 	int zp_working_mode = 0;
 	int dzp_error, zp_error;
-	int error;
 
 	/*
 	 * Arghh, this check is going to require a couple of questions
 	 * to be asked.  We want specific DELETE permissions to
 	 * take precedence over WRITE/EXECUTE.  We don't
 	 * want an ACL such as this to mess us up.
-	 * user:sloar:write_data:deny,user:sloar:delete:allow
+	 * user:joe:write_data:deny,user:joe:delete:allow
 	 *
 	 * However, deny permissions may ultimately be overridden
 	 * by secpolicy_vnode_access().
@@ -1494,20 +1507,40 @@
 		return (dzp_error);
 
 	/*
-	 * First handle the first row
+	 * First check the first row.
+	 * We only need to see if parent Allows delete_child
 	 */
 	if ((dzp_working_mode & ACE_DELETE_CHILD) == 0)
 		return (0);
 
 	/*
 	 * Second row
+	 * we already have the necessary information in
+	 * zp_working_mode, zp_error and dzp_error.
 	 */
 
 	if ((zp_working_mode & ACE_DELETE) == 0)
 		return (0);
 
 	/*
+	 * Now zp_error should either be EACCES which indicates
+	 * a "deny" delete entry or ACCESS_UNDETERMINED if the "delete"
+	 * entry exists on the target.
+	 *
+	 * dzp_error should be either EACCES which indicates a "deny"
+	 * entry for delete_child or ACCESS_UNDETERMINED if no delete_child
+	 * entry exists.  If value is EACCES then we are done
+	 * and zfs_delete_final_check() will make the final decision
+	 * regarding to allow the delete.
+	 */
+
+	ASSERT(zp_error != 0 && dzp_error != 0);
+	if (dzp_error == EACCES)
+		return (zfs_delete_final_check(zp, dzp, cr));
+
+	/*
 	 * Third Row
+	 * Only need to check for write/execute on parent
 	 */
 
 	dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
@@ -1517,7 +1550,7 @@
 		return (dzp_error);
 
 	if ((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0)
-		goto sticky;
+		return (zfs_sticky_remove_access(dzp, zp, cr));
 
 	/*
 	 * Fourth Row
@@ -1525,18 +1558,9 @@
 
 	if (((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) != 0) &&
 	    ((zp_working_mode & ACE_DELETE) == 0))
-		goto sticky;
-
-	error = secpolicy_vnode_access(cr, ZTOV(zp),
-	    dzp->z_phys->zp_uid, S_IWRITE|S_IEXEC);
+		return (zfs_sticky_remove_access(dzp, zp, cr));
 
-	if (error)
-		return (error);
-
-sticky:
-	error = zfs_sticky_remove_access(dzp, zp, cr);
-
-	return (error);
+	return (zfs_delete_final_check(zp, dzp, cr));
 }
 
 int