|
|
/**********************************************************************/ /** Microsoft Passport **/ /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/ /**********************************************************************/
/*
ppshadowdocument.cpp manages a local shadow of the CCD
FILE HISTORY:
*/ #include "precomp.h"
//===========================================================================
//
// PpShadowDocument
//
PpShadowDocument::PpShadowDocument() { }
//===========================================================================
//
// PpShadowDocument
//
PpShadowDocument::PpShadowDocument( tstring& strURL) : m_strURL(strURL) { }
//===========================================================================
//
// PpShadowDocument
//
PpShadowDocument::PpShadowDocument( tstring& strURL, tstring& strLocalFile) : m_strURL(strURL), m_strLocalFile(strLocalFile) { }
//===========================================================================
//
// SetURL -- URL
//
void PpShadowDocument::SetURL( tstring& strURL) { m_strURL = strURL; }
//===========================================================================
//
// SetLocalFile -- localfile name
//
void PpShadowDocument::SetLocalFile( tstring& strLocalFile) { m_strLocalFile = strLocalFile; }
//===========================================================================
//
// GetDocument -- get CCDs DOM interface
// -- bForceFetch : force an HTTPs, otherwise using local shadow
//
HRESULT PpShadowDocument::GetDocument( IXMLDocument** ppiXMLDocument, BOOL bForceFetch ) { HRESULT hr; PpNexusClient nexusClient; IPersistStreamInitPtr xmlStream; IXMLDocumentPtr xmlDoc;
if(ppiXMLDocument == NULL) { hr = E_INVALIDARG; goto Cleanup; }
*ppiXMLDocument = NULL;
if(bForceFetch) { // Fetch the XML document
if(!m_strURL.empty()) hr = nexusClient.FetchCCD(m_strURL, ppiXMLDocument); else { tstring strMsg; if(!m_strLocalFile.empty()) { strMsg = TEXT("for "); strMsg += m_strLocalFile; }
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::ERROR_TYPE, NEXUS_EMPTYREMOTENAME, strMsg.c_str() ); } hr = S_FALSE; }
if(m_strLocalFile.empty()) { tstring strMsg; if(!m_strURL.empty()) { strMsg = TEXT("for "); strMsg += m_strURL; }
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_EMPTYLOCALNAME, strMsg.c_str() ); } goto Cleanup; }
// If FetchCCD failed and a local file is configured, read from the file.
// If FetchCCD succeeded and a local file is configured, write to the file.
if(hr == S_OK) { if(!NoPersist(*ppiXMLDocument)) SaveDocument(*ppiXMLDocument); else { if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_NOTPERSISTING, m_strURL.c_str()); } } } else { // use new hr variable, not to eat the global one
HRESULT hr1 = LoadDocument(ppiXMLDocument);
if (NULL != g_pAlert) { if (hr1 != S_OK) g_pAlert->report(PassportAlertInterface::ERROR_TYPE, NEXUS_LOADFAILED, m_strLocalFile.c_str()); else g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_USINGLOCAL, m_strLocalFile.c_str()); } } } else { if(!m_strLocalFile.empty()) { hr = LoadDocument(ppiXMLDocument); if(hr == S_OK) { // If the file is still valid, then return.
if(IsValidCCD(*ppiXMLDocument)) { if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_USINGLOCAL, m_strLocalFile.c_str()); } goto Cleanup; } } else { if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::ERROR_TYPE, NEXUS_LOADFAILED, m_strLocalFile.c_str()); } } } else { tstring strMsg; if(!m_strURL.empty()) { strMsg = TEXT("for "); strMsg += m_strURL; }
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_EMPTYLOCALNAME, strMsg.c_str() ); } }
// At this point, we're in one of two states:
// 1. *ppiXMLDocument is NULL
// 2. *ppiXMLDocument is not NULL, but points to a document that is old
// Fetch the XML document, if successful release the document loaded from
// disk (if any).
if(!m_strURL.empty()) hr = nexusClient.FetchCCD(m_strURL, &xmlDoc); else { tstring strMsg; if(!m_strLocalFile.empty()) { strMsg = TEXT("for "); strMsg += m_strLocalFile; }
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::ERROR_TYPE, NEXUS_EMPTYREMOTENAME, strMsg.c_str() ); } hr = S_FALSE; }
if(hr == S_OK) { if(*ppiXMLDocument) (*ppiXMLDocument)->Release(); xmlDoc->QueryInterface(IID_IXMLDocument, (void**)ppiXMLDocument);
// If FetchCCD succeeded and a local file is configured, write to the file.
if(!m_strLocalFile.empty()) { if(!NoPersist(*ppiXMLDocument)) { HANDLE hToken = NULL; //
// In certain configurations this code can be run while impersonating a user who
// does not have access to the directory to store the partner2.xml. Therefore
// we revert to self prior to attempting to save the document.
//
if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hToken)) { RevertToSelf(); }
SaveDocument(*ppiXMLDocument);
if (hToken) { // put the impersonation token back
if (!SetThreadToken(NULL, hToken)) { hr = E_FAIL; } CloseHandle(hToken); } } else { if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_NOTPERSISTING, m_strURL.c_str()); } } } else { tstring strMsg; if(!m_strURL.empty()) { strMsg = TEXT("for "); strMsg += m_strURL; }
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_EMPTYLOCALNAME, strMsg.c_str() ); } } } else if(*ppiXMLDocument) {
// TODO: the logic is not so clear, on 3.0 timeframe, rewrite this whole func
if (NULL != g_pAlert) { g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, NEXUS_USINGLOCAL, m_strLocalFile.c_str()); } hr = S_OK; } else { // If we get here it means that the fetch from the nexus failed
// and the load from disk failed. It is sufficient here to simply
// fall through because hr will already contain an error code
// which should indicate to the caller that no document is
// available.
} }
Cleanup:
return hr; }
//===========================================================================
//
// IsValidCCD -- check ValidUntil attribute of the CCD
//
BOOL PpShadowDocument::IsValidCCD( IXMLDocument* piXMLDocument ) { BOOL bReturn; HRESULT hr; IXMLElementPtr piRootElement; SYSTEMTIME sysTime; DOUBLE dblTime; VARIANT vAttrValue; VARIANT vAttrDate;
hr = piXMLDocument->get_root(&piRootElement); if(hr != S_OK) { bReturn = FALSE; goto Cleanup; }
VariantInit(&vAttrValue); hr = piRootElement->getAttribute(L"ValidUntil", &vAttrValue); if(hr != S_OK) { bReturn = FALSE; goto Cleanup; }
VariantInit(&vAttrDate); hr = VariantChangeType(&vAttrDate, &vAttrValue, 0, VT_DATE); if(hr != S_OK) { bReturn = FALSE; goto Cleanup; }
GetSystemTime(&sysTime); SystemTimeToVariantTime(&sysTime, &dblTime);
bReturn = ((long)V_DATE(&vAttrDate) >= (long)dblTime);
Cleanup:
VariantClear(&vAttrValue); VariantClear(&vAttrDate);
return bReturn; }
//===========================================================================
//
// NoPersist -- Check no persist attribute of the document
//
BOOL PpShadowDocument::NoPersist( IXMLDocument* piXMLDocument ) { BOOL bReturn; HRESULT hr; IXMLElementPtr piRootElement; VARIANT vAttrValue;
hr = piXMLDocument->get_root(&piRootElement); if(hr != S_OK) { bReturn = FALSE; goto Cleanup; }
VariantInit(&vAttrValue); hr = piRootElement->getAttribute(L"NoPersist", &vAttrValue); if(hr != S_OK) { bReturn = FALSE; goto Cleanup; }
bReturn = (lstrcmpiW(L"true", V_BSTR(&vAttrValue)) == 0);
Cleanup:
VariantClear(&vAttrValue);
return bReturn; }
//===========================================================================
//
// SaveDocument -- save CCD to local file
//
HRESULT PpShadowDocument::SaveDocument( IXMLDocument* piXMLDoc ) { HRESULT hr; HANDLE hFile = INVALID_HANDLE_VALUE; ULARGE_INTEGER uliSize; LARGE_INTEGER liZero = {0,0}; IStreamPtr piStream; IPersistStreamInitPtr piPSI; LPBYTE lpBuf = NULL; DWORD dwCurBlock; DWORD dwBytesWritten;
hr = CreateStreamOnHGlobal(NULL, TRUE, &piStream); if(hr != S_OK) goto Cleanup;
hr = piXMLDoc->QueryInterface(IID_IPersistStreamInit, (void**)&piPSI); if(hr != S_OK) goto Cleanup;
piPSI->Save(piStream, TRUE);
piStream->Seek(liZero, STREAM_SEEK_CUR, &uliSize); piStream->Seek(liZero, STREAM_SEEK_SET, NULL);
if(uliSize.HighPart != 0) { hr = E_FAIL; goto Cleanup; }
lpBuf = new BYTE[uliSize.LowPart]; if(lpBuf == NULL) { hr = E_OUTOFMEMORY; goto Cleanup; }
hFile = CreateFile( m_strLocalFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastError(); goto Cleanup; }
for(dwCurBlock = 0; dwCurBlock < uliSize.HighPart; dwCurBlock++) { hr = piStream->Read(lpBuf, 0xFFFFFFFF, NULL); if(!WriteFile(hFile, lpBuf, 0xFFFFFFFF, NULL, NULL)) { hr = GetLastError(); goto Cleanup; } }
hr = piStream->Read(lpBuf, uliSize.LowPart, NULL); if(hr != S_OK) goto Cleanup;
if(!WriteFile(hFile, lpBuf, uliSize.LowPart, &dwBytesWritten, NULL)) { hr = GetLastError(); goto Cleanup; }
hr = S_OK;
Cleanup:
if(hr != S_OK) { TCHAR achErrBuf[1024]; LPCTSTR apszStrings[] = { m_strLocalFile.c_str(), achErrBuf }; LPVOID lpMsgBuf = NULL; ULONG cchTmp;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_MAX_WIDTH_MASK, GetModuleHandle(TEXT("wininet.dll")), hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL );
lstrcpy(achErrBuf, TEXT("0x")); _ultot(hr, &(achErrBuf[2]), 16); achErrBuf[sizeof(achErrBuf) / sizeof(achErrBuf[0]) - 1] = TEXT('\0'); if(lpMsgBuf != NULL && *(LPTSTR)lpMsgBuf != TEXT('\0')) { cchTmp = _tcslen(achErrBuf) + 1; _tcsncat(achErrBuf, TEXT(" ("), (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - cchTmp); _tcsncat(achErrBuf, (LPTSTR)lpMsgBuf, (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - (cchTmp + 2)); cchTmp = _tcslen(achErrBuf) + 1; _tcsncat(achErrBuf, TEXT(") "), (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - cchTmp); }
lstrcat(achErrBuf, TEXT(" when trying to save the fetched file to disk."));
g_pAlert->report(PassportAlertInterface::ERROR_TYPE, NEXUS_LOCALSAVEFAILED, 2, apszStrings, 0, NULL );
LocalFree(lpMsgBuf);
hr = E_FAIL; }
if(lpBuf != NULL) delete [] lpBuf;
if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
return hr; }
//===========================================================================
//
// LoadDocument -- get CCDs from local
//
HRESULT PpShadowDocument::LoadDocument( IXMLDocument** ppiXMLDocument ) { HRESULT hr; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwFileSizeLow; DWORD dwBytesRead; LPBYTE lpBuf = NULL; IStreamPtr piStream; IPersistStreamInitPtr piPSI; LARGE_INTEGER liZero = {0,0};
hFile = CreateFile( m_strLocalFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { hr = E_FAIL; goto Cleanup; }
dwFileSizeLow = GetFileSize(hFile, NULL); if(dwFileSizeLow == 0xFFFFFFFF) { hr = GetLastError(); goto Cleanup; }
lpBuf = new BYTE[dwFileSizeLow]; if(lpBuf == NULL) { hr = E_OUTOFMEMORY; goto Cleanup; }
hr = CreateStreamOnHGlobal(NULL, TRUE, &piStream); if(hr != S_OK) { hr = E_FAIL; goto Cleanup; }
if(ReadFile(hFile, lpBuf, dwFileSizeLow, &dwBytesRead, NULL) == 0) { hr = E_FAIL; goto Cleanup; }
try { hr = piStream->Write(lpBuf, dwFileSizeLow, NULL);
hr = piStream->Seek(liZero, STREAM_SEEK_SET, NULL); } catch(...) { hr = E_FAIL; goto Cleanup; }
//
// Now create an XML object and initialize it using the stream.
//
hr = CoCreateInstance(__uuidof(XMLDocument), NULL, CLSCTX_ALL, IID_IPersistStreamInit, (void**)&piPSI); if(hr != S_OK) goto Cleanup;
hr = piPSI->Load((IStream*)piStream); if(hr != S_OK) goto Cleanup;
hr = piPSI->QueryInterface(__uuidof(IXMLDocument), (void**)ppiXMLDocument);
Cleanup:
if(lpBuf != NULL) delete [] lpBuf;
if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
return hr;
}
|