Files
ladislav-zezula-FileTest/DlgPrivileges.cpp
2023-12-13 17:51:56 +01:00

630 lines
20 KiB
C++

/*****************************************************************************/
/* DlgPrivileges.cpp Copyright (c) Ladislav Zezula 2009 */
/*---------------------------------------------------------------------------*/
/* Description : */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 19.05.09 1.00 Lad Created */
/*****************************************************************************/
#include "FileTest.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// Local defines
template <DWORD Count>
struct TTokenPrivileges
{
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[Count];
};
struct TPrivilegeAndCtrl
{
LPCTSTR szPrivName;
UINT nCtrlID;
};
struct TDialogData
{
PTOKEN_PRIVILEGES pTokenPrivs;
DWORD dwIntegrityLevel;
DWORD dwSaveIntLevel;
BOOL bLongPathsSupported;
BOOL bLongPathsEnabled;
DWORD bFirstInit:1; // If TRUE, the dialog never received WM_INITDIALOG
};
//-----------------------------------------------------------------------------
// Local variables
static TPrivilegeAndCtrl PrivCtrlList[] =
{
{SE_TAKE_OWNERSHIP_NAME, IDC_TAKE_OWNERSHIP_NAME},
{SE_CHANGE_NOTIFY_NAME, IDC_CHANGE_NOTIFY_NAME},
{SE_MANAGE_VOLUME_NAME, IDC_MANAGE_VOLUME_NAME},
{SE_SECURITY_NAME, IDC_SECURITY_NAME},
{SE_RESTORE_NAME, IDC_RESTORE_NAME},
{SE_BACKUP_NAME, IDC_BACKUP_NAME},
{SE_TCB_NAME, IDC_TCB_NAME}
};
static LPCTSTR szKeyName = _T("SYSTEM\\CurrentControlSet\\Control\\FileSystem");
static LPCTSTR szValName = _T("LongPathsEnabled");
//-----------------------------------------------------------------------------
// Local functions
static TDialogData * GetData(HWND hDlg)
{
return (TDialogData *)GetWindowLongPtr(hDlg, DWLP_USER);
}
static void LoadSystemSettings(TDialogData & Data)
{
PTOKEN_MANDATORY_LABEL pMandatoryLabel = NULL;
PTOKEN_PRIVILEGES pTokenPrivs = NULL;
HANDLE hToken;
HKEY hSubKey;
DWORD cbMandatoryLabel = 0;
DWORD cbTokenPrivs = 0;
DWORD cbValue = sizeof(DWORD);
DWORD dwValue = 0;
DWORD dwType = 0;
// Set the default values
Data.dwIntegrityLevel = INTEGRITY_LEVEL_NONE;
// Open current thread/process token
hToken = OpenCurrentToken(TOKEN_QUERY);
if(hToken != NULL)
{
// Query the token privileges
GetTokenInformation(hToken, TokenPrivileges, pTokenPrivs, cbTokenPrivs, &cbTokenPrivs);
if(cbTokenPrivs != 0)
{
pTokenPrivs = (PTOKEN_PRIVILEGES)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, cbTokenPrivs);
if(pTokenPrivs != NULL)
{
GetTokenInformation(hToken, TokenPrivileges, pTokenPrivs, cbTokenPrivs, &cbTokenPrivs);
Data.pTokenPrivs = pTokenPrivs;
}
}
// Query the token mandatory label. Supported on Vista or newer.
GetTokenInformation(hToken, TokenIntegrityLevel, pMandatoryLabel, cbMandatoryLabel, &cbMandatoryLabel);
if(cbMandatoryLabel != 0)
{
pMandatoryLabel = (PTOKEN_MANDATORY_LABEL)HeapAlloc(GetProcessHeap(), 0, cbMandatoryLabel);
if(pMandatoryLabel != NULL)
{
if(GetTokenInformation(hToken, TokenIntegrityLevel, pMandatoryLabel, cbMandatoryLabel, &cbMandatoryLabel))
{
SID_IDENTIFIER_AUTHORITY SiaMandatoryLabel = SECURITY_MANDATORY_LABEL_AUTHORITY;
PSID pSid = pMandatoryLabel->Label.Sid;
UCHAR dwSubAuthCount = *GetSidSubAuthorityCount(pSid);
GetTokenInformation(hToken, TokenIntegrityLevel, pMandatoryLabel, cbMandatoryLabel, &cbMandatoryLabel);
Data.dwIntegrityLevel = SECURITY_MANDATORY_MEDIUM_RID;
// Is that a mandatory label SID ?
if(!memcmp(GetSidIdentifierAuthority(pSid), &SiaMandatoryLabel, sizeof(SID_IDENTIFIER_AUTHORITY)))
{
Data.dwIntegrityLevel = *GetSidSubAuthority(pSid, dwSubAuthCount - 1);
}
}
HeapFree(g_hHeap, 0, pMandatoryLabel);
}
}
CloseHandle(hToken);
}
// Query the option "Enable long path names"
// Windows build must be at least 14393
if(g_dwWinBuild >= 14393)
{
// The feature is supported
Data.bLongPathsSupported = TRUE;
// Let's get whether it's enabled
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
{
if(RegQueryValueEx(hSubKey, szValName, NULL, &dwType, (LPBYTE)(&dwValue), &cbValue) == ERROR_SUCCESS && dwType == REG_DWORD)
Data.bLongPathsEnabled = (dwValue != 0) ? TRUE : FALSE;
RegCloseKey(hSubKey);
}
}
// Save the original integrity level
Data.dwSaveIntLevel = Data.dwIntegrityLevel;
}
static void SetIntegrityLevelText(HWND hDlg)
{
LPCTSTR szIntLevel = _T("");
DWORD dwIntLevel;
DlgText2Hex32(hDlg, IDC_INTLEVEL_VALUE, &dwIntLevel);
switch(dwIntLevel)
{
case SECURITY_MANDATORY_UNTRUSTED_RID:
szIntLevel = _T("SECURITY_MANDATORY_UNTRUSTED_RID");
break;
case SECURITY_MANDATORY_LOW_RID:
szIntLevel = _T("SECURITY_MANDATORY_LOW_RID");
break;
case SECURITY_MANDATORY_MEDIUM_RID:
szIntLevel = _T("SECURITY_MANDATORY_MEDIUM_RID");
break;
case SECURITY_MANDATORY_HIGH_RID:
szIntLevel = _T("SECURITY_MANDATORY_HIGH_RID");
break;
case SECURITY_MANDATORY_SYSTEM_RID:
szIntLevel = _T("SECURITY_MANDATORY_SYSTEM_RID");
break;
case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:
szIntLevel = _T("SECURITY_MANDATORY_PROTECTED_PROCESS_RID");
break;
}
SetDlgItemText(hDlg, IDC_INTLEVEL_TEXT, szIntLevel);
}
static void InitDialog_Privileges(TDialogData * pData, HWND hDlg)
{
PTOKEN_PRIVILEGES pTokenPrivs;
HWND hWndChild;
// If query token succeeded, parse them
if((pTokenPrivs = pData->pTokenPrivs) != NULL)
{
for(DWORD i = 0; i < pTokenPrivs->PrivilegeCount; i++)
{
PLUID_AND_ATTRIBUTES pLuid = pTokenPrivs->Privileges + i;
TCHAR szPrivName[0x80];
DWORD cchName = _countof(szPrivName);
LookupPrivilegeName(NULL, &pLuid->Luid, szPrivName, &cchName);
// Find the appropriate check box. If found, reflect the privilege to it
for(size_t j = 0; j < _countof(PrivCtrlList); j++)
{
if(!_tcsicmp(PrivCtrlList[j].szPrivName, szPrivName))
{
// Is the checkbox there ?
if((hWndChild = GetDlgItem(hDlg, PrivCtrlList[j].nCtrlID)) != NULL)
{
Button_SetCheck(hWndChild, (pLuid->Attributes & SE_PRIVILEGE_ENABLED) ? BST_CHECKED : BST_UNCHECKED);
EnableWindow(hWndChild, TRUE);
break;
}
}
}
}
}
}
static DWORD SaveDialog_Privileges(TDialogData * /* pData */, HWND hDlg)
{
TTokenPrivileges<_countof(PrivCtrlList)> tkp = {0};
HANDLE hToken;
DWORD dwErrCode = ERROR_SUCCESS;
DWORD dwEnabled;
HWND hWndChild;
// Open current thread/process token
hToken = OpenCurrentToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
if(hToken != NULL)
{
// Parse all checkboxes and update privilege
for(size_t i = 0; i < _countof(PrivCtrlList); i++)
{
// Retrieve the check box
if((hWndChild = GetDlgItem(hDlg, PrivCtrlList[i].nCtrlID)) != NULL)
{
// If the check box is disabled, it means that the privilege is not granted
if(IsWindowEnabled(hWndChild))
{
// Is the privilege enabled?
dwEnabled = (Button_GetCheck(hWndChild) == BST_CHECKED) ? SE_PRIVILEGE_ENABLED : 0;
// Get the LUID for the privilege.
if(LookupPrivilegeValue(NULL, PrivCtrlList[i].szPrivName, &tkp.Privileges[tkp.PrivilegeCount].Luid))
{
tkp.Privileges[tkp.PrivilegeCount].Attributes = dwEnabled;
tkp.PrivilegeCount++;
}
else
{
dwErrCode = GetLastError();
break;
}
}
}
}
// If there is at least one privilege to set, do it
if(dwErrCode == ERROR_SUCCESS && tkp.PrivilegeCount != 0)
{
if(!AdjustTokenPrivileges(hToken, FALSE, (PTOKEN_PRIVILEGES)(&tkp), 0, NULL, NULL))
dwErrCode = GetLastError();
}
// Close the token handle
CloseHandle(hToken);
}
else
{
dwErrCode = GetLastError();
}
return dwErrCode;
}
static void InitDialog_IntegrityLevel(TDialogData * pData, HWND hDlg, HWND hWndChild)
{
TCHAR szText[0x20] = _T("<not supported>");
BOOL bEnable = FALSE;
if(pData->dwIntegrityLevel != INTEGRITY_LEVEL_NONE)
{
StringCchPrintf(szText, _countof(szText), _T("%08lX"), pData->dwIntegrityLevel);
bEnable = TRUE;
}
// Update the edit control
EnableDlgItems(hDlg, bEnable, IDC_INTLEVEL_VALUE, IDC_INTLEVEL_UPDOWN, 0);
SetWindowText(hWndChild, szText);
Edit_LimitText(hWndChild, 12);
// Update the up-down control
if((hWndChild = GetDlgItem(hDlg, IDC_INTLEVEL_UPDOWN)) != NULL)
{
SendMessage(hWndChild, UDM_SETRANGE32, 0, 0x7FFFFFFF);
SendMessage(hWndChild, UDM_SETPOS32, 0, 0x40000000);
}
}
static DWORD SaveDialog_IntegrityLevel(TDialogData * pData, HWND hDlg, HWND hWndChild)
{
SID_IDENTIFIER_AUTHORITY Sia = SECURITY_MANDATORY_LABEL_AUTHORITY;
TOKEN_MANDATORY_LABEL tml;
HANDLE hToken = NULL;
DWORD dwIntLevel = 0;
DWORD dwErrCode = ERROR_SUCCESS;
PSID pMandatorySid = NULL;
// Retrieve the integrity level
DlgText2Hex32(hDlg, IDC_INTLEVEL_VALUE, &dwIntLevel);
// Did we change the integrity level?
if(IsWindowEnabled(hWndChild) && (dwIntLevel != pData->dwSaveIntLevel))
{
// Open current thread/process token
if((hToken = OpenCurrentToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT)) != NULL)
{
// Creae a new SID for mandatory label
if(AllocateAndInitializeSid(&Sia, 1, dwIntLevel, 0, 0, 0, 0, 0, 0, 0, &pMandatorySid))
{
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = pMandatorySid;
// Apply the integrity level to the token
if(!SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL)))
dwErrCode = GetLastError();
FreeSid(pMandatorySid);
}
else
{
dwErrCode = GetLastError();
}
// Close the token handle
CloseHandle(hToken);
}
else
{
dwErrCode = GetLastError();
}
}
return dwErrCode;
}
static void InitDialog_LongPaths(TDialogData * pData, HWND hWndChild)
{
EnableWindow(hWndChild, pData->bLongPathsSupported);
Button_SetCheck(hWndChild, pData->bLongPathsEnabled ? BST_CHECKED : BST_UNCHECKED);
}
static DWORD SaveDialog_LongPaths(TDialogData * /* pData */, HWND hWndChild)
{
HKEY hSubKey = NULL;
DWORD dwErrCode = ERROR_SUCCESS;
DWORD dwValue = 0;
// Is the feature supported at all?
if(IsWindowEnabled(hWndChild))
{
// Retrieve the state
dwValue = (Button_GetCheck(hWndChild) == BST_CHECKED) ? 1 : 0;
// Let's get whether it's enabled
dwErrCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_SET_VALUE, &hSubKey);
if(dwErrCode == ERROR_SUCCESS)
{
dwErrCode = RegSetValueEx(hSubKey, szValName, 0, REG_DWORD, (LPBYTE)(&dwValue), sizeof(DWORD));
RegCloseKey(hSubKey);
}
}
return dwErrCode;
}
//-----------------------------------------------------------------------------
// Dialog handlers
static int OnInitDialog(HWND hDlg, LPARAM lParam)
{
LPPROPSHEETPAGE psp = (LPPROPSHEETPAGE)lParam;
TDialogData * pData = (TDialogData *)(psp->lParam);
HWND hWndChild;
// Set the dialog data
SetWindowLongPtr(hDlg, DWLP_USER, psp->lParam);
// Save the pointer to the dialog data to the dialog
if(pData->bFirstInit == FALSE)
{
CenterWindowToParent(GetParent(hDlg));
pData->bFirstInit = TRUE;
}
// Configure the privileges, if present
if((hWndChild = GetDlgItem(hDlg, IDC_TAKE_OWNERSHIP_NAME)) != NULL)
InitDialog_Privileges(pData, hDlg);
// Configure the integrity level, if present
if((hWndChild = GetDlgItem(hDlg, IDC_INTLEVEL_VALUE)) != NULL)
InitDialog_IntegrityLevel(pData, hDlg, hWndChild);
// Configure the long path settings
if((hWndChild = GetDlgItem(hDlg, IDC_ENABLE_LONG_PATH_NAME)) != NULL)
InitDialog_LongPaths(pData, hWndChild);
// Update the privileges and LongPath settings
return TRUE;
}
static bool OnApply(HWND hDlg)
{
TDialogData * pData = GetData(hDlg);
LPCTSTR szCategory = NULL;
LPTSTR szErrorText = NULL;
DWORD dwErrCode = ERROR_SUCCESS;
HWND hWndChild;
// Configure the privileges, if present
if(dwErrCode == ERROR_SUCCESS)
{
if((hWndChild = GetDlgItem(hDlg, IDC_TAKE_OWNERSHIP_NAME)) != NULL)
{
dwErrCode = SaveDialog_Privileges(pData, hDlg);
szCategory = _T("privileges");
}
}
// Configure the integrity level, if present
if(dwErrCode == ERROR_SUCCESS)
{
if((hWndChild = GetDlgItem(hDlg, IDC_INTLEVEL_VALUE)) != NULL)
{
dwErrCode = SaveDialog_IntegrityLevel(pData, hDlg, hWndChild);
szCategory = _T("integrity level");
}
}
// Configure the long path settings
if(dwErrCode == ERROR_SUCCESS)
{
if((hWndChild = GetDlgItem(hDlg, IDC_ENABLE_LONG_PATH_NAME)) != NULL)
{
dwErrCode = SaveDialog_LongPaths(pData, hWndChild);
szCategory = _T("long paths");
}
}
// Show an error message
if(dwErrCode != ERROR_SUCCESS)
{
if((szErrorText = GetErrorText(GetLastError())) != NULL)
{
MessageBoxRc(hDlg, IDS_ERROR, IDS_E_APPLY_SETTINGS, szCategory, szErrorText);
delete [] szErrorText;
}
}
return (bool)(dwErrCode == ERROR_SUCCESS);
}
static int OnSelectAllCheckBoxes(HWND hDlg, int nChecked)
{
TCHAR szClassName[100];
HWND hWndChild = GetFirstChild(hDlg);
DWORD dwStyles;
// Enumerate all children
while(hWndChild != NULL)
{
GetClassName(hWndChild, szClassName, _countof(szClassName));
dwStyles = (DWORD)GetWindowLong(hWndChild, GWL_STYLE);
if(!_tcsicmp(szClassName, WC_BUTTON) && (dwStyles & BS_AUTOCHECKBOX))
{
if(IsWindowEnabled(hWndChild))
{
Button_SetCheck(hWndChild, nChecked);
}
}
hWndChild = GetNextSibling(hWndChild);
}
return TRUE;
}
static int OnDeltaPos(HWND hDlg, NMUPDOWN * pNMUpDown)
{
DWORD dwSaveIntLevel;
DWORD dwIntLevel = 0;
// Retrieve the integrity level
DlgText2Hex32(hDlg, IDC_INTLEVEL_VALUE, &dwIntLevel);
dwSaveIntLevel = dwIntLevel;
// Move the integrity level
if(pNMUpDown->iDelta > 0)
{
if(dwIntLevel <= 0x0000E000)
dwIntLevel += 0x00001000;
else
dwIntLevel = 0x0000F000;
}
else
{
if(dwIntLevel >= 0x1000)
dwIntLevel -= 0x00001000;
else
dwIntLevel = 0;
}
// Update the integrity level
if(dwIntLevel != dwSaveIntLevel)
Hex2DlgText32(hDlg, IDC_INTLEVEL_VALUE, dwIntLevel);
return TRUE;
}
static void OnCommand(HWND hDlg, UINT nNotifyCode, UINT nCtrlID)
{
switch(nNotifyCode)
{
case BN_CLICKED:
if(nCtrlID == IDC_SELECT_ALL)
{
OnSelectAllCheckBoxes(hDlg, BST_CHECKED);
break;
}
if(nCtrlID == IDC_CLEAR_ALL)
{
OnSelectAllCheckBoxes(hDlg, BST_UNCHECKED);
break;
}
break;
case EN_CHANGE:
if(nCtrlID == IDC_INTLEVEL_VALUE)
SetIntegrityLevelText(hDlg);
break;
}
}
static INT_PTR OnNotify(HWND hDlg, LPNMHDR pNMHdr)
{
switch(pNMHdr->code)
{
case UDN_DELTAPOS:
OnDeltaPos(hDlg, (NMUPDOWN *)pNMHdr);
break;
case PSN_APPLY:
if(!OnApply(hDlg))
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
break;
}
return TRUE;
}
static INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return OnInitDialog(hDlg, lParam);
case WM_COMMAND:
OnCommand(hDlg, HIWORD(wParam), LOWORD(wParam));
break;
case WM_NOTIFY:
return OnNotify(hDlg, (LPNMHDR)lParam);
}
return FALSE;
}
INT_PTR PrivilegesDialog(HWND hParent)
{
PROPSHEETHEADER psh = {0}; // Defines the property sheet
PROPSHEETPAGE psp = {0}; // Defines the property sheet pages
HPROPSHEETPAGE hPsp[5] = {0}; // An array to hold the page's HPROPSHEETPAGE handles
TDialogData Data = {0};
int nPages = 0;
// Load the current system settings
LoadSystemSettings(Data);
// Create the "Privileges" page
psp.dwSize = sizeof(PROPSHEETPAGE);
psp.pszTemplate = MAKEINTRESOURCE(IDD_SETTINGS01);
psp.hInstance = g_hInst;
psp.pfnDlgProc = DialogProc;
psp.dwFlags = PSP_DEFAULT;
psp.lParam = (LPARAM)(&Data);
hPsp[nPages++] = CreatePropertySheetPage(&psp);
// Create the "Integrity Level" page
psp.dwSize = sizeof(PROPSHEETPAGE);
psp.pszTemplate = MAKEINTRESOURCE(IDD_SETTINGS02);
psp.hInstance = g_hInst;
psp.pfnDlgProc = DialogProc;
psp.dwFlags = PSP_DEFAULT;
psp.lParam = (LPARAM)(&Data);
hPsp[nPages++] = CreatePropertySheetPage(&psp);
// Create the "Long Path Names" page
psp.dwSize = sizeof(PROPSHEETPAGE);
psp.pszTemplate = MAKEINTRESOURCE(IDD_SETTINGS03);
psp.hInstance = g_hInst;
psp.pfnDlgProc = DialogProc;
psp.dwFlags = PSP_DEFAULT;
psp.lParam = (LPARAM)(&Data);
hPsp[nPages++] = CreatePropertySheetPage(&psp);
// Create the property sheet
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.hInstance = g_hInst;
psh.hwndParent = hParent;
psh.pszIcon = MAKEINTRESOURCE(IDI_FILE_TEST);
psh.pszCaption = MAKEINTRESOURCE(IDS_SETTINGS);
psh.phpage = hPsp;
psh.dwFlags = PSH_USEICONID | PSH_NOAPPLYNOW;
psh.nStartPage = 0;
psh.nPages = nPages;
// Run the wizard and return the error code
return PropertySheet(&psh);
}