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.

466 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: updates.h
  8. // Definition of the Updates class
  9. //
  10. //--------------------------------------------------------------------------
  11. #pragma once
  12. #include "wuauengi.h"
  13. #include "wuaulib.h"
  14. #include <Wtsapi32.h>
  15. #include <wuaustate.h>
  16. #include <wuaueng.h>
  17. #include <accctrl.h>
  18. #include <aclapi.h>
  19. #include "pch.h"
  20. // functions IUpdates uses
  21. void HrUninit(void);
  22. HRESULT StartDownload(void);
  23. HRESULT PauseDownload(BOOL bPause);
  24. HRESULT GetUpdatesList(VARIANT *vList);
  25. HRESULT GetInstallXML(BSTR *pbstrCatalogXML, BSTR *pbstrDownloadXML);
  26. void saveSelection(VARIANT *selection);
  27. HRESULT GetDownloadStatus(UINT *pPercentage, DWORD *pdwnldStatus, BOOL fCareAboutConnection = TRUE);
  28. HRESULT GetInstallStatus(UINT *pNumFinished, DWORD *pStatus);
  29. HRESULT GetEvtHandles(AUEVTHANDLES *pAuEvtHandles);
  30. DWORD AvailableSessions(void);
  31. BOOL IsSessionAUEnabledAdmin(DWORD dwSessionId);
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Updates
  34. class Updates :
  35. public IUpdates
  36. {
  37. public:
  38. HANDLE m_hEngineMutex;
  39. Updates();
  40. ~Updates();
  41. BOOL m_fInitializeSecurity(void);
  42. HRESULT m_AccessCheckClient(void);
  43. HRESULT GetServiceHandles();
  44. DWORD ProcessState();
  45. BOOL CheckConnection();
  46. // IUnknown
  47. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
  48. STDMETHOD_(ULONG, AddRef)(void);
  49. STDMETHOD_(ULONG, Release)(void);
  50. // IClassFactory
  51. STDMETHOD(CreateInstance)(IUnknown*,REFIID,void**);
  52. STDMETHOD(LockServer)(BOOL);
  53. // IUpdates
  54. STDMETHOD(get_State)(/*[out, retval]*/ AUSTATE *pAuState);
  55. STDMETHOD(get_Option)(/*[out, retval]*/ AUOPTION * pAuOpt);
  56. STDMETHOD(put_Option)(/*[in]*/ AUOPTION auopt);
  57. STDMETHOD(GetUpdatesList)(/*[out]*/ VARIANT *pUpdates);
  58. STDMETHOD(SaveSelections)(/*[in]*/ VARIANT vUpdates);
  59. STDMETHOD(StartDownload)(void);
  60. STDMETHOD(GetDownloadStatus)(/*[out]*/ UINT *, /*[out]*/ DWORD *);
  61. STDMETHOD(SetDownloadPaused)(/*[in]*/ BOOL bPaused);
  62. STDMETHOD(ConfigureAU)();
  63. STDMETHOD(AvailableSessions(/*[out]*/ UINT *pcSess));
  64. STDMETHOD(get_EvtHandles(/*[in]*/DWORD dwCltProcId, /*[out]*/ AUEVTHANDLES *pauevtHandles));
  65. STDMETHOD(ClientMessage(/*[in]*/ UINT msg));
  66. //STDMETHOD(PingStatus(/*[in]*/ StatusEntry se));
  67. STDMETHOD(GetNotifyData(/*[out]*/ CLIENT_NOTIFY_DATA *pNotifyData));
  68. STDMETHOD(GetInstallXML(/*[out]*/ BSTR *pbstrCatalogXML, /*[out]*/ BSTR *pbstrDownloadXML));
  69. STDMETHOD(LogEvent(/*[in]*/ WORD wType, /*[in]*/ WORD wCategory, /*[in]*/ DWORD dwEventID, /*[in]*/ VARIANT vItems));
  70. private:
  71. SECURITY_DESCRIPTOR m_AdminSecurityDesc;
  72. static GENERIC_MAPPING m_AdminGenericMapping;
  73. PSID m_pAdminSid;
  74. PACL m_pAdminAcl;
  75. long m_refs;
  76. };
  77. class CLIENT_HANDLES
  78. {
  79. public:
  80. CLIENT_HANDLES(void){
  81. InitHandle();
  82. }
  83. ~CLIENT_HANDLES(void){
  84. Reset(TRUE);
  85. }
  86. BOOL fRebootWarningMode()
  87. {
  88. return m_fRebootWarningMode;
  89. }
  90. void StopClients(BOOL fRelaunch) {
  91. if (m_fRebootWarningMode)
  92. {
  93. DEBUGMSG("WUAUENG told %d CLIENT(S) to exit", m_dwRebootWarningClientNum);
  94. if (NULL != m_hClientExitEvt)
  95. {
  96. SetEvent(m_hClientExitEvt);
  97. }
  98. }
  99. else
  100. {
  101. if (fClient())
  102. {
  103. if (fRelaunch)
  104. {
  105. DEBUGMSG("WUAUENG told WUAUCLT to relaunch");
  106. NotifyClient(NOTIFY_RELAUNCH_CLIENT);
  107. }
  108. else
  109. {
  110. DEBUGMSG("WUAUENG told WUAUCLT to exit");
  111. NotifyClient(NOTIFY_STOP_CLIENT);
  112. }
  113. }
  114. else
  115. {
  116. DEBUGMSG("WARNING: StopClients() : no existing client");
  117. }
  118. }
  119. }
  120. void ClientAddTrayIcon(void) {
  121. if (m_fRebootWarningMode || m_fAsLocalSystem)
  122. {
  123. DEBUGMSG("WARNING: ClientAddTrayIcon() called in wrong mode");
  124. return;
  125. }
  126. if (fClient())
  127. {
  128. NotifyClient(NOTIFY_ADD_TRAYICON);
  129. }
  130. }
  131. void ClientRemoveTrayIcon(void) {
  132. if (m_fRebootWarningMode || m_fAsLocalSystem)
  133. {
  134. DEBUGMSG("WARNING: ClientRemoveTrayIcon() called in wrong mode");
  135. return;
  136. }
  137. if (fClient())
  138. {
  139. NotifyClient(NOTIFY_REMOVE_TRAYICON);
  140. }
  141. }
  142. void ClientStateChange(void) {
  143. if (m_fRebootWarningMode || m_fAsLocalSystem)
  144. {
  145. DEBUGMSG("WARNING: ClientStateChange() called in wrong mode");
  146. return;
  147. }
  148. NotifyClient(NOTIFY_STATE_CHANGE);
  149. }
  150. void ClientShowInstallWarning(void){
  151. if (m_fRebootWarningMode || m_fAsLocalSystem)
  152. {
  153. DEBUGMSG("WARNING: ClientShowInstallWarning() called in wrong mode");
  154. return;
  155. }
  156. if (fClient())
  157. {
  158. NotifyClient(NOTIFY_SHOW_INSTALLWARNING);
  159. }
  160. }
  161. void ResetClient(void) {
  162. if (m_fRebootWarningMode || m_fAsLocalSystem)
  163. {
  164. DEBUGMSG("WARNING: ResetClient() called in wrong mode");
  165. return;
  166. }
  167. if (fClient())
  168. {
  169. NotifyClient(NOTIFY_RESET);
  170. }
  171. }
  172. //checking existence of client(s)
  173. BOOL fClient(void) {
  174. if (m_fRebootWarningMode)
  175. {
  176. return m_dwRebootWarningClientNum > 0;
  177. }
  178. else
  179. {
  180. return (-1 != m_dwProcId) && (NULL != m_hClientProcess);
  181. }
  182. }
  183. void SetHandle(PROCESS_INFORMATION & ProcessInfo, BOOL fAsLocalSystem)
  184. {
  185. m_fRebootWarningMode = FALSE;
  186. m_fAsLocalSystem = fAsLocalSystem;
  187. m_dwProcId = ProcessInfo.dwProcessId;
  188. m_hClientProcess = ProcessInfo.hProcess;
  189. SafeCloseHandle(ProcessInfo.hThread);
  190. }
  191. BOOL AddHandle(PROCESS_INFORMATION & ProcessInfo)
  192. {
  193. HANDLE *pTmp;
  194. m_fRebootWarningMode = TRUE;
  195. SafeCloseHandle(ProcessInfo.hThread);
  196. pTmp = (HANDLE*) realloc(m_phRebootWarningClients, (m_dwRebootWarningClientNum+1)*sizeof(HANDLE));
  197. if (NULL == pTmp)
  198. {
  199. return FALSE;
  200. }
  201. m_phRebootWarningClients = pTmp;
  202. m_phRebootWarningClients[m_dwRebootWarningClientNum] = ProcessInfo.hProcess;
  203. m_dwRebootWarningClientNum ++;
  204. return TRUE;
  205. }
  206. void RemoveHandle(HANDLE hProcess)
  207. {
  208. if (m_fRebootWarningMode)
  209. {
  210. for (DWORD i = 0; i < m_dwRebootWarningClientNum; i++)
  211. {
  212. if (hProcess == m_phRebootWarningClients[i])
  213. {
  214. CloseHandle(hProcess);
  215. m_phRebootWarningClients[i] = m_phRebootWarningClients[m_dwRebootWarningClientNum -1];
  216. m_dwRebootWarningClientNum --;
  217. DEBUGMSG("RemoveHandle in Reboot warning mode");
  218. }
  219. }
  220. if (0 == m_dwRebootWarningClientNum)
  221. {//all clients are gone
  222. Reset();
  223. }
  224. }
  225. else
  226. {
  227. DEBUGMSG("RemoveHandle in regular mode");
  228. if (hProcess == m_hClientProcess)
  229. { //all clients are gone
  230. Reset();
  231. }
  232. }
  233. }
  234. void InitHandle(void)
  235. {
  236. DEBUGMSG("WUAUENG client handles initialized");
  237. m_hClientProcess = NULL;
  238. m_dwProcId = -1;
  239. m_dwRebootWarningClientNum = 0;
  240. m_phRebootWarningClients = NULL;
  241. m_fRebootWarningMode = FALSE;
  242. m_fAsLocalSystem = FALSE;
  243. m_hClientExitEvt = NULL;
  244. }
  245. DWORD GetProcId(void)
  246. {
  247. if (m_fRebootWarningMode)
  248. {
  249. DEBUGMSG("WARNING: GetProcId() called in wrong mode");
  250. return -1;
  251. }
  252. return m_dwProcId;
  253. }
  254. CONST HANDLE hClientProcess(void)
  255. {
  256. if (m_fRebootWarningMode)
  257. {
  258. DEBUGMSG("WARNING: hClientProcess() called in wrong mode");
  259. return NULL;
  260. }
  261. return m_hClientProcess;
  262. }
  263. void WaitForClientExits()
  264. {
  265. HANDLE *pTmp;
  266. if (!m_fRebootWarningMode)
  267. {
  268. if (NULL != m_hClientProcess)
  269. {
  270. WaitForSingleObject(m_hClientProcess, INFINITE);
  271. }
  272. }
  273. else
  274. {
  275. if (m_dwRebootWarningClientNum > 0)
  276. {
  277. WaitForMultipleObjects(m_dwRebootWarningClientNum, m_phRebootWarningClients, TRUE, INFINITE);
  278. }
  279. }
  280. Reset();
  281. return;
  282. }
  283. //////////////////////////////////////////////////////////////////
  284. // szName should have size of at least MAX_PATH characters
  285. //////////////////////////////////////////////////////////////////
  286. BOOL CreateClientExitEvt(LPTSTR OUT szName, DWORD dwCchSize)
  287. {
  288. const TCHAR szClientName[] = _T("Global\\Microsoft.WindowsUpdate.AU.ClientExitEvt.");
  289. TCHAR szBuf[50];
  290. GUID guid;
  291. HRESULT hr;
  292. AUASSERT(NULL == m_hClientExitEvt);
  293. if (FAILED(hr = CoCreateGuid(&guid)))
  294. {
  295. DEBUGMSG("Fail to Create guid with error %#lx", hr);
  296. return FALSE;
  297. }
  298. StringFromGUID2(guid, szBuf, ARRAYSIZE(szBuf)); // szBuf should be big enough, function always succeed
  299. if (FAILED(hr = StringCchCopyEx(szName, dwCchSize, szClientName, NULL, NULL, MISTSAFE_STRING_FLAGS)) ||
  300. FAILED(hr = StringCchCatEx(szName, dwCchSize, szBuf, NULL, NULL, MISTSAFE_STRING_FLAGS))) //szName is now 86 characters long
  301. {
  302. DEBUGMSG("Fail to construct client exit event name with error %#lx", hr);
  303. return FALSE;
  304. }
  305. if (NULL == (m_hClientExitEvt = CreateEvent(NULL, TRUE, FALSE, szName)))
  306. {
  307. DEBUGMSG("Fail to create client exit event with error %d", GetLastError());
  308. return FALSE;
  309. }
  310. if (!AllowEveryOne(m_hClientExitEvt))
  311. {
  312. DEBUGMSG("Fail to grant access on client exit event to everyone");
  313. SafeCloseHandleNULL(m_hClientExitEvt);
  314. return FALSE;
  315. }
  316. DEBUGMSG("access granted to everyone on client exit event");
  317. return TRUE;
  318. }
  319. private:
  320. void NotifyClient(CLIENT_NOTIFY_CODE notClientCode)
  321. {
  322. //notify client even before or after it is created
  323. #ifdef DBG
  324. LPCSTR aClientCodeMsg[] = {"stop client", "add trayicon", "remove trayicon", "state change", "show install warning", "reset client", "relaunch client"};
  325. DEBUGMSG("Notify Client for %s", aClientCodeMsg[notClientCode-1]);
  326. #endif
  327. gClientNotifyData.actionCode = notClientCode;
  328. SetEvent(ghNotifyClient);
  329. return;
  330. }
  331. ////////////////////////////////////////////////////////////////////
  332. // grant SYNCHRONIZE access on hObject to everyone
  333. ////////////////////////////////////////////////////////////////////
  334. BOOL AllowEveryOne (HANDLE hObject) // handle to the event
  335. {
  336. LPTSTR pszTrustee; // trustee for new ACE
  337. TRUSTEE_FORM TrusteeForm; // format of trustee structure
  338. DWORD dwRes;
  339. PACL pOldDACL = NULL, pNewDACL = NULL;
  340. PSECURITY_DESCRIPTOR pSD = NULL;
  341. EXPLICIT_ACCESS ea;
  342. PSID pWorldSid = NULL;
  343. BOOL fRet;
  344. // World SID
  345. SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
  346. if (! (fRet =AllocateAndInitializeSid(&WorldAuth,1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0,&pWorldSid)))
  347. {
  348. DEBUGMSG("WUAUENG: AllowEveryOne() failed with error %d", GetLastError());
  349. goto Cleanup;
  350. }
  351. // Get a pointer to the existing DACL.
  352. dwRes = GetSecurityInfo(hObject, SE_KERNEL_OBJECT,
  353. DACL_SECURITY_INFORMATION,
  354. NULL, NULL, &pOldDACL, NULL, &pSD);
  355. if (!(fRet = (ERROR_SUCCESS == dwRes))) {
  356. DEBUGMSG( "GetSecurityInfo Error %u", dwRes );
  357. goto Cleanup;
  358. }
  359. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  360. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  361. ea.grfAccessPermissions = SYNCHRONIZE;
  362. ea.grfAccessMode = SET_ACCESS;
  363. ea.grfInheritance= NO_INHERITANCE;
  364. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  365. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  366. ea.Trustee.ptstrName = (LPTSTR)pWorldSid;
  367. // Create a new ACL that merges the new ACE
  368. // into the existing DACL.
  369. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
  370. if (!(fRet = (ERROR_SUCCESS == dwRes))) {
  371. DEBUGMSG( "SetEntriesInAcl Error %u", dwRes );
  372. goto Cleanup;
  373. }
  374. // Attach the new ACL as the object's DACL.
  375. dwRes = SetSecurityInfo(hObject, SE_KERNEL_OBJECT,
  376. DACL_SECURITY_INFORMATION,
  377. NULL, NULL, pNewDACL, NULL);
  378. if (!(fRet = (ERROR_SUCCESS == dwRes))) {
  379. DEBUGMSG( "SetSecurityInfo Error %u", dwRes );
  380. goto Cleanup;
  381. }
  382. Cleanup:
  383. if(pSD != NULL)
  384. LocalFree((HLOCAL) pSD);
  385. if(pNewDACL != NULL)
  386. LocalFree((HLOCAL) pNewDACL);
  387. if (NULL != pWorldSid)
  388. {
  389. FreeSid(pWorldSid);
  390. }
  391. return fRet;
  392. }
  393. void Reset( BOOL fDestructor = FALSE)
  394. {
  395. SafeCloseHandleNULL(m_hClientProcess);
  396. SafeCloseHandleNULL(m_hClientExitEvt);
  397. m_dwProcId = -1;
  398. if (!fDestructor)
  399. {
  400. ResetEvent(ghNotifyClient);
  401. }
  402. if (m_dwRebootWarningClientNum > 0)
  403. {
  404. DEBUGMSG("WUAUENG CLIENT_HANDLES::Reset() close %d handles", m_dwRebootWarningClientNum);
  405. for (DWORD i = 0; i < m_dwRebootWarningClientNum; i++)
  406. {
  407. CloseHandle(m_phRebootWarningClients[i]);
  408. }
  409. }
  410. SafeFreeNULL(m_phRebootWarningClients); //still need to free even m_dwRebootWarningClientNum is 0
  411. m_dwRebootWarningClientNum = 0;
  412. m_phRebootWarningClients = NULL;
  413. m_fRebootWarningMode = FALSE;
  414. m_fAsLocalSystem = FALSE;
  415. }
  416. private:
  417. HANDLE m_hClientProcess; //Handle to the client process
  418. DWORD m_dwProcId;
  419. HANDLE *m_phRebootWarningClients;
  420. DWORD m_dwRebootWarningClientNum; //number of valid handles in m_phRebootWarningClients
  421. BOOL m_fRebootWarningMode;
  422. BOOL m_fAsLocalSystem;
  423. HANDLE m_hClientExitEvt;
  424. };
  425. extern CLIENT_HANDLES ghClientHandles;