//======================================================================= // // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. // // File: manifest.cpp // // Description: // // Implementation for the GetManifest() function // //======================================================================= #include "iuengine.h" #include #include #include #include #include "schemamisc.h" #include "WaitUtil.h" #include "download.h" #include #include #include #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 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 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: // // // // ... // ... // ... // // // // ///////////////////////////////////////////////////////////////////////////// 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 ); }