/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
*/
/*
* Copyright Likewise Software
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Authors: Rafal Szczesniak (rafal@likewisesoftware.com)
*/
#include
#include
#define MU_ASSERT_STATUS_SUCCESS(status) \
MU_ASSERT(STATUS_SUCCESS == (status))
MU_TEST(Security, 0000_SidInitialize)
{
NTSTATUS status = STATUS_SUCCESS;
PSID sid = NULL;
ULONG sidSize = 0;
SID_IDENTIFIER_AUTHORITY ntAuthority = { SECURITY_NT_AUTHORITY };
const UCHAR ntSubAuthorityCount = 4;
sidSize = RtlLengthRequiredSid(ntSubAuthorityCount);
MU_ASSERT(sidSize >= SID_MIN_SIZE);
status = RTL_ALLOCATE(&sid, SID, sidSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlInitializeSid(sid, &ntAuthority, ntSubAuthorityCount);
MU_ASSERT_STATUS_SUCCESS(status);
MU_ASSERT(RtlValidSid(sid));
MU_ASSERT(RtlLengthSid(sid) == sidSize);
MU_ASSERT(RtlEqualMemory(&sid->IdentifierAuthority, &ntAuthority, sizeof(ntAuthority)));
RTL_FREE(&sid);
}
MU_TEST(Security, 0001_SidFromCString)
{
NTSTATUS status = STATUS_SUCCESS;
PSTR initialSidString = "S-1-5-21-100-200-300-500";
PSID sid = NULL;
PSTR parsedSidString = NULL;
status = RtlAllocateSidFromCString(&sid, initialSidString);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAllocateCStringFromSid(&parsedSidString, sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_ASSERT(RtlCStringIsEqual(initialSidString, parsedSidString, FALSE));
RTL_FREE(&parsedSidString);
RTL_FREE(&sid);
}
MU_TEST(Security, 0001_SidFromWC16String)
{
NTSTATUS status = STATUS_SUCCESS;
PSTR initialSidStringA = "S-1-5-21-100-200-300-500";
PWSTR initialSidString = NULL;
PSID sid = NULL;
PWSTR parsedSidString = NULL;
status = RtlWC16StringAllocateFromCString(&initialSidString, initialSidStringA);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAllocateSidFromWC16String(&sid, initialSidString);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAllocateWC16StringFromSid(&parsedSidString, sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_ASSERT(RtlWC16StringIsEqual(initialSidString, parsedSidString, FALSE));
RTL_FREE(&parsedSidString);
RTL_FREE(&sid);
RTL_FREE(&initialSidString);
}
MU_TEST(Security, 0002_SidChange)
{
MU_SKIP("Not implemented");
// RtlSidAllocate
// RtlSidCopyAlloc
// SidCopy
// RtlSidAppendRid
}
static
VOID
DumpSecurityDescriptor(
IN PSECURITY_DESCRIPTOR_ABSOLUTE SecurityDescriptor
)
{
NTSTATUS status = STATUS_SUCCESS;
SECURITY_DESCRIPTOR_CONTROL control = 0;
UCHAR revision = 0;
PSID sid = NULL;
BOOLEAN isDefaulted = FALSE;
PSTR sidString = NULL;
BOOLEAN isPresent = FALSE;
PACL acl = NULL;
ULONG aceIndex = 0;
status = RtlGetSecurityDescriptorControl(
SecurityDescriptor,
&control,
&revision);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("control = 0x%04x, revision = %u", control, revision);
status = RtlGetOwnerSecurityDescriptor(
SecurityDescriptor,
&sid,
&isDefaulted);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAllocateCStringFromSid(&sidString, sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("OwnerSid = %s (%c)", sidString, isDefaulted ? 'Y' : 'N');
status = RtlGetGroupSecurityDescriptor(
SecurityDescriptor,
&sid,
&isDefaulted);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAllocateCStringFromSid(&sidString, sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("GroupSid = %s (%c)", sidString, isDefaulted ? 'Y' : 'N');
status = RtlGetDaclSecurityDescriptor(
SecurityDescriptor,
&isPresent,
&acl,
&isDefaulted);
MU_ASSERT_STATUS_SUCCESS(status);
// ISSUE-Hmm...need to make public accessor for ace count since
// we made ACL extra private...
for (;;)
{
PACCESS_ALLOWED_ACE ace = NULL;
status = RtlGetAce(acl, aceIndex++, OUT_PPVOID(&ace));
if (STATUS_INVALID_PARAMETER == status)
{
break;
}
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("Dacl ACE %u - (Type = %u, Flags = 0x%02x, Size = %u)",
aceIndex,
ace->Header.AceType,
ace->Header.AceFlags,
ace->Header.AceSize);
switch (ace->Header.AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
status = RtlAllocateCStringFromSid(&sidString, (PSID) &ace->SidStart);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO(" 0x%08x %s", ace->Mask, sidString);
break;
}
}
}
static
VOID
DumpTokenInfo(
IN PACCESS_TOKEN Token,
IN TOKEN_INFORMATION_CLASS TokenInformationClass
)
{
NTSTATUS status = STATUS_SUCCESS;
PBYTE tokenInfo = NULL;
ULONG size = 0;
ULONG savedSize = 0;
status = RtlQueryAccessTokenInformation(
Token,
TokenInformationClass,
tokenInfo,
size,
&size);
MU_ASSERT(STATUS_BUFFER_TOO_SMALL == status);
MU_INFO("size = %u", size);
savedSize = size;
status = RTL_ALLOCATE(&tokenInfo, BYTE, size);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlQueryAccessTokenInformation(
Token,
TokenInformationClass,
tokenInfo,
size,
&size);
MU_INFO("status = 0x%08x", status);
MU_ASSERT_STATUS_SUCCESS(status);
MU_ASSERT(size == savedSize);
switch (TokenInformationClass)
{
case TokenUser:
{
PTOKEN_USER tokenUser = (PTOKEN_USER) tokenInfo;
PSTR sidString = NULL;
status = RtlAllocateCStringFromSid(&sidString, tokenUser->User.Sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("User = %s", sidString);
break;
}
case TokenGroups:
{
PTOKEN_GROUPS tokenGroups = (PTOKEN_GROUPS) tokenInfo;
ULONG i = 0;
PSTR sidString = NULL;
MU_INFO("GroupCount = %u", tokenGroups->GroupCount);
for (i = 0; i < tokenGroups->GroupCount; i++)
{
status = RtlAllocateCStringFromSid(&sidString, tokenGroups->Groups[i].Sid);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("Groups[%u] = (0x%08x, %s)", i, tokenGroups->Groups[i].Attributes, sidString);
}
break;
}
}
}
static
VOID
DumpToken(
IN PACCESS_TOKEN Token
)
{
DumpTokenInfo(Token, TokenUser);
DumpTokenInfo(Token, TokenGroups);
}
MU_TEST(Security, 0003_AccessCheck)
{
NTSTATUS status = STATUS_SUCCESS;
static BYTE buffer[] = {
0x01, 0x00, 0x04, 0x84, 0x14, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4c, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
0x06, 0x6a, 0xeb, 0x18, 0x5a, 0xbb, 0xfe, 0x46, 0xa8, 0x7f, 0x47, 0x83, 0x0d, 0x07, 0x00, 0x00,
0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x06, 0x6a, 0xeb, 0x18,
0x5a, 0xbb, 0xfe, 0x46, 0xa8, 0x7f, 0x47, 0x83, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0xcc, 0x00,
0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x06, 0x6a, 0xeb, 0x18, 0x5a, 0xbb, 0xfe, 0x46,
0xa8, 0x7f, 0x47, 0x83, 0xed, 0x06, 0x00, 0x00, 0x00, 0x10, 0x24, 0x00, 0xff, 0x01, 0x1f, 0x00,
0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x06, 0x6a, 0xeb, 0x18,
0x5a, 0xbb, 0xfe, 0x46, 0xa8, 0x7f, 0x47, 0x83, 0x0d, 0x07, 0x00, 0x00, 0x00, 0x1b, 0x24, 0x00,
0x00, 0x00, 0x00, 0x10, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
0x06, 0x6a, 0xeb, 0x18, 0x5a, 0xbb, 0xfe, 0x46, 0xa8, 0x7f, 0x47, 0x83, 0x0d, 0x07, 0x00, 0x00,
0x00, 0x10, 0x14, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
0x12, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x00, 0xff, 0x01, 0x1f, 0x00,
0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
0x00, 0x1b, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00
};
PSID sid = NULL;
TOKEN_USER tokenUser = { { 0 } };
union {
TOKEN_GROUPS tokenGroups;
struct {
ULONG GroupCount;
SID_AND_ATTRIBUTES Groups[10];
};
} tokenGroupsUnion = { .tokenGroups = { 0 } };
TOKEN_OWNER tokenOwner = { 0 };
TOKEN_PRIMARY_GROUP tokenPrimaryGroup = { 0 };
TOKEN_DEFAULT_DACL tokenDefaultDacl = { 0 };
PACCESS_TOKEN token = NULL;
PSECURITY_DESCRIPTOR_RELATIVE relativeSd = (PSECURITY_DESCRIPTOR_RELATIVE) (PBYTE) buffer;
ULONG relativeSdLength = sizeof(buffer);
PSECURITY_DESCRIPTOR_ABSOLUTE sd = NULL;
PACL dacl = NULL;
PACL sacl = NULL;
PSID owner = NULL;
PSID primaryGroup = NULL;
ULONG sdSize = 0;
ULONG daclSize = 0;
ULONG saclSize = 0;
ULONG ownerSize = 0;
ULONG primaryGroupSize = 0;
GENERIC_MAPPING mapping = {
.GenericRead = 0,
.GenericWrite = 0,
.GenericExecute = 0,
.GenericAll = 0,
};
ACCESS_MASK granted = 0;
BOOLEAN isGranted = FALSE;
// SID present in an ACE
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-1805");
MU_ASSERT_STATUS_SUCCESS(status);
tokenUser.User.Sid = sid;
// Bogus SID
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-12345678");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
SetFlag(tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Attributes, SE_GROUP_ENABLED);
tokenGroupsUnion.GroupCount++;
// Bogus SID
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-87654321");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
tokenGroupsUnion.GroupCount++;
// SID present in an ACE
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-1773");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
SetFlag(tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Attributes, SE_GROUP_ENABLED);
tokenGroupsUnion.GroupCount++;
status = RtlCreateAccessToken(
&token,
&tokenUser,
&tokenGroupsUnion.tokenGroups,
&tokenOwner,
&tokenPrimaryGroup,
&tokenDefaultDacl,
NULL);
MU_ASSERT_STATUS_SUCCESS(status);
DumpToken(token);
status = RtlValidRelativeSecurityDescriptor(
relativeSd,
relativeSdLength,
0);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlSelfRelativeToAbsoluteSD(
relativeSd,
NULL,
&sdSize,
NULL,
&daclSize,
NULL,
&saclSize,
NULL,
&ownerSize,
NULL,
&primaryGroupSize);
MU_ASSERT(STATUS_BUFFER_TOO_SMALL == status);
daclSize = LW_MAX(daclSize, 1);
saclSize = LW_MAX(saclSize, 1);
ownerSize = LW_MAX(ownerSize, 1);
primaryGroupSize = LW_MAX(primaryGroupSize, 1);
status = RTL_ALLOCATE(&sd, VOID, sdSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RTL_ALLOCATE(&dacl, VOID, daclSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RTL_ALLOCATE(&sacl, VOID, saclSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RTL_ALLOCATE(&owner, VOID, ownerSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RTL_ALLOCATE(&primaryGroup, VOID, primaryGroupSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlSelfRelativeToAbsoluteSD(
relativeSd,
sd,
&sdSize,
dacl,
&daclSize,
sacl,
&saclSize,
owner,
&ownerSize,
primaryGroup,
&primaryGroupSize);
MU_ASSERT_STATUS_SUCCESS(status);
DumpSecurityDescriptor(sd);
isGranted = RtlAccessCheck(
sd,
token,
MAXIMUM_ALLOWED,
0,
&mapping,
&granted,
&status);
MU_ASSERT(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED);
MU_INFO("status = 0x%08x, granted = 0x%08x (%c)", status, granted, isGranted ? 'Y' : 'N');
}
MU_TEST(Security, 0004_AccessMarshal)
{
NTSTATUS status = STATUS_SUCCESS;
PSID sid = NULL;
TOKEN_USER tokenUser = { { 0 } };
union {
TOKEN_GROUPS tokenGroups;
struct {
ULONG GroupCount;
SID_AND_ATTRIBUTES Groups[10];
};
} tokenGroupsUnion = { .tokenGroups = { 0 } };
TOKEN_OWNER tokenOwner = { 0 };
TOKEN_PRIMARY_GROUP tokenPrimaryGroup = { 0 };
TOKEN_DEFAULT_DACL tokenDefaultDacl = { 0 };
PACCESS_TOKEN token = NULL;
PACCESS_TOKEN token2 = NULL;
PACCESS_TOKEN_SELF_RELATIVE relative = NULL;
ULONG ulRelativeSize = 0;
//PSID primaryGroup = NULL;
// SID present in an ACE
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-1805");
MU_ASSERT_STATUS_SUCCESS(status);
tokenUser.User.Sid = sid;
// Bogus SID
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-12345678");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
SetFlag(tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Attributes, SE_GROUP_ENABLED);
tokenGroupsUnion.GroupCount++;
// Bogus SID
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-87654321");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
tokenGroupsUnion.GroupCount++;
// SID present in an ACE
status = RtlAllocateSidFromCString(&sid, "S-1-5-21-418081286-1191099226-2202501032-1773");
MU_ASSERT_STATUS_SUCCESS(status);
tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Sid = sid;
SetFlag(tokenGroupsUnion.Groups[tokenGroupsUnion.GroupCount].Attributes, SE_GROUP_ENABLED);
tokenGroupsUnion.GroupCount++;
status = RtlCreateAccessToken(
&token,
&tokenUser,
&tokenGroupsUnion.tokenGroups,
&tokenOwner,
&tokenPrimaryGroup,
&tokenDefaultDacl,
NULL);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("Original token:");
DumpToken(token);
status = RtlAccessTokenToSelfRelativeAccessToken(
token,
NULL,
&ulRelativeSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RTL_ALLOCATE(&relative, struct _ACCESS_TOKEN_SELF_RELATIVE, ulRelativeSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlAccessTokenToSelfRelativeAccessToken(
token,
relative,
&ulRelativeSize);
MU_ASSERT_STATUS_SUCCESS(status);
status = RtlSelfRelativeAccessTokenToAccessToken(
relative,
ulRelativeSize,
&token2);
MU_ASSERT_STATUS_SUCCESS(status);
MU_INFO("Reconstructed token:");
DumpToken(token2);
}
/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/