ntsec: inheritance, sec_acl and chown

Pierre A. Humblet Pierre.Humblet@ieee.org
Thu Jan 9 03:35:00 GMT 2003


Corinna,

here are
- a refresh of what I had sent before the holidays.
- a fix for chown

Pierre

2003/01/07  Pierre Humblet  <pierre.humblet@ieee.org>

	* sec_acl.cc (search_ace): Use id == -1, instead of < 0, as wildcard.
	(setacl): Start the search for a matching default at the next entry.
	Invalidate the type of merged entries instead of clearing it.
	Use well_known_creator for default owner and owning group and do 
	not try to merge non-default and default entries in these cases.
	(getacl): Recognize well_known_creator for default owner and group.
	(acl_worker): Improve errno settings and streamline the nontsec case.
	* security.cc (write_sd): Remove the call to set_process_privilege.
	(alloc_sd): If the owner changes, call set_process_privilege and return
	immediately on failure. Change inheritance rules: on new directories add
	inherit only allow ACEs for creator_owner, creator_group and everyone. 
	Preserve all inheritances through chmod and chown calls. Introduce 
	isownergroup to implement the uid == gid case, to keep the inheritance 
	code simple. Do not initialize owner_sid and group_sid and stop using 
	the variable psd.
-------------- next part --------------
Index: sec_acl.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sec_acl.cc,v
retrieving revision 1.23
diff -u -p -r1.23 sec_acl.cc
--- sec_acl.cc	12 Dec 2002 03:09:38 -0000	1.23
+++ sec_acl.cc	9 Jan 2003 01:45:18 -0000
@@ -1,4 +1,4 @@
-/* secacl.cc: Sun compatible ACL functions.
+/* sec_acl.cc: Sun compatible ACL functions.

    Copyright 2000, 2001, 2002 Red Hat, Inc.

@@ -41,7 +41,7 @@ searchace (__aclent16_t *aclp, int nentr
   int i;

   for (i = 0; i < nentries; ++i)
-    if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id))
+    if ((aclp[i].a_type == type && (id == -1 || aclp[i].a_id == id))
 	|| !aclp[i].a_type)
       return i;
   return -1;
@@ -137,26 +137,31 @@ setacl (const char *file, int nentries,
        * inheritance bits is created.
        */
       if (!(aclbufp[i].a_type & ACL_DEFAULT)
-	  && (pos = searchace (aclbufp, nentries,
+	  && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
+          && (pos = searchace (aclbufp + i + 1, nentries - i - 1,
 			       aclbufp[i].a_type | ACL_DEFAULT,
 			       (aclbufp[i].a_type & (USER|GROUP))
 			       ? aclbufp[i].a_id : -1)) >= 0
-	  && aclbufp[pos].a_type
 	  && aclbufp[i].a_perm == aclbufp[pos].a_perm)
 	{
 	  inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
-	  /* This eliminates the corresponding default entry. */
-	  aclbufp[pos].a_type = 0;
+          /* This invalidates the corresponding default entry. */
+          aclbufp[pos].a_type = USER|GROUP|ACL_DEFAULT;
 	}
       switch (aclbufp[i].a_type)
 	{
 	case USER_OBJ:
-	case DEF_USER_OBJ:
 	  allow |= STANDARD_RIGHTS_ALL & ~DELETE;
 	  if (!add_access_allowed_ace (acl, ace_off++, allow,
 					owner, acl_len, inheritance))
 	    return -1;
 	  break;
+	case DEF_USER_OBJ:
+	  allow |= STANDARD_RIGHTS_ALL & ~DELETE;
+	  if (!add_access_allowed_ace (acl, ace_off++, allow,
+				       well_known_creator_owner_sid, acl_len, inheritance))
+	    return -1;
+	  break;
 	case USER:
 	case DEF_USER:
 	  if (!(pw = internal_getpwuid (aclbufp[i].a_id))
@@ -166,11 +171,15 @@ setacl (const char *file, int nentries,
 	    return -1;
 	  break;
 	case GROUP_OBJ:
-	case DEF_GROUP_OBJ:
 	  if (!add_access_allowed_ace (acl, ace_off++, allow,
 					group, acl_len, inheritance))
 	    return -1;
 	  break;
+	case DEF_GROUP_OBJ:
+	  if (!add_access_allowed_ace (acl, ace_off++, allow,
+				       well_known_creator_group_sid, acl_len, inheritance))
+	    return -1;
+	  break;
 	case GROUP:
 	case DEF_GROUP:
 	  if (!(gr = internal_getgrgid (aclbufp[i].a_id))
@@ -336,6 +345,16 @@ getacl (const char *file, DWORD attr, in
 	      type = USER_OBJ;
 	      id = uid;
 	    }
+	  else if (ace_sid == well_known_creator_group_sid)
+	    {
+	      type = GROUP_OBJ | ACL_DEFAULT;
+	      id = ILLEGAL_GID;
+	    }
+	  else if (ace_sid == well_known_creator_owner_sid)
+	    {
+	      type = USER_OBJ | ACL_DEFAULT;
+	      id = ILLEGAL_GID;
+	    }
 	  else
 	    {
 	      id = ace_sid.get_id (FALSE, &type);
@@ -352,7 +371,7 @@ getacl (const char *file, DWORD attr, in
 	    }
 	  if (!type)
 	    continue;
-	  if (!(ace->Header.AceFlags & INHERIT_ONLY))
+	  if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
 	    {
 	      if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
 		getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
@@ -360,6 +379,10 @@ getacl (const char *file, DWORD attr, in
 	  if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
 	      && (attr & FILE_ATTRIBUTE_DIRECTORY))
 	    {
+	      if (type == USER_OBJ)
+		type = USER;
+	      else if (type == GROUP_OBJ)
+		type = GROUP;
 	      type |= ACL_DEFAULT;
 	      types_def |= type;
 	      if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
@@ -475,45 +498,30 @@ acl_worker (const char *path, int cmd, i
 	  set_errno (ENOSYS);
 	  break;
 	case GETACL:
-	  if (nentries < 1)
-	    set_errno (EINVAL);
+	  if (!aclbufp)
+	    set_errno(EFAULT);
+	  else if (nentries < MIN_ACL_ENTRIES)
+	    set_errno (ENOSPC);
 	  else if ((nofollow && !lstat64 (path, &st))
 		   || (!nofollow && !stat64 (path, &st)))
 	    {
-	      __aclent16_t lacl[4];
-	      if (nentries > 0)
-		{
-		  lacl[0].a_type = USER_OBJ;
-		  lacl[0].a_id = st.st_uid;
-		  lacl[0].a_perm = (st.st_mode & S_IRWXU) >> 6;
-		}
-	      if (nentries > 1)
-		{
-		  lacl[1].a_type = GROUP_OBJ;
-		  lacl[1].a_id = st.st_gid;
-		  lacl[1].a_perm = (st.st_mode & S_IRWXG) >> 3;
-		}
-	      if (nentries > 2)
-		{
-		  lacl[2].a_type = OTHER_OBJ;
-		  lacl[2].a_id = ILLEGAL_GID;
-		  lacl[2].a_perm = st.st_mode & S_IRWXO;
-		}
-	      if (nentries > 3)
-		{
-		  lacl[3].a_type = CLASS_OBJ;
-		  lacl[3].a_id = ILLEGAL_GID;
-		  lacl[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
-		}
-	      if (nentries > 4)
-		nentries = 4;
-	      if (aclbufp)
-		memcpy (aclbufp, lacl, nentries * sizeof (__aclent16_t));
-	      ret = nentries;
+	      aclbufp[0].a_type = USER_OBJ;
+	      aclbufp[0].a_id = st.st_uid;
+	      aclbufp[0].a_perm = (st.st_mode & S_IRWXU) >> 6;
+	      aclbufp[1].a_type = GROUP_OBJ;
+	      aclbufp[1].a_id = st.st_gid;
+	      aclbufp[1].a_perm = (st.st_mode & S_IRWXG) >> 3;
+	      aclbufp[2].a_type = OTHER_OBJ;
+	      aclbufp[2].a_id = ILLEGAL_GID;
+	      aclbufp[2].a_perm = st.st_mode & S_IRWXO;
+	      aclbufp[3].a_type = CLASS_OBJ;
+	      aclbufp[3].a_id = ILLEGAL_GID;
+	      aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
+	      ret = MIN_ACL_ENTRIES;
 	    }
 	  break;
 	case GETACLCNT:
-	  ret = 4;
+	  ret = MIN_ACL_ENTRIES;
 	  break;
 	}
       syscall_printf ("%d = acl (%s)", ret, path);
@@ -527,19 +535,20 @@ acl_worker (const char *path, int cmd, i
 			 nentries, aclbufp);
 	break;
       case GETACL:
-	if (nentries < 1)
-	  break;
-	return getacl (real_path.get_win32 (),
-		       real_path.file_attributes (),
-		       nentries, aclbufp);
+	if (!aclbufp)
+	  set_errno(EFAULT);
+	else return getacl (real_path.get_win32 (),
+			    real_path.file_attributes (),
+			    nentries, aclbufp);
+	break;
       case GETACLCNT:
 	return getacl (real_path.get_win32 (),
 		       real_path.file_attributes (),
 		       0, NULL);
       default:
+	set_errno (EINVAL);
 	break;
     }
-  set_errno (EINVAL);
   syscall_printf ("-1 = acl (%s)", path);
   return -1;
 }
Index: security.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/security.cc,v
retrieving revision 1.129
diff -u -p -r1.129 security.cc
--- security.cc	14 Dec 2002 16:57:25 -0000	1.129
+++ security.cc	9 Jan 2003 01:47:03 -0000
@@ -1,4 +1,4 @@
-/* security.cc: NT security functions
+ /* security.cc: NT security functions

    Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.

@@ -1142,14 +1142,6 @@ write_sd (const char *file, PSECURITY_DE
       return -1;
     }

-  /* No need to be thread save. */
-  static BOOL first_time = TRUE;
-  if (first_time)
-    {
-      set_process_privilege (SE_RESTORE_NAME);
-      first_time = FALSE;
-    }
-
   HANDLE fh;
   fh = CreateFile (file,
 		   WRITE_OWNER | WRITE_DAC,
@@ -1548,7 +1540,7 @@ alloc_sd (__uid32_t uid, __gid32_t gid,
     debug_printf ("GetSecurityDescriptorGroup %E");

   /* Get SID of owner. */
-  cygsid owner_sid (NO_SID);
+  cygsid owner_sid;
   /* Check for current user first */
   if (uid == myself->uid)
     owner_sid = cygheap->user.sid ();
@@ -1561,8 +1553,13 @@ alloc_sd (__uid32_t uid, __gid32_t gid,
     }
   owner_sid.debug_print ("alloc_sd: owner SID =");

+  /* Must have SE_RESTORE_NAME privilege to change owner */
+  if (cur_owner_sid && owner_sid != cur_owner_sid
+      && set_process_privilege (SE_RESTORE_NAME) < 0 )
+    return NULL;
+
   /* Get SID of new group. */
-  cygsid group_sid (NO_SID);
+  cygsid group_sid;
   /* Check for current user first */
   if (gid == myself->gid)
     group_sid = cygheap->user.groups.pgsid;
@@ -1577,7 +1574,6 @@ alloc_sd (__uid32_t uid, __gid32_t gid,

   /* Initialize local security descriptor. */
   SECURITY_DESCRIPTOR sd;
-  PSECURITY_DESCRIPTOR psd = NULL;
   if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
     {
       __seterrno ();
@@ -1674,59 +1670,48 @@ alloc_sd (__uid32_t uid, __gid32_t gid,

   /* Add owner and group permissions if SIDs are equal
      and construct deny attributes for group and owner. */
-  DWORD group_deny;
-  if (owner_sid == group_sid)
-    {
-      owner_allow |= group_allow;
-      group_allow = group_deny = 0L;
-    }
-  else
-    {
-      group_deny = ~group_allow & other_allow;
-      group_deny &= ~(STANDARD_RIGHTS_READ
-		      | FILE_READ_ATTRIBUTES | FILE_READ_EA);
-    }
+  BOOL isownergroup;
+  if ((isownergroup = (owner_sid == group_sid)))
+    owner_allow |= group_allow;
+
   DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
   owner_deny &= ~(STANDARD_RIGHTS_READ
 		  | FILE_READ_ATTRIBUTES | FILE_READ_EA
 		  | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA);
-
-  /* Construct appropriate inherit attribute. */
-  DWORD inherit = (attribute & S_IFDIR) ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
-					: NO_INHERITANCE;
+
+  DWORD group_deny = ~group_allow & other_allow;
+  group_deny &= ~(STANDARD_RIGHTS_READ
+		  | FILE_READ_ATTRIBUTES | FILE_READ_EA);

   /* Set deny ACE for owner. */
   if (owner_deny
       && !add_access_denied_ace (acl, ace_off++, owner_deny,
-				 owner_sid, acl_len, inherit))
+				 owner_sid, acl_len, NO_INHERITANCE))
     return NULL;
   /* Set deny ACE for group here to respect the canonical order,
      if this does not impact owner */
-  if (group_deny && !(owner_allow & group_deny))
-    {
-      if (!add_access_denied_ace (acl, ace_off++, group_deny,
-				 group_sid, acl_len, inherit))
-	return NULL;
-      group_deny = 0;
-    }
+  if (group_deny && !(group_deny & owner_allow) && !isownergroup
+      && !add_access_denied_ace (acl, ace_off++, group_deny,
+				 group_sid, acl_len, NO_INHERITANCE))
+    return NULL;
   /* Set allow ACE for owner. */
   if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
-			       owner_sid, acl_len, inherit))
+			       owner_sid, acl_len, NO_INHERITANCE))
     return NULL;
   /* Set deny ACE for group, if still needed. */
-  if (group_deny
+  if (group_deny & owner_allow && !isownergroup
       && !add_access_denied_ace (acl, ace_off++, group_deny,
-				 group_sid, acl_len, inherit))
+				 group_sid, acl_len, NO_INHERITANCE))
     return NULL;
   /* Set allow ACE for group. */
-  if (group_allow
+  if (!isownergroup
       && !add_access_allowed_ace (acl, ace_off++, group_allow,
-				  group_sid, acl_len, inherit))
+				  group_sid, acl_len, NO_INHERITANCE))
     return NULL;

   /* Set allow ACE for everyone. */
   if (!add_access_allowed_ace (acl, ace_off++, other_allow,
-			       well_known_world_sid, acl_len, inherit))
+			       well_known_world_sid, acl_len, NO_INHERITANCE))
     return NULL;
   /* Set null ACE for special bits. */
   if (null_allow
@@ -1736,7 +1721,7 @@ alloc_sd (__uid32_t uid, __gid32_t gid,

   /* Fill ACL with unrelated ACEs from current security descriptor. */
   PACL oacl;
-  BOOL acl_exists;
+  BOOL acl_exists = FALSE;
   ACCESS_ALLOWED_ACE *ace;
   if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy)
       && acl_exists && oacl)
@@ -1745,19 +1730,26 @@ alloc_sd (__uid32_t uid, __gid32_t gid,
 	{
 	  cygsid ace_sid ((PSID) &ace->SidStart);
 	  /* Check for related ACEs. */
+	  if (ace_sid == well_known_null_sid)
+	    continue;
 	  if ((ace_sid == cur_owner_sid)
 	      || (ace_sid == owner_sid)
 	      || (ace_sid == cur_group_sid)
 	      || (ace_sid == group_sid)
-	      || (ace_sid == well_known_world_sid)
-	      || (ace_sid == well_known_null_sid))
-	    continue;
+	      || (ace_sid == well_known_world_sid))
+	    {
+	      if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
+		ace->Header.AceFlags |= INHERIT_ONLY;
+	      else
+		continue;
+	    }
 	  /*
 	   * Add unrelated ACCESS_DENIED_ACE to the beginning but
 	   * behind the owner_deny, ACCESS_ALLOWED_ACE to the end.
+	   * FIXME: this would break the order of the inherit_only ACEs
 	   */
 	  if (!AddAce (acl, ACL_REVISION,
-		       ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ?
+		       ace->Header.AceType == ACCESS_DENIED_ACE_TYPE?
 		       (owner_deny ? 1 : 0) : MAXDWORD,
 		       (LPVOID) ace, ace->Header.AceSize))
 	    {
@@ -1767,6 +1759,46 @@ alloc_sd (__uid32_t uid, __gid32_t gid,
 	  acl_len += ace->Header.AceSize;
 	}

+  /* Construct appropriate inherit attribute for new directories */
+  if (attribute & S_IFDIR && !acl_exists )
+    {
+      const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY;
+
+#if 0 /* FIXME: Not done currently as this breaks the canonical order */
+      /* Set deny ACE for owner. */
+      if (owner_deny
+	  && !add_access_denied_ace (acl, ace_off++, owner_deny,
+				     well_known_creator_owner_sid, acl_len, inherit))
+	return NULL;
+      /* Set deny ACE for group here to respect the canonical order,
+	 if this does not impact owner */
+      if (group_deny && !(group_deny & owner_allow)
+	  && !add_access_denied_ace (acl, ace_off++, group_deny,
+				     well_known_creator_group_sid, acl_len, inherit))
+	return NULL;
+#endif
+      /* Set allow ACE for owner. */
+      if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
+				   well_known_creator_owner_sid, acl_len, inherit))
+	return NULL;
+#if 0 /* FIXME: Not done currently as this breaks the canonical order and
+	 won't be preserved on chown and chmod */
+      /* Set deny ACE for group, conflicting with owner_allow. */
+      if (group_deny & owner_allow
+	  && !add_access_denied_ace (acl, ace_off++, group_deny,
+				     well_known_creator_group_sid, acl_len, inherit))
+	return NULL;
+#endif
+      /* Set allow ACE for group. */
+      if (!add_access_allowed_ace (acl, ace_off++, group_allow,
+				   well_known_creator_group_sid, acl_len, inherit))
+	return NULL;
+      /* Set allow ACE for everyone. */
+      if (!add_access_allowed_ace (acl, ace_off++, other_allow,
+				   well_known_world_sid, acl_len, inherit))
+	return NULL;
+    }
+
   /* Set AclSize to computed value. */
   acl->AclSize = acl_len;
   debug_printf ("ACL-Size: %d", acl_len);
@@ -1791,10 +1823,9 @@ alloc_sd (__uid32_t uid, __gid32_t gid,
       __seterrno ();
       return NULL;
     }
-  psd = sd_ret;
   debug_printf ("Created SD-Size: %d", *sd_size_ret);

-  return psd;
+  return sd_ret;
 }

 void


More information about the Cygwin-patches mailing list