From 07b629e8e4472785809bcdf9820922c2b874c313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Fri, 10 Nov 2017 15:50:31 -0600 Subject: [PATCH] advapi32: Implement GetExplicitEntriesFromAclW. Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/advapi32/security.c | 84 ++++++++++++++++++- dlls/advapi32/tests/security.c | 142 +++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 4 deletions(-) diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index c9d5cfaffad..ae9d6bdeb1b 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -4211,11 +4211,87 @@ DWORD WINAPI GetExplicitEntriesFromAclA( PACL pacl, PULONG pcCountOfExplicitEntr /****************************************************************************** * GetExplicitEntriesFromAclW [ADVAPI32.@] */ -DWORD WINAPI GetExplicitEntriesFromAclW( PACL pacl, PULONG pcCountOfExplicitEntries, - PEXPLICIT_ACCESSW* pListOfExplicitEntries) +DWORD WINAPI GetExplicitEntriesFromAclW( PACL pacl, PULONG count, PEXPLICIT_ACCESSW *list ) { - FIXME("%p %p %p\n",pacl, pcCountOfExplicitEntries, pListOfExplicitEntries); - return ERROR_CALL_NOT_IMPLEMENTED; + ACL_SIZE_INFORMATION sizeinfo; + EXPLICIT_ACCESSW *entries; + MAX_SID *sid_entries; + ACE_HEADER *ace; + NTSTATUS status; + int i; + + TRACE("%p %p %p\n",pacl, count, list); + + if (!count || !list) + return ERROR_INVALID_PARAMETER; + + status = RtlQueryInformationAcl(pacl, &sizeinfo, sizeof(sizeinfo), AclSizeInformation); + if (status) return RtlNtStatusToDosError(status); + + if (!sizeinfo.AceCount) + { + *count = 0; + *list = NULL; + return ERROR_SUCCESS; + } + + entries = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (sizeof(EXPLICIT_ACCESSW) + sizeof(MAX_SID)) * sizeinfo.AceCount); + if (!entries) return ERROR_OUTOFMEMORY; + sid_entries = (MAX_SID *)(entries + sizeinfo.AceCount); + + for (i = 0; i < sizeinfo.AceCount; i++) + { + status = RtlGetAce(pacl, i, (void**)&ace); + if (status) goto error; + + switch (ace->AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + { + ACCESS_ALLOWED_ACE *allow = (ACCESS_ALLOWED_ACE *)ace; + entries[i].grfAccessMode = GRANT_ACCESS; + entries[i].grfInheritance = ace->AceFlags; + entries[i].grfAccessPermissions = allow->Mask; + + CopySid(sizeof(MAX_SID), (PSID)&sid_entries[i], (PSID)&allow->SidStart); + entries[i].Trustee.pMultipleTrustee = NULL; + entries[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + entries[i].Trustee.TrusteeForm = TRUSTEE_IS_SID; + entries[i].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + entries[i].Trustee.ptstrName = (WCHAR *)&sid_entries[i]; + break; + } + + case ACCESS_DENIED_ACE_TYPE: + { + ACCESS_DENIED_ACE *deny = (ACCESS_DENIED_ACE *)ace; + entries[i].grfAccessMode = DENY_ACCESS; + entries[i].grfInheritance = ace->AceFlags; + entries[i].grfAccessPermissions = deny->Mask; + + CopySid(sizeof(MAX_SID), (PSID)&sid_entries[i], (PSID)&deny->SidStart); + entries[i].Trustee.pMultipleTrustee = NULL; + entries[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + entries[i].Trustee.TrusteeForm = TRUSTEE_IS_SID; + entries[i].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + entries[i].Trustee.ptstrName = (WCHAR *)&sid_entries[i]; + break; + } + + default: + FIXME("Unhandled ace type %d\n", ace->AceType); + entries[i].grfAccessMode = NOT_USED_ACCESS; + continue; + } + } + + *count = sizeinfo.AceCount; + *list = entries; + return ERROR_SUCCESS; + +error: + LocalFree(entries); + return RtlNtStatusToDosError(status); } /****************************************************************************** diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 73fd7524776..08d3705771b 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -133,6 +133,7 @@ static BOOL (WINAPI *pGetWindowsAccountDomainSid)(PSID,PSID,DWORD*); static void (WINAPI *pRtlInitAnsiString)(PANSI_STRING,PCSZ); static NTSTATUS (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); static PSID_IDENTIFIER_AUTHORITY (WINAPI *pGetSidIdentifierAuthority)(PSID); +static DWORD (WINAPI *pGetExplicitEntriesFromAclW)(PACL,PULONG,PEXPLICIT_ACCESSW*); static HMODULE hmod; static int myARGC; @@ -227,6 +228,7 @@ static void init(void) pGetWindowsAccountDomainSid = (void *)GetProcAddress(hmod, "GetWindowsAccountDomainSid"); pGetSidIdentifierAuthority = (void *)GetProcAddress(hmod, "GetSidIdentifierAuthority"); pDuplicateTokenEx = (void *)GetProcAddress(hmod, "DuplicateTokenEx"); + pGetExplicitEntriesFromAclW = (void *)GetProcAddress(hmod, "GetExplicitEntriesFromAclW"); myARGC = winetest_get_mainargs( &myARGV ); } @@ -7098,6 +7100,145 @@ static void test_child_token_sd(void) HeapFree(GetProcessHeap(), 0, sd); } +static void test_GetExplicitEntriesFromAclW(void) +{ + static const WCHAR wszCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'}; + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY }; + SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY }; + PSID everyone_sid = NULL, users_sid = NULL; + EXPLICIT_ACCESSW access; + EXPLICIT_ACCESSW *access2; + PACL new_acl, old_acl = NULL; + ULONG count; + DWORD res; + + if (!pGetExplicitEntriesFromAclW) + { + win_skip("GetExplicitEntriesFromAclW is not available\n"); + return; + } + + if (!pSetEntriesInAclW) + { + win_skip("SetEntriesInAclW is not available\n"); + return; + } + + old_acl = HeapAlloc(GetProcessHeap(), 0, 256); + res = InitializeAcl(old_acl, 256, ACL_REVISION); + if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("ACLs not implemented - skipping tests\n"); + HeapFree(GetProcessHeap(), 0, old_acl); + return; + } + ok(res, "InitializeAcl failed with error %d\n", GetLastError()); + + res = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid); + ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError()); + + res = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &users_sid); + ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError()); + + res = AddAccessAllowedAce(old_acl, ACL_REVISION, KEY_READ, users_sid); + ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError()); + + access2 = NULL; + res = pGetExplicitEntriesFromAclW(old_acl, &count, &access2); + ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError()); + ok(count == 1, "Expected count == 1, got %d\n", count); + ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode); + ok(access2[0].grfAccessPermissions == KEY_READ, "Expected KEY_READ, got %d\n", access2[0].grfAccessPermissions); + ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm); + ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance); + ok(EqualSid(access2[0].Trustee.ptstrName, users_sid), "Expected equal SIDs\n"); + LocalFree(access2); + + access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + access.Trustee.pMultipleTrustee = NULL; + + access.grfAccessPermissions = KEY_WRITE; + access.grfAccessMode = GRANT_ACCESS; + access.grfInheritance = NO_INHERITANCE; + access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + access.Trustee.TrusteeForm = TRUSTEE_IS_SID; + access.Trustee.ptstrName = everyone_sid; + res = pSetEntriesInAclW(1, &access, old_acl, &new_acl); + ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); + ok(new_acl != NULL, "returned acl was NULL\n"); + + access2 = NULL; + res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2); + ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError()); + ok(count == 2, "Expected count == 2, got %d\n", count); + ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode); + ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions); + ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, + "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType); + ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm); + ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance); + ok(EqualSid(access2[0].Trustee.ptstrName, everyone_sid), "Expected equal SIDs\n"); + LocalFree(access2); + LocalFree(new_acl); + + access.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + res = pSetEntriesInAclW(1, &access, old_acl, &new_acl); + ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); + ok(new_acl != NULL, "returned acl was NULL\n"); + + access2 = NULL; + res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2); + ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError()); + ok(count == 2, "Expected count == 2, got %d\n", count); + ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode); + ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions); + ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, + "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType); + ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm); + ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance); + ok(EqualSid(access2[0].Trustee.ptstrName, everyone_sid), "Expected equal SIDs\n"); + LocalFree(access2); + LocalFree(new_acl); + + access.Trustee.TrusteeForm = TRUSTEE_IS_NAME; + access.Trustee.ptstrName = (LPWSTR)wszCurrentUser; + res = pSetEntriesInAclW(1, &access, old_acl, &new_acl); + ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); + ok(new_acl != NULL, "returned acl was NULL\n"); + + access2 = NULL; + res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2); + ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError()); + ok(count == 2, "Expected count == 2, got %d\n", count); + ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode); + ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions); + ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, + "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType); + ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm); + ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance); + LocalFree(access2); + LocalFree(new_acl); + + access.grfAccessMode = REVOKE_ACCESS; + access.Trustee.TrusteeForm = TRUSTEE_IS_SID; + access.Trustee.ptstrName = users_sid; + res = pSetEntriesInAclW(1, &access, old_acl, &new_acl); + ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); + ok(new_acl != NULL, "returned acl was NULL\n"); + + access2 = (void *)0xdeadbeef; + res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2); + ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError()); + ok(count == 0, "Expected count == 0, got %d\n", count); + ok(access2 == NULL, "access2 was not NULL\n"); + LocalFree(new_acl); + + FreeSid(users_sid); + FreeSid(everyone_sid); + HeapFree(GetProcessHeap(), 0, old_acl); +} + START_TEST(security) { init(); @@ -7151,6 +7292,7 @@ START_TEST(security) test_pseudo_tokens(); test_maximum_allowed(); test_token_label(); + test_GetExplicitEntriesFromAclW(); /* Must be the last test, modifies process token */ test_token_security_descriptor();