You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
664 lines
18 KiB
664 lines
18 KiB
/**********************************************************************/
|
|
/** 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;
|
|
|
|
|
|
}
|