Source code of Windows XP (NT5)
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.

2400 lines
63 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: Update.cpp
  6. //
  7. // Owner: JHou
  8. //
  9. // Description:
  10. //
  11. // Industry Update v1.0 client control stub - Implementation of CUpdate
  12. //
  13. //
  14. // Revision History:
  15. //
  16. // Date Author Desc
  17. // ~~~~ ~~~~~~ ~~~~
  18. // 9/15/2000 JHou created.
  19. //
  20. //=======================================================================
  21. #include "stdafx.h"
  22. #include "iu.h"
  23. #include "iucommon.h"
  24. #include "IUCtl.h"
  25. #include "Update.h"
  26. #include "iudl.h"
  27. #include "selfupd.h"
  28. #include "loadengine.h"
  29. #include <logging.h>
  30. #include <fileutil.h>
  31. #include <trust.h>
  32. #include <osdet.h>
  33. #include <exdisp.h>
  34. #include <UrlAgent.h>
  35. #include <wusafefn.h>
  36. typedef BOOL (WINAPI* pfn_InternetCrackUrl)(LPCTSTR, DWORD, DWORD, LPURL_COMPONENTS);
  37. extern HANDLE g_hEngineLoadQuit;
  38. extern CIUUrlAgent *g_pIUUrlAgent;
  39. #define Initialized (2 == m_lInitState)
  40. /////////////////////////////////////////////////////////////////////////////
  41. //
  42. // declaration of function template for CoFreeUnusedLibrariesEx(), which is
  43. // available on Win98+ and Win2000+ only, in ole32.dll
  44. //
  45. /////////////////////////////////////////////////////////////////////////////
  46. typedef void (WINAPI * PFN_CoFreeUnusedLibrariesEx) (IN DWORD dwUnloadDelay,
  47. IN DWORD dwReserved);
  48. extern "C" const CLSID CLSID_Update2;
  49. typedef HRESULT (STDMETHODCALLTYPE* PROC_RegServer)(void);
  50. DWORD MyGetModuleFileName(HMODULE hModule, LPTSTR pszBuf, DWORD cchBuf);
  51. BOOL IsThisUpdate2();
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CUpdate
  54. /////////////////////////////////////////////////////////////////////////////
  55. // Constructor
  56. //
  57. /////////////////////////////////////////////////////////////////////////////
  58. CUpdate::CUpdate()
  59. : m_EvtWindow(this),
  60. m_dwSafety(0),
  61. m_dwMode(0x0),
  62. m_hValidated(E_FAIL), // container not validated yet
  63. m_fUseCompression(TRUE),
  64. m_fOfflineMode(FALSE),
  65. m_hEngineModule(NULL),
  66. m_pClientSite(NULL),
  67. m_lInitState(0L),
  68. m_dwUpdateInfo(0x0),
  69. m_hIUEngine(NULL)
  70. {
  71. m_szReqControlVer[0] = _T('\0');
  72. m_gfInit_csLock = SafeInitializeCriticalSection(&m_lock);
  73. m_evtControlQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
  74. m_EvtWindow.Create();
  75. /*
  76. we decided to use the new Win32 API GetControlUpdateInfo() to expose these
  77. data and let a wrapper control to call it so we won't have reboot issue on
  78. OS prior to WinXP
  79. //
  80. // try to free unused libraries
  81. //
  82. HMODULE hOle32Dll = LoadLibrary(_T("ole32.dll"));
  83. if (NULL != hOle32Dll)
  84. {
  85. //
  86. // The min platforms support CoFreeUnusedLibrariesEx() are W2K and W98
  87. // so we can't call it directly
  88. //
  89. PFN_CoFreeUnusedLibrariesEx pFreeLib = (PFN_CoFreeUnusedLibrariesEx)
  90. GetProcAddress(hOle32Dll,
  91. "CoFreeUnusedLibrariesEx");
  92. if (NULL != pFreeLib)
  93. {
  94. //
  95. // ask to release the unused library immediately, this will cause the COM objects
  96. // that being released (e.g., set obj to nothing) unloaded from memory immediately,
  97. // so in control update case we can safely jump to a to use <OBJECT> with codebase
  98. // to update the control and it won't cause reboot even though on this page we already
  99. // loaded the control
  100. //
  101. pFreeLib(0, 0);
  102. }
  103. FreeLibrary(hOle32Dll);
  104. }
  105. //
  106. // figure out if we are upate 2, we are if this module name ends with "2.dll"
  107. //
  108. m_fIsThisUpdate2 = ::IsThisUpdate2();
  109. */
  110. }
  111. /////////////////////////////////////////////////////////////////////////////
  112. // Destructor
  113. //
  114. /////////////////////////////////////////////////////////////////////////////
  115. CUpdate::~CUpdate()
  116. {
  117. m_EvtWindow.Destroy();
  118. if(m_gfInit_csLock)
  119. {
  120. DeleteCriticalSection(&m_lock);
  121. }
  122. if (NULL != m_evtControlQuit)
  123. {
  124. CloseHandle(m_evtControlQuit);
  125. }
  126. SafeReleaseNULL(m_pClientSite);
  127. }
  128. /////////////////////////////////////////////////////////////////////////////
  129. // GetInterfaceSafetyOptions()
  130. //
  131. // Retrieves the safety options supported by the object.
  132. /////////////////////////////////////////////////////////////////////////////
  133. STDMETHODIMP CUpdate::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
  134. {
  135. if (!m_gfInit_csLock)
  136. {
  137. return E_OUTOFMEMORY;
  138. }
  139. if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
  140. return E_POINTER;
  141. HRESULT hr = S_OK;
  142. if (riid == IID_IDispatch)
  143. {
  144. *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
  145. *pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
  146. }
  147. else
  148. {
  149. *pdwSupportedOptions = 0;
  150. *pdwEnabledOptions = 0;
  151. hr = E_NOINTERFACE;
  152. }
  153. return hr;
  154. }
  155. /////////////////////////////////////////////////////////////////////////////
  156. // SetInterfaceSafetyOptions()
  157. //
  158. // Makes the object safe for initialization or scripting.
  159. /////////////////////////////////////////////////////////////////////////////
  160. STDMETHODIMP CUpdate::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
  161. {
  162. if (!m_gfInit_csLock)
  163. {
  164. return E_OUTOFMEMORY;
  165. }
  166. // If we're being asked to set our safe for scripting option then oblige
  167. if (riid == IID_IDispatch)
  168. {
  169. // Store our current safety level to return in GetInterfaceSafetyOptions
  170. m_dwSafety = dwEnabledOptions & dwOptionSetMask;
  171. return S_OK;
  172. }
  173. return E_NOINTERFACE;
  174. }
  175. /////////////////////////////////////////////////////////////////////////////
  176. // InterfaceSupportsErrorInfo()
  177. //
  178. // Indicates whether the interface identified by riid supports the
  179. // IErrorInfo interface
  180. /////////////////////////////////////////////////////////////////////////////
  181. STDMETHODIMP CUpdate::InterfaceSupportsErrorInfo(REFIID riid)
  182. {
  183. if (!m_gfInit_csLock)
  184. {
  185. return E_OUTOFMEMORY;
  186. }
  187. static const IID* arr[] =
  188. {
  189. &IID_IUpdate
  190. };
  191. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  192. {
  193. if (InlineIsEqualGUID(*arr[i],riid))
  194. return S_OK;
  195. }
  196. return S_FALSE;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////
  199. // GetSystemSpec()
  200. //
  201. // Gets the basic system specs.
  202. // Input:
  203. // bstrXmlClasses - a list of requested classes in xml format, NULL if any.
  204. // For example:
  205. // <devices>
  206. // <class name="video"/>
  207. // <class name="sound" id="2560AD4D-3ED3-49C6-A937-4368C0B0E06A"/>
  208. // </devices>
  209. // Return:
  210. // pbstrXmlDetectionResult - the detection result in xml format.
  211. /////////////////////////////////////////////////////////////////////////////
  212. STDMETHODIMP CUpdate::GetSystemSpec(BSTR bstrXmlClasses,
  213. BSTR* pbstrXmlDetectionResult)
  214. {
  215. HRESULT hr = E_FAIL;
  216. LOG_Block("CUpdate::GetSystemSpec");
  217. if (!m_gfInit_csLock)
  218. {
  219. return E_OUTOFMEMORY;
  220. }
  221. if (1 == IsWindowsUpdateUserAccessDisabled())
  222. {
  223. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  224. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  225. }
  226. //
  227. // load the engine if it's not up-to-date
  228. //
  229. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  230. {
  231. //
  232. // engine is current, delegate the call to engine
  233. //
  234. PFN_GetSystemSpec pfnGetSystemSpec = (PFN_GetSystemSpec)GetProcAddress(m_hEngineModule, "EngGetSystemSpec");
  235. DWORD dwFlags = 0x0;
  236. if (m_fOfflineMode)
  237. {
  238. dwFlags |= FLAG_OFFLINE_MODE;
  239. }
  240. if (NULL != m_hIUEngine && NULL != pfnGetSystemSpec)
  241. {
  242. hr = pfnGetSystemSpec(m_hIUEngine, bstrXmlClasses, dwFlags, pbstrXmlDetectionResult);
  243. }
  244. else
  245. {
  246. LOG_ErrorMsg(ERROR_INVALID_DLL);
  247. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  248. }
  249. }
  250. return hr;
  251. }
  252. /////////////////////////////////////////////////////////////////////////////
  253. // GetManifest()
  254. //
  255. // Gets a catalog base on the specified information.
  256. // Input:
  257. // bstrXmlClientInfo - the credentials of the client in xml format
  258. // bstrXmlSystemSpec - the detected system specifications in xml
  259. // bstrXmlQuery - the user query infomation in xml
  260. // Return:
  261. // pbstrXmlCatalog - the xml catalog retrieved
  262. /////////////////////////////////////////////////////////////////////////////
  263. STDMETHODIMP CUpdate::GetManifest(BSTR bstrXmlClientInfo,
  264. BSTR bstrXmlSystemSpec,
  265. BSTR bstrXmlQuery,
  266. BSTR* pbstrXmlCatalog)
  267. {
  268. HRESULT hr = E_FAIL;
  269. LOG_Block("CUpdate::GetManifest");
  270. if (!m_gfInit_csLock)
  271. {
  272. return E_OUTOFMEMORY;
  273. }
  274. if (1 == IsWindowsUpdateUserAccessDisabled())
  275. {
  276. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  277. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  278. }
  279. if (m_fOfflineMode)
  280. {
  281. // if we are in offline mode we can't download from the internet.
  282. LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
  283. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  284. }
  285. //
  286. // load the engine if it's not up-to-date
  287. //
  288. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  289. {
  290. //
  291. // engine is current, delegate the call to engine
  292. //
  293. PFN_GetManifest pfnGetManifest = (PFN_GetManifest)GetProcAddress(m_hEngineModule, "EngGetManifest");
  294. if (NULL != m_hIUEngine && NULL != pfnGetManifest)
  295. {
  296. DWORD dwFlags = 0x0;
  297. if (m_fUseCompression)
  298. {
  299. dwFlags |= FLAG_USE_COMPRESSION;
  300. }
  301. hr = pfnGetManifest(m_hIUEngine, bstrXmlClientInfo, bstrXmlSystemSpec, bstrXmlQuery, dwFlags, pbstrXmlCatalog);
  302. }
  303. else
  304. {
  305. LOG_ErrorMsg(ERROR_INVALID_DLL);
  306. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  307. }
  308. }
  309. return hr;
  310. }
  311. /////////////////////////////////////////////////////////////////////////////
  312. // Detect()
  313. //
  314. // Do detection.
  315. // Input:
  316. // bstrXmlCatalog - the xml catalog portion containing items to be detected
  317. // Output:
  318. // pbstrXmlItems - the detected items in xml format
  319. // e.g.
  320. // <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1" force="1"/>
  321. /////////////////////////////////////////////////////////////////////////////
  322. STDMETHODIMP CUpdate::Detect(BSTR bstrXmlCatalog,
  323. BSTR* pbstrXmlItems)
  324. {
  325. HRESULT hr = E_FAIL;
  326. LOG_Block("CUpdate::Detect");
  327. if (!m_gfInit_csLock)
  328. {
  329. return E_OUTOFMEMORY;
  330. }
  331. if (1 == IsWindowsUpdateUserAccessDisabled())
  332. {
  333. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  334. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  335. }
  336. //
  337. // load the engine if it's not up-to-date
  338. //
  339. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  340. {
  341. //
  342. // engine is current, delegate the call to engine
  343. //
  344. PFN_Detect pfnDetect = (PFN_Detect)GetProcAddress(m_hEngineModule, "EngDetect");
  345. DWORD dwFlags = 0x0;
  346. if (m_fOfflineMode)
  347. {
  348. dwFlags |= FLAG_OFFLINE_MODE;
  349. }
  350. if (NULL != m_hIUEngine && NULL != pfnDetect)
  351. {
  352. hr = pfnDetect(m_hIUEngine, bstrXmlCatalog, dwFlags, pbstrXmlItems);
  353. }
  354. else
  355. {
  356. LOG_ErrorMsg(ERROR_INVALID_DLL);
  357. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  358. }
  359. }
  360. return hr;
  361. }
  362. /////////////////////////////////////////////////////////////////////////////
  363. // Download()
  364. //
  365. // Do synchronized downloading.
  366. // Input:
  367. // bstrXmlClientInfo - the credentials of the client in xml format
  368. // bstrXmlCatalog - the xml catalog portion containing items to be downloaded
  369. // bstrDestinationFolder - the destination folder. Null will use the default IU folder
  370. // lMode - indicates throttled or fore-ground downloading mode
  371. // punkProgressListener - the callback function pointer for reporting download progress
  372. // Output:
  373. // pbstrXmlItems - the items with download status in xml format
  374. // e.g.
  375. // <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" downloaded="1"/>
  376. /////////////////////////////////////////////////////////////////////////////
  377. STDMETHODIMP CUpdate::Download(BSTR bstrXmlClientInfo,
  378. BSTR bstrXmlCatalog,
  379. BSTR bstrDestinationFolder,
  380. LONG lMode,
  381. IUnknown* punkProgressListener,
  382. BSTR* pbstrXmlItems)
  383. {
  384. HRESULT hr = E_FAIL;
  385. LOG_Block("CUpdate::Download");
  386. if (!m_gfInit_csLock)
  387. {
  388. return E_OUTOFMEMORY;
  389. }
  390. if (1 == IsWindowsUpdateUserAccessDisabled())
  391. {
  392. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  393. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  394. }
  395. if (m_fOfflineMode)
  396. {
  397. // if we are in offline mode we can't download from the internet.
  398. LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
  399. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  400. }
  401. //
  402. // load the engine if it's not up-to-date
  403. //
  404. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  405. {
  406. //
  407. // engine is current, delegate the call to engine
  408. //
  409. PFN_Download pfnDownload = (PFN_Download)GetProcAddress(m_hEngineModule, "EngDownload");
  410. if (NULL != m_hIUEngine && NULL != pfnDownload)
  411. {
  412. hr = pfnDownload(m_hIUEngine,
  413. bstrXmlClientInfo,
  414. bstrXmlCatalog,
  415. bstrDestinationFolder,
  416. lMode,
  417. punkProgressListener,
  418. m_EvtWindow.GetEvtHWnd(), // should we send event msg for sync download?
  419. pbstrXmlItems);
  420. }
  421. else
  422. {
  423. LOG_ErrorMsg(ERROR_INVALID_DLL);
  424. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  425. }
  426. }
  427. return hr;
  428. }
  429. /////////////////////////////////////////////////////////////////////////////
  430. // DownloadAsync()
  431. //
  432. // Download asynchronously - the method will return before completion.
  433. // Input:
  434. // bstrXmlClientInfo - the credentials of the client in xml format
  435. // bstrXmlCatalog - the xml catalog portion containing items to be downloaded
  436. // bstrDestinationFolder - the destination folder. Null will use the default IU folder
  437. // lMode - indicates throttled or fore-ground downloading mode
  438. // punkProgressListener - the callback function pointer for reporting download progress
  439. // bstrUuidOperation - an id provided by the client to provide further
  440. // identification to the operation as indexes may be reused.
  441. // Output:
  442. // pbstrUuidOperation - the operation ID. If it is not provided by the in bstrUuidOperation
  443. // parameter (an empty string is passed), it will generate a new UUID,
  444. // in which case, the caller will be responsible to free the memory of
  445. // the string buffer that holds the generated UUID using SysFreeString().
  446. // Otherwise, it returns the value passed by bstrUuidOperation.
  447. /////////////////////////////////////////////////////////////////////////////
  448. STDMETHODIMP CUpdate::DownloadAsync(BSTR bstrXmlClientInfo,
  449. BSTR bstrXmlCatalog,
  450. BSTR bstrDestinationFolder,
  451. LONG lMode,
  452. IUnknown* punkProgressListener,
  453. BSTR bstrUuidOperation,
  454. BSTR* pbstrUuidOperation)
  455. {
  456. HRESULT hr = E_FAIL;
  457. LOG_Block("CUpdate::DownloadAsync");
  458. if (!m_gfInit_csLock)
  459. {
  460. return E_OUTOFMEMORY;
  461. }
  462. if (1 == IsWindowsUpdateUserAccessDisabled())
  463. {
  464. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  465. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  466. }
  467. if (m_fOfflineMode)
  468. {
  469. // if we are in offline mode we can't download from the internet.
  470. LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
  471. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  472. }
  473. //
  474. // load the engine if it's not up-to-date
  475. //
  476. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  477. {
  478. //
  479. // engine is current, delegate the call to engine
  480. //
  481. PFN_DownloadAsync pfnDownloadAsync = (PFN_DownloadAsync)GetProcAddress(m_hEngineModule, "EngDownloadAsync");
  482. if (NULL != m_hIUEngine && NULL != pfnDownloadAsync)
  483. {
  484. hr = pfnDownloadAsync(m_hIUEngine,
  485. bstrXmlClientInfo,
  486. bstrXmlCatalog,
  487. bstrDestinationFolder,
  488. lMode,
  489. punkProgressListener,
  490. m_EvtWindow.GetEvtHWnd(),
  491. bstrUuidOperation,
  492. pbstrUuidOperation);
  493. }
  494. else
  495. {
  496. LOG_ErrorMsg(ERROR_INVALID_DLL);
  497. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  498. }
  499. }
  500. return hr;
  501. }
  502. /////////////////////////////////////////////////////////////////////////////
  503. // Install()
  504. //
  505. // Do synchronized installation.
  506. // Input:
  507. // bstrXmlCatalog - the xml catalog portion containing items to be installed
  508. // bstrXmlDownloadedItems - the xml of downloaded items and their respective download
  509. // result as described in the result schema. Install uses this
  510. // to know whether the items were downloaded and if so where they
  511. // were downloaded to so that it can install the items
  512. // lMode - indicates different installation mode
  513. // punkProgressListener - the callback function pointer for reporting install progress
  514. // Output:
  515. // pbstrXmlItems - the items with installation status in xml format
  516. // e.g.
  517. // <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1"/>
  518. /////////////////////////////////////////////////////////////////////////////
  519. STDMETHODIMP CUpdate::Install(BSTR bstrXmlClientInfo,
  520. BSTR bstrXmlCatalog,
  521. BSTR bstrXmlDownloadedItems,
  522. LONG lMode,
  523. IUnknown* punkProgressListener,
  524. BSTR* pbstrXmlItems)
  525. {
  526. HRESULT hr = E_FAIL;
  527. LOG_Block("CUpdate::Install");
  528. if (!m_gfInit_csLock)
  529. {
  530. return E_OUTOFMEMORY;
  531. }
  532. if (1 == IsWindowsUpdateUserAccessDisabled())
  533. {
  534. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  535. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  536. }
  537. if (m_fOfflineMode)
  538. {
  539. // make sure offline mode parameter is set if SetProperty() Offline Mode was Set
  540. lMode |= UPDATE_OFFLINE_MODE;
  541. }
  542. //
  543. // load the engine if it's not up-to-date
  544. //
  545. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  546. {
  547. //
  548. // engine is current, delegate the call to engine
  549. //
  550. PFN_Install pfnInstall = (PFN_Install)GetProcAddress(m_hEngineModule, "EngInstall");
  551. if (NULL != m_hIUEngine && NULL != pfnInstall)
  552. {
  553. hr = pfnInstall(m_hIUEngine,
  554. bstrXmlClientInfo,
  555. bstrXmlCatalog,
  556. bstrXmlDownloadedItems,
  557. lMode,
  558. punkProgressListener,
  559. m_EvtWindow.GetEvtHWnd(),
  560. pbstrXmlItems);
  561. }
  562. else
  563. {
  564. LOG_ErrorMsg(ERROR_INVALID_DLL);
  565. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  566. }
  567. }
  568. return hr;
  569. }
  570. /////////////////////////////////////////////////////////////////////////////
  571. // InstallAsync()
  572. //
  573. // Install Asynchronously.
  574. // Input:
  575. // bstrXmlCatalog - the xml catalog portion containing items to be installed
  576. // bstrXmlDownloadedItems - the xml of downloaded items and their respective download
  577. // result as described in the result schema. Install uses this
  578. // to know whether the items were downloaded and if so where they
  579. // were downloaded to so that it can install the items
  580. // lMode - indicates different installation mode
  581. // punkProgressListener - the callback function pointer for reporting install progress
  582. // bstrUuidOperation - an id provided by the client to provide further
  583. // identification to the operation as indexes may be reused.
  584. // Output:
  585. // pbstrUuidOperation - the operation ID. If it is not provided by the in bstrUuidOperation
  586. // parameter (an empty string is passed), it will generate a new UUID,
  587. // in which case, the caller will be responsible to free the memory of
  588. // the string buffer that holds the generated UUID using SysFreeString().
  589. // Otherwise, it returns the value passed by bstrUuidOperation.
  590. /////////////////////////////////////////////////////////////////////////////
  591. STDMETHODIMP CUpdate::InstallAsync(BSTR bstrXmlClientInfo,
  592. BSTR bstrXmlCatalog,
  593. BSTR bstrXmlDownloadedItems,
  594. LONG lMode,
  595. IUnknown* punkProgressListener,
  596. BSTR bstrUuidOperation,
  597. BSTR* pbstrUuidOperation)
  598. {
  599. HRESULT hr = E_FAIL;
  600. LOG_Block("CUpdate::InstallAsync");
  601. if (!m_gfInit_csLock)
  602. {
  603. return E_OUTOFMEMORY;
  604. }
  605. if (1 == IsWindowsUpdateUserAccessDisabled())
  606. {
  607. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  608. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  609. }
  610. if (m_fOfflineMode)
  611. {
  612. // make sure offline mode parameter is set if SetProperty() Offline Mode was Set
  613. lMode |= UPDATE_OFFLINE_MODE;
  614. }
  615. //
  616. // load the engine if it's not up-to-date
  617. //
  618. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  619. {
  620. //
  621. // engine is current, delegate the call to engine
  622. //
  623. PFN_InstallAsync pfnInstallAsync = (PFN_InstallAsync)GetProcAddress(m_hEngineModule, "EngInstallAsync");
  624. if (NULL != m_hIUEngine && NULL != pfnInstallAsync)
  625. {
  626. hr = pfnInstallAsync(m_hIUEngine,
  627. bstrXmlClientInfo,
  628. bstrXmlCatalog,
  629. bstrXmlDownloadedItems,
  630. lMode,
  631. punkProgressListener,
  632. m_EvtWindow.GetEvtHWnd(),
  633. bstrUuidOperation,
  634. pbstrUuidOperation);
  635. }
  636. else
  637. {
  638. LOG_ErrorMsg(ERROR_INVALID_DLL);
  639. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  640. }
  641. }
  642. return hr;
  643. }
  644. /////////////////////////////////////////////////////////////////////////////
  645. // SetOperationMode()
  646. // Set the operation status.
  647. //
  648. // Input:
  649. // bstrUuidOperation - an id provided by the client to provide further
  650. // identification to the operation as indexes may be reused.
  651. // lMode - the mode affecting the operation:
  652. //
  653. // UPDATE_COMMAND_PAUSE
  654. // UPDATE_COMMAND_RESUME
  655. // UPDATE_COMMAND_CANCEL
  656. // UPDATE_NOTIFICATION_COMPLETEONLY
  657. // UPDATE_NOTIFICATION_ANYPROGRESS
  658. // UPDATE_NOTIFICATION_1PCT
  659. // UPDATE_NOTIFICATION_5PCT
  660. // UPDATE_NOTIFICATION_10PCT
  661. // UPDATE_SHOWUI
  662. //
  663. /////////////////////////////////////////////////////////////////////////////
  664. STDMETHODIMP CUpdate::SetOperationMode(
  665. BSTR bstrUuidOperation,
  666. LONG lMode)
  667. {
  668. HRESULT hr = E_FAIL;
  669. LOG_Block("CUpdate::SetOperationMode");
  670. if (!m_gfInit_csLock)
  671. {
  672. return E_OUTOFMEMORY;
  673. }
  674. if (1 == IsWindowsUpdateUserAccessDisabled())
  675. {
  676. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  677. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  678. }
  679. //
  680. // load the engine if it's not up-to-date
  681. //
  682. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  683. {
  684. //
  685. // engine is current, delegate the call to engine
  686. //
  687. PFN_SetOperationMode pfnSetOperationMode = (PFN_SetOperationMode)GetProcAddress(m_hEngineModule, "EngSetOperationMode");
  688. if (NULL != m_hIUEngine && NULL != pfnSetOperationMode)
  689. {
  690. hr = pfnSetOperationMode(m_hIUEngine, bstrUuidOperation, lMode);
  691. }
  692. else
  693. {
  694. LOG_ErrorMsg(ERROR_INVALID_DLL);
  695. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  696. }
  697. }
  698. return hr;
  699. }
  700. /////////////////////////////////////////////////////////////////////////////
  701. // GetHistory()
  702. //
  703. // Get the history log.
  704. // Input:
  705. // bstrDateTimeFrom - the start date and time for which a log is required.
  706. // This is a string in ANSI format (YYYY-MM-DDTHH-MM).
  707. // If the string is empty, there will be no date restriction
  708. // of the returned history log.
  709. // bstrDateTimeTo - the end date and time for which a log is required.
  710. // This is a string in ANSI format (YYYY-MM-DDTHH-MM).
  711. // If the string is empty, there will be no date restriction
  712. // of the returned history log.
  713. // bstrClient - the name of the client that initiated the action. If this parameter
  714. // is null or an empty string, then there will be no filtering based
  715. // on the client.
  716. // bstrPath - the path used for download or install. Used in the corporate version
  717. // by IT managers. If this parameter is null or an empty string, then
  718. // there will be no filtering based on the path.
  719. // Output:
  720. // pbstrLog - the history log in xml format
  721. /////////////////////////////////////////////////////////////////////////////
  722. STDMETHODIMP CUpdate::GetHistory(BSTR bstrDateTimeFrom,
  723. BSTR bstrDateTimeTo,
  724. BSTR bstrClient,
  725. BSTR bstrPath,
  726. BSTR* pbstrLog)
  727. {
  728. HRESULT hr = E_FAIL;
  729. LOG_Block("CUpdate::GetHistory");
  730. if (!m_gfInit_csLock)
  731. {
  732. return E_OUTOFMEMORY;
  733. }
  734. if (1 == IsWindowsUpdateUserAccessDisabled())
  735. {
  736. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  737. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  738. }
  739. //
  740. // load the engine if it's not up-to-date
  741. //
  742. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  743. {
  744. //
  745. // engine is current, delegate the call to engine
  746. //
  747. PFN_GetHistory pfnGetHistory = (PFN_GetHistory)GetProcAddress(m_hEngineModule, "EngGetHistory");
  748. if (NULL != m_hIUEngine && NULL != pfnGetHistory)
  749. {
  750. hr = pfnGetHistory(m_hIUEngine,
  751. bstrDateTimeFrom,
  752. bstrDateTimeTo,
  753. bstrClient,
  754. bstrPath,
  755. pbstrLog);
  756. }
  757. else
  758. {
  759. LOG_ErrorMsg(ERROR_INVALID_DLL);
  760. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  761. }
  762. }
  763. return hr;
  764. }
  765. /////////////////////////////////////////////////////////////////////////////
  766. //
  767. // private overriding function InternalRelease(), to unlock the engine
  768. // if the reference (before the release) is 1, i.e., the last ref
  769. // count about to be released
  770. //
  771. /////////////////////////////////////////////////////////////////////////////
  772. ULONG CUpdate::InternalRelease()
  773. {
  774. if (1 == m_dwRef)
  775. {
  776. //
  777. // the control is going to really gone, we need to make sure that
  778. // if the engine is loaded, we unload it here.
  779. //
  780. UnlockEngine();
  781. CleanupDownloadLib();
  782. }
  783. return CComObjectRootEx<CComMultiThreadModel>::InternalRelease();
  784. }
  785. /////////////////////////////////////////////////////////////////////////////
  786. // UnlockEngine()
  787. //
  788. // release the engine dll if ref cnt of engine is down to zero
  789. /////////////////////////////////////////////////////////////////////////////
  790. HRESULT CUpdate::UnlockEngine()
  791. {
  792. if (!m_gfInit_csLock)
  793. {
  794. return E_OUTOFMEMORY;
  795. }
  796. TCHAR szSystemDir[MAX_PATH];
  797. TCHAR szEngineDllPath[MAX_PATH];
  798. TCHAR szEngineNewDllPath[MAX_PATH];
  799. int iVerCheck = 0;
  800. HRESULT hr = S_OK;
  801. SetEvent(m_evtControlQuit);
  802. EnterCriticalSection(&m_lock);
  803. if (NULL != m_hEngineModule)
  804. {
  805. //
  806. // We have to delete the engine instance we are using. This will clean up
  807. // all resources, stop threads, etc. for the instance we own.
  808. //
  809. PFN_DeleteEngUpdateInstance pfnDeleteEngUpdateInstance = (PFN_DeleteEngUpdateInstance) GetProcAddress(m_hEngineModule, "DeleteEngUpdateInstance");
  810. if (NULL != pfnDeleteEngUpdateInstance)
  811. {
  812. pfnDeleteEngUpdateInstance(m_hIUEngine);
  813. }
  814. //
  815. // Cleanup any global threads (it checks to see if we are last instance)
  816. //
  817. PFN_ShutdownGlobalThreads pfnShutdownGlobalThreads = (PFN_ShutdownGlobalThreads) GetProcAddress(m_hEngineModule, "ShutdownGlobalThreads");
  818. if (NULL != pfnShutdownGlobalThreads)
  819. {
  820. pfnShutdownGlobalThreads();
  821. }
  822. //
  823. // unload engine
  824. //
  825. FreeLibrary(m_hEngineModule);
  826. m_hEngineModule = NULL;
  827. m_lInitState = 0; // mark as uninitialized
  828. //
  829. // get path of enginenew.dll
  830. //
  831. GetSystemDirectory(szSystemDir, ARRAYSIZE(szSystemDir));
  832. hr = PathCchCombine(szEngineNewDllPath, ARRAYSIZE(szEngineNewDllPath), szSystemDir,ENGINENEWDLL);
  833. if (FAILED(hr))
  834. {
  835. return hr;
  836. }
  837. //
  838. // see if we should try to update the engine (locally)
  839. //
  840. HKEY hkey = NULL;
  841. DWORD dwStatus = 0;
  842. DWORD dwSize = sizeof(dwStatus);
  843. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hkey))
  844. {
  845. RegQueryValueEx(hkey, REGVAL_SELFUPDATESTATUS, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
  846. }
  847. if (FileExists(szEngineNewDllPath) &&
  848. S_OK == VerifyFileTrust(szEngineNewDllPath, NULL, ReadWUPolicyShowTrustUI()) &&
  849. SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED == dwStatus)
  850. {
  851. // an iuenginenew.dll exists, try replacing the engine.dll This will fail if this is
  852. // not the last process using the engine. This is not a problem, when that process
  853. // finishes it will rename the DLL.
  854. hr = PathCchCombine(szEngineDllPath, ARRAYSIZE(szEngineDllPath), szSystemDir,ENGINEDLL);
  855. if (FAILED(hr))
  856. {
  857. return hr;
  858. }
  859. if (SUCCEEDED(CompareFileVersion(szEngineDllPath, szEngineNewDllPath, &iVerCheck)) &&
  860. iVerCheck < 0 &&
  861. TRUE == MoveFileEx(szEngineNewDllPath, szEngineDllPath, MOVEFILE_REPLACE_EXISTING))
  862. {
  863. // Rename was Successful.. reset RegKey Information about SelfUpdate Status
  864. // Because the rename was successful we know no other processes are interacting
  865. // It should be safe to set the reg key.
  866. dwStatus = 0; // PreFast
  867. RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
  868. }
  869. }
  870. else if (SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED == dwStatus)
  871. {
  872. // registry indicates rename required, but enginenew DLL does not exist. Reset registry
  873. dwStatus = 0;
  874. RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
  875. }
  876. if (NULL != hkey)
  877. {
  878. RegCloseKey(hkey);
  879. }
  880. }
  881. LeaveCriticalSection(&m_lock);
  882. ResetEvent(m_evtControlQuit);
  883. return S_OK;
  884. }
  885. /**
  886. *
  887. * Get the mode of a specified operation.
  888. *
  889. * @param bstrUuidOperation: same as in SetOperationMode()
  890. * @param plMode - the retval for the mode found in a bitmask for:
  891. * (value in brackets [] means default)
  892. * UPDATE_COMMAND_PAUSE (TRUE/[FALSE])
  893. * UPDATE_COMMAND_RESUME (TRUE/[FALSE])
  894. * UPDATE_NOTIFICATION_COMPLETEONLY (TRUE/[FALSE])
  895. * UPDATE_NOTIFICATION_ANYPROGRESS ([TRUE]/FALSE)
  896. * UPDATE_NOTIFICATION_1PCT (TRUE/[FALSE])
  897. * UPDATE_NOTIFICATION_5PCT (TRUE/[FALSE])
  898. * UPDATE_NOTIFICATION_10PCT (TRUE/[FALSE])
  899. * UPDATE_SHOWUI (TRUE/[FALSE])
  900. *
  901. */
  902. STDMETHODIMP CUpdate::GetOperationMode(BSTR bstrUuidOperation, LONG *plMode)
  903. {
  904. HRESULT hr = E_FAIL;
  905. LOG_Block("CUpdate::GetOperationMode");
  906. if (!m_gfInit_csLock)
  907. {
  908. return E_OUTOFMEMORY;
  909. }
  910. if (1 == IsWindowsUpdateUserAccessDisabled())
  911. {
  912. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  913. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  914. }
  915. //
  916. // load the engine if it's not up-to-date
  917. //
  918. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  919. {
  920. //
  921. // engine is current, delegate the call to engine
  922. //
  923. PFN_GetOperationMode pfnGetOperationMode = (PFN_GetOperationMode)GetProcAddress(m_hEngineModule, "EngGetOperationMode");
  924. if (NULL != m_hIUEngine && NULL != pfnGetOperationMode)
  925. {
  926. hr = pfnGetOperationMode(m_hIUEngine, bstrUuidOperation, plMode);
  927. }
  928. else
  929. {
  930. LOG_ErrorMsg(ERROR_INVALID_DLL);
  931. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  932. }
  933. }
  934. return hr;
  935. }
  936. /**
  937. *
  938. * Set a property of this control
  939. * Calling this method will not cause the engine loaded
  940. *
  941. * @param lProperty - the identifier to flag which property need changed
  942. * UPDATE_PROP_OFFLINEMODE (TRUE/[FALSE])
  943. * UPDATE_PROP_USECOMPRESSION ([TRUE]/FALSE)
  944. *
  945. * @param varValue - the value to change
  946. *
  947. */
  948. STDMETHODIMP CUpdate::SetProperty(LONG lProperty, VARIANT varValue)
  949. {
  950. LOG_Block("CUpdate::SetProperty");
  951. HRESULT hr = S_OK;
  952. if (!m_gfInit_csLock)
  953. {
  954. return E_OUTOFMEMORY;
  955. }
  956. if (1 == IsWindowsUpdateUserAccessDisabled())
  957. {
  958. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  959. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  960. }
  961. switch(lProperty)
  962. {
  963. case UPDATE_PROP_USECOMPRESSION:
  964. if (VT_BOOL != varValue.vt)
  965. {
  966. hr = E_INVALIDARG;
  967. LOG_ErrorMsg(hr);
  968. }
  969. else
  970. {
  971. m_fUseCompression = (VARIANT_TRUE == varValue.boolVal) ? TRUE : FALSE;
  972. }
  973. break;
  974. case UPDATE_PROP_OFFLINEMODE:
  975. if (VT_BOOL != varValue.vt)
  976. {
  977. hr = E_INVALIDARG;
  978. LOG_ErrorMsg(hr);
  979. }
  980. else
  981. {
  982. m_fOfflineMode = (VARIANT_TRUE == varValue.boolVal) ? TRUE : FALSE;
  983. }
  984. break;
  985. default:
  986. return E_NOTIMPL;
  987. }
  988. return S_OK;
  989. }
  990. /**
  991. *
  992. * Retrieve a property of this control
  993. * Calling this method will not cause the engine loaded
  994. *
  995. * @param lProperty - the identifier to flag which property need retrieved
  996. * UPDATE_PROP_OFFLINEMODE (TRUE/[FALSE])
  997. * UPDATE_PROP_USECOMPRESSION ([TRUE]/FALSE)
  998. *
  999. * @param varValue - the value to retrieve
  1000. *
  1001. */
  1002. STDMETHODIMP CUpdate::GetProperty(LONG lProperty, VARIANT *pvarValue)
  1003. {
  1004. LOG_Block("CUpdate::GetProperty");
  1005. if (!m_gfInit_csLock)
  1006. {
  1007. return E_OUTOFMEMORY;
  1008. }
  1009. if (1 == IsWindowsUpdateUserAccessDisabled())
  1010. {
  1011. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  1012. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  1013. }
  1014. if (NULL == pvarValue)
  1015. {
  1016. return E_INVALIDARG;
  1017. }
  1018. VariantInit(pvarValue);
  1019. switch(lProperty)
  1020. {
  1021. case UPDATE_PROP_USECOMPRESSION:
  1022. pvarValue->vt = VT_BOOL;
  1023. pvarValue->boolVal = (m_fUseCompression) ? VARIANT_TRUE : VARIANT_FALSE;
  1024. break;
  1025. case UPDATE_PROP_OFFLINEMODE:
  1026. pvarValue->vt = VT_BOOL;
  1027. pvarValue->boolVal = (m_fOfflineMode) ? VARIANT_TRUE : VARIANT_FALSE;
  1028. break;
  1029. default:
  1030. return E_NOTIMPL;
  1031. }
  1032. return S_OK;
  1033. }
  1034. /////////////////////////////////////////////////////////////////////////////
  1035. //
  1036. // Primarily expose shlwapi BrowseForFolder API, can also do checking
  1037. // on R/W access if flagged so.
  1038. //
  1039. // @param bstrStartFolder - the folder from which to start. If NULL or empty str
  1040. // is being passed in, then start from desktop
  1041. //
  1042. // @param flag - validating check
  1043. // UI_WRITABLE for checking write access, OK button may disabled.
  1044. // UI_READABLE for checking read access, OK button may disabled.
  1045. // NO_UI_WRITABLE for checking write access, return error if no access
  1046. // NO_UI_READABLE for checking read access, return error if no access
  1047. // 0 (default) for no checking.
  1048. //
  1049. // @param pbstrFolder - returned folder if a valid folder selected
  1050. //
  1051. /////////////////////////////////////////////////////////////////////////////
  1052. STDMETHODIMP CUpdate::BrowseForFolder(BSTR bstrStartFolder, LONG flag, BSTR* pbstrFolder)
  1053. {
  1054. HRESULT hr = E_FAIL;
  1055. LOG_Block("CUpdate::BrowseForFolder");
  1056. if (!m_gfInit_csLock)
  1057. {
  1058. return E_OUTOFMEMORY;
  1059. }
  1060. if (1 == IsWindowsUpdateUserAccessDisabled())
  1061. {
  1062. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  1063. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  1064. }
  1065. //
  1066. // load the engine if it's not up-to-date
  1067. //
  1068. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  1069. {
  1070. //
  1071. // engine is current, delegate the call to engine
  1072. //
  1073. PFN_BrowseForFolder pfnBrowseForFolder = (PFN_BrowseForFolder)GetProcAddress(m_hEngineModule, "EngBrowseForFolder");
  1074. if (NULL != m_hIUEngine && NULL != pfnBrowseForFolder)
  1075. {
  1076. hr = pfnBrowseForFolder(m_hIUEngine, bstrStartFolder, flag, pbstrFolder);
  1077. }
  1078. else
  1079. {
  1080. LOG_ErrorMsg(ERROR_INVALID_DLL);
  1081. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  1082. }
  1083. }
  1084. return hr;
  1085. }
  1086. /**
  1087. *
  1088. * Allows the Caller to Request the Control to do a Reboot
  1089. *
  1090. */
  1091. STDMETHODIMP CUpdate::RebootMachine()
  1092. {
  1093. HRESULT hr = E_FAIL;
  1094. LOG_Block("CUpdate::RebootMachine");
  1095. if (!m_gfInit_csLock)
  1096. {
  1097. return E_OUTOFMEMORY;
  1098. }
  1099. if (1 == IsWindowsUpdateUserAccessDisabled())
  1100. {
  1101. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  1102. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  1103. }
  1104. //
  1105. // load the engine if it's not up-to-date
  1106. //
  1107. if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
  1108. {
  1109. PFN_RebootMachine pfnRebootMachine = (PFN_RebootMachine)GetProcAddress(m_hEngineModule, "EngRebootMachine");
  1110. if (NULL != m_hIUEngine && NULL != pfnRebootMachine)
  1111. {
  1112. hr = pfnRebootMachine(m_hIUEngine);
  1113. }
  1114. else
  1115. {
  1116. LOG_ErrorMsg(ERROR_INVALID_DLL);
  1117. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  1118. }
  1119. }
  1120. return hr;
  1121. }
  1122. //
  1123. // Override of IObjectWithSite::SetSite()
  1124. // Internet Explorer QIs for IObjectWithSite, and calls this method
  1125. // with a pointer to its IOleClientSite
  1126. //
  1127. STDMETHODIMP CUpdate::SetSite(IUnknown* pSite)
  1128. {
  1129. if (!m_gfInit_csLock)
  1130. {
  1131. return E_OUTOFMEMORY;
  1132. }
  1133. SafeReleaseNULL(m_pClientSite);
  1134. m_pClientSite = pSite;
  1135. if (NULL != m_pClientSite)
  1136. m_pClientSite->AddRef();
  1137. return IObjectWithSiteImpl<CUpdate>::SetSite(pSite);
  1138. }
  1139. /**
  1140. *
  1141. * Security feature: make sure if the user of this control is
  1142. * a web page then the URL can be found in iuident.txt
  1143. *
  1144. * This function should be called after iuident refreshed.
  1145. *
  1146. * Return: TRUE/FALSE, to tell if we can continue
  1147. *
  1148. */
  1149. const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerURLs");
  1150. const TCHAR IDENT_IUSERVERCOUNT[] = _T("ServerCount");
  1151. const TCHAR IDENT_IUSERVER[] = _T("Server");
  1152. HRESULT CUpdate::ValidateControlContainer(void)
  1153. {
  1154. LOG_Block("ValidateControlContainer");
  1155. if (!m_gfInit_csLock)
  1156. {
  1157. return E_OUTOFMEMORY;
  1158. }
  1159. IServiceProvider* pISP = NULL;
  1160. IWebBrowserApp* pWeb = NULL;
  1161. BSTR bstrUrl = NULL;
  1162. LPTSTR lpszUrl = NULL;
  1163. #if !(defined(_UNICODE) || defined(UNICODE))
  1164. // ANSI build
  1165. LPSTR lpszAnsiUrl = NULL;
  1166. #endif
  1167. TCHAR szIUDir[MAX_PATH];
  1168. TCHAR szIdentFile[MAX_PATH];
  1169. TCHAR szServer[32];
  1170. LPTSTR szValidURL = NULL;
  1171. if (E_FAIL != m_hValidated)
  1172. {
  1173. //
  1174. // has been invalidated already
  1175. //
  1176. LOG_Internet(_T("Validate result: %s"), SUCCEEDED(m_hValidated) ? _T("S_OK") : _T("INET_E_INVALID_URL"));
  1177. return m_hValidated;
  1178. }
  1179. //
  1180. // check to see if the container is a web page/site, if
  1181. // not done so yet.
  1182. //
  1183. if (NULL != m_pClientSite)
  1184. {
  1185. //
  1186. // this is a web site!
  1187. //
  1188. m_hValidated = INET_E_INVALID_URL;
  1189. LOG_Internet(_T("Found control called by a web page"));
  1190. if (SUCCEEDED(m_pClientSite->QueryInterface(IID_IServiceProvider, (void**)&pISP)) &&
  1191. NULL != pISP &&
  1192. SUCCEEDED(pISP->QueryService(IID_IWebBrowserApp, IID_IWebBrowserApp, (void**)&pWeb)) &&
  1193. NULL != pWeb &&
  1194. SUCCEEDED(pWeb->get_LocationURL(&bstrUrl)) &&
  1195. NULL != bstrUrl)
  1196. {
  1197. #if defined(_UNICODE) || defined(UNICODE)
  1198. lpszUrl = bstrUrl;
  1199. #else // ANSI build
  1200. int nBufferLength = WideCharToMultiByte(CP_ACP, 0, bstrUrl, -1, NULL, 0, NULL, NULL);
  1201. lpszAnsiUrl = (LPSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nBufferLength);
  1202. if (NULL == lpszAnsiUrl || 0 == nBufferLength)
  1203. {
  1204. //
  1205. // Unfortunately, we return this error in place of E_OUTOFMEMORY, but the most
  1206. // likely scenario that would cause this would be a security attack (bad URL)
  1207. //
  1208. goto CleanUp; // Will return INET_E_INVALID_URL
  1209. }
  1210. WideCharToMultiByte(CP_ACP, 0, bstrUrl, -1, lpszAnsiUrl, nBufferLength, NULL, NULL);
  1211. lpszUrl = lpszAnsiUrl;
  1212. #endif
  1213. LOG_Internet(_T("Web address = %s"), lpszUrl);
  1214. //
  1215. // no matter what protocol specified in this URL
  1216. // (can be anything: http, ftp, UNC, path...)
  1217. // we just need to verify it against iuident.txt
  1218. //
  1219. szValidURL = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  1220. if (NULL == szValidURL)
  1221. {
  1222. SafeReleaseNULL(pISP);
  1223. SafeReleaseNULL(pWeb);
  1224. SysFreeString(bstrUrl);
  1225. LOG_ErrorMsg(E_OUTOFMEMORY);
  1226. return E_OUTOFMEMORY;
  1227. }
  1228. GetIndustryUpdateDirectory(szIUDir);
  1229. m_hValidated = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir,IDENTTXT);
  1230. if (FAILED(m_hValidated))
  1231. {
  1232. SafeReleaseNULL(pISP);
  1233. SafeReleaseNULL(pWeb);
  1234. SysFreeString(bstrUrl);
  1235. SafeHeapFree(szValidURL);
  1236. LOG_ErrorMsg(m_hValidated);
  1237. return m_hValidated;
  1238. }
  1239. // Fix of bug 557430: IU: Security: Use InternetCrackUrl to verify server url used by control.
  1240. URL_COMPONENTS urlComp;
  1241. ZeroMemory(&urlComp, sizeof(urlComp));
  1242. urlComp.dwStructSize = sizeof(urlComp);
  1243. // Only interested in the hostname
  1244. LPTSTR pszHostName = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  1245. urlComp.lpszHostName = pszHostName;
  1246. urlComp.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
  1247. #if defined(UNICODE)
  1248. pfn_InternetCrackUrl pfnInternetCrackUrl = (pfn_InternetCrackUrl)GetProcAddress(
  1249. GetModuleHandle(_T("wininet.dll")), "InternetCrackUrlW");
  1250. #else
  1251. pfn_InternetCrackUrl pfnInternetCrackUrl = (pfn_InternetCrackUrl)GetProcAddress(
  1252. GetModuleHandle(_T("wininet.dll")), "InternetCrackUrlA");
  1253. #endif
  1254. if (pfnInternetCrackUrl != NULL)
  1255. {
  1256. BOOL fRet = (*pfnInternetCrackUrl)(lpszUrl, 0, 0, &urlComp);
  1257. if (fRet==FALSE) {
  1258. SafeHeapFree(pszHostName);
  1259. m_hValidated = INET_E_INVALID_URL;
  1260. goto CleanUp;
  1261. }
  1262. }
  1263. else
  1264. {
  1265. SafeHeapFree(pszHostName);
  1266. SafeReleaseNULL(pISP);
  1267. SafeReleaseNULL(pWeb);
  1268. SysFreeString(bstrUrl);
  1269. SafeHeapFree(szValidURL);
  1270. m_hValidated = ERROR_PROC_NOT_FOUND;
  1271. LOG_ErrorMsg(m_hValidated);
  1272. return m_hValidated;
  1273. }
  1274. //
  1275. // get number to servers to compare
  1276. //
  1277. int iServerCnt = GetPrivateProfileInt(IDENT_IUSERVERCACHE,
  1278. IDENT_IUSERVERCOUNT,
  1279. -1,
  1280. szIdentFile);
  1281. //
  1282. // loop through
  1283. //
  1284. URL_COMPONENTS urlCompi;
  1285. m_hValidated = INET_E_INVALID_URL;
  1286. for (INT i=1; i<=iServerCnt; i++)
  1287. {
  1288. StringCchPrintfEx(szServer,ARRAYSIZE(szServer),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%d"), IDENT_IUSERVER, i);
  1289. //
  1290. // get valid server from iuident
  1291. //
  1292. GetPrivateProfileString(IDENT_IUSERVERCACHE,
  1293. szServer,
  1294. _T(""),
  1295. szValidURL,
  1296. INTERNET_MAX_URL_LENGTH,
  1297. szIdentFile);
  1298. ZeroMemory(&urlCompi, sizeof(urlCompi));
  1299. urlCompi.dwStructSize = sizeof(urlCompi);
  1300. LPTSTR pszHostNamei = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  1301. urlCompi.lpszHostName = pszHostNamei;
  1302. urlCompi.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
  1303. if (TRUE == (*pfnInternetCrackUrl)(szValidURL, 0, 0, &urlCompi))
  1304. {
  1305. if (0 == lstrcmpi(urlComp.lpszHostName, urlCompi.lpszHostName))
  1306. {
  1307. //
  1308. // Found the current site URL is in this valid URL domain!
  1309. //
  1310. LogMessage("Windows Update Web Site has a valid address: %ls", bstrUrl);
  1311. m_hValidated = S_OK;
  1312. SafeHeapFree(pszHostNamei);
  1313. break;
  1314. }
  1315. }
  1316. SafeHeapFree(pszHostNamei);
  1317. }
  1318. SafeHeapFree(pszHostName);
  1319. }
  1320. }
  1321. else
  1322. {
  1323. //
  1324. // NTRAID#NTBUG9-436604-2001/07/17-waltw Security fix: block possible user system information
  1325. // leak to non WU callers
  1326. //
  1327. // If the COM user doesn't call SetSite on our IObjectWithSiteImpl to set m_pClientSite or doesn't
  1328. // support IID_IWebBrowserApp functionality on the client site then we won't support them since
  1329. // we can't validate the URL that invoked us
  1330. //
  1331. m_hValidated = INET_E_INVALID_URL;
  1332. }
  1333. CleanUp:
  1334. SafeReleaseNULL(pISP);
  1335. SafeReleaseNULL(pWeb);
  1336. SysFreeString(bstrUrl);
  1337. SafeHeapFree(szValidURL);
  1338. LOG_Internet(_T("Validate result: %s"), SUCCEEDED(m_hValidated) ? _T("S_OK") : _T("INET_E_INVALID_URL"));
  1339. if (FAILED(m_hValidated) && NULL != lpszUrl)
  1340. {
  1341. #if defined(UNICODE) || defined(_UNICODE)
  1342. LogError(m_hValidated, "Site URL %ls is not valid", lpszUrl);
  1343. #else
  1344. LogError(m_hValidated, "Site URL %s is not valid", lpszUrl);
  1345. #endif
  1346. }
  1347. #if !(defined(UNICODE) || defined(_UNICODE))
  1348. if (NULL != lpszAnsiUrl)
  1349. {
  1350. HeapFree(GetProcessHeap(), 0, (LPVOID) lpszAnsiUrl);
  1351. }
  1352. #endif
  1353. return m_hValidated;
  1354. }
  1355. /////////////////////////////////////////////////////////////////////////////
  1356. //
  1357. // PRIVATE DetectEngine()
  1358. //
  1359. // download the ident and find out if need to update engine
  1360. //
  1361. // Note that this function itself is not thread safe. Need to call it
  1362. // inside critical section
  1363. //
  1364. /////////////////////////////////////////////////////////////////////////////
  1365. HRESULT CUpdate::DetectEngine(BOOL *pfUpdateAvail)
  1366. {
  1367. LOG_Block("GetPropUpdateInfo()");
  1368. if (!m_gfInit_csLock)
  1369. {
  1370. return E_OUTOFMEMORY;
  1371. }
  1372. HRESULT hr = S_OK;
  1373. if (NULL == pfUpdateAvail)
  1374. {
  1375. return E_INVALIDARG;
  1376. }
  1377. *pfUpdateAvail = FALSE;
  1378. //
  1379. // get the latest ident
  1380. //
  1381. if (NULL == m_hEngineModule)
  1382. {
  1383. //
  1384. // This is the first load of the engine for this instance, check for selfupdate first.
  1385. // First step is to check for an updated iuident.cab and download it.
  1386. //
  1387. //
  1388. // Only Download the Ident if we are NOT in Offline Mode
  1389. //
  1390. if (!m_fOfflineMode)
  1391. {
  1392. //
  1393. // download iuident and populate g_pIUUrlAgent
  1394. //
  1395. if (FAILED(hr = DownloadIUIdent_PopulateData()))
  1396. {
  1397. LOG_ErrorMsg(hr);
  1398. return hr;
  1399. }
  1400. //
  1401. // check engine update info. Note that since 2nd pram is FALSE
  1402. // means don't do any actual update, therefore its 1st argument
  1403. // is also ignored.
  1404. //
  1405. hr = SelfUpdateCheck(
  1406. FALSE, // async update? ignored now
  1407. FALSE, // don't do actual update
  1408. m_evtControlQuit, // quit event.
  1409. NULL, // no event firing
  1410. NULL // no callback needed
  1411. );
  1412. if (IU_SELFUPDATE_FAILED == hr)
  1413. {
  1414. LOG_Error(_T("SelfUpdate Failed, using current Engine DLL"));
  1415. hr = S_FALSE; // not fatal, let the existing engine work
  1416. }
  1417. *pfUpdateAvail = (S_FALSE == hr);
  1418. }
  1419. }
  1420. return hr;
  1421. }
  1422. /////////////////////////////////////////////////////////////////////////////
  1423. //
  1424. // Initialize() API must be called before any other API will function
  1425. //
  1426. // If any other API is called before the control is initialized,
  1427. // that API will return OLE_E_BLANK, signalling this OLE control is an
  1428. // uninitialized object (although in this case it's a bit different from
  1429. // its original meaning)
  1430. //
  1431. // Parameters:
  1432. //
  1433. // lInitFlag - IU_INIT_CHECK, cause Initialize() download ident and check if any
  1434. // of the components need updated. currently we support control version
  1435. // check and engine version check. Return value is a bit mask
  1436. //
  1437. // - IU_INIT_UPDATE_SYNC, cause Initialize() kicks off update engine
  1438. // process if already called by IU_INIT_CHECK and a new engine is available.
  1439. // When API returns, the update process is finished.
  1440. //
  1441. // - IU_INIT_UPDATE_ASYNC, cause Initialize() kicks off update engine
  1442. // process in Asynchronized mode if already called by IU_INIT_CHECK and
  1443. // a new engine is available. This API will return right after the
  1444. // update process starts.
  1445. //
  1446. // punkUpdateCompleteListener - this is a pointer to a user-implemented
  1447. // COM callback feature. It contains only one function OnComplete() that
  1448. // will be called when the engine update is done.
  1449. // This value can be NULL.
  1450. //
  1451. /////////////////////////////////////////////////////////////////////////////
  1452. STDMETHODIMP CUpdate::Initialize(LONG lInitFlag, IUnknown *punkUpdateCompleteListener, LONG *plRetVal)
  1453. {
  1454. HRESULT hr = S_OK;
  1455. LOG_Block("Initialize()");
  1456. if (!m_gfInit_csLock)
  1457. {
  1458. return E_OUTOFMEMORY;
  1459. }
  1460. TCHAR szFilePath[MAX_PATH + 1] = {0};
  1461. FILE_VERSION verControl;
  1462. int iCompareResult = 0;
  1463. DWORD dwErr = 0;
  1464. char szAnsiRequiredControlVersion[64];
  1465. LOG_Out(_T("Parameters: (0x%08x, 0x%08x, 0x%08x)"), lInitFlag, punkUpdateCompleteListener, plRetVal);
  1466. //
  1467. // we should to previlidge check first.
  1468. //
  1469. if (1 == IsWindowsUpdateUserAccessDisabled())
  1470. {
  1471. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  1472. return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
  1473. }
  1474. if (0x0 == GetLogonGroupInfo())
  1475. {
  1476. //
  1477. // if the current logon is neither member of admins nor power users
  1478. // or windows update is disabled, there is no need to continue
  1479. //
  1480. return E_ACCESSDENIED;
  1481. }
  1482. USES_CONVERSION;
  1483. EnterCriticalSection(&m_lock);
  1484. LPTSTR ptszLivePingServerUrl = NULL;
  1485. LPTSTR ptszCorpPingServerUrl = NULL;
  1486. if (NULL != (ptszCorpPingServerUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR))))
  1487. {
  1488. if (FAILED(g_pIUUrlAgent->GetCorpPingServer(ptszCorpPingServerUrl, INTERNET_MAX_URL_LENGTH)))
  1489. {
  1490. LOG_Out(_T("failed to get corp WU ping server URL"));
  1491. SafeHeapFree(ptszCorpPingServerUrl);
  1492. }
  1493. }
  1494. else
  1495. {
  1496. LOG_Out(_T("failed to allocate memory for ptszCorpPingServerUrl"));
  1497. }
  1498. if (IU_INIT_CHECK == lInitFlag)
  1499. {
  1500. // RAID: 453770 IU - IUCTL - Initialize check returns Engine update required
  1501. // after downloading new engine using Initialize Sync/Async
  1502. // Fix: initialize dwFlag to 0 rather than m_dwUpdateInfo (carried forward
  1503. // previous IU_UPDATE_ENGINE_BIT even when new engine had been brought down).
  1504. DWORD dwFlag = 0;
  1505. BOOL fEngineUpdate = FALSE;
  1506. FILE_VERSION verCurrent;
  1507. CleanUpIfFalseAndSetHrMsg((NULL == plRetVal), E_INVALIDARG);
  1508. hr = DetectEngine(&fEngineUpdate);
  1509. if (IU_SELFUPDATE_USENEWDLL == hr)
  1510. {
  1511. //
  1512. // found engine already been updated by someone,
  1513. // but not renamed to iuengine.dll yet
  1514. //
  1515. // doesn't matter to us,since we always try
  1516. // to load enginenew before we try to load eng.
  1517. //
  1518. hr = S_OK;
  1519. }
  1520. if (g_pIUUrlAgent->HasBeenPopulated())
  1521. {
  1522. ptszLivePingServerUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  1523. CleanUpFailedAllocSetHrMsg(ptszLivePingServerUrl);
  1524. if (FAILED(g_pIUUrlAgent->GetLivePingServer(ptszLivePingServerUrl, INTERNET_MAX_URL_LENGTH)))
  1525. {
  1526. LOG_Out(_T("failed to get live ping server URL"));
  1527. SafeHeapFree(ptszLivePingServerUrl);
  1528. }
  1529. }
  1530. CleanUpIfFailedAndMsg(hr);
  1531. if (fEngineUpdate)
  1532. {
  1533. dwFlag = IU_UPDATE_ENGINE_BIT;
  1534. }
  1535. //
  1536. // get required version number of iuctl from iuident
  1537. //
  1538. GetIndustryUpdateDirectory(szFilePath);
  1539. CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), IDENTTXT));
  1540. (void) GetPrivateProfileString(
  1541. _T("IUControl"),
  1542. _T("ControlVer"),
  1543. _T("0.0.0.0"),
  1544. m_szReqControlVer,
  1545. ARRAYSIZE(m_szReqControlVer),
  1546. szFilePath);
  1547. #ifdef UNICODE
  1548. WideCharToMultiByte(CP_ACP, 0, m_szReqControlVer, -1, szAnsiRequiredControlVersion,
  1549. sizeof(szAnsiRequiredControlVersion), NULL, NULL);
  1550. ConvertStringVerToFileVer(szAnsiRequiredControlVersion, &verControl);
  1551. #else
  1552. ConvertStringVerToFileVer(m_szReqControlVer, &verControl);
  1553. #endif
  1554. //
  1555. // get current iuctl.dll version number
  1556. //
  1557. szFilePath[0] = _T('\0');
  1558. if (0 == GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)))
  1559. {
  1560. Win32MsgSetHrGotoCleanup(GetLastError());
  1561. }
  1562. CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuctl.dll")));
  1563. //
  1564. // change for bug fix 488487 by charlma 11/30/2001
  1565. // in order to output file ver to freelog, we dig out verionn here:
  1566. //
  1567. //
  1568. // if we failed to get the version, GetFileVersion() alraedy produced debug log.
  1569. // we just use 0.0.0.0 to do compare, since in that case we need to update it!
  1570. //
  1571. ZeroMemory((void*)(&verCurrent), sizeof(verCurrent));
  1572. if (GetFileVersion(szFilePath, &verCurrent))
  1573. {
  1574. LogMessage("Current iuctl.dll version: %d.%d.%d.%d",
  1575. verCurrent.Major,
  1576. verCurrent.Minor,
  1577. verCurrent.Build,
  1578. verCurrent.Ext);
  1579. }
  1580. iCompareResult = CompareFileVersion(verCurrent, verControl);
  1581. //CleanUpIfFailedAndSetHrMsg(CompareFileVersion(szFilePath, verControl, &iCompareResult));
  1582. if (iCompareResult < 0)
  1583. {
  1584. //
  1585. // if current control dll (szFilePath) has lower version
  1586. // then the one specified in ident
  1587. //
  1588. dwFlag |= IU_UPDATE_CONTROL_BIT;
  1589. #if defined(UNICODE) || defined(_UNICODE)
  1590. LogMessage("IUCtl needs update to %ls", m_szReqControlVer);
  1591. #else
  1592. LogMessage("IUCtl needs update to %s", m_szReqControlVer);
  1593. #endif
  1594. }
  1595. //
  1596. // also output engine version
  1597. //
  1598. if ((0 != GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)) &&
  1599. SUCCEEDED(hr = PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuenginenew.dll"))) &&
  1600. GetFileVersion(szFilePath, &verCurrent)) ||
  1601. (0 != GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)) &&
  1602. SUCCEEDED(hr = PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuengine.dll"))) &&
  1603. GetFileVersion(szFilePath, &verCurrent))
  1604. )
  1605. {
  1606. LogMessage("Current iuengine.dll version: %d.%d.%d.%d",
  1607. verCurrent.Major,
  1608. verCurrent.Minor,
  1609. verCurrent.Build,
  1610. verCurrent.Ext);
  1611. }
  1612. *plRetVal = (LONG) dwFlag;
  1613. m_dwUpdateInfo = dwFlag;
  1614. if (0x0 == dwFlag)
  1615. {
  1616. //
  1617. // no update needed. move to READY stage
  1618. //
  1619. m_lInitState = 2;
  1620. }
  1621. else
  1622. {
  1623. m_lInitState = 1; // we have update work to do!
  1624. }
  1625. }
  1626. else
  1627. {
  1628. BOOL fSync = (IU_INIT_UPDATE_SYNC == lInitFlag);
  1629. if (!fSync && (IU_INIT_UPDATE_ASYNC != lInitFlag))
  1630. {
  1631. //
  1632. // unknown flag
  1633. //
  1634. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  1635. }
  1636. if (1 != m_lInitState || (m_dwUpdateInfo & IU_UPDATE_CONTROL_BIT))
  1637. {
  1638. //
  1639. // if we are not indicated that update needed. this
  1640. // call shouldn't happen at all!
  1641. //
  1642. SetHrMsgAndGotoCleanUp(E_UNEXPECTED);
  1643. }
  1644. //
  1645. // we need to check update again before we kick off the
  1646. // actual update process since we don't know when last
  1647. // time you get the info saying we need to update. Probably
  1648. // it's already been updated, or is being updated.
  1649. //
  1650. // so we call the check function again but this time tell
  1651. // the check function that if update needed then do it.
  1652. //
  1653. hr = SelfUpdateCheck(fSync, TRUE, m_evtControlQuit, this, punkUpdateCompleteListener);
  1654. if (IU_SELFUPDATE_USENEWDLL == hr)
  1655. {
  1656. //
  1657. // found engine already been updated by someone,
  1658. // but not renamed to iuengine.dll yet
  1659. //
  1660. // doesn't matter to us,since we always try
  1661. // to load enginenew before we try to load eng.
  1662. //
  1663. m_lInitState = 2;
  1664. hr = S_OK;
  1665. }
  1666. if (fSync && SUCCEEDED(hr))
  1667. {
  1668. //
  1669. // synchronized update done and successful
  1670. //
  1671. m_lInitState = 2;
  1672. }
  1673. if (NULL != plRetVal)
  1674. {
  1675. *plRetVal = (LONG)hr; // result pass out: 0 or error code
  1676. }
  1677. }
  1678. if (2 == m_lInitState)
  1679. {
  1680. if (NULL == m_hEngineModule)
  1681. {
  1682. //
  1683. // check if iuengine new exist and validate the file
  1684. //
  1685. TCHAR szEnginePath[MAX_PATH + 1];
  1686. TCHAR szEngineNewPath[MAX_PATH + 1];
  1687. int cch = 0;
  1688. int iVerCheck = 0;
  1689. cch = GetSystemDirectory(szEnginePath, ARRAYSIZE(szEnginePath));
  1690. CleanUpIfFalseAndSetHrMsg(cch == 0 || cch >= ARRAYSIZE(szEnginePath), HRESULT_FROM_WIN32(GetLastError()));
  1691. (void) StringCchCopy(szEngineNewPath, ARRAYSIZE(szEngineNewPath), szEnginePath);
  1692. hr = PathCchAppend(szEnginePath, ARRAYSIZE(szEnginePath), ENGINEDLL);
  1693. CleanUpIfFailedAndMsg(hr);
  1694. hr = PathCchAppend(szEngineNewPath, ARRAYSIZE(szEngineNewPath), ENGINENEWDLL);
  1695. CleanUpIfFailedAndMsg(hr);
  1696. //
  1697. // try to verify trust of engine new
  1698. //
  1699. if (FileExists(szEngineNewPath) &&
  1700. S_OK == VerifyFileTrust(szEngineNewPath, NULL, ReadWUPolicyShowTrustUI()) &&
  1701. SUCCEEDED(CompareFileVersion(szEnginePath, szEngineNewPath, &iVerCheck)) &&
  1702. iVerCheck < 0)
  1703. {
  1704. //
  1705. // load the engine
  1706. //
  1707. m_hEngineModule = LoadLibraryFromSystemDir(_T("iuenginenew.dll"));
  1708. }
  1709. if (NULL != m_hEngineModule)
  1710. {
  1711. LOG_Internet(_T("IUCtl Using IUENGINENEW.DLL"));
  1712. }
  1713. else
  1714. {
  1715. LOG_Internet(_T("IUCtl Using IUENGINE.DLL"));
  1716. m_hEngineModule = LoadLibraryFromSystemDir(_T("iuengine.dll"));
  1717. if (NULL == m_hEngineModule)
  1718. {
  1719. dwErr = GetLastError();
  1720. LOG_ErrorMsg(dwErr);
  1721. hr = HRESULT_FROM_WIN32(dwErr);
  1722. }
  1723. }
  1724. //
  1725. // If load engine succeeded, get a CEngUpdate instance and start aynsc misc worker threads
  1726. //
  1727. if (NULL != m_hEngineModule)
  1728. {
  1729. #if defined(DBG)
  1730. // Log error if m_hIUEngine isn't NULL
  1731. if (NULL != m_hIUEngine)
  1732. {
  1733. LOG_Error(_T("m_hIUEngine should be NULL here!"));
  1734. }
  1735. #endif
  1736. PFN_CreateEngUpdateInstance pfnCreateEngUpdateInstance =
  1737. (PFN_CreateEngUpdateInstance) GetProcAddress(m_hEngineModule, "CreateEngUpdateInstance");
  1738. if (NULL != pfnCreateEngUpdateInstance)
  1739. {
  1740. m_hIUEngine = pfnCreateEngUpdateInstance();
  1741. }
  1742. if (NULL == m_hIUEngine)
  1743. {
  1744. hr = E_OUTOFMEMORY;
  1745. LOG_ErrorMsg(hr);
  1746. FreeLibrary(m_hEngineModule);
  1747. m_hEngineModule = NULL;
  1748. }
  1749. else
  1750. {
  1751. //
  1752. // If load engine and create instance succeeded, start aynsc misc worker threads
  1753. //
  1754. PFN_AsyncExtraWorkUponEngineLoad pfnAsyncExtraWorkUponEngineLoad =
  1755. (PFN_AsyncExtraWorkUponEngineLoad) GetProcAddress(m_hEngineModule, "AsyncExtraWorkUponEngineLoad");
  1756. if (NULL != pfnAsyncExtraWorkUponEngineLoad)
  1757. {
  1758. pfnAsyncExtraWorkUponEngineLoad();
  1759. }
  1760. }
  1761. }
  1762. }
  1763. if (IU_INIT_UPDATE_ASYNC == lInitFlag && SUCCEEDED(hr))
  1764. {
  1765. //
  1766. // this is a rare case: the previous Iniitalize() call tells
  1767. // that engine update needed, but now, when we try to update it
  1768. // in async mode, we found it's no longer true.
  1769. // Must be some other process already complete the engine update
  1770. // task since then. But it may or may not completed the change
  1771. // file name process yet.
  1772. //
  1773. // For us, we just need to signal that we are done to update.
  1774. //
  1775. //
  1776. // signal callback
  1777. //
  1778. IUpdateCompleteListener* pCallback = NULL;
  1779. if (NULL != punkUpdateCompleteListener && (SUCCEEDED(hr = punkUpdateCompleteListener->QueryInterface(IID_IUpdateCompleteListener, (void**) &pCallback))))
  1780. {
  1781. pCallback->OnComplete(dwErr);
  1782. pCallback->Release();
  1783. LOG_Out(_T("Returned from callback API OnComplete()"));
  1784. }
  1785. else
  1786. {
  1787. //
  1788. // signal event if user has not passed in a progress listner IUnknown ptr
  1789. //
  1790. HWND hWnd = m_EvtWindow.GetEvtHWnd();
  1791. if (NULL != hWnd)
  1792. {
  1793. PostMessage(hWnd, UM_EVENT_SELFUPDATE_COMPLETE, 0, (LPARAM)dwErr);
  1794. LOG_Out(_T("Fired event OnComplete()"));
  1795. }
  1796. }
  1797. hr = S_OK;
  1798. }
  1799. }
  1800. CleanUp:
  1801. PingEngineUpdate(
  1802. m_hEngineModule,
  1803. &g_hEngineLoadQuit,
  1804. 1,
  1805. ptszLivePingServerUrl,
  1806. ptszCorpPingServerUrl,
  1807. hr,
  1808. _T("IU_SITE")); // Only the site (other than test) calls this function
  1809. LeaveCriticalSection(&m_lock);
  1810. SafeHeapFree(ptszLivePingServerUrl);
  1811. SafeHeapFree(ptszCorpPingServerUrl);
  1812. return hr;
  1813. }
  1814. HRESULT CUpdate::ChangeControlInitState(LONG lNewState)
  1815. {
  1816. HRESULT hr = S_OK;
  1817. LOG_Block("ChangeControlInitState()");
  1818. if (!m_gfInit_csLock)
  1819. {
  1820. return E_OUTOFMEMORY;
  1821. }
  1822. EnterCriticalSection(&m_lock);
  1823. m_lInitState = lNewState;
  1824. if (2 == m_lInitState && NULL == m_hEngineModule)
  1825. {
  1826. //
  1827. // load the engine
  1828. //
  1829. m_hEngineModule = LoadLibraryFromSystemDir(_T("iuenginenew.dll"));
  1830. if (NULL != m_hEngineModule)
  1831. {
  1832. LOG_Internet(_T("IUCtl Using IUENGINENEW.DLL"));
  1833. }
  1834. else
  1835. {
  1836. LOG_Internet(_T("IUCtl Using IUENGINE.DLL"));
  1837. m_hEngineModule = LoadLibraryFromSystemDir(_T("iuengine.dll"));
  1838. if (NULL == m_hEngineModule)
  1839. {
  1840. DWORD dwErr = GetLastError();
  1841. LOG_ErrorMsg(dwErr);
  1842. hr = HRESULT_FROM_WIN32(dwErr);
  1843. }
  1844. }
  1845. //
  1846. // Create the CEngUpdate instance
  1847. //
  1848. if (NULL != m_hEngineModule)
  1849. {
  1850. #if defined(DBG)
  1851. // Log error if m_hIUEngine isn't NULL
  1852. if (NULL != m_hIUEngine)
  1853. {
  1854. LOG_Error(_T("m_hIUEngine should be NULL here!"));
  1855. }
  1856. #endif
  1857. PFN_CreateEngUpdateInstance pfnCreateEngUpdateInstance =
  1858. (PFN_CreateEngUpdateInstance) GetProcAddress(m_hEngineModule, "CreateEngUpdateInstance");
  1859. if (NULL != pfnCreateEngUpdateInstance)
  1860. {
  1861. m_hIUEngine = pfnCreateEngUpdateInstance();
  1862. }
  1863. if (NULL == m_hIUEngine)
  1864. {
  1865. hr = E_OUTOFMEMORY;
  1866. LOG_ErrorMsg(hr);
  1867. FreeLibrary(m_hEngineModule);
  1868. m_hEngineModule = NULL;
  1869. }
  1870. }
  1871. }
  1872. LeaveCriticalSection(&m_lock);
  1873. return hr;
  1874. }
  1875. STDMETHODIMP CUpdate::PrepareSelfUpdate(LONG lStep)
  1876. {
  1877. return E_NOTIMPL;
  1878. }
  1879. /////////////////////////////////////////////////////////////////////////////
  1880. //
  1881. // Helper API to let the caller (script) knows the necessary information
  1882. // when Initialize() returns control need updated.
  1883. //
  1884. // For the current implementation, bstrClientName is ignored, and
  1885. // the returned bstr has format:
  1886. // "<version>|<url>"
  1887. // where:
  1888. // <version> is the expacted version number of the control
  1889. // <url> is the base url to get the control if this is a CorpWU policy controlled machine,
  1890. // or empty if this is a consumer machine (in that case caller, i.e., script, knows
  1891. // the default base url, which is the v4 live site)
  1892. //
  1893. // Script will need these two pieces of information in order to make a right <OBJECT> tag
  1894. // for control update.
  1895. //
  1896. /////////////////////////////////////////////////////////////////////////////
  1897. STDMETHODIMP CUpdate::GetControlExtraInfo(BSTR bstrClientName, BSTR *pbstrExtraInfo)
  1898. {
  1899. return E_NOTIMPL;
  1900. }
  1901. /////////////////////////////////////////////////////////////////////////////
  1902. //
  1903. // new Win32 API called by wrapper control to retrieve update info
  1904. //
  1905. //
  1906. /////////////////////////////////////////////////////////////////////////////
  1907. int GetControlUpdateInfo(LPTSTR lpszUpdateInfo, int cchBufferSize)
  1908. {
  1909. LOG_Block("GetControlUpdateInfo()");
  1910. HRESULT hr = S_OK;
  1911. int nSize = 0;
  1912. BOOL fCorpUser = FALSE, fBetaSelfUpdate = FALSE;
  1913. FILE_VERSION fvCurrentCtl, fvCurrentEngine;
  1914. TCHAR szDir[MAX_PATH];
  1915. TCHAR szFile[MAX_PATH];
  1916. TCHAR szExpectedEngVer[64]; // 64 should be more then enough
  1917. TCHAR szExpectedCtlVer[64]; // if not enough, then it's bad data anyway
  1918. HKEY hKey;
  1919. DWORD dwErr = ERROR_SUCCESS; // error code for this API
  1920. if (1 == IsWindowsUpdateUserAccessDisabled())
  1921. {
  1922. dwErr = ERROR_SERVICE_DISABLED;
  1923. LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
  1924. goto CleanUp;
  1925. }
  1926. if (0x0 == GetLogonGroupInfo())
  1927. {
  1928. dwErr = ERROR_ACCESS_DENIED;
  1929. goto CleanUp;
  1930. }
  1931. if (FAILED(hr = DownloadIUIdent_PopulateData()))
  1932. {
  1933. LOG_ErrorMsg(hr);
  1934. dwErr = hr;
  1935. goto CleanUp;
  1936. }
  1937. //
  1938. // get current control ver
  1939. //
  1940. GetSystemDirectory(szDir, ARRAYSIZE(szDir));
  1941. hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IUCTL);
  1942. if (FAILED(hr))
  1943. {
  1944. LOG_ErrorMsg(hr);
  1945. dwErr = hr;
  1946. goto CleanUp;
  1947. }
  1948. if (!GetFileVersion(szFile, &fvCurrentCtl))
  1949. {
  1950. ZeroMemory(&fvCurrentCtl, sizeof(fvCurrentCtl));
  1951. }
  1952. //
  1953. // get current engine ver
  1954. //
  1955. hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,ENGINENEWDLL);
  1956. if (FAILED(hr))
  1957. {
  1958. LOG_ErrorMsg(hr);
  1959. dwErr = hr;
  1960. goto CleanUp;
  1961. }
  1962. if (!GetFileVersion(szFile, &fvCurrentEngine))
  1963. {
  1964. //
  1965. // if no engine new there, check engine ver
  1966. //
  1967. hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,ENGINEDLL);
  1968. if (FAILED(hr))
  1969. {
  1970. LOG_ErrorMsg(hr);
  1971. dwErr = hr;
  1972. goto CleanUp;
  1973. }
  1974. if (!GetFileVersion(szFile, &fvCurrentEngine))
  1975. {
  1976. ZeroMemory(&fvCurrentCtl, sizeof(fvCurrentEngine));
  1977. }
  1978. }
  1979. //
  1980. // check if this is beta code
  1981. //
  1982. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL,0, KEY_READ, &hKey))
  1983. {
  1984. // Check for Beta IU SelfUpdate Handling Requested
  1985. DWORD dwStatus = 0;
  1986. DWORD dwSize = sizeof(dwStatus);
  1987. DWORD dwRet = RegQueryValueEx(hKey, REGVAL_BETASELFUPDATE, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
  1988. if (1 == dwStatus)
  1989. {
  1990. fBetaSelfUpdate = TRUE;
  1991. }
  1992. RegCloseKey(hKey);
  1993. }
  1994. //
  1995. // get expected control ver
  1996. //
  1997. GetIndustryUpdateDirectory(szDir);
  1998. hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IDENTTXT);
  1999. if (FAILED(hr))
  2000. {
  2001. LOG_ErrorMsg(hr);
  2002. dwErr = hr;
  2003. goto CleanUp;
  2004. }
  2005. GetPrivateProfileString(_T("IUControl"),
  2006. _T("ControlVer"),
  2007. _T(""),
  2008. szExpectedCtlVer,
  2009. ARRAYSIZE(szExpectedCtlVer),
  2010. szFile);
  2011. if ('\0' == szExpectedCtlVer[0])
  2012. {
  2013. //
  2014. // no selfupdate available, no server version information. bad ident?
  2015. //
  2016. dwErr = ERROR_FILE_CORRUPT;
  2017. goto CleanUp;
  2018. }
  2019. //
  2020. // get expected engine ver
  2021. //
  2022. GetIndustryUpdateDirectory(szDir);
  2023. hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IDENTTXT);
  2024. if (FAILED(hr))
  2025. {
  2026. LOG_ErrorMsg(hr);
  2027. dwErr = hr;
  2028. goto CleanUp;
  2029. }
  2030. GetPrivateProfileString(fBetaSelfUpdate ? IDENT_IUBETASELFUPDATE : IDENT_IUSELFUPDATE,
  2031. IDENT_VERSION,
  2032. _T(""),
  2033. szExpectedEngVer,
  2034. ARRAYSIZE(szExpectedEngVer),
  2035. szFile);
  2036. if ('\0' == szExpectedEngVer[0])
  2037. {
  2038. //
  2039. // no selfupdate available, no server version information. bad ident?
  2040. //
  2041. dwErr = ERROR_FILE_CORRUPT;
  2042. goto CleanUp;
  2043. }
  2044. hr = g_pIUUrlAgent->IsIdentFromPolicy();
  2045. if (FAILED(hr))
  2046. {
  2047. dwErr = (DWORD)hr;
  2048. goto CleanUp;
  2049. }
  2050. fCorpUser = (S_OK == hr) ? TRUE : FALSE;
  2051. hr = S_OK;
  2052. //
  2053. // contscut data
  2054. // the constructed buffer will be in format
  2055. // <CurrentCtlVer>|<ExpCtlVer>|CurrentEngVer>|<ExpEngVer>|<baseUrl>
  2056. //
  2057. nSize = wnsprintf(lpszUpdateInfo, cchBufferSize, _T("%d.%d.%d.%d|%s|%d.%d.%d.%d|%s|%d"),
  2058. fvCurrentCtl.Major, fvCurrentCtl.Minor, fvCurrentCtl.Build, fvCurrentCtl.Ext,
  2059. szExpectedCtlVer,
  2060. fvCurrentEngine.Major, fvCurrentEngine.Minor, fvCurrentEngine.Build, fvCurrentEngine.Ext,
  2061. szExpectedEngVer,
  2062. fCorpUser ? 1 : 0);
  2063. if (nSize < 0)
  2064. {
  2065. nSize = 0;
  2066. dwErr = ERROR_INSUFFICIENT_BUFFER;
  2067. goto CleanUp;
  2068. }
  2069. CleanUp:
  2070. SetLastError(dwErr);
  2071. return nSize;
  2072. }