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.

502 lines
14 KiB

  1. /*************************************************************************\
  2. *
  3. * icamsg.c
  4. *
  5. * Process ICA send message requests
  6. *
  7. * Copyright (c) 1985 - 1999, Microsoft Corporation
  8. *
  9. * $Author:
  10. *
  11. \*************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <dbt.h>
  15. #include <ntdddisk.h>
  16. #include "ntuser.h"
  17. #include <winsta.h>
  18. #include <wstmsg.h>
  19. #define MAX_STRING_BYTES (512 * sizeof(WCHAR))
  20. /*
  21. * maximum messages (messagebox) a session can have pending.
  22. */
  23. #define MAX_MESSAGES_PER_SESSION 25
  24. NTSTATUS RemoteMessageThread(
  25. PVOID pVoid);
  26. VOID UserHardErrorEx(
  27. PCSR_THREAD pt,
  28. PHARDERROR_MSG pmsg,
  29. PCTXHARDERRORINFO pCtxHEInfo);
  30. NTSTATUS ReplyMessageToTerminalServer(
  31. NTSTATUS ReplyStatus,
  32. PNTSTATUS pStatus,
  33. ULONG Response,
  34. PULONG pResponse,
  35. HANDLE hEvent);
  36. PCTXHARDERRORINFO gpchiList;
  37. HANDLE g_hDoMessageEvent;
  38. ULONG PendingMessages;
  39. /******************************************************************************\
  40. * RemoteDoMessage
  41. \******************************************************************************/
  42. NTSTATUS
  43. RemoteDoMessage(
  44. PWINSTATION_APIMSG pMsg)
  45. {
  46. WINSTATIONSENDMESSAGEMSG * pSMsg = &pMsg->u.SendMessage;
  47. PCTXHARDERRORINFO pchi;
  48. NTSTATUS Status;
  49. CLIENT_ID ClientId;
  50. static HANDLE hMessageThread = NULL;
  51. /*
  52. * if termsrv rpc is going to wait we must have status and event.
  53. * also if we are not going to wait, we must not have status and event.
  54. */
  55. UserAssert(pSMsg->DoNotWait == (pSMsg->pStatus == 0));
  56. UserAssert(pSMsg->DoNotWait == (pSMsg->hEvent == 0));
  57. UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION);
  58. /*
  59. * are we being flooded with messages?
  60. */
  61. if (PendingMessages == MAX_MESSAGES_PER_SESSION) {
  62. return STATUS_UNSUCCESSFUL;
  63. }
  64. /*
  65. * Create list entry
  66. */
  67. if ((pchi = LocalAlloc(LPTR, sizeof(CTXHARDERRORINFO))) == NULL) {
  68. goto memError;
  69. } else if ((pchi->pTitle = LocalAlloc(LPTR, pSMsg->TitleLength + sizeof(WCHAR))) == NULL) {
  70. goto memError;
  71. } else if ((pchi->pMessage = LocalAlloc(LPTR, pSMsg->MessageLength + sizeof(WCHAR))) == NULL) {
  72. goto memError;
  73. }
  74. /*
  75. * Increment our pending message count.
  76. */
  77. EnterCrit();
  78. PendingMessages++;
  79. pchi->CountPending = TRUE;
  80. /*
  81. * Initialize
  82. */
  83. pchi->ClientId = pMsg->h.ClientId;
  84. pchi->MessageId = pMsg->MessageId;
  85. pchi->Timeout = pSMsg->Timeout;
  86. pchi->pStatus = pSMsg->pStatus;
  87. pchi->pResponse = pSMsg->pResponse;
  88. pchi->hEvent = pSMsg->hEvent;
  89. pchi->DoNotWait = pSMsg->DoNotWait;
  90. pchi->Style = pSMsg->Style;
  91. pchi->DoNotWaitForCorrectDesktop = pSMsg->DoNotWaitForCorrectDesktop;
  92. pchi->pTitle[pSMsg->TitleLength / sizeof(WCHAR)] = L'\0';
  93. RtlCopyMemory(pchi->pTitle, pSMsg->pTitle, pSMsg->TitleLength);
  94. pchi->pMessage[pSMsg->MessageLength / sizeof(WCHAR)] = L'\0';
  95. RtlCopyMemory(pchi->pMessage, pSMsg->pMessage, pSMsg->MessageLength);
  96. /*
  97. * Link in at the head.
  98. */
  99. pchi->pchiNext = gpchiList;
  100. gpchiList = pchi;
  101. LeaveCrit();
  102. /*
  103. * Start message thread if not running, otherwise signal thread.
  104. */
  105. if (hMessageThread == NULL) {
  106. Status = RtlCreateUserThread(NtCurrentProcess(),
  107. NULL,
  108. TRUE,
  109. 0,
  110. 0,
  111. 0,
  112. RemoteMessageThread,
  113. NULL,
  114. &hMessageThread,
  115. &ClientId);
  116. if (NT_SUCCESS(Status)) {
  117. /*
  118. * Add thread to server thread pool.
  119. */
  120. CsrAddStaticServerThread(hMessageThread, &ClientId, 0);
  121. NtResumeThread(hMessageThread, NULL);
  122. } else {
  123. RIPMSGF1(RIP_WARNING,
  124. "Cannot start RemoteMessageThread, Status 0x%x",
  125. Status);
  126. }
  127. } else {
  128. if (g_hDoMessageEvent == NULL) {
  129. return STATUS_UNSUCCESSFUL;
  130. }
  131. Status = NtSetEvent(g_hDoMessageEvent, NULL);
  132. if (!NT_SUCCESS(Status)) {
  133. RIPMSGF1(RIP_WARNING,
  134. "Error NtSetEvent failed, Status = 0x%x",
  135. Status);
  136. return Status;
  137. }
  138. }
  139. return STATUS_SUCCESS;
  140. memError:
  141. if (pchi) {
  142. if (pchi->pMessage) {
  143. LocalFree(pchi->pMessage);
  144. }
  145. if (pchi->pTitle) {
  146. LocalFree(pchi->pTitle);
  147. }
  148. LocalFree(pchi);
  149. }
  150. if (!pSMsg->DoNotWait) {
  151. ReplyMessageToTerminalServer(
  152. STATUS_NO_MEMORY,
  153. pSMsg->pStatus,
  154. 0, // response is NA at this case, since we havent gotten one.
  155. pSMsg->pResponse,
  156. pSMsg->hEvent);
  157. }
  158. return STATUS_NO_MEMORY;
  159. }
  160. /*******************************************************************************
  161. *
  162. * RemoteDoLoadStringNMessage
  163. *
  164. * ENTRY:
  165. *
  166. * EXIT:
  167. * STATUS_SUCCESS - successful
  168. *
  169. ******************************************************************************/
  170. NTSTATUS
  171. RemoteDoLoadStringNMessage(
  172. PWINSTATION_APIMSG pMsg)
  173. {
  174. WINSTATIONLOADSTRINGMSG * pSMsg = &pMsg->u.LoadStringMessage;
  175. PCTXHARDERRORINFO pchi = NULL;
  176. NTSTATUS Status;
  177. CLIENT_ID ClientId;
  178. static HANDLE hMessageThread = NULL;
  179. WCHAR *szText = NULL;
  180. WCHAR *szTitle = NULL;
  181. WCHAR *FUSDisconnectMsg = NULL;
  182. int cchTitle, cchMessage;
  183. BOOL f;
  184. /*
  185. * If termsrv rpc is going to wait we must have status and event. Also
  186. * if we are not going to wait, we must not have status and event.
  187. */
  188. UserAssert(pSMsg->DoNotWait == (pSMsg->pStatus == 0));
  189. UserAssert(pSMsg->DoNotWait == (pSMsg->hEvent == 0));
  190. UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION);
  191. //
  192. // Allocate the strings needed to display the Popup MessageBox.
  193. //
  194. if ((szTitle = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES)) == NULL) {
  195. goto NoMem;
  196. }
  197. if ((FUSDisconnectMsg = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES)) == NULL) {
  198. goto NoMem;
  199. }
  200. szText = ServerLoadString(ghModuleWin, pSMsg->TitleId, NULL, &f);
  201. cchTitle = wsprintf(szTitle, L"%s", szText);
  202. cchTitle = (cchTitle + 1) * sizeof(WCHAR);
  203. szText = ServerLoadString(ghModuleWin, pSMsg->MessageId, NULL, &f);
  204. cchMessage = wsprintf(FUSDisconnectMsg, L"%s\\%s %s", pSMsg->pDomain, pSMsg->pUserName, szText);
  205. cchMessage = (cchMessage + 1) * sizeof(WCHAR);
  206. /*
  207. * Create list entry.
  208. */
  209. if ((pchi = LocalAlloc(LPTR, sizeof(CTXHARDERRORINFO))) == NULL) {
  210. goto NoMem;
  211. } else if ((pchi->pTitle = LocalAlloc(LPTR, cchTitle + sizeof(WCHAR))) == NULL) {
  212. goto NoMem;
  213. } else if ((pchi->pMessage = LocalAlloc(LPTR, cchMessage + sizeof(WCHAR))) == NULL) {
  214. goto NoMem;
  215. }
  216. /*
  217. * Initialize.
  218. */
  219. pchi->ClientId = pMsg->h.ClientId;
  220. pchi->MessageId = pMsg->MessageId;
  221. pchi->Timeout = pSMsg->Timeout;
  222. pchi->pResponse = pSMsg->pResponse;
  223. pchi->pStatus = pSMsg->pStatus;
  224. pchi->hEvent = pSMsg->hEvent;
  225. pchi->DoNotWait = pSMsg->DoNotWait;
  226. pchi->Style = pSMsg->Style;
  227. pchi->CountPending = FALSE;
  228. pchi->DoNotWaitForCorrectDesktop = FALSE;
  229. pchi->pTitle[cchTitle / sizeof(WCHAR)] = L'\0';
  230. RtlCopyMemory(pchi->pTitle, szTitle, cchTitle);
  231. pchi->pMessage[cchMessage / sizeof(WCHAR)] = L'\0';
  232. RtlCopyMemory(pchi->pMessage, FUSDisconnectMsg, cchMessage);
  233. /*
  234. * Link in at the head.
  235. */
  236. EnterCrit();
  237. pchi->pchiNext = gpchiList;
  238. gpchiList = pchi;
  239. LeaveCrit();
  240. LocalFree(szTitle);
  241. LocalFree(FUSDisconnectMsg);
  242. /*
  243. * Start message thread if not running, otherwise signal thread.
  244. */
  245. if (hMessageThread == NULL) {
  246. Status = RtlCreateUserThread(NtCurrentProcess(),
  247. NULL,
  248. TRUE,
  249. 0,
  250. 0,
  251. 0,
  252. RemoteMessageThread,
  253. NULL,
  254. &hMessageThread,
  255. &ClientId);
  256. if (NT_SUCCESS(Status)) {
  257. /*
  258. * Add thread to server thread pool.
  259. */
  260. CsrAddStaticServerThread(hMessageThread, &ClientId, 0);
  261. NtResumeThread(hMessageThread, NULL);
  262. } else {
  263. RIPMSGF1(RIP_WARNING,
  264. "Cannot start RemoteMessageThread, Status 0x%x",
  265. Status);
  266. }
  267. } else {
  268. if (g_hDoMessageEvent == NULL) {
  269. return STATUS_UNSUCCESSFUL;
  270. }
  271. Status = NtSetEvent(g_hDoMessageEvent, NULL);
  272. if (!NT_SUCCESS(Status)) {
  273. RIPMSGF2(RIP_WARNING,
  274. "NtSetEvent(0x%x) failed with Status 0x%x",
  275. g_hDoMessageEvent,
  276. Status);
  277. return Status;
  278. }
  279. }
  280. return STATUS_SUCCESS;
  281. NoMem:
  282. if (szTitle) {
  283. LocalFree(szTitle);
  284. }
  285. if (FUSDisconnectMsg) {
  286. LocalFree(FUSDisconnectMsg);
  287. }
  288. if (pchi) {
  289. if (pchi->pMessage) {
  290. LocalFree(pchi->pMessage);
  291. }
  292. if (pchi->pTitle) {
  293. LocalFree(pchi->pTitle);
  294. }
  295. LocalFree(pchi);
  296. }
  297. if (!pSMsg->DoNotWait) {
  298. ReplyMessageToTerminalServer(
  299. STATUS_NO_MEMORY,
  300. pSMsg->pStatus,
  301. 0, // response is NA at this case, since we havent gotten one.
  302. pSMsg->pResponse,
  303. pSMsg->hEvent);
  304. }
  305. return STATUS_NO_MEMORY;
  306. }
  307. /******************************************************************************\
  308. * RemoteMessageThread
  309. \******************************************************************************/
  310. NTSTATUS RemoteMessageThread(
  311. PVOID pVoid)
  312. {
  313. HARDERROR_MSG hemsg;
  314. PCTXHARDERRORINFO pchi, *ppchi;
  315. UNICODE_STRING Message, Title;
  316. NTSTATUS Status;
  317. OBJECT_ATTRIBUTES ObjA;
  318. UNREFERENCED_PARAMETER(pVoid);
  319. /*
  320. * Create sync event.
  321. */
  322. InitializeObjectAttributes(&ObjA, NULL, 0, NULL, NULL);
  323. Status = NtCreateEvent(&g_hDoMessageEvent, EVENT_ALL_ACCESS, &ObjA,
  324. NotificationEvent, FALSE);
  325. if (!NT_SUCCESS(Status)) {
  326. RIPMSGF1(RIP_WARNING, "NtCreateEvent failed, Status = 0x%x", Status);
  327. goto Exit;
  328. }
  329. while (!gbExitInProgress) {
  330. EnterCrit();
  331. if (gpchiList != NULL) {
  332. /*
  333. * Find last entry
  334. */
  335. for (ppchi = &gpchiList; *ppchi != NULL && (*ppchi)->pchiNext != NULL;
  336. ppchi = &(*ppchi)->pchiNext) {
  337. /* do nothing */;
  338. }
  339. /*
  340. * Found it.
  341. */
  342. if ((pchi = *ppchi) != NULL) {
  343. /*
  344. * Unlink from the list.
  345. */
  346. for (ppchi = &gpchiList; *ppchi != NULL && *ppchi != pchi;
  347. ppchi = &(*ppchi)->pchiNext) {
  348. /* do nothing */;
  349. }
  350. if (*ppchi != NULL) {
  351. *ppchi = pchi->pchiNext;
  352. }
  353. LeaveCrit();
  354. /*
  355. * Make strings unicode
  356. */
  357. RtlInitUnicodeString(&Title, pchi->pTitle);
  358. RtlInitUnicodeString(&Message, pchi->pMessage);
  359. /*
  360. * Initialize harderror message struct
  361. */
  362. hemsg.h.ClientId = pchi->ClientId;
  363. hemsg.Status = STATUS_SERVICE_NOTIFICATION;
  364. hemsg.NumberOfParameters = 3;
  365. hemsg.UnicodeStringParameterMask = 3;
  366. hemsg.ValidResponseOptions = OptionOk;
  367. hemsg.Parameters[0] = (ULONG_PTR)&Message;
  368. hemsg.Parameters[1] = (ULONG_PTR)&Title;
  369. hemsg.Parameters[2] = (ULONG_PTR)pchi->Style;
  370. /*
  371. * Place message in harderror queue.
  372. */
  373. UserHardErrorEx(NULL, &hemsg, pchi);
  374. } else {
  375. LeaveCrit();
  376. }
  377. } else {
  378. LeaveCrit();
  379. }
  380. if (gpchiList == NULL) {
  381. UserAssert(g_hDoMessageEvent != NULL);
  382. Status = NtWaitForSingleObject(g_hDoMessageEvent, FALSE, NULL);
  383. UserAssert(NT_SUCCESS(Status));
  384. NtResetEvent(g_hDoMessageEvent, NULL);
  385. }
  386. }
  387. NtClose(g_hDoMessageEvent);
  388. g_hDoMessageEvent = NULL;
  389. Exit:
  390. UserExitWorkerThread(Status);
  391. return Status;
  392. }
  393. /******************************************************************************\
  394. * HardErrorRemove
  395. \******************************************************************************/
  396. VOID HardErrorRemove(
  397. PCTXHARDERRORINFO pchi)
  398. {
  399. /*
  400. * Notify ICASRV's RPC thread if waiting.
  401. */
  402. if (!pchi->DoNotWait) {
  403. ReplyMessageToTerminalServer(
  404. STATUS_SUCCESS,
  405. pchi->pStatus,
  406. pchi->Response,
  407. pchi->pResponse,
  408. pchi->hEvent);
  409. }
  410. EnterCrit();
  411. if (pchi->CountPending) {
  412. UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION);
  413. PendingMessages--;
  414. }
  415. LocalFree(pchi->pMessage);
  416. LocalFree(pchi->pTitle);
  417. LocalFree(pchi);
  418. LeaveCrit();
  419. }