1461 lines
44 KiB
C++
1461 lines
44 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//
|
|
// ResourceAttributesSample.cpp
|
|
//
|
|
// A simple command line tool for creating a security descriptor with
|
|
// resource attribute ACEs and a CAP ID ACE, then calling AuthzAccessCheck
|
|
// on that security descriptor to display the resulting access rights granted.
|
|
//
|
|
// The caller can specify the resource attributes to use by either:
|
|
// 1. Supplying resource attributes through the command line, in the form
|
|
// (Name,ValueType,Flags,Value1,Value2...)
|
|
// 2. Pointing to a file that already has resource attributes.
|
|
//
|
|
// The program will do the following:
|
|
// 1. Read in the CAP ID, and check if it is applied to the machine:
|
|
// a. If CAP is applied, then it can be used in the AccessCheck.
|
|
// b. If CAP is not applied, the applied CAPs are printed and the
|
|
// program exits.
|
|
// 2. If a file is given, it tries to get its resource attributes.
|
|
// a. If present, the attributes are printed and used in the
|
|
// security descriptor.
|
|
// b. If not present, the program exits.
|
|
// 3. If resource attributes are given, they are parsed, and used in
|
|
// the security descriptor.
|
|
// 4. A security descriptor with a CAP ID ACE and resource attribute ACEs
|
|
// is created.
|
|
// 5. AuthzAccessCheck is called using this security descriptor, and the
|
|
// the resulting access rights granted are printed to the console.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma warning(disable: 26018)
|
|
#pragma warning(disable: 28251)
|
|
#include "ResourceAttributesSample.h"
|
|
|
|
|
|
_Success_(return == TRUE)
|
|
BOOL
|
|
CreateSecurityDescriptor(
|
|
_In_ PSID CapIDSid,
|
|
_In_reads_(ResourceAttributeCt) PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceAttributes,
|
|
_In_ DWORD ResourceAttributeCt,
|
|
_Outptr_ PSECURITY_DESCRIPTOR* SecurityDescriptorResult
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a self-relative security descriptor (SD) with System as the
|
|
owner and group. The DACL of the SD grants everyone full control, and
|
|
a SACL is created with a CAPID ACE and resource attribute ACEs and added
|
|
to the SD.
|
|
|
|
Arguments:
|
|
|
|
CapIDSid : The SID of the CAP ID Ace to add to the SD
|
|
|
|
ResourceAttributes : An array of resource attributes to add to the SD
|
|
|
|
ResourceAttributeCt : The length of the ResourceAttributes array
|
|
|
|
SecurityDescriptorResult : The resulting SD upon success, otherwise NULL
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor = {0};
|
|
PSID SystemSID = NULL;
|
|
PSID EveryoneSID = NULL;
|
|
PACL Dacl = NULL;
|
|
PACL Sacl = NULL;
|
|
UCHAR DaclBuffer[1024] = {0};
|
|
UCHAR SaclBuffer[1024] = {0};
|
|
SID_IDENTIFIER_AUTHORITY SIDAuthNt = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
DWORD Bytes = 0;
|
|
DWORD Size = 0;
|
|
CLAIM_SECURITY_ATTRIBUTES_INFORMATION ClaimInfo = {0};
|
|
|
|
if (SecurityDescriptorResult == NULL ||
|
|
CapIDSid == NULL ||
|
|
ResourceAttributes == NULL)
|
|
{
|
|
wprintf(L"ERROR: Invalid argument\n");
|
|
goto Cleanup;
|
|
}
|
|
*SecurityDescriptorResult = NULL;
|
|
|
|
//
|
|
// Create a default security descriptor with system as the owner, system
|
|
// as a the primary group, and a DACL that grants everyone full control
|
|
//
|
|
|
|
// Initialize the security descriptor
|
|
if (!InitializeSecurityDescriptor(
|
|
&SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
PrintErrorMessage(L"ERROR: InitializeSecurityDescriptor Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Create the sytem SID for the security descriptor owner/group
|
|
if(!AllocateAndInitializeSid(
|
|
&SIDAuthNt,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&SystemSID))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AllocateAndInitializeSid Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Create the everyone SID
|
|
if(!AllocateAndInitializeSid(
|
|
&SIDAuthWorld,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&EveryoneSID))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AllocateAndInitializeSid Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Set the owner of the security descriptor to System.
|
|
if (!SetSecurityDescriptorOwner(&SecurityDescriptor, SystemSID, TRUE))
|
|
{
|
|
PrintErrorMessage(L"ERROR: SetSecurityDescriptorOwner Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Set the primary group to System.
|
|
if (!SetSecurityDescriptorGroup(&SecurityDescriptor, SystemSID, TRUE))
|
|
{
|
|
PrintErrorMessage(L"ERROR: SetSecurityDescriptorGroup Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Initialize the DACL
|
|
Dacl = (PACL)DaclBuffer;
|
|
if (!InitializeAcl(Dacl, ARRAYSIZE(DaclBuffer), ACL_REVISION))
|
|
{
|
|
PrintErrorMessage(L"ERROR: InitializeAcl Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Add an ACE to the DACL to grant everyone full control
|
|
if (!AddAccessAllowedAce(Dacl, ACL_REVISION, KEY_ALL_ACCESS, EveryoneSID))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AddAccessAllowedAce Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Now add the dACL to the security descriptor.
|
|
if (!SetSecurityDescriptorDacl(&SecurityDescriptor, TRUE, Dacl, FALSE))
|
|
{
|
|
PrintErrorMessage(L"ERROR: SetSecurityDescriptorDacl Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Initialize the SACL.
|
|
// Note: The ACL buffer is a static 1K buffer, so adding a large number of
|
|
// resource attribute ACEs will cause AddResourceAttributeAce to fail if
|
|
// the size exceeds the 1K limit. If you have a need for a large number
|
|
// of ACEs, consider increasing the buffer size or using dynamic memory
|
|
// allocation.
|
|
Sacl = (PACL)SaclBuffer;
|
|
if (!InitializeAcl(Sacl, ARRAYSIZE(SaclBuffer), ACL_REVISION))
|
|
{
|
|
PrintErrorMessage(L"ERROR: InitializeAcl Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Add a CAPID Ace to the ACL
|
|
if (!AddScopedPolicyIDAce(Sacl, ACL_REVISION, 0, 0, CapIDSid))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AddScopedPolicyIDAce Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Build up the claim information structure.
|
|
ClaimInfo.AttributeCount = 1;
|
|
ClaimInfo.Version = CLAIM_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1;
|
|
|
|
// Iterate over the resource claims and add an ACE for each one.
|
|
for (DWORD i = 0; i < ResourceAttributeCt; ++i)
|
|
{
|
|
ClaimInfo.Attribute.pAttributeV1 = ResourceAttributes[i];
|
|
if (!AddResourceAttributeAce(
|
|
Sacl,
|
|
ACL_REVISION,
|
|
0,
|
|
0,
|
|
EveryoneSID,
|
|
&ClaimInfo,
|
|
&Bytes))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AddResourceAttributeAce Error",
|
|
GetLastError());
|
|
wprintf(L" -Attribute = %ws\n", ResourceAttributes[i]->Name);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// Now add the SACL to the security descriptor.
|
|
if (!SetSecurityDescriptorSacl(&SecurityDescriptor, TRUE, Sacl, FALSE))
|
|
{
|
|
PrintErrorMessage(L"ERROR: SetSecurityDescriptorSacl Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Convert to a self relative security descriptor
|
|
if (!MakeSelfRelativeSD(&SecurityDescriptor, NULL, &Size))
|
|
{
|
|
// First call to MakeSelfRelativeSD should return
|
|
// ERROR_INSUFFICIENT_BUFFER and set Size to the necessary buffer
|
|
// length
|
|
assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
*SecurityDescriptorResult = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,Size);
|
|
if (NULL == *SecurityDescriptorResult)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!MakeSelfRelativeSD(
|
|
&SecurityDescriptor,
|
|
*SecurityDescriptorResult,
|
|
&Size))
|
|
{
|
|
PrintErrorMessage(L"ERROR: MakeSelfRelativeSD Error",
|
|
GetLastError());
|
|
LocalFree(*SecurityDescriptorResult);
|
|
*SecurityDescriptorResult = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// We have successfully created a self-relative security descriptor
|
|
// with the Central Access Policy and resource attributes
|
|
Succeeded = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*SecurityDescriptorResult = NULL;
|
|
}
|
|
|
|
Cleanup:
|
|
if (EveryoneSID)
|
|
{
|
|
FreeSid(EveryoneSID);
|
|
}
|
|
if (SystemSID)
|
|
{
|
|
FreeSid(SystemSID);
|
|
}
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PerformAccessCheck(
|
|
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an Authz context and calls AuthzAccessCheck on the supplied
|
|
security descriptor. The results of the access check are printed out to
|
|
the console.
|
|
|
|
Arguments:
|
|
|
|
SecurityDescriptor : The security descriptor used in the access check.
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
HANDLE Token = NULL;
|
|
AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResMgrHandle = NULL;
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientHandle = NULL;
|
|
LUID ZeroLuid = {0, 0};
|
|
AUTHZ_ACCESS_REQUEST AccessRequest = {0};
|
|
AUTHZ_ACCESS_REPLY AccessReply = {0};
|
|
BYTE Buffer[1024] = {0};
|
|
|
|
if (NULL == SecurityDescriptor)
|
|
{
|
|
wprintf(L"ERROR: Invalid argument\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Open the process token
|
|
if (!OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&Token))
|
|
{
|
|
PrintErrorMessage(L"ERROR: OpenProcessToken Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Initialize the resource manager for AuthzAccessCheck
|
|
if (!AuthzInitializeResourceManager(
|
|
AUTHZ_RM_FLAG_NO_AUDIT,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&AuthzResMgrHandle))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AuthzInitializeResourceManager Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the authorization context from the token to use for access check
|
|
if (!AuthzInitializeContextFromToken(
|
|
0,
|
|
Token,
|
|
AuthzResMgrHandle,
|
|
NULL,
|
|
ZeroLuid,
|
|
NULL,
|
|
&AuthzClientHandle))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AuthzInitializeContextFromToken Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Initialize the request and reply structures passed to AuthzAccessCheck
|
|
AccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
|
|
AccessRequest.PrincipalSelfSid = NULL;
|
|
AccessRequest.ObjectTypeList = NULL;
|
|
AccessRequest.ObjectTypeListLength = 0;
|
|
AccessRequest.OptionalArguments = NULL;
|
|
|
|
AccessReply.ResultListLength = 1;
|
|
AccessReply.GrantedAccessMask = (PACCESS_MASK)Buffer;
|
|
AccessReply.Error = (PDWORD)(Buffer+sizeof(ACCESS_MASK));
|
|
|
|
// Perform the actual access check
|
|
if (!AuthzAccessCheck(
|
|
0,
|
|
AuthzClientHandle,
|
|
&AccessRequest,
|
|
NULL,
|
|
SecurityDescriptor,
|
|
NULL,
|
|
0,
|
|
&AccessReply,
|
|
NULL))
|
|
{
|
|
PrintErrorMessage(L"ERROR: AuthzAccessCheck Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Print out the results of the AuthzAccessCheck
|
|
wprintf(L"\nAccess Mask = 0x%08x\n\n", AccessReply.GrantedAccessMask[0]);
|
|
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
if (NULL != AuthzClientHandle)
|
|
{
|
|
AuthzFreeContext(AuthzClientHandle);
|
|
}
|
|
if (NULL != AuthzResMgrHandle)
|
|
{
|
|
AuthzFreeResourceManager(AuthzResMgrHandle);
|
|
}
|
|
if (NULL != Token)
|
|
{
|
|
CloseHandle(Token);
|
|
}
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
_Success_(return == TRUE)
|
|
BOOL
|
|
IsValidCapID(
|
|
_In_ LPCWSTR CapID,
|
|
_Outptr_ PSID* CapIDSidResult
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if the requested CAP ID is present on the machine. If it is not,
|
|
then the applied CAPs are printed out to the console. If it is present,
|
|
then the string SID is converted to a binary SID and returned to the
|
|
caller.
|
|
|
|
Arguments:
|
|
|
|
CapID : The CAP ID requested
|
|
|
|
CapIDSidResult : The SID form of the requested CAP ID returned if the
|
|
CAP is present on the machine, otherwise NULL
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the CAP is present, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
NTSTATUS Status;
|
|
BOOL IsValidCapID = FALSE;
|
|
PSID CapIDSid = NULL;
|
|
PSID* AppliedCaps = NULL;
|
|
ULONG CapCount = 0;
|
|
LPWSTR CapIDString = NULL;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuthCap = SECURITY_SCOPED_POLICY_ID_AUTHORITY;
|
|
|
|
if (NULL == CapID || NULL == CapIDSidResult)
|
|
{
|
|
wprintf(L"ERROR: Invalid argument\n");
|
|
goto Cleanup;
|
|
}
|
|
*CapIDSidResult = NULL;
|
|
|
|
// Convert the CAPID string to a SID
|
|
if (!ConvertStringSidToSid(CapID, &CapIDSid))
|
|
{
|
|
PrintErrorMessage(L"ERROR: ConvertStringSidToSid Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Check that the CAPID is a valid SID
|
|
if (!IsValidSid(CapIDSid))
|
|
{
|
|
wprintf(L"ERROR: The supplied CAPID is not a valid SID\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Check that the SID is a valid CAP ID
|
|
if (!RtlEqualMemory(
|
|
&((PISID)CapIDSid)->IdentifierAuthority,
|
|
&SIDAuthCap,
|
|
sizeof(SID_IDENTIFIER_AUTHORITY)))
|
|
{
|
|
wprintf(L"ERROR: The CAPID doesn't have the correct authority S-1-17\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the applied CAPIDs on the machine
|
|
Status = LsaGetAppliedCAPIDs(NULL, &AppliedCaps, &CapCount);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
wprintf(L"ERROR: LsaGetAppliedCAPIDs Error %u\n", Status);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Search the applied CAPs on the machine for a match to the requested CAP
|
|
for (ULONG i = 0; i < CapCount; i++)
|
|
{
|
|
if (EqualSid(AppliedCaps[i], CapIDSid))
|
|
{
|
|
IsValidCapID = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsValidCapID)
|
|
{
|
|
*CapIDSidResult = CapIDSid;
|
|
CapIDSid = NULL;
|
|
}
|
|
else
|
|
{
|
|
// The requested CAPID is not part of the applied Central Policies
|
|
wprintf(L"The requested CAPID could not be found on the target machine."
|
|
L"\nThe applied CAPIDs are:\n");
|
|
for (ULONG i = 0; i < CapCount; i++)
|
|
{
|
|
if (!ConvertSidToStringSid(AppliedCaps[i], &CapIDString))
|
|
{
|
|
PrintErrorMessage(L"ERROR: ConvertSidToStringSid Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
wprintf(L" %ws\n", CapIDString);
|
|
|
|
LocalFree(CapIDString);
|
|
CapIDString = NULL;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (AppliedCaps != NULL)
|
|
{
|
|
for (ULONG i = 0; i < CapCount; i++)
|
|
{
|
|
LsaFreeMemory(AppliedCaps[i]);
|
|
}
|
|
LsaFreeMemory(AppliedCaps);
|
|
}
|
|
if (CapIDSid)
|
|
{
|
|
FreeSid(CapIDSid);
|
|
}
|
|
LocalFree(CapIDString);
|
|
|
|
return IsValidCapID;
|
|
}
|
|
|
|
|
|
_Success_(return == TRUE)
|
|
BOOL
|
|
GetFileResourceAttributes(
|
|
_In_ LPCWSTR FileName,
|
|
_Outptr_result_buffer_(*Count) PCLAIM_SECURITY_ATTRIBUTE_V1* FileResourceAttributes[],
|
|
_Out_ DWORD* Count
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the resource attribute ACEs from a file, parses the SDDL for the
|
|
resource attributes ACEs to print them in a friendly format to the console.
|
|
Then it interprets the resource attributes SDDL and populates a resource
|
|
claim structure that can be used to add a resouce attribute ACE to a
|
|
security descriptor.
|
|
|
|
Arguments:
|
|
|
|
FileName : The file to get the resource properties from.
|
|
|
|
FileResourceAttributes : The resulting array of resource attribute
|
|
structures.
|
|
|
|
Count : The number of claims in the array.
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
DWORD Success = ERROR_SUCCESS;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
PACL Sacl = NULL;
|
|
LPWSTR SDDL = NULL;
|
|
LPWSTR NextToken = NULL;
|
|
LPWSTR NextAttribute = NULL;
|
|
PRESOURCE_ATTRIBUTE AttributeTokens = NULL;
|
|
PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceAttributes = NULL;
|
|
DWORD AttributeCount = 0;
|
|
DWORD CurrentAttribute = 0;
|
|
DWORD ByteCount = 0;
|
|
|
|
if (NULL == FileName ||
|
|
NULL == FileResourceAttributes ||
|
|
NULL == Count)
|
|
{
|
|
wprintf(L"ERROR: Invalid argument\n");
|
|
goto Cleanup;
|
|
}
|
|
*FileResourceAttributes = NULL;
|
|
*Count = 0;
|
|
|
|
//
|
|
// Get the security descriptor for the file.
|
|
// Note that we will use the SecurityDescriptor, but Sacl is now
|
|
// also pointing to the attribute ACEs.
|
|
//
|
|
Success = GetNamedSecurityInfo(
|
|
FileName,
|
|
SE_FILE_OBJECT,
|
|
ATTRIBUTE_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Sacl,
|
|
&SecurityDescriptor);
|
|
if (ERROR_SUCCESS != Success)
|
|
{
|
|
PrintErrorMessage(L"ERROR: GetNamedSecurityInfo Error",
|
|
Success);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Convert the binary security descriptor to SDDL.
|
|
if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
SecurityDescriptor,
|
|
SDDL_REVISION_1,
|
|
ATTRIBUTE_SECURITY_INFORMATION, // attribute ACEs only
|
|
&SDDL,
|
|
NULL))
|
|
{
|
|
PrintErrorMessage(L"ERROR: "
|
|
L"ConvertSecurityDescriptorToStringSecurityDescriptor "
|
|
L"Error",
|
|
GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Count the number of resource attributes in the SDDL
|
|
NextToken = SDDL;
|
|
while (NextToken)
|
|
{
|
|
NextToken = wcsstr(NextToken, L"(RA;");
|
|
if (NextToken != NULL)
|
|
{
|
|
AttributeCount++;
|
|
NextToken++;
|
|
}
|
|
}
|
|
|
|
if (AttributeCount < 1)
|
|
{
|
|
wprintf(L"\nThe file %ws does not have resource attributes\n",
|
|
FileName);
|
|
goto Cleanup;
|
|
}
|
|
|
|
AttributeTokens = new RESOURCE_ATTRIBUTE[AttributeCount];
|
|
if (NULL == AttributeTokens)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
ZeroMemory(AttributeTokens, AttributeCount * sizeof(RESOURCE_ATTRIBUTE));
|
|
|
|
// Parse the SDDL string to pull out the name, flags, type, and values
|
|
// tokens from each resource attribute.
|
|
NextToken = SDDL;
|
|
while (NextToken)
|
|
{
|
|
// Look for (RA; which is the resource ACE signature
|
|
NextToken = wcsstr(NextToken, L"(RA;");
|
|
|
|
if (NextToken != NULL)
|
|
{
|
|
// Skip past AceType
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Skip past AceFlags
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Skip past Rights
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Skip past ObjectGuid
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Skip past InheritObjectGuid
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Skip past AccountSid
|
|
NextToken = wcsstr(NextToken, L";");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
// Get the start of the resource claim string
|
|
NextToken = wcsstr(NextToken, L"(");
|
|
if (NULL == NextToken)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Resource claim string ends at closing parenthesis
|
|
NextAttribute = wcstok_s(NULL,L")",&NextToken);
|
|
if (NULL == NextAttribute)
|
|
{
|
|
wprintf(L"ERROR: Invalid SDDL encountered\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Parse the resource attribute string into its tokens
|
|
if (!ParseResourceAttributeString(
|
|
NextAttribute,
|
|
AttributeTokens[CurrentAttribute]))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
NextAttribute = NULL;
|
|
CurrentAttribute++;
|
|
}
|
|
}
|
|
|
|
// Allocate an array of resource claim structures to fill and return
|
|
ByteCount = sizeof(PCLAIM_SECURITY_ATTRIBUTE_V1) * AttributeCount;
|
|
ResourceAttributes = static_cast<PCLAIM_SECURITY_ATTRIBUTE_V1*>(
|
|
LocalAlloc(LPTR, ByteCount));
|
|
if (NULL == ResourceAttributes)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
AttributeCount = 0;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Loop over the parsed resource attributes to print the values to the
|
|
// console, and fill the claim structures to return to the caller.
|
|
wprintf(L"\nResource attributes for file %ws:\n\n", FileName);
|
|
for (CurrentAttribute = 0;
|
|
CurrentAttribute < AttributeCount;
|
|
CurrentAttribute++)
|
|
{
|
|
PrintResourceAttribute(AttributeTokens[CurrentAttribute]);
|
|
if (!InterpretResourceAttribute(
|
|
AttributeTokens[CurrentAttribute],
|
|
&ResourceAttributes[CurrentAttribute]))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
*FileResourceAttributes = ResourceAttributes;
|
|
*Count = AttributeCount;
|
|
ResourceAttributes = NULL;
|
|
AttributeCount = 0;
|
|
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
if (AttributeTokens)
|
|
{
|
|
delete [] AttributeTokens;
|
|
}
|
|
|
|
for (DWORD i = 0; i < AttributeCount && ResourceAttributes; ++i)
|
|
{
|
|
LocalFree(ResourceAttributes[i]);
|
|
}
|
|
LocalFree(ResourceAttributes);
|
|
|
|
LocalFree(SDDL);
|
|
LocalFree(SecurityDescriptor);
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ParseResourceAttributeString(
|
|
_In_ LPWSTR AttributeString,
|
|
_Inout_ RESOURCE_ATTRIBUTE& Attribute
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a resource attribute in the SDDL format:
|
|
(Name, ValueType, Flags, Value1, Value2,...)
|
|
The string is validated and parsed to extract the name, type, flags, and
|
|
values strings.
|
|
|
|
Arguments:
|
|
|
|
AttributeString : The full resource attribute in (name,type,flags,values).
|
|
|
|
Attribute : A structure containing the tokenized parts of the
|
|
attribute.
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
LPWSTR NextToken = NULL;
|
|
|
|
if (NULL == AttributeString)
|
|
{
|
|
wprintf(L"ERROR: Invalid parameter\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken = AttributeString;
|
|
|
|
//
|
|
// Tokenize the string to get pointers to the name, type, flags, and values
|
|
//
|
|
|
|
// Extract Name
|
|
if (NextToken[0] != L'(')
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute format - attribute doesn't"
|
|
L"have starting '('\n");
|
|
goto Cleanup;
|
|
}
|
|
NextToken++;
|
|
|
|
Attribute.Name = wcstok_s(NextToken, L",", &NextToken);
|
|
if (NULL == Attribute.Name)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute format - no name\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Extract Type
|
|
Attribute.Type = wcstok_s(NULL, L",", &NextToken);
|
|
if (NULL == Attribute.Type)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute format - no type\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Extract Flags
|
|
Attribute.Flags = wcstok_s(NULL,L",",&NextToken);
|
|
if (NULL == Attribute.Flags)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute format - no flags\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Extract Values
|
|
Attribute.Values = wcstok_s(NULL,L")",&NextToken);
|
|
if (NULL == Attribute.Values)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute format - no values\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
_Success_(return == TRUE)
|
|
BOOL
|
|
InterpretResourceAttribute(
|
|
_In_ RESOURCE_ATTRIBUTE AttributeTokens,
|
|
_Outptr_ PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceClaimResult
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a tokenized resource attribute string structure and produces a
|
|
self-relative claim structure that can be used to add a resource attribute
|
|
ACE to a security descriptor.
|
|
|
|
Arguments:
|
|
|
|
AttributeTokens : The tokenized resource attribute string structure.
|
|
|
|
ResourceClaimResult : The resulting resource claim structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
HRESULT hr = S_OK;
|
|
LPWSTR NextToken = NULL;
|
|
LPWSTR* Values = NULL;
|
|
LPWSTR EndPtr = NULL;
|
|
PCLAIM_SECURITY_ATTRIBUTE_V1 ResourceAttribute = NULL;
|
|
PBYTE NextMemory = NULL;
|
|
DWORD ByteCount = 0;
|
|
DWORD ValueCount = 0;
|
|
WORD ValueType = 0;
|
|
SIZE_T NameBytes = 0;
|
|
DWORD Flags = 0;
|
|
|
|
if (NULL == ResourceClaimResult)
|
|
{
|
|
wprintf(L"ERROR: Invalid parameter\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Interpret the value type string into an actual value type
|
|
ValueType = GetValueType(AttributeTokens.Type);
|
|
if (ValueType == CLAIM_SECURITY_ATTRIBUTE_TYPE_INVALID)
|
|
{
|
|
wprintf(L"Claim %ws has an unknown type (%ws)",
|
|
AttributeTokens.Name,
|
|
AttributeTokens.Type);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the number of claim values in the string (comma separated)
|
|
NextToken = AttributeTokens.Values;
|
|
while (NextToken)
|
|
{
|
|
ValueCount++;
|
|
NextToken = wcsstr(NextToken, L",");
|
|
if (NextToken != NULL)
|
|
{
|
|
NextToken++;
|
|
}
|
|
}
|
|
|
|
// Must be at lease one value
|
|
if (ValueCount < 1)
|
|
{
|
|
wprintf(L"ERROR: No values for the resource claim\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Break up the claim values string into individual values
|
|
Values = new LPWSTR[ValueCount];
|
|
if (NULL == Values)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get a pointer to each individual value
|
|
NextToken = AttributeTokens.Values;
|
|
for (DWORD i = 0; i < ValueCount && NextToken; ++i)
|
|
{
|
|
Values[i] = wcstok_s(NextToken, L",", &NextToken);
|
|
}
|
|
|
|
// Get the entire size required for the resource attribute structure, so we
|
|
// can allocate a single block of contiguous memory.
|
|
NameBytes = (wcsnlen(AttributeTokens.Name, MAX_PATH) + 1) * sizeof(WCHAR);
|
|
ByteCount = ALIGN(sizeof(CLAIM_SECURITY_ATTRIBUTE_V1));
|
|
ByteCount += ALIGN(NameBytes);
|
|
ByteCount += ALIGN(ValueCount * GetValueSize(ValueType));
|
|
|
|
if (ValueType == CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING)
|
|
{
|
|
// Additional allocation for each string in the array
|
|
for (DWORD i = 0; i < ValueCount; ++i)
|
|
{
|
|
ByteCount += ALIGN((wcslen(Values[i]) + 1) * sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
NextMemory = static_cast<PBYTE>(LocalAlloc(LPTR, ByteCount));
|
|
if (NULL == NextMemory)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
ResourceAttribute = (PCLAIM_SECURITY_ATTRIBUTE_V1)NextMemory;
|
|
NextMemory += ALIGN(sizeof(CLAIM_SECURITY_ATTRIBUTE_V1));
|
|
|
|
// Fill out resource claim structure
|
|
ResourceAttribute->ValueType = ValueType;
|
|
ResourceAttribute->ValueCount = ValueCount;
|
|
ResourceAttribute->Reserved = 0;
|
|
ResourceAttribute->Name = (LPWSTR)NextMemory;
|
|
|
|
hr = StringCbCopy(ResourceAttribute->Name, NameBytes, AttributeTokens.Name);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: StringCbCopy hr = 0x%08x\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
NextMemory += ALIGN(NameBytes);
|
|
|
|
// Convert the string hex flags to the actual integer value
|
|
EndPtr = AttributeTokens.Flags + wcslen(AttributeTokens.Flags);
|
|
Flags = wcstoul(AttributeTokens.Flags, &EndPtr, 0);
|
|
|
|
if(((Flags & 0x0000FFFF) & (~CLAIM_SECURITY_ATTRIBUTE_VALID_FLAGS)) != 0)
|
|
{
|
|
wprintf(L"ERROR: Invalid flags\n");
|
|
goto Cleanup;
|
|
}
|
|
ResourceAttribute->Flags = Flags;
|
|
|
|
// Fill up the values array
|
|
switch(ValueType)
|
|
{
|
|
case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
|
|
ResourceAttribute->Values.pInt64 = (LONG64*)NextMemory;
|
|
for (DWORD i = 0; i < ValueCount; ++i)
|
|
{
|
|
EndPtr = Values[i] + wcslen(Values[i]);
|
|
ResourceAttribute->Values.pInt64[i] = _wcstoi64(Values[i],
|
|
&EndPtr,
|
|
0);
|
|
}
|
|
break;
|
|
case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
|
|
case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
|
|
ResourceAttribute->Values.pUint64 = (DWORD64*)NextMemory;
|
|
for (DWORD i = 0; i < ValueCount; ++i)
|
|
{
|
|
EndPtr = Values[i] + wcslen(Values[i]);
|
|
ResourceAttribute->Values.pUint64[i] = _wcstoui64(Values[i],
|
|
&EndPtr,
|
|
0);
|
|
}
|
|
break;
|
|
case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
|
|
ResourceAttribute->Values.ppString = (LPWSTR*)NextMemory;
|
|
NextMemory += ALIGN(ValueCount * GetValueSize(ValueType));
|
|
|
|
for (DWORD i = 0; i < ValueCount; ++i)
|
|
{
|
|
ResourceAttribute->Values.ppString[i] = (LPWSTR)NextMemory;
|
|
hr = StringCbCopy(ResourceAttribute->Values.ppString[i],
|
|
(wcslen(Values[i]) + 1) * sizeof(WCHAR),
|
|
Values[i]);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: StringCbCopy hr = 0x%08\n");
|
|
goto Cleanup;
|
|
}
|
|
NextMemory += ALIGN((wcslen(Values[i]) + 1) * sizeof(WCHAR));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
*ResourceClaimResult = ResourceAttribute;
|
|
ResourceAttribute = NULL;
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
if (Values)
|
|
{
|
|
delete [] Values;
|
|
}
|
|
LocalFree(ResourceAttribute);
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
_Success_(return == TRUE)
|
|
BOOL
|
|
ParseResourceAttributesArguments(
|
|
_In_ LPCWSTR ResourceAttributesArgs,
|
|
_Outptr_result_buffer_(*Count) PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceAttributesResult[],
|
|
_Out_ DWORD* Count
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the resource attribute arguments passed in on the command line using
|
|
the SDDL format for resource attributes:
|
|
(Name, ValueType, Flags, Value1, Value2,...)
|
|
|
|
Arguments:
|
|
|
|
ResourceAttributesArgs : The resource attributes arguments string.
|
|
|
|
ResourceAttributesResult : An array of parsed resource attributes in claim
|
|
structures that can be used to add a resource
|
|
claim to a security descriptor.
|
|
|
|
Count : The number of claims in the array.
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE - If the function succeeds, TRUE is returned, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceAttributes = NULL;
|
|
DWORD AttributeCount = 0;
|
|
LPWSTR NextToken = NULL;
|
|
LPWSTR NextAttribute = NULL;
|
|
DWORD ByteCount = 0;
|
|
RESOURCE_ATTRIBUTE Attribute = {0};
|
|
DWORD CurrentAttribute = 0;
|
|
|
|
if (NULL == ResourceAttributesArgs ||
|
|
NULL == ResourceAttributesResult ||
|
|
NULL == Count)
|
|
{
|
|
wprintf(L"ERROR: Invalid argument\n");
|
|
goto Cleanup;
|
|
}
|
|
*ResourceAttributesResult = NULL;
|
|
*Count = 0;
|
|
|
|
if (ResourceAttributesArgs[0] != L'(')
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attributes parameter\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the number of resource attributes by searching for the "(" token
|
|
// Resource attributes must be of the form: (Name, Type, Flags, Value1,...)
|
|
NextToken = (LPWSTR)ResourceAttributesArgs;
|
|
while(NextToken != NULL)
|
|
{
|
|
NextToken = wcsstr(NextToken, L"(");
|
|
if (NULL != NextToken)
|
|
{
|
|
AttributeCount++;
|
|
NextToken++;
|
|
}
|
|
}
|
|
|
|
if (AttributeCount < 1)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attributes parameter format\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Allocate an array of claim structures
|
|
ByteCount = AttributeCount * sizeof(PCLAIM_SECURITY_ATTRIBUTE_V1);
|
|
ResourceAttributes = static_cast<PCLAIM_SECURITY_ATTRIBUTE_V1*>(
|
|
LocalAlloc(LPTR, ByteCount));
|
|
if (NULL == ResourceAttributes)
|
|
{
|
|
wprintf(L"ERROR: Out of memory\n");
|
|
AttributeCount = 0;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Iterate over the resource attributes argument, parsing each attribute,
|
|
// then convert the string resource attribute into a claim structure
|
|
// required for adding the resource claims to an ACE
|
|
wprintf(L"\nThe requested resource attributes are:\n\n");
|
|
NextToken = (LPWSTR)ResourceAttributesArgs;
|
|
while(NextToken)
|
|
{
|
|
// Start of the next claim
|
|
NextToken = wcsstr(NextToken, L"(");
|
|
if (NextToken != NULL)
|
|
{
|
|
// End of claim
|
|
NextAttribute = wcstok_s(NULL,L")",&NextToken);
|
|
if (NULL == NextAttribute)
|
|
{
|
|
wprintf(L"ERROR: Invalid resource attribute parameter format:"
|
|
L"%ws\n", NextToken);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Intermediate parsing of the resource string
|
|
if (!ParseResourceAttributeString(NextAttribute, Attribute))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
PrintResourceAttribute(Attribute);
|
|
|
|
// Convert the string resource structure into an actual claim
|
|
// structure
|
|
if (!InterpretResourceAttribute(
|
|
Attribute,
|
|
&ResourceAttributes[CurrentAttribute]))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
NextAttribute = NULL;
|
|
CurrentAttribute++;
|
|
}
|
|
}
|
|
|
|
*ResourceAttributesResult = ResourceAttributes;
|
|
*Count = AttributeCount;
|
|
ResourceAttributes = NULL;
|
|
AttributeCount = 0;
|
|
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
for (DWORD i = 0; i < AttributeCount && ResourceAttributes; ++i)
|
|
{
|
|
LocalFree(ResourceAttributes[i]);
|
|
}
|
|
LocalFree (ResourceAttributes);
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintResourceAttribute(
|
|
_In_ RESOURCE_ATTRIBUTE Attribute
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to prints out a resource attribute in a friendly format.
|
|
|
|
Arguments:
|
|
|
|
Attribute : A structure containing the resource attribute to print.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LPWSTR Type = Attribute.Type;;
|
|
LPWSTR FriendlyValueType = NULL;
|
|
|
|
if(0 == _wcsnicmp(Type, SDDL_INT, SDDL_LEN_TAG(SDDL_INT)))
|
|
{
|
|
FriendlyValueType = L"Integer";
|
|
}
|
|
else if(0 == _wcsnicmp(Type, SDDL_UINT, SDDL_LEN_TAG(SDDL_UINT)))
|
|
{
|
|
FriendlyValueType = L"Unsigned Integer";
|
|
}
|
|
else if(0 == _wcsnicmp(Type, SDDL_WSTRING, SDDL_LEN_TAG(SDDL_WSTRING)))
|
|
{
|
|
FriendlyValueType = L"String";
|
|
}
|
|
else if(0 == _wcsnicmp(Type, SDDL_BOOLEAN, SDDL_LEN_TAG(SDDL_BOOLEAN)))
|
|
{
|
|
FriendlyValueType = L"Boolean";
|
|
}
|
|
else
|
|
{
|
|
FriendlyValueType = L"Unknown";
|
|
}
|
|
|
|
wprintf(L"Resource Attribute:\n");
|
|
wprintf(L" - Name : %ws\n", Attribute.Name);
|
|
wprintf(L" - Type : %ws (%ws)\n", FriendlyValueType, Type);
|
|
wprintf(L" - Flags : %ws\n", Attribute.Flags);
|
|
wprintf(L" - Values : %ws\n", Attribute.Values);
|
|
wprintf(L"\n");
|
|
}
|
|
|
|
|
|
int
|
|
__cdecl
|
|
wmain(
|
|
_In_ DWORD argc,
|
|
_In_reads_(argc) LPCWSTR argv[]
|
|
)
|
|
{
|
|
BOOL Succeeded = FALSE;
|
|
LPWSTR FileName = NULL;
|
|
LPWSTR CapID = NULL;
|
|
LPWSTR Attributes = NULL;
|
|
PSID CapIDSid = NULL;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
PCLAIM_SECURITY_ATTRIBUTE_V1* ResourceAttributes = NULL;
|
|
DWORD ResourceAttributeCt = 0;
|
|
|
|
if (argc != 5)
|
|
{
|
|
PrintUsage();
|
|
goto Cleanup;
|
|
}
|
|
|
|
for (DWORD i = 1, j = 2; j < argc; i += 2, j += 2)
|
|
{
|
|
if (FileParameter(argv[i]))
|
|
{
|
|
FileName = (LPWSTR)argv[j];
|
|
}
|
|
else if (CapParameter(argv[i]))
|
|
{
|
|
CapID = (LPWSTR)argv[j];
|
|
}
|
|
else if (RaParameter(argv[i]))
|
|
{
|
|
Attributes = (LPWSTR)argv[j];
|
|
}
|
|
else
|
|
{
|
|
PrintUsage();
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ((CapID == NULL) ||
|
|
(Attributes == NULL && FileName == NULL) ||
|
|
(Attributes != NULL && FileName != NULL))
|
|
{
|
|
PrintUsage();
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Attributes && !ParseResourceAttributesArguments(
|
|
(LPCWSTR)Attributes,
|
|
&ResourceAttributes,
|
|
&ResourceAttributeCt))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (FileName && !GetFileResourceAttributes(
|
|
FileName,
|
|
&ResourceAttributes,
|
|
&ResourceAttributeCt))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!IsValidCapID((LPCWSTR)CapID, &CapIDSid))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!CreateSecurityDescriptor(
|
|
CapIDSid,
|
|
ResourceAttributes,
|
|
ResourceAttributeCt,
|
|
&SecurityDescriptor))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!PerformAccessCheck(SecurityDescriptor))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
Succeeded = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (CapIDSid)
|
|
{
|
|
FreeSid(CapIDSid);
|
|
}
|
|
LocalFree(SecurityDescriptor);
|
|
|
|
for (DWORD i = 0; i < ResourceAttributeCt; ++i)
|
|
{
|
|
LocalFree(ResourceAttributes[i]);
|
|
}
|
|
LocalFree(ResourceAttributes);
|
|
|
|
return Succeeded ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
VOID
|
|
PrintErrorMessage(
|
|
_In_ LPWSTR ErrorMessage,
|
|
_In_ DWORD ErrorCode
|
|
)
|
|
{
|
|
LPWSTR SystemMsg = NULL;
|
|
|
|
if (FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK |
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
ErrorCode,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPWSTR)&SystemMsg,
|
|
0,
|
|
NULL))
|
|
{
|
|
wprintf(L"%ws '%ws'(%u)\n", ErrorMessage, SystemMsg, ErrorCode);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"%ws %u\n", ErrorMessage, ErrorCode);
|
|
}
|
|
|
|
LocalFree(SystemMsg);
|
|
}
|
|
|
|
VOID
|
|
PrintUsage()
|
|
{
|
|
printf(
|
|
" \n"
|
|
" A command line tool for creating a security descriptor with resource \n"
|
|
" property claim ACEs and a Central Access Policy ACE, and displaying \n"
|
|
" the results of AuthzAccessCheck on that security descriptor. \n"
|
|
" \n"
|
|
" Usage: \n"
|
|
" \n"
|
|
" ResourceAttributesSample [-cap <ID>] [-file <PATH> | -ra <ATTRIBUTES>] \n"
|
|
" -cap : A Central Access Policy SID (CAP ID). CAP IDs are of the\n"
|
|
" form: S-1-17-... \n"
|
|
" -file : A file path used to get resource properties from a file \n"
|
|
" to use in the security descriptor. The file's resource \n"
|
|
" properties are also printed to the console. \n"
|
|
" -ra : Resource properties to add to the security descriptor. \n"
|
|
" Resource properties should be specified in the following\n"
|
|
" form: \n"
|
|
" (Name, ValueType, Flags, Value1, Value2...) \n"
|
|
" -Name = Resource Property Name \n"
|
|
" -ValueType = TI (Integer) \n"
|
|
" = TU (Unsigned Integer) \n"
|
|
" = TB (Boolean) \n"
|
|
" = TS (String) \n"
|
|
" -Flags = Hexadecimal Flag Value \n"
|
|
" -Value = Comma separated values \n"
|
|
" Examples: \n"
|
|
" \n"
|
|
" ResourceAttributesSample -cap S-1-17-11 -file C:\\test.txt \n"
|
|
" ResourceAttributesSample -cap S-1-17-22 -ra (\"Int\",TI,0x0,123) \n"
|
|
" \n"
|
|
);
|
|
}
|