[newlib-cygwin] Fix reading/writing Samba ACLs using RFC2307 mapping

Corinna Vinschen corinna@sourceware.org
Sat Mar 12 17:05:00 GMT 2016


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

commit fc180edcf4231fdfbc73560432bc45e926c08eaa
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Sat Mar 12 17:56:21 2016 +0100

    Fix reading/writing Samba ACLs using RFC2307 mapping
    
    When using RFC2307 uid/gid-mapping on Samba shares, the POSIX ACL contains
    the Windows SIDs.  When writing back such an ACL we have to map the
    Windows SIDs back to the corresponding Samba SIDs representing the UNIX
    uid/gid value.  When reading Samba SIDs, make sure never to evaluate a
    UNIX user account as group.
    
    	* sec_acl.cc (set_posix_access): Convert Windows SIDs to
    	RFC2307-mapped Sambe UNIX SIDs.
    	* sec_helper.cc (cygpsid::get_id): Skip UNIX user accounts when
    	trying to evaluate a SID as group.  Skip UNIX group accounts when
    	trying to evaluate a SID as user.
    	* cygheap.h (cygheap_ugid_cache::reverse_get): New method to
    	get nfs id from cygwin id.
    	(cygheap_ugid_cache::reverse_get_uid): Wrapper for uids.
    	(cygheap_ugid_cache::reverse_get_gid): Wrapper for gids.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/cygheap.h     |  9 +++++++
 winsup/cygwin/sec_acl.cc    | 59 ++++++++++++++++++++++++++++++++++++++++-----
 winsup/cygwin/sec_helper.cc | 32 +++++++++++++++---------
 3 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index fd84814..c394e7f 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -508,6 +508,13 @@ class cygheap_ugid_cache
 	  return _map[i].cyg_id;
       return (uint32_t) -1;
     }
+    uint32_t reverse_get (uint32_t id) const
+    {
+      for (uint32_t i = 0; i < _cnt; ++i)
+	if (_map[i].cyg_id == id)
+	  return _map[i].nfs_id;
+      return (uint32_t) -1;
+    }
     void add (uint32_t nfs_id, uint32_t cyg_id)
     {
       if (_cnt >= _max)
@@ -523,6 +530,8 @@ class cygheap_ugid_cache
 public:
   uid_t get_uid (uid_t uid) const { return uids.get (uid); }
   gid_t get_gid (gid_t gid) const { return gids.get (gid); }
+  uid_t reverse_get_uid (uid_t uid) const { return uids.reverse_get (uid); }
+  gid_t reverse_get_gid (gid_t gid) const { return gids.reverse_get (gid); }
   void add_uid (uid_t nfs_uid, uid_t cyg_uid) { uids.add (nfs_uid, cyg_uid); }
   void add_gid (gid_t nfs_gid, gid_t cyg_gid) { gids.add (nfs_gid, cyg_gid); }
 };
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 3993249..1919fb7 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -138,7 +138,8 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
 {
   SECURITY_DESCRIPTOR sd;
   cyg_ldap cldap;
-  PSID owner, group;
+  PSID owner = NULL, group = NULL;
+  cygsid smb_owner, smb_group;
   NTSTATUS status;
   tmp_pathbuf tp;
   cygpsid *aclsid;
@@ -157,9 +158,27 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
      modified by inheritable ACEs. */
   RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
 
-  /* Fetch owner and group and set in security descriptor. */
-  owner = sidfromuid (uid, &cldap);
-  group = sidfromgid (gid, &cldap);
+  /* Fetch owner and group and set in security descriptor.
+
+     For Samba we check if there's an RFC2307 mapping in place, otherwise
+     we're trying to create an ACL with the wrong Windows SIDs rather than
+     the correct Unix SIDs.  Same happens below for mapping other USER and
+     GROUP SIDs. */
+  if (is_samba)
+    {
+      uint32_t smb_uid, smb_gid;
+
+      smb_uid = cygheap->ugid_cache.reverse_get_uid (uid);
+      if (smb_uid != ILLEGAL_UID)
+	owner = smb_owner.create (22, 2, 1, smb_uid);
+      smb_gid = cygheap->ugid_cache.reverse_get_gid (gid);
+      if (smb_gid != ILLEGAL_GID)
+	group = smb_group.create (22, 2, 2, smb_gid);
+    }
+  if (!owner)
+    owner = sidfromuid (uid, &cldap);
+  if (!group)
+    group = sidfromgid (gid, &cldap);
   if (!owner || !group)
     {
       set_errno (EINVAL);
@@ -224,7 +243,21 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
 	break;
       case USER:
       case DEF_USER:
-	aclsid[idx] = sidfromuid (aclbufp[idx].a_id, &cldap);
+	aclsid[idx] = NO_SID;
+	if (is_samba)
+	  {
+	    uint32_t smb_uid;
+	    cygsid *smb_sid;
+
+	    smb_uid = cygheap->ugid_cache.reverse_get_uid (aclbufp[idx].a_id);
+	    if (smb_uid != ILLEGAL_UID)
+	      {
+		smb_sid = (cygsid *) alloca (sizeof (cygsid));
+		aclsid[idx] = smb_sid->create (22, 2, 1, smb_uid);
+	      }
+	  }
+	if (!aclsid[idx])
+	  aclsid[idx] = sidfromuid (aclbufp[idx].a_id, &cldap);
 	break;
       case GROUP_OBJ:
 	aclsid[idx] = group;
@@ -235,7 +268,21 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
 	break;
       case GROUP:
       case DEF_GROUP:
-	aclsid[idx] = sidfromgid (aclbufp[idx].a_id, &cldap);
+	aclsid[idx] = NO_SID;
+	if (is_samba)
+	  {
+	    uint32_t smb_gid;
+	    cygsid *smb_sid;
+
+	    smb_gid = cygheap->ugid_cache.reverse_get_gid (aclbufp[idx].a_id);
+	    if (smb_gid != ILLEGAL_GID)
+	      {
+		smb_sid = (cygsid *) alloca (sizeof (cygsid));
+		aclsid[idx] = smb_sid->create (22, 2, 2, smb_gid);
+	      }
+	  }
+	if (!aclsid[idx])
+	  aclsid[idx] = sidfromgid (aclbufp[idx].a_id, &cldap);
 	break;
       case CLASS_OBJ:
       case DEF_CLASS_OBJ:
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index e93a9a9..0ad09e0 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -117,21 +117,28 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
 	id = myself->gid;
       else if (sid_id_auth (psid) == 22 && cygheap->pg.nss_grp_db ())
 	{
-	  /* Samba UNIX group.  Try to map to Cygwin gid.  If there's no
+	  /* Samba UNIX group?  Try to map to Cygwin gid.  If there's no
 	     mapping in the cache, try to fetch it from the configured
 	     RFC 2307 domain (see last comment in cygheap_domain_info::init()
-	     for more information) and add it to the mapping cache. */
-	  gid_t gid = sid_sub_auth_rid (psid);
-	  gid_t map_gid = cygheap->ugid_cache.get_gid (gid);
-	  if (map_gid == ILLEGAL_GID)
+	     for more information) and add it to the mapping cache.
+	     If this is a user, not a group, make sure to skip the subsequent
+	     internal_getgrsid call, otherwise we end up with a fake group
+	     entry for a UNIX user account. */
+	  if (sid_sub_auth (psid, 0) == 2)
 	    {
-	      if (pldap->open (cygheap->dom.get_rfc2307_domain ()) == NO_ERROR)
-		map_gid = pldap->remap_gid (gid);
-	      if (map_gid == ILLEGAL_GID) 
-		map_gid = MAP_UNIX_TO_CYGWIN_ID (gid);
-	      cygheap->ugid_cache.add_gid (gid, map_gid);
+	      gid_t gid = sid_sub_auth_rid (psid);
+	      gid_t map_gid = cygheap->ugid_cache.get_gid (gid);
+	      if (map_gid == ILLEGAL_GID)
+		{
+		  if (pldap->open (cygheap->dom.get_rfc2307_domain ())
+		      == NO_ERROR)
+		    map_gid = pldap->remap_gid (gid);
+		  if (map_gid == ILLEGAL_GID) 
+		    map_gid = MAP_UNIX_TO_CYGWIN_ID (gid);
+		  cygheap->ugid_cache.add_gid (gid, map_gid);
+		}
+	      id = (uid_t) map_gid;
 	    }
-	  id = (uid_t) map_gid;
 	}
       else if ((gr = internal_getgrsid (*this, pldap)))
 	id = gr->gr_gid;
@@ -147,7 +154,8 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
       struct passwd *pw;
       if (*this == cygheap->user.sid ())
 	id = myself->uid;
-      else if (sid_id_auth (psid) == 22 && cygheap->pg.nss_pwd_db ())
+      else if (sid_id_auth (psid) == 22 && sid_sub_auth (psid, 0) == 1
+	       && cygheap->pg.nss_pwd_db ())
 	{
 	  /* Samba UNIX user.  See comment above. */
 	  uid_t uid = sid_sub_auth_rid (psid);



More information about the Cygwin-cvs mailing list