/**********************************************************************/ /** Microsoft Passport **/ /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/ /**********************************************************************/ /* PassportConfiguration.cpp FILE HISTORY: */ // PassportConfiguration.cpp: implementation of the CPassportConfiguration class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "PassportConfiguration.h" #include #include "passportguard.hpp" extern BOOL g_bRegistering; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// //=========================================================================== // // CPassportConfiguration // CPassportConfiguration::CPassportConfiguration() : m_rDefault(NULL), m_n(NULL), m_rlastDefault(NULL), m_nlast(NULL), m_lastAttempt(0), m_ConfigMap(NULL), m_lastConfigMap(NULL), m_rPending(NULL), m_nPending(NULL), m_bUpdateInProgress(false), m_ConfigMapPending(NULL) { m_nUpdate = RegisterCCDUpdateNotification(_T(PRCONFIG), this); m_rUpdate = RegisterConfigChangeNotification(this); } //=========================================================================== // // ~CPassportConfiguration // CPassportConfiguration::~CPassportConfiguration() { REGCONFIGMAP::iterator it; if (m_nUpdate) UnregisterCCDUpdateNotification(m_nUpdate); if (m_rUpdate) UnregisterConfigChangeNotification(m_rUpdate); // // Empty out config maps. // { PassportGuard g(m_lock); if(m_ConfigMap) { while((it = m_ConfigMap->begin()) != m_ConfigMap->end()) { it->second->Release(); free(it->first); m_ConfigMap->erase(it); } delete m_ConfigMap; m_ConfigMap = NULL; } if(m_lastConfigMap) { while((it = m_lastConfigMap->begin()) != m_lastConfigMap->end()) { it->second->Release(); free(it->first); m_lastConfigMap->erase(it); } delete m_lastConfigMap; m_lastConfigMap = NULL; } if(m_ConfigMapPending) { while((it = m_ConfigMapPending->begin()) != m_ConfigMapPending->end()) { it->second->Release(); free(it->first); m_ConfigMapPending->erase(it); } delete m_ConfigMapPending; m_ConfigMapPending = NULL; } if (m_rDefault) { m_rDefault->Release(); m_rDefault = NULL; } if (m_n) { m_n->Release(); m_n = NULL; } if (m_rlastDefault) { m_rlastDefault->Release(); m_rlastDefault = NULL; } if (m_nlast) { m_nlast->Release(); m_nlast = NULL; } if (m_rPending) { m_rPending->Release(); m_rPending = NULL; } if (m_nPending) { m_nPending->Release(); m_nPending = NULL; } } } //=========================================================================== // // IsIPAddress // BOOL CPassportConfiguration::IsIPAddress( LPSTR szSiteName ) { for(LPSTR sz = szSiteName; *sz; sz++) if(!_istdigit(*sz) && *sz != '.' && *sz != ':') return FALSE; return TRUE; } //=========================================================================== // // checkoutRegistryConfig // CRegistryConfig* CPassportConfiguration::checkoutRegistryConfig( LPSTR szHost // Can be host name or IP ) { CRegistryConfig* c = NULL; REGCONFIGMAP::iterator it; PassportGuard g(m_lock); if(m_ConfigMap != NULL && szHost && szHost[0]) { if(IsIPAddress(szHost)) { for(it = m_ConfigMap->begin(); it != m_ConfigMap->end(); it++) { if(lstrcmpA(szHost, it->second->getHostIP()) == 0) { c = it->second->AddRef(); break; } } } else { it = m_ConfigMap->find(szHost); if(it != m_ConfigMap->end()) c = it->second->AddRef(); } } if (c == NULL) { if(!m_rDefault) { UpdateNow(); c = m_rDefault ? m_rDefault->AddRef() : NULL; } else c = m_rDefault->AddRef(); } return c; } //=========================================================================== // // checkoutRegistryConfigBySite // CRegistryConfig* CPassportConfiguration::checkoutRegistryConfigBySite( LPSTR szSiteName ) { CRegistryConfig* crc = NULL; CHAR achHostName[2048]; DWORD dwHostNameBufLen; if(szSiteName && szSiteName[0]) { dwHostNameBufLen = sizeof(achHostName); if(CRegistryConfig::GetHostName(szSiteName, achHostName, &dwHostNameBufLen) != ERROR_SUCCESS) goto Cleanup; crc = checkoutRegistryConfig(achHostName); } else { crc = checkoutRegistryConfig(); } Cleanup: return crc; } //=========================================================================== // // checkoutNexusConfig // CNexusConfig* CPassportConfiguration::checkoutNexusConfig() { if (!m_n) { PassportGuard g(m_lock); if (!m_n) // In case it happened while we were waiting UpdateNow(); return m_n ? m_n->AddRef() : NULL; } CNexusConfig *c = m_n->AddRef(); return c; } //=========================================================================== // // isValid // BOOL CPassportConfiguration::isValid() { if (m_rDefault != NULL && m_n != NULL) return m_rDefault->isValid() && m_n->isValid(); else { PassportGuard g(m_lock); if (m_rDefault == NULL || m_n == NULL) // In case it happened while we were waiting { BOOL retVal = UpdateNow(FALSE); return retVal; } } return (m_rDefault && m_rDefault->isValid()) && (m_n && m_n->isValid()); } //=========================================================================== // // TakeRegistrySnapshot // BOOL CPassportConfiguration::TakeRegistrySnapshot( CRegistryConfig** ppRegConfig, REGCONFIGMAP** ppConfigMap ) { HKEY hkSites = 0; BOOL bReturn; *ppRegConfig = NULL; *ppConfigMap = NULL; // Registry CRegistryConfig* pNewRegConfig = new CRegistryConfig(); if(!pNewRegConfig) { bReturn = FALSE; goto Cleanup; } pNewRegConfig->AddRef(); // // Read in all other site configs. Only if we find a sites reg key with // one or more subkeys. // REGCONFIGMAP* pNewRegMap = NULL; { LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Passport\\Sites"), 0, KEY_READ, &hkSites); if(lResult == ERROR_SUCCESS) { DWORD dwNumSites; lResult = RegQueryInfoKey(hkSites, NULL, NULL, NULL, &dwNumSites, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if(lResult == ERROR_SUCCESS && dwNumSites) { // need to wrap this because it uses STL and the STL constructors don't // check memory allocations and can AV in low memory conditions try { pNewRegMap = new REGCONFIGMAP(); } catch(...) { bReturn = FALSE; goto Cleanup; } if(pNewRegMap) { DWORD dwKeyIndex = 0; CHAR achSiteName[256]; DWORD dwSiteNameLen = sizeof(achSiteName); while(RegEnumKeyExA(hkSites, dwKeyIndex++, achSiteName, &dwSiteNameLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { CRegistryConfig* crSite = new CRegistryConfig(achSiteName); if(crSite) { crSite->AddRef(); if (crSite->isValid()) { REGCONFIGMAP::value_type* v = new REGCONFIGMAP::value_type(_strdup(crSite->getHostName()), crSite); if(v) { try { pNewRegMap->insert(*v); } catch(...) { delete v; crSite->Release(); bReturn = FALSE; goto Cleanup; } delete v; } else crSite->Release(); } else { if (g_pAlert) g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_CONFIGURATION, crSite->getFailureString()); crSite->Release(); } } dwSiteNameLen = sizeof(achSiteName); } } } else { pNewRegMap = NULL; } RegCloseKey(hkSites); hkSites = 0; } else { pNewRegMap = NULL; } } // Assign out parameters and return value. *ppRegConfig = pNewRegConfig; pNewRegConfig = NULL; *ppConfigMap = pNewRegMap; pNewRegMap = NULL; bReturn = TRUE; Cleanup: if (0 != hkSites) { RegCloseKey(hkSites); } if (NULL != pNewRegConfig) { delete pNewRegConfig; } if (NULL != pNewRegMap) { try { delete pNewRegMap; } catch(...) { } } return bReturn; } //=========================================================================== // // ApplyRegistrySnapshot // BOOL CPassportConfiguration::ApplyRegistrySnapshot( CRegistryConfig* pRegConfig, REGCONFIGMAP* pConfigMap ) { // // Record the registration state now in case it changes midstream. This // can happen during setup when we're called on a separate thread via // msppnxus!PpNotificationThread::run, which executes while msppmgr.dll // is still setting up the Passport registry values. // BOOL fRegistering = g_bRegistering; if (pRegConfig->isValid()) { REGCONFIGMAP* temp = m_lastConfigMap; { PassportGuard g(m_lock); if (m_rlastDefault) m_rlastDefault->Release(); m_rlastDefault = m_rDefault; m_rDefault = pRegConfig; // // Shuffle config map pointers. // m_lastConfigMap = m_ConfigMap; m_ConfigMap = pConfigMap; } // // Delete the old site map. // if(temp) { REGCONFIGMAP::iterator it; while((it = temp->begin()) != temp->end()) { free(it->first); it->second->Release(); temp->erase(it); } delete temp; } if (g_pAlert) g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, PM_VALID_CONFIGURATION); } else { if (g_pAlert && !fRegistering) { g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_CONFIGURATION, pRegConfig->getFailureString()); } pRegConfig->Release(); if(pConfigMap) { REGCONFIGMAP::iterator it; while((it = pConfigMap->begin()) != pConfigMap->end()) { free(it->first); it->second->Release(); pConfigMap->erase(it); } delete pConfigMap; } } return TRUE; } //=========================================================================== // // TakeNexusSnapshot // BOOL CPassportConfiguration::TakeNexusSnapshot( CNexusConfig** ppNexusConfig, BOOL bForceFetch ) { BOOL bReturn; CNexusConfig* pNexusConfig = NULL; CComPtr pXMLDoc; *ppNexusConfig = NULL; if (GetCCD(_T(PRCONFIG),&pXMLDoc, bForceFetch)) { pNexusConfig = new CNexusConfig(); if(!pNexusConfig) { bReturn = FALSE; goto Cleanup; } if (!pNexusConfig->Read(pXMLDoc)) { bReturn = FALSE; goto Cleanup; } pNexusConfig->AddRef(); } else { if (g_pAlert) { if (g_pAlert) g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0); } m_lastAttempt = time(NULL); bReturn = FALSE; goto Cleanup; } *ppNexusConfig = pNexusConfig; bReturn = TRUE; Cleanup: if(pNexusConfig && bReturn == FALSE) delete pNexusConfig; return bReturn; } //=========================================================================== // // ApplyNexusSnapshot // BOOL CPassportConfiguration::ApplyNexusSnapshot( CNexusConfig* pNexusConfig ) { BOOL bReturn; if (pNexusConfig->isValid()) { PassportGuard g(m_lock); if (m_nlast) m_nlast->Release(); m_nlast = m_n; m_n = pNexusConfig; if (g_pAlert) g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, PM_CCD_LOADED); } else { // NexusConfig throws an alert already if (pNexusConfig) { pNexusConfig->Release(); } bReturn = FALSE; goto Cleanup; } bReturn = TRUE; Cleanup: return bReturn; } //=========================================================================== // // UpdateNow // // Update both configs BOOL CPassportConfiguration::UpdateNow(BOOL forceFetch) { BOOL bReturn; time_t now; CComPtr is; time(&now); if(m_bUpdateInProgress) { bReturn = FALSE; goto Cleanup; } if (now - m_lastAttempt < 60 && m_n == NULL) { // Don't overload on attempts to the nexus bReturn = FALSE; goto Cleanup; } // Registry LocalConfigurationUpdated(); if (m_rDefault == NULL) { m_lastAttempt = now - 30; bReturn = FALSE; goto Cleanup; } // // If we are registering msppmgr.dll then we don't want to try and fetch the CCD // since the registration occurs during setup and at that time the network isn't // available. If this does occur then msppmgr.dll hangs and setup breaks in with // registration time out. // if (!g_bRegistering) { if (GetCCD(_T(PRCONFIG),&is, forceFetch)) { try { NexusConfigUpdated(is); } catch(...) { if (g_pAlert) { if (g_pAlert) g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0); } bReturn = FALSE; goto Cleanup; } } else { if (g_pAlert) { if (g_pAlert) g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0); } m_lastAttempt = now; bReturn = FALSE; goto Cleanup; } } if (!m_n) { m_lastAttempt = now; bReturn = FALSE; goto Cleanup; } m_lastAttempt = 0; bReturn = TRUE; Cleanup: return bReturn; } //=========================================================================== // // PrepareUpdate // BOOL CPassportConfiguration::PrepareUpdate(BOOL forceFetch) { BOOL bReturn; static PassportLock prepareLock; PassportGuard g(prepareLock); // Don't allow another first phase while second phase // is pending. //if(m_bUpdateInProgress) //{ // bReturn = FALSE; // goto Cleanup; //} // The PrepareUpdate is called by the Refresh method in msppext.dll where // a lock value is maintained to prevent calling first phase PrepareUpdate // while second phase CommitUpdate is pending. If for some reason the Refresh // aborts after calling PrepareUpdate and before calling CommintUpdate, // m_bUpdateInProgress will remain true preventing future Refresh. Since no first // first phase PrepareUpdate can be called while second phase CommitUpdate is pending, // m_bUpdateInProgress can be set to false safely //if(m_bUpdateInProgress) { if(m_ConfigMapPending) { REGCONFIGMAP::iterator it; while((it = m_ConfigMapPending->begin()) != m_ConfigMapPending->end()) { it->second->Release(); free(it->first); m_ConfigMapPending->erase(it); } delete m_ConfigMapPending; m_ConfigMapPending = NULL; } if (m_rPending) { m_rPending->Release(); m_rPending = NULL; } if (m_nPending) { m_nPending->Release(); m_nPending = NULL; } m_bUpdateInProgress = false; } // Get the current registry config. if (!TakeRegistrySnapshot(&m_rPending, &m_ConfigMapPending)) return FALSE; // Get the latest xml if (!TakeNexusSnapshot(&m_nPending, forceFetch)) return FALSE; m_bUpdateInProgress = true; bReturn = TRUE; return bReturn; } //=========================================================================== // // CommitUpdate // BOOL CPassportConfiguration::CommitUpdate() { BOOL bReturn; // Update default registry and any sites if(!ApplyRegistrySnapshot(m_rPending, m_ConfigMapPending)) { bReturn = FALSE; goto Cleanup; } if(!ApplyNexusSnapshot(m_nPending)) { bReturn = FALSE; goto Cleanup; } m_rPending = NULL; m_ConfigMapPending = NULL; m_nPending = NULL; bReturn = TRUE; Cleanup: m_bUpdateInProgress = false; return bReturn; } //=========================================================================== // // LocalConfigurationUpdated // void CPassportConfiguration::LocalConfigurationUpdated() { // // Read in default config. // CRegistryConfig* pNewRegConfig; REGCONFIGMAP* pNewConfigMap; if(!TakeRegistrySnapshot(&pNewRegConfig, &pNewConfigMap)) return; // // Here we don't care about the results of reading in non-default sites. pNewConfigMap will be NULL // if anything bad happened and events will be in the event log. As long as we have a valid // default configuration we can go ahead and do the switch. // ApplyRegistrySnapshot(pNewRegConfig, pNewConfigMap); } //=========================================================================== // // NexusConfigUpdated // void CPassportConfiguration::NexusConfigUpdated(IXMLDocument *is) { CNexusConfig *newc = new CNexusConfig(); if (newc) { if (newc->Read(is)) { newc->AddRef(); ApplyNexusSnapshot(newc); } else { delete newc; } } } //=========================================================================== // // getFailureString // LPWSTR CPassportConfiguration::getFailureString() { // IsValid must be called before this if (!m_rDefault) return L"Registry configuration failed."; if (!m_rDefault->isValid()) return m_rDefault->getFailureString(); if (!m_n) return L"Nexus configuration failed."; if (!m_n->isValid()) return m_n->getFailureString(); return L"OK"; } //=========================================================================== // // HasSites // BOOL CPassportConfiguration::HasSites() { return (m_ConfigMap && m_ConfigMap->size()); } //=========================================================================== // // Dump // void CPassportConfiguration::Dump(BSTR* pbstrDump) { //m_rDefault->Dump(pbstrDump); //m_ConfigMap->Dump(pbstrDump); m_n->Dump(pbstrDump); }