Leaked source code of windows server 2003
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.

1073 lines
30 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: manifest.cpp
  6. //
  7. // Description:
  8. //
  9. // Implementation for the GetManifest() function
  10. //
  11. //=======================================================================
  12. #include "iuengine.h"
  13. #include <iucommon.h>
  14. #include <fileutil.h>
  15. #include <shlwapi.h>
  16. #include <wininet.h>
  17. #include "schemamisc.h"
  18. #include "WaitUtil.h"
  19. #include "download.h"
  20. #include <httprequest.h>
  21. #include <httprequest_i.c>
  22. #include <iuxml.h>
  23. #define QuitIfNull(p) {if (NULL == p) {hr = E_INVALIDARG; LOG_ErrorMsg(hr); return hr;}}
  24. #define QuitIfFail(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
  25. #define ERROR_INVALID_PID 100
  26. #define E_INVALID_PID MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,ERROR_INVALID_PID)
  27. #define errorInvalidLicense 1
  28. const TCHAR g_szInvalidPID[] = _T("The PID is invalid");
  29. const TCHAR IDENT_IUSCHEMA[] = _T("IUSchema");
  30. const TCHAR IDENT_IUSCHEMA_SOAPQUERY[] = _T("SOAPQuerySchema");
  31. const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerCache");
  32. const TCHAR IDENT_IUSERVERCOUNT[] = _T("ServerCount");
  33. const TCHAR IDENT_IUSERVER[] = _T("Server");
  34. const CHAR SZ_GET_MANIFEST[] = "Querying software update catalog from";
  35. const CHAR SZ_GET_MANIFEST_ERROR[] = "Querying software update catalog";
  36. HRESULT ValidatePID(IXMLDOMDocument *pXmlDomDocument);
  37. void PingInvalidPID(BSTR bstrClientName,HRESULT hRes,HANDLE *phQuit,DWORD dwNumHandles);
  38. /////////////////////////////////////////////////////////////////////////////
  39. // Function forward declarations
  40. /////////////////////////////////////////////////////////////////////////////
  41. HRESULT GetServerURL(IXMLDOMDocument *pXMLQuery, IXMLDOMDocument *pXMLClientInfo, LPTSTR *ppszURL);
  42. HRESULT GetSOAPQuery(IXMLDOMDocument *pXMLClientInfo, IXMLDOMDocument *pXMLSystemSpec,
  43. IXMLDOMDocument *pXMLQuery, IXMLDOMDocument **ppSOAPQuery);
  44. /////////////////////////////////////////////////////////////////////////////
  45. // GetManifest()
  46. //
  47. // Gets a catalog base on the specified information.
  48. // Input:
  49. // bstrXmlClientInfo - the credentials of the client in xml format
  50. // bstrXmlSystemSpec - the detected system specifications in xml
  51. // bstrXmlQuery - the user query infomation in xml
  52. // Return:
  53. // pbstrXmlCatalog - the xml catalog retrieved
  54. /////////////////////////////////////////////////////////////////////////////
  55. HRESULT WINAPI CEngUpdate::GetManifest(BSTR bstrXmlClientInfo,
  56. BSTR bstrXmlSystemSpec,
  57. BSTR bstrXmlQuery,
  58. DWORD dwFlags,
  59. BSTR *pbstrXmlCatalog)
  60. {
  61. LOG_Block("GetManifest()");
  62. // clear any previous cancel event
  63. ResetEvent(m_evtNeedToQuit);
  64. USES_IU_CONVERSION;
  65. HRESULT hr = E_FAIL;
  66. CXmlClientInfo xmlClientInfo;
  67. IXMLDOMDocument *pXMLSystemSpec = NULL;
  68. IXMLDOMDocument *pXMLQuery = NULL;
  69. IXMLDOMDocument *pSOAPQuery = NULL;
  70. IXMLHttpRequest *pIXMLHttpRequest = NULL;
  71. IWinHttpRequest *pWinHttpRequest = NULL;
  72. BSTR bstrXmlSOAPQuery = NULL;
  73. BSTR bstrPOST = NULL, bstrURL = NULL;
  74. BSTR bstrClientName = NULL;
  75. LPTSTR pszURL = NULL;
  76. LONG lCount = 0;
  77. MSG msg;
  78. DWORD dwRet;
  79. BOOL fDontAllowProxy = FALSE;
  80. SAUProxySettings pauProxySettings;
  81. ZeroMemory(&pauProxySettings, sizeof(SAUProxySettings));
  82. //
  83. // load the DOM Doc for Query, ClientInfo, SystemSpec respectively
  84. //
  85. LOG_XmlBSTR(bstrXmlQuery);
  86. hr = LoadXMLDoc(bstrXmlQuery, &pXMLQuery, FALSE);
  87. CleanUpIfFailedAndMsg(hr);
  88. LOG_XmlBSTR(bstrXmlClientInfo);
  89. hr = xmlClientInfo.LoadXMLDocument(bstrXmlClientInfo, FALSE);
  90. CleanUpIfFailedAndMsg(hr);
  91. CleanUpIfFailedAndSetHrMsg(xmlClientInfo.GetClientName(&bstrClientName));
  92. CleanUpIfFailedAndSetHrMsg(g_pUrlAgent->IsClientSpecifiedByPolicy(OLE2T(bstrClientName)));
  93. //
  94. // Set flag to NOT set proxy for WinHTTP
  95. //
  96. if (S_FALSE ==hr)
  97. {
  98. fDontAllowProxy = FALSE;
  99. hr = S_OK;
  100. }
  101. else // S_OK
  102. {
  103. fDontAllowProxy = TRUE;
  104. }
  105. //
  106. // we treat bstrXmlSystemSpec as optional
  107. //
  108. if (NULL != bstrXmlSystemSpec && SysStringLen(bstrXmlSystemSpec) > 0)
  109. {
  110. LOG_XmlBSTR(bstrXmlSystemSpec);
  111. hr = LoadXMLDoc(bstrXmlSystemSpec, &pXMLSystemSpec, FALSE);
  112. CleanUpIfFailedAndMsg(hr);
  113. }
  114. //
  115. // retrieve the ServerCache URL from the Query xml doc and validate it
  116. //
  117. hr = GetServerURL(pXMLQuery, xmlClientInfo.GetDocument(), &pszURL);
  118. CleanUpIfFailedAndMsg(hr);
  119. //
  120. // concatenate the above several xml client input into a single XML
  121. // with the SOAP syntax/format that the server recognizes
  122. //
  123. hr = GetSOAPQuery(xmlClientInfo.GetDocument(), pXMLSystemSpec, pXMLQuery, &pSOAPQuery);
  124. if (FAILED(hr))
  125. {
  126. LOG_ErrorMsg(hr);
  127. goto CleanUp;
  128. }
  129. #if defined(DBG)
  130. else
  131. {
  132. BSTR bstrSOAPQuery = NULL;
  133. pSOAPQuery->get_xml(&bstrSOAPQuery);
  134. LOG_XmlBSTR(bstrSOAPQuery);
  135. SafeSysFreeString(bstrSOAPQuery);
  136. }
  137. #endif
  138. //
  139. // change again: add WINHTTP support for AU running as a service;
  140. // use GetAllowedDownloadTransport(0) to determine -
  141. // 1) 0 == try winhttp first & if that fails, try wininet.
  142. // 2) WUDF_ALLOWWINHTTPONLY == only try winhttp. never fall back on wininet.
  143. // 3) WUDF_ALLOWWININETONLY == only try wininet. never use winhttp.
  144. //
  145. // in WINHTTP the compression is not supported yet at this time;
  146. // in WININET we removed the compression support at this point due to a bug in URLMON (< IE6.0).
  147. //
  148. // in both cases we use asynchronized sending in order to abort timely for a cancel event
  149. //
  150. BOOL fLoadWINHTTP = FALSE;
  151. DWORD dwTransportFlag = GetAllowedDownloadTransport(0);
  152. if ((0 == dwTransportFlag) || (WUDF_ALLOWWINHTTPONLY == dwTransportFlag))
  153. {
  154. hr = CoCreateInstance(CLSID_WinHttpRequest,
  155. NULL,
  156. CLSCTX_INPROC_SERVER,
  157. IID_IWinHttpRequest,
  158. (void **) &pWinHttpRequest);
  159. if (SUCCEEDED(hr))
  160. {
  161. BOOL fRetry = FALSE;
  162. bstrURL = SysAllocString(T2OLE(pszURL));
  163. fLoadWINHTTP = TRUE;
  164. VARIANT vProxyServer, vBypassList;
  165. hr = GetAUProxySettings(bstrURL, &pauProxySettings);
  166. CleanUpIfFailedAndMsg(hr);
  167. DWORD iProxy = pauProxySettings.iProxy;
  168. if (-1 == iProxy)
  169. pauProxySettings.iProxy = iProxy = 0;
  170. //
  171. // open request
  172. //
  173. VARIANT vBool;
  174. vBool.vt = VT_BOOL;
  175. vBool.boolVal = VARIANT_TRUE;
  176. bstrPOST = SysAllocString(L"POST");
  177. Retry:
  178. hr = pWinHttpRequest->Open(bstrPOST, // HTTP method: "POST"
  179. bstrURL, // requested URL
  180. vBool); // asynchronous operation
  181. CleanUpIfFailedAndMsg(hr);
  182. //
  183. // For SSL URLs, set the WinHttpRequestOption_SslErrorIgnoreFlags
  184. // option to zero so that no server certificate errors are ignored.
  185. //
  186. // The default at the time this code was written was 0x3300, which
  187. // means ignore all server certificate errors. Using this default
  188. // would significantly reduce security in various ways; for example
  189. // if the 0x0100 bit was set, WinHttp would trust certificates from
  190. // any root certificate authority, even it it was not in the list of
  191. // trusted CAs.
  192. //
  193. // Note that at the time this code was written, the WinHttp
  194. // documentation made no mention of Certificate Revocation List
  195. // checking. It is assumed that the default CRL behavior
  196. // implemented by WinHttp will provide adequate security and
  197. // performance.
  198. //
  199. if ((_T('H') == pszURL[0] || _T('h') == pszURL[0]) && // Sorry, this is simpler than using a function.
  200. (_T('T') == pszURL[1] || _T('t') == pszURL[1]) &&
  201. (_T('T') == pszURL[2] || _T('t') == pszURL[2]) &&
  202. (_T('P') == pszURL[3] || _T('p') == pszURL[3]) &&
  203. (_T('S') == pszURL[4] || _T('s') == pszURL[4]) &&
  204. _T(':') == pszURL[5])
  205. {
  206. VARIANT vOption;
  207. VariantInit(&vOption);
  208. vOption.vt = VT_I4;
  209. vOption.lVal = 0;
  210. hr = pWinHttpRequest->put_Option(WinHttpRequestOption_SslErrorIgnoreFlags, vOption);
  211. VariantClear(&vOption);
  212. CleanUpIfFailedAndMsg(hr);
  213. }
  214. if (TRUE == fDontAllowProxy)
  215. {
  216. LOG_Internet(_T("Don't set the proxy due to policy"));
  217. }
  218. else
  219. {
  220. //
  221. // set proxy
  222. //
  223. VariantInit(&vProxyServer);
  224. VariantInit(&vBypassList);
  225. BOOL fSetProxy = TRUE;
  226. if (pauProxySettings.rgwszProxies != NULL)
  227. {
  228. vProxyServer.vt = VT_BSTR;
  229. vProxyServer.bstrVal = SysAllocString(pauProxySettings.rgwszProxies[iProxy]);
  230. }
  231. else if (pauProxySettings.rgwszProxies == NULL)
  232. {
  233. fSetProxy = FALSE;
  234. }
  235. if (pauProxySettings.wszBypass != NULL)
  236. {
  237. vBypassList.vt = VT_BSTR;
  238. vBypassList.bstrVal = SysAllocString(pauProxySettings.wszBypass);
  239. }
  240. if (fSetProxy)
  241. {
  242. hr = pWinHttpRequest->SetProxy(HTTPREQUEST_PROXYSETTING_PROXY, vProxyServer, vBypassList);
  243. }
  244. VariantClear(&vProxyServer);
  245. VariantClear(&vBypassList);
  246. CleanUpIfFailedAndMsg(hr);
  247. }
  248. //
  249. // send request
  250. //
  251. VARIANT vQuery;
  252. vQuery.vt = VT_UNKNOWN;
  253. vQuery.punkVal = pSOAPQuery;
  254. hr = pWinHttpRequest->Send(vQuery);
  255. if (FAILED(hr))
  256. {
  257. LOG_Internet(_T("WinHttpRequest: Send failed: 0x%08x"), hr);
  258. fRetry = TRUE;
  259. goto getNextProxyForRetry;
  260. }
  261. //
  262. // check if quit or completion every 1/4 second
  263. //
  264. VARIANT vTimeOut;
  265. vTimeOut.vt = VT_I4;
  266. vTimeOut.lVal = 0;
  267. VARIANT_BOOL fSuccess = VARIANT_FALSE;
  268. hr = pWinHttpRequest->WaitForResponse(vTimeOut, &fSuccess);
  269. if (FAILED(hr))
  270. {
  271. LOG_Internet(_T("WinHttpRequest: WaitForResponse failed: 0x%08x"), hr);
  272. fRetry = TRUE;
  273. goto getNextProxyForRetry;
  274. }
  275. // we wait up to 30 sec (120*250 ms)
  276. lCount = 0;
  277. while (!fSuccess && lCount <120)
  278. {
  279. lCount++;
  280. //
  281. // Wait for 250ms while pumping messages, but return if m_evtNeedToQuit signaled
  282. //
  283. dwRet = MyMsgWaitForMultipleObjects(1, &m_evtNeedToQuit, FALSE, 250, QS_ALLINPUT);
  284. if (WAIT_TIMEOUT != dwRet)
  285. {
  286. //
  287. // Either the event was signaled or a message being pumped says quit
  288. //
  289. pWinHttpRequest->Abort();
  290. hr = E_ABORT;
  291. goto CleanUp;
  292. }
  293. hr = pWinHttpRequest->WaitForResponse(vTimeOut, &fSuccess);
  294. if (FAILED(hr))
  295. {
  296. LOG_Internet(_T("WinHttpRequest: WaitForResponse failed: 0x%08x"), hr);
  297. fRetry = TRUE;
  298. goto getNextProxyForRetry;
  299. }
  300. }
  301. //
  302. // check the HTTP status code returned by a request
  303. //
  304. LONG lStatus = HTTP_STATUS_OK;// 200
  305. hr = pWinHttpRequest->get_Status(&lStatus);
  306. if (FAILED(hr))
  307. {
  308. LOG_Internet(_T("WinHttpRequest: get_Status failed: 0x%08x"), hr);
  309. fRetry = TRUE;
  310. goto getNextProxyForRetry;
  311. }
  312. fRetry = FALSE;
  313. if (!fSuccess)
  314. {
  315. // time out
  316. hr = E_FAIL;
  317. fRetry = TRUE;
  318. }
  319. else if (HTTP_STATUS_OK != lStatus)
  320. {
  321. // COMPLETED, but error in status
  322. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_HTTP, lStatus);
  323. LOG_ErrorMsg(hr);
  324. fRetry = TRUE;
  325. }
  326. else
  327. {
  328. //
  329. // get response
  330. //
  331. hr = pWinHttpRequest->get_ResponseText(pbstrXmlCatalog);
  332. CleanUpIfFailedAndMsg(hr);
  333. //
  334. // verify the response is a well-formed XML document
  335. //
  336. IXMLDOMDocument *pXMLDoc = NULL;
  337. hr = LoadXMLDoc(*pbstrXmlCatalog, &pXMLDoc);
  338. if(SUCCEEDED(hr))
  339. {
  340. hr=ValidatePID(pXMLDoc);
  341. if(FAILED(hr))
  342. {
  343. PingInvalidPID(bstrClientName,hr,&m_evtNeedToQuit,1);
  344. LogError(hr,"Validation of PID failed");
  345. }
  346. //The Banned PID case is not a failure for the GetManifest call.
  347. if(E_INVALID_PID == hr)
  348. {
  349. hr = S_OK;
  350. }
  351. }
  352. SafeReleaseNULL(pXMLDoc);
  353. CleanUpIfFailedAndMsg(hr);
  354. }
  355. getNextProxyForRetry:
  356. if (fRetry && !fDontAllowProxy)
  357. {
  358. if (pauProxySettings.cProxies > 1 && pauProxySettings.rgwszProxies != NULL)
  359. {
  360. iProxy = ( iProxy + 1) % pauProxySettings.cProxies;
  361. }
  362. if (iProxy != pauProxySettings.iProxy)
  363. {
  364. LogError(hr, "Will retry.");
  365. pWinHttpRequest->Abort();
  366. goto Retry;
  367. }
  368. else
  369. {
  370. LogError(hr, "Already tried all proxies. Will not retry.");
  371. }
  372. }
  373. }
  374. else
  375. {
  376. if (WUDF_ALLOWWINHTTPONLY == dwTransportFlag)
  377. {
  378. CleanUpIfFailedAndMsg(hr);
  379. }
  380. }
  381. }
  382. if ((0 == dwTransportFlag && !fLoadWINHTTP) || (WUDF_ALLOWWININETONLY == dwTransportFlag))
  383. {
  384. //
  385. // 475506 W2K: IU - IU control's GetManifest method call fails on all subsequent
  386. // calls after the first. - On Win 2K Only
  387. //
  388. // We no longer take the FLAG_USE_COMPRESSION into account for WinInet since we
  389. // previously used URLMON and there are bugs that would require a rewrite of
  390. // xmlhttp.* to fix and we haven't been using compression on the live site to date.
  391. //
  392. LOG_Internet(_T("GetManifest using WININET.DLL"));
  393. //
  394. // create an XMLHttpRequest object
  395. //
  396. hr = CoCreateInstance(CLSID_XMLHTTPRequest,
  397. NULL,
  398. CLSCTX_INPROC_SERVER,
  399. IID_IXMLHttpRequest,
  400. (void **) &pIXMLHttpRequest);
  401. CleanUpIfFailedAndMsg(hr);
  402. //
  403. // open request
  404. //
  405. VARIANT vEmpty, vBool;
  406. vEmpty.vt = VT_EMPTY;
  407. vBool.vt = VT_BOOL;
  408. vBool.boolVal= VARIANT_FALSE;
  409. bstrPOST = SysAllocString(L"POST");
  410. bstrURL = SysAllocString(T2OLE(pszURL));
  411. hr = pIXMLHttpRequest->open(bstrPOST, // HTTP method: "POST"
  412. bstrURL, // requested URL
  413. vBool, // synchronous operation
  414. vEmpty, // user for authentication (no authentication for V1.0)
  415. vEmpty); // pswd for authentication
  416. CleanUpIfFailedAndMsg(hr);
  417. //
  418. // send request
  419. //
  420. VARIANT vQuery;
  421. vQuery.vt = VT_UNKNOWN;
  422. vQuery.punkVal = pSOAPQuery;
  423. hr = pIXMLHttpRequest->send(vQuery);
  424. CleanUpIfFailedAndMsg(hr);
  425. //
  426. // check the HTTP status code returned by a request
  427. //
  428. LONG lResultStatus = HTTP_STATUS_OK;// 200
  429. hr = pIXMLHttpRequest->get_status(&lResultStatus);
  430. CleanUpIfFailedAndMsg(hr);
  431. if (HTTP_STATUS_OK != lResultStatus)
  432. {
  433. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_HTTP, lResultStatus);
  434. LOG_ErrorMsg(hr);
  435. }
  436. else
  437. {
  438. //
  439. // get response
  440. //
  441. hr = pIXMLHttpRequest->get_responseText(pbstrXmlCatalog);
  442. CleanUpIfFailedAndMsg(hr);
  443. //
  444. // verify the response is a well-formed XML document
  445. //
  446. IXMLDOMDocument *pXMLDoc = NULL;
  447. hr = LoadXMLDoc(*pbstrXmlCatalog, &pXMLDoc);
  448. if(SUCCEEDED(hr))
  449. {
  450. hr=ValidatePID(pXMLDoc);
  451. if(FAILED(hr))
  452. {
  453. PingInvalidPID(bstrClientName,hr,&m_evtNeedToQuit,1);
  454. LogError(hr,"Validation of PID failed");
  455. }
  456. //The Banned pid case is not a failure for the GetManifest call
  457. if(E_INVALID_PID == hr)
  458. {
  459. hr = S_OK;
  460. }
  461. }
  462. SafeReleaseNULL(pXMLDoc);
  463. CleanUpIfFailedAndMsg(hr);
  464. }
  465. }
  466. CleanUp:
  467. if (SUCCEEDED(hr))
  468. {
  469. #if defined(UNICODE) || defined(_UNICODE)
  470. LogMessage("%s %ls", SZ_GET_MANIFEST, pszURL);
  471. #else
  472. LogMessage("%s %s", SZ_GET_MANIFEST, pszURL);
  473. #endif
  474. }
  475. else
  476. {
  477. if (NULL == pszURL)
  478. {
  479. LogError(hr, SZ_GET_MANIFEST_ERROR);
  480. }
  481. else
  482. {
  483. #if defined(UNICODE) || defined(_UNICODE)
  484. LogError(hr, "%s %ls", SZ_GET_MANIFEST, pszURL);
  485. #else
  486. LogError(hr, "%s %s", SZ_GET_MANIFEST, pszURL);
  487. #endif
  488. }
  489. }
  490. if (NULL != pszURL)
  491. HeapFree(GetProcessHeap(), 0, pszURL);
  492. SafeReleaseNULL(pXMLSystemSpec);
  493. SafeReleaseNULL(pXMLQuery);
  494. SafeReleaseNULL(pSOAPQuery);
  495. SafeReleaseNULL(pIXMLHttpRequest);
  496. SafeReleaseNULL(pWinHttpRequest);
  497. SysFreeString(bstrPOST);
  498. SysFreeString(bstrURL);
  499. SysFreeString(bstrXmlSOAPQuery);
  500. SysFreeString(bstrClientName);
  501. FreeAUProxySettings(&pauProxySettings);
  502. return hr;
  503. }
  504. /////////////////////////////////////////////////////////////////////////////
  505. // GetServerURL()
  506. //
  507. // Retrieve the ServerCache URL from the Query xml doc and validate that
  508. // URL against the ServerCache URLs in iuident.txt.
  509. // Return:
  510. // ppszURL - the ServerCache URL path pointer
  511. /////////////////////////////////////////////////////////////////////////////
  512. HRESULT GetServerURL(IXMLDOMDocument *pXMLQuery, IXMLDOMDocument *pXMLClientInfo, LPTSTR *ppszURL)
  513. {
  514. LOG_Block("GetServerURL()");
  515. USES_IU_CONVERSION;
  516. HRESULT hr = E_FAIL;
  517. if ((NULL == pXMLQuery) || (NULL == pXMLClientInfo) || (NULL == ppszURL))
  518. {
  519. LOG_ErrorMsg(E_INVALIDARG);
  520. return E_INVALIDARG;
  521. }
  522. IXMLDOMNode* pQueryNode = NULL;
  523. IXMLDOMNode* pQueryClient = NULL;
  524. BSTR bstrQuery = SysAllocString(L"query");
  525. BSTR bstrHref = SysAllocString(L"href");
  526. BSTR bstrClientInfo = SysAllocString(L"clientInfo");
  527. BSTR bstrClientName = SysAllocString(L"clientName");
  528. BSTR bstrURL = NULL, bstrClient = NULL;
  529. LPTSTR pszURL = NULL;
  530. INT iServerCnt;
  531. BOOL fInternalServer = FALSE;
  532. QuitIfFail(FindSingleDOMNode(pXMLClientInfo, bstrClientInfo, &pQueryClient));
  533. QuitIfFail(GetAttribute(pQueryClient, bstrClientName, &bstrClient));
  534. pszURL = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  535. CleanUpFailedAllocSetHrMsg(pszURL);
  536. //
  537. // failure in "g_pUrlAgent = new CUrlAgent"
  538. //
  539. CleanUpFailedAllocSetHrMsg(g_pUrlAgent);
  540. QuitIfFail(g_pUrlAgent->GetQueryServer(OLE2T(bstrClient), pszURL, INTERNET_MAX_URL_LENGTH, &fInternalServer));
  541. if (fInternalServer)
  542. {
  543. //
  544. // we have policy override for this client, set the query url as WUServer in policy
  545. //
  546. *ppszURL = pszURL;
  547. hr = S_OK;
  548. }
  549. else
  550. {
  551. //
  552. // we don't have policy override for this client;
  553. //
  554. // find the ServerCache URL from <query> node
  555. //
  556. QuitIfFail(FindSingleDOMNode(pXMLQuery, bstrQuery, &pQueryNode));
  557. if (SUCCEEDED(GetAttribute(pQueryNode, bstrHref, &bstrURL))
  558. && NULL != bstrURL && SysStringLen(bstrURL) >0)
  559. {
  560. //
  561. // this is the case that the query specified the serverl url, we need
  562. // to do the validation for the url here...
  563. //
  564. // pszURL is alloced to be INTERNET_MAX_URL_LENGTH above.
  565. hr = StringCchCopyEx(pszURL, INTERNET_MAX_URL_LENGTH, OLE2T(bstrURL),
  566. NULL, NULL, MISTSAFE_STRING_FLAGS);
  567. if (FAILED(hr))
  568. {
  569. LOG_ErrorMsg(hr);
  570. goto CleanUp;
  571. }
  572. //
  573. // process the iuident.txt to find all valid ServerCache URLs
  574. //
  575. TCHAR szIUDir[MAX_PATH];
  576. TCHAR szIdentFile[MAX_PATH];
  577. GetIndustryUpdateDirectory(szIUDir);
  578. hr = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir, IDENTTXT);
  579. if (FAILED(hr))
  580. {
  581. LOG_ErrorMsg(hr);
  582. goto CleanUp;
  583. }
  584. iServerCnt = GetPrivateProfileInt(IDENT_IUSERVERCACHE,
  585. IDENT_IUSERVERCOUNT,
  586. -1,
  587. szIdentFile);
  588. if (-1 == iServerCnt)
  589. {
  590. // no ServerCount number specified in iuident.txt
  591. LOG_Error(_T("No ServerCount number specified in iuident.txt"));
  592. hr = E_FAIL;
  593. goto CleanUp;
  594. }
  595. hr = INET_E_INVALID_URL;
  596. for (INT i=1; i<=iServerCnt; i++)
  597. {
  598. TCHAR szValidURL[INTERNET_MAX_URL_LENGTH];
  599. TCHAR szServer[32];
  600. hr = StringCchPrintfEx(szServer, ARRAYSIZE(szServer), NULL, NULL, MISTSAFE_STRING_FLAGS,
  601. _T("%s%d"), IDENT_IUSERVER, i);
  602. if (FAILED(hr))
  603. {
  604. LOG_ErrorMsg(hr);
  605. goto CleanUp;
  606. }
  607. hr = INET_E_INVALID_URL;
  608. GetPrivateProfileString(IDENT_IUSERVERCACHE,
  609. szServer,
  610. _T(""),
  611. szValidURL,
  612. ARRAYSIZE(szValidURL),
  613. szIdentFile);
  614. if ('\0' == szValidURL[0])
  615. {
  616. // no ServerCache URL specified in iuident.txt for this server
  617. LOG_Error(_T("No ServerCache URL specified in iuident.txt for %s%d"), IDENT_IUSERVER, i);
  618. hr = E_FAIL;
  619. goto CleanUp;
  620. }
  621. if (0 == lstrcmpi(szValidURL, pszURL))
  622. {
  623. // it's a valid ServerCache URL
  624. *ppszURL = pszURL;
  625. hr = S_OK;
  626. break;
  627. }
  628. }
  629. }
  630. else
  631. {
  632. //
  633. // this is the case that the query didn't specify the serverl url, we just use the
  634. // server url that was found through g_pUrlAgent according to the clientName.
  635. //
  636. // now insert the URL into the <query> node
  637. //
  638. BSTR bstrTemp = T2BSTR(pszURL);
  639. QuitIfFail(SetAttribute(pQueryNode, bstrHref, bstrTemp));
  640. SafeSysFreeString(bstrTemp);
  641. *ppszURL = pszURL;
  642. }
  643. }
  644. CleanUp:
  645. if (FAILED(hr))
  646. {
  647. HeapFree(GetProcessHeap(), 0, pszURL);
  648. *ppszURL = NULL;
  649. LOG_ErrorMsg(hr);
  650. }
  651. SafeReleaseNULL(pQueryNode);
  652. SafeReleaseNULL(pQueryClient);
  653. SysFreeString(bstrQuery);
  654. SysFreeString(bstrHref);
  655. SysFreeString(bstrURL);
  656. SysFreeString(bstrClientInfo);
  657. SysFreeString(bstrClientName);
  658. SysFreeString(bstrClient);
  659. return hr;
  660. }
  661. /////////////////////////////////////////////////////////////////////////////
  662. // GetSOAPQuery()
  663. //
  664. // Concatenate the several xml client input into a single XML
  665. // with the SOAP syntax/format that the server recognizes
  666. // Input:
  667. // pXMLClientInfo - the credentials of the client in DOM Doc format
  668. // pXMLSystemSpec - the detected system specifications in DOM Doc
  669. // pXMLQuery - the user query infomation in DOM Doc
  670. // Return:
  671. // ppSOAPQuery - the concatenated query in DOM Doc with required SOAP syntax
  672. //
  673. // SOAPQuery xml doc example:
  674. // <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
  675. // <SOAP:Body>
  676. // <GetManifest>
  677. // <clientInfo>...</clientInfo>
  678. // <systemSpec>...</systemSpec>
  679. // <query href="//windowsupdate.microsoft.com/servecache.asp">...</query>
  680. // </GetManifest>
  681. // </SOAP:Body>
  682. // </SOAP:Envelope>
  683. //
  684. /////////////////////////////////////////////////////////////////////////////
  685. HRESULT GetSOAPQuery(IXMLDOMDocument *pXMLClientInfo,
  686. IXMLDOMDocument *pXMLSystemSpec,
  687. IXMLDOMDocument *pXMLQuery,
  688. IXMLDOMDocument **ppSOAPQuery)
  689. {
  690. LOG_Block("GetSOAPQuery()");
  691. USES_IU_CONVERSION;
  692. HRESULT hr = E_FAIL;
  693. IXMLDOMDocument* pDocSOAPQuery = NULL;
  694. IXMLDOMNode* pNodeSOAPEnvelope = NULL;
  695. IXMLDOMNode* pNodeSOAPBody = NULL;
  696. IXMLDOMNode* pNodeGetManifest = NULL;
  697. IXMLDOMNode* pNodeClientInfo = NULL;
  698. IXMLDOMNode* pNodeClientInfoNew = NULL;
  699. IXMLDOMNode* pNodeSystemInfo = NULL;
  700. IXMLDOMNode* pNodeSystemInfoNew = NULL;
  701. IXMLDOMNode* pNodeQuery = NULL;
  702. IXMLDOMNode* pNodeQueryNew = NULL;
  703. BSTR bstrNameSOAPEnvelope = SysAllocString(L"SOAP:Envelope");
  704. BSTR bstrNameSOAPBody = SysAllocString(L"SOAP:Body");
  705. BSTR bstrNameGetManifest = SysAllocString(L"GetManifest");
  706. BSTR bstrClientInfo = SysAllocString(L"clientInfo");
  707. BSTR bstrSystemInfo = SysAllocString(L"systemInfo");
  708. BSTR bstrQuery = SysAllocString(L"query");
  709. BSTR bstrNameSpaceSchema = NULL;
  710. //
  711. // process the iuident.txt to find the SOAPQuery schema path
  712. //
  713. TCHAR szIUDir[MAX_PATH];
  714. TCHAR szIdentFile[MAX_PATH];
  715. LPTSTR pszSOAPQuerySchema = NULL;
  716. LPTSTR pszNameSpaceSchema = NULL;
  717. pszSOAPQuerySchema = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  718. if (NULL == pszSOAPQuerySchema)
  719. {
  720. hr = E_OUTOFMEMORY;
  721. LOG_ErrorMsg(hr);
  722. goto CleanUp;
  723. }
  724. pszNameSpaceSchema = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  725. if (NULL == pszNameSpaceSchema)
  726. {
  727. hr = E_OUTOFMEMORY;
  728. LOG_ErrorMsg(hr);
  729. goto CleanUp;
  730. }
  731. GetIndustryUpdateDirectory(szIUDir);
  732. hr = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir, IDENTTXT);
  733. if (FAILED(hr))
  734. {
  735. LOG_ErrorMsg(hr);
  736. goto CleanUp;
  737. }
  738. GetPrivateProfileString(IDENT_IUSCHEMA,
  739. IDENT_IUSCHEMA_SOAPQUERY,
  740. _T(""),
  741. pszSOAPQuerySchema,
  742. INTERNET_MAX_URL_LENGTH,
  743. szIdentFile);
  744. if ('\0' == pszSOAPQuerySchema[0])
  745. {
  746. // no SOAPQuery schema path specified in iuident.txt
  747. LOG_Error(_T("No schema path specified in iuident.txt for SOAPQuery"));
  748. hr = E_FAIL;
  749. goto CleanUp;
  750. }
  751. // pszNameSpaceSchema is alloced to be INTERNET_MAX_URL_LENGTH above
  752. hr = StringCchPrintfEx(pszNameSpaceSchema, INTERNET_MAX_URL_LENGTH, NULL, NULL, MISTSAFE_STRING_FLAGS,
  753. _T("x-schema:%s"), pszSOAPQuerySchema);
  754. if (FAILED(hr))
  755. {
  756. LOG_ErrorMsg(hr);
  757. goto CleanUp;
  758. }
  759. bstrNameSpaceSchema = T2BSTR(pszNameSpaceSchema);
  760. //
  761. // construct the SOAPQuery xml
  762. //
  763. QuitIfFail(CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void **)&pDocSOAPQuery));
  764. pNodeSOAPEnvelope = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameSOAPEnvelope, bstrNameSpaceSchema);
  765. if (NULL == pNodeSOAPEnvelope) goto CleanUp;
  766. QuitIfFail(InsertNode(pDocSOAPQuery, pNodeSOAPEnvelope));
  767. pNodeSOAPBody = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameSOAPBody, bstrNameSpaceSchema);
  768. if (NULL == pNodeSOAPBody) goto CleanUp;
  769. QuitIfFail(InsertNode(pNodeSOAPEnvelope, pNodeSOAPBody));
  770. pNodeGetManifest = CreateDOMNode(pDocSOAPQuery, NODE_ELEMENT, bstrNameGetManifest);
  771. if (NULL == pNodeGetManifest) goto CleanUp;
  772. QuitIfFail(InsertNode(pNodeSOAPBody, pNodeGetManifest));
  773. if (NULL != pXMLClientInfo)
  774. {
  775. QuitIfFail(FindSingleDOMNode(pXMLClientInfo, bstrClientInfo, &pNodeClientInfo));
  776. QuitIfFail(CopyNode(pNodeClientInfo, pDocSOAPQuery, &pNodeClientInfoNew));
  777. QuitIfFail(InsertNode(pNodeGetManifest, pNodeClientInfoNew));
  778. }
  779. if (NULL != pXMLSystemSpec)
  780. {
  781. QuitIfFail(FindSingleDOMNode(pXMLSystemSpec, bstrSystemInfo, &pNodeSystemInfo));
  782. QuitIfFail(CopyNode(pNodeSystemInfo, pDocSOAPQuery, &pNodeSystemInfoNew));
  783. QuitIfFail(InsertNode(pNodeGetManifest, pNodeSystemInfoNew));
  784. }
  785. QuitIfFail(FindSingleDOMNode(pXMLQuery, bstrQuery, &pNodeQuery));
  786. QuitIfFail(CopyNode(pNodeQuery, pDocSOAPQuery, &pNodeQueryNew));
  787. QuitIfFail(InsertNode(pNodeGetManifest, pNodeQueryNew));
  788. CleanUp:
  789. if (FAILED(hr))
  790. {
  791. LOG_ErrorMsg(hr);
  792. SafeReleaseNULL(pDocSOAPQuery);
  793. }
  794. SafeReleaseNULL(pNodeSOAPEnvelope);
  795. SafeReleaseNULL(pNodeSOAPBody);
  796. SafeReleaseNULL(pNodeGetManifest);
  797. SafeReleaseNULL(pNodeClientInfo);
  798. SafeReleaseNULL(pNodeClientInfoNew);
  799. SafeReleaseNULL(pNodeSystemInfo);
  800. SafeReleaseNULL(pNodeSystemInfoNew);
  801. SafeReleaseNULL(pNodeQuery);
  802. SafeReleaseNULL(pNodeQueryNew);
  803. SysFreeString(bstrNameSOAPEnvelope);
  804. SysFreeString(bstrNameSOAPBody);
  805. SysFreeString(bstrNameGetManifest);
  806. SysFreeString(bstrClientInfo);
  807. SysFreeString(bstrSystemInfo);
  808. SysFreeString(bstrQuery);
  809. SafeHeapFree(pszSOAPQuerySchema);
  810. SafeHeapFree(pszNameSpaceSchema);
  811. SysFreeString(bstrNameSpaceSchema);
  812. *ppSOAPQuery = pDocSOAPQuery;
  813. return hr;
  814. }
  815. // Function name : ValidatePID
  816. // Description : This function is used to check the return xml from the
  817. // server in response to getmanifest calls.
  818. // If the catalogStatus attribute is not present or is 0 then the pid validation succeeded
  819. // If the catalogStatus attribute is 1 then an error is returned
  820. // Return type : HRESULT
  821. // Argument : IXMLDOMDocument *pXmlDomDocument
  822. HRESULT ValidatePID(IXMLDOMDocument *pXmlDomDocument)
  823. {
  824. LOG_Block("ValidatePID()");
  825. HRESULT hr = S_OK;
  826. IXMLDOMElement *pRootElement = NULL;
  827. long lStatus = 0;
  828. if(!pXmlDomDocument)
  829. {
  830. return E_INVALIDARG;
  831. }
  832. BSTR bCatalogStatus = SysAllocString(L"catalogStatus");
  833. if(!bCatalogStatus)
  834. {
  835. return E_OUTOFMEMORY;
  836. }
  837. QuitIfFail( pXmlDomDocument->get_documentElement(&pRootElement) );
  838. //get the catalogStatus attribute
  839. QuitIfFail( GetAttribute( (IXMLDOMNode *)pRootElement, bCatalogStatus, &lStatus));
  840. if(errorInvalidLicense == lStatus)
  841. hr = E_INVALID_PID;
  842. CleanUp:
  843. if(FAILED(hr))
  844. LOG_ErrorMsg(hr);
  845. //catalogStatus is an optional attribute. If it is not found we get the
  846. //hresult as S_FALSE. So reset it to S_OK
  847. if(S_FALSE == hr)
  848. hr = S_OK;
  849. SafeReleaseNULL(pRootElement);
  850. SysFreeString(bCatalogStatus);
  851. return hr;
  852. }
  853. // Function name : PingInvalidPID
  854. // Description : This function sends a ping message to the server
  855. // to indicate failure of PID validation
  856. // Return type : void
  857. // Argument : BSTR bstrClientName
  858. // Argument : HRESULT hRes
  859. // Argument : HANDLE *phQuit
  860. // Argument : DWORD dwNumHandles
  861. void PingInvalidPID(BSTR bstrClientName, HRESULT hRes, HANDLE *phQuit, DWORD dwNumHandles)
  862. {
  863. LOG_Block("PingInvalidPID()");
  864. USES_IU_CONVERSION;
  865. HRESULT hr = S_OK;
  866. URLLOGSTATUS status = URLLOGSTATUS_Declined;
  867. LPTSTR ptszLivePingServerUrl = NULL;
  868. LPTSTR ptszCorpPingServerUrl = NULL;
  869. if (NULL != (ptszLivePingServerUrl = (LPTSTR)HeapAlloc(
  870. GetProcessHeap(),
  871. HEAP_ZERO_MEMORY,
  872. INTERNET_MAX_URL_LENGTH * sizeof(TCHAR))))
  873. {
  874. if (FAILED( g_pUrlAgent->GetLivePingServer(ptszLivePingServerUrl, INTERNET_MAX_URL_LENGTH) ) )
  875. {
  876. SafeHeapFree(ptszLivePingServerUrl);
  877. }
  878. }
  879. else
  880. {
  881. LOG_Out(_T("failed to allocate memory for ptszLivePingServerUrl"));
  882. }
  883. if (NULL != (ptszCorpPingServerUrl = (LPTSTR)HeapAlloc(
  884. GetProcessHeap(),
  885. HEAP_ZERO_MEMORY,
  886. INTERNET_MAX_URL_LENGTH * sizeof(TCHAR))))
  887. {
  888. if (FAILED(g_pUrlAgent->GetCorpPingServer(ptszCorpPingServerUrl, INTERNET_MAX_URL_LENGTH)))
  889. {
  890. LOG_Out(_T("failed to get corp WU ping server URL"));
  891. SafeHeapFree(ptszCorpPingServerUrl);
  892. }
  893. }
  894. else
  895. {
  896. LOG_Out(_T("failed to allocate memory for ptszCorpPingServerUrl"));
  897. }
  898. LPTSTR lpClientName = NULL;
  899. if(bstrClientName)
  900. {
  901. lpClientName = OLE2T(bstrClientName);
  902. }
  903. CUrlLog pingSvr(lpClientName, ptszLivePingServerUrl, ptszCorpPingServerUrl);
  904. SafeHeapFree(ptszLivePingServerUrl);
  905. SafeHeapFree(ptszCorpPingServerUrl);
  906. pingSvr.Ping(TRUE, // on-line
  907. URLLOGDESTINATION_DEFAULT, // going live or corp WU ping server
  908. phQuit, // pt to cancel events
  909. dwNumHandles, // number of events
  910. URLLOGACTIVITY_Download, // activity
  911. status, // status code
  912. hRes,
  913. NULL,
  914. NULL,
  915. g_szInvalidPID
  916. );
  917. }