windows-nt/Source/XPSP1/NT/com/ole32/oleui/chicago/util.cpp

2199 lines
64 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1994.
//
// File: util.cpp
//
// Contents: Implements the utility class CUtility
//
// Classes:
//
// Methods: CUtility::CkForAccessDenied
// CUtility::CkAccessRights
// CUtility::PostErrorMessage (x2)
// CUtility::WriteRegSzNamedValue
// CUtility::WriteRegDwordNamedValue
// CUtility::WriteRegSingleACL
// CUtility::WriteRegKeyACL
// CUtility::WriteRegKeyACL2
// CUtility::WriteLsaPassword
// CUtility::DeleteRegKey
// CUtility::DeleteRegValue
// CUtility::WriteSrvIdentity
// CUtility::ACLEditor
// CUtility::ACLEditor2
// CUtility::InvokeUserBrowser
// CUtility::InvokeMachineBrowser
// CUtility::StringFromGUID
// CUtility::IsEqualGuid
// CUtility::AdjustPrivilege
// CUtility::VerifyRemoteMachine
// CUtility::RetrieveUserPassword
// CUtility::StoreUserPassword
// CUtility::LookupProcessInfo
// CUtility::MakeSecDesc
// CUtility::CheckSDForCOM_RIGHTS_EXECUTE
// CUtility::ChangeService
// CUtility::UpdateDCOMInfo(void)
// CUtility::FixHelp
// CUtility::CopySD
// CUtility::SetInheritanceFlags
//
// Functons: callBackFunc
// ControlFixProc
//
// History: 23-Apr-96 BruceMa Created.
//
//----------------------------------------------------------------------
#include "stdafx.h"
#include "assert.h"
#include "resource.h"
#include "afxtempl.h"
#include "types.h"
#include "datapkt.h"
#include "clspsht.h"
extern "C"
{
#include <getuser.h>
}
#include "util.h"
#include "virtreg.h"
extern "C"
{
#include <ntlsa.h>
#include <ntseapi.h>
#include <sedapi.h>
#include <winnetwk.h>
#include <uiexport.h>
#include <rpc.h>
#include <rpcdce.h>
}
extern "C"
{
int _stdcall UpdateActivationSettings(HANDLE hRpc, RPC_STATUS *status);
}
static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
8, 9, '-', 10, 11, 12, 13, 14, 15 };
static const TCHAR szDigits[] = TEXT("0123456789ABCDEF");
static const DWORD SIZEOF_SID = 44;
// This leaves space for 2 access allowed ACEs in the ACL.
const DWORD SIZEOF_ACL = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) +
2 * SIZEOF_SID;
static const DWORD SIZEOF_TOKEN_USER = sizeof(TOKEN_USER) + SIZEOF_SID;
static const SID LOCAL_SYSTEM_SID = {SID_REVISION, 1, {0,0,0,0,0,5},
SECURITY_LOCAL_SYSTEM_RID };
static const DWORD NUM_SEC_PKG = 8;
// These are required for the method CUtility::UpdateDCOMInfo which invokes
// an RPC proxy which expects the following
extern "C" void * _stdcall MIDL_user_allocate(size_t size)
{
return new BYTE[size];
}
extern "C" void _stdcall MIDL_user_free(void *p)
{
delete p;
}
CUtility::CUtility(void)
{
m_hRpc = NULL;
}
CUtility::~CUtility(void)
{
if (m_hRpc != NULL)
{
RpcBindingFree(&m_hRpc);
}
}
void CUtility::CkForAccessDenied(int err)
{
if (err == ERROR_ACCESS_DENIED)
{
CString sMsg;
CString sCaption;
sMsg.LoadString(IDS_ACCESSDENIED);
sCaption.LoadString(IDS_SYSTEMMESSAGE);
MessageBox(NULL, sMsg, sCaption, MB_OK);
}
}
BOOL CUtility::CkAccessRights(HKEY hRoot, TCHAR *szKeyPath)
{
int err;
HKEY hKey;
BYTE aSid[256];
DWORD cbSid = 256;
PSECURITY_DESCRIPTOR pSid = (PSECURITY_DESCRIPTOR) aSid;
BOOL fFreePsid = FALSE;
// Open the specified key
err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey);
// The key may not exist
if (err == ERROR_FILE_NOT_FOUND)
{
return TRUE;
}
if (err == ERROR_SUCCESS)
{
// Fetch the security descriptor on this key
err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
(PSECURITY_DESCRIPTOR) aSid,
&cbSid);
if (err == ERROR_INSUFFICIENT_BUFFER)
{
pSid = (PSECURITY_DESCRIPTOR) malloc(cbSid);
if (pSid == NULL)
{
return FALSE;
}
fFreePsid = TRUE;
err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
(PSECURITY_DESCRIPTOR) pSid,
&cbSid);
}
// We've read the security descriptor - now try to write it
if (err == ERROR_SUCCESS)
{
err = RegSetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSid);
}
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
}
return err == ERROR_SUCCESS ? TRUE : FALSE;
}
void CUtility::PostErrorMessage(void)
{
TCHAR szMessage[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
0, szMessage, sizeof( szMessage ), NULL);
CString sCaption;
sCaption.LoadString(IDS_SYSTEMMESSAGE);
MessageBox(NULL, szMessage, sCaption, MB_OK);
}
void CUtility::PostErrorMessage(int err)
{
TCHAR szMessage[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
0, szMessage, sizeof( szMessage ), NULL);
CString sCaption;
sCaption.LoadString(IDS_SYSTEMMESSAGE);
MessageBox(NULL, szMessage, sCaption, MB_OK);
}
// Write a named string value to the registry
int CUtility::WriteRegSzNamedValue(HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
TCHAR *szVal,
DWORD dwSize)
{
int err;
HKEY hKey;
ULONG lSize;
// Open the key
if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey)) != ERROR_SUCCESS)
{
return err;
}
// Attempt to write the named value
lSize = _tcslen(szVal) + 1;
if ((err = RegSetValueEx(hKey, szValueName, NULL, REG_SZ, (BYTE *) szVal,
lSize*sizeof(TCHAR) ))
!= ERROR_SUCCESS)
{
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return err;
}
// Successful
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return ERROR_SUCCESS;
}
// Write a named DWORD value to the registry
int CUtility::WriteRegDwordNamedValue(HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
DWORD dwVal)
{
int err;
HKEY hKey;
// Open the key
if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey))
!= ERROR_SUCCESS)
{
return err;
}
// Attempt to write the named value
if (RegSetValueEx(hKey, szValueName, NULL, REG_DWORD, (BYTE *) &dwVal,
sizeof(DWORD))
!= ERROR_SUCCESS)
{
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return GetLastError();
}
// Return the value
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return ERROR_SUCCESS;
}
// Write an ACL as a registry named value
int CUtility::WriteRegSingleACL(HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
PSECURITY_DESCRIPTOR pSec)
{
int err;
HKEY hKey = hRoot;
PSrSecurityDescriptor pSrSec;
PSrAcl pDacl;
// Open the key unless the key path is NULL
if (szKeyPath)
{
if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey))
!= ERROR_SUCCESS)
{
return err;
}
}
// If there are no ACE's and this is DefaultAccessPermission, then
// interpret this as activator access only which we indicate by
// removing the named value
pSrSec = (PSrSecurityDescriptor) pSec;
pDacl = (PSrAcl) (((BYTE *) pSec) + (pSrSec->Dacl));
if (_tcscmp(szValueName, TEXT("DefaultAccessPermission")) == 0 &&
pDacl->AceCount == 0)
{
RegDeleteValue(hKey, szValueName);
}
// Else write the ACL simply as a REG_SZ value
else
{
err = RegSetValueEx(hKey,
szValueName,
0,
REG_BINARY,
(BYTE *) pSec,
#if 0
RtlLengthSecurityDescriptor(pSec));
#else
10);
#endif
}
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return err;
}
// Write an ACL on a registry key
int CUtility::WriteRegKeyACL(HKEY hKey,
HKEY *phClsids,
unsigned cClsids,
PSECURITY_DESCRIPTOR pSec,
PSECURITY_DESCRIPTOR pSecOrig)
{
int err;
// The logic is somewhat different depending on whether we're starting
// with HKEY_CLASSES_ROOT or a specific AppID
if (hKey == HKEY_CLASSES_ROOT)
{
return WriteRegKeyACL2(hKey, hKey, pSec, pSecOrig);
}
// It's a specific AppID
else
{
// Write the security on the AppID key
if (err = RegSetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSec) != ERROR_SUCCESS)
{
return err;
}
// Iterate over the CLSID's covered by this AppID and recursively
// write security on them and their subkeys
for (UINT k = 0; k < cClsids; k++)
{
if (err = WriteRegKeyACL2(phClsids[k], phClsids[k], pSec, pSecOrig)
!= ERROR_SUCCESS)
{
return err;
}
}
}
return ERROR_SUCCESS;
}
// Write an ACL recursively on a registry key provided the current
// security descriptor on the key is the same as the passed in
// original security descriptor
int CUtility::WriteRegKeyACL2(HKEY hRoot,
HKEY hKey,
PSECURITY_DESCRIPTOR pSec,
PSECURITY_DESCRIPTOR pSecOrig)
{
BYTE aCurrSD[256];
DWORD cbCurrSD = 256;
PSECURITY_DESCRIPTOR pCurrSD = (PSECURITY_DESCRIPTOR) aCurrSD;
BOOL fFreePCurrSD = FALSE;
int err;
BOOL fProceed;
// Read the current security descriptor on this key
err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
aCurrSD,
&cbCurrSD);
if (err == ERROR_MORE_DATA || err == ERROR_INSUFFICIENT_BUFFER)
{
pCurrSD = (SECURITY_DESCRIPTOR *) new BYTE[cbCurrSD];
if (pCurrSD == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
fFreePCurrSD = TRUE;
}
else if (err != ERROR_SUCCESS)
{
return err;
}
if ((err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pCurrSD,
&cbCurrSD)
!= ERROR_SUCCESS))
{
if (fFreePCurrSD)
{
delete pCurrSD;
}
return err;
}
// Only proceed down this subtree if the current SD and the
// original SD are the same
fProceed = CompareSDs((PSrSecurityDescriptor) pCurrSD,
(PSrSecurityDescriptor) pSecOrig);
// We're done with the current security descriptor
if (fFreePCurrSD)
{
delete pCurrSD;
}
if (!fProceed)
{
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return ERROR_SUCCESS;
}
// Write the top level ACL
err = RegSetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSec);
// Now enumerate the subkeys and write ACL's on them
DWORD iSubKey;
TCHAR szSubKeyName[128];
HKEY hKey2;
iSubKey = 0;
while (err == ERROR_SUCCESS)
{
// Enumerate the next key
err = RegEnumKey(hKey, iSubKey, szSubKeyName, 128);
if (err != ERROR_SUCCESS)
{
break;
}
// Prepare for the next key
iSubKey++;
// Open this subkey and recursively write the ACL on it and
// all of its subkeys
if (RegOpenKeyEx(hKey, szSubKeyName, 0, KEY_ALL_ACCESS, &hKey2)
== ERROR_SUCCESS)
{
err = WriteRegKeyACL2(hRoot, hKey2, pSec, pSecOrig);
}
}
if (hKey != hRoot)
{
RegCloseKey(hKey);
}
return err == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : err;
}
// Write a user's password to the private LSA database
int CUtility::WriteLsaPassword(CLSID appid, TCHAR *szPassword)
{
return ERROR_SUCCESS;
}
int CUtility::DeleteRegKey(HKEY hRoot, TCHAR *szKeyPath)
{
return RegDeleteKey(hRoot, szKeyPath);
}
int CUtility::DeleteRegValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName)
{
int err;
HKEY hKey;
if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey)) == ERROR_SUCCESS)
{
err = RegDeleteValue(hKey, szValueName);
if (hRoot != hKey)
RegCloseKey(hKey);
}
return err;
}
// Change the identity under which a service runs
int CUtility::WriteSrvIdentity(TCHAR *szService, TCHAR *szIdentity)
{
return ERROR_SUCCESS;
}
DWORD __stdcall callBackFunc(HWND hwndParent,
HANDLE hInstance,
ULONG CallBackContext,
PSECURITY_DESCRIPTOR SecDesc,
PSECURITY_DESCRIPTOR SecDescNewObjects,
BOOLEAN ApplyToSubContainers,
BOOLEAN ApplyToSubObjects,
LPDWORD StatusReturn)
{
int err = ERROR_SUCCESS;
PCallBackContext pCallBackContext = (PCallBackContext) CallBackContext;
// Set the inheritance flags on the new security descriptor
if (pCallBackContext->pktType == RegKeyACL)
{
g_util.SetInheritanceFlags((SECURITY_DESCRIPTOR *) SecDesc);
}
// Write the new or modified security descriptor
if (*pCallBackContext->pIndex == -1)
{
if (pCallBackContext->pktType == SingleACL)
{
err = g_virtreg.NewRegSingleACL(
pCallBackContext->info.single.hRoot,
pCallBackContext->info.single.szKeyPath,
pCallBackContext->info.single.szValueName,
(SECURITY_DESCRIPTOR *) SecDesc,
FALSE,
pCallBackContext->pIndex);
}
else
{
err = g_virtreg.NewRegKeyACL(
pCallBackContext->info.regKey.hKey,
pCallBackContext->info.regKey.phClsids,
pCallBackContext->info.regKey.cClsids,
pCallBackContext->info.regKey.szTitle,
pCallBackContext->origSD,
(SECURITY_DESCRIPTOR *) SecDesc,
FALSE,
pCallBackContext->pIndex);
}
}
else
{
g_virtreg.ChgRegACL(*pCallBackContext->pIndex,
(SECURITY_DESCRIPTOR *) SecDesc,
FALSE);
}
*StatusReturn = err;
return err;
}
// Invoke the ACL editor on the specified named value. This method
// writes an ACL data packet to the virtual registry. This method is for
// Access and Launch security only (pktType SingleACL).
int CUtility::ACLEditor(HWND hWnd,
HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
int *pIndex,
PACKETTYPE pktType,
TCHAR *szPermType)
{
int err;
HKEY hKey;
BYTE aSD[128];
DWORD cbSD = 128;
DWORD dwType;
SECURITY_DESCRIPTOR *pSD = (SECURITY_DESCRIPTOR *) aSD;
BOOL fFreePSD = FALSE;
SID *pSid;
TCHAR szAllow[32];
TCHAR szDeny[32];
CString szAllow_;
CString szDeny_;
szAllow_.LoadString(IDS_Allow_);
szDeny_.LoadString(IDS_Deny_);
// Build the allow and deny strings
_tcscpy(szAllow, (LPCTSTR) szAllow_);
_tcscat(szAllow, szPermType);
_tcscpy(szDeny, (LPCTSTR) szDeny_);
_tcscat(szDeny, szPermType);
// Fetch the current SD, either from the registry, by default if the
// named value doesn't exist or from the virtual registry
if (*pIndex == -1)
{
// Open the specified key
if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0,
KEY_ALL_ACCESS, &hKey))
!= ERROR_SUCCESS)
{
return err;
}
// Attempt to read the specified named value
err = RegQueryValueEx(hKey, szValueName, 0, &dwType, (BYTE *) aSD,
&cbSD);
if (err == ERROR_MORE_DATA || err == ERROR_INSUFFICIENT_BUFFER)
{
pSD = (SECURITY_DESCRIPTOR *) new BYTE[cbSD];
if (pSD == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
fFreePSD = TRUE;
err = RegQueryValueEx(hKey, szValueName, 0, &dwType,
(BYTE *) pSD, &cbSD);
}
// The named valued doesn't exist. If this is
// \\HKEY_CLASSES_ROOT\...
// then use the default named value if it exists
else if (err != ERROR_SUCCESS)
{
if (hRoot != HKEY_LOCAL_MACHINE)
{
if (err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\OLE"),
0,
KEY_ALL_ACCESS,
&hKey)
!= ERROR_SUCCESS)
{
return err;
}
// Attempt to read the specified named value
TCHAR szDefault[32];
_tcscpy(szDefault, TEXT("Default"));
_tcscat(szDefault, szValueName);
err = RegQueryValueEx(hKey, szDefault, 0, &dwType,
(BYTE *) aSD, &cbSD);
if (err == ERROR_MORE_DATA)
{
pSD = (SECURITY_DESCRIPTOR *) new BYTE[cbSD];
if (pSD == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
fFreePSD = TRUE;
err = RegQueryValueEx(hKey, szDefault, 0, &dwType,
(BYTE *) pSD, &cbSD);
}
RegCloseKey(hKey);
}
}
// If still don't have an SD, then simply create one
if (err != ERROR_SUCCESS)
{
if (!g_util.LookupProcessInfo(&pSid, NULL))
{
return GetLastError();
}
if (!g_util.MakeSecDesc(pSid, &pSD))
{
delete pSid;
return GetLastError();
}
fFreePSD = TRUE;
}
}
// Fetch the most recently edited SD
else
{
CDataPacket *pCdp = g_virtreg.GetAt(*pIndex);
pSD = pCdp -> pkt.acl.pSec;
}
// Initialize the callback context
m_sCallBackContext.pktType = pktType;
m_sCallBackContext.pIndex = pIndex;
m_sCallBackContext.origSD = pSD;
m_sCallBackContext.info.single.hRoot = hRoot;
m_sCallBackContext.info.single.szKeyPath = szKeyPath;
m_sCallBackContext.info.single.szValueName = szValueName;
// Invoke the ACL editor
DWORD dwStatus = 0;
GENERIC_MAPPING genericMapping;
CString szObjectType;
szObjectType.LoadString(IDS_Registry_value);
SED_HELP_INFO helpInfo =
{
L"dcomcnfg.hlp",
{HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG}
};
#ifndef UNICODE
WCHAR * wszObjectType = new WCHAR[szObjectType.GetLength() + 1];
mbstowcs(wszObjectType, szObjectType, szObjectType.GetLength() + 1);
#endif
SED_OBJECT_TYPE_DESCRIPTOR objTyp =
{1, // Revision
FALSE, // Is container?
FALSE, // Allow new object perms?
FALSE, // Specific to generic?
&genericMapping, // Generic mapping
NULL, // Generic mapping new
#ifdef UNICODE
(TCHAR *) ((LPCTSTR) szObjectType), // Object type name
#else
(WCHAR *) ((LPCWSTR) wszObjectType), // Object type name
#endif
&helpInfo, // Help info
L"", // Ckbox title
L"", // Apply title
L"", //
NULL, // Special object access
NULL // New special object access
};
#ifndef UNICODE
WCHAR wszAllow[32];
mbstowcs(wszAllow, szAllow, 32);
WCHAR wszDeny[32];
mbstowcs(wszDeny, szDeny, 32);
SED_APPLICATION_ACCESS appAccess[] =
{{SED_DESC_TYPE_RESOURCE, COM_RIGHTS_EXECUTE, 0, wszAllow},
{SED_DESC_TYPE_RESOURCE, 0, 0, wszDeny}};
SED_APPLICATION_ACCESSES appAccesses =
{2, // Count of access groups
appAccess, // Access array
wszAllow // Default access name
};
#else
SED_APPLICATION_ACCESS appAccess[] =
{{SED_DESC_TYPE_RESOURCE, COM_RIGHTS_EXECUTE, 0, szAllow},
{SED_DESC_TYPE_RESOURCE, 0, 0, szDeny}};
SED_APPLICATION_ACCESSES appAccesses =
{2, // Count of access groups
appAccess, // Access array
szAllow // Default access name
};
#endif
// Intialize the help contexts
helpInfo.aulHelpContext[HC_MAIN_DLG] =
IDH_REGISTRY_VALUE_PERMISSIONS;
helpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_GLOBAL;
helpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_GLOBAL;
helpInfo.aulHelpContext[HC_ADD_USER_DLG] =
IDH_ADD_USERS_AND_GROUPS;
helpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_LG_DLG] =
IDH_LOCAL_GROUP_MEMBERSHIP;
helpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] =
IDH_GLOBAL_GROUP_MEMBERSHIP;
helpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] =
IDH_FIND_ACCOUNT1;
genericMapping.GenericRead = GENERIC_ALL;
genericMapping.GenericWrite = GENERIC_ALL;
genericMapping.GenericExecute = GENERIC_ALL;
genericMapping.GenericAll = GENERIC_ALL;
// If this is for Access or Launch permissons then check that the
// SD contains only allows and deny's for COM_RIGHTS_EXECUTE
if (!CheckSDForCOM_RIGHTS_EXECUTE(pSD))
{
return IDCANCEL;
}
// Invoke the ACL editor
// SedDiscretionaryAclEditor(hWnd, // Owner hWnd
// GetModuleHandle(NULL), // Owner hInstance
// NULL, // Server
// &objTyp, // ObjectTyp,
// &appAccesses, // Application accesses
// szValueName, // Object name,
// callBackFunc, // Callback function
// (ULONG) &m_sCallBackContext, // Callback context
// pSD, // Security descriptor,
// FALSE, // Couldnt read Dacl,
// FALSE, // Can't write Dacl,
// &dwStatus, // SED status return,
// 0); // Flags
// Check status return
if (dwStatus != ERROR_SUCCESS)
{
// PostErrorMessage(dwStatus);
}
// We're done
if (fFreePSD)
{
delete pSD;
}
return dwStatus == 0 ? ERROR_SUCCESS : IDCANCEL;
}
// Invoke the ACL editor on the specified key. This method writes an ACL
// data packet to the virtual registry. This method supports configuration
// security only (pktType RegKeyACL).
int CUtility::ACLEditor2(HWND hWnd,
HKEY hKey,
HKEY *phClsids,
unsigned cClsids,
TCHAR *szTitle,
int *pIndex,
PACKETTYPE pktType)
{
int err;
BYTE aSD[128];
DWORD cbSD = 128;
SECURITY_DESCRIPTOR *pSD = (SECURITY_DESCRIPTOR *) aSD;
BOOL fFreePSD = FALSE;
TCHAR szKeyRead[32];
CString szKeyRead_;
TCHAR szHkeyClassesRoot[32];
CString szHkeyClassesRoot_;
// Initialize strings
szKeyRead_.LoadString(IDS_Key_Read);
_tcscpy(szKeyRead, (LPCTSTR) szKeyRead_);
szHkeyClassesRoot_.LoadString(IDS_HKEY_CLASSES_ROOT);
_tcscpy(szHkeyClassesRoot, (LPCTSTR) szHkeyClassesRoot_);
if (*pIndex == -1)
{
// Read the security descriptor on this key
err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
aSD,
&cbSD);
if (err == ERROR_MORE_DATA || err == ERROR_INSUFFICIENT_BUFFER)
{
pSD = (SECURITY_DESCRIPTOR *) new BYTE[cbSD];
if (pSD == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
fFreePSD = TRUE;
}
else if (err != ERROR_SUCCESS)
{
return err;
}
if ((err = RegGetKeySecurity(hKey,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSD,
&cbSD)
!= ERROR_SUCCESS))
{
if (fFreePSD)
{
delete pSD;
}
return err;
}
}
// Fetch the most recently edited SD
else
{
CDataPacket *pCdp = g_virtreg.GetAt(*pIndex);
pSD = pCdp -> pkt.racl.pSec;
}
// Initialize the callback context
m_sCallBackContext.pktType = pktType;
m_sCallBackContext.pIndex = pIndex;
m_sCallBackContext.origSD = pSD;
m_sCallBackContext.info.regKey.hKey = hKey;
m_sCallBackContext.info.regKey.phClsids = phClsids;
m_sCallBackContext.info.regKey.cClsids = cClsids;
m_sCallBackContext.info.regKey.szTitle = szTitle;
// Invoke the ACL editor
DWORD dwStatus = 0;
GENERIC_MAPPING genericMapping;
CString szObjectType;
szObjectType.LoadString(IDS_Registry_Key);
CString szQueryValue;
szQueryValue.LoadString(IDS_Query_Value);
CString szSetValue;
szSetValue.LoadString(IDS_Set_Value);
CString szCreateSubkeys;
szCreateSubkeys.LoadString(IDS_Create_Subkey);
CString szEnumerateSubkeys;
szEnumerateSubkeys.LoadString(IDS_Enumerate_Subkeys);
CString szNotify;
szNotify.LoadString(IDS_Notify);
CString szCreateLink;
szCreateLink.LoadString(IDS_Create_Link);
CString szDelete;
szDelete.LoadString(IDS_Delete);
CString szWriteDAC;
szWriteDAC.LoadString(IDS_Write_DAC);
CString szWriteOwner;
szWriteOwner.LoadString(IDS_Write_Owner);
CString szReadControl;
szReadControl.LoadString(IDS_Read_Control);
CString szRead;
szRead.LoadString(IDS_Read);
CString szFullControl;
szFullControl.LoadString(IDS_Full_Control);
CString szSpecialAccess;
szSpecialAccess.LoadString(IDS_Special_AccessDotDotDot);
SED_HELP_INFO helpInfo =
{
L"dcomcnfg.hlp",
{HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG,
HC_MAIN_DLG}
};
#ifndef UNICODE
WCHAR * wszObjectType = new WCHAR[szObjectType.GetLength() + 1];
mbstowcs(wszObjectType, szObjectType, szObjectType.GetLength() + 1);
WCHAR * wszSpecialAccess = new WCHAR[szSpecialAccess.GetLength() + 1];
mbstowcs(wszSpecialAccess, szSpecialAccess, szSpecialAccess.GetLength() + 1);
#endif
SED_OBJECT_TYPE_DESCRIPTOR objTyp =
{SED_REVISION1, // Revision
FALSE, // Is container?
FALSE, // Allow new object perms?
FALSE, // Specific to generic?
&genericMapping, // Generic mapping
NULL, // Generic mapping new
#ifdef UNICODE
(TCHAR *) ((LPCTSTR) szObjectType), // Object type name
#else
(WCHAR *) ((LPCWSTR) wszObjectType), // Object type name
#endif
&helpInfo, // Help info
L"", // Ckbox title
L"", // Apply title
L"", //
#ifdef UNICODE
(TCHAR *) ((LPCTSTR) szSpecialAccess), // Special Access menu item
#else
(WCHAR *) ((LPCWSTR) wszSpecialAccess), // Special Access menu item
#endif
NULL // New special object access
};
#ifdef UNICODE
SED_APPLICATION_ACCESS appAccess[] =
{
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_QUERY_VALUE, 0,
(TCHAR *) ((LPCTSTR) szQueryValue) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_SET_VALUE, 0,
(TCHAR *) ((LPCTSTR) szSetValue) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_SUB_KEY, 0,
(TCHAR *) ((LPCTSTR) szCreateSubkeys) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_ENUMERATE_SUB_KEYS, 0,
(TCHAR *) ((LPCTSTR) szEnumerateSubkeys) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_NOTIFY, 0,
(TCHAR *) ((LPCTSTR) szNotify) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_LINK, 0,
(TCHAR *) ((LPCTSTR) szCreateLink) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, 0x00010000, /* DELETE, */ 0,
(TCHAR *) ((LPCTSTR) szDelete) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_DAC, 0,
(TCHAR *) ((LPCTSTR) szWriteDAC) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_OWNER, 0,
(TCHAR *) ((LPCTSTR) szWriteOwner) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, READ_CONTROL, 0,
(TCHAR *) ((LPCTSTR) szReadControl) },
{ SED_DESC_TYPE_RESOURCE, KEY_READ, 0,
(TCHAR *) ((LPCTSTR) szRead) },
{ SED_DESC_TYPE_RESOURCE, GENERIC_ALL, /* KEY_ALL_ACCESS, */ 0,
(TCHAR *) ((LPCTSTR) szFullControl) }
};
SED_APPLICATION_ACCESSES appAccesses =
{12, // Count of access groups
appAccess, // Access array
szKeyRead // Default access name
};
#else
WCHAR * wszQueryValue = new WCHAR[szQueryValue.GetLength() + 1];
mbstowcs(wszQueryValue, szQueryValue, szQueryValue.GetLength() + 1);
WCHAR * wszSetValue = new WCHAR[szSetValue.GetLength() + 1];
mbstowcs(wszSetValue, szSetValue, szSetValue.GetLength() + 1);
WCHAR * wszCreateSubkeys = new WCHAR[szCreateSubkeys.GetLength() + 1];
mbstowcs(wszCreateSubkeys, szCreateSubkeys, szCreateSubkeys.GetLength() + 1);
WCHAR * wszEnumerateSubkeys = new WCHAR[szEnumerateSubkeys.GetLength() + 1];
mbstowcs(wszEnumerateSubkeys, szEnumerateSubkeys, szEnumerateSubkeys.GetLength() + 1);
WCHAR * wszNotify = new WCHAR[szNotify.GetLength() + 1];
mbstowcs(wszNotify, szNotify, szNotify.GetLength() + 1);
WCHAR * wszCreateLink = new WCHAR[szCreateLink.GetLength() + 1];
mbstowcs(wszCreateLink, szCreateLink, szCreateLink.GetLength() + 1);
WCHAR * wszDelete = new WCHAR[szDelete.GetLength() + 1];
mbstowcs(wszDelete, szDelete, szDelete.GetLength() + 1);
WCHAR * wszWriteDAC = new WCHAR[szWriteDAC.GetLength() + 1];
mbstowcs(wszWriteDAC, szWriteDAC, szWriteDAC.GetLength() + 1);
WCHAR * wszWriteOwner = new WCHAR[szWriteOwner.GetLength() + 1];
mbstowcs(wszWriteOwner, szWriteOwner, szWriteOwner.GetLength() + 1);
WCHAR * wszReadControl = new WCHAR[szReadControl.GetLength() + 1];
mbstowcs(wszReadControl, szReadControl, szReadControl.GetLength() + 1);
WCHAR * wszRead = new WCHAR[szRead.GetLength() + 1];
mbstowcs(wszRead, szRead, szRead.GetLength() + 1);
WCHAR * wszFullControl = new WCHAR[szFullControl.GetLength() + 1];
mbstowcs(wszFullControl, szFullControl, szFullControl.GetLength() + 1);
SED_APPLICATION_ACCESS appAccess[] =
{
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_QUERY_VALUE, 0,
(WCHAR *) ((LPCWSTR) wszQueryValue) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_SET_VALUE, 0,
(WCHAR *) ((LPCWSTR) wszSetValue) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_SUB_KEY, 0,
(WCHAR *) ((LPCWSTR) wszCreateSubkeys) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_ENUMERATE_SUB_KEYS, 0,
(WCHAR *) ((LPCWSTR) wszEnumerateSubkeys) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_NOTIFY, 0,
(WCHAR *) ((LPCWSTR) wszNotify) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_LINK, 0,
(WCHAR *) ((LPCWSTR) wszCreateLink) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, 0x00010000, /* DELETE, */ 0,
(WCHAR *) ((LPCWSTR) wszDelete) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_DAC, 0,
(WCHAR *) ((LPCWSTR) wszWriteDAC) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_OWNER, 0,
(WCHAR *) ((LPCWSTR) wszWriteOwner) },
{ SED_DESC_TYPE_RESOURCE_SPECIAL, READ_CONTROL, 0,
(WCHAR *) ((LPCWSTR) wszReadControl) },
{ SED_DESC_TYPE_RESOURCE, KEY_READ, 0,
(WCHAR *) ((LPCWSTR) wszRead) },
{ SED_DESC_TYPE_RESOURCE, GENERIC_ALL, /* KEY_ALL_ACCESS, */ 0,
(WCHAR *) ((LPCWSTR) wszFullControl) }
};
WCHAR wszKeyRead[32];
mbstowcs(wszKeyRead, szKeyRead, 32);
SED_APPLICATION_ACCESSES appAccesses =
{12, // Count of access groups
appAccess, // Access array
wszKeyRead // Default access name
};
#endif
// Intialize the help contexts
helpInfo.aulHelpContext[HC_MAIN_DLG] =
IDH_REGISTRY_KEY_PERMISSIONS;
if (hKey == HKEY_CLASSES_ROOT)
{
helpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_GLOBAL;
helpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_GLOBAL;
}
else
{
helpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_PER_APPID;
helpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] =
IDH_SPECIAL_ACCESS_PER_APPID;
}
helpInfo.aulHelpContext[HC_ADD_USER_DLG] =
IDH_ADD_USERS_AND_GROUPS;
helpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_LG_DLG] =
IDH_LOCAL_GROUP_MEMBERSHIP;
helpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] =
IDH_GLOBAL_GROUP_MEMBERSHIP;
helpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] =
IDH_FIND_ACCOUNT1;
genericMapping.GenericRead = KEY_READ;
genericMapping.GenericWrite = KEY_WRITE;
genericMapping.GenericExecute = KEY_READ;
genericMapping.GenericAll = KEY_ALL_ACCESS;
// Invoke the ACL editor
// SedDiscretionaryAclEditor(hWnd, // Owner hWnd
// GetModuleHandle(NULL), // Owner hInstance
// NULL, // Server
// &objTyp, // ObjectTyp,
// &appAccesses, // Application accesses
// szTitle ? szTitle : szHkeyClassesRoot,// Object name,
// callBackFunc, // Callback function
// (ULONG) &m_sCallBackContext, // Callback context
// pSD, // Security descriptor,
// FALSE, // Couldnt read Dacl,
// FALSE, // Can't write Dacl,
// &dwStatus, // SED status return,
// 0); // Flags
// Check status return
if (dwStatus != ERROR_SUCCESS)
{
// PostErrorMessage(dwStatus);
}
// We're done
if (fFreePSD)
{
delete pSD;
}
return dwStatus == 0 ? ERROR_SUCCESS : IDCANCEL;
}
BOOL CUtility::InvokeUserBrowser(HWND hWnd, TCHAR *szUser)
{
BOOL fRet = FALSE;
HUSERBROW hUser;
USERBROWSER sUserBrowser;
SUserDetailsPlus sUserDetailsPlus;
ULONG ulSize = USER_DETAILS_BUFFER_SIZE;
CString szTitle;
szTitle.LoadString(IDS_Browse_for_users);
sUserBrowser.ulStructSize = sizeof(USERBROWSER);
sUserBrowser.fUserCancelled = FALSE;
sUserBrowser.fExpandNames = TRUE;
sUserBrowser.hwndOwner = hWnd;
#ifdef UNICODE
sUserBrowser.pszTitle = (TCHAR *) ((LPCTSTR) szTitle);
#else
WCHAR * wszTitle = new WCHAR[szTitle.GetLength() + 1];
mbstowcs(wszTitle, szTitle, szTitle.GetLength() + 1);
sUserBrowser.pszTitle = (WCHAR *) ((LPCWSTR) wszTitle);
#endif
sUserBrowser.pszInitialDomain = NULL;
sUserBrowser.Flags = USRBROWS_DONT_SHOW_COMPUTER |
USRBROWS_SINGLE_SELECT |
USRBROWS_INCL_ALL |
USRBROWS_SHOW_USERS;
sUserBrowser.ulHelpContext = IDH_BROWSE_FOR_USERS;
sUserBrowser.pszHelpFileName = L"dcomcnfg.hlp";
#if 0
hUser = OpenUserBrowser(&sUserBrowser);
if (hUser == NULL)
{
return FALSE;
}
else
{
CString szBackslash;
szBackslash.LoadString(IDS_backslash);
if (EnumUserBrowserSelection(hUser,
&sUserDetailsPlus.sUserDetails,
&ulSize))
{
_tcscpy(szUser, sUserDetailsPlus.sUserDetails.pszDomainName);
_tcscat(szUser, (LPCTSTR) szBackslash);
_tcscat(szUser, sUserDetailsPlus.sUserDetails.pszAccountName);
fRet = TRUE;
}
}
CloseUserBrowser(hUser);
#endif
return fRet;
}
BOOL CUtility::InvokeMachineBrowser(TCHAR *szMachine)
{
///////////////////////////////////////////////////
// If we end up not wanting to use I_SystemFocusDialog, then the code below
// is the start for fetching machine resources ourselves
#if 1
DWORD dwErr;
NETRESOURCE aNetResource[1000];
HANDLE hNetwork;
DWORD dwEntries = 100;
DWORD dwBufSize = sizeof(aNetResource);
dwErr = WNetOpenEnum(RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
0,
NULL,
&hNetwork);
if (dwErr == NO_ERROR)
{
dwEntries = 0xffffffff;
dwErr = WNetEnumResource(hNetwork,
&dwEntries,
aNetResource,
&dwBufSize);
}
WNetCloseEnum(hNetwork);
dwErr = WNetOpenEnum(RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
0,
aNetResource,
&hNetwork);
if (dwErr == NO_ERROR)
{
dwEntries = 0xffffffff;
dwErr = WNetEnumResource(hNetwork,
&dwEntries,
&aNetResource[1],
&dwBufSize);
}
return dwErr == NO_ERROR ? TRUE : FALSE;
#else
///////////////////////////////////////////////////////
UINT err;
BOOL fOkPressed = FALSE;
err = I_SystemFocusDialog(GetForegroundWindow(),
// FOCUSDLG_BROWSE_LOGON_DOMAIN |
// FOCUSDLG_BROWSE_WKSTA_DOMAIN,
0x30003,
szMachine,
128,
&fOkPressed,
TEXT("dcomcnfg.hlp"),
IDH_SELECT_DOMAIN);
if (err == ERROR_SUCCESS && fOkPressed)
{
return TRUE;
}
else
{
return FALSE;
}
#endif
}
int CUtility::StringFromGUID(GUID &rguid, TCHAR *lpsz, int cbMax)
{
int i;
LPTSTR p = lpsz;
const BYTE * pBytes = (const BYTE *) &rguid;
*p++ = L'{';
for (i = 0; i < sizeof(GuidMap); i++)
{
if (GuidMap[i] == '-')
{
*p++ = L'-';
}
else
{
*p++ = szDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
*p++ = szDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
}
}
*p++ = L'}';
*p = L'\0';
return GUIDSTR_MAX;
}
BOOL CUtility::IsEqualGuid(GUID &guid1, GUID &guid2)
{
return (
((PLONG) &guid1)[0] == ((PLONG) &guid2)[0] &&
((PLONG) &guid1)[1] == ((PLONG) &guid2)[1] &&
((PLONG) &guid1)[2] == ((PLONG) &guid2)[2] &&
((PLONG) &guid1)[3] == ((PLONG) &guid2)[3]);
}
BOOL CUtility::AdjustPrivilege(TCHAR *szPrivilege)
{
HANDLE hProcessToken = 0;
BOOL bOK = FALSE;
TOKEN_PRIVILEGES privileges;
if( !OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hProcessToken ) )
{
return FALSE;
}
privileges.PrivilegeCount = 1;
privileges.Privileges[ 0 ].Attributes = SE_PRIVILEGE_ENABLED;
if( !LookupPrivilegeValue(NULL, szPrivilege,
&privileges.Privileges[ 0 ].Luid ) )
{
return FALSE;
}
if( !AdjustTokenPrivileges( hProcessToken, FALSE,
&privileges,
0L, NULL, NULL ) )
{
return FALSE;
}
if( hProcessToken )
{
CloseHandle( hProcessToken );
}
return TRUE;
}
BOOL CUtility::VerifyRemoteMachine(TCHAR *szRemoteMachine)
{
NETRESOURCE sResource;
NETRESOURCE sResource2;
DWORD dwErr;
HANDLE hEnum;
DWORD cbEntries;
DWORD cbBfr;
// TODO: Get this function to work. Right now WNetEnumResource is
// screwing up the stack, causing an AV and anyway returns the error
// ERROR_NO_MORE_ITEMS which I don't understand.
//
// Also, it is not clear that we should verify the remote machine name.
// It may have different formats, e.g. IP address or a URL specification.
// It may not even be on an NT network. In any case it may be offline
// currently.
return TRUE;
sResource.dwScope = RESOURCE_GLOBALNET;
sResource.dwType = RESOURCETYPE_ANY;
sResource.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
sResource.dwUsage = RESOURCEUSAGE_CONTAINER;
sResource.lpLocalName = NULL;
sResource.lpRemoteName = szRemoteMachine;
sResource.lpComment = NULL;
sResource.lpProvider = NULL;
dwErr = WNetOpenEnum(RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
RESOURCEUSAGE_CONTAINER,
&sResource,
&hEnum);
if (dwErr == NO_ERROR)
{
cbEntries = 1;
cbBfr = sizeof(NETRESOURCE);
dwErr = WNetEnumResource(hEnum, &cbEntries, &sResource2, &cbBfr);
}
CloseHandle(hEnum);
return TRUE;
}
BOOL CUtility::RetrieveUserPassword(TCHAR *szAppid, CString &sPassword)
{
#ifdef UNICODE
LSA_OBJECT_ATTRIBUTES sObjAttributes;
HANDLE hPolicy = NULL;
LSA_UNICODE_STRING sKey;
PLSA_UNICODE_STRING psPassword;
TCHAR szKey[4 + GUIDSTR_MAX + 1];
// Formulate the access key
_tcscpy(szKey, TEXT("SCM:"));
_tcscat(szKey, szAppid);
// UNICODE_STRING length fields are in bytes and include the NULL
// terminator
sKey.Length = (_tcslen(szKey) + 1) * sizeof(WCHAR);
sKey.MaximumLength = (GUIDSTR_MAX + 5) * sizeof(WCHAR);
sKey.Buffer = szKey;
// Open the local security policy
InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
if (!NT_SUCCESS(LsaOpenPolicy(NULL, &sObjAttributes,
POLICY_GET_PRIVATE_INFORMATION, &hPolicy)))
{
return FALSE;
}
// Read the user's password
if (!NT_SUCCESS(LsaRetrievePrivateData(hPolicy, &sKey, &psPassword)))
{
LsaClose(hPolicy);
return FALSE;
}
// Close the policy handle, we're done with it now.
LsaClose(hPolicy);
// Copy the password
sPassword = psPassword->Buffer;
#endif
return TRUE;
}
BOOL CUtility::StoreUserPassword(TCHAR *szAppid, CString &szPassword)
{
#ifdef UNICODE
LSA_OBJECT_ATTRIBUTES sObjAttributes;
HANDLE hPolicy = NULL;
LSA_UNICODE_STRING sKey;
LSA_UNICODE_STRING sPassword;
TCHAR szKey[4 + GUIDSTR_MAX + 1];
// Formulate the access key
_tcscpy(szKey, TEXT("SCM:"));
_tcscat(szKey, szAppid);
// UNICODE_STRING length fields are in bytes and include the NULL
// terminator
sKey.Length = (_tcslen(szKey) + 1) * sizeof(WCHAR);
sKey.MaximumLength = (GUIDSTR_MAX + 5) * sizeof(WCHAR);
sKey.Buffer = szKey;
// Make the password a UNICODE string
sPassword.Length = (_tcslen(LPCTSTR(szPassword)) + 1) * sizeof(WCHAR);
sPassword.Buffer = (TCHAR *) LPCTSTR(szPassword);
sPassword.MaximumLength = sPassword.Length;
// Open the local security policy
InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
if (!NT_SUCCESS(LsaOpenPolicy(NULL, &sObjAttributes,
POLICY_CREATE_SECRET, &hPolicy)))
{
return FALSE;
}
// Store the user's password
if (!NT_SUCCESS(LsaStorePrivateData(hPolicy, &sKey, &sPassword)))
{
g_util.PostErrorMessage();
LsaClose(hPolicy);
return FALSE;
}
// Close the policy handle, we're done with it now.
LsaClose(hPolicy);
#endif
return TRUE;
}
BOOL CUtility::LookupProcessInfo(SID **ppSid, TCHAR **ppszPrincName)
{
BYTE aMemory[SIZEOF_TOKEN_USER];
TOKEN_USER *pTokenUser = (TOKEN_USER *) &aMemory;
HANDLE hToken = NULL;
DWORD lIgnore;
DWORD lSidLen;
DWORD lNameLen = 0;
DWORD lDomainLen = 0;
TCHAR *pDomainName = NULL;
SID_NAME_USE sIgnore;
if (ppszPrincName != NULL)
*ppszPrincName = NULL;
// Open the process's token.
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
// Lookup SID of process token.
if (GetTokenInformation( hToken, TokenUser, pTokenUser,
sizeof(aMemory), &lIgnore ))
{
// Allocate memory to hold the SID.
lSidLen = GetLengthSid( pTokenUser->User.Sid );
*ppSid = (SID *) new BYTE[lSidLen];
if (*ppSid == NULL)
{
return FALSE;
}
memcpy(*ppSid, pTokenUser->User.Sid, lSidLen);
// Stop now if the caller doesn't want the user name.
if (ppszPrincName != NULL)
{
// Find out how much memory to allocate for the name.
LookupAccountSid(NULL, pTokenUser->User.Sid, NULL, &lNameLen,
NULL, &lDomainLen, NULL );
if (lNameLen != 0)
{
// Allocate memory for the user's name.
*ppszPrincName =
(TCHAR *) new BYTE[lNameLen*sizeof(TCHAR)];
if (ppszPrincName == NULL)
{
CloseHandle( hToken );
return FALSE;
}
pDomainName = (TCHAR *) new BYTE[lDomainLen*sizeof(TCHAR)];
if (pDomainName == NULL)
{
delete ppszPrincName;
CloseHandle( hToken );
return FALSE;
}
// Find the user's name.
if (!LookupAccountSid( NULL, pTokenUser->User.Sid,
*ppszPrincName, &lNameLen,
pDomainName,
&lDomainLen, &sIgnore))
{
delete ppszPrincName;
delete pDomainName;
CloseHandle( hToken );
return FALSE;
}
}
delete ppszPrincName;
delete pDomainName;
}
}
CloseHandle( hToken );
}
return TRUE;
}
BOOL CUtility::MakeSecDesc(SID *pSid, SECURITY_DESCRIPTOR **ppSD)
{
ACL *pAcl;
DWORD lSidLen;
SID *pGroup;
SID *pOwner;
// In case we fail
*ppSD = NULL;
// Allocate the security descriptor.
lSidLen = GetLengthSid( pSid );
*ppSD = (SECURITY_DESCRIPTOR *) new BYTE[
sizeof(SECURITY_DESCRIPTOR) + 2*lSidLen + SIZEOF_ACL];
if (*ppSD == NULL)
{
return FALSE;
}
pGroup = (SID *) (*ppSD + 1);
pOwner = (SID *) (((BYTE *) pGroup) + lSidLen);
pAcl = (ACL *) (((BYTE *) pOwner) + lSidLen);
// Initialize a new security descriptor.
if (!InitializeSecurityDescriptor(*ppSD, SECURITY_DESCRIPTOR_REVISION))
{
delete *ppSD;
return FALSE;
}
// Initialize a new ACL.
if (!InitializeAcl(pAcl, SIZEOF_ACL, ACL_REVISION2))
{
delete *ppSD;
return FALSE;
}
// Comment out this code because the only time we create a default SD is
// when attempting to edit
// \\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLE.DefaultAccessPermission
// which we want to start with 0 ACE's
/*
// Allow the current user access.
if (!AddAccessAllowedAce( pAcl, ACL_REVISION2, COM_RIGHTS_EXECUTE, pSid ))
{
delete *ppSD;
return FALSE;
}
// Allow local system access.
if (!AddAccessAllowedAce( pAcl, ACL_REVISION2, COM_RIGHTS_EXECUTE,
(void *) &LOCAL_SYSTEM_SID ))
{
delete *ppSD;
return FALSE;
}
*/
// Add a new ACL to the security descriptor.
if (!SetSecurityDescriptorDacl( *ppSD, TRUE, pAcl, FALSE ))
{
delete *ppSD;
return FALSE;
}
// Set the group.
memcpy( pGroup, pSid, lSidLen );
if (!SetSecurityDescriptorGroup( *ppSD, pGroup, FALSE ))
{
delete *ppSD;
return FALSE;
}
// Set the owner.
memcpy( pOwner, pSid, lSidLen );
if (!SetSecurityDescriptorOwner( *ppSD, pOwner, FALSE ))
{
delete *ppSD;
return FALSE;
}
// Check the security descriptor.
assert(IsValidSecurityDescriptor(*ppSD));
return TRUE;
}
BOOL CUtility::CheckSDForCOM_RIGHTS_EXECUTE(SECURITY_DESCRIPTOR *pSD)
{
PSrSecurityDescriptor pSrSD = (PSrSecurityDescriptor) pSD;
PSrAcl pDacl;
PSrAce pAce;
DWORD cbAces;
// Check whether the security descriptor is self-relative
if (pSrSD->Dacl > 0x1000)
{
pDacl = (PSrAcl) pSrSD->Dacl;
// Check for a deny ALL
if (pDacl == NULL)
{
return TRUE;
}
}
else
{
// First check for a deny ALL
if (pSrSD->Dacl == 0)
{
return TRUE;
}
pDacl = (PSrAcl) (((BYTE *) pSrSD) + (pSrSD->Dacl));
}
// Do over the ACE's
for (pAce = (PSrAce) (((BYTE *) pDacl) + sizeof(SSrAcl)),
cbAces = pDacl->AceCount;
cbAces;
pAce = (PSrAce) (((BYTE *) pAce) + pAce->AceSize),
cbAces--)
{
// Check that it is
// a) an allow on COM_RIGHTS_EXECUTE
// b) a deny on GENERIC_ALL,
// c) a deny on COM_RIGHTS_EXECUTE,
// d) a deny ALL (handled above if the DACL is NULL) or
// e) an allow everyone (handled implicitly if cbAces == 0)
if (!(((pAce->Type == 0 && pAce->AccessMask == COM_RIGHTS_EXECUTE)
||
(pAce->Type == 1 && pAce->AccessMask == GENERIC_ALL)
||
(pAce->Type == 1 && pAce->AccessMask == COM_RIGHTS_EXECUTE))))
{
CString szText;
CString szTitle;
szText.LoadString(IDS_The_security_);
szTitle.LoadString(IDS_DCOM_Configuration_Warning);
if (MessageBox(GetForegroundWindow(),
(LPCTSTR) szText,
(LPCTSTR) szTitle,
MB_YESNO) == IDYES)
{
pAce->Flags = 0;
pAce->Type = 0;
pAce->AccessMask = COM_RIGHTS_EXECUTE;
}
else
{
return FALSE;
}
}
}
return TRUE;
}
BOOL CUtility::ChangeService(const TCHAR *szService,
const TCHAR *szIdentity,
const TCHAR *szPassword,
const TCHAR *szDisplay)
{
SC_HANDLE hSCManager;
SC_HANDLE hService;
// Open the service control manager
if (hSCManager = OpenSCManager(NULL, NULL, GENERIC_READ | GENERIC_WRITE))
{
// Try to open a handle to the requested service
if (!(hService = OpenService(hSCManager,
szService,
GENERIC_READ | GENERIC_WRITE)))
{
g_util.PostErrorMessage();
CloseServiceHandle(hSCManager);
return FALSE;
}
// Close the service manager's database
CloseServiceHandle(hSCManager);
// Change service identity parameters
if (ChangeServiceConfig(hService,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
szIdentity,
szPassword,
szDisplay))
{
// Return success
CloseServiceHandle(hService);
return TRUE;
}
else
{
g_util.PostErrorMessage();
CloseServiceHandle(hService);
return FALSE;
}
}
else
{
g_util.PostErrorMessage();
return FALSE;
}
}
BOOL CUtility::UpdateDCOMInfo(void)
{
RPC_STATUS status;
#ifdef UNICODE
TCHAR *pszBindString;
#else
unsigned char * pszBindString;
#endif
// Get a binding handle to the SCM if we haven't yet
if (m_hRpc == NULL)
{
#ifdef UNICODE
status = RpcStringBindingCompose(NULL,
TEXT("ncalrpc"),
NULL,
TEXT("epmapper"),
NULL,
&pszBindString);
#else
status = RpcStringBindingCompose(NULL,
(unsigned char *)"ncalrpc",
NULL,
(unsigned char *)"epmapper",
NULL,
&pszBindString);
#endif
if (status != RPC_S_OK)
{
return status;
}
status = RpcBindingFromStringBinding(pszBindString, &m_hRpc);
RpcStringFree(&pszBindString);
if (status != ERROR_SUCCESS)
{
return status;
}
}
// Call over to the SCM to get the global registry values read
// into memory
UpdateActivationSettings(m_hRpc, &status);
return status;
}
LRESULT CALLBACK ControlFixProc( HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
// This is a work-around because there is a bug in msdev 4.1: Cannot get
// WM_HELP message processed by a control on which DDX_Control data exchange
// is done because of subclassing problem. See msdn Q145865 for a discussion
// plus work-around code.
void CUtility::FixHelp(CWnd* pWnd)
{
// search all child windows. If their window proc
// is AfxWndProc, then subclass with our window proc
CWnd* pWndChild = pWnd->GetWindow(GW_CHILD);
while(pWndChild != NULL)
{
if (GetWindowLong(pWndChild->GetSafeHwnd(),
GWL_WNDPROC) == (LONG)AfxWndProc)
{
SetWindowLong(pWndChild->GetSafeHwnd(), GWL_WNDPROC,
(LONG)ControlFixProc);
}
pWndChild = pWndChild->GetWindow(GW_HWNDNEXT);
}
}
LRESULT CALLBACK ControlFixProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_HELP)
{
// bypass MFC's handler, message will be sent to parent
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return AfxWndProc(hwnd,uMsg,wParam,lParam);
}
// Compare two security descriptors in self-relative form to
// determine if they're the same
BOOL CUtility::CompareSDs(PSrSecurityDescriptor pSD1,
PSrSecurityDescriptor pSD2)
{
PSID pSid1, pSid2;
PSrAcl pDacl1, pDacl2;
PSrAce pAce1, pAce2;
BYTE *p1, *p2;
// Compare the owners
pSid1 = (PSID) (((BYTE *) pSD1) + pSD1->Owner);
pSid2 = (PSID) (((BYTE *) pSD2) + pSD2->Owner);
if (!EqualSid(pSid1, pSid2))
{
return FALSE;
}
// Compare the groups
pSid1 = (PSID) (((BYTE *) pSD1) + pSD1->Group);
pSid2 = (PSID) (((BYTE *) pSD2) + pSD2->Group);
if (!EqualSid(pSid1, pSid2))
{
return FALSE;
}
// Compare the DACL's
pDacl1 = (PSrAcl) (((BYTE *) pSD1) + pSD1->Dacl);
pDacl2 = (PSrAcl) (((BYTE *) pSD2) + pSD2->Dacl);
// Check first that they are the same size and have the same
// number of ACE's
if (! (pDacl1->AclSize == pDacl2->AclSize &&
pDacl1->AceCount == pDacl2->AceCount))
{
return FALSE;
}
// Now compare the ACL ACE by ACE
pAce1 = (PSrAce) (((BYTE *) pDacl1) + sizeof(SSrAcl));
pAce2 = (PSrAce) (((BYTE *) pDacl2) + sizeof(SSrAcl));
for (int k = 0; k < pDacl1->AceCount; k++)
{
// Check the ACE headers
if (! (pAce1->Type == pAce2->Type &&
pAce1->AceSize == pAce2->AceSize &&
pAce1->AccessMask == pAce2->AccessMask))
{
return FALSE;
}
// Check the SID's
p1 = (BYTE *) (((BYTE *) pAce1) + sizeof(ACE_HEADER));
p2 = (BYTE *) (((BYTE *) pAce2) + sizeof(ACE_HEADER));
for (ULONG j = 0; j < pAce1->AceSize - sizeof(ACE_HEADER); j++)
{
if (p1[j] != p2[j])
{
return FALSE;
}
}
// Go to the next ACE
pAce1 = (PSrAce) (((BYTE *) pAce1) + pAce1->AceSize);
pAce2 = (PSrAce) (((BYTE *) pAce2) + pAce2->AceSize);
}
return TRUE;
}
int CUtility::SetAccountRights(const TCHAR *szUser, TCHAR *szPrivilege)
{
#if UNICODE
int err;
LSA_HANDLE hPolicy;
LSA_OBJECT_ATTRIBUTES objAtt;
DWORD cbSid = 1;
TCHAR szDomain[128];
DWORD cbDomain = 128;
PSID pSid = NULL;
SID_NAME_USE snu;
LSA_UNICODE_STRING privStr;
// Get a policy handle
memset(&objAtt, 0, sizeof(LSA_OBJECT_ATTRIBUTES));
if (!NT_SUCCESS(LsaOpenPolicy(NULL,
&objAtt,
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
&hPolicy)))
{
return GetLastError();
}
// Fetch the SID for the specified user
LookupAccountName(NULL, szUser, pSid, &cbSid, szDomain, &cbDomain, &snu);
if ((err = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
{
LsaClose(hPolicy);
return err;
}
pSid = new BYTE[cbSid];
if (pSid == NULL)
{
LsaClose(hPolicy);
return ERROR_OUTOFMEMORY;
}
if (!LookupAccountName(NULL, szUser, pSid, &cbSid,
szDomain, &cbDomain, &snu))
{
LsaClose(hPolicy);
return GetLastError();
}
// Set the specified privilege on this account
privStr.Length = _tcslen(szPrivilege) * sizeof(WCHAR);
privStr.MaximumLength = privStr.Length + sizeof(WCHAR);
privStr.Buffer = szPrivilege;
if (!NT_SUCCESS(LsaAddAccountRights(hPolicy, pSid, &privStr, 1)))
{
LsaClose(hPolicy);
return GetLastError();
}
// We're done
delete pSid;
LsaClose(hPolicy);
#endif
return ERROR_SUCCESS;
}
// This method is included only because in the debug version when using
// MFC they validate the C++ heap, whereas RtlCopySecurityDescriptor uses
// the standard process heap, causing MFC to throw a breakpoint
void CUtility::CopySD(SECURITY_DESCRIPTOR *pSrc, SECURITY_DESCRIPTOR **pDest)
{
ULONG cbLen;
SECURITY_DESCRIPTOR *pSD;
#if 0
cbLen = RtlLengthSecurityDescriptor(pSrc);
#else
cbLen = 10;
#endif
pSD = (SECURITY_DESCRIPTOR *) new BYTE[cbLen];
*pDest = pSD;
if (pSD)
{
memcpy(pSD, pSrc, cbLen);
}
}
// Set the inheritance flags on a security descriptor so keys created
// under the key having this security descriptor will inherit all its
// ACE's. We do this as a utility routine rather than via the ACL
// editor because doing that adds check boxes and such to the ACL editor,
// so it's cleaner this way.
//
// Note. The security descriptor is expected to be in absolute form
void CUtility::SetInheritanceFlags(SECURITY_DESCRIPTOR *pSec)
{
PSrAcl pAcl = (PSrAcl) pSec->Dacl;
PSrAce pAce;
int k;
// Do over the ACE's this DACL
for (k = pAcl->AceCount, pAce = (PSrAce) (((BYTE *) pAcl) + sizeof(SSrAcl));
k;
k--, pAce = (PSrAce) (((BYTE *) pAce) + pAce->AceSize))
{
pAce->Flags |= CONTAINER_INHERIT_ACE;
}
}