//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 2000-2002. // // File: SaferUtil.cpp // // Contents: Utility methods for Software Restriction Policies extension // //---------------------------------------------------------------------------- #include "stdafx.h" #include #include #include #include #include "SaferUtil.h" #include "SaferEntry.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern HKEY g_hkeyLastSaferRegistryScope; bool g_bIsComputer = false; extern GUID g_guidExtension; extern GUID g_guidRegExt; extern GUID g_guidSnapin; void InitializeSecurityLevelComboBox ( CComboBox& comboBox, bool bLimit, DWORD dwLevelID, HKEY hGroupPolicyKey, DWORD* pdwSaferLevels, bool bIsComputer) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if ( !hGroupPolicyKey ) // is RSOP { CString szText = SaferGetLevelFriendlyName (dwLevelID, hGroupPolicyKey, bIsComputer); int nItem = comboBox.AddString (szText); ASSERT (nItem >= 0); if ( nItem >= 0 ) { VERIFY (CB_ERR != comboBox.SetItemData (nItem, dwLevelID)); VERIFY (CB_ERR != comboBox.SetCurSel (nItem)); } return; } if ( pdwSaferLevels ) { for (UINT nIndex = 0; NO_MORE_SAFER_LEVELS != pdwSaferLevels[nIndex]; nIndex++) { CString szText; int nItem = 0; switch (pdwSaferLevels[nIndex]) { case SAFER_LEVELID_FULLYTRUSTED: szText = SaferGetLevelFriendlyName (pdwSaferLevels[nIndex], hGroupPolicyKey, bIsComputer); nItem = comboBox.AddString (szText); ASSERT (nItem >= 0); if ( nItem >= 0 ) { VERIFY (CB_ERR != comboBox.SetItemData (nItem, pdwSaferLevels[nIndex])); if ( pdwSaferLevels[nIndex] == dwLevelID || AUTHZ_UNKNOWN_LEVEL == dwLevelID) VERIFY (CB_ERR != comboBox.SetCurSel (nItem)); } break; case SAFER_LEVELID_CONSTRAINED: if ( !bLimit ) { szText = SaferGetLevelFriendlyName (pdwSaferLevels[nIndex], hGroupPolicyKey, bIsComputer); nItem = comboBox.AddString (szText); ASSERT (nItem >= 0); if ( nItem >= 0 ) { VERIFY (CB_ERR != comboBox.SetItemData (nItem, pdwSaferLevels[nIndex])); if ( pdwSaferLevels[nIndex] == dwLevelID ) VERIFY (CB_ERR != comboBox.SetCurSel (nItem)); } } break; case SAFER_LEVELID_DISALLOWED: szText = SaferGetLevelFriendlyName (pdwSaferLevels[nIndex], hGroupPolicyKey, bIsComputer); nItem = comboBox.AddString (szText); ASSERT (nItem >= 0); if ( nItem >= 0 ) { VERIFY (CB_ERR != comboBox.SetItemData (nItem, pdwSaferLevels[nIndex])); if ( pdwSaferLevels[nIndex] == dwLevelID ) VERIFY (CB_ERR != comboBox.SetCurSel (nItem)); } break; case SAFER_LEVELID_NORMALUSER: case SAFER_LEVELID_UNTRUSTED: if ( !bLimit ) { if ( hGroupPolicyKey ) { szText = SaferGetLevelFriendlyName (pdwSaferLevels[nIndex], hGroupPolicyKey, bIsComputer); nItem = comboBox.AddString (szText); ASSERT (nItem >= 0); if ( nItem >= 0 ) { VERIFY (CB_ERR != comboBox.SetItemData (nItem, pdwSaferLevels[nIndex])); if ( pdwSaferLevels[nIndex] == dwLevelID ) VERIFY (CB_ERR != comboBox.SetCurSel (nItem)); } } } break; default: ASSERT (0); break; } } } } class CLevelPair { public: CLevelPair () : m_dwLevelID ((DWORD) -1) { } virtual ~CLevelPair () {} DWORD m_dwLevelID; CString m_szLevelName; }; CString SaferGetLevelFriendlyName (DWORD dwLevelID, HKEY hGroupPolicyKey, const bool bIsComputer) { CString szLevelName; SAFER_LEVEL_HANDLE hLevel = 0; BOOL bRVal = FALSE; const int NUM_LEVEL_PAIRS = 10; static CLevelPair levelPairs[NUM_LEVEL_PAIRS]; for (int nLevelIndex = 0; nLevelIndex < NUM_LEVEL_PAIRS; nLevelIndex++) { if ( -1 == levelPairs[nLevelIndex].m_dwLevelID ) break; else if ( dwLevelID == levelPairs[nLevelIndex].m_dwLevelID ) { return levelPairs[nLevelIndex].m_szLevelName; } } if ( hGroupPolicyKey ) { if ( !g_hkeyLastSaferRegistryScope ) SetRegistryScope (hGroupPolicyKey, bIsComputer); bRVal = SaferCreateLevel (SAFER_SCOPEID_REGISTRY, dwLevelID, SAFER_LEVEL_OPEN, &hLevel, hGroupPolicyKey); } else { bRVal = SaferCreateLevel (SAFER_SCOPEID_MACHINE, dwLevelID, SAFER_LEVEL_OPEN, &hLevel, 0); } if ( bRVal ) { DWORD dwBufferSize = 0; DWORD dwErr = 0; bRVal = SaferGetLevelInformation(hLevel, SaferObjectFriendlyName, 0, dwBufferSize, &dwBufferSize); if ( !bRVal && ERROR_INSUFFICIENT_BUFFER == GetLastError () ) { PWSTR pszLevelName = (PWSTR) LocalAlloc (LPTR, dwBufferSize); if ( pszLevelName ) { bRVal = SaferGetLevelInformation(hLevel, SaferObjectFriendlyName, pszLevelName, dwBufferSize, &dwBufferSize); ASSERT (bRVal); if ( bRVal ) { szLevelName = pszLevelName; } else { dwErr = GetLastError (); _TRACE (0, L"SaferGetLevelInformation(SaferObjectFriendlyName) failed: %d\n", dwErr); } LocalFree (pszLevelName); } } else if ( !bRVal ) { dwErr = GetLastError (); _TRACE (0, L"SaferGetLevelInformation(SaferObjectFriendlyName) failed: %d\n", dwErr); } VERIFY (SaferCloseLevel (hLevel)); } else { DWORD dwErr = GetLastError (); _TRACE (0, L"SaferCloseLevel (SAFER_SCOPEID_REGISTRY, 0x%x, SAFER_LEVEL_OPEN) failed: %d\n", dwLevelID, dwErr); } if ( nLevelIndex < NUM_LEVEL_PAIRS && !szLevelName.IsEmpty () ) { levelPairs[nLevelIndex].m_dwLevelID = dwLevelID; levelPairs[nLevelIndex].m_szLevelName = szLevelName; } return szLevelName; } CString SaferGetLevelDescription (DWORD dwLevelID, HKEY hGroupPolicyKey, const bool bIsComputer) { CString szDescription; SAFER_LEVEL_HANDLE hLevel = 0; BOOL bRVal = FALSE; if ( hGroupPolicyKey ) { if ( !g_hkeyLastSaferRegistryScope ) SetRegistryScope (hGroupPolicyKey, bIsComputer); bRVal = SaferCreateLevel (SAFER_SCOPEID_REGISTRY, dwLevelID, SAFER_LEVEL_OPEN, &hLevel, hGroupPolicyKey); } else { if ( g_hkeyLastSaferRegistryScope ) SetRegistryScope (0, bIsComputer); bRVal = SaferCreateLevel (SAFER_SCOPEID_MACHINE, dwLevelID, SAFER_LEVEL_OPEN, &hLevel, 0); } ASSERT (bRVal); if ( bRVal ) { DWORD dwBufferSize = 0; DWORD dwErr = 0; bRVal = SaferGetLevelInformation(hLevel, SaferObjectDescription, 0, dwBufferSize, &dwBufferSize); if ( !bRVal && ERROR_INSUFFICIENT_BUFFER == GetLastError () ) { PWSTR pszDescription = (PWSTR) LocalAlloc (LPTR, dwBufferSize); if ( pszDescription ) { bRVal = SaferGetLevelInformation(hLevel, SaferObjectDescription, pszDescription, dwBufferSize, &dwBufferSize); ASSERT (bRVal); if ( bRVal ) { szDescription = pszDescription; } else { dwErr = GetLastError (); _TRACE (0, L"SaferGetLevelInformation(SaferObjectFriendlyName) failed: %d\n", dwErr); } LocalFree (pszDescription); } } else if ( !bRVal ) { dwErr = GetLastError (); _TRACE (0, L"SaferGetLevelInformation(SaferObjectFriendlyName) failed: %d\n", dwErr); } if ( ERROR_NOT_FOUND == dwErr || szDescription.IsEmpty () ) { VERIFY (szDescription.LoadString (IDS_NOT_AVAILABLE)); } VERIFY (SaferCloseLevel (hLevel)); } else { DWORD dwErr = GetLastError (); _TRACE (0, L"SaferCreateLevel (%s, 0x%x, SAFER_LEVEL_OPEN) failed: %d\n", hGroupPolicyKey ? L"SAFER_SCOPEID_REGISTRY" : L"SAFER_SCOPEID_MACHINE", dwLevelID, dwErr); } return szDescription; } HRESULT SaferGetLevelID (SAFER_LEVEL_HANDLE hLevel, DWORD& dwLevelID) { ASSERT (0 != g_hkeyLastSaferRegistryScope); DWORD dwBufferSize = sizeof (DWORD); HRESULT hr = S_OK; BOOL bRVal = SaferGetLevelInformation(hLevel, SaferObjectLevelId, &dwLevelID, dwBufferSize, &dwBufferSize); ASSERT (bRVal); if ( !bRVal ) { DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"SaferGetLevelInformation(SaferObjectLevelId) failed: %d\n", dwErr); } return hr; } CSaferEntries::CSaferEntries( bool bIsMachine, PCWSTR pszMachineName, PCWSTR pszObjectName, IGPEInformation* pGPEInformation, IRSOPInformation* pRSOPInformation, CRSOPObjectArray& rsopObjectArray, LPCONSOLE pConsole) : CCertMgrCookie (bIsMachine ? CERTMGR_SAFER_COMPUTER_ENTRIES : CERTMGR_SAFER_USER_ENTRIES, pszMachineName, pszObjectName), m_pTrustedPublishersStore (0), m_pDisallowedStore (0) { if ( pGPEInformation ) { m_pTrustedPublishersStore = new CCertStoreSafer ( CERT_SYSTEM_STORE_RELOCATE_FLAG, L"", SAFER_TRUSTED_PUBLISHER_STORE_FRIENDLY_NAME, SAFER_TRUSTED_PUBLISHER_STORE_NAME, L"", pGPEInformation, bIsMachine ? NODEID_Machine : NODEID_User, pConsole); m_pDisallowedStore = new CCertStoreSafer ( CERT_SYSTEM_STORE_RELOCATE_FLAG, L"", SAFER_DISALLOWED_STORE_FRIENDLY_NAME, SAFER_DISALLOWED_STORE_NAME, L"", pGPEInformation, bIsMachine ? NODEID_Machine : NODEID_User, pConsole); } else if ( pRSOPInformation ) { m_pTrustedPublishersStore = new CCertStoreRSOP ( CERT_SYSTEM_STORE_RELOCATE_FLAG, L"", SAFER_TRUSTED_PUBLISHER_STORE_FRIENDLY_NAME, SAFER_TRUSTED_PUBLISHER_STORE_NAME, L"", rsopObjectArray, bIsMachine ? NODEID_Machine : NODEID_User, pConsole); m_pDisallowedStore = new CCertStoreRSOP ( CERT_SYSTEM_STORE_RELOCATE_FLAG, L"", SAFER_DISALLOWED_STORE_FRIENDLY_NAME, SAFER_DISALLOWED_STORE_NAME, L"", rsopObjectArray, bIsMachine ? NODEID_Machine : NODEID_User, pConsole); } } CSaferEntries::~CSaferEntries () { if ( m_pTrustedPublishersStore ) { m_pTrustedPublishersStore->Release (); m_pTrustedPublishersStore = 0; } if ( m_pDisallowedStore ) { m_pDisallowedStore->Release (); m_pDisallowedStore = 0; } } HRESULT CSaferEntries::GetTrustedPublishersStore(CCertStore **ppStore) { if ( !ppStore ) return E_POINTER; if ( m_pTrustedPublishersStore ) { m_pTrustedPublishersStore->AddRef (); *ppStore = m_pTrustedPublishersStore; } else return E_FAIL; return S_OK; } HRESULT CSaferEntries::GetDisallowedStore(CCertStore **ppStore) { if ( !ppStore ) return E_POINTER; if ( m_pDisallowedStore ) { m_pDisallowedStore->AddRef (); *ppStore = m_pDisallowedStore; } else return E_FAIL; return S_OK; } HRESULT SetRegistryScope (HKEY hKey, bool bIsComputer) { HRESULT hr = S_OK; if ( g_hkeyLastSaferRegistryScope != hKey || g_bIsComputer != bIsComputer ) { BOOL bRVal = SaferiChangeRegistryScope (hKey, REG_OPTION_NON_VOLATILE); ASSERT (bRVal); if ( bRVal ) { g_hkeyLastSaferRegistryScope = hKey; g_bIsComputer = bIsComputer; } else { DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"SaferiChangeRegistryScope (%s) failed: %d\n", hKey ? L"hKey" : L"0", dwErr); } } return hr; } /////////////////////////////////////////////////////////////////////////////// // Returns S_OK if the file has a valid signed hash HRESULT GetSignedFileHash( IN LPCWSTR pwszFilename, OUT BYTE rgbFileHash[SAFER_MAX_HASH_SIZE], OUT DWORD *pcbFileHash, OUT ALG_ID *pHashAlgid ) { HRESULT hr = S_OK; if ( !pwszFilename || !rgbFileHash || !pcbFileHash || !pHashAlgid ) return E_POINTER; _TRACE (1, L"Entering GetSignedFileHash (%s)\n", pwszFilename); // Returns S_OK and the hash if the file was signed and contains a valid // hash *pcbFileHash = SAFER_MAX_HASH_SIZE; hr = WTHelperGetFileHash( pwszFilename, 0, NULL, rgbFileHash, pcbFileHash, pHashAlgid); if ( FAILED (hr) ) { _TRACE (0, L"WTHelperGetFileHash (%s) failed: 0x%x\n", pwszFilename, hr); } _TRACE (-1, L"Leaving GetSignedFileHash (%s): 0x%x\n", pwszFilename, hr); return hr; } HRESULT ComputeMD5Hash(IN HANDLE hFile, BYTE hashResult[SAFER_MAX_HASH_SIZE], DWORD& dwHashSize) /*++ Routine Description: Computes the MD5 hash of a given file's contents and prints the resulting hash value to the screen. Arguments: szFilename - filename to compute hash of. Return Value: Returns 0 on success, or a non-zero exit code on failure. --*/ { _TRACE (1, L"Entering ComputeMD5Hash ()\n"); HRESULT hr = S_OK; ASSERT (hashResult); if ( !hashResult ) return E_POINTER; // // Open the specified file and map it into memory. // // security review 2/25/2002 BryanWal ok // NOTICE - hFile is from GetOpenFileName () HANDLE hMapping = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if ( hMapping ) { DWORD dwDataLen = GetFileSize (hFile, NULL); if ( -1 != dwDataLen ) { // security review 2/25/2002 BryanWal ok LPBYTE pbData = (LPBYTE) ::MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, dwDataLen); if ( pbData ) { // // Generate the hash value of the specified file. // HCRYPTPROV hProvider = 0; if ( CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_SIG, CRYPT_VERIFYCONTEXT) || CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ) { HCRYPTHASH hHash = 0; if ( CryptCreateHash(hProvider, CALG_MD5, 0, 0, &hHash) ) { if ( CryptHashData (hHash, pbData, dwDataLen, 0) ) { dwHashSize = SAFER_MAX_HASH_SIZE; if (!CryptGetHashParam(hHash, HP_HASHVAL, hashResult, &dwHashSize, 0)) { dwHashSize = 0; DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"CryptHashData () failed: 0x%x\n", hr); } } else { DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"CryptHashData () failed: 0x%x\n", hr); } CryptDestroyHash(hHash); } else { DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"CryptCreateHash () failed: 0x%x\n", hr); } CryptReleaseContext(hProvider, 0); } else { DWORD dwErr = GetLastError (); hr = HRESULT_FROM_WIN32 (dwErr); _TRACE (0, L"CryptAcquireContext () failed: 0x%x\n", hr); } ::UnmapViewOfFile(pbData); } else { DWORD dwErr = GetLastError (); _TRACE (0, L"MapViewOfFile () failed: 0x%x\n", dwErr); hr = HRESULT_FROM_WIN32 (dwErr); } } else { DWORD dwErr = GetLastError (); _TRACE (0, L"GetFileSize () failed: 0x%x\n", dwErr); hr = HRESULT_FROM_WIN32 (dwErr); } VERIFY (CloseHandle(hMapping)); hMapping = 0; } else { DWORD dwErr = GetLastError (); _TRACE (0, L"CreateFileMapping () failed: 0x%x\n", dwErr); hr = HRESULT_FROM_WIN32 (dwErr); } _TRACE (-1, L"Leaving ComputeMD5Hash (): 0x%x\n", hr); return hr; } CString GetURLZoneFriendlyName (DWORD dwURLZoneID) { CString szFriendlyName; switch (dwURLZoneID) { case URLZONE_LOCAL_MACHINE: VERIFY (szFriendlyName.LoadString (IDS_URLZONE_LOCAL_MACHINE)); break; case URLZONE_INTRANET: VERIFY (szFriendlyName.LoadString (IDS_URLZONE_INTRANET)); break; case URLZONE_TRUSTED: VERIFY (szFriendlyName.LoadString (IDS_URLZONE_TRUSTED)); break; case URLZONE_INTERNET: VERIFY (szFriendlyName.LoadString (IDS_URLZONE_INTERNET)); break; case URLZONE_UNTRUSTED: VERIFY (szFriendlyName.LoadString (IDS_URLZONE_UNTRUSTED)); break; default: ASSERT (0); VERIFY (szFriendlyName.LoadString (IDS_URLZONE_UNKNOWN)); break; } return szFriendlyName; } // // Given a GUID in string format it returns a GUID struct // // e.g. "{00299570-246d-11d0-a768-00aa006e0529}" to a struct form // BOOL GuidFromString(GUID* pGuid, const CString& szGuidString) { ASSERT (pGuid); if ( !pGuid ) return FALSE; // security review 2/25/2002 BryanWal ok ::ZeroMemory(pGuid, sizeof(GUID)); // security review 2/25/2002 BryanWal ok size_t nLen = wcslen (szGuidString); // the string length should be 38 if (nLen != 38) return FALSE; return SUCCEEDED(::CLSIDFromString ((LPOLESTR)((PCWSTR)szGuidString), pGuid)); } HRESULT SaferSetDefinedFileTypes ( HWND hWnd, HKEY hGroupPolicyKey, PCWSTR pszFileTypes, int nBufLen) { HRESULT hr = S_OK; DWORD dwDisposition = 0; HKEY hKey = 0; LONG lResult = ::RegCreateKeyEx (hGroupPolicyKey, // handle of an open key SAFER_COMPUTER_CODEIDS_REGKEY, // address of subkey name 0, // reserved L"", // address of class string REG_OPTION_NON_VOLATILE, // special options flag // security review 2/25/2002 BryanWal ok KEY_SET_VALUE, // desired security access NULL, // address of key security structure &hKey, // address of buffer for opened handle &dwDisposition); // address of disposition value buffer ASSERT (ERROR_SUCCESS == lResult); if ( ERROR_SUCCESS == lResult ) { lResult = ::RegSetValueEx ( hKey, // handle to key SAFER_EXETYPES_REGVALUE, // value name 0, // reserved REG_MULTI_SZ, // value type (PBYTE) pszFileTypes, // value data nBufLen); // size of value data if ( ERROR_SUCCESS != lResult ) { DisplaySystemError (hWnd, lResult); _TRACE (0, L"RegSetValueEx (SAFER_EXETYPES_REGVALUE, %s) failed: %d\n", pszFileTypes, lResult); hr = HRESULT_FROM_WIN32 (lResult); } RegCloseKey (hKey); } else { DisplaySystemError (hWnd, lResult); _TRACE (0, L"RegCreateKeyEx (SAFER_CODEID_KEY) failed: %d\n", lResult); hr = HRESULT_FROM_WIN32 (lResult); } return hr; }