Files
ladislav-zezula-FileTest/Page09Security.cpp
T
Ladislav Zezula 9301dbbb97 Progress
2023-02-06 10:13:40 +01:00

2296 lines
74 KiB
C++

/*****************************************************************************/
/* Page09Security.cpp Copyright (c) Ladislav Zezula 2005 */
/*---------------------------------------------------------------------------*/
/* Description : */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 15.08.05 1.00 Lad The first version of Page09Security.cpp */
/*****************************************************************************/
#include "FileTest.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// Local variables
#define TREE_ITEM_OWNER OWNER_SECURITY_INFORMATION
#define TREE_ITEM_GROUP GROUP_SECURITY_INFORMATION
#define TREE_ITEM_DACL DACL_SECURITY_INFORMATION
#define TREE_ITEM_SACL SACL_SECURITY_INFORMATION
#define TREE_ITEM_LABEL LABEL_SECURITY_INFORMATION
#define TREE_ITEM_NO_SID 0x10000000 // Under OWNER/GROUP, No SID present
#define TREE_ITEM_SID 0x10000001 // Under OWNER/GROUP: Present SID
#define TREE_ITEM_NULL_ACL 0x10000003 // NULL Acl ("click to create new")
#define TREE_ITEM_EMPTY_ACL 0x10000004 // Empty Acl ("click to create new")
#define TREE_ITEM_ACE 0x20000000 // An ACE. Lower 8 bits indicate the ACE type
#define TREE_ITEM_ACE_HEADER_TYPE 0x30000005 // ACE_HEADER::AceType
#define TREE_ITEM_ACE_HEADER_FLAGS 0x30000006 // ACE_HEADER::AceFlags
#define TREE_ITEM_ACE_HEADER_SIZE 0x30000007 // ACE_HEADER::AceSize
#define TREE_ITEM_ACE_MASK 0x30000008 // ACE::Mask
#define TREE_ITEM_ADS_ACE_MASK 0x30000009 // ACE::Mask for ADS ACEs
#define TREE_ITEM_MANDATORY_MASK 0x3000000A // ACE::Mask for SYSTEM_MANDATORY_LABEL_ACE
#define TREE_ITEM_MANDATORY_LABEL 0x3000000B // Integrity level as 32-bit value (SECURITY_MANDATORY_LABEL_AUTHORITY)
#define TREE_ITEM_ACE_FLAGS 0x3000000C // ACE:Flags
#define TREE_ITEM_ACE_OBJ_GUID 0x3000000D // ACE:ObjectType
#define TREE_ITEM_ACE_OBJ_GUID2 0x3000000E // ACE:InheritedObjectType
#define TREE_ITEM_TYPE_MASK 0xF0000000
#define TREE_ITEM_VALUE_MASK 0x0FFFFFFF
#define MAXIMUM_ACL_SIZE 0xFFF8 // The biggest ACL that can possibly exist
typedef bool (*ACE_FILTER_PROC)(PACE_HEADER pAceHeader);
// Masks for each tre item
static LPCTSTR szUnknownSid = _T("<UNKNOWN-SID>");
static LPCTSTR szNullAcl = _T("<NULL ACL. Double-click to create new...>");
static LPCTSTR szEmptyAcl = _T("<Empty ACL. Double-click to create new...>");
static LPCTSTR szAceHdrTypeFmt = _T("AceType: 0x%02lX");
static LPCTSTR szAceHdrFlagsFmt = _T("AceFlags: 0x%02lX ");
static LPCTSTR szAceHdrSizeFmt = _T("AceSize: 0x%04lX");
static LPCTSTR szAceMaskFmt = _T("Mask: 0x%08lX ");
static LPCTSTR szIntLevelFmt = _T("IntLevel: 0x%08lX");
static LPCTSTR szAceFlagsFmt = _T("Flags: 0x%08lX ");
static LPCTSTR szAceObjTypeFmt = _T("ObjectType: %s");
static LPCTSTR szAceObjTypeFmt2 = _T("InheritedObjectType: %s");
static SID_IDENTIFIER_AUTHORITY SiaNull = SECURITY_NULL_SID_AUTHORITY;
static SID_IDENTIFIER_AUTHORITY SiaWorld = SECURITY_WORLD_SID_AUTHORITY;
static SID_IDENTIFIER_AUTHORITY SiaLabel = SECURITY_MANDATORY_LABEL_AUTHORITY;
static TFlagInfo AceHdrTypes[] =
{
FLAGINFO_NUMV(ACCESS_ALLOWED_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_DENIED_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_AUDIT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_ALARM_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_ALLOWED_COMPOUND_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_ALLOWED_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_DENIED_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_AUDIT_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_ALARM_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_ALLOWED_CALLBACK_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_DENIED_CALLBACK_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_AUDIT_CALLBACK_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_ALARM_CALLBACK_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE),
FLAGINFO_NUMV(SYSTEM_MANDATORY_LABEL_ACE_TYPE),
FLAGINFO_END()
};
static TFlagInfo AceHdrFlags[] =
{
FLAGINFO_BITV(OBJECT_INHERIT_ACE),
FLAGINFO_BITV(CONTAINER_INHERIT_ACE),
FLAGINFO_BITV(NO_PROPAGATE_INHERIT_ACE),
FLAGINFO_BITV(INHERIT_ONLY_ACE),
FLAGINFO_BITV(INHERITED_ACE),
FLAGINFO_BITV(SUCCESSFUL_ACCESS_ACE_FLAG),
FLAGINFO_BITV(FAILED_ACCESS_ACE_FLAG),
FLAGINFO_END()
};
static TFlagInfo AceMasks[] =
{
FLAGINFO_BITV(FILE_READ_DATA),
FLAGINFO_BITV(FILE_WRITE_DATA),
FLAGINFO_BITV(FILE_APPEND_DATA),
FLAGINFO_BITV(FILE_READ_EA),
FLAGINFO_BITV(FILE_WRITE_EA),
FLAGINFO_BITV(FILE_EXECUTE),
FLAGINFO_BITV(FILE_DELETE_CHILD),
FLAGINFO_BITV(FILE_READ_ATTRIBUTES),
FLAGINFO_BITV(FILE_WRITE_ATTRIBUTES),
FLAGINFO_BITV(DELETE),
FLAGINFO_BITV(READ_CONTROL),
FLAGINFO_BITV(WRITE_DAC),
FLAGINFO_BITV(WRITE_OWNER),
FLAGINFO_BITV(SYNCHRONIZE),
FLAGINFO_BITV(GENERIC_WRITE),
FLAGINFO_BITV(GENERIC_READ),
FLAGINFO_BITV(GENERIC_WRITE),
FLAGINFO_BITV(GENERIC_EXECUTE),
FLAGINFO_BITV(GENERIC_ALL),
FLAGINFO_END()
};
static TFlagInfo AdsAceMasks[] =
{
FLAGINFO_BITV(ADS_RIGHT_DS_CREATE_CHILD),
FLAGINFO_BITV(ADS_RIGHT_DS_DELETE_CHILD),
FLAGINFO_BITV(ADS_RIGHT_ACTRL_DS_LIST),
FLAGINFO_BITV(ADS_RIGHT_DS_SELF),
FLAGINFO_BITV(ADS_RIGHT_DS_READ_PROP),
FLAGINFO_BITV(ADS_RIGHT_DS_WRITE_PROP),
FLAGINFO_BITV(ADS_RIGHT_DS_DELETE_TREE),
FLAGINFO_BITV(ADS_RIGHT_DS_LIST_OBJECT),
FLAGINFO_BITV(ADS_RIGHT_DS_CONTROL_ACCESS),
FLAGINFO_BITV(ADS_RIGHT_DELETE),
FLAGINFO_BITV(ADS_RIGHT_READ_CONTROL),
FLAGINFO_BITV(ADS_RIGHT_WRITE_DAC),
FLAGINFO_BITV(ADS_RIGHT_WRITE_OWNER),
FLAGINFO_BITV(ADS_RIGHT_SYNCHRONIZE),
FLAGINFO_BITV(ADS_RIGHT_ACCESS_SYSTEM_SECURITY),
FLAGINFO_BITV(ADS_RIGHT_GENERIC_READ),
FLAGINFO_BITV(ADS_RIGHT_GENERIC_WRITE),
FLAGINFO_BITV(ADS_RIGHT_GENERIC_EXECUTE),
FLAGINFO_BITV(ADS_RIGHT_GENERIC_ALL),
FLAGINFO_END()
};
static TFlagInfo MandatoryMasks[] =
{
FLAGINFO_BITV(SYSTEM_MANDATORY_LABEL_NO_WRITE_UP),
FLAGINFO_BITV(SYSTEM_MANDATORY_LABEL_NO_READ_UP),
FLAGINFO_BITV(SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP),
FLAGINFO_END()
};
static TFlagInfo AceFlags[] =
{
FLAGINFO_BITV(ACE_OBJECT_TYPE_PRESENT),
FLAGINFO_BITV(ACE_INHERITED_OBJECT_TYPE_PRESENT),
FLAGINFO_END()
};
static TFlagInfo IntegrityLevels[] =
{
FLAGINFO_NUMV(SECURITY_MANDATORY_UNTRUSTED_RID),
FLAGINFO_NUMV(SECURITY_MANDATORY_LOW_RID),
FLAGINFO_NUMV(SECURITY_MANDATORY_MEDIUM_RID),
FLAGINFO_NUMV(SECURITY_MANDATORY_HIGH_RID),
FLAGINFO_NUMV(SECURITY_MANDATORY_SYSTEM_RID),
FLAGINFO_NUMV(SECURITY_MANDATORY_PROTECTED_PROCESS_RID),
FLAGINFO_END()
};
static DWORD AceSizes[] =
{
sizeof(ACCESS_ALLOWED_ACE), // ACCESS_ALLOWED_ACE_TYPE
sizeof(ACCESS_DENIED_ACE), // ACCESS_DENIED_ACE_TYPE
sizeof(SYSTEM_AUDIT_ACE), // SYSTEM_AUDIT_ACE_TYPE
sizeof(SYSTEM_ALARM_ACE), // SYSTEM_ALARM_ACE_TYPE
0, // ACCESS_ALLOWED_COMPOUND_ACE_TYPE (?)
sizeof(ACCESS_ALLOWED_OBJECT_ACE), // ACCESS_ALLOWED_OBJECT_ACE_TYPE
sizeof(ACCESS_DENIED_OBJECT_ACE), // ACCESS_DENIED_OBJECT_ACE_TYPE
sizeof(SYSTEM_AUDIT_OBJECT_ACE), // SYSTEM_AUDIT_OBJECT_ACE_TYPE
sizeof(SYSTEM_ALARM_OBJECT_ACE), // SYSTEM_ALARM_OBJECT_ACE_TYPE
sizeof(ACCESS_ALLOWED_CALLBACK_ACE), // ACCESS_ALLOWED_CALLBACK_ACE_TYPE
sizeof(ACCESS_DENIED_CALLBACK_ACE), // ACCESS_DENIED_CALLBACK_ACE_TYPE
sizeof(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE), // ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE
sizeof(ACCESS_DENIED_CALLBACK_OBJECT_ACE), // ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE
sizeof(SYSTEM_AUDIT_CALLBACK_ACE), // SYSTEM_AUDIT_CALLBACK_ACE_TYPE
sizeof(SYSTEM_ALARM_CALLBACK_ACE), // SYSTEM_ALARM_CALLBACK_ACE_TYPE
sizeof(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE), // SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE
sizeof(SYSTEM_ALARM_CALLBACK_OBJECT_ACE), // SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
sizeof(SYSTEM_MANDATORY_LABEL_ACE), // SYSTEM_MANDATORY_LABEL_ACE_TYPE
};
static DWORD AceSidOffsets[] =
{
FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart),
FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_ALARM_ACE, SidStart),
0, // ACCESS_ALLOWED_COMPOUND_ACE(?)
FIELD_OFFSET(ACCESS_ALLOWED_OBJECT_ACE, SidStart),
FIELD_OFFSET(ACCESS_DENIED_OBJECT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_AUDIT_OBJECT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_ALARM_OBJECT_ACE, SidStart),
FIELD_OFFSET(ACCESS_ALLOWED_CALLBACK_ACE, SidStart),
FIELD_OFFSET(ACCESS_DENIED_CALLBACK_ACE, SidStart),
FIELD_OFFSET(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, SidStart),
FIELD_OFFSET(ACCESS_DENIED_CALLBACK_OBJECT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_AUDIT_CALLBACK_ACE, SidStart),
FIELD_OFFSET(SYSTEM_ALARM_CALLBACK_ACE, SidStart),
FIELD_OFFSET(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_ALARM_CALLBACK_OBJECT_ACE, SidStart),
FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart)
};
//-----------------------------------------------------------------------------
// Local functions - SID
static PSID Sid_Allocate(DWORD dwLength)
{
#ifdef _DEBUG
return (PSID)malloc(dwLength); // Allocate using malloc, so we can track the leaks
#else
return (PSID)HeapAlloc(g_hHeap, 0, dwLength);
#endif
}
// A public function, also used in ACE_HELPER
void Sid_Free(PSID pSid)
{
#ifdef _DEBUG
free(pSid);
#else
HeapFree(g_hHeap, 0, pSid);
#endif
}
static PSID Sid_AllocateAndInitialize(
IN PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
IN BYTE nSubAuthorityCount,
IN PDWORD pnSubAuthorities)
{
PSID pSid;
// Prepare a buffer of a sufficient size
pSid = Sid_Allocate(GetSidLengthRequired(nSubAuthorityCount));
if(pSid == NULL)
return NULL;
// Fill in the identifier authority and sub-authority count
if(InitializeSid(pSid, pIdentifierAuthority, nSubAuthorityCount))
{
// Fill in the sub-authorities
for (BYTE i = 0; i < nSubAuthorityCount; i++)
{
*GetSidSubAuthority(pSid, i) = pnSubAuthorities[i];
}
}
else
{
// Failed initialization; cleanup
Sid_Free(pSid);
pSid = NULL;
}
// Return our new SID
return pSid;
}
// Creates a new SID of "Everyone" depending on the ACE type
// Caller must free the returned SID using Sid_Free
static PSID Sid_CreateNew(BYTE AceType)
{
// We only create two types of SID - "Everyone" and "Mandatory Medium"
if(AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
{
DWORD nSubAuthorities[] = { SECURITY_MANDATORY_MEDIUM_RID };
return Sid_AllocateAndInitialize(&SiaLabel, RTL_NUMBER_OF(nSubAuthorities), nSubAuthorities);
}
else
{
DWORD nSubAuthorities[] = { SECURITY_WORLD_RID };
return Sid_AllocateAndInitialize(&SiaWorld, RTL_NUMBER_OF(nSubAuthorities), nSubAuthorities);
}
}
// Changes an user name service ("fltmgr") into a properly prefixed name ("NT_SERVICE\\fltmgr")
static bool CheckForServiceAccount(LPTSTR szUserName)
{
TCHAR szSaveUserName[MAX_PATH];
TCHAR szKeyName[MAX_PATH];
HKEY hSubKey;
// Save the user name
StringCchCopy(szSaveUserName, _countof(szSaveUserName), szUserName);
// If the name resembles a service, give it the NT_SERVICE prefix. This only applies in Vista or newer
if(g_dwWinVer >= 0x0600 && _tcschr(szUserName, _T('\\')) == NULL)
{
StringCchPrintf(szKeyName, _countof(szKeyName), _T("SYSTEM\\CurrentControlSet\\Services\\%s"), szUserName);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
{
StringCchPrintf(szUserName, MAX_PATH, _T("NT SERVICE\\%s"), szSaveUserName);
RegCloseKey(hSubKey);
return true;
}
}
return false;
}
void SidToString(PSID pvSid, LPTSTR szString, size_t cchString, bool bAddUserName)
{
PSID_IDENTIFIER_AUTHORITY pSia;
SID * pSid = (SID *)pvSid;
LPTSTR szStringEnd = szString + cchString;
UCHAR SubAuthCount;
// Add the "S-%u-" begin with revision
pSia = GetSidIdentifierAuthority(pSid);
StringCchPrintfEx(szString, (szStringEnd - szString), &szString, NULL, 0, _T("S-%u-%u"),
pSid->Revision,
pSia->Value[5]);
// Add the subauthorities
SubAuthCount = *GetSidSubAuthorityCount(pSid);
for(DWORD i = 0; i < SubAuthCount; i++)
{
DWORD dwSubAuth = *GetSidSubAuthority(pSid, i);
StringCchPrintfEx(szString, (szStringEnd - szString), &szString, NULL, 0, L"-%u", dwSubAuth);
}
// If we are required to add user name, do it.
if(bAddUserName)
{
SID_NAME_USE SidNameUse;
TCHAR szDomainName[128] = _T("");
TCHAR szUserName[128] = _T("");
DWORD cchDomainName = _countof(szDomainName);
DWORD cchUserName = _countof(szUserName);
if(LookupAccountSid(NULL, pSid, szUserName, &cchUserName, szDomainName, &cchDomainName, &SidNameUse))
{
if(szDomainName[0] != 0)
StringCchPrintf(szString, (szStringEnd - szString), _T(" (%s\\%s)"), szDomainName, szUserName);
else
StringCchPrintf(szString, (szStringEnd - szString), _T(" (%s)"), szUserName);
}
else
{
StringCchPrintf(szString, (szStringEnd - szString), _T(" (Unknown SID)"));
}
}
}
bool StringToSid(LPTSTR szSid, PSID * ppSid)
{
SID_IDENTIFIER_AUTHORITY Sia = SiaNull;
SID_NAME_USE SidNameUse;
PSID pNewSid = NULL;
TCHAR szDomainName[128] = _T("");
DWORD dwSubAuthCount = 0;
DWORD dwSubAuth[SID_MAX_SUB_AUTHORITIES];
DWORD dwDomainName = _countof(szDomainName);
DWORD dwRevision = SID_REVISION;
DWORD dwLength = 0;
BOOL bResult;
// Verify the string sid value
if(szSid == NULL || szSid[0] == 0)
return false;
// Case 1: Sid is entered as text form ("S-1-....")
if(szSid[0] == _T('S') && szSid[1] == _T('-') && szSid[2] == _T('1') && szSid[3] == _T('-'))
{
// Skip revision
dwRevision = SID_REVISION;
szSid += 4;
// Get the identifier authority
Sia.Value[5] = (BYTE)StrToInt(szSid, &szSid, 10);
if(szSid[0] != _T('-'))
return false;
// Get the subauthorities
memset(dwSubAuth, 0, sizeof(dwSubAuth));
while(szSid[0] == _T('-') && dwSubAuthCount < SID_MAX_SUB_AUTHORITIES)
{
dwSubAuth[dwSubAuthCount++] = StrToInt(szSid + 1, &szSid, 10);
}
// If an unknown character found, do nothing
if(szSid[0] == 0 || szSid[0] == _T(' '))
{
// Create the SID
*ppSid = Sid_AllocateAndInitialize(&Sia, (BYTE)dwSubAuthCount, dwSubAuth);
return (*ppSid != NULL);
}
return false;
}
// Case 2: Domain\Username
__LookupAccountName:
bResult = LookupAccountName(NULL, szSid, pNewSid, &dwLength, szDomainName, &dwDomainName, &SidNameUse);
// If we haven't received the length, try some well-known user names
if(bResult == FALSE && dwLength == 0)
{
if(GetLastError() == ERROR_NONE_MAPPED && CheckForServiceAccount(szSid))
goto __LookupAccountName;
}
// If we received a non-zero length, allocate SID and try again
if(bResult == FALSE && dwLength != 0)
{
pNewSid = Sid_Allocate(dwLength);
bResult = LookupAccountName(NULL, szSid, pNewSid, &dwLength, szDomainName, &dwDomainName, &SidNameUse);
}
// If succeeded, give the SID
if(bResult)
*ppSid = pNewSid;
return (bool)(bResult != FALSE);
}
//
// The SID in the SYSTEM_MANDATORY_LABEL_ACE has the following format:
//
// - IdentifierAuthority is set to SECURITY_MANDATORY_LABEL_AUTHORITY
// - The last subauthority is set to one of the SECURITY_MANDATORY_XXXX values
//
static DWORD SidToIntegrityLevel(PSID pSid)
{
DWORD dwSubAuthCount;
if(pSid != NULL)
{
// Retrieve integrity level from SID
if(!memcmp(GetSidIdentifierAuthority(pSid), &SiaLabel, sizeof(SID_IDENTIFIER_AUTHORITY)))
{
dwSubAuthCount = *GetSidSubAuthorityCount(pSid);
if(dwSubAuthCount > 0)
{
return *GetSidSubAuthority(pSid, dwSubAuthCount - 1);
}
}
}
// Set default integrity level
return SECURITY_MANDATORY_MEDIUM_RID;
}
//-----------------------------------------------------------------------------
// Local functions ACEs, ACLs
static PACL Acl_CreateEmpty(DWORD dwAclSize = MAXIMUM_ACL_SIZE)
{
PACL pAcl;
// Allocate new ACL of the maximum size
pAcl = (PACL)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, MAXIMUM_ACL_SIZE);
if(pAcl != NULL)
InitializeAcl(pAcl, dwAclSize, ACL_REVISION);
// Return the ACL
return pAcl;
}
// Creates a new ACL with one ACE, granting full access to Everyone
// Caller must free the returned buffer using HeapFree
static PACL Acl_CreateOneItem(BYTE AceType)
{
DWORD dwSidLength = 0;
DWORD dwAclLength = 0;
PSID pSid = NULL;
PACL pAcl = NULL;
BOOL bResult = FALSE;
// Create SID for "Everyone"
pSid = Sid_CreateNew(AceType);
if(pSid != NULL)
{
// Calculate the size of the new ACE and initialize it
dwSidLength = GetLengthSid(pSid);
dwAclLength = sizeof(ACL) + AceSizes[AceType] - sizeof(DWORD) + dwSidLength;
// Create new empty ACL
pAcl = Acl_CreateEmpty(dwAclLength);
if(pAcl != NULL)
{
// Perform the ACE-specific addition
switch(AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
bResult = AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid);
break;
case ACCESS_DENIED_ACE_TYPE:
bResult = AddAccessDeniedAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid);
break;
case SYSTEM_AUDIT_ACE_TYPE:
bResult = AddAuditAccessAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid, TRUE, TRUE);
break;
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
bResult = MyAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, pSid);
break;
default: // Not supported
bResult = FALSE;
break;
}
// If something went wrong, free the ACL
if(bResult == FALSE)
{
HeapFree(g_hHeap, 0, pAcl);
pAcl = NULL;
}
}
// Free the allocated SID
Sid_Free(pSid);
}
return pAcl;
}
static PACL Acl_FinishBuild(PACL pAcl)
{
PACE_HEADER pAceHeader;
DWORD dwAceCount = pAcl->AceCount;
DWORD dwAceSize = sizeof(ACL);
// Acount the size of all ACEs
for(DWORD i = 0; i < dwAceCount; i++)
{
// Retrieve the n-th ACE
if(!GetAce(pAcl, i, (LPVOID *)&pAceHeader))
break;
// Add the size to the ACL
dwAceSize = dwAceSize + pAceHeader->AceSize;
}
// Adjust the size of the ACL
pAcl->AclSize = (WORD)dwAceSize;
return pAcl;
}
static bool AceFilterIncludeAll(PACE_HEADER)
{
return true;
}
static bool AceFilterExcludeMandatoryAces(PACE_HEADER pAceHeader)
{
return (pAceHeader->AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE);
}
static bool AceFilterMandatoryAcesOnly(PACE_HEADER pAceHeader)
{
return (pAceHeader->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE);
}
//-----------------------------------------------------------------------------
// Local functions - tree items
static BOOL IsTreeItemAce(LPARAM lParam)
{
return ((lParam & TREE_ITEM_TYPE_MASK) == TREE_ITEM_ACE) ? TRUE : FALSE;
}
static LPCSTR GetAceTypeString(DWORD AceType)
{
BYTE MaxAceType = (BYTE)(_countof(AceHdrTypes) - 1);
// Insert the "root" item with ACE type
return (AceType < MaxAceType) ? AceHdrTypes[AceType].szFlagText : "UNKNOWN_ACE";
}
// The item text is expected to be in format "Name: 0x12345678"
static LPTSTR GetItemTextValue(LPTSTR szItemText)
{
LPTSTR szSpacePtr;
// Retrieve the first occurence of ":"
szItemText = _tcschr(szItemText, _T(':'));
if(szItemText != NULL)
{
// Skip the colon
szItemText++;
// Skip spaces
while(szItemText[0] == ' ')
szItemText++;
// If the number is followed by a space, cut it
szSpacePtr = _tcschr(szItemText, _T(' '));
if(szSpacePtr != NULL)
szSpacePtr[0] = 0;
}
// Return the text
return szItemText;
}
static BYTE GetDefaultAceType(HWND hTreeView, HTREEITEM hParent)
{
BYTE AceType = ACCESS_ALLOWED_ACE_TYPE;
// Retrieve the parent item
switch(TreeView_GetItemParam(hTreeView, hParent))
{
case TREE_ITEM_DACL:
AceType = ACCESS_ALLOWED_ACE_TYPE;
break;
case TREE_ITEM_SACL:
AceType = SYSTEM_AUDIT_ACE_TYPE;
break;
case TREE_ITEM_LABEL:
AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
break;
default:
assert(FALSE);
break;
}
return AceType;
}
static bool TreeView_ItemToValue32(HWND hTreeView, HTREEITEM hItem, LPDWORD PtrValue)
{
TVITEM tvi;
LPTSTR szValue;
TCHAR szItemText[256];
DWORD dwErrCode;
// Get the text from the
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
if(TreeView_GetItem(hTreeView, &tvi))
{
// Retrieve the value
szValue = GetItemTextValue(szItemText);
if(szValue != NULL)
{
// Convert the 32-bit value to an integer
dwErrCode = Text2Hex32(szValue, PtrValue);
return (dwErrCode == ERROR_SUCCESS);
}
}
return false;
}
static bool TreeView_ItemToGuid(HWND hTreeView, HTREEITEM hItem, LPGUID PtrGuid)
{
TVITEM tvi;
LPTSTR szValue;
TCHAR szItemText[256];
// Get the text from the
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
if(TreeView_GetItem(hTreeView, &tvi))
{
// Retrieve the value
szValue = GetItemTextValue(szItemText);
if(szValue != NULL)
{
return StringToGuid(szValue, PtrGuid);
}
}
return false;
}
static HTREEITEM TreeView_SidToItem(HWND hTreeView, HTREEITEM hItem, PSID pSid, LPCTSTR szDefaultText)
{
LPARAM lParam = TREE_ITEM_NO_SID;
TCHAR szTextBuff[256];
// If the SID is present, convert the SID to the tree item
if(pSid != NULL)
{
// Convert the SID to text
SidToString(pSid, szTextBuff, _countof(szTextBuff), true);
szDefaultText = szTextBuff;
lParam = TREE_ITEM_SID;
}
return TreeView_SetTreeItem(hTreeView, hItem, szDefaultText, lParam);
}
static HTREEITEM TreeView_InsertSidItem(HWND hTreeView, HTREEITEM hParent, PSID pSid, LPCTSTR szDefaultText)
{
HTREEITEM hItem;
// Insert a new item
hItem = InsertTreeItem(hTreeView, hParent, szDefaultText, TREE_ITEM_NO_SID);
if(hItem != NULL)
{
// Apply the SID to the item and expand the parent
TreeView_SidToItem(hTreeView, hItem, pSid, szDefaultText);
TreeView_Expand(hTreeView, hParent, TVE_EXPAND);
}
return hItem;
}
static bool TreeView_ItemToSid(HWND hTreeView, HTREEITEM hItem, PSID * ppSid, bool bCanCreateNewSid)
{
TVITEM tvi;
TCHAR szItemText[256];
// Get the text from the treeview item
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
TreeView_GetItem(hTreeView, &tvi);
// Convert the tree item to SID
switch(tvi.lParam)
{
case TREE_ITEM_NO_SID:
if(bCanCreateNewSid)
*ppSid = Sid_CreateNew(ACCESS_ALLOWED_ACE_TYPE);
break;
case TREE_ITEM_SID:
StringToSid(szItemText, ppSid);
break;
}
return (*ppSid != NULL);
}
static bool TreeView_ItemToSid(HWND hTreeView, HTREEITEM hItem, ACE_HELPER & AceHelper)
{
PSID pSid = NULL;
bool bResult = false;
if(TreeView_ItemToSid(hTreeView, hItem, &pSid, false))
{
AceHelper.SetAllocatedSid(pSid);
bResult = true;
}
return bResult;
}
static HTREEITEM TreeView_MandatorySidToItem(HWND hTreeView, HTREEITEM hParent, PSID pSid)
{
TCHAR szItemText[256];
// Format the integrity level
StringCchPrintf(szItemText, _countof(szItemText), szIntLevelFmt, SidToIntegrityLevel(pSid));
return TreeView_SetTreeItem(hTreeView, hParent, szItemText, TREE_ITEM_MANDATORY_LABEL);
}
static HTREEITEM TreeView_InsertMandatorySidItem(HWND hTreeView, HTREEITEM hParent, PSID pSid, LPCTSTR szDefaultText)
{
HTREEITEM hItem;
// Insert a new item
hItem = InsertTreeItem(hTreeView, hParent, szDefaultText, TREE_ITEM_MANDATORY_LABEL);
if(hItem != NULL)
{
// Apply the SID to the item and expand the parent
TreeView_MandatorySidToItem(hTreeView, hItem, pSid);
TreeView_Expand(hTreeView, hParent, TVE_EXPAND);
}
return hItem;
}
static bool TreeView_ItemToMandatorySid(HWND hTreeView, HTREEITEM hItem, ACE_HELPER & AceHelper)
{
DWORD dwIntLevel = SECURITY_MANDATORY_MEDIUM_RID;
PSID pSid = NULL;
bool bResult = false;
// Convert the item to SID
if(TreeView_ItemToValue32(hTreeView, hItem, &dwIntLevel))
{
// Create new mandatory label SID
DWORD nSubAuthorities[] = { dwIntLevel };
pSid = Sid_AllocateAndInitialize(&SiaLabel, RTL_NUMBER_OF(nSubAuthorities), nSubAuthorities);
if(pSid != NULL)
{
// Store the SID to the ACE_HELPER structure
AceHelper.SetAllocatedSid(pSid);
bResult = true;
}
}
return bResult;
}
static HTREEITEM TreeView_AceToItem(
HWND hTreeView,
HTREEITEM hItem,
ACE_HELPER & AceHelper)
{
TCHAR szItemText[256];
// Check if the layout is supported
if(AceHelper.AceLayout == ACE_LAYOUT_UNKNOWN)
return NULL;
// If the parent is valis
if(hItem != NULL)
{
// Delete all children
TreeView_DeleteChildren(hTreeView, hItem);
// Insert the subitem with ACE type
StringCchPrintf(szItemText, _countof(szItemText), szAceHdrTypeFmt, AceHelper.AceType);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_HEADER_TYPE);
// Insert the subitem with ACE flags
NamedValueToString(AceHdrFlags, szItemText, _countof(szItemText), szAceHdrFlagsFmt, AceHelper.AceFlags);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_HEADER_FLAGS);
// Insert the subitem with ACE size
StringCchPrintf(szItemText, _countof(szItemText), szAceHdrSizeFmt, AceHelper.AceSize);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_HEADER_SIZE);
// Insert the ACE:Mask (ACCESS_MASK), if present
if(AceHelper.AceLayout & ACE_FIELD_ACCESS_MASK)
{
NamedValueToString(AceMasks, szItemText, _countof(szItemText), szAceMaskFmt, AceHelper.Mask);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_MASK);
}
// Insert the ACE:Mask (Object ACEs), if present
if(AceHelper.AceLayout & ACE_FIELD_ADS_ACCESS_MASK)
{
NamedValueToString(AdsAceMasks, szItemText, _countof(szItemText), szAceMaskFmt, AceHelper.Mask);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ADS_ACE_MASK);
}
// Insert the ACE:Mask (MANDATORY_LABEL_MASK), if present
if(AceHelper.AceLayout & ACE_FIELD_MANDATORY_MASK)
{
NamedValueToString(MandatoryMasks, szItemText, _countof(szItemText), szAceMaskFmt, AceHelper.Mask);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_MANDATORY_MASK);
}
// Insert the ACE::Flags, if present
if(AceHelper.AceLayout & ACE_FIELD_FLAGS)
{
NamedValueToString(AceFlags, szItemText, _countof(szItemText), szAceFlagsFmt, AceHelper.Flags);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_FLAGS);
}
// Insert the ACE:ObjectType, if present
// Info about object GUIDs, see https://msdn.microsoft.com/en-us/library/cc223512.aspx
if(AceHelper.AceLayout & ACE_FIELD_OBJECT_TYPE)
{
GuidValueToString(szItemText, _countof(szItemText), szAceObjTypeFmt, &AceHelper.ObjectType);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_OBJ_GUID);
}
// Insert the ACE:InheritedObjectType, if present
if(AceHelper.AceLayout & ACE_FIELD_OBJECT_TYPE2)
{
GuidValueToString(szItemText, _countof(szItemText), szAceObjTypeFmt2, &AceHelper.InheritedObjectType);
InsertTreeItem(hTreeView, hItem, szItemText, TREE_ITEM_ACE_OBJ_GUID2);
}
// Insert the integrity level, if present
if(AceHelper.AceLayout & ACE_FIELD_MANDATORY_SID)
TreeView_InsertMandatorySidItem(hTreeView, hItem, AceHelper.Sid, szUnknownSid);
// Insert the access SID, if present
if(AceHelper.AceLayout & ACE_FIELD_ACCESS_SID)
TreeView_InsertSidItem(hTreeView, hItem, AceHelper.Sid, szUnknownSid);
// Expand the item
TreeView_Expand(hTreeView, hItem, TVE_EXPAND);
}
// Return the item handle
return hItem;
}
static HTREEITEM TreeView_AceToItem(
HWND hTreeView,
HTREEITEM hParent,
PACE_HEADER pAceHeader)
{
ACE_HELPER AceHelper;
if(!AceHelper.SetAce(pAceHeader))
return NULL;
return TreeView_AceToItem(hTreeView, hParent, AceHelper);
}
static HTREEITEM TreeView_InsertAceItem(
HWND hTreeView,
HTREEITEM hParent,
HTREEITEM hInsertAfter,
PACE_HEADER pAceHeader)
{
HTREEITEM hItem;
LPCSTR szAceTypeString = GetAceTypeString(pAceHeader->AceType);
// Insert the "root" item with ACE type
hItem = InsertTreeItem(hTreeView, hParent, hInsertAfter, TWideString(szAceTypeString), (PVOID)(ULONG_PTR)(TREE_ITEM_ACE | pAceHeader->AceType));
if(hItem != NULL)
{
// Fill the ACE structure
TreeView_AceToItem(hTreeView, hItem, pAceHeader);
TreeView_Expand(hTreeView, hParent, TVE_EXPAND);
}
// Return the newly created tree item
return hItem;
}
static bool TreeView_ItemToAce(
HWND hTreeView,
HTREEITEM hItem,
ACE_HELPER & AceHelper)
{
DWORD dwAceType = 0;
// Fill the entire structure with zeros
AceHelper.Reset();
// Retrieve the (first/next) child
hItem = TreeView_GetChild(hTreeView, hItem);
while(hItem != NULL)
{
bool bResult = false;
// Get the values of the ACE according the item type
switch(TreeView_GetItemParam(hTreeView, hItem))
{
case TREE_ITEM_ACE_HEADER_TYPE: // Save the ACE_Header::AceType
if(TreeView_ItemToValue32(hTreeView, hItem, &dwAceType))
bResult = AceHelper.SetAceType(dwAceType);
break;
case TREE_ITEM_ACE_HEADER_FLAGS: // Save the ACE_Header::AceFlags
bResult = TreeView_ItemToValue32(hTreeView, hItem, &AceHelper.AceFlags);
break;
case TREE_ITEM_ACE_HEADER_SIZE: // Save the ACE_HEADER::AceSize (even if it will not be used)
bResult = TreeView_ItemToValue32(hTreeView, hItem, &AceHelper.AceSize);
break;
case TREE_ITEM_ACE_MASK:
case TREE_ITEM_ADS_ACE_MASK:
case TREE_ITEM_MANDATORY_MASK:
bResult = TreeView_ItemToValue32(hTreeView, hItem, &AceHelper.Mask);
break;
case TREE_ITEM_ACE_FLAGS:
bResult = TreeView_ItemToValue32(hTreeView, hItem, &AceHelper.Flags);
break;
case TREE_ITEM_ACE_OBJ_GUID:
bResult = TreeView_ItemToGuid(hTreeView, hItem, &AceHelper.ObjectType);
break;
case TREE_ITEM_ACE_OBJ_GUID2:
bResult = TreeView_ItemToGuid(hTreeView, hItem, &AceHelper.InheritedObjectType);
break;
case TREE_ITEM_MANDATORY_LABEL:
bResult = TreeView_ItemToMandatorySid(hTreeView, hItem, AceHelper);
break;
case TREE_ITEM_SID:
bResult = TreeView_ItemToSid(hTreeView, hItem, AceHelper);
break;
}
// If an error happened, do nothing
if(!bResult)
return false;
hItem = TreeView_GetNextSibling(hTreeView, hItem);
}
return true;
}
static DWORD TreeView_InsertAclItems(
HWND hTreeView,
HTREEITEM hParent,
PACL pAcl,
ACE_FILTER_PROC PfnAceFilter)
{
PACE_HEADER pAceHeader;
HTREEITEM hItem;
DWORD dwAceCount = 0;
//
// Note: parent ACL item already has the proper item text and LPARAM
//
// Do nothing if there is no item
if(hParent != NULL)
{
// Remove all children, if any
TreeView_DeleteChildren(hTreeView, hParent);
// Insert new children, if needed
if(pAcl != NULL)
{
// Parse all ACEs
for(WORD AceIndex = 0; AceIndex < pAcl->AceCount; AceIndex++)
{
if(GetAce(pAcl, AceIndex, (PVOID *)&pAceHeader))
{
// If the filter approves the ACE, insert it
if(PfnAceFilter(pAceHeader))
{
hItem = TreeView_InsertAceItem(hTreeView, hParent, TVI_LAST, pAceHeader);
dwAceCount += (hItem != NULL) ? 1 : 0;
}
}
}
// If we didn't insert any ACEs, insert default text
// Also triggers on empty ACLs
if(dwAceCount == 0)
{
hItem = InsertTreeItem(hTreeView, hParent, szEmptyAcl, TREE_ITEM_EMPTY_ACL);
}
}
else
{
// NULL DACL
hItem = InsertTreeItem(hTreeView, hParent, szNullAcl, TREE_ITEM_NULL_ACL);
}
// Always expand the item
TreeView_Expand(hTreeView, hParent, TVE_EXPAND);
}
return dwAceCount;
}
static bool TreeView_ItemToAcl_Add(
HWND hTreeView,
HTREEITEM hItem,
PACL pAcl)
{
ACE_HELPER AceHelper;
LPARAM lParam;
BOOL bResult = FALSE;
// Work while we have an ACE item
while(hItem != NULL)
{
// Retrieve the type of the ACE
lParam = TreeView_GetItemParam(hTreeView, hItem);
if((lParam & TREE_ITEM_TYPE_MASK) != TREE_ITEM_ACE)
return false;
// Retrieve the (first/next) child
bResult = TreeView_ItemToAce(hTreeView, hItem, AceHelper);
if(bResult == FALSE)
return false;
// Create an ACE that reflects the type
switch(lParam & TREE_ITEM_VALUE_MASK)
{
case ACCESS_ALLOWED_ACE_TYPE:
bResult = AddAccessAllowedAceEx(pAcl, ACL_REVISION, AceHelper.AceFlags, AceHelper.Mask, AceHelper.Sid);
break;
case ACCESS_DENIED_ACE_TYPE:
bResult = AddAccessDeniedAceEx(pAcl, ACL_REVISION, AceHelper.AceFlags, AceHelper.Mask, AceHelper.Sid);
break;
case SYSTEM_AUDIT_ACE_TYPE:
bResult = AddAuditAccessAceEx(pAcl, ACL_REVISION, AceHelper.AceFlags, AceHelper.Mask, AceHelper.Sid, FALSE, FALSE);
break;
default: // Let our helper to add the ACE
bResult = AceHelper.AddToAcl(pAcl);
break;
}
// Get the next sibling
hItem = TreeView_GetNextSibling(hTreeView, hItem);
}
// We need to free the SID
return (bool)(bResult != FALSE);
}
static BOOL TreeView_ItemToAcl(
HWND hTreeView,
HTREEITEM hAclItem1,
HTREEITEM hAclItem2,
PACL * ppAcl)
{
LPARAM lParam1;
PACL pAcl = NULL;
// The variant with no ACLs
if(hAclItem1 == NULL && hAclItem2 == NULL)
{
*ppAcl = NULL;
return TRUE;
}
// The variant with only one tree item
if(hAclItem1 != NULL && hAclItem2 == NULL)
{
// Retrieve the item param
lParam1 = TreeView_GetItemParam(hTreeView, hAclItem1);
// If the param means NULL ACL, give the caller a NULL ACL
if(lParam1 == TREE_ITEM_NULL_ACL)
{
*ppAcl = NULL;
return TRUE;
}
// If the param means an empty ACL, create an empty ACL
if(lParam1 == TREE_ITEM_EMPTY_ACL)
{
*ppAcl = Acl_CreateEmpty(sizeof(ACL));
return TRUE;
}
}
// Build a new ACL of the maximum size
assert(hAclItem1 || hAclItem2);
pAcl = Acl_CreateEmpty();
if(pAcl == NULL)
return FALSE;
// If the primary item is an ACL item, we insert all ACEs to the ACL
if(hAclItem1 != NULL)
TreeView_ItemToAcl_Add(hTreeView, hAclItem1, pAcl);
// If the secondary item is an ACL item, we insert all ACEs to the ACL
if(hAclItem2 != NULL)
TreeView_ItemToAcl_Add(hTreeView, hAclItem2, pAcl);
// Finalize the ACL
*ppAcl = Acl_FinishBuild(pAcl);
return TRUE;
}
static void TreeView_SdToTreeView(
HWND hTreeView,
PSECURITY_DESCRIPTOR pSD)
{
HTREEITEM hItem;
TCHAR szNotPresent[128];
PSID pOwner = NULL;
PSID pGroup = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
BOOL bTemp;
// Clear all current tree view items
TreeView_DeleteAllItems(hTreeView);
LoadString(g_hInst, IDS_NOT_PRESENT, szNotPresent, _countof(szNotPresent));
//
// Insert tree item for owner security information
//
hItem = InsertTreeItem(hTreeView, TVI_ROOT, _T("OWNER_SECURITY_INFORMATION"), TREE_ITEM_OWNER);
if(GetSecurityDescriptorOwner(pSD, &pOwner, &bTemp))
TreeView_InsertSidItem(hTreeView, hItem, pOwner, szNotPresent);
//
// Insert tree item for group security information
//
hItem = InsertTreeItem(hTreeView, TVI_ROOT, _T("GROUP_SECURITY_INFORMATION"), TREE_ITEM_GROUP);
if(GetSecurityDescriptorGroup(pSD, &pGroup, &bTemp))
TreeView_InsertSidItem(hTreeView, hItem, pGroup, szNotPresent);
//
// Insert tree item for DACL security information
//
hItem = InsertTreeItem(hTreeView, TVI_ROOT, _T("DACL_SECURITY_INFORMATION"), TREE_ITEM_DACL);
if(GetSecurityDescriptorDacl(pSD, &bTemp, &pDacl, &bTemp))
TreeView_InsertAclItems(hTreeView, hItem, pDacl, AceFilterIncludeAll);
//
// Insert tree item for SACL security information
//
hItem = InsertTreeItem(hTreeView, TVI_ROOT, _T("SACL_SECURITY_INFORMATION"), TREE_ITEM_SACL);
if(GetSecurityDescriptorSacl(pSD, &bTemp, &pSacl, &bTemp))
TreeView_InsertAclItems(hTreeView, hItem, pSacl, AceFilterExcludeMandatoryAces);
//
// Insert tree item for LABEL security information
//
hItem = InsertTreeItem(hTreeView, TVI_ROOT, _T("LABEL_SECURITY_INFORMATION"), TREE_ITEM_LABEL);
if(GetSecurityDescriptorSacl(pSD, &bTemp, &pSacl, &bTemp))
TreeView_InsertAclItems(hTreeView, hItem, pSacl, AceFilterMandatoryAcesOnly);
}
void TreeView_DeferItemText(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
TVITEM tvi;
// Apply the text to the tree item
tvi.mask = TVIF_TEXT;
tvi.hItem = (HTREEITEM)wParam;
tvi.pszText = (LPTSTR)lParam;
TreeView_SetItem(hTreeView, &tvi);
// Free the text
delete [] tvi.pszText;
}
static SECURITY_INFORMATION GetWantedSecurityInfo(HWND hDlg)
{
SECURITY_INFORMATION SecInfo = 0;
if(IsDlgButtonChecked(hDlg, IDC_OWNER_INFORMATION) == BST_CHECKED)
SecInfo |= OWNER_SECURITY_INFORMATION;
if(IsDlgButtonChecked(hDlg, IDC_GROUP_INFORMATION) == BST_CHECKED)
SecInfo |= GROUP_SECURITY_INFORMATION;
if(IsDlgButtonChecked(hDlg, IDC_DACL_INFORMATION) == BST_CHECKED)
SecInfo |= DACL_SECURITY_INFORMATION;
if(IsDlgButtonChecked(hDlg, IDC_SACL_INFORMATION) == BST_CHECKED)
SecInfo |= SACL_SECURITY_INFORMATION;
if(IsDlgButtonChecked(hDlg, IDC_LABEL_INFORMATION) == BST_CHECKED)
SecInfo |= LABEL_SECURITY_INFORMATION;
return SecInfo;
}
static void UpdateContextMenu(HWND hTreeView, HTREEITEM hItem, HMENU hMainMenu)
{
HTREEITEM hNextItem;
HMENU hSubMenu = GetSubMenu(hMainMenu, 0);
UINT uEnable = MF_GRAYED;
// Move ACE up is only allowed when the ACE is not the first one
if(TreeView_GetPrevSibling(hTreeView, hItem) == NULL)
EnableMenuItem(hSubMenu, IDC_MOVE_ACE_UP, MF_GRAYED);
// Move ACE down is only allowed when the ACE is not the last one
hNextItem = TreeView_GetNextSibling(hTreeView, hItem);
if(hNextItem != NULL)
{
if(TreeView_GetItemParam(hTreeView, hNextItem) != TREE_ITEM_NULL_ACL)
uEnable = MF_ENABLED;
}
EnableMenuItem(hSubMenu, IDC_MOVE_ACE_DOWN, uEnable);
}
static HTREEITEM TreeView_GetPreviousItem(HWND hTreeView, HTREEITEM hItem)
{
hItem = TreeView_GetPrevSibling(hTreeView, hItem);
if(hItem == NULL)
hItem = TVI_FIRST;
return hItem;
}
static BOOL DeferSetItemNumericValue(HWND hDlg, LPNMTVDISPINFO pTVDispInfo, TFlagInfo * pFlags, LPCTSTR szFormat)
{
LPTSTR szItemText;
size_t cchItemText = 0x400;
DWORD dwValue32 = 0;
BOOL bAcceptChanges = FALSE;
// The item must be valid
if(pTVDispInfo->item.pszText != NULL && pTVDispInfo->item.pszText[0] != 0)
{
// Attempt to convert the hexa value to DWORD
if(Text2Hex32(pTVDispInfo->item.pszText, &dwValue32) == ERROR_SUCCESS)
{
// Allocate the item text
szItemText = new TCHAR[cchItemText];
if(szItemText != NULL)
{
// Either format the text as value with flags, or just a value
if(pFlags != NULL)
NamedValueToString(pFlags, szItemText, cchItemText, szFormat, dwValue32);
else
StringCchPrintf(szItemText, cchItemText, szFormat, dwValue32);
// Yes, accept changes
PostMessage(hDlg, WM_DEFER_ITEM_TEXT, (WPARAM)pTVDispInfo->item.hItem, (LPARAM)szItemText);
bAcceptChanges = TRUE;
}
}
}
return bAcceptChanges;
}
static BOOL DeferSetItemGuidValue(HWND hDlg, LPNMTVDISPINFO pTVDispInfo, LPCTSTR szFormat)
{
LPTSTR szItemText;
size_t cchItemText = 0x400;
GUID guid;
BOOL bAcceptChanges = FALSE;
// The item must be valid
if(pTVDispInfo->item.pszText != NULL && pTVDispInfo->item.pszText[0] != 0)
{
// Attempt to convert the text value to GUID
if(StringToGuid(pTVDispInfo->item.pszText, &guid))
{
// Allocate the item text
szItemText = new TCHAR[cchItemText];
if(szItemText != NULL)
{
// Format the guid
GuidValueToString(szItemText, cchItemText, szFormat, &guid);
// Yes, accept changes
PostMessage(hDlg, WM_DEFER_ITEM_TEXT, (WPARAM)pTVDispInfo->item.hItem, (LPARAM)szItemText);
bAcceptChanges = TRUE;
}
}
}
return bAcceptChanges;
}
static BOOL DeferSetItemSidValue(HWND hDlg, LPNMTVDISPINFO pTVDispInfo)
{
LPTSTR szItemText;
size_t cchItemText = 0x400;
PSID pSid = NULL;
BOOL bAcceptChanges = FALSE;
// The item must be valid
if(pTVDispInfo->item.pszText != NULL && pTVDispInfo->item.pszText[0] != 0)
{
// Convert the SID to string
if(StringToSid(pTVDispInfo->item.pszText, &pSid))
{
// Allocate the item text
szItemText = new TCHAR[cchItemText];
if(szItemText != NULL)
{
// Convert the SID to string and post it to the dialog
SidToString(pSid, szItemText, cchItemText, true);
PostMessage(hDlg, WM_DEFER_ITEM_TEXT, (WPARAM)pTVDispInfo->item.hItem, (LPARAM)szItemText);
bAcceptChanges = TRUE;
}
// Free the SID
Sid_Free(pSid);
}
}
return bAcceptChanges;
}
//-----------------------------------------------------------------------------
// Message handlers
static TAnchors * pAnchors = NULL;
static int OnInitDialog(HWND hDlg, LPARAM lParam)
{
TFileTestData * pData;
PROPSHEETPAGE * pPage = (PROPSHEETPAGE *)lParam;
// Remember the data pointer
SetDialogData(hDlg, pPage->lParam);
pData = (TFileTestData *)pPage->lParam;
// Configure dialog resizing
if(pData->bEnableResizing)
{
pAnchors = new TAnchors();
pAnchors->AddAnchor(hDlg, IDC_MAIN_FRAME, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_SECURITY, akAll);
pAnchors->AddAnchor(hDlg, IDC_QUERY_SECURITY, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_SET_BLANK, akLeftCenter | akBottom);
pAnchors->AddAnchor(hDlg, IDC_SET_SECURITY, akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_RESULT_FRAME, akLeft | akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE_TITLE, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE, akLeft | akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_INFORMATION_TITLE, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_INFORMATION, akLeft | akRight | akBottom);
}
// Set the default security information to query
CheckDlgButton(hDlg, IDC_OWNER_INFORMATION, BST_CHECKED);
CheckDlgButton(hDlg, IDC_GROUP_INFORMATION, BST_CHECKED);
CheckDlgButton(hDlg, IDC_DACL_INFORMATION, BST_CHECKED);
// CheckDlgButton(hDlg, IDC_SACL_INFORMATION, BST_CHECKED);
// Set blank security descriptor
PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_SET_BLANK, BN_CLICKED), 0);
return TRUE;
}
static int OnSetAclType(HWND hDlg, LPCTSTR szItemText, UINT AclType)
{
HTREEITEM hItem;
TVITEM tvi;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
// Get the selected item
hItem = TreeView_GetSelection(hTreeView);
if(hItem != NULL)
{
tvi.mask = TVIF_PARAM | TVIF_TEXT;
tvi.pszText = (LPTSTR)szItemText;
tvi.lParam = AclType;
tvi.hItem = hItem;
TreeView_SetItem(hTreeView, &tvi);
}
return TRUE;
}
static int OnCreateNewSid(HWND /* hDlg */, HWND hTreeView, HTREEITEM hItem)
{
PSID pSid;
pSid = Sid_CreateNew(ACCESS_ALLOWED_ACE_TYPE);
if(pSid != NULL)
{
TreeView_SidToItem(hTreeView, hItem, pSid, szUnknownSid);
Sid_Free(pSid);
}
return TRUE;
}
static int OnInsertAceBefore(HWND hDlg, BOOL bBeforeSelected, BOOL bDeleteSelected = FALSE)
{
PACE_HEADER pAceHeader;
HTREEITEM hItemToDelete = NULL;
HTREEITEM hInsertAfter;
HTREEITEM hParent;
HTREEITEM hItem = NULL;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
PACL pAcl;
// Retrieve the item where to insert it
hInsertAfter = TreeView_GetSelection(hTreeView);
hParent = TreeView_GetParent(hTreeView, hInsertAfter);
// Shall we deleted the item?
if(bDeleteSelected)
hItemToDelete = hInsertAfter;
// If we shall insert the item BEFORE the current one, move back
if(bBeforeSelected)
hInsertAfter = TreeView_GetPreviousItem(hTreeView, hInsertAfter);
// Create ACE with one entry and set it to the new item
pAcl = Acl_CreateOneItem(GetDefaultAceType(hTreeView, hParent));
if(pAcl != NULL)
{
// Insert the ACE
if(GetAce(pAcl, 0, (LPVOID *)(&pAceHeader)))
hItem = TreeView_InsertAceItem(hTreeView, hParent, hInsertAfter, pAceHeader);
// Shall we delete the previous item?
if(hItemToDelete != NULL)
TreeView_DeleteItem(hTreeView, hItemToDelete);
// Select the item
TreeView_Select(hTreeView, hItem, TVGN_CARET);
HeapFree(g_hHeap, 0, pAcl);
}
return TRUE;
}
static int OnSwapAceWith(HWND hDlg, BOOL bWithPrevious)
{
ACE_HELPER AceHelper1;
ACE_HELPER AceHelper2;
HTREEITEM hSwapWith;
HTREEITEM hParent;
HTREEITEM hItem;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
// Retrieve the item where to insert it
hItem = TreeView_GetSelection(hTreeView);
hParent = TreeView_GetParent(hTreeView, hItem);
// Get the previous or next item to swap with
hSwapWith = (bWithPrevious) ? TreeView_GetPrevSibling(hTreeView, hItem)
: TreeView_GetNextSibling(hTreeView, hItem);
if(hItem != NULL && hSwapWith != NULL)
{
// Retrieve both ACEsPerform the swap operation
TreeView_ItemToAce(hTreeView, hItem, AceHelper1);
TreeView_ItemToAce(hTreeView, hSwapWith, AceHelper2);
// Change both items
TreeView_AceToItem(hTreeView, hSwapWith, AceHelper1);
TreeView_AceToItem(hTreeView, hItem, AceHelper2);
// Select the previous item
TreeView_Select(hTreeView, hSwapWith, TVGN_CARET);
}
return TRUE;
}
static int OnDeleteAce(HWND hDlg)
{
HTREEITEM hParent;
HTREEITEM hItem;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
DWORD dwChildCount;
hItem = TreeView_GetSelection(hTreeView);
hParent = TreeView_GetParent(hTreeView, hItem);
if(hParent != NULL && hItem != NULL)
{
// Delete the tree item
if(TreeView_DeleteItem(hTreeView, hItem))
{
// Retrieve the child count
dwChildCount = TreeView_GetChildCount(hTreeView, hParent);
if(dwChildCount == 0)
{
// Insert the ACL as empty
hItem = InsertTreeItem(hTreeView, hParent, szEmptyAcl, TREE_ITEM_EMPTY_ACL);
TreeView_Select(hTreeView, hItem, TVGN_CARET);
}
}
}
return TRUE;
}
static int OnSetBlankSecurityDescriptor(HWND hDlg)
{
SECURITY_DESCRIPTOR sd;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
// Initialize the tree view with blank security descriptor
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
TreeView_SdToTreeView(hTreeView, &sd);
return TRUE;
}
static int OnQuerySecurity(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
PSECURITY_DESCRIPTOR pSD = NULL;
SECURITY_INFORMATION SecInfo;
NTSTATUS Status = STATUS_SUCCESS;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
BYTE SecDescBuff[0x400];
DWORD cbSD = 0;
// Get the mask about which security information we want
SecInfo = GetWantedSecurityInfo(hDlg);
// Query the security information
if(IsHandleValid(pData->hFile))
{
pSD = (PSECURITY_DESCRIPTOR)SecDescBuff;
cbSD = sizeof(SecDescBuff);
Status = NtQuerySecurityObject(pData->hFile, SecInfo, pSD, cbSD, &cbSD);
if(Status == STATUS_BUFFER_TOO_SMALL && cbSD != 0)
{
pSD = (PSECURITY_DESCRIPTOR)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, cbSD);
Status = NtQuerySecurityObject(pData->hFile, SecInfo, pSD, cbSD, &cbSD);
}
}
// Set the result to the dialog controls
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFO_INT32, Status, cbSD);
// If succeeded, load our tree view with security information
if(NT_SUCCESS(Status))
TreeView_SdToTreeView(hTreeView, pSD);
// Free buffers and return
if(pSD != NULL && (PBYTE)pSD != SecDescBuff)
HeapFree(g_hHeap, 0, pSD);
return TRUE;
}
static int OnSetSecurity(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
SECURITY_DESCRIPTOR sd;
SECURITY_INFORMATION AppliedSecInfo = 0;
SECURITY_INFORMATION WantedSecInfo;
HTREEITEM hChildItem[5];
HTREEITEM hAclItem1 = NULL;
HTREEITEM hAclItem2 = NULL;
HTREEITEM hItem;
NTSTATUS Status = STATUS_SUCCESS;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
PSID pOwner = NULL;
PSID pGroup = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
// Get the mask about which security information we want
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
WantedSecInfo = GetWantedSecurityInfo(hDlg);
// Get handles of all child items
hChildItem[0] = TreeView_GetChild(hTreeView, TVI_ROOT);
hChildItem[1] = TreeView_GetNextSibling(hTreeView, hChildItem[0]);
hChildItem[2] = TreeView_GetNextSibling(hTreeView, hChildItem[1]);
hChildItem[3] = TreeView_GetNextSibling(hTreeView, hChildItem[2]);
hChildItem[4] = TreeView_GetNextSibling(hTreeView, hChildItem[3]);
//
// Put owner into the security descriptor
//
if(WantedSecInfo & OWNER_SECURITY_INFORMATION)
{
hItem = TreeView_GetChild(hTreeView, hChildItem[0]);
if(hItem != NULL)
{
if(TreeView_ItemToSid(hTreeView, hItem, &pOwner, false) && pOwner != NULL)
{
SetSecurityDescriptorOwner(&sd, pOwner, FALSE);
AppliedSecInfo |= OWNER_SECURITY_INFORMATION;
}
}
}
//
// Put group into the security descriptor
//
if(WantedSecInfo & GROUP_SECURITY_INFORMATION)
{
hItem = TreeView_GetChild(hTreeView, hChildItem[1]);
if(hItem != NULL)
{
if(TreeView_ItemToSid(hTreeView, hItem, &pGroup, false) && pGroup != NULL)
{
SetSecurityDescriptorGroup(&sd, pGroup, FALSE);
AppliedSecInfo |= GROUP_SECURITY_INFORMATION;
}
}
}
//
// Put DACL into the security descriptor
//
if(WantedSecInfo & DACL_SECURITY_INFORMATION)
{
hItem = TreeView_GetChild(hTreeView, hChildItem[2]);
if(hItem != NULL)
{
if(TreeView_ItemToAcl(hTreeView, hItem, NULL, &pDacl))
{
SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
AppliedSecInfo |= DACL_SECURITY_INFORMATION;
}
}
}
//
// Put SACL into the security descriptor
// Note: We have to combine SACL from two tree items
//
if(WantedSecInfo & (SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION))
{
// Get handles to wanted tree items
if(WantedSecInfo & SACL_SECURITY_INFORMATION)
hAclItem1 = TreeView_GetChild(hTreeView, hChildItem[3]);
if(WantedSecInfo & LABEL_SECURITY_INFORMATION)
hAclItem2 = TreeView_GetChild(hTreeView, hChildItem[4]);
if(TreeView_ItemToAcl(hTreeView, hAclItem1, hAclItem2, &pSacl))
{
SetSecurityDescriptorSacl(&sd, TRUE, pSacl, FALSE);
AppliedSecInfo |= (WantedSecInfo & (SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION));
}
}
// Apply the security descriptor to the file
if(AppliedSecInfo != 0)
{
// Set the result to the dialog controls
Status = NtSetSecurityObject(pData->hFile, AppliedSecInfo, &sd);
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_NOINFO, Status);
}
// Free all 4 parts of the security information
if(pSacl != NULL)
HeapFree(g_hHeap, 0, pSacl);
if(pDacl != NULL)
HeapFree(g_hHeap, 0, pDacl);
if(pGroup != NULL)
Sid_Free(pGroup);
if(pOwner != NULL)
Sid_Free(pOwner);
return TRUE;
}
static int OnSetActive(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
BOOL bEnable = FALSE;
if(IsHandleValid(pData->hFile))
bEnable = TRUE;
EnableDlgItems(hDlg, bEnable, IDC_QUERY_SECURITY, IDC_SET_SECURITY, 0);
return TRUE;
}
static BOOL OnEditNumericItemInPlace(
HWND /* hDlg */,
HWND hTreeView,
HTREEITEM hItem,
LPCTSTR szFormat)
{
TVITEM tvi;
LPTSTR szValue;
TCHAR szItemText[0x400];
HWND hEdit;
DWORD dwValue32 = 0;
DWORD dwErrCode;
// Retrieve the item text
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
if(!TreeView_GetItem(hTreeView, &tvi))
return FALSE;
// Retrieve the value
szValue = GetItemTextValue(szItemText);
if(szValue == NULL)
return FALSE;
// Convert the value to 32-bit integer
dwErrCode = Text2Hex32(szValue, &dwValue32);
if(dwErrCode != ERROR_SUCCESS)
return FALSE;
// Format the item to the edit field
StringCchPrintf(szItemText, _countof(szItemText), szFormat, dwValue32);
// Apply the value to the edit field
hEdit = TreeView_GetEditControl(hTreeView);
if(hEdit == NULL)
return FALSE;
// Apply the value to the edit item
Edit_LimitText(hEdit, 0x10);
SetWindowText(hEdit, szItemText);
return TRUE;
}
static BOOL OnEditGuidItemInPlace(
HWND /* hDlg */,
HWND hTreeView,
HTREEITEM hItem)
{
TVITEM tvi;
LPTSTR szGuidValue;
TCHAR szItemText[0x400];
HWND hEdit;
// Retrieve the item text
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
if(!TreeView_GetItem(hTreeView, &tvi))
return FALSE;
// Retrieve the value
szGuidValue = GetItemTextValue(szItemText);
if(szGuidValue == NULL)
return FALSE;
// Apply the value to the edit field
hEdit = TreeView_GetEditControl(hTreeView);
if(hEdit == NULL)
return FALSE;
// Apply the value to the edit item
Edit_LimitText(hEdit, 0x30);
SetWindowText(hEdit, szGuidValue);
return TRUE;
}
static BOOL OnEditSidItemInPlace(HWND /* hDlg */, HWND hTreeView, HTREEITEM hItem)
{
TCHAR szItemText[128];
HWND hEdit = TreeView_GetEditControl(hTreeView);
PSID pSid = NULL;
if(hEdit != NULL)
{
if(TreeView_ItemToSid(hTreeView, hItem, &pSid, true))
{
Edit_LimitText(hEdit, 128);
SidToString(pSid, szItemText, _countof(szItemText), false);
SetWindowText(hEdit, szItemText);
Sid_Free(pSid);
return TRUE;
}
}
return FALSE;
}
static void OnEditAceTypeModal(HWND hDlg, HWND hTreeView, HTREEITEM hItem)
{
ACE_HELPER AceHelper;
LPCSTR szAceTypeString;
bool bResult = false;
// Get the current ACE type from the item
if(TreeView_ItemToAce(hTreeView, hItem, AceHelper))
{
DWORD dwAceType = AceHelper.AceType;
// Run the dialog
if(FlagsDialog(hDlg, IDS_ACE_TYPE, AceHdrTypes, dwAceType) == IDOK && dwAceType != AceHelper.AceType)
{
// Put the ACE type
if(AceHelper.SetAceType(dwAceType))
{
// Create new SID
AceHelper.SetAllocatedSid(Sid_CreateNew((BYTE)AceHelper.AceType));
// Set the item text
szAceTypeString = GetAceTypeString(AceHelper.AceType);
TreeView_SetTreeItem(hTreeView, hItem, TWideString(szAceTypeString), (TREE_ITEM_ACE | AceHelper.AceType));
// Fill the sub-item
bResult = (TreeView_AceToItem(hTreeView, hItem, AceHelper) != NULL);
}
// Show an error if failed
if(bResult == false)
{
MessageBoxRc(hDlg, IDS_ERROR, IDS_ACE_TYPE_NOT_SUPPORTED, dwAceType);
}
}
}
}
static void OnEditNumericItemModal(
HWND hDlg,
HWND hTreeView,
HTREEITEM hItem, // Item to be edited
TFlagInfo * pFlags, // Flags array
LPCTSTR szFormat, // Format of the flags to be inserted back
UINT nIDTitle) // Title for the flags dialog
{
TVITEM tvi;
LPTSTR szValue;
TCHAR szItemText[0x400];
DWORD dwFlags32 = 0;
DWORD dwErrCode;
// Retrieve the item text
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
tvi.cchTextMax = _countof(szItemText);
if(!TreeView_GetItem(hTreeView, &tvi))
return;
// Retrieve the value
szValue = GetItemTextValue(szItemText);
if(szValue == NULL)
return;
// Convert the value to 32-bit integer
dwErrCode = Text2Hex32(szValue, &dwFlags32);
if(dwErrCode != ERROR_SUCCESS)
return;
// Either invoke the values dialog or the flags dialog
if(FlagsDialog(hDlg, nIDTitle, pFlags, dwFlags32) == IDOK)
{
NamedValueToString(pFlags, szItemText, _countof(szItemText), szFormat, dwFlags32);
TreeView_SetItem(hTreeView, &tvi);
}
}
static int OnBeginLabelEdit(HWND hDlg, LPNMTVDISPINFO pTVDispInfo)
{
HWND hTreeView = pTVDispInfo->hdr.hwndFrom;
BOOL bStartEditing = FALSE;
// Verify if the selected tree item is editable
switch(pTVDispInfo->item.lParam)
{
case TREE_ITEM_ACE_HEADER_FLAGS:
bStartEditing = OnEditNumericItemInPlace(hDlg, hTreeView, pTVDispInfo->item.hItem, _T("%02lX"));
break;
case TREE_ITEM_ACE_MASK:
case TREE_ITEM_ADS_ACE_MASK:
case TREE_ITEM_MANDATORY_MASK:
bStartEditing = OnEditNumericItemInPlace(hDlg, hTreeView, pTVDispInfo->item.hItem, _T("%08lX"));
break;
case TREE_ITEM_MANDATORY_LABEL:
bStartEditing = OnEditNumericItemInPlace(hDlg, hTreeView, pTVDispInfo->item.hItem, _T("%08lX"));
break;
case TREE_ITEM_ACE_OBJ_GUID:
case TREE_ITEM_ACE_OBJ_GUID2:
bStartEditing = OnEditGuidItemInPlace(hDlg, hTreeView, pTVDispInfo->item.hItem);
break;
case TREE_ITEM_SID:
case TREE_ITEM_NO_SID:
bStartEditing = OnEditSidItemInPlace(hDlg, hTreeView, pTVDispInfo->item.hItem);
break;
default:
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_CANNOT_EDIT_THIS);
break;
}
// If we start editing something, make sure that Esc key will not
// cancel the entire FileTest
DisableCloseDialog(hDlg, bStartEditing);
// Store the result info the dialog's private variables
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, bStartEditing ? FALSE : TRUE);
return TRUE;
}
static int OnEndLabelEdit(HWND hDlg, LPNMTVDISPINFO pTVDispInfo)
{
BOOL bAcceptChanges = FALSE;
// If pszText contains NULL, it means that the user cancelled the editing
if(pTVDispInfo->item.pszText != NULL)
{
// Verify if the selected file info class is editable
switch(pTVDispInfo->item.lParam)
{
case TREE_ITEM_ACE_HEADER_FLAGS:
bAcceptChanges = DeferSetItemNumericValue(hDlg, pTVDispInfo, AceHdrFlags, szAceHdrFlagsFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_ACE_MASK:
bAcceptChanges = DeferSetItemNumericValue(hDlg, pTVDispInfo, AceMasks, szAceMaskFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_ADS_ACE_MASK:
bAcceptChanges = DeferSetItemNumericValue(hDlg, pTVDispInfo, AdsAceMasks, szAceMaskFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_MANDATORY_MASK:
bAcceptChanges = DeferSetItemNumericValue(hDlg, pTVDispInfo, MandatoryMasks, szAceMaskFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_MANDATORY_LABEL:
bAcceptChanges = DeferSetItemNumericValue(hDlg, pTVDispInfo, NULL, szIntLevelFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_ACE_OBJ_GUID:
bAcceptChanges = DeferSetItemGuidValue(hDlg, pTVDispInfo, szAceObjTypeFmt);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_ACE_OBJ_GUID2:
bAcceptChanges = DeferSetItemGuidValue(hDlg, pTVDispInfo, szAceObjTypeFmt2);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
case TREE_ITEM_SID:
case TREE_ITEM_NO_SID:
bAcceptChanges = DeferSetItemSidValue(hDlg, pTVDispInfo);
if(bAcceptChanges == FALSE)
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_INVALID_DATA_FORMAT);
break;
default:
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_CANNOT_EDIT_THIS);
break;
}
}
// Enable the exit button
DisableCloseDialog(hDlg, FALSE);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, bAcceptChanges);
return TRUE;
}
static int OnTVContextMenu(HWND hDlg, LPARAM lParam)
{
HTREEITEM hItem;
POINT pt;
LPARAM ItemParam;
HMENU hMainMenu = NULL;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
RECT rect;
// Get the selected item
hItem = TreeView_GetSelection(hTreeView);
if(hItem != NULL)
{
// Get the LPARAM of the tree item.
ItemParam = TreeView_GetItemParam(hTreeView, hItem);
// NULL DACL or Empty DACL -> Exec context menu of that item type
if(ItemParam == TREE_ITEM_NULL_ACL || ItemParam == TREE_ITEM_EMPTY_ACL)
{
hMainMenu = FindContextMenu(IDR_ACL_TYPE_MENU);
}
if(IsTreeItemAce(ItemParam))
{
hMainMenu = FindContextMenu(IDR_ACE_MENU);
}
// If we picked a menu, execute it
if(hMainMenu != 0)
{
// Update the menu
UpdateContextMenu(hTreeView, hItem, hMainMenu);
// If we don't have the coords, make them from the tree item
if(lParam == 0xFFFFFFFF)
{
TreeView_GetItemRect(hTreeView, hItem, &rect, TRUE);
pt.x = rect.left;
pt.y = rect.bottom;
ClientToScreen(hTreeView, &pt);
lParam = MAKELPARAM(pt.x, pt.y);
}
// Execute the menu
return ExecuteContextMenu(hDlg, hMainMenu, lParam);
}
}
return FALSE;
}
static int OnTVRightClick(HWND hDlg)
{
TVHITTESTINFO hti;
HTREEITEM hItem;
POINT pt;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
// Select the right-clicked tree view item
GetCursorPos(&pt);
ScreenToClient(hTreeView, &pt);
hti.pt = pt;
hti.flags = TVHT_ONITEMLABEL;
hItem = TreeView_HitTest(hTreeView, &hti);
// If there is an item clicked, select it
if(hItem != NULL)
TreeView_Select(hTreeView, hItem, TVGN_CARET);
return FALSE;
}
static int OnTVDoubleClick(HWND hDlg)
{
HTREEITEM hSelItem;
LPARAM lParam;
HWND hTreeView = GetDlgItem(hDlg, IDC_SECURITY);
bool bGoToParent = true;
// Get the lParam of the clicked item
hSelItem = TreeView_GetSelection(hTreeView);
lParam = TreeView_GetItemParam(hTreeView, hSelItem);
// The ACE type item is the same like the ACE type subitem
if(IsTreeItemAce(lParam))
{
lParam = TREE_ITEM_ACE_HEADER_TYPE;
bGoToParent = false;
}
// Edit the item
switch(lParam)
{
case TREE_ITEM_NO_SID:
OnCreateNewSid(hDlg, hTreeView, hSelItem);
break;
case TREE_ITEM_NULL_ACL: // Insert a new ACE to the tree
case TREE_ITEM_EMPTY_ACL:
OnInsertAceBefore(hDlg, TRUE, TRUE);
break;
case TREE_ITEM_ACE_HEADER_TYPE:
if(bGoToParent)
hSelItem = TreeView_GetParent(hTreeView, hSelItem);
OnEditAceTypeModal(hDlg, hTreeView, hSelItem);
break;
case TREE_ITEM_ACE_HEADER_FLAGS:
OnEditNumericItemModal(hDlg, hTreeView, hSelItem, AceHdrFlags, szAceHdrFlagsFmt, IDS_ACE_FLAGS);
break;
case TREE_ITEM_ACE_MASK:
OnEditNumericItemModal(hDlg, hTreeView, hSelItem, AceMasks, szAceMaskFmt, IDS_ACE_MASK);
break;
case TREE_ITEM_ADS_ACE_MASK:
OnEditNumericItemModal(hDlg, hTreeView, hSelItem, AdsAceMasks, szAceMaskFmt, IDS_ADS_ACE_MASK);
break;
case TREE_ITEM_MANDATORY_MASK:
OnEditNumericItemModal(hDlg, hTreeView, hSelItem, MandatoryMasks, szAceMaskFmt, IDS_MANDATORY_MASK);
break;
case TREE_ITEM_ACE_OBJ_GUID:
case TREE_ITEM_ACE_OBJ_GUID2:
ObjectGuidHelpDialog(hDlg);
break;
case TREE_ITEM_MANDATORY_LABEL:
OnEditNumericItemModal(hDlg, hTreeView, hSelItem, IntegrityLevels, szIntLevelFmt, IDS_INTEGRITY_LEVEL);
break;
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
static void OnTVKeyDown(HWND hDlg, NMTVKEYDOWN * pNMTVKeyDown)
{
if(pNMTVKeyDown->wVKey == VK_SPACE)
{
OnTVDoubleClick(hDlg);
return;
}
if(pNMTVKeyDown->wVKey == 'C' && GetAsyncKeyState(VK_CONTROL) < 0)
{
TreeView_CopyToClipboard(pNMTVKeyDown->hdr.hwndFrom);
return;
}
}
static int OnCommand(HWND hDlg, UINT nNotify, UINT nIDCtrl)
{
if(nNotify == BN_CLICKED || nNotify == 1)
{
switch(nIDCtrl)
{
case ID_EDIT_LABEL:
return TreeView_EditLabel_ID(hDlg, IDC_SECURITY);
case ID_DOUBLE_CLICK:
return OnTVDoubleClick(hDlg);
case IDC_SET_NULL_ACL:
return OnSetAclType(hDlg, szNullAcl, TREE_ITEM_NULL_ACL);
case IDC_SET_EMPTY_ACL:
return OnSetAclType(hDlg, szEmptyAcl, TREE_ITEM_EMPTY_ACL);
case IDC_NEW_ACE_BEFORE:
return OnInsertAceBefore(hDlg, TRUE);
case IDC_NEW_ACE_AFTER:
return OnInsertAceBefore(hDlg, FALSE);
case IDC_MOVE_ACE_UP:
return OnSwapAceWith(hDlg, TRUE);
case IDC_MOVE_ACE_DOWN:
return OnSwapAceWith(hDlg, FALSE);
case IDC_DELETE_ACE:
return OnDeleteAce(hDlg);
case IDC_SET_BLANK:
return OnSetBlankSecurityDescriptor(hDlg);
case IDC_QUERY_SECURITY:
return OnQuerySecurity(hDlg);
case IDC_SET_SECURITY:
return OnSetSecurity(hDlg);
}
}
return FALSE;
}
static int OnNotify(HWND hDlg, NMHDR * pNMHDR)
{
switch(pNMHDR->code)
{
case PSN_SETACTIVE:
return OnSetActive(hDlg);
case NM_RCLICK:
if(pNMHDR->idFrom == IDC_SECURITY)
return OnTVRightClick(hDlg);
break;
case NM_DBLCLK:
if(pNMHDR->idFrom == IDC_SECURITY)
return OnTVDoubleClick(hDlg);
break;
case TVN_KEYDOWN:
OnTVKeyDown(hDlg, (NMTVKEYDOWN *)pNMHDR);
break;
case TVN_BEGINLABELEDIT:
return OnBeginLabelEdit(hDlg, (LPNMTVDISPINFO)pNMHDR);
case TVN_ENDLABELEDIT:
return OnEndLabelEdit(hDlg, (LPNMTVDISPINFO)pNMHDR);
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Public functions
INT_PTR CALLBACK PageProc09(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Handlers specific to our dialog
switch(uMsg)
{
case WM_INITDIALOG:
OnInitDialog(hDlg, lParam);
return TRUE;
case WM_SIZE:
if(pAnchors != NULL)
pAnchors->OnSize();
return FALSE;
case WM_DEFER_ITEM_TEXT:
TreeView_DeferItemText(hDlg, wParam, lParam);
return TRUE;
case WM_CONTEXTMENU:
return OnTVContextMenu(hDlg, lParam);
case WM_COMMAND:
return OnCommand(hDlg, HIWORD(wParam), LOWORD(wParam));
case WM_NOTIFY:
return OnNotify(hDlg, (NMHDR *)lParam);
case WM_DESTROY:
if(pAnchors != NULL)
delete pAnchors;
pAnchors = NULL;
return FALSE;
}
return FALSE;
}