//+--------------------------------------------------------------------- // // 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 } #include "util.h" #include "virtreg.h" extern "C" { #include #include #include #include #include #include #include } 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; } }