|
|
// File: regzone.cxx
//
// Contents: Registry management for a single zone.
//
// Classes: CRegZone
//
// Functions:
//
// History:
//
//----------------------------------------------------------------------------
#include "zonepch.h"
// Max # of chars to the root of the zones tree (SZZONES, SZTEMPLATE,...)
#define MAX_REGZONE_ROOT 100
// Value names in the registry
#define SZZONEINDEX __TEXT("ZoneIndex")
#define SZTEMPLATEINDEX __TEXT("TemplateIndex")
#define SZDISPLAYNAME __TEXT("DisplayName")
#define SZICON __TEXT("Icon")
#define SZDESCRIPTION __TEXT("Description")
#define SZFLAGS __TEXT("Flags")
// Registry key names for the template policies
#define SZLOW __TEXT("Low")
#define SZMEDLOW __TEXT("MedLow")
#define SZMEDIUM __TEXT("Medium")
#define SZHIGH __TEXT("High")
CRegZone::CRegZoneCache CRegZone::s_rzcache; HANDLE CRegZone::CRegZoneCache::s_hMutexCounter;
// Array of Value Names corresponding to zone attributes.
// These values will not be copied when doing a mass copy
// from a template zone (HIGH, MED, LOW) to a zone.
static LPCTSTR rgszAttributeNames [ ] = { __TEXT(""), // The default value is excluded as well.
SZZONEINDEX, SZTEMPLATEINDEX, SZDISPLAYNAME, SZDESCRIPTION, SZICON, SZFLAGS, SZMINLEVEL, SZRECLEVEL, SZCURRLEVEL, };
struct templateNameIdxMap { URLTEMPLATE index; LPCTSTR pszName; };
static templateNameIdxMap TemplateNameIdxMap [ ] = { { URLTEMPLATE_LOW, SZLOW }, { URLTEMPLATE_MEDLOW, SZMEDLOW}, { URLTEMPLATE_MEDIUM, SZMEDIUM}, { URLTEMPLATE_HIGH, SZHIGH} };
// CRegZone implementation.
CRegZone::CRegZone() { // defaults
m_dwZoneId = ZONEID_INVALID; m_dwZoneFlags = ZAFLAGS_ADD_SITES; // BUGBUG: what is the right default here.
m_lpZoneName = NULL; m_lpZonePath = NULL;
m_bStandard = TRUE; m_bZoneLockOut = FALSE; m_bHKLMOnly = TRUE; }
CRegZone::~CRegZone() { LocalFree((HLOCAL)m_lpZoneName); LocalFree((HLOCAL)m_lpZonePath); }
// Sets up the CRegZone object a given string.
// If the setting is in the Zones key the string passed in is the actual
// zone index. Otherwise it is one of the "High", "Medium", "Low" strings which indicates
// a template policy.
BOOL CRegZone::Init(LPCWSTR lpwStr, BOOL bUseHKLMOnly, REGZONEUSE regZoneUse, BOOL bCreate /*=TRUE*/) { TransAssert(lpwStr != NULL); if (lpwStr == NULL) { return FALSE; }
m_bHKLMOnly = bUseHKLMOnly; m_regZoneUse = regZoneUse;
TCHAR szTemp[MAX_REGZONE_ROOT + MAX_ZONE_NAME];
StrCpyW(szTemp, (regZoneUse == REGZONEUSEZONES? SZZONES : SZTEMPLATE)); StrCatW(szTemp, lpwStr);
m_lpZonePath = StrDup(szTemp); if(!m_lpZonePath) { return FALSE; } m_lpZoneName = StrDup(lpwStr); if(!m_lpZoneName) { return FALSE; }
CRegKey regKey(bUseHKLMOnly);
if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return FALSE; }
// Add code here to
DWORD dwZoneId = ZONEID_INVALID;
// Get the Zone Index.
if ( regZoneUse == REGZONEUSEZONES ) { // The Zone Id for the string is the same as the key name.
// Just convert the string
m_dwZoneId = StrToInt(m_lpZoneName); } else if (regZoneUse == REGZONEUSETEMPLATE ) { if (regKey.QueryValue(&dwZoneId, SZTEMPLATEINDEX) == ERROR_SUCCESS) m_dwZoneId = dwZoneId; else { // Could happen if the registry is messed up.
TransAssert(FALSE); } } else { TransAssert(FALSE); }
// Get the zone flags
if (regKey.QueryValue(&m_dwZoneFlags, SZFLAGS) != ERROR_SUCCESS) { m_dwZoneFlags = ZAFLAGS_ADD_SITES; // What is the right value here.
} else { // return value from UpdateZoneMapFlags ignored.
UpdateZoneMapFlags( ); } // Check and make sure the zone Id's are within range.
// Assert that the zone ID's are in the appropriate user or standard range.
return TRUE; }
// This updates the flags in the ZoneMap part of the registry which correspond to the
// ZAFLAGS_. For convenience the UI will only update the ZAFLAGS.
BOOL CRegZone::UpdateZoneMapFlags( ) { // ProxyByPass is current controlled by the ProxyByPass flag, not the zoneAttrib.
if (m_dwZoneId == URLZONE_INTRANET) { // If we are updating zonemap flags we have to invalidate any url to zone caches
CSecurityManager::IncrementGlobalCounter( ); CRegKey regZoneMap; if (ERROR_SUCCESS == regZoneMap.Open(NULL, SZZONEMAP, KEY_READ | KEY_WRITE)) { if (m_dwZoneFlags & ZAFLAGS_INCLUDE_PROXY_OVERRIDE) { // We will succeed even if this fails.
regZoneMap.SetValue(m_dwZoneId, SZPROXYBYPASS); } else { regZoneMap.DeleteValue(SZPROXYBYPASS); }
if (m_dwZoneFlags & ZAFLAGS_INCLUDE_INTRANET_SITES) { // We will succeed even if this fails.
regZoneMap.SetValue(m_dwZoneId, SZINTRANETNAME); } else { regZoneMap.DeleteValue(SZINTRANETNAME); }
DWORD dwUncAsIntranet = (m_dwZoneFlags & ZAFLAGS_UNC_AS_INTRANET) ? 1 : 0 ; regZoneMap.SetValue(dwUncAsIntranet, SZUNCASINTRANET);
} } return TRUE; }
// Static functions.
VOID CRegZone::IncrementGlobalCounter( ) { CRegZone::CRegZoneCache::IncrementGlobalCounter( ); }
BOOL CRegZone::IsAttributeName(LPCTSTR psz) { DWORD dwMaxIndex = sizeof(rgszAttributeNames)/sizeof(rgszAttributeNames[0]);
for ( DWORD dwIndex = 0 ; dwIndex < dwMaxIndex ; dwIndex++ ) { #ifndef UNIX
if (0 == StrCmpW(psz, rgszAttributeNames[dwIndex])) #else
if (0 == lstrcmpi(psz, rgszAttributeNames[dwIndex])) #endif
return TRUE; }
return FALSE; }
LPCTSTR CRegZone::GetTemplateNameFromIndex(URLTEMPLATE urlTemplateIndex) { DWORD dwMaxIndex = sizeof(TemplateNameIdxMap) / sizeof(TemplateNameIdxMap[0]);
for (DWORD dwIndex = 0 ; dwIndex < dwMaxIndex ; dwIndex++ ) { if (TemplateNameIdxMap[dwIndex].index == urlTemplateIndex) return TemplateNameIdxMap[dwIndex].pszName; } return NULL; } // These are static functions to deal with aggregate policies.
// Because of the discrepancy between the UI and the actions defined,
// there are cases where the security manager munges the policies for certain actions.
inline void CRegZone::KludgeMapAggregatePolicy(DWORD dwAction, LPDWORD pdwPolicy) { TransAssert(pdwPolicy != NULL);
switch (dwAction) { case URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY: case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY: case URLACTION_SCRIPT_OVERRIDE_SAFETY: { if (GetUrlPolicyPermissions(*pdwPolicy) == URLPOLICY_QUERY) SetUrlPolicyPermissions(*pdwPolicy, URLPOLICY_DISALLOW); break; } } }
// Call this function to determine if an action is aggregated by some
// other action.
// RETURNS : TRUE if there is an aggregate action corr to dwAction.
// also returns the action in pdwAggregate.
// FALSE: if this action is not aggregated by some other action.
// pdwAggregate is unchanged in this case.
inline BOOL CRegZone::GetAggregateAction(DWORD dwAction, LPDWORD pdwAggregate) { DWORD dwAggregate = 0; BOOL bReturn = FALSE; TransAssert(dwAction >= URLACTION_MIN); switch(dwAction) { case URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY: case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY: case URLACTION_ACTIVEX_CONFIRM_NOOBJECTSAFETY: case URLACTION_SCRIPT_OVERRIDE_SAFETY: bReturn = TRUE; dwAggregate = URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY; break; case URLACTION_HTML_SUBMIT_FORMS_FROM: case URLACTION_HTML_SUBMIT_FORMS_TO: bReturn = TRUE; dwAggregate = URLACTION_HTML_SUBMIT_FORMS; break; }
if (bReturn && pdwAggregate) *pdwAggregate = dwAggregate;
return bReturn; }
// Functions corresponding to IInternetZoneManager functionality.
STDMETHODIMP CRegZone::GetZoneAttributes(ZONEATTRIBUTES& zoneAttrib) { if (!IsValid()) { return E_FAIL; }
CRegKey regKey(m_bHKLMOnly);
if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return E_FAIL; }
// Since this is the first rev, we should have enough memory
// to fill in the ZONEATTRIBUTES structure. If we need to extend
// the structure this code will have to be modified.
TransAssert(zoneAttrib.cbSize >= sizeof(ZONEATTRIBUTES));
// Amount of information we will copy.
zoneAttrib.cbSize = sizeof(ZONEATTRIBUTES);
TransAssert(regKey!= NULL);
DWORD dwCount; LONG lRet;
// BUGBUG deal with values exceeding size limit.
// We would have to allocate memory ourself and
// truncate the resulting string down.
// Read DisplayName.
dwCount = sizeof(zoneAttrib.szDisplayName); lRet = regKey.QueryValue(zoneAttrib.szDisplayName, SZDISPLAYNAME, &dwCount); TransAssert(ERROR_MORE_DATA != lRet);
if (NO_ERROR != lRet) zoneAttrib.szDisplayName[0] = __TEXT('\0');
// Read Description
dwCount = sizeof(zoneAttrib.szDescription); regKey.QueryValue(zoneAttrib.szDescription, SZDESCRIPTION, &dwCount); TransAssert(ERROR_MORE_DATA != lRet);
if (NO_ERROR != lRet) zoneAttrib.szDescription[0] = __TEXT('\0'); // Read Icon.
dwCount = sizeof(zoneAttrib.szIconPath); regKey.QueryValue(zoneAttrib.szIconPath, SZICON, &dwCount); TransAssert(ERROR_MORE_DATA != lRet);
if (NO_ERROR != lRet) zoneAttrib.szIconPath[0] = __TEXT('\0');
// Read Current, Recommended and Min Settings.
QueryTemplatePolicyIndex(regKey, SZMINLEVEL, &zoneAttrib.dwTemplateMinLevel); QueryTemplatePolicyIndex(regKey, SZRECLEVEL, &zoneAttrib.dwTemplateRecommended); QueryTemplatePolicyIndex(regKey, SZCURRLEVEL, &zoneAttrib.dwTemplateCurrentLevel);
// Re-read the flags in case someone else updated it in an independent process.
DWORD dwZoneFlags; if (regKey.QueryValue(&dwZoneFlags, SZFLAGS) == ERROR_SUCCESS) { m_dwZoneFlags = dwZoneFlags; UpdateZoneMapFlags(); }
zoneAttrib.dwFlags = m_dwZoneFlags;
return S_OK; } STDMETHODIMP CRegZone::SetZoneAttributes(const ZONEATTRIBUTES& zoneAttrib) { if (!IsValid()) { return E_FAIL; }
// Check if the attributes we are trying to set are valid.
if (!IsValidTemplateIndex(zoneAttrib.dwTemplateMinLevel) || !IsValidTemplateIndex(zoneAttrib.dwTemplateCurrentLevel) || !IsValidTemplateIndex(zoneAttrib.dwTemplateRecommended)) { return E_INVALIDARG; }
CRegKey regKey(m_bHKLMOnly);
if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE | KEY_READ) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return E_FAIL; }
// Write the descriptive strings.
// These should almost never be changed by this call.
if (zoneAttrib.szDisplayName[0] != TEXT('\0')) regKey.SetValue(zoneAttrib.szDisplayName, SZDISPLAYNAME);
if (zoneAttrib.szDescription[0] != TEXT('\0')) regKey.SetValue(zoneAttrib.szDescription, SZDESCRIPTION);
if (zoneAttrib.szIconPath[0] != TEXT('\0')) regKey.SetValue(zoneAttrib.szIconPath, SZICON);
// Write the Template Indicies.
SetTemplatePolicyIndex(regKey, SZMINLEVEL, zoneAttrib.dwTemplateMinLevel); SetTemplatePolicyIndex(regKey, SZRECLEVEL, zoneAttrib.dwTemplateRecommended);
DWORD dwTemplateCurrentLevel;
// When the caller is setting the "CurrentLevel" to "Custom" it is assumed
// that the caller has already changed the underlying policies.
if (zoneAttrib.dwTemplateCurrentLevel == URLTEMPLATE_CUSTOM) { SetTemplatePolicyIndex(regKey, SZCURRLEVEL, zoneAttrib.dwTemplateCurrentLevel); } else { CopyTemplatePolicies(zoneAttrib.dwTemplateCurrentLevel); }
// Finally write the flags value.
regKey.SetValue(zoneAttrib.dwFlags, SZFLAGS); m_dwZoneFlags = zoneAttrib.dwFlags; UpdateZoneMapFlags();
IncrementGlobalCounter(); // increment the count to invalidate the zone policy cache
return S_OK; }
STDMETHODIMP CRegZone::GetActionPolicy(DWORD dwAction, URLZONEREG urlZoneReg, DWORD& dwPolicy) const { if (!IsValid()) return E_FAIL;
DWORD dwActionUse;
// If the action is aggregated by some other action, then we should
// actually check the policy for the aggregate action. If the function
if (!GetAggregateAction(dwAction, &dwActionUse)) dwActionUse = dwAction;
// If it is a hard-coded zone get the policy from internal tables.
// Don't look up the registry for these.
if (IsHardCodedZone() && GetHardCodedZonePolicy(dwActionUse, dwPolicy)) { // dwPolicy should have the policy now.
} else { if(!s_rzcache.Lookup(m_dwZoneId, m_lpZonePath, dwActionUse, UseHKLM(urlZoneReg), &dwPolicy)) { return E_FAIL; }
// For some special aggregate policies we have to modify the policy value.
KludgeMapAggregatePolicy(dwAction, &dwPolicy); }
return S_OK; }
STDMETHODIMP CRegZone::SetActionPolicy(DWORD dwAction, URLZONEREG urlZoneReg, DWORD dwPolicy) { if (!IsValid()) return E_FAIL;
CRegKey regKey(UseHKLM(urlZoneReg));
if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return E_FAIL; }
// Policies cannot be set on Actions that are aggregate's.
// They can be only be set on the aggregator policy.
if (IsHardCodedZone()) { TransAssert(FALSE); return E_FAIL; } DWORD dwActionUse;
// If the action is aggregated by some other action, then we should
// actually use the policy for the aggregate action.
if (!GetAggregateAction(dwAction, &dwActionUse)) dwActionUse = dwAction;
// Convert the Action to a string.
#ifndef unix
TCHAR wsz[9]; // FFFFFFFF\0
#else
TCHAR wsz[(sizeof(DWORD)+1)*sizeof(WCHAR)]; #endif /* unix */
if (!DwToWchar(dwActionUse, wsz, 16)) { TransAssert(FALSE); return E_UNEXPECTED; }
DWORD dwPolicyOld; if(!s_rzcache.Lookup(m_dwZoneId, m_lpZonePath, dwActionUse, UseHKLM(urlZoneReg), &dwPolicyOld) || dwPolicyOld != dwPolicy) { regKey.SetValue(dwPolicy, wsz);
s_rzcache.Add(m_dwZoneId, dwActionUse, UseHKLM(urlZoneReg), dwPolicy, URLZONE_FINDCACHEENTRY); // We have to reset the "CurrentLevel" to "Custom" because we have changed an underlying policy:
SetTemplatePolicyIndex(regKey, SZCURRLEVEL, URLTEMPLATE_CUSTOM); }
return S_OK; }
STDMETHODIMP CRegZone::GetCustomPolicy (REFGUID guid, URLZONEREG urlZoneReg, BYTE** ppByte, DWORD *pcb) const { if (!IsValid()) return E_FAIL;
CRegKey regKey(UseHKLM(urlZoneReg));
if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return E_FAIL; }
// Convert the Action to a string.
TCHAR sz[40]; // {8CC49940-3146-11CF-97A1-00AA00424A9F}\0
SHStringFromGUID(guid, sz, sizeof(sz));
*pcb = 0; // First figure out the amount of memory required.
if (regKey.QueryBinaryValue(NULL, sz, pcb) != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); }
// Memory will be freed by caller.
*ppByte = (BYTE *)CoTaskMemAlloc(*pcb);
if ( *ppByte == NULL) { return E_OUTOFMEMORY; }
// Actually query the registry for the value.
if (regKey.QueryBinaryValue(*ppByte, sz, pcb) != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); }
return S_OK; }
STDMETHODIMP CRegZone::SetCustomPolicy (REFGUID guid, URLZONEREG urlZoneReg, BYTE* pByte, DWORD cb) { if (!IsValid()) return E_FAIL;
CRegKey regKey(UseHKLM(urlZoneReg));
if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE) != ERROR_SUCCESS) { // BUGBUG:: We have to be able to deal with this. situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
return E_FAIL; }
// Convert the Action to a string.
TCHAR sz[40]; // {8CC49940-3146-11CF-97A1-00AA00424A9F}\0
SHStringFromGUID(guid, sz, sizeof(sz));
DWORD dwError = ERROR_SUCCESS; if ((dwError = regKey.SetBinaryValue(pByte, sz, cb)) != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(dwError); }
return S_OK; }
STDMETHODIMP CRegZone::CopyTemplatePolicies(DWORD dwTemplate) // Copy the policies from a predefined template into the current zone
{ HRESULT hr = E_FAIL;
// First check if we can get a name back for the template.
LPCTSTR szTemplateName = GetTemplateNameFromIndex((URLTEMPLATE)dwTemplate);
if (NULL == szTemplateName ) return E_INVALIDARG;
// Create a CRegZone for the template.
CRegZone regTemplate;
if (regTemplate.Init(szTemplateName, TRUE /* templates are stored in HKLM only */, REGZONEUSETEMPLATE)) { CRegKey regZoneKey(m_bHKLMOnly); CRegKey regTemplateKey(TRUE);
if ((NO_ERROR == regTemplateKey.Open(NULL, regTemplate.m_lpZonePath, KEY_READ)) && (NO_ERROR == regZoneKey.Open(NULL, m_lpZonePath, KEY_WRITE))) { TCHAR szValueName[MAX_VALUE_NAME]; DWORD dwNameLen = sizeof(szValueName)/sizeof(TCHAR); DWORD dwBufLen = 2048; DWORD dwActualLen = 2048; BYTE * buffer = new BYTE[dwBufLen]; DWORD dwEnumIndex = 0; DWORD dwType; LONG lRet;
while ((lRet = regTemplateKey.EnumValue (dwEnumIndex, szValueName, &dwNameLen, &dwType, buffer, &dwActualLen)) != ERROR_NO_MORE_ITEMS) { // Need more memory, allocate and re-try.
if (lRet == ERROR_MORE_DATA && dwActualLen > dwBufLen) { dwBufLen = dwActualLen; delete [] buffer; buffer = new BYTE[dwBufLen];
dwNameLen = sizeof(szValueName)/sizeof(TCHAR); // Try with the bigger buffer.
lRet = regTemplateKey.EnumValue(dwEnumIndex, szValueName, &dwNameLen, &dwType, buffer, &dwActualLen); } // dwActualLen contains the actual size of the data to be written.
if (lRet == NO_ERROR && !IsAttributeName(szValueName)) { // Copy the value over.
regZoneKey.SetValueOfType(buffer, szValueName, dwActualLen, dwType); }
dwEnumIndex++; dwActualLen = dwBufLen; dwNameLen = sizeof(szValueName)/sizeof(TCHAR); } // Set the "CurrentLevel" value to the Template Index.
if (regZoneKey.SetValue(dwTemplate, SZCURRLEVEL) == NO_ERROR) hr = S_OK;
delete [] buffer; } }
return hr; } // CRegZoneContainer methods.
CRegZoneContainer::CRegZoneContainer() { m_ppRegZones = NULL; m_cZones = 0; m_bHKLMOnly = FALSE;
m_pZoneEnumList = NULL; m_dwNextEnum = 0; InitializeCriticalSection(&m_csect); }
CRegZoneContainer::~CRegZoneContainer() { Detach(); DeleteCriticalSection(&m_csect); };
// This functions goes through the registry and creates the CRegZone objects corresponding
// to the zones currently in the registry.
BOOL CRegZoneContainer::Attach(BOOL bUseHKLM, REGZONEUSE regZoneUse /* = REGZONEUSEZONES */) { // If this assert fires you probably forgot to call Detach.
TransAssert(m_cZones == 0); TransAssert(m_ppRegZones == NULL); // recover if we are messed up.
Detach();
m_bHKLMOnly = bUseHKLM ;
TCHAR sz[MAX_REGZONE_ROOT]; StrCpyW(sz, (regZoneUse == REGZONEUSEZONES ? SZZONES : SZTEMPLATE ));
// Make sure we have the minimal set of zones required and we self-heal if there is a problem.
// even if self-heal fails we ignore the error code and try to initialize the zones anyway.
if (regZoneUse == REGZONEUSEZONES ) SelfHeal(bUseHKLM);
CRegKey regKey(m_bHKLMOnly); if (regKey.Open(NULL, sz, KEY_READ) != ERROR_SUCCESS) { // Hosed setup right defaults here.
return FALSE; }
TransAssert(regKey.m_hKey != NULL);
// For each entry in the registry
DWORD dwIndex = 0; DWORD dwCount = 0; DWORD lRes; TCHAR szZoneName[MAX_ZONE_NAME]; DWORD dwSize = MAX_ZONE_NAME;
CRegListElem *pElemStart = NULL;
for (; (lRes = regKey.EnumKey(dwIndex, szZoneName, &dwSize)) != ERROR_NO_MORE_ITEMS; dwIndex++) { if (lRes != ERROR_SUCCESS) { break; } dwSize = MAX_ZONE_NAME;
CRegZone *pRegZone = new CRegZone(); if (pRegZone == NULL) { m_cZones = 0; // Out of memory -- change all error codes to return HRESULT's
break; } if (!pRegZone->Init(szZoneName, m_bHKLMOnly)) { continue; // can't create the zone for some reason.
}
m_cZones++; CRegListElem * pRegListElem = new CRegListElem(); if ( pRegListElem == NULL) { m_cZones = 0; break; // Out of memory.
}
pRegListElem->pRegZone = pRegZone; pRegListElem->dwZoneIndex = pRegZone->GetZoneId();
// Insert list into sorted position.
if (pElemStart == NULL) { pElemStart = pRegListElem; pRegListElem->next = NULL; } else if (pElemStart->dwZoneIndex > pRegListElem->dwZoneIndex) { // Insert to the head of the list.
pRegListElem->next = pElemStart; pElemStart = pRegListElem; } else { // Insert in the correct position.
CRegListElem *pElemCurr = pElemStart; while (pElemCurr->next != NULL && pElemCurr->next->dwZoneIndex < pRegListElem->dwZoneIndex ) { pElemCurr = pElemCurr->next; }
TransAssert(pElemCurr != NULL); pRegListElem->next = pElemCurr->next; pElemCurr->next = pRegListElem; } }
// Now that we have all the RegZones collected we will just store them in
// sorted order in an array.
if (m_cZones) m_ppRegZones = new LPREGZONE[m_cZones]; else m_ppRegZones = NULL;
if (m_ppRegZones == NULL) { // Out of memory
m_cZones = 0; return FALSE; }
for (dwIndex = 0; dwIndex < m_cZones ; dwIndex++) { TransAssert(pElemStart != NULL);
m_ppRegZones[dwIndex] = pElemStart->pRegZone; CRegListElem * pElemDelete = pElemStart; pElemStart = pElemStart->next; delete pElemDelete; }
return TRUE;
}
BOOL CRegZoneContainer::Detach() { // First free all the CRegZone entries we are holding on to.
DWORD dwIndex = 0;
for (; dwIndex < m_cZones; dwIndex++) { delete m_ppRegZones[dwIndex]; }
delete [] m_ppRegZones; m_ppRegZones = NULL; m_cZones = 0; m_bHKLMOnly = TRUE;
// Zone enumerator cleanup.
// This ASSERT will fire if you forget to call DestroyZoneEnumerator before
// freeing the object.
TransAssert(m_pZoneEnumList == NULL); CZoneEnumList * pNextEnum = m_pZoneEnumList; while (pNextEnum != NULL) { CZoneEnumList * pEnumListDelete = pNextEnum; pNextEnum = pNextEnum->next; delete pEnumListDelete; }
return TRUE; }
// This function makes sure that the minimal set of zones are in the registry If things are missing
// it calls the self-registration entry point and re-creates the zone key.
#define WIN2KSETUP TEXT("System\\Setup")
#define INPROGRESS TEXT("SystemSetupInProgress")
BOOL CRegZoneContainer::SelfHeal(BOOL bUseHKLM) { HKEY hKeyZones = NULL;
if (IsInGUIModeSetup()) { // ignore SelfHeal if we're in GUI-mode setup
return TRUE; }
if (RegOpenKeyEx((bUseHKLM ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER), SZZONES, 0, KEY_READ, &hKeyZones) == ERROR_SUCCESS) { // Strings corresponding to the five pre-defined zones.
TCHAR * rgszZones[] = { TEXT("0"), TEXT("1"), TEXT("2"), TEXT("3"), TEXT("4") }; int i; for (i = 0 ; i < ARRAYSIZE(rgszZones) ; i++ ) { HKEY hKey;
DWORD dwError = RegOpenKeyEx(hKeyZones, rgszZones[i], 0, KEY_READ, &hKey); if (dwError != ERROR_SUCCESS) break; else RegCloseKey(hKey); }
RegCloseKey(hKeyZones);
// If we succesfully opened all the zones.
if (i == ARRAYSIZE(rgszZones)) { return TRUE; }
}
// If we reached here we were not able to open atleast one of the keys.
// Note that we use L"" because ZonesDllInstall takes a LPCWSTR
BOOL bRet; HRESULT hr = ZonesDllInstall(TRUE, bUseHKLM ? L"HKLM" : L"HKCU"); if (SUCCEEDED(hr)) { CRegKey regKey(bUseHKLM);
// Keep track of how many times we self heal for diagnostic purposes..
DWORD dwSelfHealCount; TCHAR *pszSelfHealCount = TEXT("SelfHealCount");
if (regKey.Open(NULL, SZZONES, KEY_READ | KEY_WRITE) == ERROR_SUCCESS) { if (regKey.QueryValue(&dwSelfHealCount, pszSelfHealCount) != ERROR_SUCCESS) dwSelfHealCount = 0;
dwSelfHealCount++; regKey.SetValue(dwSelfHealCount, pszSelfHealCount); }
bRet = TRUE; } else bRet = FALSE;
return bRet; }
CRegZone * CRegZoneContainer::GetRegZoneByName(LPCTSTR lpName) const { DWORD dwIndex = 0; CRegZone *pRegZone = NULL;
for ( ; dwIndex < m_cZones; dwIndex++ ) { pRegZone = m_ppRegZones[dwIndex] ;
if (pRegZone && StrCmpIW(pRegZone->GetZoneName(), lpName) == 0) break; }
return pRegZone; }
CRegZone * CRegZoneContainer::GetRegZoneById(DWORD dwZoneId) const { DWORD dwIndex = 0; CRegZone * pReturnZone = NULL;
for (; dwIndex < m_cZones ; dwIndex++ ) { CRegZone * pRegZone = m_ppRegZones[dwIndex];
if (pRegZone == NULL) { // This shouldn't happen but a safety check doesn't hurt.
break; } else if (pRegZone->GetZoneId() == dwZoneId) { pReturnZone = pRegZone; break; // Got it
} else if (pRegZone->GetZoneId() > dwZoneId) { break; } }
return pReturnZone; }
// Zone Enumeration functions.
BOOL CRegZoneContainer::VerifyZoneEnum(DWORD dwEnum ) const { BOOL bFound = FALSE;
CZoneEnumList *pNext = m_pZoneEnumList; while (pNext) { if (pNext->dwEnum == dwEnum) { bFound = TRUE; break; }
pNext = pNext->next; } return bFound; }
STDMETHODIMP CRegZoneContainer::CreateZoneEnumerator(DWORD* pdwEnum, DWORD *pdwCount) { if (pdwEnum == NULL || pdwCount == NULL) return E_INVALIDARG;
if (m_cZones == 0) { return E_FAIL; }
CZoneEnumList *pEnumListElem = new CZoneEnumList; if (pEnumListElem == NULL) return E_OUTOFMEMORY;
pEnumListElem->dwEnum = m_dwNextEnum++;
EnterCriticalSection(&m_csect);
if (m_pZoneEnumList == NULL) { pEnumListElem->next = NULL; m_pZoneEnumList = pEnumListElem; } else { pEnumListElem->next = m_pZoneEnumList; m_pZoneEnumList = pEnumListElem; }
*pdwEnum = m_pZoneEnumList->dwEnum; *pdwCount = m_cZones; TransAssert(VerifyZoneEnum(*pdwEnum)); LeaveCriticalSection(&m_csect); return S_OK; }
STDMETHODIMP CRegZoneContainer::GetZoneAt(DWORD dwEnum, DWORD dwIndex, DWORD *pdwZone) { if (!VerifyZoneEnum(dwEnum) || dwIndex >= m_cZones) { return E_INVALIDARG; }
if (m_ppRegZones && m_ppRegZones[dwIndex]) { *pdwZone = m_ppRegZones[dwIndex]->GetZoneId(); return S_OK; } else { return E_OUTOFMEMORY; } }
STDMETHODIMP CRegZoneContainer::DestroyZoneEnumerator(DWORD dwEnum) { HRESULT hr = S_OK; CZoneEnumList *pDelete = NULL;
EnterCriticalSection(&m_csect); if (m_pZoneEnumList == NULL) { } else if (m_pZoneEnumList->dwEnum == dwEnum) { pDelete = m_pZoneEnumList; m_pZoneEnumList = pDelete->next; } else { CZoneEnumList *pCurr = m_pZoneEnumList;
while (pCurr != NULL) { if (pCurr->next && pCurr->next->dwEnum == dwEnum) { pDelete = pCurr->next; pCurr->next = pDelete->next; break; } pCurr = pCurr->next; } }
if (pDelete == NULL) { // Didn't find the entry must be an invalid Enumerator.
hr = E_INVALIDARG; } else { delete pDelete; hr = S_OK; } LeaveCriticalSection(&m_csect); return hr; }
//=============================================================================
// CRegZoneCache methods
//=============================================================================
CRegZone::CRegZoneCache::CRegZoneCache(void) { InitializeCriticalSection(&m_csectZoneCache); // single static object, so this only gets inited once per
// process.
s_hMutexCounter = CreateMutexA(NULL, FALSE, "ZonesCacheCounterMutex"); m_iAdd = 0; }
CRegZone::CRegZoneCache::~CRegZoneCache(void) { Flush(); DeleteCriticalSection(&m_csectZoneCache) ;
CloseHandle(s_hMutexCounter); }
BOOL CRegZone::CRegZoneCache::Lookup(DWORD dwZone, LPTSTR lpZonePath, DWORD dwAction, BOOL fUseHKLM, DWORD *pdwPolicy) { BOOL fFound = FALSE; int iEntry = URLZONE_FINDCACHEENTRY;
TransAssert(iEntry < MAX_REG_ZONE_CACHE);
EnterCriticalSection(&m_csectZoneCache);
if ( !IsCounterEqual() ) Flush(); fFound = FindCacheEntry(dwZone, dwAction, fUseHKLM, iEntry ); if (fFound) { if (pdwPolicy) { *pdwPolicy = m_arzce[iEntry].m_dwPolicy; } } else { // Convert the Action to a string.
#ifndef unix
TCHAR wsz[9]; // FFFFFFFF\0
#else
TCHAR wsz[(sizeof(DWORD)+1)*sizeof(WCHAR)]; #endif /* unix */
if (DwToWchar(dwAction, wsz, 16)) { CRegKey regKey(fUseHKLM);
if (regKey.Open(NULL, lpZonePath, KEY_READ) == ERROR_SUCCESS) { if (regKey.QueryValue(pdwPolicy, wsz) == ERROR_SUCCESS) { fFound = TRUE; Add(dwZone, dwAction, fUseHKLM, *pdwPolicy, iEntry); } } else { // BUGBUG:: We have to be able to deal with this situation and not just bail.
// Possibilities: Setup defaults here if we can create and write to the key
TransAssert(FALSE); } } else { TransAssert(FALSE); } }
LeaveCriticalSection(&m_csectZoneCache);
return fFound; }
void CRegZone::CRegZoneCache::Add(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, DWORD dwPolicy, int iEntry) { BOOL fFound;
TransAssert(iEntry < MAX_REG_ZONE_CACHE); EnterCriticalSection(&m_csectZoneCache);
if ( !IsCounterEqual() ) Flush();
if(iEntry == URLZONE_FINDCACHEENTRY) // using optional param that indicates the entry we want to add so don't bother doing a find.
fFound = FindCacheEntry(dwZone, dwAction, fUseHKLM, iEntry ); // found or not, iEntry will be the right place to set it.
m_arzce[iEntry].Set(dwZone, dwAction, fUseHKLM, dwPolicy);
SetToCurrentCounter(); // validate this cache.
LeaveCriticalSection(&m_csectZoneCache); }
void CRegZone::CRegZoneCache::Flush(void) { int i;
EnterCriticalSection(&m_csectZoneCache);
for ( i = 0; i < MAX_REG_ZONE_CACHE; i++ ) m_arzce[i].Flush();
m_iAdd = 0; LeaveCriticalSection(&m_csectZoneCache); }
// Is the counter we saved with the cache entry, equal to the current counter.
BOOL CRegZone::CRegZoneCache::IsCounterEqual( ) const { CExclusiveLock lock(s_hMutexCounter); LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER); // If we couldn't create the shared memory for some reason, we just assume our cache is up to date.
if (lpdwCounter == NULL) return TRUE;
return (m_dwPrevCounter == *lpdwCounter); }
VOID CRegZone::CRegZoneCache::SetToCurrentCounter( ) { CExclusiveLock lock(s_hMutexCounter); LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER); if (lpdwCounter == NULL) return;
m_dwPrevCounter = *lpdwCounter; }
VOID CRegZone::CRegZoneCache::IncrementGlobalCounter( ) { CExclusiveLock lock(s_hMutexCounter); LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER); if (lpdwCounter == NULL) return;
(*lpdwCounter)++; }
BOOL CRegZone::CRegZoneCache::FindCacheEntry(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, int& riEntry ) { BOOL fFound = FALSE;
for ( riEntry = 0; (m_arzce[riEntry].m_dwZone != ZONEID_INVALID) && (riEntry < MAX_REG_ZONE_CACHE); riEntry++ ) { if ( m_arzce[riEntry].m_dwZone == dwZone && m_arzce[riEntry].m_dwAction == dwAction && m_arzce[riEntry].m_fUseHKLM == fUseHKLM ) { fFound = TRUE; break; } }
if(!fFound) { riEntry = m_iAdd; m_iAdd = (m_iAdd + 1) % MAX_REG_ZONE_CACHE; // next index to add an entry that's not found
} return fFound; } void CRegZone::CRegZoneCache::CRegZoneCacheEntry::Set(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, DWORD dwPolicy) { m_dwZone = dwZone; m_dwAction = dwAction; m_fUseHKLM = fUseHKLM; m_dwPolicy = dwPolicy; }
void CRegZone::CRegZoneCache::CRegZoneCacheEntry::Flush(void) { m_dwZone = ZONEID_INVALID; }
|