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.

431 lines
13 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: ThemeManagerSessionData.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // This file contains a class that implements information the encapsulates a
  7. // client TS session for the theme server.
  8. //
  9. // History: 2000-10-10 vtan created
  10. // 2000-11-29 vtan moved to separate file
  11. // --------------------------------------------------------------------------
  12. #include "StandardHeader.h"
  13. #include "ThemeManagerSessionData.h"
  14. #include <uxthemep.h>
  15. #include <UxThemeServer.h>
  16. #include "SingleThreadedExecution.h"
  17. #include "StatusCode.h"
  18. #include "ThemeManagerAPIRequest.h"
  19. #include "TokenInformation.h"
  20. // --------------------------------------------------------------------------
  21. // CThemeManagerSessionData::s_pAPIConnection
  22. //
  23. // Purpose: Static member variables.
  24. //
  25. // History: 2000-12-02 vtan created
  26. // --------------------------------------------------------------------------
  27. CAPIConnection* CThemeManagerSessionData::s_pAPIConnection = NULL;
  28. // --------------------------------------------------------------------------
  29. // CThemeManagerSessionData::CThemeManagerSessionData
  30. //
  31. // Arguments: pAPIConnection = CAPIConnection for port access control.
  32. // dwSessionID = Session ID.
  33. //
  34. // Returns: <none>
  35. //
  36. // Purpose: Constructor for CThemeManagerSessionData.
  37. //
  38. // History: 2000-11-17 vtan created
  39. // --------------------------------------------------------------------------
  40. CThemeManagerSessionData::CThemeManagerSessionData (DWORD dwSessionID) :
  41. _dwSessionID(dwSessionID),
  42. _pvThemeLoaderData(NULL),
  43. _hToken(NULL),
  44. _hProcessClient(NULL),
  45. _hWait(NULL)
  46. {
  47. }
  48. // --------------------------------------------------------------------------
  49. // CThemeManagerSessionData::~CThemeManagerSessionData
  50. //
  51. // Arguments: <none>
  52. //
  53. // Returns: <none>
  54. //
  55. // Purpose: Destructor for CThemeManagerSessionData.
  56. //
  57. // History: 2000-11-17 vtan created
  58. // --------------------------------------------------------------------------
  59. CThemeManagerSessionData::~CThemeManagerSessionData (void)
  60. {
  61. ASSERTMSG(_hWait == NULL, "Wait not executed or removed in CThemeManagerSessionData::~CThemeManagerSessionData");
  62. ASSERTMSG(_hProcessClient == NULL, "_hProcessClient not closed in CThemeManagerSessionData::~CThemeManagerSessionData");
  63. TSTATUS(UserLogoff());
  64. if (_pvThemeLoaderData != NULL)
  65. {
  66. SessionFree(_pvThemeLoaderData);
  67. _pvThemeLoaderData = NULL;
  68. }
  69. }
  70. // --------------------------------------------------------------------------
  71. // CThemeManagerSessionData::GetData
  72. //
  73. // Arguments: <none>
  74. //
  75. // Returns: void*
  76. //
  77. // Purpose: Returns the internal data blob allocated by SessionCreate.
  78. //
  79. // History: 2000-11-17 vtan created
  80. // --------------------------------------------------------------------------
  81. void* CThemeManagerSessionData::GetData (void) const
  82. {
  83. return(_pvThemeLoaderData);
  84. }
  85. // --------------------------------------------------------------------------
  86. // CThemeManagerSessionData::EqualSessionID
  87. //
  88. // Arguments: dwSessionID
  89. //
  90. // Returns: bool
  91. //
  92. // Purpose: Returns whether the given session ID matches this session
  93. // data.
  94. //
  95. // History: 2000-11-30 vtan created
  96. // --------------------------------------------------------------------------
  97. bool CThemeManagerSessionData::EqualSessionID (DWORD dwSessionID) const
  98. {
  99. return(dwSessionID == _dwSessionID);
  100. }
  101. // --------------------------------------------------------------------------
  102. // CThemeManagerSessionData::Allocate
  103. //
  104. // Arguments: hProcessClient = Handle to the client process.
  105. //
  106. // Returns: NTSTATUS
  107. //
  108. // Purpose: Allocates a data blob via SessionCreate which also keeps a
  109. // handle to the client process that initiated the session. This
  110. // is always winlogon in the client session ID.
  111. //
  112. // History: 2000-11-17 vtan created
  113. // --------------------------------------------------------------------------
  114. NTSTATUS CThemeManagerSessionData::Allocate (HANDLE hProcessClient, DWORD dwServerChangeNumber, void *pfnRegister, void *pfnUnregister, void *pfnClearStockObjects, DWORD dwStackSizeReserve, DWORD dwStackSizeCommit)
  115. {
  116. NTSTATUS status;
  117. if (DuplicateHandle(GetCurrentProcess(),
  118. hProcessClient,
  119. GetCurrentProcess(),
  120. &_hProcessClient,
  121. SYNCHRONIZE,
  122. FALSE,
  123. 0) != FALSE)
  124. {
  125. ASSERTMSG(_hWait == NULL, "_hWait already exists in CThemeManagerSessionData::Allocate");
  126. AddRef();
  127. if (RegisterWaitForSingleObject(&_hWait,
  128. _hProcessClient,
  129. CB_SessionTermination,
  130. this,
  131. INFINITE,
  132. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE) != FALSE)
  133. {
  134. _pvThemeLoaderData = SessionAllocate(hProcessClient, dwServerChangeNumber, pfnRegister, pfnUnregister, pfnClearStockObjects, dwStackSizeReserve, dwStackSizeCommit);
  135. if (_pvThemeLoaderData != NULL)
  136. {
  137. status = STATUS_SUCCESS;
  138. }
  139. else
  140. {
  141. status = STATUS_NO_MEMORY;
  142. }
  143. }
  144. else
  145. {
  146. status = CStatusCode::StatusCodeOfLastError();
  147. }
  148. if (!NT_SUCCESS(status))
  149. {
  150. HANDLE hWait;
  151. // In the case of failure grab the _hWait and try to unregister it.
  152. // If the unregister fails then the callback is already executing
  153. // and there's little we can to stop it. This means that the winlogon
  154. // for the client session died between the time we entered this function
  155. // and registered the wait and now. If the unregister worked then then
  156. // callback hasn't executed so just release the resources.
  157. hWait = InterlockedExchangePointer(&_hWait, NULL);
  158. if (hWait != NULL)
  159. {
  160. if (UnregisterWait(hWait) != FALSE)
  161. {
  162. Release();
  163. }
  164. ReleaseHandle(_hProcessClient);
  165. if (_pvThemeLoaderData != NULL)
  166. {
  167. SessionFree(_pvThemeLoaderData);
  168. _pvThemeLoaderData = NULL;
  169. }
  170. }
  171. }
  172. }
  173. else
  174. {
  175. status = CStatusCode::StatusCodeOfLastError();
  176. }
  177. return(status);
  178. }
  179. // --------------------------------------------------------------------------
  180. // CThemeManagerSessionData::Cleanup
  181. //
  182. // Arguments: <none>
  183. //
  184. // Returns: NTSTATUS
  185. //
  186. // Purpose: Used to unregister the wait on the client process. This is
  187. // necessary to prevent the callback from occurring after the
  188. // service has been shut down which will cause access to a static
  189. // member variable that is NULL'd out.
  190. //
  191. // History: 2001-01-05 vtan created
  192. // --------------------------------------------------------------------------
  193. NTSTATUS CThemeManagerSessionData::Cleanup (void)
  194. {
  195. HANDLE hWait;
  196. hWait = InterlockedExchangePointer(&_hWait, NULL);
  197. if (hWait != NULL)
  198. {
  199. if (UnregisterWait(hWait) != FALSE)
  200. {
  201. Release();
  202. }
  203. ReleaseHandle(_hProcessClient);
  204. }
  205. return(STATUS_SUCCESS);
  206. }
  207. // --------------------------------------------------------------------------
  208. // CThemeManagerSessionData::UserLogon
  209. //
  210. // Arguments: hToken = Handle to the token of the user logging on.
  211. //
  212. // Returns: NTSTATUS
  213. //
  214. // Purpose: Saves a copy of the token for use at log off. Allows access
  215. // to the theme port to the logon SID of the token.
  216. //
  217. // History: 2000-11-17 vtan created
  218. // --------------------------------------------------------------------------
  219. NTSTATUS CThemeManagerSessionData::UserLogon (HANDLE hToken)
  220. {
  221. NTSTATUS status;
  222. if (_hToken == NULL)
  223. {
  224. if (DuplicateHandle(GetCurrentProcess(),
  225. hToken,
  226. GetCurrentProcess(),
  227. &_hToken,
  228. 0,
  229. FALSE,
  230. DUPLICATE_SAME_ACCESS) != FALSE)
  231. {
  232. PSID pSIDLogon;
  233. CTokenInformation token(hToken);
  234. pSIDLogon = token.GetLogonSID();
  235. if (pSIDLogon != NULL)
  236. {
  237. if (s_pAPIConnection != NULL)
  238. {
  239. status = s_pAPIConnection->AddAccess(pSIDLogon, PORT_CONNECT);
  240. }
  241. else
  242. {
  243. status = STATUS_SUCCESS;
  244. }
  245. }
  246. else
  247. {
  248. status = STATUS_INVALID_PARAMETER;
  249. }
  250. }
  251. else
  252. {
  253. status = CStatusCode::StatusCodeOfLastError();
  254. }
  255. }
  256. else
  257. {
  258. status = STATUS_SUCCESS;
  259. }
  260. return(status);
  261. }
  262. // --------------------------------------------------------------------------
  263. // CThemeManagerSessionData::UserLogoff
  264. //
  265. // Arguments: <none>
  266. //
  267. // Returns: NTSTATUS
  268. //
  269. // Purpose: Remove access to the theme port for the user being logged off.
  270. //
  271. // History: 2000-11-17 vtan created
  272. // --------------------------------------------------------------------------
  273. NTSTATUS CThemeManagerSessionData::UserLogoff (void)
  274. {
  275. NTSTATUS status;
  276. if (_hToken != NULL)
  277. {
  278. PSID pSIDLogon;
  279. CTokenInformation token(_hToken);
  280. pSIDLogon = token.GetLogonSID();
  281. if (pSIDLogon != NULL)
  282. {
  283. if (s_pAPIConnection != NULL)
  284. {
  285. status = s_pAPIConnection->RemoveAccess(pSIDLogon);
  286. }
  287. else
  288. {
  289. status = STATUS_SUCCESS;
  290. }
  291. }
  292. else
  293. {
  294. status = STATUS_INVALID_PARAMETER;
  295. }
  296. ReleaseHandle(_hToken);
  297. }
  298. else
  299. {
  300. status = STATUS_SUCCESS;
  301. }
  302. return(status);
  303. }
  304. // --------------------------------------------------------------------------
  305. // CThemeManagerSessionData::SetAPIConnection
  306. //
  307. // Arguments: <none>
  308. //
  309. // Returns: <none>
  310. //
  311. // Purpose: Sets the static CAPIConnection for port access changes.
  312. //
  313. // History: 2000-12-02 vtan created
  314. // --------------------------------------------------------------------------
  315. void CThemeManagerSessionData::SetAPIConnection (CAPIConnection *pAPIConnection)
  316. {
  317. pAPIConnection->AddRef();
  318. s_pAPIConnection = pAPIConnection;
  319. }
  320. // --------------------------------------------------------------------------
  321. // CThemeManagerSessionData::ReleaseAPIConnection
  322. //
  323. // Arguments: <none>
  324. //
  325. // Returns: <none>
  326. //
  327. // Purpose: Releases the static CAPIConnection for port access changes.
  328. //
  329. // History: 2000-12-02 vtan created
  330. // --------------------------------------------------------------------------
  331. void CThemeManagerSessionData::ReleaseAPIConnection (void)
  332. {
  333. s_pAPIConnection->Release();
  334. s_pAPIConnection = NULL;
  335. }
  336. // --------------------------------------------------------------------------
  337. // CThemeManagerSessionData::SessionTermination
  338. //
  339. // Arguments: <none>
  340. //
  341. // Returns: <none>
  342. //
  343. // Purpose: Callback on winlogon process termination for a given session.
  344. // We clean up the session specific data blob when this happens.
  345. // This allows the process handles on winlogon to be released.
  346. // If this isn't done then a zombie lives and the session is
  347. // never reclaimed.
  348. //
  349. // History: 2000-12-09 vtan created
  350. // --------------------------------------------------------------------------
  351. void CThemeManagerSessionData::SessionTermination (void)
  352. {
  353. HANDLE hWait;
  354. hWait = InterlockedExchangePointer(&_hWait, NULL);
  355. if (hWait != NULL)
  356. {
  357. (BOOL)UnregisterWait(hWait);
  358. ReleaseHandle(_hProcessClient);
  359. }
  360. CThemeManagerAPIRequest::SessionDestroy(_dwSessionID);
  361. Release();
  362. }
  363. // --------------------------------------------------------------------------
  364. // CThemeManagerSessionData::CB_SessionTermination
  365. //
  366. // Arguments: pParameter = This object.
  367. // TimerOrWaitFired = Not used.
  368. //
  369. // Returns: <none>
  370. //
  371. // Purpose: Callback stub to member function.
  372. //
  373. // History: 2000-12-09 vtan created
  374. // --------------------------------------------------------------------------
  375. void CALLBACK CThemeManagerSessionData::CB_SessionTermination (void *pParameter, BOOLEAN TimerOrWaitFired)
  376. {
  377. UNREFERENCED_PARAMETER(TimerOrWaitFired);
  378. static_cast<CThemeManagerSessionData*>(pParameter)->SessionTermination();
  379. }