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.

528 lines
18 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: BadApplicationAPIRequest.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // This file contains a class to implement bad application manager API
  7. // requests.
  8. //
  9. // History: 2000-08-25 vtan created
  10. // 2000-12-04 vtan moved to separate file
  11. // --------------------------------------------------------------------------
  12. #ifdef _X86_
  13. #include "StandardHeader.h"
  14. #include "BadApplicationAPIRequest.h"
  15. #include "StatusCode.h"
  16. #include "TokenInformation.h"
  17. // --------------------------------------------------------------------------
  18. // CBadApplicationAPIRequest::s_pBadApplicationManager
  19. //
  20. // Purpose: Single instance of the CBadApplicationManager object.
  21. //
  22. // History: 2000-08-26 vtan created
  23. // --------------------------------------------------------------------------
  24. CBadApplicationManager* CBadApplicationAPIRequest::s_pBadApplicationManager = NULL;
  25. // --------------------------------------------------------------------------
  26. // CBadApplicationAPIRequest::CBadApplicationAPIRequest
  27. //
  28. // Arguments: pAPIDispatcher = CAPIDispatcher that calls this object.
  29. //
  30. // Returns: <none>
  31. //
  32. // Purpose: Constructor for the CBadApplicationAPIRequest class. It just passes the
  33. // control to the super class.
  34. //
  35. // History: 2000-08-25 vtan created
  36. // --------------------------------------------------------------------------
  37. CBadApplicationAPIRequest::CBadApplicationAPIRequest (CAPIDispatcher* pAPIDispatcher) :
  38. CAPIRequest(pAPIDispatcher)
  39. {
  40. }
  41. // --------------------------------------------------------------------------
  42. // CBadApplicationAPIRequest::CBadApplicationAPIRequest
  43. //
  44. // Arguments: pAPIDispatcher = CAPIDispatcher that calls this object.
  45. // portMessage = CPortMessage to copy construct.
  46. //
  47. // Returns: <none>
  48. //
  49. // Purpose: Constructor for the CBadApplicationAPIRequest class. It just passes the
  50. // control to the super class.
  51. //
  52. // History: 2000-08-25 vtan created
  53. // --------------------------------------------------------------------------
  54. CBadApplicationAPIRequest::CBadApplicationAPIRequest (CAPIDispatcher* pAPIDispatcher, const CPortMessage& portMessage) :
  55. CAPIRequest(pAPIDispatcher, portMessage)
  56. {
  57. }
  58. // --------------------------------------------------------------------------
  59. // CBadApplicationAPIRequest::~CBadApplicationAPIRequest
  60. //
  61. // Arguments: <none>
  62. //
  63. // Returns: <none>
  64. //
  65. // Purpose: Destructor for the CBadApplicationAPIRequest class.
  66. //
  67. // History: 2000-08-25 vtan created
  68. // --------------------------------------------------------------------------
  69. CBadApplicationAPIRequest::~CBadApplicationAPIRequest (void)
  70. {
  71. }
  72. // --------------------------------------------------------------------------
  73. // CBadApplicationAPIRequest::Execute
  74. //
  75. // Arguments: <none>
  76. //
  77. // Returns: NTSTATUS
  78. //
  79. // Purpose: Execute implementation for bad application API requests. This
  80. // function dispatches requests based on the API request number.
  81. //
  82. // History: 2000-08-25 vtan created
  83. // --------------------------------------------------------------------------
  84. NTSTATUS CBadApplicationAPIRequest::Execute (void)
  85. {
  86. NTSTATUS status;
  87. switch (reinterpret_cast<API_BAM*>(&_data)->apiGeneric.ulAPINumber)
  88. {
  89. case API_BAM_QUERYRUNNING:
  90. status = Execute_QueryRunning();
  91. break;
  92. case API_BAM_REGISTERRUNNING:
  93. status = Execute_RegisterRunning();
  94. break;
  95. case API_BAM_QUERYUSERPERMISSION:
  96. status = Execute_QueryUserPermission();
  97. break;
  98. case API_BAM_TERMINATERUNNING:
  99. status = Execute_TerminateRunning();
  100. break;
  101. case API_BAM_REQUESTSWITCHUSER:
  102. status = Execute_RequestSwitchUser();
  103. break;
  104. default:
  105. DISPLAYMSG("Unknown API request in CBadApplicationAPIRequest::Execute");
  106. status = STATUS_NOT_IMPLEMENTED;
  107. break;
  108. }
  109. TSTATUS(status);
  110. return(status);
  111. }
  112. // --------------------------------------------------------------------------
  113. // CBadApplicationAPIRequest::StaticInitialize
  114. //
  115. // Arguments: <none>
  116. //
  117. // Returns: NTSTATUS
  118. //
  119. // Purpose: Static initializer for the class. It creates the static
  120. // instance of the CBadApplicationManager which must be a single
  121. // instance and knows about bad running applications.
  122. //
  123. // History: 2000-08-26 vtan created
  124. // --------------------------------------------------------------------------
  125. NTSTATUS CBadApplicationAPIRequest::StaticInitialize (HINSTANCE hInstance)
  126. {
  127. NTSTATUS status;
  128. if (s_pBadApplicationManager == NULL)
  129. {
  130. s_pBadApplicationManager = new CBadApplicationManager(hInstance);
  131. if (s_pBadApplicationManager != NULL)
  132. {
  133. status = STATUS_SUCCESS;
  134. }
  135. else
  136. {
  137. status = STATUS_NO_MEMORY;
  138. }
  139. }
  140. else
  141. {
  142. status = STATUS_SUCCESS;
  143. }
  144. return(status);
  145. }
  146. // --------------------------------------------------------------------------
  147. // CBadApplicationAPIRequest::StaticTerminate
  148. //
  149. // Arguments: <none>
  150. //
  151. // Returns: NTSTATUS
  152. //
  153. // Purpose: Static destructor for the class. This terminates the bad
  154. // application manager, releases the reference on the object and
  155. // clears out the static variable. When the thread dies it will
  156. // clean itself up.
  157. //
  158. // History: 2000-08-26 vtan created
  159. // --------------------------------------------------------------------------
  160. NTSTATUS CBadApplicationAPIRequest::StaticTerminate (void)
  161. {
  162. if (s_pBadApplicationManager != NULL)
  163. {
  164. s_pBadApplicationManager->Terminate();
  165. s_pBadApplicationManager->Release();
  166. s_pBadApplicationManager = NULL;
  167. }
  168. return(STATUS_SUCCESS);
  169. }
  170. // --------------------------------------------------------------------------
  171. // CBadApplicationAPIRequest::Execute_QueryRunning
  172. //
  173. // Arguments: <none>
  174. //
  175. // Returns: NTSTATUS
  176. //
  177. // Purpose: Handles API_BAM_QUERYRUNNING. Returns whether or not the
  178. // requested image path is currently a known (tracked)
  179. // executable that is running. Let the bad application manager
  180. // do the work. Exclude checking in the same session.
  181. //
  182. // History: 2000-08-26 vtan created
  183. // --------------------------------------------------------------------------
  184. NTSTATUS CBadApplicationAPIRequest::Execute_QueryRunning (void)
  185. {
  186. NTSTATUS status;
  187. HANDLE hProcessClient;
  188. API_BAM_QUERYRUNNING_IN *pAPIIn;
  189. API_BAM_QUERYRUNNING_OUT *pAPIOut;
  190. WCHAR *pszImageName;
  191. hProcessClient = _pAPIDispatcher->GetClientProcess();
  192. pAPIIn = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiQueryRunning.in;
  193. pAPIOut = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiQueryRunning.out;
  194. status = _AllocAndMapClientString(hProcessClient, pAPIIn->pszImageName, pAPIIn->cchImageName,
  195. MAX_PATH, &pszImageName);
  196. if(NT_SUCCESS(status))
  197. {
  198. CBadApplication badApplication(pszImageName);
  199. pAPIOut->fResult = s_pBadApplicationManager->QueryRunning(badApplication, _pAPIDispatcher->GetClientSessionID());
  200. status = STATUS_SUCCESS;
  201. _FreeMappedClientString(pszImageName);
  202. }
  203. SetDataLength(sizeof(API_BAM));
  204. return(status);
  205. }
  206. // --------------------------------------------------------------------------
  207. // CBadApplicationAPIRequest::Execute_RegisterRunning
  208. //
  209. // Arguments: <none>
  210. //
  211. // Returns: NTSTATUS
  212. //
  213. // Purpose: Handles API_BAM_REGISTERRUNNING. Adds the given image
  214. // executable to the list of currently running bad applications
  215. // so that further instances can be excluded.
  216. //
  217. // History: 2000-08-26 vtan created
  218. // --------------------------------------------------------------------------
  219. NTSTATUS CBadApplicationAPIRequest::Execute_RegisterRunning (void)
  220. {
  221. NTSTATUS status;
  222. API_BAM_REGISTERRUNNING_IN *pAPIIn;
  223. API_BAM_REGISTERRUNNING_OUT *pAPIOut;
  224. WCHAR *pszImageName;
  225. pAPIIn = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiRegisterRunning.in;
  226. pAPIOut = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiRegisterRunning.out;
  227. if ((pAPIIn->bamType > BAM_TYPE_MINIMUM) && (pAPIIn->bamType < BAM_TYPE_MAXIMUM))
  228. {
  229. status = _AllocAndMapClientString(_pAPIDispatcher->GetClientProcess(),
  230. pAPIIn->pszImageName, pAPIIn->cchImageName,
  231. MAX_PATH, &pszImageName);
  232. if (NT_SUCCESS(status))
  233. {
  234. HANDLE hProcess;
  235. CBadApplication badApplication(pszImageName);
  236. hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
  237. FALSE,
  238. pAPIIn->dwProcessID);
  239. if (hProcess != NULL)
  240. {
  241. status = s_pBadApplicationManager->RegisterRunning(badApplication, hProcess, pAPIIn->bamType);
  242. TBOOL(CloseHandle(hProcess));
  243. }
  244. else
  245. {
  246. status = CStatusCode::StatusCodeOfLastError();
  247. }
  248. _FreeMappedClientString(pszImageName);
  249. }
  250. }
  251. else
  252. {
  253. status = STATUS_INVALID_PARAMETER;
  254. }
  255. SetDataLength(sizeof(API_BAM));
  256. return(status);
  257. }
  258. // --------------------------------------------------------------------------
  259. // CBadApplicationAPIRequest::Execute_QueryUserPermission
  260. //
  261. // Arguments: <none>
  262. //
  263. // Returns: NTSTATUS
  264. //
  265. // Purpose: Handles API_BAM_QUERYUSERPERMISSION. Queries the client
  266. // permission to close down the bad application. Also returns
  267. // the current user of the bad application.
  268. //
  269. // History: 2000-08-31 vtan created
  270. // --------------------------------------------------------------------------
  271. NTSTATUS CBadApplicationAPIRequest::Execute_QueryUserPermission (void)
  272. {
  273. NTSTATUS status;
  274. API_BAM_QUERYUSERPERMISSION_IN *pAPIIn;
  275. API_BAM_QUERYUSERPERMISSION_OUT *pAPIOut;
  276. WCHAR* pszImageName;
  277. pAPIIn = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiQueryUserPermission.in;
  278. pAPIOut = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiQueryUserPermission.out;
  279. status = _AllocAndMapClientString(_pAPIDispatcher->GetClientProcess(),
  280. pAPIIn->pszImageName, pAPIIn->cchImageName,
  281. MAX_PATH, &pszImageName);
  282. if(NT_SUCCESS(status))
  283. {
  284. HANDLE hProcess;
  285. CBadApplication badApplication(pszImageName);
  286. // Query information on the bad application
  287. // (get back the process handle).
  288. status = s_pBadApplicationManager->QueryInformation(badApplication, hProcess);
  289. if (NT_SUCCESS(status))
  290. {
  291. HANDLE hToken;
  292. // Get the client token and impersonate that user.
  293. status = OpenClientToken(hToken);
  294. if (NT_SUCCESS(status))
  295. {
  296. bool fCanShutdownApplication;
  297. HANDLE hTokenProcess;
  298. CTokenInformation tokenInformationClient(hToken);
  299. fCanShutdownApplication = tokenInformationClient.IsUserAnAdministrator();
  300. // Get the bad application process token to get
  301. // information on the user for the process.
  302. if (OpenProcessToken(hProcess,
  303. TOKEN_QUERY,
  304. &hTokenProcess) != FALSE)
  305. {
  306. const WCHAR *pszUserDisplayName;
  307. CTokenInformation tokenInformationProcess(hTokenProcess);
  308. pszUserDisplayName = tokenInformationProcess.GetUserDisplayName();
  309. if (pszUserDisplayName != NULL)
  310. {
  311. int iCharsToWrite;
  312. SIZE_T dwNumberOfBytesWritten;
  313. // Return the information back to the client.
  314. pAPIOut->fCanShutdownApplication = fCanShutdownApplication;
  315. iCharsToWrite = lstrlen(pszUserDisplayName) + sizeof('\0');
  316. if (iCharsToWrite > pAPIIn->cchUser)
  317. {
  318. iCharsToWrite = pAPIIn->cchUser;
  319. }
  320. if (WriteProcessMemory(_pAPIDispatcher->GetClientProcess(),
  321. pAPIIn->pszUser,
  322. const_cast<WCHAR*>(pszUserDisplayName),
  323. iCharsToWrite * sizeof(WCHAR),
  324. &dwNumberOfBytesWritten) != FALSE)
  325. {
  326. status = STATUS_SUCCESS;
  327. }
  328. else
  329. {
  330. status = CStatusCode::StatusCodeOfLastError();
  331. }
  332. }
  333. else
  334. {
  335. status = CStatusCode::StatusCodeOfLastError();
  336. }
  337. TBOOL(CloseHandle(hTokenProcess));
  338. }
  339. else
  340. {
  341. status = CStatusCode::StatusCodeOfLastError();
  342. }
  343. TBOOL(CloseHandle(hToken));
  344. }
  345. else
  346. {
  347. status = CStatusCode::StatusCodeOfLastError();
  348. }
  349. TBOOL(CloseHandle(hProcess));
  350. }
  351. _FreeMappedClientString(pszImageName);
  352. }
  353. SetDataLength(sizeof(API_BAM));
  354. return(status);
  355. }
  356. // --------------------------------------------------------------------------
  357. // CBadApplicationAPIRequest::Execute_QueryUserPermission
  358. //
  359. // Arguments: <none>
  360. //
  361. // Returns: NTSTATUS
  362. //
  363. // Purpose: Handles API_BAM_TERMINATERUNNING. Terminates the given running
  364. // bad application so a different instance on a different
  365. // window station can start it.
  366. //
  367. // History: 2000-08-31 vtan created
  368. // --------------------------------------------------------------------------
  369. NTSTATUS CBadApplicationAPIRequest::Execute_TerminateRunning (void)
  370. {
  371. NTSTATUS status;
  372. API_BAM_TERMINATERUNNING_IN *pAPIIn;
  373. API_BAM_TERMINATERUNNING_OUT *pAPIOut;
  374. WCHAR *pszImageName;
  375. pAPIIn = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiTerminateRunning.in;
  376. pAPIOut = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiTerminateRunning.out;
  377. status = _AllocAndMapClientString(_pAPIDispatcher->GetClientProcess(),
  378. pAPIIn->pszImageName, pAPIIn->cchImageName,
  379. MAX_PATH, &pszImageName);
  380. if(NT_SUCCESS(status))
  381. {
  382. HANDLE hToken;
  383. // Get the client token and for membership of the local administrators
  384. // group. DO NOT IMPERSONATE THE CLIENT. This will almost certainly
  385. // guarantee that the process cannot be terminated.
  386. status = OpenClientToken(hToken);
  387. if (NT_SUCCESS(status))
  388. {
  389. CTokenInformation tokenInformationClient(hToken);
  390. if (tokenInformationClient.IsUserAnAdministrator())
  391. {
  392. HANDLE hProcess;
  393. CBadApplication badApplication(pszImageName);
  394. // Query information on the bad application
  395. // (get back the process handle).
  396. status = s_pBadApplicationManager->QueryInformation(badApplication, hProcess);
  397. if (NT_SUCCESS(status))
  398. {
  399. do
  400. {
  401. status = CBadApplicationManager::PerformTermination(hProcess, true);
  402. TBOOL(CloseHandle(hProcess));
  403. } while (NT_SUCCESS(status) &&
  404. NT_SUCCESS(s_pBadApplicationManager->QueryInformation(badApplication, hProcess)));
  405. }
  406. // If the information could not be found then it's
  407. // probably not running. This indicates success.
  408. else
  409. {
  410. status = STATUS_SUCCESS;
  411. }
  412. }
  413. else
  414. {
  415. status = STATUS_ACCESS_DENIED;
  416. }
  417. TBOOL(CloseHandle(hToken));
  418. }
  419. _FreeMappedClientString(pszImageName);
  420. }
  421. pAPIOut->fResult = NT_SUCCESS(status);
  422. SetDataLength(sizeof(API_BAM));
  423. return(status);
  424. }
  425. // --------------------------------------------------------------------------
  426. // CBadApplicationAPIRequest::Execute_RequestSwitchUser
  427. //
  428. // Arguments: <none>
  429. //
  430. // Returns: NTSTATUS
  431. //
  432. // Purpose: Handles API_BAM_REQUESTSWITCHUSER. Request from
  433. // winlogon/msgina to switch a user. Terminate all bad
  434. // applications related to disconnect. Reject the disconnect if
  435. // it fails.
  436. //
  437. // History: 2000-11-02 vtan created
  438. // --------------------------------------------------------------------------
  439. NTSTATUS CBadApplicationAPIRequest::Execute_RequestSwitchUser (void)
  440. {
  441. API_BAM_REQUESTSWITCHUSER_OUT *pAPIOut;
  442. pAPIOut = &reinterpret_cast<API_BAM*>(&_data)->apiSpecific.apiRequestSwitchUser.out;
  443. pAPIOut->fAllowSwitch = NT_SUCCESS(s_pBadApplicationManager->RequestSwitchUser());
  444. SetDataLength(sizeof(API_BAM));
  445. return(STATUS_SUCCESS);
  446. }
  447. #endif /* _X86_ */