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.

593 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: updates.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. /////////////////////////////////////////////////////////////////////////////
  13. //
  14. GENERIC_MAPPING Updates::m_AdminGenericMapping = {
  15. STANDARD_RIGHTS_READ, // Generic read
  16. STANDARD_RIGHTS_WRITE, // Generic write
  17. STANDARD_RIGHTS_EXECUTE, // Generic execute
  18. STANDARD_RIGHTS_READ | // Generic all
  19. STANDARD_RIGHTS_WRITE |
  20. STANDARD_RIGHTS_EXECUTE
  21. };
  22. Updates::Updates()
  23. : m_pAdminSid(NULL),
  24. m_pAdminAcl(NULL),
  25. m_refs(0)
  26. {
  27. m_hEngineMutex = CreateMutex(NULL, FALSE, NULL);
  28. }
  29. Updates::~Updates()
  30. {
  31. CloseHandle(m_hEngineMutex);
  32. if ( NULL != m_pAdminAcl )
  33. {
  34. delete m_pAdminAcl;
  35. }
  36. if ( NULL != m_pAdminSid )
  37. {
  38. FreeSid(m_pAdminSid);
  39. }
  40. DEBUGMSG("Updates: CoDisconnectObject");
  41. if ( FAILED(CoDisconnectObject((IUnknown *)this, 0)) )
  42. {
  43. DEBUGMSG("CoDisconnectObject() failed");
  44. }
  45. }
  46. BOOL Updates::m_fInitializeSecurity(void)
  47. {
  48. BOOL fStatus;
  49. ULONG cbAcl;
  50. SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
  51. fStatus = AllocateAndInitializeSid(
  52. &ntAuthority,
  53. 2,
  54. SECURITY_BUILTIN_DOMAIN_RID,
  55. DOMAIN_ALIAS_RID_ADMINS,
  56. 0,0,0,0,0,0,
  57. &m_pAdminSid);
  58. if ( !fStatus )
  59. {
  60. DEBUGMSG("Fail to initialize SID with error %d", GetLastError());
  61. return FALSE;
  62. }
  63. cbAcl = sizeof(ACL)
  64. + sizeof(ACCESS_ALLOWED_ACE)
  65. - sizeof(DWORD) //sizeof(ACCESS_ALLOWED_ACE.SidStart)
  66. + GetLengthSid(m_pAdminSid);
  67. m_pAdminAcl = (PACL) new BYTE[ cbAcl ];
  68. if ( (NULL == m_pAdminAcl)
  69. || !InitializeAcl(m_pAdminAcl, cbAcl, ACL_REVISION)
  70. || !AddAccessAllowedAce(m_pAdminAcl, ACL_REVISION, STANDARD_RIGHTS_WRITE, m_pAdminSid)
  71. || !InitializeSecurityDescriptor(&m_AdminSecurityDesc, SECURITY_DESCRIPTOR_REVISION)
  72. || !SetSecurityDescriptorOwner(&m_AdminSecurityDesc, m_pAdminSid, FALSE)
  73. || !SetSecurityDescriptorGroup(&m_AdminSecurityDesc, m_pAdminSid, FALSE)
  74. || !SetSecurityDescriptorDacl(&m_AdminSecurityDesc, TRUE, m_pAdminAcl, FALSE) )
  75. {
  76. if ( NULL != m_pAdminAcl )
  77. {
  78. delete m_pAdminAcl;
  79. m_pAdminAcl = NULL;
  80. FreeSid(m_pAdminSid);
  81. m_pAdminSid = NULL;
  82. }
  83. return FALSE;
  84. }
  85. return TRUE;
  86. }
  87. HRESULT Updates::m_AccessCheckClient(void)
  88. {
  89. BOOL accessGranted = FALSE;
  90. DWORD grantedAccess;
  91. HANDLE clientToken = NULL;
  92. BYTE privilegeSet[500]; // Large buffer
  93. DWORD privilegeSetSize = sizeof(privilegeSet);
  94. static BOOL fInitSecurity = FALSE;
  95. if ( !fInitSecurity )
  96. {
  97. if ( !(fInitSecurity = m_fInitializeSecurity()) )
  98. {
  99. DEBUGMSG("Fail to initialized SID");
  100. return E_ACCESSDENIED;
  101. }
  102. }
  103. if (FAILED(CoImpersonateClient()))
  104. {
  105. return E_ACCESSDENIED;
  106. }
  107. if ( OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &clientToken) )
  108. {
  109. if (FALSE == AccessCheck(
  110. &m_AdminSecurityDesc,
  111. clientToken,
  112. STANDARD_RIGHTS_WRITE,
  113. &m_AdminGenericMapping,
  114. (PPRIVILEGE_SET) privilegeSet,
  115. &privilegeSetSize,
  116. &grantedAccess,
  117. &accessGranted))
  118. {
  119. DEBUGMSG("Fail to call AccessCheck() with error %d", GetLastError());
  120. }
  121. }
  122. if ( clientToken != NULL )
  123. {
  124. CloseHandle( clientToken );
  125. }
  126. if (FAILED(CoRevertToSelf()))
  127. {
  128. return E_ACCESSDENIED;;
  129. }
  130. return (accessGranted )? S_OK : E_ACCESSDENIED;
  131. }
  132. STDMETHODIMP Updates::QueryInterface(REFIID riid, void **ppvObject)
  133. {
  134. if (NULL == ppvObject)
  135. {
  136. return E_INVALIDARG;
  137. }
  138. if(riid == IID_IUnknown ||
  139. riid == IID_IClassFactory ||
  140. riid == IID_IUpdates)
  141. {
  142. *ppvObject = this;
  143. AddRef();
  144. }
  145. else
  146. {
  147. *ppvObject = NULL;
  148. return E_NOINTERFACE;
  149. }
  150. return S_OK;
  151. }
  152. ULONG __stdcall Updates::AddRef()
  153. {
  154. long cRef = InterlockedIncrement(&m_refs);
  155. DEBUGMSG("Updates AddRef = %d", cRef);
  156. return cRef;
  157. }
  158. ULONG __stdcall Updates::Release()
  159. {
  160. long cRef = InterlockedDecrement(&m_refs);
  161. DEBUGMSG("Updates Release = %d", cRef);
  162. return cRef;
  163. }
  164. STDMETHODIMP Updates::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
  165. {
  166. HRESULT hr = m_AccessCheckClient();
  167. if ( FAILED(hr) )
  168. {
  169. return hr;
  170. }
  171. if(pUnkOuter != NULL)
  172. {
  173. return CLASS_E_NOAGGREGATION;
  174. }
  175. if (NULL == ppvObject)
  176. {
  177. return E_INVALIDARG;
  178. }
  179. if(riid == IID_IUnknown ||
  180. riid == IID_IClassFactory ||
  181. riid == IID_IUpdates)
  182. {
  183. *ppvObject = this;
  184. AddRef();
  185. }
  186. else
  187. {
  188. *ppvObject = NULL;
  189. return E_NOINTERFACE;
  190. }
  191. return S_OK;
  192. }
  193. STDMETHODIMP Updates::LockServer(BOOL /*bFlag*/)
  194. {
  195. HRESULT hr = m_AccessCheckClient();
  196. if ( FAILED(hr) )
  197. {
  198. return hr;
  199. }
  200. return E_FAIL;
  201. }
  202. STDMETHODIMP Updates::AvailableSessions(UINT *pcSess)
  203. {
  204. HRESULT hr = m_AccessCheckClient();
  205. if ( FAILED(hr))
  206. {
  207. return hr;
  208. }
  209. if (NULL == pcSess)
  210. {
  211. return E_INVALIDARG;
  212. }
  213. *pcSess = ::AvailableSessions();
  214. //DEBUGMSG("WUAUENG Updates::AvailableSessions was called and return value is %d", *pcSess);
  215. return S_OK;
  216. }
  217. STDMETHODIMP Updates::get_State(/*[out, retval]*/ AUSTATE *pAuState)
  218. {
  219. HRESULT hr = m_AccessCheckClient();
  220. if ( FAILED(hr) )
  221. {
  222. return hr;
  223. }
  224. if (NULL == pAuState)
  225. {
  226. return E_INVALIDARG;
  227. }
  228. WaitForSingleObject(m_hEngineMutex, INFINITE);
  229. pAuState->dwState = gpState->GetState();
  230. pAuState->fDisconnected = gpState->fDisconnected();
  231. pAuState->dwCltAction = gpState->GetCltAction();
  232. gpState->SetCltAction(AUCLT_ACTION_NONE); //once client read it, reset
  233. ReleaseMutex(m_hEngineMutex);
  234. return S_OK;
  235. }
  236. STDMETHODIMP Updates::GetUpdatesList(/*[out]*/ VARIANT *pUpdates)
  237. {
  238. HRESULT hr = m_AccessCheckClient();
  239. if ( FAILED(hr) )
  240. {
  241. return hr;
  242. }
  243. DEBUGMSG("WUAUENG Getting updates list");
  244. if ( NULL == pUpdates )
  245. {
  246. return E_INVALIDARG;
  247. }
  248. WaitForSingleObject(m_hEngineMutex, INFINITE);
  249. hr = ::GetUpdatesList(pUpdates);
  250. ReleaseMutex(m_hEngineMutex);
  251. return hr;
  252. }
  253. STDMETHODIMP Updates::GetNotifyData(/*[out]*/ CLIENT_NOTIFY_DATA *pNotifyData)
  254. {
  255. HRESULT hr = m_AccessCheckClient();
  256. if ( FAILED(hr) )
  257. {
  258. return hr;
  259. }
  260. DEBUGMSG("WUAUENG Getting client notify data");
  261. if ( NULL == pNotifyData )
  262. {
  263. return E_INVALIDARG;
  264. }
  265. WaitForSingleObject(m_hEngineMutex, INFINITE);
  266. *pNotifyData = gClientNotifyData;
  267. ReleaseMutex(m_hEngineMutex);
  268. return hr;
  269. }
  270. /* fixcode, only used by client, could get rid of and add VARIANT to ClientMessage()*/
  271. STDMETHODIMP Updates::SaveSelections(/*[in]*/ VARIANT vUpdates)
  272. {
  273. HRESULT hr = m_AccessCheckClient();
  274. DEBUGMSG("Updates::SaveSelections start");
  275. if ( FAILED(hr) )
  276. {
  277. goto done;
  278. }
  279. DEBUGMSG("WUAUENG Saving selections, state is %d", gpState->GetState());
  280. if (vUpdates.vt != (VT_ARRAY | VT_VARIANT))
  281. {
  282. DEBUGMSG("WUAUENG invalid variant list");
  283. return E_INVALIDARG;
  284. }
  285. WaitForSingleObject(m_hEngineMutex, INFINITE);
  286. ::saveSelection(&vUpdates);
  287. hr = S_OK;
  288. ReleaseMutex(m_hEngineMutex);
  289. done:
  290. DEBUGMSG("Updates::SaveSelections end");
  291. return hr;
  292. }
  293. STDMETHODIMP Updates::StartDownload(void)
  294. {
  295. DEBUGMSG("WUAUENG updates->StartDownload called");
  296. HRESULT hr = m_AccessCheckClient();
  297. if ( FAILED(hr) )
  298. {
  299. return hr;
  300. }
  301. WaitForSingleObject(m_hEngineMutex, INFINITE);
  302. hr = ::StartDownload();
  303. ReleaseMutex(m_hEngineMutex);
  304. return hr;
  305. }
  306. STDMETHODIMP Updates::GetDownloadStatus(UINT *pPercentage, DWORD *pStatus)
  307. {
  308. HRESULT hr = m_AccessCheckClient();
  309. if ( FAILED(hr) )
  310. {
  311. return hr;
  312. }
  313. if ((NULL == pPercentage) || (NULL == pStatus))
  314. {
  315. return E_INVALIDARG;
  316. }
  317. WaitForSingleObject(m_hEngineMutex, INFINITE);
  318. hr = ::GetDownloadStatus(pPercentage, pStatus);
  319. ReleaseMutex(m_hEngineMutex);
  320. return hr;
  321. }
  322. STDMETHODIMP Updates::SetDownloadPaused(/*[in]*/ BOOL bPaused)
  323. {
  324. HRESULT hr = m_AccessCheckClient();
  325. if ( FAILED(hr) )
  326. {
  327. return hr;
  328. }
  329. return PauseDownload(bPaused);
  330. }
  331. STDMETHODIMP Updates::ClientMessage(/*[in]*/ UINT msg)
  332. {
  333. HRESULT hr = m_AccessCheckClient();
  334. if ( FAILED(hr) )
  335. {
  336. return hr;
  337. }
  338. // fixcode is this whole interface just one big security whole? what about other
  339. // routines. can't anyone call them?
  340. switch (msg)
  341. {
  342. case AUMSG_PRE_INSTALL:
  343. DEBUGMSG("WUAUENG ClientMessage(AUMSG_PRE_INSTALL)");
  344. DEBUGMSG("WUAUENG Msg:Install, State->Install Pending");
  345. gpState->SetState(AUSTATE_INSTALL_PENDING); // is there any benefit to doing this?
  346. break;
  347. default:
  348. DEBUGMSG("WUAUENG ClientMessage(!!unknown!!)");
  349. break;
  350. }
  351. return S_OK;
  352. }
  353. STDMETHODIMP Updates::get_Option(AUOPTION * pVal)
  354. {
  355. HRESULT hr = m_AccessCheckClient();
  356. if ( FAILED(hr) )
  357. {
  358. return hr;
  359. }
  360. if (NULL == pVal)
  361. {
  362. return E_INVALIDARG;
  363. }
  364. if (NULL == gpState)
  365. {
  366. return E_FAIL;
  367. }
  368. *pVal = gpState->GetOption();
  369. return S_OK;
  370. }
  371. STDMETHODIMP Updates::put_Option(AUOPTION val)
  372. {
  373. HRESULT hr = m_AccessCheckClient();
  374. if ( FAILED(hr) )
  375. {
  376. return hr;
  377. }
  378. AUOPTION CurrOption = gpState->GetOption();
  379. if ( FAILED(hr = gpState->SetOption(val)) )
  380. {
  381. return hr;
  382. }
  383. // if asking to disable, post msg
  384. if ( (AUOPTION_AUTOUPDATE_DISABLE == val.dwOption) && (CurrOption.dwOption != val.dwOption) )
  385. {
  386. DEBUGMSG("AU service disabled");
  387. DisableAU();
  388. }
  389. // else if asking to enable, post msg
  390. else if ((AUOPTION_AUTOUPDATE_DISABLE == CurrOption.dwOption) && (val.dwOption != CurrOption.dwOption)
  391. || gpState->GetState() < AUSTATE_DETECT_PENDING)
  392. {
  393. ResetEngine();
  394. }
  395. if (CurrOption.dwOption != val.dwOption
  396. || (AUOPTION_SCHEDULED == val.dwOption
  397. && (CurrOption.dwSchedInstallDay != val.dwSchedInstallDay
  398. || CurrOption.dwSchedInstallTime != val.dwSchedInstallTime)))
  399. {
  400. SetEvent(ghSettingsChanged);
  401. }
  402. return S_OK;
  403. }
  404. STDMETHODIMP Updates::ConfigureAU()
  405. {
  406. HRESULT hr = m_AccessCheckClient();
  407. if ( FAILED(hr) )
  408. {
  409. return hr;
  410. }
  411. WaitForSingleObject(m_hEngineMutex, 10000);
  412. if ( AUSTATE_NOT_CONFIGURED == gpState->GetState() )
  413. {
  414. PostThreadMessage(gdwWorkerThreadId, AUMSG_EULA_ACCEPTED, 0, 0);
  415. }
  416. ReleaseMutex(m_hEngineMutex);
  417. return S_OK;
  418. }
  419. STDMETHODIMP Updates::get_EvtHandles(DWORD dwCltProcId, AUEVTHANDLES *pauevtHandles)
  420. {
  421. HRESULT hr = m_AccessCheckClient();
  422. if ( FAILED(hr) )
  423. {
  424. return hr;
  425. }
  426. WaitForSingleObject(ghMutex, INFINITE); // make sure proc id has been populated
  427. DWORD dwProcId = ghClientHandles.GetProcId();
  428. ReleaseMutex(ghMutex);
  429. if (dwProcId != dwCltProcId)
  430. {
  431. DEBUGMSG("WUAUENG Unauthorized client %d trying to get event handles for real client %d", dwCltProcId, dwProcId);
  432. return E_ACCESSDENIED;
  433. }
  434. if (NULL == pauevtHandles)
  435. {
  436. DEBUGMSG("WUAUENG GetEvtHandles invalid argument");
  437. return E_INVALIDARG;
  438. }
  439. WaitForSingleObject(m_hEngineMutex, INFINITE);
  440. hr = ::GetEvtHandles(pauevtHandles);
  441. ReleaseMutex(m_hEngineMutex);
  442. return hr;
  443. }
  444. STDMETHODIMP Updates::GetInstallXML(/*[out]*/ BSTR *pbstrCatalogXML, /*[out]*/ BSTR *pbstrDownloadXML)
  445. {
  446. DEBUGMSG("Updates::GetInstallXML");
  447. HRESULT hr = m_AccessCheckClient();
  448. if ( FAILED(hr) )
  449. {
  450. goto done;
  451. }
  452. if (NULL == pbstrCatalogXML || NULL == pbstrDownloadXML)
  453. {
  454. return E_INVALIDARG;
  455. }
  456. WaitForSingleObject(m_hEngineMutex, INFINITE);
  457. hr = ::GetInstallXML(pbstrCatalogXML, pbstrDownloadXML);
  458. ReleaseMutex(m_hEngineMutex);
  459. done:
  460. return hr;
  461. }
  462. STDMETHODIMP Updates::LogEvent(/*[in]*/ WORD wType, /*[in]*/ WORD wCategory, /*[in]*/ DWORD dwEventID, /*[in]*/ VARIANT vItems)
  463. {
  464. DEBUGMSG("Updates::LogEvent");
  465. HRESULT hr = m_AccessCheckClient();
  466. if ( FAILED(hr) )
  467. {
  468. return hr;
  469. }
  470. if ((VT_ARRAY | VT_BSTR) != vItems.vt ||
  471. NULL == vItems.parray)
  472. {
  473. DEBUGMSG("WUAUENG invalid variant list");
  474. return E_INVALIDARG;
  475. }
  476. WaitForSingleObject(m_hEngineMutex, INFINITE);
  477. CAUEventLog aueventlog(g_hInstance);
  478. hr = aueventlog.LogEvent(
  479. wType,
  480. wCategory,
  481. dwEventID,
  482. vItems.parray) ? S_OK : E_FAIL;
  483. ReleaseMutex(m_hEngineMutex);
  484. return hr;
  485. }