2013-11-21 12:40:27 -08:00
|
|
|
From 5e49f53a4bd591e67c9b7c4fdaf46933e319f9aa Mon Sep 17 00:00:00 2001
|
2013-11-21 12:33:37 -08:00
|
|
|
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
2013-11-21 12:40:27 -08:00
|
|
|
Date: Mon, 18 Nov 2013 18:15:20 -0700
|
2013-11-21 12:33:37 -08:00
|
|
|
Subject: ntdll: Inherit security attributes from parent directories.
|
|
|
|
|
|
|
|
---
|
2013-11-21 12:40:27 -08:00
|
|
|
dlls/advapi32/tests/security.c | 40 ++++++++++++++++++-
|
|
|
|
dlls/ntdll/file.c | 85 +++++++++++++++++++++++++++++++++++++++-
|
2013-11-21 12:33:37 -08:00
|
|
|
2 files changed, 123 insertions(+), 2 deletions(-)
|
|
|
|
|
2013-11-21 12:40:27 -08:00
|
|
|
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
|
|
|
index 7d28c05..a8d136b 100644
|
|
|
|
--- a/dlls/advapi32/tests/security.c
|
|
|
|
+++ b/dlls/advapi32/tests/security.c
|
|
|
|
@@ -3013,10 +3013,11 @@ static void test_CreateDirectoryA(void)
|
2013-11-21 12:33:37 -08:00
|
|
|
ACL_SIZE_INFORMATION acl_size;
|
|
|
|
ACCESS_ALLOWED_ACE *ace;
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
+ char tmpfile[MAX_PATH];
|
|
|
|
char tmpdir[MAX_PATH];
|
|
|
|
+ HANDLE token, hTemp;
|
|
|
|
struct _SID *owner;
|
|
|
|
BOOL bret = TRUE;
|
|
|
|
- HANDLE token;
|
|
|
|
DWORD error;
|
|
|
|
PACL pDacl;
|
|
|
|
|
2013-11-21 12:40:27 -08:00
|
|
|
@@ -3108,6 +3109,43 @@ static void test_CreateDirectoryA(void)
|
2013-11-21 12:33:37 -08:00
|
|
|
ace->Mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ /* Test inheritance of ACLs */
|
|
|
|
+ strcpy(tmpfile, tmpdir);
|
|
|
|
+ lstrcatA(tmpfile, "/tmpfile");
|
|
|
|
+ hTemp = CreateFileA(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW,
|
|
|
|
+ FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
|
|
|
+ error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
|
|
|
|
+ OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, (PSID*)&owner,
|
|
|
|
+ NULL, &pDacl, NULL, &pSD);
|
|
|
|
+ ok(error == ERROR_SUCCESS, "Failed to get permissions on file.\n");
|
|
|
|
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
|
|
|
+ ok(bret, "GetAclInformation failed\n");
|
|
|
|
+ ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n",
|
|
|
|
+ acl_size.AceCount);
|
|
|
|
+ if (acl_size.AceCount > 0)
|
|
|
|
+ {
|
|
|
|
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
|
|
|
|
+ ok(bret, "Inherited Failed to get Current User ACE.\n");
|
|
|
|
+ bret = EqualSid(&ace->SidStart, user_sid);
|
|
|
|
+ ok(bret, "Inherited Current User ACE != Current User SID.\n");
|
|
|
|
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
|
|
|
|
+ "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
|
|
|
|
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
|
|
|
|
+ ace->Mask);
|
|
|
|
+ }
|
|
|
|
+ if (acl_size.AceCount > 1)
|
|
|
|
+ {
|
|
|
|
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
|
|
|
|
+ ok(bret, "Inherited Failed to get Administators Group ACE.\n");
|
|
|
|
+ bret = EqualSid(&ace->SidStart, admin_sid);
|
|
|
|
+ ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n");
|
|
|
|
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
|
|
|
|
+ "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
|
|
|
|
+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
|
|
|
|
+ ace->Mask);
|
|
|
|
+ }
|
|
|
|
+ CloseHandle(hTemp);
|
|
|
|
+
|
|
|
|
done:
|
|
|
|
HeapFree(GetProcessHeap(), 0, user);
|
|
|
|
bret = RemoveDirectoryA(tmpdir);
|
|
|
|
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
2013-11-21 12:40:27 -08:00
|
|
|
index 1de2c61..8948bb7 100644
|
2013-11-21 12:33:37 -08:00
|
|
|
--- a/dlls/ntdll/file.c
|
|
|
|
+++ b/dlls/ntdll/file.c
|
2013-11-21 12:40:27 -08:00
|
|
|
@@ -103,6 +103,81 @@ mode_t FILE_umask = 0;
|
2013-11-21 12:33:37 -08:00
|
|
|
|
|
|
|
static const WCHAR ntfsW[] = {'N','T','F','S'};
|
|
|
|
|
|
|
|
+static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
|
|
|
|
+ PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
|
|
|
|
+ ULONG attributes, ULONG sharing, ULONG disposition,
|
|
|
|
+ ULONG options, PVOID ea_buffer, ULONG ea_length );
|
|
|
|
+
|
|
|
|
+struct security_descriptor *FILE_get_parent_sd(UNICODE_STRING *filenameW)
|
|
|
|
+{
|
|
|
|
+ SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION
|
|
|
|
+ |DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
|
|
|
|
+ PSECURITY_DESCRIPTOR parentsd = NULL;
|
|
|
|
+ ACL_SIZE_INFORMATION acl_size;
|
|
|
|
+ BOOLEAN present, defaulted;
|
|
|
|
+ WCHAR *p, parent[MAX_PATH];
|
|
|
|
+ OBJECT_ATTRIBUTES pattr;
|
|
|
|
+ UNICODE_STRING parentW;
|
|
|
|
+ IO_STATUS_BLOCK io;
|
|
|
|
+ NTSTATUS status;
|
|
|
|
+ HANDLE hparent;
|
|
|
|
+ ULONG n1, n2;
|
|
|
|
+ PACL pDacl;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ parentW.Buffer = parent;
|
|
|
|
+ parentW.Length = filenameW->Length;
|
|
|
|
+ memcpy(parentW.Buffer, filenameW->Buffer, filenameW->Length);
|
|
|
|
+ if ((p = strrchrW(parent, '\\')) != NULL)
|
|
|
|
+ {
|
|
|
|
+ p[0] = 0;
|
|
|
|
+ parentW.Length = (p-parent)*sizeof(WCHAR);
|
|
|
|
+ }
|
|
|
|
+ memset(&pattr, 0x0, sizeof(pattr));
|
|
|
|
+ pattr.Length = sizeof(pattr);
|
|
|
|
+ pattr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
|
|
+ pattr.ObjectName = &parentW;
|
|
|
|
+ status = FILE_CreateFile( &hparent, READ_CONTROL|ACCESS_SYSTEM_SECURITY, &pattr, &io, NULL,
|
|
|
|
+ FILE_FLAG_BACKUP_SEMANTICS,
|
|
|
|
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
|
|
|
|
+ FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0 );
|
|
|
|
+ if (status == STATUS_SUCCESS)
|
|
|
|
+ status = NtQuerySecurityObject( hparent, info, NULL, 0, &n1 );
|
|
|
|
+ if (status == STATUS_BUFFER_TOO_SMALL && (parentsd = RtlAllocateHeap( GetProcessHeap(), 0, n1 )) != NULL)
|
|
|
|
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
|
|
|
|
+ if (status == STATUS_SUCCESS)
|
|
|
|
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
|
|
|
|
+ if (hparent != INVALID_HANDLE_VALUE)
|
|
|
|
+ NtClose( hparent );
|
|
|
|
+ if (status != STATUS_SUCCESS) return NULL;
|
|
|
|
+ status = RtlGetDaclSecurityDescriptor(parentsd, &present, &pDacl, &defaulted);
|
|
|
|
+ if (status != STATUS_SUCCESS || !present) return NULL;
|
|
|
|
+ status = RtlQueryInformationAcl(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
|
|
|
+ if (status != STATUS_SUCCESS) return NULL;
|
|
|
|
+
|
|
|
|
+ for (i=acl_size.AceCount-1; i>=0; i--)
|
|
|
|
+ {
|
|
|
|
+ DWORD inheritance_mask = INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
|
|
|
|
+ ACE_HEADER *ace;
|
|
|
|
+
|
|
|
|
+ status = RtlGetAce(pDacl, i, (VOID **)&ace);
|
|
|
|
+ if (status != STATUS_SUCCESS || !(ace->AceFlags & inheritance_mask))
|
|
|
|
+ {
|
|
|
|
+ RtlDeleteAce(pDacl, i);
|
|
|
|
+ acl_size.AceCount--;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ ace->AceFlags = (ace->AceFlags & ~inheritance_mask) | INHERITED_ACE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!acl_size.AceCount)
|
|
|
|
+ {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ return parentsd;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
/**************************************************************************
|
|
|
|
* FILE_CreateFile (internal)
|
|
|
|
* Open a file.
|
2013-11-21 12:40:27 -08:00
|
|
|
@@ -161,10 +236,18 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
|
2013-11-21 12:33:37 -08:00
|
|
|
{
|
|
|
|
struct security_descriptor *sd;
|
|
|
|
struct object_attributes objattr;
|
|
|
|
+ PSECURITY_DESCRIPTOR parentsd = NULL, psd;
|
|
|
|
|
|
|
|
objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
|
|
|
|
objattr.name_len = 0;
|
|
|
|
- io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
|
|
|
|
+ psd = attr->SecurityDescriptor;
|
|
|
|
+ if (!psd && (disposition == FILE_CREATE||disposition == FILE_OVERWRITE_IF))
|
|
|
|
+ parentsd = FILE_get_parent_sd( attr->ObjectName );
|
|
|
|
+ if (parentsd)
|
|
|
|
+ psd = parentsd;
|
|
|
|
+ io->u.Status = NTDLL_create_struct_sd( psd, &sd, &objattr.sd_len );
|
|
|
|
+ if (parentsd)
|
|
|
|
+ RtlFreeHeap( GetProcessHeap(), 0, parentsd );
|
|
|
|
if (io->u.Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
RtlFreeAnsiString( &unix_name );
|
|
|
|
--
|
|
|
|
1.7.9.5
|
|
|
|
|