Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
15 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Compatibility.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // Module to handle compatibility problems in general.
  7. //
  8. // History: 2000-08-03 vtan created
  9. // --------------------------------------------------------------------------
  10. #include "StandardHeader.h"
  11. #include "Compatibility.h"
  12. #include <lpcfus.h>
  13. #include <trayp.h>
  14. #include "KernelResources.h"
  15. #include "RegistryResources.h"
  16. #include "SingleThreadedExecution.h"
  17. // --------------------------------------------------------------------------
  18. // CCompatibility::HasEnoughMemoryForNewSession
  19. //
  20. // Purpose: LPC port to server
  21. //
  22. // History: 2000-11-02 vtan created
  23. // --------------------------------------------------------------------------
  24. HANDLE CCompatibility::s_hPort = INVALID_HANDLE_VALUE;
  25. // --------------------------------------------------------------------------
  26. // CCompatibility::HasEnoughMemoryForNewSession
  27. //
  28. // Arguments: <none>
  29. //
  30. // Returns: bool
  31. //
  32. // Purpose: Currently unused. Was originally intended to be used to stop
  33. // disconnects if there isn't enough memory. Algorithm and/or
  34. // usage still to be decided.
  35. //
  36. // History: 2000-08-03 vtan created
  37. // --------------------------------------------------------------------------
  38. bool CCompatibility::HasEnoughMemoryForNewSession (void)
  39. {
  40. return(true);
  41. }
  42. // --------------------------------------------------------------------------
  43. // CCompatibility::DropSessionProcessesWorkSets
  44. //
  45. // Arguments: <none>
  46. //
  47. // Returns: <none>
  48. //
  49. // Purpose: Iterates all the processes in the session (of the calling
  50. // process) and drops their working sets. This is in preparation
  51. // for a disconnect when typically the session is idle.
  52. //
  53. // History: 2000-08-03 vtan created
  54. // --------------------------------------------------------------------------
  55. void CCompatibility::DropSessionProcessesWorkingSets (void)
  56. {
  57. (bool)EnumSessionProcesses(NtCurrentPeb()->SessionId, CB_DropSessionProcessesWorkingSetsProc, NULL);
  58. }
  59. // --------------------------------------------------------------------------
  60. // CCompatibility::TerminateNonCompliantApplications
  61. //
  62. // Arguments: <none>
  63. //
  64. // Returns: NTSTATUS
  65. //
  66. // Purpose: Requests disconnect capability from the Bad Application
  67. // Manager service. This will check the session to be
  68. // disconnected (this process -> the client) and walk its list
  69. // of processes registered as type 2 (terminate on disconnect).
  70. //
  71. // If any of those processes cannot be identified as being
  72. // terminated gracefully then the disconnect is failed.
  73. //
  74. // If the BAM is down then allow the call.
  75. //
  76. // History: 2000-09-08 vtan created
  77. // 2000-11-02 vtan rework to call BAM service
  78. // --------------------------------------------------------------------------
  79. NTSTATUS CCompatibility::TerminateNonCompliantApplications (void)
  80. {
  81. NTSTATUS status;
  82. if (s_hPort == INVALID_HANDLE_VALUE)
  83. {
  84. status = ConnectToServer();
  85. }
  86. else if (s_hPort != NULL)
  87. {
  88. status = STATUS_SUCCESS;
  89. }
  90. else
  91. {
  92. status = STATUS_OBJECT_NAME_NOT_FOUND;
  93. }
  94. if (NT_SUCCESS(status))
  95. {
  96. status = RequestSwitchUser();
  97. // If the port is disconnected because the service was stopped and
  98. // restarted then dump the current handle and re-establish a new
  99. // connection.
  100. if (status == STATUS_PORT_DISCONNECTED)
  101. {
  102. ReleaseHandle(s_hPort);
  103. s_hPort = INVALID_HANDLE_VALUE;
  104. }
  105. }
  106. else
  107. {
  108. status = STATUS_SUCCESS;
  109. }
  110. return(status);
  111. }
  112. // --------------------------------------------------------------------------
  113. // CCompatibility::MinimizeWindowsOnDisconnect
  114. //
  115. // Arguments: <none>
  116. //
  117. // Returns: <none>
  118. //
  119. // Purpose: Creates a thread to walk the windows on WinSta0\Default and
  120. // minimize them. This is required because
  121. // user32!SetThreadDesktop doesn't work on the main thread of
  122. // winlogon due to the SAS window.
  123. //
  124. // History: 2001-04-13 vtan created
  125. // --------------------------------------------------------------------------
  126. void CCompatibility::MinimizeWindowsOnDisconnect (void)
  127. {
  128. (BOOL)QueueUserWorkItem(CB_MinimizeWindowsWorkItem, NULL, WT_EXECUTEDEFAULT);
  129. }
  130. // --------------------------------------------------------------------------
  131. // CCompatibility::RestoreWindowsOnReconnect
  132. //
  133. // Arguments: <none>
  134. //
  135. // Returns: <none>
  136. //
  137. // Purpose: Walks the array of minimized windows for this session and
  138. // restores them. Deletes the array for the next time.
  139. //
  140. // History: 2001-04-13 vtan created
  141. // --------------------------------------------------------------------------
  142. void CCompatibility::RestoreWindowsOnReconnect (void)
  143. {
  144. (BOOL)QueueUserWorkItem(CB_RestoreWindowsWorkItem, NULL, WT_EXECUTEDEFAULT);
  145. }
  146. // --------------------------------------------------------------------------
  147. // CCompatibility::StaticInitialize
  148. //
  149. // Arguments: <none>
  150. //
  151. // Returns: NTSTATUS
  152. //
  153. // Purpose:
  154. //
  155. // History: 2001-06-22 vtan created
  156. // --------------------------------------------------------------------------
  157. NTSTATUS CCompatibility::StaticInitialize (void)
  158. {
  159. return(STATUS_SUCCESS);
  160. }
  161. // --------------------------------------------------------------------------
  162. // CCompatibility::StaticTerminate
  163. //
  164. // Arguments: <none>
  165. //
  166. // Returns: NTSTATUS
  167. //
  168. // Purpose: Release resources used by the module.
  169. //
  170. // History: 2001-06-22 vtan created
  171. // --------------------------------------------------------------------------
  172. NTSTATUS CCompatibility::StaticTerminate (void)
  173. {
  174. if ((s_hPort != INVALID_HANDLE_VALUE) && (s_hPort != NULL))
  175. {
  176. TBOOL(CloseHandle(s_hPort));
  177. s_hPort = INVALID_HANDLE_VALUE;
  178. }
  179. return(STATUS_SUCCESS);
  180. }
  181. // --------------------------------------------------------------------------
  182. // CCompatibility::ConnectToServer
  183. //
  184. // Arguments: <none>
  185. //
  186. // Returns: NTSTATUS
  187. //
  188. // Purpose: Connects to the Bad Application Manager server if no
  189. // connection has been established.
  190. //
  191. // History: 2000-11-02 vtan created
  192. // --------------------------------------------------------------------------
  193. NTSTATUS CCompatibility::ConnectToServer (void)
  194. {
  195. ULONG ulConnectionInfoLength;
  196. UNICODE_STRING portName;
  197. SECURITY_QUALITY_OF_SERVICE sqos;
  198. WCHAR szConnectionInfo[32];
  199. ASSERTMSG(s_hPort == INVALID_HANDLE_VALUE, "Attempt to call CCompatibility::ConnectToServer more than once");
  200. RtlInitUnicodeString(&portName, FUS_PORT_NAME);
  201. sqos.Length = sizeof(sqos);
  202. sqos.ImpersonationLevel = SecurityImpersonation;
  203. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  204. sqos.EffectiveOnly = TRUE;
  205. lstrcpyW(szConnectionInfo, FUS_CONNECTION_REQUEST);
  206. ulConnectionInfoLength = sizeof(szConnectionInfo);
  207. return(NtConnectPort(&s_hPort,
  208. &portName,
  209. &sqos,
  210. NULL,
  211. NULL,
  212. NULL,
  213. szConnectionInfo,
  214. &ulConnectionInfoLength));
  215. }
  216. // --------------------------------------------------------------------------
  217. // CCompatibility::RequestSwitchUser
  218. //
  219. // Arguments: <none>
  220. //
  221. // Returns: NTSTATUS
  222. //
  223. // Purpose: Request the BAM server to do BAM2.
  224. //
  225. // History: 2001-03-08 vtan created
  226. // --------------------------------------------------------------------------
  227. NTSTATUS CCompatibility::RequestSwitchUser (void)
  228. {
  229. NTSTATUS status;
  230. FUSAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  231. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  232. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  233. portMessageIn.apiBAM.apiGeneric.ulAPINumber = API_BAM_REQUESTSWITCHUSER;
  234. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_BAM);
  235. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(FUSAPI_PORT_MESSAGE));
  236. status = NtRequestWaitReplyPort(s_hPort, &portMessageIn.portMessage, &portMessageOut.portMessage);
  237. if (NT_SUCCESS(status))
  238. {
  239. status = portMessageOut.apiBAM.apiGeneric.status;
  240. if (NT_SUCCESS(status))
  241. {
  242. if (portMessageOut.apiBAM.apiSpecific.apiRequestSwitchUser.out.fAllowSwitch)
  243. {
  244. status = STATUS_SUCCESS;
  245. }
  246. else
  247. {
  248. status = STATUS_ACCESS_DENIED;
  249. }
  250. }
  251. }
  252. return(status);
  253. }
  254. // --------------------------------------------------------------------------
  255. // CCompatibility::CB_DropSessionProcessesWorkingSetsProc
  256. //
  257. // Arguments: dwProcessID = Process ID for this enumeration.
  258. // pV = User data pointer.
  259. //
  260. // Returns: bool
  261. //
  262. // Purpose: Attempts to open the given process ID to change the quotas.
  263. // This will drop the working set when set to -1.
  264. //
  265. // History: 2000-08-07 vtan created
  266. // --------------------------------------------------------------------------
  267. bool CCompatibility::CB_DropSessionProcessesWorkingSetsProc (DWORD dwProcessID, void *pV)
  268. {
  269. UNREFERENCED_PARAMETER(pV);
  270. HANDLE hProcess;
  271. ASSERTMSG(pV == NULL, "Unexpected pV passed to CCompatibility::CB_DropSessionProcessesWorkingSetsProc");
  272. hProcess = OpenProcess(PROCESS_SET_QUOTA, FALSE, dwProcessID);
  273. if (hProcess != NULL)
  274. {
  275. TBOOL(SetProcessWorkingSetSize(hProcess, static_cast<SIZE_T>(-1), static_cast<SIZE_T>(-1)));
  276. TBOOL(CloseHandle(hProcess));
  277. }
  278. return(true);
  279. }
  280. // --------------------------------------------------------------------------
  281. // CCompatibility::EnumSessionProcesses
  282. //
  283. // Arguments: dwSessionID = Session ID to enumerate processes of.
  284. // pfnCallback = Callback procedure address.
  285. // pV = User defined data to pass to callback.
  286. //
  287. // Returns: bool
  288. //
  289. // Purpose: Enumerates all processes on the system looking only for those
  290. // in the given session ID. Once a process ID is found it passes
  291. // that back to the callback. The callback may return false to
  292. // terminate the loop and return a false result to the caller of
  293. // this function.
  294. //
  295. // History: 2000-08-07 vtan created
  296. // --------------------------------------------------------------------------
  297. bool CCompatibility::EnumSessionProcesses (DWORD dwSessionID, PFNENUMSESSIONPROCESSESPROC pfnCallback, void *pV)
  298. {
  299. bool fResult;
  300. ULONG ulLengthToAllocate, ulLengthReturned;
  301. SYSTEM_PROCESS_INFORMATION spi, *pSPI;
  302. fResult = false;
  303. (NTSTATUS)NtQuerySystemInformation(SystemProcessInformation,
  304. &spi,
  305. sizeof(spi),
  306. &ulLengthToAllocate);
  307. pSPI = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(LocalAlloc(LMEM_FIXED, ulLengthToAllocate));
  308. if (pSPI != NULL)
  309. {
  310. SYSTEM_PROCESS_INFORMATION *pAllocatedSPI;
  311. pAllocatedSPI = pSPI;
  312. if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessInformation,
  313. pSPI,
  314. ulLengthToAllocate,
  315. &ulLengthReturned)))
  316. {
  317. fResult = true;
  318. while (fResult && (pSPI != NULL))
  319. {
  320. if (pSPI->SessionId == dwSessionID)
  321. {
  322. fResult = pfnCallback(HandleToUlong(pSPI->UniqueProcessId), pV);
  323. }
  324. if (pSPI->NextEntryOffset != 0)
  325. {
  326. pSPI = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(reinterpret_cast<unsigned char*>(pSPI) + pSPI->NextEntryOffset);
  327. }
  328. else
  329. {
  330. pSPI = NULL;
  331. }
  332. }
  333. }
  334. (HLOCAL)LocalFree(pAllocatedSPI);
  335. }
  336. return(fResult);
  337. }
  338. // --------------------------------------------------------------------------
  339. // CCompatibility::CB_MinimizeWindowsWorkItem
  340. //
  341. // Arguments: pV = User data.
  342. //
  343. // Returns: DWORD
  344. //
  345. // Purpose: Separate thread to handle switching to the default desktop and
  346. // enumerating the windows on it and minimizing them.
  347. //
  348. // History: 2001-04-13 vtan created
  349. // --------------------------------------------------------------------------
  350. DWORD WINAPI CCompatibility::CB_MinimizeWindowsWorkItem (void *pV)
  351. {
  352. UNREFERENCED_PARAMETER(pV);
  353. CDesktop desktop;
  354. if (NT_SUCCESS(desktop.Set(TEXT("Default"))))
  355. {
  356. HWND hwndTray;
  357. hwndTray = FindWindow(TEXT("Shell_TrayWnd"), NULL);
  358. if (hwndTray != NULL)
  359. {
  360. // can be a post since we don't care how long it takes for the windows
  361. // to be minimized
  362. PostMessage(hwndTray, WM_COMMAND, 415 /* IDM_MINIMIZEALL */, 0);
  363. }
  364. }
  365. return(0);
  366. }
  367. // --------------------------------------------------------------------------
  368. // CCompatibility::CB_RestoreWindowsWorkItem
  369. //
  370. // Arguments: pV = User data.
  371. //
  372. // Returns: DWORD
  373. //
  374. // Purpose: Separate thread to handle switching to the default desktop and
  375. // enumerating the windows on it and minimizing them.
  376. //
  377. // History: 2001-04-25 vtan created
  378. // --------------------------------------------------------------------------
  379. DWORD WINAPI CCompatibility::CB_RestoreWindowsWorkItem (void *pV)
  380. {
  381. UNREFERENCED_PARAMETER(pV);
  382. CDesktop desktop;
  383. if (NT_SUCCESS(desktop.Set(TEXT("Default"))))
  384. {
  385. HWND hwndTray;
  386. hwndTray = FindWindow(TEXT("Shell_TrayWnd"), NULL);
  387. if (hwndTray != NULL)
  388. {
  389. // use SendMessage to make this happen more quickly, otherwise the user
  390. // might wonder where all of their apps went
  391. SendMessage(hwndTray, WM_COMMAND, 416 /* IDM_UNDO */, 0);
  392. }
  393. }
  394. return(0);
  395. }