This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] Preliminary read side implementation of new permission handling.


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=52f01a0ff8f06ec1f15ab576867da3abf577e891

commit 52f01a0ff8f06ec1f15ab576867da3abf577e891
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Wed Mar 18 17:49:12 2015 +0100

    Preliminary read side implementation of new permission handling.
    
    	* acl.h (MAX_ACL_ENTRIES): Raise to 2730.  Add comment to explain.
    	* sec_acl.cc:  Add leading comment to explain new ACL style.
    	Add definitions and macros to use for bits in new Cygwin ACL.
    	(DENY_RWX): New mask value for all temporary deny bits.
    	(getace): Add bool parameter to decide when leaving all bits intact,
    	rather than filtering them per the already set bits.
    	(get_posix_access): New function, taking over functionality to read
    	POSIX ACL from SECURITY_DESCRIPTOR.
    	(getacl): Just call get_posix_access.
    	* sec_helper.cc (well_known_cygwin_sid): Define.
    	* security.cc (get_attribute_from_acl): Remove.
    	(get_info_from_sd): Remove.
    	(get_reg_sd): Call get_posix_access instead of get_info_from_sd.
    	(get_file_attribute): Ditto.
    	(get_object_attribute): Ditto.
    	* security.h (well_known_cygwin_sid): Declare.
    	(get_posix_access): Add prototype.
    
    	* Throughout, use simpler ACE macros from Windows' accctrl.h.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/ChangeLog            |  23 ++
 winsup/cygwin/include/cygwin/acl.h |  12 +-
 winsup/cygwin/sec_acl.cc           | 496 ++++++++++++++++++++++++++-----------
 winsup/cygwin/sec_helper.cc        |  11 +-
 winsup/cygwin/security.cc          | 204 +--------------
 winsup/cygwin/security.h           |   3 +
 6 files changed, 394 insertions(+), 355 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index bd9e71f..5d45cdc 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,28 @@
 2015-03-18  Corinna Vinschen  <corinna@vinschen.de>
 
+	Preliminary read side implementation of new permission handling.
+	* acl.h (MAX_ACL_ENTRIES): Raise to 2730.  Add comment to explain.
+	* sec_acl.cc:  Add leading comment to explain new ACL style.
+	Add definitions and macros to use for bits in new Cygwin ACL.
+	(DENY_RWX): New mask value for all temporary deny bits.
+	(getace): Add bool parameter to decide when leaving all bits intact,
+	rather than filtering them per the already set bits.
+	(get_posix_access): New function, taking over functionality to read
+	POSIX ACL from SECURITY_DESCRIPTOR.
+	(getacl): Just call get_posix_access.
+	* sec_helper.cc (well_known_cygwin_sid): Define.
+	* security.cc (get_attribute_from_acl): Remove.
+	(get_info_from_sd): Remove.
+	(get_reg_sd): Call get_posix_access instead of get_info_from_sd.
+	(get_file_attribute): Ditto.
+	(get_object_attribute): Ditto.
+	* security.h (well_known_cygwin_sid): Declare.
+	(get_posix_access): Add prototype.
+
+	* Throughout, use simpler ACE macros from Windows' accctrl.h.
+
+2015-03-18  Corinna Vinschen  <corinna@vinschen.de>
+
 	* grp.cc (pwdgrp::parse_group): Call cygsid::getfromgr_passwd.
 	* passwd.cc (pwdgrp::parse_passwd): Call cygsid::getfrompw_gecos.
 	* pwdgrp.h (cygsid::getfrompw): Implement as inline method here,
diff --git a/winsup/cygwin/include/cygwin/acl.h b/winsup/cygwin/include/cygwin/acl.h
index 8fa5a65..dcdfc00 100644
--- a/winsup/cygwin/include/cygwin/acl.h
+++ b/winsup/cygwin/include/cygwin/acl.h
@@ -1,6 +1,6 @@
 /* cygwin/acl.h header file for Cygwin.
 
-   Copyright 1999, 2000, 2001, 2002, 2010, 2014 Red Hat, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2010, 2014, 2015 Red Hat, Inc.
    Written by C. Vinschen.
 
 This file is part of Cygwin.
@@ -25,8 +25,16 @@ extern "C" {
 #define GETACL          (0x1)
 #define GETACLCNT       (0x2)
 
+/* Windows ACLs have a maximum size of 64K.  Counting the most pessimistic way,
+   the maximum number of ACEs is 3276.  Technet claims "approximately 1820",
+   which uses the length of normal user and group SIDs for the computation. 
+   We're now going with 2730, the number of aclent_t entries matching a 32K
+   buffer.
+   On one hand, there are only a limited number of SIDs shorter than the normal
+   user/group SIDs, on the other hand there are no deny aclent_t entries, so we
+   should be fine with 32K aclbuf_t buffers provided by the caller. */
 #define	MIN_ACL_ENTRIES (3)    // minimal acl entries from GETACLCNT
-#define	MAX_ACL_ENTRIES	(256)  // max entries of each type
+#define	MAX_ACL_ENTRIES	(2730) // max entries of each type
 
 // Return values of aclcheck(3) in case of error */
 #define GRP_ERROR       (0x1)
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index e5019cb..a93e191 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -24,6 +24,64 @@ details. */
 #include "ntdll.h"
 #include "tls_pbuf.h"
 
+/* How does a correctly constructed new-style Windows ACL claiming to be a
+   POSIX ACL look like?
+
+   - Cygwin ACE (special bits, CLASS_OBJ).
+
+   - If a USER entry has more permissions than any group, Everyone, or if it
+     has more permissions than allowed by the CLASS_OBJ entry:
+
+     USER      deny ACEs   == POSIX allow
+			      & ^(mask | all group allows | Everyone allow)
+
+   - USER_OBJ  allow ACE
+   - USER      allow ACEs
+
+     The POSIX permissions returned for a USER entry are the allow bits alone!
+
+   - If a GROUP entry has more permissions than Everyone, or if it has more
+     permissions than allowed by the CLASS_OBJ entry:
+
+     GROUP	deny ACEs  == POSIX allow & ^(mask | Everyone allow)
+
+   - GROUP_OBJ	allow ACE
+   - GROUP	allow ACEs
+
+     The POSIX permissions returned for a GROUP entry are the allow bits alone!
+
+   - OTHER_OBJ	allow ACE
+
+   Rinse and repeat for default ACEs with INHERIT flags set.
+
+   - Default Cygwin ACE (S_ISGID, CLASS_OBJ). */
+
+						/* POSIX <-> Win32 */
+
+/* Historically, these bits are stored in a NULL SID ACE.  To distinguish
+   the new ACL style from the old one, we're now using an invented SID, the
+   Cygwin SID (S-1-0-1132029815).  The new ACEs can exist twice in an ACL,
+   the "normal one" containg CLASS_OBJ and special bits, and the one with
+   INHERIT bit set to pass the DEF_CLASS_OBJ bits and the S_ISGID bit on. */
+#define CYG_ACE_ISVTX		0x001		/* 0x200 <-> 0x001 */
+#define CYG_ACE_ISGID		0x002		/* 0x400 <-> 0x002 */
+#define CYG_ACE_ISUID		0x004		/* 0x800 <-> 0x004 */
+#define CYG_ACE_ISBITS_TO_POSIX(val)	\
+				(((val) & 0x007) << 9)
+#define CYG_ACE_ISBITS_TO_WIN(val) \
+				(((val) & (S_ISVTX | S_ISUID | S_IS_GID)) >> 9)
+
+#define CYG_ACE_MASK_X		0x008		/* 0x001 <-> 0x008 */
+#define CYG_ACE_MASK_W		0x010		/* 0x002 <-> 0x010 */
+#define CYG_ACE_MASK_R		0x020		/* 0x004 <-> 0x020 */
+#define CYG_ACE_MASK_RWX	0x038
+#define CYG_ACE_MASK_VALID	0x040		/* has mask if set */
+#define CYG_ACE_MASK_TO_POSIX(val)	\
+				(((val) & CYG_ACE_MASK_RWX) >> 3)
+#define CYG_ACE_MASK_TO_WIN(val)	\
+				((((val) & S_IRWXO) << 3) \
+				 | CYG_ACE_MASK_VALID)
+
 static int
 searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID)
 {
@@ -235,8 +293,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
 	allow |= FILE_DELETE_CHILD;
       /* Set inherit property. */
       DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
-			  ? (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
-			     | INHERIT_ONLY_ACE)
+			  ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
 			  : NO_INHERITANCE;
       /*
        * If a specific acl contains a corresponding default entry with
@@ -251,7 +308,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
 			       ? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
 	  && aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
 	{
-	  inheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
+	  inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
 	  /* invalidate the corresponding default entry. */
 	  invalid[i + 1 + pos] = true;
 	}
@@ -337,15 +394,19 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
 #define DENY_R 040000
 #define DENY_W 020000
 #define DENY_X 010000
+#define DENY_RWX (DENY_R | DENY_W | DENY_X)
 
+/* New style ACL means, just read the bits and store them away.  Don't
+   create masked values on your own. */
 static void
 getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
-	DWORD win_ace_type)
+	DWORD win_ace_type, bool new_style)
 {
   acl.a_type = type;
   acl.a_id = id;
 
-  if ((win_ace_mask & FILE_READ_BITS) && !(acl.a_perm & (S_IROTH | DENY_R)))
+  if ((win_ace_mask & FILE_READ_BITS)
+      && (new_style || !(acl.a_perm & (S_IROTH | DENY_R))))
     {
       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
 	acl.a_perm |= S_IROTH;
@@ -353,7 +414,8 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
 	acl.a_perm |= DENY_R;
     }
 
-  if ((win_ace_mask & FILE_WRITE_BITS) && !(acl.a_perm & (S_IWOTH | DENY_W)))
+  if ((win_ace_mask & FILE_WRITE_BITS)
+      && (new_style || !(acl.a_perm & (S_IWOTH | DENY_W))))
     {
       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
 	acl.a_perm |= S_IWOTH;
@@ -361,7 +423,8 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
 	acl.a_perm |= DENY_W;
     }
 
-  if ((win_ace_mask & FILE_EXEC_BITS) && !(acl.a_perm & (S_IXOTH | DENY_X)))
+  if ((win_ace_mask & FILE_EXEC_BITS)
+      && (new_style || !(acl.a_perm & (S_IXOTH | DENY_X))))
     {
       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
 	acl.a_perm |= S_IXOTH;
@@ -370,40 +433,92 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
     }
 }
 
+/* From the SECURITY_DESCRIPTOR given in psd, compute user, owner, posix
+   attributes, as well as the POSIX acl.  The function returns the number
+   of entries returned in aclbufp, or -1 in case of error. */
 int
-getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
+get_posix_access (PSECURITY_DESCRIPTOR psd,
+		  mode_t *attr_ret, uid_t *uid_ret, gid_t *gid_ret,
+		  aclent_t *aclbufp, int nentries)
 {
-  security_descriptor sd;
-
-  if (get_file_sd (handle, pc, sd, false))
-    return -1;
-
-  cygpsid owner_sid;
-  cygpsid group_sid;
+  tmp_pathbuf tp;
   NTSTATUS status;
-  BOOLEAN dummy;
+  BOOLEAN dummy, acl_exists;
+  PACL acl;
+  PACCESS_ALLOWED_ACE ace;
+  cygpsid owner_sid, group_sid;
+  cyg_ldap cldap;
   uid_t uid;
   gid_t gid;
-  cyg_ldap cldap;
+  mode_t attr = 0;
+  aclent_t *lacl = NULL;
+  cygpsid ace_sid;
+  int pos, type, id;
+
+  bool new_style = false;
+  int types_def = 0;
+  int def_pgrp_pos = -1;
+  bool has_class_perm = false, has_def_class_perm = false;
+  mode_t class_perm = 0, def_class_perm = 0;
 
-  status = RtlGetOwnerSecurityDescriptor (sd, (PSID *) &owner_sid, &dummy);
+  if (aclbufp && nentries < MIN_ACL_ENTRIES)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  /* If reading the security descriptor failed, treat the object as
+     unreadable. */
+  if (!psd)
+    {
+      if (attr_ret)
+        *attr_ret &= S_IFMT;
+      if (uid_ret)
+        *uid_ret = ILLEGAL_UID;
+      if (gid_ret)
+        *gid_ret = ILLEGAL_GID;
+      if (aclbufp)
+	{
+	  aclbufp[0].a_type = USER_OBJ;
+	  aclbufp[0].a_id = ILLEGAL_UID;
+	  aclbufp[0].a_perm = 0;
+	  aclbufp[1].a_type = GROUP_OBJ;
+	  aclbufp[1].a_id = ILLEGAL_GID;
+	  aclbufp[1].a_perm = 0;
+	  aclbufp[2].a_type = OTHER_OBJ;
+	  aclbufp[2].a_id = ILLEGAL_GID;
+	  aclbufp[2].a_perm = 0;
+	  return MIN_ACL_ENTRIES;
+	}
+      return 0;
+    }
+  /* Fetch owner, group, and ACL from security descriptor. */
+  status = RtlGetOwnerSecurityDescriptor (psd, (PSID *) &owner_sid, &dummy);
   if (!NT_SUCCESS (status))
     {
       __seterrno_from_nt_status (status);
       return -1;
     }
-  uid = owner_sid.get_uid (&cldap);
-
-  status = RtlGetGroupSecurityDescriptor (sd, (PSID *) &group_sid, &dummy);
+  status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy);
+  if (!NT_SUCCESS (status))
+    {
+      __seterrno_from_nt_status (status);
+      return -1;
+    }
+  status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy);
   if (!NT_SUCCESS (status))
     {
       __seterrno_from_nt_status (status);
       return -1;
     }
+  /* Set uidret, gidret, and initalize attributes. */
+  uid = owner_sid.get_uid (&cldap);
   gid = group_sid.get_gid (&cldap);
+  if (attr_ret)
+    attr |= (*attr_ret & S_IFMT);
 
-  aclent_t lacl[MAX_ACL_ENTRIES];
-  memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t));
+  /* Create and initialize local aclent_t array. */
+  lacl = (aclent_t *) tp.c_get ();
+  memset (lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t *));
   lacl[0].a_type = USER_OBJ;
   lacl[0].a_id = uid;
   lacl[1].a_type = GROUP_OBJ;
@@ -411,102 +526,127 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
   lacl[2].a_type = OTHER_OBJ;
   lacl[2].a_id = ILLEGAL_GID;
 
-  PACL acl;
-  BOOLEAN acl_exists;
-
-  status = RtlGetDaclSecurityDescriptor (sd, &acl_exists, &acl, &dummy);
-  if (!NT_SUCCESS (status))
+  /* No ACEs?  Everybody has full access. */
+  if (!acl_exists || !acl || acl->AceCount == 0)
     {
-      __seterrno_from_nt_status (status);
-      return -1;
+      for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos)
+	lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
+      goto out;
     }
 
-  int pos, i, types_def = 0;
-  int pgrp_pos = 1, def_pgrp_pos = -1;
-  bool has_class_perm = false, has_def_class_perm = false;
-  mode_t class_perm = 0, def_class_perm = 0;
-
-  if (!acl_exists || !acl)
-    for (pos = 0; pos < 3; ++pos)
-      lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
-  else
+  for (int i = 0; i < acl->AceCount; ++i)
     {
-      for (i = 0; i < acl->AceCount; ++i)
-	{
-	  ACCESS_ALLOWED_ACE *ace;
-
-	  if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
-	    continue;
+      if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
+	continue;
 
-	  cygpsid ace_sid ((PSID) &ace->SidStart);
-	  int id;
-	  int type = 0;
+      ace_sid = (PSID) &ace->SidStart;
 
-	  if (ace_sid == well_known_null_sid)
-	    {
-	      /* Simply ignore. */
-	      continue;
-	    }
-	  if (ace_sid == well_known_world_sid)
-	    {
-	      type = OTHER_OBJ;
-	      id = ILLEGAL_GID;
-	    }
-	  else if (ace_sid == owner_sid)
-	    {
-	      type = USER_OBJ;
-	      id = uid;
-	    }
-	  else if (ace_sid == group_sid)
-	    {
-	      type = GROUP_OBJ;
-	      id = gid;
-	    }
-	  else if (ace_sid == well_known_creator_group_sid)
-	    {
-	      type = DEF_GROUP_OBJ;
-	      types_def |= type;
-	      id = ILLEGAL_GID;
-	    }
-	  else if (ace_sid == well_known_creator_owner_sid)
+      if (ace_sid == well_known_null_sid)
+	{
+	  /* Old-style or non-Cygwin ACL.  Fetch only the special bits. */
+	  attr |= CYG_ACE_ISBITS_TO_POSIX (ace->Mask);
+	  continue;
+	}
+      if (ace_sid == well_known_cygwin_sid)
+	{
+	  /* New-style ACL.  Note the fact that a mask value is present since
+	     that changes how getace fetches the information.  That's fine,
+	     because the Cygwin SID ACE is supposed to precede all USER, GROUP
+	     and GROUP_OBJ entries.  Any ACL not created that way has been
+	     rearranged by the Windows functionality to create the brain-dead
+	     "canonical" ACL order and is broken anyway. */
+	  attr |= CYG_ACE_ISBITS_TO_POSIX (ace->Mask);
+	  if (ace->Mask & CYG_ACE_MASK_VALID)
 	    {
-	      type = DEF_USER_OBJ;
-	      types_def |= type;
-	      id = ILLEGAL_GID;
+	      new_style = true;
+	      type = (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
+		     ? DEF_CLASS_OBJ : CLASS_OBJ;
+	      if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, ILLEGAL_GID))
+		  >= 0)
+		{
+		  lacl[pos].a_type = type;
+		  lacl[pos].a_id = ILLEGAL_GID;
+		  lacl[pos].a_perm = CYG_ACE_MASK_TO_POSIX (ace->Mask);
+		}
+	      if (type == CLASS_OBJ)	/* Needed for POSIX permissions. */
+		{
+		  has_class_perm = true;
+		  class_perm = lacl[pos].a_perm;
+		}
+	      else
+		{
+		  has_def_class_perm = true;
+		  def_class_perm = lacl[pos].a_perm;
+		}
 	    }
-	  else
-	    id = ace_sid.get_id (TRUE, &type, &cldap);
-
+	  continue;
+	}
+      else if (ace_sid == owner_sid)
+	{
+	  type = USER_OBJ;
+	  id = uid;
+	}
+      else if (ace_sid == group_sid)
+	{
+	  type = GROUP_OBJ;
+	  id = gid;
+	}
+      else if (ace_sid == well_known_world_sid)
+	{
+	  type = OTHER_OBJ;
+	  id = ILLEGAL_GID;
+	}
+      else if (ace_sid == well_known_creator_owner_sid)
+	{
+	  type = DEF_USER_OBJ;
+	  types_def |= type;
+	  id = ILLEGAL_GID;
+	}
+      else if (ace_sid == well_known_creator_group_sid)
+	{
+	  type = DEF_GROUP_OBJ;
+	  types_def |= type;
+	  id = ILLEGAL_GID;
+	}
+      else
+	{
+	  id = ace_sid.get_id (TRUE, &type, &cldap);
 	  if (!type)
 	    continue;
-	  if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE || type & ACL_DEFAULT))
+	}
+      if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
+	{
+	  if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
 	    {
-	      if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
+	      getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType,
+		      new_style && type & (USER | GROUP));
+	      if (!new_style)
 		{
-		  getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
 		  /* Fix up CLASS_OBJ value. */
-		  if (type == USER || type == GROUP)
+		  if (type & (USER | GROUP))
 		    {
 		      has_class_perm = true;
 		      class_perm |= lacl[pos].a_perm;
 		    }
 		}
 	    }
-	  if ((ace->Header.AceFlags
-	      & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))
-	      && pc.isdir ())
+	}
+      if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT))
+	{
+	  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)
 	    {
-	      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)
+	      getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType,
+		      new_style && type & (USER | GROUP));
+	      if (!new_style)
 		{
-		  getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
 		  /* Fix up DEF_CLASS_OBJ value. */
-		  if (type == DEF_USER || type == DEF_GROUP)
+		  if (type & (USER | GROUP))
 		    {
 		      has_def_class_perm = true;
 		      def_class_perm |= lacl[pos].a_perm;
@@ -517,80 +657,134 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
 		}
 	    }
 	}
-      /* If secondary user and group entries exist in the ACL, fake a matching
-	 CLASS_OBJ entry. The CLASS_OBJ permissions are the or'ed permissions
-	 of the primary group permissions and all secondary user and group
-	 permissions. */
-      if (has_class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+    }
+  /* If this is an old-style or non-Cygwin ACL, and secondary user and group
+     entries exist in the ACL, fake a matching CLASS_OBJ entry. The CLASS_OBJ
+     permissions are the or'ed permissions of the primary group permissions
+     and all secondary user and group permissions. */
+  if (!new_style && has_class_perm
+      && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+    {
+      lacl[pos].a_type = CLASS_OBJ;
+      lacl[pos].a_id = ILLEGAL_GID;
+      lacl[pos].a_perm = class_perm | lacl[1].a_perm;
+    }
+  /* Ensure that the default acl contains at least
+     DEF_(USER|GROUP|OTHER)_OBJ entries.  */
+  if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+    {
+      if (!(types_def & USER_OBJ))
 	{
-	  lacl[pos].a_type = CLASS_OBJ;
-	  lacl[pos].a_id = ILLEGAL_GID;
-	  lacl[pos].a_perm = class_perm | lacl[pgrp_pos].a_perm;
+	  lacl[pos].a_type = DEF_USER_OBJ;
+	  lacl[pos].a_id = uid;
+	  lacl[pos].a_perm = lacl[0].a_perm;
+	  pos++;
 	}
-      /* Ensure that the default acl contains at least
-      	 DEF_(USER|GROUP|OTHER)_OBJ entries.  */
-      if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+      if (!(types_def & GROUP_OBJ) && pos < MAX_ACL_ENTRIES)
 	{
-	  if (!(types_def & USER_OBJ))
-	    {
-	      lacl[pos].a_type = DEF_USER_OBJ;
-	      lacl[pos].a_id = uid;
-	      lacl[pos].a_perm = lacl[0].a_perm;
-	      pos++;
-	    }
-	  if (!(types_def & GROUP_OBJ) && pos < MAX_ACL_ENTRIES)
-	    {
-	      lacl[pos].a_type = DEF_GROUP_OBJ;
-	      lacl[pos].a_id = gid;
-	      lacl[pos].a_perm = lacl[1].a_perm;
-	      /* Note the position of the DEF_GROUP_OBJ entry. */
-	      def_pgrp_pos = pos;
-	      pos++;
-	    }
-	  if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
-	    {
-	      lacl[pos].a_type = DEF_OTHER_OBJ;
-	      lacl[pos].a_id = ILLEGAL_GID;
-	      lacl[pos].a_perm = lacl[2].a_perm;
-	      pos++;
-	    }
+	  lacl[pos].a_type = DEF_GROUP_OBJ;
+	  lacl[pos].a_id = gid;
+	  lacl[pos].a_perm = lacl[1].a_perm;
+	  /* Note the position of the DEF_GROUP_OBJ entry. */
+	  def_pgrp_pos = pos;
+	  pos++;
 	}
-      /* If secondary user default and group default entries exist in the ACL,
-	 fake a matching DEF_CLASS_OBJ entry. The DEF_CLASS_OBJ permissions are
-	 the or'ed permissions of the primary group default permissions and all
-	 secondary user and group default permissions. */
-      if (has_def_class_perm
-	  && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+      if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
 	{
-	  lacl[pos].a_type = DEF_CLASS_OBJ;
+	  lacl[pos].a_type = DEF_OTHER_OBJ;
 	  lacl[pos].a_id = ILLEGAL_GID;
-	  lacl[pos].a_perm = def_class_perm;
-	  if (def_pgrp_pos >= 0)
-	    lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
+	  lacl[pos].a_perm = lacl[2].a_perm;
+	  pos++;
 	}
     }
+  /* If this is an old-style or non-Cygwin ACL, and secondary user default
+     and group default entries exist in the ACL, fake a matching DEF_CLASS_OBJ
+     entry. The DEF_CLASS_OBJ permissions are the or'ed permissions of the
+     primary group default permissions and all secondary user and group def.
+     permissions. */
+  if (!new_style && has_def_class_perm
+      && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
+    {
+      lacl[pos].a_type = DEF_CLASS_OBJ;
+      lacl[pos].a_id = ILLEGAL_GID;
+      lacl[pos].a_perm = def_class_perm;
+      if (def_pgrp_pos >= 0)
+	lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
+    }
+
+  /* Make sure `pos' contains the number of used entries in lacl. */
   if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
     pos = MAX_ACL_ENTRIES;
+
+  /* For old-style or non-Cygwin ACLs, check for merging permissions. */
+  if (!new_style)
+    for (int i = 0; i < pos; ++i)
+      {
+	/* Current user?  If the user entry has a deny ACE, don't check. */
+	if (lacl[i].a_id == myself->uid
+	    && lacl[i].a_type & (USER_OBJ | USER)
+	    && !(lacl[i].a_type & ACL_DEFAULT)
+	    && !(lacl[i].a_perm & DENY_RWX))
+	  {
+	    int gpos;
+	    gid_t grps[NGROUPS_MAX];
+	    cyg_ldap cldap;
+
+	    /* Sum up all permissions of groups the user is member of, plus
+	       everyone perms, and merge them to user perms.  */
+	    mode_t grp_perm = lacl[2].a_perm & S_IRWXO;
+	    int gnum = internal_getgroups (NGROUPS_MAX, grps, &cldap);
+	    for (int g = 0; g < gnum && grp_perm != S_IRWXO; ++g)
+	      if ((gpos = 1, grps[g] == lacl[gpos].a_id)
+		  || (gpos = searchace (lacl, MAX_ACL_ENTRIES, GROUP, grps[g]))
+		     >= 0)
+		grp_perm |= lacl[gpos].a_perm & S_IRWXO;
+	    lacl[i].a_perm |= grp_perm;
+	  }
+	/* For all groups, if everyone has more permissions, add everyone
+	   perms to group perms.  Skip groups with deny ACE. */
+	else if (lacl[i].a_id & (GROUP_OBJ | GROUP)
+		 && !(lacl[i].a_type & ACL_DEFAULT)
+		 && !(lacl[i].a_perm & DENY_RWX))
+	  lacl[i].a_perm |= lacl[2].a_perm & S_IRWXO;
+      }
+  /* Construct POSIX permission bits.  Fortunately we know exactly where
+     to fetch the affecting bits from, at least as long as the array
+     hasn't been sorted. */
+  attr |= (lacl[0].a_perm & S_IRWXO) << 6;
+  attr |= (has_class_perm ? class_perm : (lacl[1].a_perm & S_IRWXO)) << 3;
+  attr |= (lacl[2].a_perm & S_IRWXO);
+
+out:
+  if (uid_ret)
+    *uid_ret = uid;
+  if (gid_ret)
+    *gid_ret = gid;
+  if (attr_ret)
+    *attr_ret = attr;
   if (aclbufp)
     {
-#if 0
-      /* Disable owner/group permissions equivalence if owner SID == group SID.
-	 It's technically not quite correct, but it helps in case a security
-	 conscious application checks if a file has too open permissions.  In
-	 fact, since owner == group, there's no security issue here. */
-      if (owner_sid == group_sid)
-	lacl[1].a_perm = lacl[0].a_perm;
-#endif
       if (pos > nentries)
 	{
 	  set_errno (ENOSPC);
 	  return -1;
 	}
       memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
-      for (i = 0; i < pos; ++i)
-	aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
+      for (int i = 0; i < pos; ++i)
+	aclbufp[i].a_perm &= S_IRWXO;
       aclsort32 (pos, 0, aclbufp);
     }
+  return pos;
+}
+
+int
+getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
+{
+  security_descriptor sd;
+
+  if (get_file_sd (handle, pc, sd, false))
+    return -1;
+  int pos = get_posix_access (sd, NULL, NULL, NULL, aclbufp, nentries);
   syscall_printf ("%R = getacl(%S)", pos, pc.get_nt_native_path ());
   return pos;
 }
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index 679f3a8..1ea69c3 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -40,6 +40,8 @@ SECURITY_ATTRIBUTES NO_COPY_RO sec_all_nih =
 
 MKSID (well_known_null_sid, "S-1-0-0",
        SECURITY_NULL_SID_AUTHORITY, 1, SECURITY_NULL_RID);
+MKSID (well_known_cygwin_sid, "S-1-0-1132029815",
+       SECURITY_NULL_SID_AUTHORITY, 1, 0x43796777); /* "Cygw" */
 MKSID (well_known_world_sid, "S-1-1-0",
        SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID);
 MKSID (well_known_local_sid, "S-1-2-0",
@@ -616,22 +618,21 @@ _recycler_sd (void *buf, bool users, bool dir)
      pre-Vista permissions the same way as on Vista and later. */
   RtlCreateAcl (dacl, MAX_DACL_LEN (3), ACL_REVISION);
   RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
-			    dir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
+			    dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
 				: NO_INHERITANCE,
 			    FILE_ALL_ACCESS, well_known_admins_sid);
   RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
-			    dir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
+			    dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
 				: NO_INHERITANCE,
 			    FILE_ALL_ACCESS, well_known_system_sid);
   if (users)
-    RtlAddAccessAllowedAceEx (dacl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE,
+    RtlAddAccessAllowedAceEx (dacl, ACL_REVISION, INHERIT_NO_PROPAGATE,
 			      FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
 			      | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES,
 			      well_known_users_sid);
   else
     RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
-			      dir ? CONTAINER_INHERIT_ACE
-				    | OBJECT_INHERIT_ACE
+			      dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
 				  : NO_INHERITANCE,
 			      FILE_ALL_ACCESS, cygheap->user.sid ());
   LPVOID ace;
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 1bc0c50..e6cbd4c 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -234,194 +234,6 @@ set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown)
   return res;
 }
 
-static void
-get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
-			PSID group_sid, bool grp_member)
-{
-  ACCESS_ALLOWED_ACE *ace;
-  mode_t allow = 0;
-  mode_t deny = 0;
-  mode_t *flags, *anti;
-  bool isownergroup = RtlEqualSid (owner_sid, group_sid);
-
-  for (DWORD i = 0; i < acl->AceCount; ++i)
-    {
-      if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
-	continue;
-      if (ace->Header.AceFlags & INHERIT_ONLY_ACE)
-	continue;
-      switch (ace->Header.AceType)
-	{
-	case ACCESS_ALLOWED_ACE_TYPE:
-	  flags = &allow;
-	  anti = &deny;
-	  break;
-	case ACCESS_DENIED_ACE_TYPE:
-	  flags = &deny;
-	  anti = &allow;
-	  break;
-	default:
-	  continue;
-	}
-
-      cygpsid ace_sid ((PSID) &ace->SidStart);
-      if (ace_sid == well_known_world_sid)
-	{
-	  if (ace->Mask & FILE_READ_BITS)
-	    *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0)
-		      | ((!isownergroup && !(*anti & S_IRGRP)) ? S_IRGRP : 0)
-		      | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
-	  if (ace->Mask & FILE_WRITE_BITS)
-	    *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0)
-		      | ((!isownergroup && !(*anti & S_IWGRP)) ? S_IWGRP : 0)
-		      | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
-	  if (ace->Mask & FILE_EXEC_BITS)
-	    *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0)
-		      | ((!isownergroup && !(*anti & S_IXGRP)) ? S_IXGRP : 0)
-		      | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
-	  if ((S_ISDIR (*attribute)) &&
-	      (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD))
-	      == (FILE_WRITE_DATA | FILE_EXECUTE))
-	    *flags |= S_ISVTX;
-	}
-      else if (ace_sid == well_known_null_sid)
-	{
-	  /* Read SUID, SGID and VTX bits from NULL ACE. */
-	  if (ace->Mask & FILE_READ_DATA)
-	    *flags |= S_ISVTX;
-	  if (ace->Mask & FILE_WRITE_DATA)
-	    *flags |= S_ISGID;
-	  if (ace->Mask & FILE_APPEND_DATA)
-	    *flags |= S_ISUID;
-	}
-      else if (ace_sid == owner_sid)
-	{
-	  if (ace->Mask & FILE_READ_BITS)
-	    *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
-	  if (ace->Mask & FILE_WRITE_BITS)
-	    *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
-	  if (ace->Mask & FILE_EXEC_BITS)
-	    *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
-	  /* Apply deny mask to group if group SID == owner SID. */
-	  if (group_sid && isownergroup
-	      && ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
-	    {
-	      if (ace->Mask & FILE_READ_BITS)
-		*flags |= ((!(*anti & S_IRUSR)) ? S_IRGRP : 0);
-	      if (ace->Mask & FILE_WRITE_BITS)
-		*flags |= ((!(*anti & S_IWUSR)) ? S_IWGRP : 0);
-	      if (ace->Mask & FILE_EXEC_BITS)
-		*flags |= ((!(*anti & S_IXUSR)) ? S_IXGRP : 0);
-	    }
-	}
-      else if (ace_sid == group_sid)
-	{
-	  if (ace->Mask & FILE_READ_BITS)
-	    *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
-		      | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
-	  if (ace->Mask & FILE_WRITE_BITS)
-	    *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
-		      | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
-	  if (ace->Mask & FILE_EXEC_BITS)
-	    *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
-		      | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
-	}
-      else if (flags == &allow)
-	{
-	  /* Simplified computation of additional group permissions based on
-	     the CLASS_OBJ value.  CLASS_OBJ represents the or'ed value of
-	     the primary group permissions and all secondary user and group
-	     permissions.  FIXME: This only takes ACCESS_ALLOWED_ACEs into
-	     account.  The computation with additional ACCESS_DENIED_ACE
-	     handling is much more complicated. */
-	  if (ace->Mask & FILE_READ_BITS)
-	    *flags |= S_IRGRP;
-	  if (ace->Mask & FILE_WRITE_BITS)
-	    *flags |= S_IWGRP;
-	  if (ace->Mask & FILE_EXEC_BITS)
-	    *flags |= S_IXGRP;
-	}
-    }
-  *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
-#if 0
-  /* Disable owner/group permissions equivalence if owner SID == group SID.
-     It's technically not quite correct, but it helps in case a security
-     conscious application checks if a file has too open permissions.  In
-     fact, since owner == group, there's no security issue here. */
-  if (owner_sid && group_sid && RtlEqualSid (owner_sid, group_sid)
-      /* FIXME: temporary exception for /var/empty */
-      && well_known_system_sid != group_sid)
-    {
-      allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
-      allow |= (((allow & S_IRUSR) ? S_IRGRP : 0)
-		| ((allow & S_IWUSR) ? S_IWGRP : 0)
-		| ((allow & S_IXUSR) ? S_IXGRP : 0));
-    }
-#endif
-  *attribute |= allow;
-}
-
-static void
-get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute,
-		  uid_t *uidret, gid_t *gidret)
-{
-  if (!psd)
-    {
-      /* If reading the security descriptor failed, treat the object
-	 as unreadable. */
-      if (attribute)
-	*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
-      if (uidret)
-	*uidret = ILLEGAL_UID;
-      if (gidret)
-	*gidret = ILLEGAL_GID;
-      return;
-    }
-
-  cygpsid owner_sid;
-  cygpsid group_sid;
-  NTSTATUS status;
-  BOOLEAN dummy;
-
-  status = RtlGetOwnerSecurityDescriptor (psd, (PSID *) &owner_sid, &dummy);
-  if (!NT_SUCCESS (status))
-    debug_printf ("RtlGetOwnerSecurityDescriptor: %y", status);
-  status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy);
-  if (!NT_SUCCESS (status))
-    debug_printf ("RtlGetGroupSecurityDescriptor: %y", status);
-
-  uid_t uid;
-  gid_t gid;
-  bool grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid);
-  if (uidret)
-    *uidret = uid;
-  if (gidret)
-    *gidret = gid;
-
-  if (!attribute)
-    {
-      syscall_printf ("uid %u, gid %u", uid, gid);
-      return;
-    }
-
-  PACL acl;
-  BOOLEAN acl_exists;
-
-  status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy);
-  if (!NT_SUCCESS (status))
-    {
-      __seterrno_from_nt_status (status);
-      *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
-    }
-  else if (!acl_exists || !acl)
-    *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
-  else
-    get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
-
-  syscall_printf ("%sACL %y, uid %u, gid %u",
-		  (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid);
-}
-
 static int
 get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
 {
@@ -454,7 +266,7 @@ get_reg_attribute (HKEY hkey, mode_t *attribute, uid_t *uidret,
 
   if (!get_reg_sd (hkey, sd))
     {
-      get_info_from_sd (sd, attribute, uidret, gidret);
+      get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
       return 0;
     }
   /* The entries are already set to default values */
@@ -471,7 +283,7 @@ get_file_attribute (HANDLE handle, path_conv &pc,
 
       if (!get_file_sd (handle, pc, sd, false))
 	{
-	  get_info_from_sd (sd, attribute, uidret, gidret);
+	  get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
 	  return 0;
 	}
       /* ENOSYS is returned by get_file_sd if fetching the DACL from a remote
@@ -773,10 +585,10 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
 	    {
 	      if ((S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
 		  || (ace->Header.AceFlags
-		      & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)) == 0)
+		      & (SUB_CONTAINERS_AND_OBJECTS_INHERIT)) == 0)
 		continue;
 	      else
-		ace->Header.AceFlags |= INHERIT_ONLY_ACE;
+		ace->Header.AceFlags |= INHERIT_ONLY;
 	    }
 	  if (attribute & S_JUSTCREATED)
 	    {
@@ -797,8 +609,7 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
 	         it inherits the default ACL from its parent, so mark
 		 all unrelated, inherited ACEs inheritable. */
 	      if (S_ISDIR (attribute))
-		ace->Header.AceFlags |= CONTAINER_INHERIT_ACE
-					| OBJECT_INHERIT_ACE;
+		ace->Header.AceFlags |= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
 	    }
 	  else if (uid == ILLEGAL_UID && gid == ILLEGAL_UID
 		   && ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE
@@ -835,8 +646,7 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
      Cygwin applications don't need this. */
   if (S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
     {
-      const DWORD inherit = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
-			    | INHERIT_ONLY_ACE;
+      const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY;
       /* Set allow ACE for owner. */
       if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
 				   well_known_creator_owner_sid, acl_len,
@@ -936,7 +746,7 @@ get_object_attribute (HANDLE handle, uid_t *uidret, gid_t *gidret,
 
   if (get_object_sd (handle, sd))
     return -1;
-  get_info_from_sd (sd, attribute, uidret, gidret);
+  get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
   return 0;
 }
 
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index 8673457..9457eba 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -393,6 +393,7 @@ public:
 };
 
 extern cygpsid well_known_null_sid;
+extern cygpsid well_known_cygwin_sid;
 extern cygpsid well_known_world_sid;
 extern cygpsid well_known_local_sid;
 extern cygpsid well_known_console_logon_sid;
@@ -463,6 +464,8 @@ bool get_sids_info (cygpsid, cygpsid, uid_t * , gid_t *);
 struct acl;
 extern "C" int aclsort32 (int, int, struct acl *);
 extern "C" int acl32 (const char *, int, int, struct acl *);
+int get_posix_access (PSECURITY_DESCRIPTOR, mode_t *, uid_t *, gid_t *,
+		      struct acl *, int);
 int getacl (HANDLE, path_conv &, int, struct acl *);
 int setacl (HANDLE, path_conv &, int, struct acl *, bool &);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]