|
|
//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: manifest.cpp
//
// Description:
//
// Implementation for the GetManifest() function
//
//=======================================================================
#include "iuengine.h"
#include <iucommon.h>
#include <fileutil.h>
#include <shlwapi.h>
#include <wininet.h>
#include "schemamisc.h"
#include "WaitUtil.h"
#include "download.h"
#include <httprequest.h>
#include <httprequest_i.c>
#include <iuxml.h>
#define QuitIfNull(p) {if (NULL == p) {hr = E_INVALIDARG; LOG_ErrorMsg(hr); return hr;}}
#define QuitIfFail(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
#define ERROR_INVALID_PID 100
#define E_INVALID_PID MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,ERROR_INVALID_PID)
#define errorInvalidLicense 1
const TCHAR g_szInvalidPID[] = _T("The PID is invalid");
const TCHAR IDENT_IUSCHEMA[] = _T("IUSchema"); const TCHAR IDENT_IUSCHEMA_SOAPQUERY[] = _T("SOAPQuerySchema"); const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerCache"); const TCHAR IDENT_IUSERVERCOUNT[] = _T("ServerCount"); const TCHAR IDENT_IUSERVER[] = _T("Server");
const CHAR SZ_GET_MANIFEST[] = "Querying software update catalog from"; const CHAR SZ_GET_MANIFEST_ERROR[] = "Querying software update catalog";
HRESULT ValidatePID(IXMLDOMDocument *pXmlDomDocument); void PingInvalidPID(BSTR bstrClientName,HRESULT hRes,HANDLE *phQuit,DWORD dwNumHandles);
/////////////////////////////////////////////////////////////////////////////
// Function forward declarations
/////////////////////////////////////////////////////////////////////////////
HRESULT GetServerURL(IXMLDOMDocument *pXMLQuery, IXMLDOMDocument *pXMLClientInfo, LPTSTR *ppszURL); HRESULT GetSOAPQuery(IXMLDOMDocument *pXMLClientInfo, IXMLDOMDocument *pXMLSystemSpec, IXMLDOMDocument *pXMLQuery, IXMLDOMDocument **ppSOAPQuery);
/////////////////////////////////////////////////////////////////////////////
// GetManifest()
//
// Gets a catalog base on the specified information.
// Input:
// bstrXmlClientInfo - the credentials of the client in xml format
// bstrXmlSystemSpec - the detected system specifications in xml
// bstrXmlQuery - the user query infomation in xml
// Return:
// pbstrXmlCatalog - the xml catalog retrieved
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI CEngUpdate::GetManifest(BSTR bstrXmlClientInfo, BSTR bstrXmlSystemSpec, BSTR bstrXmlQuery, DWORD dwFlags, BSTR *pbstrXmlCatalog) { LOG_Block("GetManifest()");
// clear any previous cancel event
ResetEvent(m_evtNeedToQuit);
USES_IU_CONVERSION;
HRESULT hr = E_FAIL; CXmlClientInfo xmlClientInfo; IXMLDOMDocument *pXMLSystemSpec = NULL; IXMLDOMDocument *pXMLQuery = NULL; IXMLDOMDocument *pSOAPQuery = NULL; IXMLHttpRequest *pIXMLHttpRequest = NULL; IWinHttpRequest *pWinHttpRequest = NULL; BSTR bstrXmlSOAPQuery = NULL; BSTR bstrPOST = NULL, bstrURL = NULL; BSTR bstrClientName = NULL; LPTSTR pszURL = NULL; LONG lCount = 0; MSG msg; DWORD dwRet; BOOL fDontAllowProxy = FALSE; SAUProxySettings pauProxySettings; ZeroMemory(&pauProxySettings, sizeof(SAUProxySettings));
//
// load the DOM Doc for Query, ClientInfo, SystemSpec respectively
//
LOG_XmlBSTR(bstrXmlQuery); hr = LoadXMLDoc(bstrXmlQuery, &pXMLQuery, FALSE); CleanUpIfFailedAndMsg(hr);
LOG_XmlBSTR(bstrXmlClientInfo); hr = xmlClientInfo.LoadXMLDocument(bstrXmlClientInfo, FALSE); CleanUpIfFailedAndMsg(hr);
CleanUpIfFailedAndSetHrMsg(xmlClientInfo.GetClientName(&bstrClientName));
CleanUpIfFailedAndSetHrMsg(g_pUrlAgent->IsClientSpecifiedByPolicy(OLE2T(bstrClientName)));
//
// Set flag to NOT set proxy for WinHTTP
//
if (S_FALSE ==hr) { fDontAllowProxy = FALSE; hr = S_OK; } else // S_OK
{ fDontAllowProxy = TRUE; }
//
// we treat bstrXmlSystemSpec as optional
//
if (NULL != bstrXmlSystemSpec && SysStringLen(bstrXmlSystemSpec) > 0) { LOG_XmlBSTR(bstrXmlSystemSpec); hr = LoadXMLDoc(bstrXmlSystemSpec, &pXMLSystemSpec, FALSE); CleanUpIfFailedAndMsg(hr); }
//
// retrieve the ServerCache URL from the Query xml doc and validate it
//
hr = GetServerURL(pXMLQuery, xmlClientInfo.GetDocument(), &pszURL); CleanUpIfFailedAndMsg(hr);
//
// concatenate the above several xml client input into a single XML
// with the SOAP syntax/format that the server recognizes
//
hr = GetSOAPQuery(xmlClientInfo.GetDocument(), pXMLSystemSpec, pXMLQuery, &pSOAPQuery); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; } #if defined(DBG)
else { BSTR bstrSOAPQuery = NULL; pSOAPQuery->get_xml(&bstrSOAPQuery); LOG_XmlBSTR(bstrSOAPQuery); SafeSysFreeString(bstrSOAPQuery); } #endif
//
// change again: add WINHTTP support for AU running as a service;
// use GetAllowedDownloadTransport(0) to determine -
// 1) 0 == try winhttp first & if that fails, try wininet.
// 2) WUDF_ALLOWWINHTTPONLY == only try winhttp. never fall back on wininet.
// 3) WUDF_ALLOWWININETONLY == only try wininet. never use winhttp.
//
// in WINHTTP the compression is not supported yet at this time;
// in WININET we removed the compression support at this point due to a bug in URLMON (< IE6.0).
//
// in both cases we use asynchronized sending in order to abort timely for a cancel event
//
BOOL fLoadWINHTTP = FALSE; DWORD dwTransportFlag = GetAllowedDownloadTransport(0);
if ((0 == dwTransportFlag) || (WUDF_ALLOWWINHTTPONLY == dwTransportFlag)) { hr = CoCreateInstance(CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, IID_IWinHttpRequest, (void **) &pWinHttpRequest); if (SUCCEEDED(hr)) { BOOL fRetry = FALSE; bstrURL = SysAllocString(T2OLE(pszURL)); fLoadWINHTTP = TRUE; VARIANT vProxyServer, vBypassList; hr = GetAUProxySettings(bstrURL, &pauProxySettings); CleanUpIfFailedAndMsg(hr); DWORD iProxy = pauProxySettings.iProxy; if (-1 == iProxy) pauProxySettings.iProxy = iProxy = 0;
//
// open request
//
VARIANT vBool; vBool.vt = VT_BOOL; vBool.boolVal = VARIANT_TRUE; bstrPOST = SysAllocString(L"POST"); Retry: hr = pWinHttpRequest->Open(bstrPOST, // HTTP method: "POST"
bstrURL, // requested URL
vBool); // asynchronous operation
CleanUpIfFailedAndMsg(hr);
//
// For SSL URLs, set the WinHttpRequestOption_SslErrorIgnoreFlags
// option to zero so that no server certificate errors are ignored.
//
// The default at the time this code was written was 0x3300, which
// means ignore all server certificate errors. Using this default
// would significantly reduce security in various ways; for example
// if the 0x0100 bit was set, WinHttp would trust certificates from
// any root certificate authority, even it it was not in the list of
// trusted CAs.
//
// Note that at the time this code was written, the WinHttp
// documentation made no mention of Certificate Revocation List
// checking. It is assumed that the default CRL behavior
// implemented by WinHttp will provide adequate security and
// performance.
//
if ((_T('H') == pszURL[0] || _T('h') == pszURL[0]) && // Sorry, this is simpler than using a function.
(_T('T') == pszURL[1] || _T('t') == pszURL[1]) && (_T('T') == pszURL[2] || _T('t') == pszURL[2]) && (_T('P') == pszURL[3] || _T('p') == pszURL[3]) && (_T('S') == pszURL[4] || _T('s') == pszURL[4]) && _T(':') == pszURL[5]) { VARIANT vOption; VariantInit(&vOption); vOption.vt = VT_I4; vOption.lVal = 0; hr = pWinHttpRequest->put_Option(WinHttpRequestOption_SslErrorIgnoreFlags, vOption);
VariantClear(&vOption); CleanUpIfFailedAndMsg(hr); }
if (TRUE == fDontAllowProxy) { LOG_Internet(_T("Don't set the proxy due to policy")); } else { //
// set proxy
//
VariantInit(&vProxyServer); VariantInit(&vBypassList); BOOL fSetProxy = TRUE;
if (pauProxySettings.rgwszProxies != NULL) { vProxyServer.vt = VT_BSTR; vProxyServer.bstrVal = SysAllocString(pauProxySettings.rgwszProxies[iProxy]); } else if (pauProxySettings.rgwszProxies == NULL) { fSetProxy = FALSE; }
if (pauProxySettings.wszBypass != NULL) { vBypassList.vt = VT_BSTR; vBypassList.bstrVal = SysAllocString(pauProxySettings.wszBypass); }
if (fSetProxy) { hr = pWinHttpRequest->SetProxy(HTTPREQUEST_PROXYSETTING_PROXY, vProxyServer, vBypassList); } VariantClear(&vProxyServer); VariantClear(&vBypassList); CleanUpIfFailedAndMsg(hr); }
//
// send request
//
VARIANT vQuery; vQuery.vt = VT_UNKNOWN; vQuery.punkVal = pSOAPQuery;
hr = pWinHttpRequest->Send(vQuery); if (FAILED(hr)) { LOG_Internet(_T("WinHttpRequest: Send failed: 0x%08x"), hr); fRetry = TRUE; goto getNextProxyForRetry; }
//
// check if quit or completion every 1/4 second
//
VARIANT vTimeOut; vTimeOut.vt = VT_I4; vTimeOut.lVal = 0; VARIANT_BOOL fSuccess = VARIANT_FALSE; hr = pWinHttpRequest->WaitForResponse(vTimeOut, &fSuccess); if (FAILED(hr)) { LOG_Internet(_T("WinHttpRequest: WaitForResponse failed: 0x%08x"), hr); fRetry = TRUE; goto getNextProxyForRetry; }
// we wait up to 30 sec (120*250 ms)
lCount = 0; while (!fSuccess && lCount <120) { lCount++; //
// Wait for 250ms while pumping messages, but return if m_evtNeedToQuit signaled
//
dwRet = MyMsgWaitForMultipleObjects(1, &m_evtNeedToQuit, FALSE, 250, QS_ALLINPUT); if (WAIT_TIMEOUT != dwRet) { //
// Either the event was signaled or a message being pumped says quit
//
pWinHttpRequest->Abort(); hr = E_ABORT; goto CleanUp; }
hr = pWinHttpRequest->WaitForResponse(vTimeOut, &fSuccess); if (FAILED(hr)) { LOG_Internet(_T("WinHttpRequest: WaitForResponse failed: 0x%08x"), hr); fRetry = TRUE; goto getNextProxyForRetry; } }
//
// check the HTTP status code returned by a request
//
LONG lStatus = HTTP_STATUS_OK;// 200
hr = pWinHttpRequest->get_Status(&lStatus); if (FAILED(hr)) { LOG_Internet(_T("WinHttpRequest: get_Status failed: 0x%08x"), hr); fRetry = TRUE; goto getNextProxyForRetry; }
fRetry = FALSE; if (!fSuccess) { // time out
hr = E_FAIL; fRetry = TRUE; } else if (HTTP_STATUS_OK != lStatus) { // COMPLETED, but error in status
hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_HTTP, lStatus); LOG_ErrorMsg(hr); fRetry = TRUE; } else { //
// get response
//
hr = pWinHttpRequest->get_ResponseText(pbstrXmlCatalog); CleanUpIfFailedAndMsg(hr);
//
// verify the response is a well-formed XML document
//
IXMLDOMDocument *pXMLDoc = NULL; hr = LoadXMLDoc(*pbstrXmlCatalog, &pXMLDoc);
if(SUCCEEDED(hr)) { hr=ValidatePID(pXMLDoc);
if(FAILED(hr)) { PingInvalidPID(bstrClientName,hr,&m_evtNeedToQuit,1); LogError(hr,"Validation of PID failed"); }
//The Banned PID case is not a failure for the GetManifest call.
if(E_INVALID_PID == hr) { hr = S_OK; }
} SafeReleaseNULL(pXMLDoc); CleanUpIfFailedAndMsg(hr); }
getNextProxyForRetry: if (fRetry && !fDontAllowProxy) { if (pauProxySettings.cProxies > 1 && pauProxySettings.rgwszProxies != NULL) { iProxy = ( iProxy + 1) % pauProxySettings.cProxies; } if (iProxy != pauProxySettings.iProxy) { LogError(hr, "Will retry."); pWinHttpRequest->Abort(); goto Retry; } else { LogError(hr, "Already tried all proxies. Will not retry."); } }
} else { if (WUDF_ALLOWWINHTTPONLY == dwTransportFlag) { CleanUpIfFailedAndMsg(hr); } } }
if ((0 == dwTransportFlag && !fLoadWINHTTP) || (WUDF_ALLOWWININETONLY == dwTransportFlag)) { //
// 475506 W2K: IU - IU control's GetManifest method call fails on all subsequent
// calls after the first. - On Win 2K Only
//
// We no longer take the FLAG_USE_COMPRESSION into account for WinInet since we
// previously used URLMON and there are bugs that would require a rewrite of
// xmlhttp.* to fix and we haven't been using compression on the live site to date.
//
LOG_Internet(_T("GetManifest using WININET.DLL"));
//
// create an XMLHttpRequest object
//
hr = CoCreateInstance(CLSID_XMLHTTPRequest, NULL, CLSCTX_INPROC_SERVER, IID_IXMLHttpRequest, (void **) &pIXMLHttpRequest); CleanUpIfFailedAndMsg(hr);
//
// open request
//
VARIANT vEmpty, vBool; vEmpty.vt = VT_EMPTY; vBool.vt = VT_BOOL; vBool.boolVal= VARIANT_FALSE; bstrPOST = SysAllocString(L"POST"); bstrURL = SysAllocString(T2OLE(pszURL));
hr = pIXMLHttpRequest->open(bstrPOST, // HTTP method: "POST"
bstrURL, // requested URL
vBool, // synchronous operation
vEmpty, // user for authentication (no authentication for V1.0)
vEmpty); // pswd for authentication
CleanUpIfFailedAndMsg(hr);
//
// send request
//
VARIANT vQuery; vQuery.vt = VT_UNKNOWN; vQuery.punkVal = pSOAPQuery;
hr = pIXMLHttpRequest->send(vQuery); CleanUpIfFailedAndMsg(hr);
//
// check the HTTP status code returned by a request
//
LONG lResultStatus = HTTP_STATUS_OK;// 200
hr = pIXMLHttpRequest->get_status(&lResultStatus); CleanUpIfFailedAndMsg(hr);
if (HTTP_STATUS_OK != lResultStatus) { hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_HTTP, lResultStatus); LOG_ErrorMsg(hr); } else { //
// get response
//
hr = pIXMLHttpRequest->get_responseText(pbstrXmlCatalog); CleanUpIfFailedAndMsg(hr);
//
// verify the response is a well-formed XML document
//
IXMLDOMDocument *pXMLDoc = NULL; hr = LoadXMLDoc(*pbstrXmlCatalog, &pXMLDoc);
if(SUCCEEDED(hr)) { hr=ValidatePID(pXMLDoc);
if(FAILED(hr)) { PingInvalidPID(bstrClientName,hr,&m_evtNeedToQuit,1); LogError(hr,"Validation of PID failed"); } //The Banned pid case is not a failure for the GetManifest call
if(E_INVALID_PID == hr) { hr = S_OK; }
} SafeReleaseNULL(pXMLDoc); CleanUpIfFailedAndMsg(hr); } }
CleanUp: if (SUCCEEDED(hr)) { #if defined(UNICODE) || defined(_UNICODE)
LogMessage("%s %ls", SZ_GET_MANIFEST, pszURL); #else
LogMessage("%s %s", SZ_GET_MANIFEST, pszURL); #endif
} else { if (NULL == pszURL) { LogError(hr, SZ_GET_MANIFEST_ERROR); } else { #if defined(UNICODE) || defined(_UNICODE)
LogError(hr, "%s %ls", SZ_GET_MANIFEST, pszURL); #else
LogError(hr, "%s %s", SZ_GET_MANIFEST, pszURL); #endif
} }
if (NULL != pszURL) HeapFree(GetProcessHeap(), 0, pszURL); SafeReleaseNULL(pXMLSystemSpec); SafeReleaseNULL(pXMLQuery); SafeReleaseNULL(pSOAPQuery); SafeReleaseNULL(pIXMLHttpRequest); SafeReleaseNULL(pWinHttpRequest); SysFreeString(bstrPOST); SysFreeString(bstrURL); SysFreeString(bstrXmlSOAPQuery); SysFreeString(bstrClientName); FreeAUProxySettings(&pauProxySettings); return hr; }
/////////////////////////////////////////////////////////////////////////////
// GetServerURL()
//
// Retrieve the ServerCache URL from the Query xml doc and validate that
// URL against the ServerCache URLs in iuident.txt.
// Return:
// ppszURL - the ServerCache URL path pointer
/////////////////////////////////////////////////////////////////////////////
HRESULT GetServerURL(IXMLDOMDocument *pXMLQuery, IXMLDOMDocument *pXMLClientInfo, LPTSTR *ppszURL) { LOG_Block("GetServerURL()");
USES_IU_CONVERSION;
HRESULT hr = E_FAIL;
if ((NULL == pXMLQuery) || (NULL == pXMLClientInfo) || (NULL == ppszURL)) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; }
IXMLDOMNode* pQueryNode = NULL; IXMLDOMNode* pQueryClient = NULL; BSTR bstrQuery = SysAllocString(L"query"); BSTR bstrHref = SysAllocString(L"href"); BSTR bstrClientInfo = SysAllocString(L"clientInfo"); BSTR bstrClientName = SysAllocString(L"clientName"); BSTR bstrURL = NULL, bstrClient = NULL; LPTSTR pszURL = NULL; INT iServerCnt; BOOL fInternalServer = FALSE;
QuitIfFail(FindSingleDOMNode(pXMLClientInfo, bstrClientInfo, &pQueryClient)); QuitIfFail(GetAttribute(pQueryClient, bstrClientName, &bstrClient));
pszURL = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); CleanUpFailedAllocSetHrMsg(pszURL);
//
// failure in "g_pUrlAgent = new CUrlAgent"
//
CleanUpFailedAllocSetHrMsg(g_pUrlAgent); QuitIfFail(g_pUrlAgent->GetQueryServer(OLE2T(bstrClient), pszURL, INTERNET_MAX_URL_LENGTH, &fInternalServer));
if (fInternalServer) { //
// we have policy override for this client, set the query url as WUServer in policy
//
*ppszURL = pszURL; hr = S_OK; } else { //
// we don't have policy override for this client;
//
// find the ServerCache URL from <query> node
//
QuitIfFail(FindSingleDOMNode(pXMLQuery, bstrQuery, &pQueryNode)); if (SUCCEEDED(GetAttribute(pQueryNode, bstrHref, &bstrURL)) && NULL != bstrURL && SysStringLen(bstrURL) >0) { //
// this is the case that the query specified the serverl url, we need
// to do the validation for the url here...
//
// pszURL is alloced to be INTERNET_MAX_URL_LENGTH above.
hr = StringCchCopyEx(pszURL, INTERNET_MAX_URL_LENGTH, OLE2T(bstrURL), NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; }
//
// process the iuident.txt to find all valid ServerCache URLs
//
TCHAR szIUDir[MAX_PATH]; TCHAR szIdentFile[MAX_PATH];
GetIndustryUpdateDirectory(szIUDir); hr = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir, IDENTTXT); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; }
iServerCnt = GetPrivateProfileInt(IDENT_IUSERVERCACHE, IDENT_IUSERVERCOUNT, -1, szIdentFile); if (-1 == iServerCnt) { // no ServerCount number specified in iuident.txt
LOG_Error(_T("No ServerCount number specified in iuident.txt")); hr = E_FAIL; goto CleanUp; }
hr = INET_E_INVALID_URL; for (INT i=1; i<=iServerCnt; i++) { TCHAR szValidURL[INTERNET_MAX_URL_LENGTH]; TCHAR szServer[32];
hr = StringCchPrintfEx(szServer, ARRAYSIZE(szServer), NULL, NULL, MISTSAFE_STRING_FLAGS, _T("%s%d"), IDENT_IUSERVER, i); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; }
hr = INET_E_INVALID_URL; GetPrivateProfileString(IDENT_IUSERVERCACHE, szServer, _T(""), szValidURL, ARRAYSIZE(szValidURL), szIdentFile);
if ('\0' == szValidURL[0]) { // no ServerCache URL specified in iuident.txt for this server
LOG_Error(_T("No ServerCache URL specified in iuident.txt for %s%d"), IDENT_IUSERVER, i); hr = E_FAIL; goto CleanUp; } if (0 == lstrcmpi(szValidURL, pszURL)) { // it's a valid ServerCache URL
*ppszURL = pszURL; hr = S_OK; break; } } } else { //
// this is the case that the query didn't specify the serverl url, we just use the
// server url that was found through g_pUrlAgent according to the clientName.
//
// now insert the URL into the <query> node
//
BSTR bstrTemp = T2BSTR(pszURL); QuitIfFail(SetAttribute(pQueryNode, bstrHref, bstrTemp)); SafeSysFreeString(bstrTemp);
*ppszURL = pszURL; } }
CleanUp: if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, pszURL); *ppszURL = NULL; LOG_ErrorMsg(hr); } SafeReleaseNULL(pQueryNode); SafeReleaseNULL(pQueryClient); SysFreeString(bstrQuery); SysFreeString(bstrHref); SysFreeString(bstrURL); SysFreeString(bstrClientInfo); SysFreeString(bstrClientName); SysFreeString(bstrClient); return hr; }
/////////////////////////////////////////////////////////////////////////////
// GetSOAPQuery()
//
// Concatenate the several xml client input into a single XML
// with the SOAP syntax/format that the server recognizes
// Input:
// pXMLClientInfo - the credentials of the client in DOM Doc format
// pXMLSystemSpec - the detected system specifications in DOM Doc
// pXMLQuery - the user query infomation in DOM Doc
// Return:
// ppSOAPQuery - the concatenated query in DOM Doc with required SOAP syntax
//
// SOAPQuery xml doc example:
// <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
// <SOAP:Body>
// <GetManifest>
// <clientInfo>...</clientInfo>
// <systemSpec>...</systemSpec>
// <query href="//windowsupdate.microsoft.com/servecache.asp">...</query>
// </GetManifest>
// </SOAP:Body>
// </SOAP:Envelope>
//
/////////////////////////////////////////////////////////////////////////////
HRESULT GetSOAPQuery(IXMLDOMDocument *pXMLClientInfo, IXMLDOMDocument *pXMLSystemSpec, IXMLDOMDocument *pXMLQuery, IXMLDOMDocument **ppSOAPQuery) { LOG_Block("GetSOAPQuery()");
USES_IU_CONVERSION;
HRESULT hr = E_FAIL;
IXMLDOMDocument* pDocSOAPQuery = NULL; IXMLDOMNode* pNodeSOAPEnvelope = NULL; IXMLDOMNode* pNodeSOAPBody = NULL; IXMLDOMNode* pNodeGetManifest = NULL; IXMLDOMNode* pNodeClientInfo = NULL; IXMLDOMNode* pNodeClientInfoNew = NULL; IXMLDOMNode* pNodeSystemInfo = NULL; IXMLDOMNode* pNodeSystemInfoNew = NULL; IXMLDOMNode* pNodeQuery = NULL; IXMLDOMNode* pNodeQueryNew = NULL; BSTR bstrNameSOAPEnvelope = SysAllocString(L"SOAP:Envelope"); BSTR bstrNameSOAPBody = SysAllocString(L"SOAP:Body"); BSTR bstrNameGetManifest = SysAllocString(L"GetManifest"); BSTR bstrClientInfo = SysAllocString(L"clientInfo"); BSTR bstrSystemInfo = SysAllocString(L"systemInfo"); BSTR bstrQuery = SysAllocString(L"query"); BSTR bstrNameSpaceSchema = NULL;
//
// process the iuident.txt to find the SOAPQuery schema path
//
TCHAR szIUDir[MAX_PATH]; TCHAR szIdentFile[MAX_PATH]; LPTSTR pszSOAPQuerySchema = NULL; LPTSTR pszNameSpaceSchema = NULL;
pszSOAPQuerySchema = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); if (NULL == pszSOAPQuerySchema) { hr = E_OUTOFMEMORY; LOG_ErrorMsg(hr); goto CleanUp; } pszNameSpaceSchema = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); if (NULL == pszNameSpaceSchema) { hr = E_OUTOFMEMORY; LOG_ErrorMsg(hr); goto CleanUp; }
GetIndustryUpdateDirectory(szIUDir); hr = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir, IDENTTXT); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; }
GetPrivateProfileString(IDENT_IUSCHEMA, IDENT_IUSCHEMA_SOAPQUERY, _T(""), pszSOAPQuerySchema, INTERNET_MAX_URL_LENGTH, szIdentFile);
if ('\0' == pszSOAPQuerySchema[0]) { // no SOAPQuery schema path specified in iuident.txt
LOG_Error(_T("No schema path specified in iuident.txt for SOAPQuery")); hr = E_FAIL; goto CleanUp; }
// pszNameSpaceSchema is alloced to be INTERNET_MAX_URL_LENGTH above
hr = StringCchPrintfEx(pszNameSpaceSchema, INTERNET_MAX_URL_LENGTH, NULL, NULL, MISTSAFE_STRING_FLAGS, _T("x-schema:%s"), pszSOAPQuerySchema); if (FAILED(hr)) { LOG_ErrorMsg(hr); goto CleanUp; }
bstrNameSpaceSchema = T2BSTR(pszNameSpaceSchema);
//
// construct the SOAPQuery xml
//
QuitIfFail(CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void **)&pDocSOAPQuery));
pNodeSOAPEnvelope = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameSOAPEnvelope, bstrNameSpaceSchema); if (NULL == pNodeSOAPEnvelope) goto CleanUp; QuitIfFail(InsertNode(pDocSOAPQuery, pNodeSOAPEnvelope));
pNodeSOAPBody = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameSOAPBody, bstrNameSpaceSchema); if (NULL == pNodeSOAPBody) goto CleanUp; QuitIfFail(InsertNode(pNodeSOAPEnvelope, pNodeSOAPBody));
pNodeGetManifest = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameGetManifest); if (NULL == pNodeGetManifest) goto CleanUp; QuitIfFail(InsertNode(pNodeSOAPBody, pNodeGetManifest));
if (NULL != pXMLClientInfo) { QuitIfFail(FindSingleDOMNode(pXMLClientInfo, bstrClientInfo, &pNodeClientInfo)); QuitIfFail(CopyNode(pNodeClientInfo, pDocSOAPQuery, &pNodeClientInfoNew)); QuitIfFail(InsertNode(pNodeGetManifest, pNodeClientInfoNew)); } if (NULL != pXMLSystemSpec) { QuitIfFail(FindSingleDOMNode(pXMLSystemSpec, bstrSystemInfo, &pNodeSystemInfo)); QuitIfFail(CopyNode(pNodeSystemInfo, pDocSOAPQuery, &pNodeSystemInfoNew)); QuitIfFail(InsertNode(pNodeGetManifest, pNodeSystemInfoNew)); } QuitIfFail(FindSingleDOMNode(pXMLQuery, bstrQuery, &pNodeQuery)); QuitIfFail(CopyNode(pNodeQuery, pDocSOAPQuery, &pNodeQueryNew)); QuitIfFail(InsertNode(pNodeGetManifest, pNodeQueryNew));
CleanUp: if (FAILED(hr)) { LOG_ErrorMsg(hr); SafeReleaseNULL(pDocSOAPQuery); } SafeReleaseNULL(pNodeSOAPEnvelope); SafeReleaseNULL(pNodeSOAPBody); SafeReleaseNULL(pNodeGetManifest); SafeReleaseNULL(pNodeClientInfo); SafeReleaseNULL(pNodeClientInfoNew); SafeReleaseNULL(pNodeSystemInfo); SafeReleaseNULL(pNodeSystemInfoNew); SafeReleaseNULL(pNodeQuery); SafeReleaseNULL(pNodeQueryNew); SysFreeString(bstrNameSOAPEnvelope); SysFreeString(bstrNameSOAPBody); SysFreeString(bstrNameGetManifest); SysFreeString(bstrClientInfo); SysFreeString(bstrSystemInfo); SysFreeString(bstrQuery); SafeHeapFree(pszSOAPQuerySchema); SafeHeapFree(pszNameSpaceSchema); SysFreeString(bstrNameSpaceSchema); *ppSOAPQuery = pDocSOAPQuery; return hr; }
// Function name : ValidatePID
// Description : This function is used to check the return xml from the
// server in response to getmanifest calls.
// If the catalogStatus attribute is not present or is 0 then the pid validation succeeded
// If the catalogStatus attribute is 1 then an error is returned
// Return type : HRESULT
// Argument : IXMLDOMDocument *pXmlDomDocument
HRESULT ValidatePID(IXMLDOMDocument *pXmlDomDocument) { LOG_Block("ValidatePID()"); HRESULT hr = S_OK; IXMLDOMElement *pRootElement = NULL;
long lStatus = 0;
if(!pXmlDomDocument) { return E_INVALIDARG; }
BSTR bCatalogStatus = SysAllocString(L"catalogStatus");
if(!bCatalogStatus) { return E_OUTOFMEMORY; }
QuitIfFail( pXmlDomDocument->get_documentElement(&pRootElement) );
//get the catalogStatus attribute
QuitIfFail( GetAttribute( (IXMLDOMNode *)pRootElement, bCatalogStatus, &lStatus));
if(errorInvalidLicense == lStatus) hr = E_INVALID_PID;
CleanUp:
if(FAILED(hr)) LOG_ErrorMsg(hr);
//catalogStatus is an optional attribute. If it is not found we get the
//hresult as S_FALSE. So reset it to S_OK
if(S_FALSE == hr) hr = S_OK;
SafeReleaseNULL(pRootElement); SysFreeString(bCatalogStatus); return hr;
}
// Function name : PingInvalidPID
// Description : This function sends a ping message to the server
// to indicate failure of PID validation
// Return type : void
// Argument : BSTR bstrClientName
// Argument : HRESULT hRes
// Argument : HANDLE *phQuit
// Argument : DWORD dwNumHandles
void PingInvalidPID(BSTR bstrClientName, HRESULT hRes, HANDLE *phQuit, DWORD dwNumHandles) {
LOG_Block("PingInvalidPID()"); USES_IU_CONVERSION;
HRESULT hr = S_OK; URLLOGSTATUS status = URLLOGSTATUS_Declined; LPTSTR ptszLivePingServerUrl = NULL; LPTSTR ptszCorpPingServerUrl = NULL;
if (NULL != (ptszLivePingServerUrl = (LPTSTR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)))) { if (FAILED( g_pUrlAgent->GetLivePingServer(ptszLivePingServerUrl, INTERNET_MAX_URL_LENGTH) ) ) { SafeHeapFree(ptszLivePingServerUrl); } } else { LOG_Out(_T("failed to allocate memory for ptszLivePingServerUrl")); }
if (NULL != (ptszCorpPingServerUrl = (LPTSTR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)))) { if (FAILED(g_pUrlAgent->GetCorpPingServer(ptszCorpPingServerUrl, INTERNET_MAX_URL_LENGTH))) { LOG_Out(_T("failed to get corp WU ping server URL")); SafeHeapFree(ptszCorpPingServerUrl); } } else { LOG_Out(_T("failed to allocate memory for ptszCorpPingServerUrl")); }
LPTSTR lpClientName = NULL;
if(bstrClientName) { lpClientName = OLE2T(bstrClientName);
}
CUrlLog pingSvr(lpClientName, ptszLivePingServerUrl, ptszCorpPingServerUrl);
SafeHeapFree(ptszLivePingServerUrl); SafeHeapFree(ptszCorpPingServerUrl);
pingSvr.Ping(TRUE, // on-line
URLLOGDESTINATION_DEFAULT, // going live or corp WU ping server
phQuit, // pt to cancel events
dwNumHandles, // number of events
URLLOGACTIVITY_Download, // activity
status, // status code
hRes, NULL, NULL, g_szInvalidPID );
}
|