From 5e49f53a4bd591e67c9b7c4fdaf46933e319f9aa Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Mon, 18 Nov 2013 18:15:20 -0700 Subject: ntdll: Inherit security attributes from parent directories. --- dlls/advapi32/tests/security.c | 40 ++++++++++++++++++- dlls/ntdll/file.c | 85 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) 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) 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; @@ -3108,6 +3109,43 @@ static void test_CreateDirectoryA(void) 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 index 1de2c61..8948bb7 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -103,6 +103,81 @@ mode_t FILE_umask = 0; 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. @@ -161,10 +236,18 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT { 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