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.

568 lines
17 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: random.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains a random collection of support routines for the User
  7. * API functions. Many of these functions will be moved to more appropriate
  8. * files once we get our act together.
  9. *
  10. * History:
  11. * 10-17-90 DarrinM Created.
  12. * 02-06-91 IanJa HWND revalidation added (none required)
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /***************************************************************************\
  17. * xxxUpdateWindows
  18. *
  19. * User mode wrapper
  20. \***************************************************************************/
  21. BOOL xxxUpdateWindows(
  22. PWND pwnd,
  23. HRGN hrgn)
  24. {
  25. CheckLock(pwnd);
  26. xxxUpdateThreadsWindows(PtiCurrent(), pwnd, hrgn);
  27. return TRUE;
  28. }
  29. /***************************************************************************\
  30. * ValidateState
  31. *
  32. * States allowed to be set/cleared by Set/ClearWindowState. If you're
  33. * allowing a new flag here, you must make sure it won't cause an AV
  34. * in the kernel if someone sets it maliciously.
  35. \***************************************************************************/
  36. #define NUM_BYTES 16 // Window state bytes are 0 to F, explanation in user.h
  37. CONST BYTE abValidateState[NUM_BYTES] = {
  38. 0, // 0
  39. 0, // 1
  40. 0, // 2
  41. 0, // 3
  42. 0, // 4
  43. LOBYTE(WFWIN40COMPAT),
  44. 0, // 6
  45. LOBYTE(WFNOANIMATE),
  46. 0, // 8
  47. LOBYTE(WEFEDGEMASK),
  48. LOBYTE(WEFSTATICEDGE),
  49. 0, // B
  50. LOBYTE(EFPASSWORD),
  51. LOBYTE(CBFHASSTRINGS | EFREADONLY),
  52. LOBYTE(WFTABSTOP | WFSYSMENU | WFVSCROLL | WFHSCROLL | WFBORDER),
  53. LOBYTE(WFCLIPCHILDREN)
  54. };
  55. BOOL ValidateState(
  56. DWORD dwFlags)
  57. {
  58. BYTE bOffset = HIBYTE(dwFlags), bState = LOBYTE(dwFlags);
  59. if (bOffset > NUM_BYTES - 1) {
  60. return FALSE;
  61. } else {
  62. return ((bState & abValidateState[bOffset]) == bState);
  63. }
  64. }
  65. /***************************************************************************\
  66. * Set/ClearWindowState
  67. *
  68. * Wrapper functions for User mode to be able to set state flags.
  69. \***************************************************************************/
  70. VOID SetWindowState(
  71. PWND pwnd,
  72. DWORD dwFlags)
  73. {
  74. /*
  75. * Don't let anyone mess with someone else's window.
  76. */
  77. if (GETPTI(pwnd)->ppi == PtiCurrent()->ppi) {
  78. if (ValidateState(dwFlags)) {
  79. SetWF(pwnd, dwFlags);
  80. } else {
  81. RIPMSG1(RIP_ERROR, "SetWindowState: invalid flag 0x%x", dwFlags);
  82. }
  83. } else {
  84. RIPMSG1(RIP_WARNING, "SetWindowState: current ppi doesn't own pwnd %#p", pwnd);
  85. }
  86. }
  87. VOID ClearWindowState(
  88. PWND pwnd,
  89. DWORD dwFlags)
  90. {
  91. /*
  92. * Don't let anyone mess with someone else's window.
  93. */
  94. if (GETPTI(pwnd)->ppi == PtiCurrent()->ppi) {
  95. if (ValidateState(dwFlags)) {
  96. ClrWF(pwnd, dwFlags);
  97. } else {
  98. RIPMSG1(RIP_ERROR, "SetWindowState: invalid flag 0x%x", dwFlags);
  99. }
  100. } else {
  101. RIPMSG1(RIP_WARNING, "ClearWindowState: current ppi doesn't own pwnd %#p", pwnd);
  102. }
  103. }
  104. /***************************************************************************\
  105. * CheckPwndFilter
  106. *
  107. *
  108. *
  109. * History:
  110. * 11-07-90 DarrinM Translated Win 3.0 ASM code.
  111. \***************************************************************************/
  112. BOOL CheckPwndFilter(
  113. PWND pwnd,
  114. PWND pwndFilter)
  115. {
  116. if ((pwndFilter == NULL) || (pwndFilter == pwnd) ||
  117. ((pwndFilter == (PWND)1) && (pwnd == NULL))) {
  118. return TRUE;
  119. }
  120. return _IsChild(pwndFilter, pwnd);
  121. }
  122. /***************************************************************************\
  123. * AllocateUnicodeString
  124. *
  125. * History:
  126. * 10-25-90 MikeHar Wrote.
  127. * 11-09-90 DarrinM Fixed.
  128. * 01-13-92 GregoryW Neutralized.
  129. * 03-05-98 FritzS Only allocate Length+1
  130. \***************************************************************************/
  131. BOOL AllocateUnicodeString(
  132. PUNICODE_STRING pstrDst,
  133. PUNICODE_STRING cczpstrSrc)
  134. {
  135. if (cczpstrSrc == NULL) {
  136. RtlInitUnicodeString(pstrDst, NULL);
  137. return TRUE;
  138. }
  139. pstrDst->Buffer = UserAllocPoolWithQuota(cczpstrSrc->Length+sizeof(UNICODE_NULL), TAG_TEXT);
  140. if (pstrDst->Buffer == NULL) {
  141. return FALSE;
  142. }
  143. try {
  144. RtlCopyMemory(pstrDst->Buffer, cczpstrSrc->Buffer, cczpstrSrc->Length);
  145. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  146. UserFreePool(pstrDst->Buffer);
  147. pstrDst->Buffer = NULL;
  148. return FALSE;
  149. }
  150. pstrDst->MaximumLength = cczpstrSrc->Length+sizeof(UNICODE_NULL);
  151. pstrDst->Length = cczpstrSrc->Length;
  152. pstrDst->Buffer[pstrDst->Length / sizeof(WCHAR)] = 0;
  153. return TRUE;
  154. }
  155. /***************************************************************************\
  156. * xxxGetControlColor
  157. *
  158. * History:
  159. * 02-12-92 JimA Ported from Win31 sources
  160. \***************************************************************************/
  161. HBRUSH xxxGetControlColor(
  162. PWND pwndParent,
  163. PWND pwndCtl,
  164. HDC hdc,
  165. UINT message)
  166. {
  167. HBRUSH hbrush;
  168. /*
  169. * If we're sending to a window of another thread, don't send this message
  170. * but instead call DefWindowProc(). New rule about the CTLCOLOR messages.
  171. * Need to do this so that we don't send an hdc owned by one thread to
  172. * another thread. It is also a harmless change.
  173. */
  174. if (PpiCurrent() != GETPTI(pwndParent)->ppi) {
  175. return (HBRUSH)xxxDefWindowProc(pwndParent, message, (WPARAM)hdc, (LPARAM)HW(pwndCtl));
  176. }
  177. hbrush = (HBRUSH)xxxSendMessage(pwndParent, message, (WPARAM)hdc, (LPARAM)HW(pwndCtl));
  178. /*
  179. * If the brush returned from the parent is invalid, get a valid brush from
  180. * xxxDefWindowProc.
  181. */
  182. if (hbrush == 0 || !GreValidateServerHandle(hbrush, BRUSH_TYPE)) {
  183. if (hbrush != 0) {
  184. RIPMSG2(RIP_WARNING,
  185. "Invalid HBRUSH from WM_CTLCOLOR*** msg 0x%x brush 0x%x",
  186. message, hbrush);
  187. }
  188. hbrush = (HBRUSH)xxxDefWindowProc(pwndParent, message,
  189. (WPARAM)hdc, (LPARAM)pwndCtl);
  190. }
  191. return hbrush;
  192. }
  193. /***************************************************************************\
  194. * xxxGetControlBrush
  195. *
  196. * <brief description>
  197. *
  198. * History:
  199. * 12-10-90 IanJa type replaced with new 32-bit message
  200. * 01-21-91 IanJa Prefix '_' denoting exported function (although not API)
  201. \***************************************************************************/
  202. HBRUSH xxxGetControlBrush(
  203. PWND pwnd,
  204. HDC hdc,
  205. UINT message)
  206. {
  207. HBRUSH hbr;
  208. PWND pwndSend;
  209. TL tlpwndSend;
  210. CheckLock(pwnd);
  211. if ((pwndSend = (TestwndPopup(pwnd) ? pwnd->spwndOwner : pwnd->spwndParent))
  212. == NULL) {
  213. pwndSend = pwnd;
  214. }
  215. ThreadLock(pwndSend, &tlpwndSend);
  216. /*
  217. * Last parameter changes the message into a ctlcolor id.
  218. */
  219. hbr = xxxGetControlColor(pwndSend, pwnd, hdc, message);
  220. ThreadUnlock(&tlpwndSend);
  221. return hbr;
  222. }
  223. /***************************************************************************\
  224. * xxxHardErrorControl
  225. *
  226. * Performs kernel-mode hard error support functions.
  227. *
  228. * History:
  229. * 02-08-95 JimA Created.
  230. \***************************************************************************/
  231. UINT xxxHardErrorControl(
  232. DWORD dwCmd,
  233. HANDLE handle,
  234. PDESKRESTOREDATA pdrdRestore)
  235. {
  236. PTHREADINFO ptiClient, ptiCurrent = PtiCurrent();
  237. PDESKTOP pdesk;
  238. PUNICODE_STRING pstrName;
  239. NTSTATUS Status;
  240. PETHREAD Thread;
  241. BOOL fAllowForeground;
  242. /*
  243. * turn off BlockInput so the user can respond to the hard error popup
  244. */
  245. gptiBlockInput = NULL;
  246. UserAssert(ISCSRSS());
  247. switch (dwCmd) {
  248. /*
  249. * Code to catch Windows Bug 469607.
  250. */
  251. #ifdef PRERELEASE
  252. case HardErrorCheckOnDesktop:
  253. if (ptiCurrent == gptiForeground && ptiCurrent->rpdesk == NULL) {
  254. FRE_RIPMSG0(RIP_ERROR,
  255. "Harderror thread exiting while not on a desktop");
  256. }
  257. break;
  258. #endif
  259. case HardErrorSetup:
  260. /*
  261. * Don't do it if the system has not been initialized.
  262. */
  263. if (grpdeskRitInput == NULL) {
  264. RIPMSG0(RIP_WARNING, "HardErrorControl: System not initialized");
  265. return HEC_ERROR;
  266. }
  267. /*
  268. * Setup caller as the hard error handler.
  269. */
  270. if (gHardErrorHandler.pti != NULL) {
  271. RIPMSG1(RIP_WARNING, "HardErrorControl: pti not NULL %#p", gHardErrorHandler.pti);
  272. return HEC_ERROR;
  273. }
  274. /*
  275. * Mark the handler as active.
  276. */
  277. gHardErrorHandler.pti = ptiCurrent;
  278. /*
  279. * Clear any pending quits.
  280. */
  281. ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED;
  282. break;
  283. case HardErrorCleanup:
  284. /*
  285. * Remove caller as the hard error handler.
  286. */
  287. if (gHardErrorHandler.pti != ptiCurrent) {
  288. return HEC_ERROR;
  289. }
  290. gHardErrorHandler.pti = NULL;
  291. break;
  292. case HardErrorAttachUser:
  293. case HardErrorInDefDesktop:
  294. /*
  295. * Check for exit conditions. We do not allow attaches to the
  296. * disconnect desktop.
  297. */
  298. if (ISTS()) {
  299. if ((grpdeskRitInput == NULL) ||
  300. ((grpdeskRitInput == gspdeskDisconnect) &&
  301. (gspdeskShouldBeForeground == NULL)) ||
  302. ((grpdeskRitInput == gspdeskDisconnect) &&
  303. (gspdeskShouldBeForeground == gspdeskDisconnect))) {
  304. return HEC_ERROR;
  305. }
  306. }
  307. /*
  308. * Only attach to a user desktop.
  309. */
  310. if (ISTS() && grpdeskRitInput == gspdeskDisconnect) {
  311. pstrName = POBJECT_NAME(gspdeskShouldBeForeground);
  312. } else {
  313. pstrName = POBJECT_NAME(grpdeskRitInput);
  314. }
  315. if (pstrName && (!_wcsicmp(TEXT("Winlogon"), pstrName->Buffer) ||
  316. !_wcsicmp(TEXT("Disconnect"), pstrName->Buffer) ||
  317. !_wcsicmp(TEXT("Screen-saver"), pstrName->Buffer))) {
  318. RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "");
  319. return HEC_WRONGDESKTOP;
  320. }
  321. if (dwCmd == HardErrorInDefDesktop) {
  322. /*
  323. * Clear any pending quits.
  324. */
  325. ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED;
  326. return HEC_SUCCESS;
  327. }
  328. /*
  329. * Fall through.
  330. */
  331. case HardErrorAttach:
  332. /*
  333. * Save a pointer to and prevent destruction of the
  334. * current queue. This will give us a queue to return
  335. * to if journalling is occuring when we tear down the
  336. * hard error popup.
  337. */
  338. gHardErrorHandler.pqAttach = ptiCurrent->pq;
  339. (ptiCurrent->pq->cLockCount)++;
  340. /*
  341. * Fall through.
  342. */
  343. case HardErrorAttachNoQueue:
  344. /*
  345. * Check for exit conditions. We do not allow attaches to the
  346. * disconnect desktop.
  347. */
  348. if (ISTS()) {
  349. if ((grpdeskRitInput == NULL) ||
  350. ((grpdeskRitInput == gspdeskDisconnect) &&
  351. (gspdeskShouldBeForeground == NULL)) ||
  352. ((grpdeskRitInput == gspdeskDisconnect) &&
  353. (gspdeskShouldBeForeground == gspdeskDisconnect))) {
  354. return HEC_ERROR;
  355. }
  356. }
  357. /*
  358. * Attach the handler to the current desktop.
  359. */
  360. /*
  361. * Don't allow an attach to the disconnected desktop, but
  362. * remember this for later when we detach.
  363. */
  364. gbDisconnectHardErrorAttach = FALSE;
  365. if (ISTS() && grpdeskRitInput == gspdeskDisconnect) {
  366. pdesk = gspdeskShouldBeForeground;
  367. gbDisconnectHardErrorAttach = TRUE;
  368. } else {
  369. pdesk = grpdeskRitInput;
  370. }
  371. UserAssert(pdesk != NULL);
  372. Status = xxxSetCsrssThreadDesktop(pdesk, pdrdRestore);
  373. if (!NT_SUCCESS(Status)) {
  374. RIPMSG1(RIP_WARNING,
  375. "HardErrorControl: HardErrorAttachNoQueue failed: 0x%x",
  376. Status);
  377. if (dwCmd != HardErrorAttachNoQueue) {
  378. gHardErrorHandler.pqAttach = NULL;
  379. UserAssert(ptiCurrent->pq->cLockCount);
  380. (ptiCurrent->pq->cLockCount)--;
  381. }
  382. return HEC_ERROR;
  383. }
  384. /*
  385. * Make sure we actually set the pdesk in the current thread
  386. */
  387. UserAssert(ptiCurrent->rpdesk != NULL);
  388. /*
  389. * Determine if this box can come to the foreground.
  390. * Let it come to the foreground if it doesn't have a pti
  391. * (it might have just failed to load).
  392. */
  393. fAllowForeground = FALSE;
  394. if (handle != NULL) {
  395. Status = ObReferenceObjectByHandle(handle,
  396. THREAD_QUERY_INFORMATION,
  397. *PsThreadType,
  398. UserMode,
  399. &Thread,
  400. NULL);
  401. if (NT_SUCCESS(Status)) {
  402. ptiClient = PtiFromThread(Thread);
  403. if ((ptiClient == NULL) || CanForceForeground(ptiClient->ppi)) {
  404. fAllowForeground = TRUE;
  405. }
  406. UnlockThread(Thread);
  407. } else {
  408. RIPMSGF2(RIP_WARNING,
  409. "Failed to get thread (0x%p), Status: 0x%x",
  410. handle,
  411. Status);
  412. }
  413. }
  414. if (fAllowForeground) {
  415. ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
  416. TAGMSG1(DBGTAG_FOREGROUND, "xxxHardErrorControl set TIF %#lx", ptiCurrent);
  417. } else {
  418. ptiCurrent->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
  419. TAGMSG1(DBGTAG_FOREGROUND, "xxxHardErrorControl clear TIF %#lx", ptiCurrent);
  420. }
  421. break;
  422. case HardErrorDetach:
  423. /*
  424. * xxxSwitchDesktop may have sent WM_QUIT to the msgbox, so
  425. * ensure that the quit flag is reset.
  426. */
  427. ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED;
  428. /*
  429. * We will reset the hard-error queue to the pre-allocated
  430. * one so if we end up looping back (i.e. from a desktop
  431. * switch), we will have a valid queue in case the desktop
  432. * was deleted.
  433. */
  434. UserAssert(gHardErrorHandler.pqAttach->cLockCount);
  435. (gHardErrorHandler.pqAttach->cLockCount)--;
  436. DeferWinEventNotify();
  437. BEGINATOMICCHECK();
  438. if (ptiCurrent->pq != gHardErrorHandler.pqAttach) {
  439. UserAssert(gHardErrorHandler.pqAttach->cThreads == 0);
  440. AllocQueue(NULL, gHardErrorHandler.pqAttach);
  441. gHardErrorHandler.pqAttach->cThreads++;
  442. zzzAttachToQueue(ptiCurrent, gHardErrorHandler.pqAttach, NULL, FALSE);
  443. }
  444. gHardErrorHandler.pqAttach = NULL;
  445. ENDATOMICCHECK();
  446. zzzEndDeferWinEventNotify();
  447. /*
  448. * Fall through.
  449. */
  450. case HardErrorDetachNoQueue:
  451. /*
  452. * Detach the handler from the desktop and return
  453. * status to indicate if a switch has occured.
  454. */
  455. pdesk = ptiCurrent->rpdesk;
  456. xxxRestoreCsrssThreadDesktop(pdrdRestore);
  457. if (ISTS()) {
  458. /*
  459. * The hard error message box gets a desktop switch notification,
  460. * so remember that we lied to him and lie (or unlie) to him again.
  461. * A desktop switch did occur.
  462. */
  463. if (gbDisconnectHardErrorAttach) {
  464. gbDisconnectHardErrorAttach = FALSE;
  465. return HEC_DESKTOPSWITCH;
  466. }
  467. #ifdef WAY_LATER
  468. /*
  469. * This happened once and caused a trap when a KeyEvent() came in and we
  470. * directed it to this queue. I think this is a MS window that we caught
  471. * since we use this so much for license popup's.
  472. */
  473. if (gHardErrorHandler.pqAttach == gpqForeground) {
  474. gpqForeground = NULL;
  475. }
  476. #endif
  477. }
  478. return (pdesk != grpdeskRitInput ? HEC_DESKTOPSWITCH : HEC_SUCCESS);
  479. }
  480. return HEC_SUCCESS;
  481. }