This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project. See the Cygwin home page for more information.
[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index] [Subject Index] [Author Index] [Thread Index]

Re: Patch, Version 3: Unix-like permissions on objects



Sorry!

I forgot the patch to `chmod()' which is needed because
of keeping the current user and group. This has a side effect:
`SetFileSecurity()' may set owner and group only, if they are
corresponding to the current user. This is important in case
of `chown()' and `chmod()' calls.

This affects syscalls.cc and security.cc, so I attach the correct
patches to them, only.

Regards,
Corinna

ChangeLog:
==========

Sat Mar  6 21:37:00  Corinna Vinschen  <corinna.vinschen@cityweb.de>

	* syscalls.cc (chmod): Changed call to set_file_attribute,
	to keep uid/gid setting.

        * security.cc (set_nt_attribute): Set owner and group
	only, if they are corresponding to current user.
Index: syscalls.cc
===================================================================
RCS file: /src/cvsroot/winsup-990303/syscalls.cc,v
retrieving revision 1.1
diff -u -p -1 -r1.1 syscalls.cc
--- syscalls.cc	1999/03/05 22:26:50	1.1
+++ syscalls.cc	1999/03/06 20:05:54
@@ -880,2 +880,7 @@ retry:
 
+		  int attrib;
+		  BOOL a_ok;
+
+		  a_ok = get_file_attribute (win32_path.get_win32 (), &attrib);
+
 		  /* open the file again for write owner and dac */
@@ -926,2 +931,6 @@ retry:
 		  syscall_printf ("0 = chown (%s,...)", name);
+
+		  if (a_ok)
+		    set_file_attribute (win32_path.get_win32 (),
+		                        uid, gid, attrib);
 		  return 0;
@@ -991,4 +1000,8 @@ chmod (const char *path, mode_t mode)
   int now;
+
+  set_file_attribute (win32_path.get_win32 (),
+		      get_file_owner (win32_path.get_win32 ()),
+		      get_file_group (win32_path.get_win32 ()),
+                      mode);
 
-  set_file_attribute (win32_path.get_win32 (), mode);
 
Index: security.cc
===================================================================
RCS file: /src/cvsroot/winsup-990303/security.cc,v
retrieving revision 1.1
diff -u -p -1 -r1.1 security.cc
--- security.cc	1999/03/05 22:26:50	1.1
+++ security.cc	1999/03/06 20:50:46
@@ -2,5 +2,6 @@
 
-   Copyright 1997, 1998 Cygnus Solutions.
+   Copyright 1997, 1998, 1999 Cygnus Solutions.
 
-   Written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
+   Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
+   Extensions by Corinna Vinschen <corinna.vinschen@cityweb.de>
 
@@ -15,77 +16,28 @@ details. */
 #include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "winsup.h"
 
-#if 0
-PSID
-get_world_sid ()
-{
-  PSID world_sid;
-  SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY;
-
-  world_sid = (PSID) LocalAlloc (LPTR,GetSidLengthRequired (1));
+extern BOOL allow_ntea;
+BOOL allow_ntsec = FALSE;
 
-  InitializeSid (world_sid, &world_sid_auth, 1);
-  *(GetSidSubAuthority (world_sid, 0)) = SECURITY_WORLD_RID;
+extern PSID get_admin_sid ();
 
-  return world_sid;
-}
-
-int
-world_full_access (HANDLE h, int type)
+PSID
+get_world_sid ()
 {
-  PSID world_sid = NULL;
-  PSECURITY_DESCRIPTOR psd = NULL;
-  PACL pacl = NULL;
-  DWORD acl_size = 1024;
-
-  world_sid = get_world_sid();
-
-  if (!world_sid)
-    goto clean_on_error;
-
-  psd = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
-
-  if (!psd)
-    goto clean_on_error;
-
-  if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION))
-    goto clean_on_error;
+  static NO_COPY PSID sidBuf;
 
-  pacl = (PACL) LocalAlloc (LPTR, acl_size);
-
-  if (!pacl)
-    goto clean_on_error;
-
-  /* FIXME: the 3rd parameter is actually ACL_REVISION which is
-     not defined in Scott Christley's header files. */
-  if (!InitializeAcl (pacl, acl_size, 2))
-    goto clean_on_error;
-
-  if (!AddAccessAllowedAce (pacl, 2, type, world_sid))
-    goto clean_on_error;
-
-  if (!SetSecurityDescriptorDacl (psd, TRUE, pacl, FALSE))
-    goto clean_on_error;
-
-  if(!SetKernelObjectSecurity (h, DACL_SECURITY_INFORMATION, psd))
-    goto clean_on_error;
-
-  LocalFree ((HANDLE) world_sid);
-  LocalFree ((HANDLE) psd);
-  LocalFree ((HANDLE) pacl);
-  return TRUE;
-
-clean_on_error:
-    if (world_sid)
-	LocalFree ((HANDLE) world_sid);
-
-    if (psd)
-	LocalFree ((HANDLE) psd);
-
-    if (pacl)
-	LocalFree ((HANDLE) pacl);
-
-    return FALSE;
+  if (! sidBuf)
+    {
+      SID_IDENTIFIER_AUTHORITY world_sid_auth = SECURITY_WORLD_SID_AUTHORITY;
+      
+      AllocateAndInitializeSid (&world_sid_auth, 1,
+                                SECURITY_WORLD_RID, 0, 0, 0,
+				0, 0, 0, 0,
+				&sidBuf);
+    }
+  return sidBuf;
 }
-#endif
 
@@ -155,6 +107,153 @@ get_id_from_sid (PSID psid)
 }
+
+static BOOL
+get_nt_attribute (const char *file, int *attribute)
+{
+  if (os_being_run != winNT)
+    return FALSE;
+
+  syscall_printf ("file: %s", file);
+
+  if (file[1] == ':')
+    {
+      static char drive[4] = "X:\\";
+      char fs[32];
+
+      drive[0] = file[0];
+      if (! GetVolumeInformation(drive, NULL, 0, NULL, NULL, NULL,  fs, 32))
+	{
+          debug_printf ("GetVolumeInformation(%s) %d", drive, GetLastError());
+	  return FALSE;
+        }
+      if (! strcmp (fs, "FAT"))
+        return FALSE;
+    }
+
+  DWORD sd_size = 0;
+  DWORD bufdummy;
+  SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *) &bufdummy;
+
+  if (! GetFileSecurity (file, OWNER_SECURITY_INFORMATION
+		               | GROUP_SECURITY_INFORMATION
+		               | DACL_SECURITY_INFORMATION,
+		         sd, 4, &sd_size))
+    {
+      debug_printf ("GetFileSecuritySize %d", GetLastError());
+      if (sd_size == 0)
+        return FALSE;
+    }
+  sd = (SECURITY_DESCRIPTOR *) malloc (sd_size);
+  if (! sd)
+    {
+      debug_printf ("malloc");
+      return FALSE;
+    }
+  if (! GetFileSecurity (file, OWNER_SECURITY_INFORMATION
+		               | GROUP_SECURITY_INFORMATION
+		               | DACL_SECURITY_INFORMATION,
+		         sd, sd_size, &sd_size))
+    {
+      free (sd);
+      debug_printf ("GetFileSecurity %d", GetLastError ());
+      return FALSE;
+    }
+
+  PSID sidOwner;
+  PSID sidGroup;
+  BOOL dummy;
+
+  if (! GetSecurityDescriptorOwner (sd, &sidOwner, &dummy))
+    debug_printf ("GetSecurityDescriptorOwner %d", GetLastError ());
+  if (! GetSecurityDescriptorGroup (sd, &sidGroup, &dummy))
+    debug_printf ("GetSecurityDescriptorGroup %d", GetLastError ());
+
+  PACL acl;
+  BOOL acl_exists;
+
+  if (! GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy)
+      || ! acl_exists)
+    {
+      free (sd);
+      debug_printf ("GetSecurityDescriptorDacl %d", GetLastError ());
+      return FALSE;
+    }
+
+  BOOL has_owner_bits = FALSE;
+  BOOL has_group_bits = FALSE;
+  BOOL has_world_bits = FALSE;
+
+  for (DWORD i = 0; i < acl->AceCount; ++i)
+    {
+      ACCESS_ALLOWED_ACE *ace;
+
+      if (GetAce (acl, i, (PVOID *) &ace))
+	{
+	  switch (ace->Header.AceType)
+	    {
+	    case ACCESS_ALLOWED_ACE_TYPE:
+              if (sidOwner && EqualSid ((PSID) &ace->SidStart, sidOwner))
+	        {
+		  *attribute &= ~S_IRWXU;
+		  has_owner_bits = TRUE;
+	          if (ace->Mask & FILE_READ_DATA)
+		    *attribute |= S_IRUSR;
+	          if (ace->Mask & FILE_WRITE_DATA)
+		    *attribute |= S_IWUSR;
+	          if (ace->Mask & FILE_EXECUTE)
+		    *attribute |= S_IXUSR;
+	        }
+              else if (sidGroup && EqualSid ((PSID) &ace->SidStart, sidGroup))
+	        {
+		  *attribute &= ~S_IRWXG;
+		  has_group_bits = TRUE;
+	          if (ace->Mask & FILE_READ_DATA)
+		    *attribute |= S_IRGRP;
+	          if (ace->Mask & FILE_WRITE_DATA)
+		    *attribute |= S_IWGRP;
+	          if (ace->Mask & FILE_EXECUTE)
+		    *attribute |= S_IXGRP;
+	        }
+              else if (EqualSid ((PSID) &ace->SidStart, get_world_sid ()))
+	        {
+		  *attribute &= ~S_IRWXO;
+		  has_world_bits = TRUE;
+	          if (ace->Mask & FILE_READ_DATA)
+		    {
+		      *attribute |= S_IROTH;
+		      if (! sidOwner || ! has_owner_bits)
+		        *attribute |= S_IRUSR;
+		      if (! sidGroup || ! has_group_bits)
+		        *attribute |= S_IRGRP;
+		    }
+	          if (ace->Mask & FILE_WRITE_DATA)
+		    {
+		      *attribute |= S_IWOTH;
+		      if (! sidOwner || ! has_owner_bits)
+		        *attribute |= S_IWUSR;
+		      if (! sidGroup || ! has_group_bits)
+		        *attribute |= S_IWGRP;
+		    }
+	          if (ace->Mask & FILE_EXECUTE)
+		    {
+		      *attribute |= S_IXOTH;
+		      if (! sidOwner || ! has_owner_bits)
+		        *attribute |= S_IXUSR;
+		      if (! sidGroup || ! has_group_bits)
+		        *attribute |= S_IXGRP;
+		    }
+	        }
+	      break;
+	    case ACCESS_DENIED_ACE_TYPE:
+	      // Still ignored!
+	      break;
+	    default:
+	      break;
+	    }
+        }
+    }
 
-/*
- * File attribute stuff. FIXME: add NTFS security.
- */
+  free (sd);
+  syscall_printf ("file: %s %x", file, *attribute);
+  return TRUE;
+}
 
@@ -163,5 +262,246 @@ get_file_attribute (const char *file, in
 {
+  if (! attribute)
+    return FALSE;
+
   int res = NTReadEA (file, ".UNIXATTR", (char *) attribute,
 		      sizeof (*attribute));
-  return res > 0;
+
+  // symlinks are anything for everyone!
+  if ((*attribute & S_IFLNK) == S_IFLNK)
+    *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+
+  if (!allow_ntsec)
+      return res > 0;
+
+  return get_nt_attribute (file, attribute);
+}
+
+static BOOL
+set_nt_attribute (const char *file, uid_t uid, gid_t gid, int attribute)
+{
+  if (os_being_run != winNT)
+    return FALSE;
+
+  DWORD sidlen, domlen;
+  char dom[100];
+  char user[256];
+  SID_NAME_USE acc_type;
+
+  /*
+   * Caution!
+   *
+   * ID 513 is `none'. Giving explicit permissions 
+   * to `none' will result in dubious problems!
+   *
+   * Uid 513 is definitely not allowed here!
+  */
+  if (uid == 513)
+    return FALSE;
+
+  struct passwd *pw = getpwuid (uid);
+  strcpy (user, pw ? pw->pw_name : getlogin ());
+  PSID sidOwner = (PSID) malloc (1024);
+  if (! sidOwner)
+    {
+      debug_printf ("malloc 1");
+      return FALSE;
+    }
+  if (! LookupAccountName (NULL, user,
+                           sidOwner, (sidlen = 1024, &sidlen),
+                           dom, (domlen = 100, &domlen),
+                           &acc_type))
+    {
+      free (sidOwner);
+      debug_printf ("LookupAccountName(%s) %d", user, GetLastError ());
+      return FALSE;
+    }
+  else if (acc_type != SidTypeUser)
+    {
+      char domuser[356];
+      strcpy (domuser, dom);
+      strcat (domuser, "\\");
+      strcat (domuser, user);
+      if (! LookupAccountName (NULL, domuser,
+                               sidOwner, (sidlen = 1024, &sidlen),
+                               dom, (domlen = 100, &domlen),
+                               &acc_type))
+        {
+          free (sidOwner);
+	  debug_printf ("LookupAccountName(%s) %d", domuser, GetLastError ());
+          return FALSE;
+        }
+    }
+  sidOwner = (PSID) realloc (sidOwner, sidlen + 1);
+  debug_printf ("user: %s [%d]", user,
+                *GetSidSubAuthority((PSID) sidOwner,
+		*GetSidSubAuthorityCount((PSID) sidOwner) - 1));
+
+  struct group *grp = getgrgid (gid);
+  PSID sidGroup = NULL;
+
+  /*
+   * Caution!
+   *
+   * ID 513 is `none'. Giving explicit permissions 
+   * to `none' will result in dubious problems!
+   *
+   * Gid 513 will result in not setting group permissions here.
+  */
+  if (grp && gid != 513)
+    {
+      sidGroup = (PSID) malloc (1024);
+      if (! sidGroup)
+	{
+	  free (sidOwner);
+	  free (sidGroup);
+          debug_printf ("malloc 2");
+	  return FALSE;
+        }
+      if (! LookupAccountName (NULL, grp->gr_name,
+			       sidGroup, (sidlen = 1024, &sidlen),
+			       dom, (domlen = 100, &domlen),
+			       &acc_type))
+	{
+	  free (sidOwner);
+	  free (sidGroup);
+	  debug_printf ("LookupAccountName(%s) %d", grp->gr_name,
+	                                            GetLastError ());
+	  return FALSE;
+	}
+      sidGroup = (PSID) realloc (sidGroup, sidlen + 1);
+      debug_printf ("group: %s [%d]", grp->gr_name,
+		    *GetSidSubAuthority((PSID) sidGroup,
+		    *GetSidSubAuthorityCount((PSID) sidGroup) - 1));
+    }
+  else
+    debug_printf ("no group");
+
+  SECURITY_DESCRIPTOR sd;
+
+  if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
+    debug_printf ("InitializeSecurityDescriptor  %d", GetLastError ());
+  if (! SetSecurityDescriptorOwner(&sd, sidOwner, FALSE))
+    debug_printf ("SetSecurityDescriptorOwner %d", GetLastError ());
+  if (sidGroup)
+    if (! SetSecurityDescriptorGroup(&sd, sidGroup, FALSE))
+      debug_printf ("SetSecurityDescriptorGroup %d", GetLastError ());
+
+  size_t acl_len = sizeof (ACL)
+                   + 3 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD))
+                   + GetLengthSid (sidOwner)
+                   + GetLengthSid (get_admin_sid ())
+                   + GetLengthSid (get_world_sid ());
+  if (sidGroup)
+    acl_len += sizeof (ACCESS_ALLOWED_ACE)
+               - sizeof (DWORD)
+	       + GetLengthSid (sidGroup);
+
+  PACL acl = (PACL) malloc (acl_len);
+  if (! acl)
+    {
+      free (sidOwner);
+      free (sidGroup);
+      debug_printf ("malloc 4");
+      return FALSE;
+    }
+  if (! InitializeAcl (acl, acl_len, ACL_REVISION))
+    debug_printf ("InitializeAcl %d", GetLastError ());
+
+  int ace_off = 0;
+  ACCESS_ALLOWED_ACE *ace;
+
+  DWORD access = STANDARD_RIGHTS_ALL;
+  if (attribute & S_IRUSR)
+    access |= FILE_GENERIC_READ | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
+  if (attribute & S_IWUSR)
+    access |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD;
+  if (attribute & S_IXUSR)
+    access |= FILE_GENERIC_EXECUTE;
+  if (! AddAccessAllowedAce (acl, ACL_REVISION, access, sidOwner))
+    debug_printf ("AddAccessAllowedAce(owner) %d", GetLastError ());
+  if (GetAce(acl, 0, (PVOID *) &ace))
+    ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+
+  if (! sidGroup || ! EqualSid (sidGroup, get_admin_sid ()))
+    {
+      if (! AddAccessAllowedAce (acl, ACL_REVISION,
+                                 SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
+                                 get_admin_sid ()))
+        debug_printf ("AddAccessAllowedAce(admin) %d", GetLastError ());
+      if (GetAce(acl, 1, (PVOID *) &ace))
+        ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+      ace_off = 1;
+    }
+
+  if (sidGroup)
+    {
+      access = 0;
+      if (attribute & S_IRGRP)
+	{
+	  access |= FILE_GENERIC_READ;
+	  if (EqualSid (sidGroup, get_admin_sid ()))
+	    access |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
+        }
+      if (attribute & S_IWGRP)
+	access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE
+	          | DELETE | FILE_DELETE_CHILD;
+      if (attribute & S_IXGRP)
+	access |= FILE_GENERIC_EXECUTE;
+      if (! AddAccessAllowedAce (acl, ACL_REVISION, access, sidGroup))
+	debug_printf ("AddAccessAllowedAce(group) %d", GetLastError ());
+      if (GetAce(acl, 1 + ace_off, (PVOID *) &ace))
+        ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+    }
+
+  access = 0;
+  if (attribute & S_IROTH)
+    access |= FILE_GENERIC_READ;
+  if (attribute & S_IWOTH)
+    access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE
+              | DELETE | FILE_DELETE_CHILD;
+  if (attribute & S_IXOTH)
+    access |= FILE_GENERIC_EXECUTE;
+  if (! AddAccessAllowedAce (acl, ACL_REVISION, access, get_world_sid ()))
+    debug_printf ("AddAccessAllowedAce(world) %d", GetLastError ());
+  if (GetAce(acl, 2 + ace_off, (PVOID *) &ace))
+    ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+
+  if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
+    debug_printf ("SetSecurityDescriptorDacl %d", GetLastError ());
+
+  SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
+
+  if (uid == myself->uid)
+    si |= OWNER_SECURITY_INFORMATION;
+  if (grp && gid == myself->gid)
+    si |= GROUP_SECURITY_INFORMATION;
+
+  if (! SetFileSecurity (file, si, &sd))
+    debug_printf ("SetFileSecurity %d", GetLastError());
+
+  free (sidOwner);
+  free (sidGroup);
+  free (acl);
+
+  return TRUE;
+}
+
+BOOL
+set_file_attribute (const char *file, uid_t uid, gid_t gid, int attribute)
+{
+  // symlinks are anything for everyone!
+  if ((attribute & S_IFLNK) == S_IFLNK)
+    attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+
+  BOOL ret = NTWriteEA (file, ".UNIXATTR",
+                        (char *) &attribute, sizeof (attribute));
+  
+  if (!allow_ntsec)
+      return ret;
+
+  ret = set_nt_attribute (file, uid, gid, attribute);
+
+  syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", ret, file, uid, gid, attribute);
+
+  return ret;
 }
@@ -171,4 +511,3 @@ set_file_attribute (const char *file, in
 {
-  return NTWriteEA (file, ".UNIXATTR", (char *) &attribute,
-		    sizeof (attribute));
+  return set_file_attribute (file, myself->uid, myself->gid, attribute);
 }