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.

1631 lines
51 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: winsta.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Windowstation Routines
  7. *
  8. * History:
  9. * 01-14-91 JimA Created.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /***************************************************************************\
  14. * InitTerminal
  15. *
  16. * Creates the desktop thread for a terminal and also the RIT for the
  17. * IO terminal
  18. *
  19. * History:
  20. * 27-10-97 CLupu Created.
  21. \***************************************************************************/
  22. NTSTATUS xxxInitTerminal(
  23. PTERMINAL pTerm)
  24. {
  25. NTSTATUS Status;
  26. PKEVENT pEventTermInit;
  27. HANDLE hEventInputReady, hEventTermInit;
  28. USER_API_MSG m;
  29. CheckCritIn();
  30. UserAssert(!(pTerm->dwTERMF_Flags & TERMF_INITIALIZED));
  31. if (pTerm->pEventInputReady != NULL) {
  32. /*
  33. * if we make it here it means that another thread is
  34. * executing xxxInitTerminal for the same terminal and it
  35. * left the critical section.
  36. */
  37. UserAssert(pTerm->pEventTermInit != NULL);
  38. /*
  39. * use a local variable so we can safely reset
  40. * pTerm->pEventTermInit when we're done with it
  41. */
  42. pEventTermInit = pTerm->pEventTermInit;
  43. ObReferenceObject(pEventTermInit);
  44. LeaveCrit();
  45. goto Wait;
  46. }
  47. /*
  48. * Create the input ready event. RIT and desktop thread will wait for it.
  49. * It will be set when the first desktop in this terminal will be created.
  50. */
  51. Status = ZwCreateEvent(
  52. &hEventInputReady,
  53. EVENT_ALL_ACCESS,
  54. NULL,
  55. NotificationEvent,
  56. FALSE);
  57. if (!NT_SUCCESS(Status))
  58. return Status;
  59. Status = ObReferenceObjectByHandle(
  60. hEventInputReady,
  61. EVENT_ALL_ACCESS,
  62. *ExEventObjectType,
  63. KernelMode,
  64. &pTerm->pEventInputReady, NULL);
  65. ZwClose(hEventInputReady);
  66. if (!NT_SUCCESS(Status))
  67. return Status;
  68. /*
  69. * Device and RIT initialization. Don't do it for
  70. * the system terminal.
  71. */
  72. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) {
  73. if (!CreateTerminalInput(pTerm)) {
  74. ObDereferenceObject(pTerm->pEventInputReady);
  75. return STATUS_NO_MEMORY;
  76. }
  77. }
  78. /*
  79. * create an event to syncronize the terminal initialization
  80. */
  81. Status = ZwCreateEvent(
  82. &hEventTermInit,
  83. EVENT_ALL_ACCESS,
  84. NULL,
  85. NotificationEvent,
  86. FALSE);
  87. if (!NT_SUCCESS(Status)) {
  88. ObDereferenceObject(pTerm->pEventInputReady);
  89. return Status;
  90. }
  91. Status = ObReferenceObjectByHandle(
  92. hEventTermInit,
  93. EVENT_ALL_ACCESS,
  94. *ExEventObjectType,
  95. KernelMode,
  96. &pTerm->pEventTermInit, NULL);
  97. ZwClose(hEventTermInit);
  98. if (!NT_SUCCESS(Status)) {
  99. ObDereferenceObject(pTerm->pEventInputReady);
  100. return Status;
  101. }
  102. /*
  103. * use a local variable so we can safely reset
  104. * pTerm->pEventTermInit when we're done with it
  105. */
  106. pEventTermInit = pTerm->pEventTermInit;
  107. if (!InitCreateSystemThreadsMsg(&m, CST_DESKTOP, pTerm, 0, FALSE)) {
  108. ObDereferenceObject(pTerm->pEventInputReady);
  109. ObDereferenceObject(pEventTermInit);
  110. return STATUS_NO_MEMORY;
  111. }
  112. LeaveCrit();
  113. /*
  114. * Create the desktop thread.
  115. */
  116. if (ISCSRSS()) {
  117. /*
  118. * Windows bug: 452899
  119. * Since we are in CSRSS context use LpcRequestPort to send LPC_DATAGRAM message type,
  120. * Do not use LpcRequestWaitReplyPort because it will send LPC_REQUEST which will
  121. * fail (in server side).
  122. */
  123. RIPMSGF1(RIP_WARNING, "Desktop Thread for term=%p is being created within CSRSS context.", pTerm);
  124. Status = LpcRequestPort(CsrApiPort, (PPORT_MESSAGE)&m);
  125. } else {
  126. Status = LpcRequestWaitReplyPort(CsrApiPort, (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m);
  127. }
  128. if (!NT_SUCCESS(Status) || (!ISCSRSS() && !NT_SUCCESS(m.ReturnValue))) {
  129. EnterCrit();
  130. RIPMSGF1(RIP_WARNING, "Failed to create a desktop thread with 0x%x ... bailing out.", m.ReturnValue);
  131. ObDereferenceObject(pTerm->pEventInputReady);
  132. ObDereferenceObject(pEventTermInit);
  133. return STATUS_NO_MEMORY;
  134. }
  135. Wait:
  136. KeWaitForSingleObject(pEventTermInit,
  137. WrUserRequest,
  138. KernelMode,
  139. FALSE,
  140. NULL);
  141. EnterCrit();
  142. /*
  143. * dereference the terminal init event. It will eventually
  144. * go away.
  145. */
  146. ObDereferenceObject(pEventTermInit);
  147. pTerm->pEventTermInit = NULL;
  148. if (pTerm->dwTERMF_Flags & TERMF_DTINITFAILED) {
  149. return STATUS_NO_MEMORY;
  150. }
  151. pTerm->dwTERMF_Flags |= TERMF_INITIALIZED;
  152. return STATUS_SUCCESS;
  153. }
  154. static CONST LPCWSTR lpszStdFormats[] = {
  155. L"StdExit",
  156. L"StdNewDocument",
  157. L"StdOpenDocument",
  158. L"StdEditDocument",
  159. L"StdNewfromTemplate",
  160. L"StdCloseDocument",
  161. L"StdShowItem",
  162. L"StdDoVerbItem",
  163. L"System",
  164. L"OLEsystem",
  165. L"StdDocumentName",
  166. L"Protocols",
  167. L"Topics",
  168. L"Formats",
  169. L"Status",
  170. L"EditEnvItems",
  171. L"True",
  172. L"False",
  173. L"Change",
  174. L"Save",
  175. L"Close",
  176. L"MSDraw"
  177. };
  178. NTSTATUS CreateGlobalAtomTable(
  179. PVOID* ppAtomTable)
  180. {
  181. NTSTATUS Status;
  182. RTL_ATOM Atom;
  183. ULONG i;
  184. Status = RtlCreateAtomTable(0, ppAtomTable);
  185. if (!NT_SUCCESS(Status)) {
  186. RIPMSG0(RIP_WARNING, "Global atom table not created");
  187. return Status;
  188. }
  189. for (i = 0; i < ARRAY_SIZE(lpszStdFormats); i++) {
  190. Status = RtlAddAtomToAtomTable(*ppAtomTable,
  191. (PWSTR)lpszStdFormats[i],
  192. &Atom);
  193. if (!NT_SUCCESS(Status)) {
  194. RIPMSG1(RIP_WARNING,
  195. "RtlAddAtomToAtomTable failed to add atom %ws",
  196. lpszStdFormats[i]);
  197. RtlDestroyAtomTable(*ppAtomTable);
  198. return Status;
  199. }
  200. RtlPinAtomInAtomTable(*ppAtomTable, Atom);
  201. }
  202. return Status;
  203. }
  204. /***************************************************************************\
  205. * xxxCreateWindowStation
  206. *
  207. * Creates the specified windowstation and starts a logon thread for the
  208. * station.
  209. *
  210. * History:
  211. * 01-15-91 JimA Created.
  212. \***************************************************************************/
  213. HWINSTA xxxCreateWindowStation(
  214. POBJECT_ATTRIBUTES ObjectAttributes,
  215. KPROCESSOR_MODE OwnershipMode,
  216. DWORD dwDesiredAccess,
  217. HANDLE hKbdLayoutFile,
  218. DWORD offTable,
  219. PKBDTABLE_MULTI_INTERNAL pKbdTableMulti,
  220. PCWSTR pwszKLID,
  221. UINT uKbdInputLocale)
  222. {
  223. PWINDOWSTATION pwinsta;
  224. PTHREADINFO ptiCurrent;
  225. PDESKTOP pdeskTemp;
  226. HDESK hdeskTemp;
  227. PSECURITY_DESCRIPTOR psd;
  228. PSECURITY_DESCRIPTOR psdCapture;
  229. PPROCESSINFO ppiSave;
  230. NTSTATUS Status;
  231. PACCESS_ALLOWED_ACE paceList = NULL, pace;
  232. ULONG ulLength, ulLengthSid;
  233. HANDLE hEvent;
  234. HWINSTA hwinsta;
  235. DWORD dwDisableHooks;
  236. PTERMINAL pTerm = NULL;
  237. PWND pwnd;
  238. WCHAR szBaseNamedObjectDirectory[MAX_SESSION_PATH];
  239. BOOL bMDWCreated = FALSE;
  240. UserAssert(IsWinEventNotifyDeferredOK());
  241. /*
  242. * Get the pointer to the security descriptor so we can
  243. * assign it to the new object later.
  244. */
  245. psdCapture = ObjectAttributes->SecurityDescriptor;
  246. /*
  247. * The first windowstation that gets created is Winsta0 and
  248. * it's the only interactive one.
  249. */
  250. if (grpWinStaList == NULL) {
  251. /*
  252. * Assert that winlogon is the first to call CreateWindowStation
  253. */
  254. UserAssert(PsGetCurrentProcessId() == gpidLogon);
  255. pTerm = &gTermIO;
  256. } else {
  257. pTerm = &gTermNOIO;
  258. UserAssert(grpWinStaList->rpwinstaNext == NULL ||
  259. pTerm->dwTERMF_Flags & TERMF_NOIO);
  260. pTerm->dwTERMF_Flags |= TERMF_NOIO;
  261. }
  262. /*
  263. * Create the WindowStation object
  264. */
  265. Status = ObCreateObject(KernelMode, *ExWindowStationObjectType,
  266. ObjectAttributes, OwnershipMode, NULL, sizeof(WINDOWSTATION),
  267. 0, 0, &pwinsta);
  268. if (!NT_SUCCESS(Status)) {
  269. RIPNTERR0(Status, RIP_WARNING, "Failed to create windowstation");
  270. return NULL;
  271. }
  272. /*
  273. * WindowStation object was created then reference gWinstaRunRef.
  274. * We have to dereference it at FreeWindowStation().
  275. * And wait for any live objects to get freed in Win32KDriverUnload().
  276. */
  277. if (!ExAcquireRundownProtection(&gWinstaRunRef)) {
  278. goto create_error;
  279. }
  280. /*
  281. * Initialize everything.
  282. */
  283. RtlZeroMemory(pwinsta, sizeof(WINDOWSTATION));
  284. /*
  285. * Store the session id of the session who created the windowstation
  286. */
  287. pwinsta->dwSessionId = gSessionId;
  288. pwinsta->pTerm = pTerm;
  289. /*
  290. * All the windowstations in the system terminal are non-interactive.
  291. */
  292. if (pTerm->dwTERMF_Flags & TERMF_NOIO) {
  293. pwinsta->dwWSF_Flags = WSF_NOIO;
  294. }
  295. /*
  296. * Create the global atom table and populate it with the default OLE atoms
  297. * Pin each atom so they can't be deleted by bogus applications like Winword
  298. */
  299. Status = CreateGlobalAtomTable(&pwinsta->pGlobalAtomTable);
  300. if (!NT_SUCCESS(Status)) {
  301. UserAssert(pwinsta->pGlobalAtomTable == NULL);
  302. RIPNTERR0(Status, RIP_WARNING, "CreateGlobalAtomTable failed");
  303. goto create_error;
  304. }
  305. /*
  306. * create the desktop thread
  307. * and the RIT (only for the IO terminal)
  308. */
  309. if (!(pTerm->dwTERMF_Flags & TERMF_INITIALIZED)) {
  310. Status = xxxInitTerminal(pTerm);
  311. if (!NT_SUCCESS(Status)) {
  312. RIPNTERR0(Status, RIP_WARNING, "xxxInitTerminal failed");
  313. goto create_error;
  314. }
  315. }
  316. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  317. if (!xxxInitWindowStation()) {
  318. RIPNTERR0(STATUS_NO_MEMORY, RIP_WARNING, "xxxInitWindowStation failed");
  319. goto create_error;
  320. }
  321. }
  322. /*
  323. * Create only one desktop owner window per terminal.
  324. */
  325. if (pTerm->spwndDesktopOwner == NULL) {
  326. /*
  327. * Switch ppi values so window will be created using the
  328. * system's desktop window class.
  329. */
  330. ptiCurrent = PtiCurrent();
  331. ppiSave = ptiCurrent->ppi;
  332. ptiCurrent->ppi = pTerm->ptiDesktop->ppi;
  333. #ifndef LAZY_CLASS_INIT
  334. UserAssert(pTerm->ptiDesktop->ppi->W32PF_Flags & W32PF_CLASSESREGISTERED);
  335. #endif
  336. pdeskTemp = ptiCurrent->rpdesk; /* save current desktop */
  337. hdeskTemp = ptiCurrent->hdesk;
  338. if (pdeskTemp) {
  339. ObReferenceObject(pdeskTemp);
  340. LogDesktop(pdeskTemp, LD_REF_FN_CREATEWINDOWSTATION, TRUE, (ULONG_PTR)PtiCurrent());
  341. }
  342. /*
  343. * The following code is not supposed to leave the critical section because
  344. * CreateWindowStation is an API so the current thread can be on any state
  345. * setting its pdesk to NULL it's kind of bogus
  346. */
  347. DeferWinEventNotify();
  348. BEGINATOMICCHECK();
  349. if (zzzSetDesktop(ptiCurrent, NULL, NULL) == FALSE) {
  350. Status = STATUS_NO_MEMORY;
  351. EXITATOMICCHECK();
  352. zzzEndDeferWinEventNotify();
  353. /*
  354. * Restore caller's ppi
  355. */
  356. ptiCurrent->ppi = ppiSave;
  357. goto create_error;
  358. }
  359. /*
  360. * HACK HACK HACK!!! (adams) In order to create the desktop window
  361. * with the correct desktop, we set the desktop of the current thread
  362. * to the new desktop. But in so doing we allow hooks on the current
  363. * thread to also hook this new desktop. This is bad, because we don't
  364. * want the desktop window to be hooked while it is created. So we
  365. * temporarily disable hooks of the current thread and desktop, and
  366. * reenable them after switching back to the original desktop.
  367. */
  368. dwDisableHooks = ptiCurrent->TIF_flags & TIF_DISABLEHOOKS;
  369. ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
  370. /*
  371. * Create the desktop owner window
  372. *
  373. * CONSIDER (adams): Do we want to limit the desktop size so that the
  374. * width and height of a rect will fit in 16bit coordinates?
  375. *
  376. * SHRT_MIN / 2, SHRT_MIN / 2, SHRT_MAX, SHRT_MAX,
  377. *
  378. * Or do we want to limit it so just any point has 16bit coordinates?
  379. *
  380. * -SHRT_MIN, -SHRT_MIN, SHRT_MAX * 2, SHRT_MAX * 2
  381. */
  382. pwnd = xxxNVCreateWindowEx(0,
  383. (PLARGE_STRING)DESKTOPCLASS,
  384. NULL,
  385. WS_POPUP | WS_CLIPCHILDREN,
  386. SHRT_MIN / 2,
  387. SHRT_MIN / 2,
  388. SHRT_MAX,
  389. SHRT_MAX,
  390. NULL,
  391. NULL,
  392. hModuleWin,
  393. NULL,
  394. VER31);
  395. if (pwnd == NULL) {
  396. RIPMSGF0(RIP_WARNING, "Failed to create mother desktop window");
  397. Status = STATUS_NO_MEMORY;
  398. EXITATOMICCHECK();
  399. zzzEndDeferWinEventNotify();
  400. /*
  401. * Restore caller's ppi
  402. */
  403. ptiCurrent->ppi = ppiSave;
  404. /*
  405. * Restore the previous desktop
  406. */
  407. zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp);
  408. goto create_error;
  409. }
  410. /*
  411. * Mark this handle entry that is allocated out of pool
  412. */
  413. {
  414. PHE phe;
  415. UserAssert(ptiCurrent->rpdesk == NULL);
  416. phe = HMPheFromObject(pwnd);
  417. phe->bFlags |= HANDLEF_POOL;
  418. }
  419. Lock(&(pTerm->spwndDesktopOwner), pwnd);
  420. pTerm->dwTERMF_Flags |= TERMF_MOTHERWND_CREATED;
  421. UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
  422. ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks;
  423. SetVisible(pTerm->spwndDesktopOwner, SV_SET);
  424. HMChangeOwnerThread(pTerm->spwndDesktopOwner, pTerm->ptiDesktop);
  425. bMDWCreated = TRUE;
  426. /*
  427. * Restore caller's ppi
  428. */
  429. ptiCurrent->ppi = ppiSave;
  430. /*
  431. * Restore the previous desktop
  432. */
  433. if (zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp) == FALSE) {
  434. Status = STATUS_NO_MEMORY;
  435. EXITATOMICCHECK();
  436. zzzEndDeferWinEventNotify();
  437. goto create_error;
  438. }
  439. ENDATOMICCHECK();
  440. zzzEndDeferWinEventNotify();
  441. if (pdeskTemp) {
  442. LogDesktop(pdeskTemp, LD_DEREF_FN_CREATEWINDOWSTATION, FALSE, (ULONG_PTR)PtiCurrent());
  443. ObDereferenceObject(pdeskTemp);
  444. }
  445. }
  446. /*
  447. * If this is the visible windowstation, assign it to
  448. * the server and create the desktop switch notification
  449. * event.
  450. */
  451. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  452. UNICODE_STRING strName;
  453. HANDLE hRootDir;
  454. OBJECT_ATTRIBUTES obja;
  455. /*
  456. * Create desktop switch notification event.
  457. */
  458. ulLengthSid = RtlLengthSid(SeExports->SeWorldSid);
  459. ulLength = ulLengthSid + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK);
  460. /*
  461. * Allocate the ACE list
  462. */
  463. paceList = (PACCESS_ALLOWED_ACE)UserAllocPoolWithQuota(ulLength, TAG_SECURITY);
  464. if (paceList == NULL) {
  465. Status = STATUS_NO_MEMORY;
  466. goto create_error;
  467. }
  468. /*
  469. * Initialize ACE 0
  470. */
  471. pace = paceList;
  472. pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  473. pace->Header.AceSize = (USHORT)ulLength;
  474. pace->Header.AceFlags = 0;
  475. pace->Mask = SYNCHRONIZE;
  476. RtlCopySid(ulLengthSid, &pace->SidStart, SeExports->SeWorldSid);
  477. /*
  478. * Create the SD
  479. */
  480. psd = CreateSecurityDescriptor(paceList, ulLength, FALSE);
  481. UserFreePool(paceList);
  482. if (psd == NULL) {
  483. Status = STATUS_NO_MEMORY;
  484. goto create_error;
  485. }
  486. /*
  487. * Create the named event.
  488. */
  489. UserAssert(ghEventSwitchDesktop == NULL);
  490. if (gbRemoteSession) {
  491. swprintf(szBaseNamedObjectDirectory, L"\\Sessions\\%ld\\BaseNamedObjects",
  492. gSessionId);
  493. RtlInitUnicodeString(&strName, szBaseNamedObjectDirectory);
  494. } else {
  495. RtlInitUnicodeString(&strName, L"\\BaseNamedObjects");
  496. }
  497. InitializeObjectAttributes(&obja,
  498. &strName,
  499. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  500. NULL,
  501. NULL);
  502. Status = ZwOpenDirectoryObject(&hRootDir,
  503. DIRECTORY_ALL_ACCESS &
  504. ~(DELETE | WRITE_DAC | WRITE_OWNER),
  505. &obja);
  506. if (NT_SUCCESS(Status)) {
  507. RtlInitUnicodeString(&strName, L"WinSta0_DesktopSwitch");
  508. InitializeObjectAttributes(&obja,
  509. &strName,
  510. OBJ_OPENIF | OBJ_KERNEL_HANDLE,
  511. hRootDir,
  512. psd);
  513. Status = ZwCreateEvent(&hEvent, EVENT_ALL_ACCESS, &obja,
  514. NotificationEvent, FALSE);
  515. ZwClose(hRootDir);
  516. if (NT_SUCCESS(Status)) {
  517. Status = ObReferenceObjectByHandle(hEvent, EVENT_ALL_ACCESS, *ExEventObjectType,
  518. KernelMode, &gpEventSwitchDesktop, NULL);
  519. if (NT_SUCCESS(Status)) {
  520. /*
  521. * Attach to the system process and create a handle to the
  522. * object. This will ensure that the object name is retained
  523. * when hEvent is closed. This is simpler than creating a
  524. * permanent object, which takes the
  525. * SeCreatePermanentPrivilege.
  526. */
  527. KeAttachProcess(PsGetProcessPcb(gpepCSRSS));
  528. Status = ObOpenObjectByPointer(
  529. gpEventSwitchDesktop,
  530. 0,
  531. NULL,
  532. EVENT_ALL_ACCESS,
  533. NULL,
  534. KernelMode,
  535. &ghEventSwitchDesktop);
  536. KeDetachProcess();
  537. }
  538. ZwClose(hEvent);
  539. }
  540. }
  541. if (!NT_SUCCESS(Status)) {
  542. goto create_error;
  543. }
  544. UserFreePool(psd);
  545. }
  546. /*
  547. * Create a handle to the windowstation.
  548. */
  549. Status = ObInsertObject(pwinsta, NULL, dwDesiredAccess, 1,
  550. &pwinsta, &hwinsta);
  551. if (Status == STATUS_OBJECT_NAME_EXISTS) {
  552. /*
  553. * The windowstation already exists, so deref and leave.
  554. */
  555. ObDereferenceObject(pwinsta);
  556. } else if (NT_SUCCESS(Status)) {
  557. PSECURITY_DESCRIPTOR psdParent = NULL, psdNew;
  558. SECURITY_SUBJECT_CONTEXT Context;
  559. POBJECT_DIRECTORY pParentDirectory;
  560. SECURITY_INFORMATION siNew;
  561. BOOLEAN MemoryAllocated = FALSE;
  562. /*
  563. * Create security descriptor for the windowstation.
  564. * ObInsertObject only supports non-container
  565. * objects, so we must assign our own security descriptor.
  566. */
  567. SeCaptureSubjectContext(&Context);
  568. SeLockSubjectContext(&Context);
  569. pParentDirectory = OBJECT_HEADER_TO_NAME_INFO(
  570. OBJECT_TO_OBJECT_HEADER(pwinsta))->Directory;
  571. if (pParentDirectory != NULL) {
  572. Status = ObGetObjectSecurity(
  573. pParentDirectory,
  574. &psdParent,
  575. &MemoryAllocated);
  576. if ( !NT_SUCCESS(Status) ) {
  577. goto create_error;
  578. }
  579. }
  580. Status = SeAssignSecurity(
  581. psdParent,
  582. psdCapture,
  583. &psdNew,
  584. TRUE,
  585. &Context,
  586. (PGENERIC_MAPPING)&WinStaMapping,
  587. PagedPool);
  588. ObReleaseObjectSecurity(psdParent, MemoryAllocated);
  589. SeUnlockSubjectContext(&Context);
  590. SeReleaseSubjectContext(&Context);
  591. if (!NT_SUCCESS(Status)) {
  592. if (Status == STATUS_ACCESS_DENIED) {
  593. RIPNTERR0(Status,
  594. RIP_WARNING,
  595. "Access denied during object creation");
  596. } else {
  597. RIPNTERR1(Status,
  598. RIP_ERROR,
  599. "Can't create security descriptor! Status = 0x%x",
  600. Status);
  601. }
  602. } else {
  603. /*
  604. * Call the security method to copy the security descriptor
  605. */
  606. siNew = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  607. DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION);
  608. Status = ObSetSecurityDescriptorInfo(
  609. pwinsta,
  610. &siNew,
  611. psdNew,
  612. &OBJECT_TO_OBJECT_HEADER(pwinsta)->SecurityDescriptor,
  613. PagedPool,
  614. (PGENERIC_MAPPING)&WinStaMapping);
  615. SeDeassignSecurity(&psdNew);
  616. if (NT_SUCCESS(Status)) {
  617. PWINDOWSTATION *ppwinsta;
  618. /*
  619. * Put it on the tail of the global windowstation list
  620. */
  621. ppwinsta = &grpWinStaList;
  622. while (*ppwinsta != NULL)
  623. ppwinsta = &(*ppwinsta)->rpwinstaNext;
  624. LockWinSta(ppwinsta, pwinsta);
  625. /*
  626. * For interactive window stations load the keyboard
  627. * layout.
  628. */
  629. if ((pwinsta->dwWSF_Flags & WSF_NOIO) == 0 && pwszKLID != NULL) {
  630. TL tlpwinsta;
  631. PushW32ThreadLock(pwinsta, &tlpwinsta, UserDereferenceObject);
  632. if (xxxLoadKeyboardLayoutEx(
  633. pwinsta,
  634. hKbdLayoutFile,
  635. (HKL)NULL,
  636. offTable,
  637. pKbdTableMulti,
  638. pwszKLID,
  639. uKbdInputLocale,
  640. KLF_ACTIVATE | KLF_INITTIME) == NULL) {
  641. Status = STATUS_UNSUCCESSFUL;
  642. }
  643. PopW32ThreadLock(&tlpwinsta);
  644. }
  645. }
  646. }
  647. ObDereferenceObject(pwinsta);
  648. }
  649. if (!NT_SUCCESS(Status)) {
  650. RIPNTERR1(Status,
  651. RIP_WARNING,
  652. "CreateWindowStation: Failed with Status 0x%x",
  653. Status);
  654. return NULL;
  655. }
  656. return hwinsta;
  657. /*
  658. * Goto here if an error occurs so things can be cleaned up.
  659. */
  660. create_error:
  661. RIPNTERR1(Status,
  662. RIP_WARNING,
  663. "CreateWindowStation: Failed with Status 0x%x",
  664. Status);
  665. ObDereferenceObject(pwinsta);
  666. if (bMDWCreated) {
  667. /*
  668. * Switch ppi values so that HMChangeOwnerThread() can find system's
  669. * desktop window class.
  670. */
  671. ppiSave = ptiCurrent->ppi;
  672. ptiCurrent->ppi = pTerm->ptiDesktop->ppi;
  673. HMChangeOwnerThread(pTerm->spwndDesktopOwner, ptiCurrent);
  674. xxxCleanupMotherDesktopWindow(pTerm);
  675. /*
  676. * Restore caller's ppi
  677. */
  678. ptiCurrent->ppi = ppiSave;
  679. }
  680. return NULL;
  681. }
  682. __inline VOID MarkKLUnloaded(
  683. PKL pkl)
  684. {
  685. HMMarkObjectDestroy(pkl);
  686. pkl->dwKL_Flags |= KL_UNLOADED;
  687. }
  688. /***************************************************************************\
  689. * FreeWindowStation
  690. *
  691. * Called when last lock to the windowstation is removed. Frees all resources
  692. * owned by the windowstation.
  693. *
  694. * History:
  695. * 12-22-93 JimA Created.
  696. \***************************************************************************/
  697. NTSTATUS FreeWindowStation(
  698. PKWIN32_DELETEMETHOD_PARAMETERS pDeleteParams)
  699. {
  700. PWINDOWSTATION pwinsta = pDeleteParams->Object;
  701. UserAssert(OBJECT_TO_OBJECT_HEADER(pwinsta)->Type == *ExWindowStationObjectType);
  702. /*
  703. * Mark the windowstation as dying. Make sure we're not recursing.
  704. */
  705. UserAssert(!(pwinsta->dwWSF_Flags & WSF_DYING));
  706. pwinsta->dwWSF_Flags |= WSF_DYING;
  707. UserAssert(pwinsta->rpdeskList == NULL);
  708. /*
  709. * Free up the other resources.
  710. */
  711. if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && gpEventSwitchDesktop != NULL) {
  712. KeSetEvent(gpEventSwitchDesktop, EVENT_INCREMENT, FALSE);
  713. ObDereferenceObject(gpEventSwitchDesktop);
  714. gpEventSwitchDesktop = NULL;
  715. }
  716. BEGIN_REENTERCRIT();
  717. RtlDestroyAtomTable(pwinsta->pGlobalAtomTable);
  718. ForceEmptyClipboard(pwinsta);
  719. /*
  720. * Free up keyboard layouts.
  721. */
  722. if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && pwinsta->spklList != NULL) {
  723. #if DBG
  724. int iter = 0;
  725. #endif
  726. PKL pklLast = pwinsta->spklList->pklPrev;
  727. RIPMSG2(RIP_WARNING, "FreeWindowStation: pwinsta(%p)->spklList is not NULL, %p", pwinsta, pwinsta->spklList);
  728. while (pwinsta->spklList != pklLast) {
  729. PKL pklNext = pwinsta->spklList->pklNext;
  730. #if DBG
  731. ++iter;
  732. UserAssert(iter < 1000);
  733. #endif
  734. MarkKLUnloaded(pwinsta->spklList);
  735. Lock(&pwinsta->spklList, pklNext);
  736. }
  737. MarkKLUnloaded(pwinsta->spklList);
  738. Unlock(&pwinsta->spklList);
  739. HYDRA_HINT(HH_KBDLYOUTFREEWINSTA);
  740. /*
  741. * make sure the logon notify window went away
  742. */
  743. UserAssert(gspwndLogonNotify == NULL);
  744. } else {
  745. UserAssert(pwinsta->spklList == NULL);
  746. }
  747. /*
  748. * Free the USER sid.
  749. */
  750. if (pwinsta->psidUser != NULL) {
  751. UserFreePool(pwinsta->psidUser);
  752. pwinsta->psidUser = NULL;
  753. }
  754. /*
  755. * Dereference gWinstaRunRef, because it was referenced at WindowStation
  756. * creation time in xxxCreateWindowStation().
  757. */
  758. ExReleaseRundownProtection(&gWinstaRunRef);
  759. END_REENTERCRIT();
  760. return STATUS_SUCCESS;
  761. }
  762. /***************************************************************************\
  763. * DestroyWindowStation
  764. *
  765. * Removes the windowstation from the global list. We can't release any
  766. * resources until all locks have been removed.
  767. *
  768. * History:
  769. * 01-17-91 JimA Created.
  770. \***************************************************************************/
  771. NTSTATUS DestroyWindowStation(
  772. PKWIN32_CLOSEMETHOD_PARAMETERS pCloseParams)
  773. {
  774. PWINDOWSTATION pwinsta = pCloseParams->Object;
  775. PWINDOWSTATION *ppwinsta;
  776. PDESKTOP pdesk;
  777. PDESKTOP pdeskLock = NULL;
  778. UserAssert(OBJECT_TO_OBJECT_HEADER(pCloseParams->Object)->Type == *ExWindowStationObjectType);
  779. /*
  780. * If this is not the last handle, leave.
  781. */
  782. if (pCloseParams->SystemHandleCount != 1) {
  783. return STATUS_SUCCESS;
  784. }
  785. BEGIN_REENTERCRIT();
  786. /*
  787. * If the window station was linked into the terminal's list, go ahead
  788. * and unlink it.
  789. */
  790. for (ppwinsta = &grpWinStaList;
  791. *ppwinsta != NULL && pwinsta != *ppwinsta;
  792. ppwinsta = &(*ppwinsta)->rpwinstaNext) {
  793. /* do nothing */;
  794. }
  795. if (*ppwinsta != NULL) {
  796. UnlockWinSta(ppwinsta);
  797. /*
  798. * Assert that unlocking it didn't destroy it.
  799. */
  800. UserAssert(OBJECT_TO_OBJECT_HEADER(pCloseParams->Object)->Type == *ExWindowStationObjectType);
  801. *ppwinsta = pwinsta->rpwinstaNext;
  802. /*
  803. * The instruction above transfered rpwinstaNext lock ownership to
  804. * the previous element in the list. Hence the value in pwinsta can
  805. * no longer be considered valid.
  806. */
  807. pwinsta->rpwinstaNext = NULL;
  808. }
  809. /*
  810. * Notify all console threads and wait for them to terminate.
  811. */
  812. pdesk = pwinsta->rpdeskList;
  813. while (pdesk != NULL) {
  814. if (pdesk != grpdeskLogon && pdesk->dwConsoleThreadId) {
  815. LockDesktop(&pdeskLock, pdesk, LDL_FN_DESTROYWINDOWSTATION, 0);
  816. TerminateConsole(pdesk);
  817. /*
  818. * Restart scan in case desktop list has changed.
  819. */
  820. pdesk = pwinsta->rpdeskList;
  821. UnlockDesktop(&pdeskLock, LDU_FN_DESTROYWINDOWSTATION, 0);
  822. } else {
  823. pdesk = pdesk->rpdeskNext;
  824. }
  825. }
  826. END_REENTERCRIT();
  827. return STATUS_SUCCESS;
  828. }
  829. /***************************************************************************\
  830. * WindowStationOpenProcedure
  831. *
  832. * History:
  833. * 06-11-01 GerardoB Created for instrumentation/debugging purposes.
  834. * 02-26-02 Msadek Change it to deny any open with granted special
  835. * rights cross session.
  836. \***************************************************************************/
  837. NTSTATUS WindowStationOpenProcedure(
  838. PKWIN32_OPENMETHOD_PARAMETERS pOpenParams)
  839. {
  840. /*
  841. * Allow windowstation open cross session only if no special rights
  842. * granted.
  843. */
  844. if (pOpenParams->GrantedAccess & SPECIFIC_RIGHTS_ALL) {
  845. if (PsGetProcessSessionId(pOpenParams->Process) !=
  846. ((PWINDOWSTATION)pOpenParams->Object)->dwSessionId) {
  847. return STATUS_ACCESS_DENIED;
  848. }
  849. }
  850. return STATUS_SUCCESS;
  851. }
  852. /***************************************************************************\
  853. * ParseWindowStation
  854. *
  855. * Parse a windowstation path.
  856. *
  857. * History:
  858. * 06-14-95 JimA Created.
  859. \***************************************************************************/
  860. NTSTATUS ParseWindowStation(
  861. PKWIN32_PARSEMETHOD_PARAMETERS pParseParams)
  862. {
  863. PWINDOWSTATION pwinsta = pParseParams->ParseObject;
  864. UserAssert(OBJECT_TO_OBJECT_HEADER(pParseParams->ParseObject)->Type == *ExWindowStationObjectType);
  865. /*
  866. * If nothing remains to be parsed, return the windowstation.
  867. */
  868. *(pParseParams->Object) = NULL;
  869. if (pParseParams->RemainingName->Length == 0) {
  870. if (pParseParams->ObjectType != *ExWindowStationObjectType) {
  871. return STATUS_OBJECT_TYPE_MISMATCH;
  872. }
  873. ObReferenceObject(pwinsta);
  874. *(pParseParams->Object) = pwinsta;
  875. return STATUS_SUCCESS;
  876. }
  877. /*
  878. * Skip leading path separator, if present.
  879. */
  880. if (*(pParseParams->RemainingName->Buffer) == OBJ_NAME_PATH_SEPARATOR) {
  881. pParseParams->RemainingName->Buffer++;
  882. pParseParams->RemainingName->Length -= sizeof(WCHAR);
  883. pParseParams->RemainingName->MaximumLength -= sizeof(WCHAR);
  884. }
  885. /*
  886. * Validate the desktop name.
  887. */
  888. if (wcschr(pParseParams->RemainingName->Buffer, L'\\')) {
  889. return STATUS_OBJECT_PATH_INVALID;
  890. }
  891. if (pParseParams->ObjectType == *ExDesktopObjectType) {
  892. return ParseDesktop(pParseParams->ParseObject,
  893. pParseParams->ObjectType,
  894. pParseParams->AccessState,
  895. pParseParams->AccessMode,
  896. pParseParams->Attributes,
  897. pParseParams->CompleteName,
  898. pParseParams->RemainingName,
  899. pParseParams->Context,
  900. pParseParams->SecurityQos,
  901. pParseParams->Object);
  902. }
  903. return STATUS_OBJECT_TYPE_MISMATCH;
  904. }
  905. /***************************************************************************\
  906. * OkayToCloseWindowStation
  907. *
  908. * We can only close windowstation handles if they're not in use.
  909. *
  910. * History:
  911. * 08-Feb-1999 JerrySh Created.
  912. \***************************************************************************/
  913. NTSTATUS OkayToCloseWindowStation(
  914. PKWIN32_OKAYTOCLOSEMETHOD_PARAMETERS pOkCloseParams)
  915. {
  916. PWINDOWSTATION pwinsta = (PWINDOWSTATION)pOkCloseParams->Object;
  917. UserAssert(OBJECT_TO_OBJECT_HEADER(pOkCloseParams->Object)->Type == *ExWindowStationObjectType);
  918. /*
  919. * Kernel mode code can close anything.
  920. */
  921. if (pOkCloseParams->PreviousMode == KernelMode) {
  922. return STATUS_SUCCESS;
  923. /*
  924. * Do not allow a user mode process to close a kernel handle of ours.
  925. * It shouldn't. In addition, if this happens cross-session, we will try to
  926. * attach to the system processes and will bugcheck since the seesion
  927. * address space is not mapped into it. Same for the session manager
  928. * process. See bug# 759533.
  929. */
  930. } else if (PsGetProcessSessionIdEx(pOkCloseParams->Process) == -1) {
  931. return STATUS_ACCESS_DENIED;
  932. }
  933. /*
  934. * We can't close a windowstation that's being used.
  935. */
  936. if (CheckHandleInUse(pOkCloseParams->Handle) ||
  937. CheckHandleFlag(pOkCloseParams->Process, pwinsta->dwSessionId, pOkCloseParams->Handle, HF_PROTECTED)) {
  938. RIPMSG1(RIP_WARNING,
  939. "Trying to close windowstation 0x%p while still in use",
  940. pwinsta);
  941. return STATUS_UNSUCCESSFUL;
  942. }
  943. return STATUS_SUCCESS;
  944. }
  945. /***************************************************************************\
  946. * _OpenWindowStation
  947. *
  948. * Opens the specified windowstation.
  949. *
  950. * History:
  951. * 03-19-1991 JimA Created.
  952. \***************************************************************************/
  953. HWINSTA _OpenWindowStation(
  954. POBJECT_ATTRIBUTES pObjA,
  955. DWORD dwDesiredAccess,
  956. KPROCESSOR_MODE AccessMode)
  957. {
  958. HWINSTA hwinsta;
  959. NTSTATUS Status;
  960. /*
  961. * Obja is client-side. Ob interfaces protect and capture as
  962. * appropriate.
  963. */
  964. Status = ObOpenObjectByName(pObjA,
  965. *ExWindowStationObjectType,
  966. AccessMode,
  967. NULL,
  968. dwDesiredAccess,
  969. NULL,
  970. &hwinsta);
  971. if (!NT_SUCCESS(Status)) {
  972. try {
  973. RIPNTERR3(Status,
  974. RIP_VERBOSE,
  975. "Opening of winsta %.*ws failed with Status 0x%x",
  976. pObjA->ObjectName->Length,
  977. pObjA->ObjectName->Buffer,
  978. Status);
  979. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  980. }
  981. hwinsta = NULL;
  982. }
  983. return hwinsta;
  984. }
  985. /***************************************************************************\
  986. * _CloseWindowStation (API)
  987. *
  988. * Closes a windowstation for the calling process
  989. *
  990. * History:
  991. * 15-Jun-1999 JerrySh Created.
  992. \***************************************************************************/
  993. BOOL _CloseWindowStation(
  994. HWINSTA hwinsta)
  995. {
  996. HWINSTA hwinstaCurrent;
  997. _GetProcessWindowStation(&hwinstaCurrent);
  998. if (hwinsta != hwinstaCurrent) {
  999. return NT_SUCCESS(ZwClose(hwinsta));
  1000. }
  1001. return FALSE;
  1002. }
  1003. /***************************************************************************\
  1004. * _SetProcessWindowStation (API)
  1005. *
  1006. * Sets the windowstation of the calling process to the windowstation
  1007. * specified by pwinsta.
  1008. *
  1009. * History:
  1010. * 01-14-91 JimA Created.
  1011. \***************************************************************************/
  1012. NTSTATUS _SetProcessWindowStation(
  1013. HWINSTA hwinsta,
  1014. KPROCESSOR_MODE AccessMode)
  1015. {
  1016. PETHREAD Thread = PsGetCurrentThread();
  1017. PEPROCESS Process = PsGetCurrentProcess();
  1018. HWINSTA hwinstaDup, hwinstaProcess;
  1019. NTSTATUS Status;
  1020. PPROCESSINFO ppi;
  1021. PWINDOWSTATION pwinsta, pwinstaOld;
  1022. OBJECT_HANDLE_INFORMATION ohi;
  1023. Status = ObReferenceObjectByHandle(hwinsta,
  1024. 0,
  1025. *ExWindowStationObjectType,
  1026. AccessMode,
  1027. &pwinsta,
  1028. &ohi);
  1029. if (!NT_SUCCESS(Status)) {
  1030. RIPNTERR1(Status,
  1031. RIP_WARNING,
  1032. "Failed to reference windowstation with Status = 0x%x",
  1033. Status);
  1034. return Status;
  1035. }
  1036. if (pwinsta->dwSessionId != gSessionId) {
  1037. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Cannot assign a window station of a different session");
  1038. ObDereferenceObject(pwinsta);
  1039. return STATUS_INVALID_PARAMETER;
  1040. }
  1041. /*
  1042. * We need to lock the winsta handle so that an app cannot free it by
  1043. * calling GetProcessWindowStation() & CloseHandle().
  1044. */
  1045. /*
  1046. * Unprotect the old hwinsta.
  1047. */
  1048. ppi = PpiFromProcess(PsGetThreadProcess(Thread));
  1049. if (ppi->hwinsta) {
  1050. SetHandleFlag(ppi->hwinsta, HF_PROTECTED, FALSE);
  1051. }
  1052. /*
  1053. * Save the WindowStation information.
  1054. */
  1055. LockWinSta(&ppi->rpwinsta, pwinsta);
  1056. ObDereferenceObject(pwinsta);
  1057. ppi->hwinsta = hwinsta;
  1058. /*
  1059. * Protect the new Window Station Handle
  1060. */
  1061. SetHandleFlag(ppi->hwinsta, HF_PROTECTED, TRUE);
  1062. /*
  1063. * Check the old Atom Manager WindowStation to see if we are
  1064. * changing this process' WindowStation.
  1065. */
  1066. hwinstaProcess = PsGetProcessWin32WindowStation(Process);
  1067. if (hwinstaProcess != NULL) {
  1068. /*
  1069. * Get a pointer to the old WindowStation object to see if it's
  1070. * the same WindowStation that we are setting.
  1071. */
  1072. Status = ObReferenceObjectByHandle(hwinstaProcess,
  1073. 0,
  1074. *ExWindowStationObjectType,
  1075. AccessMode,
  1076. &pwinstaOld,
  1077. NULL);
  1078. if (NT_SUCCESS(Status)) {
  1079. /*
  1080. * Are they different WindowStations? If so, NULL out the
  1081. * atom manager cache so we will reset it below.
  1082. */
  1083. if (pwinsta != pwinstaOld) {
  1084. ZwClose(hwinstaProcess);
  1085. PsSetProcessWindowStation(Process, NULL);
  1086. }
  1087. ObDereferenceObject(pwinstaOld);
  1088. } else {
  1089. /*
  1090. * Their Atom Manager handle is bad? Give them a new one.
  1091. */
  1092. PsSetProcessWindowStation(Process, NULL);
  1093. RIPMSGF2(RIP_WARNING,
  1094. "Couldn't reference old WindowStation (0x%x) Status=0x%x",
  1095. hwinstaProcess,
  1096. Status);
  1097. }
  1098. }
  1099. /*
  1100. * Duplicate the WindowStation handle and stash it in the atom manager's
  1101. * cache (Process->Win32WindowStation).
  1102. */
  1103. hwinstaProcess = PsGetProcessWin32WindowStation(Process);
  1104. if (hwinstaProcess == NULL) {
  1105. Status = ZwDuplicateObject(NtCurrentProcess(),
  1106. hwinsta,
  1107. NtCurrentProcess(),
  1108. &hwinstaDup,
  1109. 0,
  1110. 0,
  1111. DUPLICATE_SAME_ACCESS);
  1112. if (NT_SUCCESS(Status)) {
  1113. PsSetProcessWindowStation(Process, hwinstaDup);
  1114. } else {
  1115. RIPMSGF2(RIP_WARNING,
  1116. "Couldn't dup WindowStation handle (0x%x) Status 0x%x",
  1117. hwinsta,
  1118. Status);
  1119. }
  1120. }
  1121. ppi->amwinsta = ohi.GrantedAccess;
  1122. if (pwinsta->dwWSF_Flags & WSF_NOIO) {
  1123. ppi->W32PF_Flags &= ~W32PF_IOWINSTA;
  1124. } else {
  1125. ppi->W32PF_Flags |= W32PF_IOWINSTA;
  1126. }
  1127. /*
  1128. * Do the access check now for readscreen so that blts off of the
  1129. * display will be as fast as possible.
  1130. */
  1131. if (RtlAreAllAccessesGranted(ohi.GrantedAccess, WINSTA_READSCREEN)) {
  1132. ppi->W32PF_Flags |= W32PF_READSCREENACCESSGRANTED;
  1133. } else {
  1134. ppi->W32PF_Flags &= ~W32PF_READSCREENACCESSGRANTED;
  1135. }
  1136. return STATUS_SUCCESS;
  1137. }
  1138. /***************************************************************************\
  1139. * _GetProcessWindowStation (API)
  1140. *
  1141. * Returns a pointer to the windowstation of the calling process.
  1142. *
  1143. * History:
  1144. * 01-14-91 JimA Created.
  1145. \***************************************************************************/
  1146. PWINDOWSTATION _GetProcessWindowStation(
  1147. HWINSTA *phwinsta)
  1148. {
  1149. PPROCESSINFO ppi = PpiCurrent();
  1150. if (phwinsta) {
  1151. *phwinsta = ppi->hwinsta;
  1152. }
  1153. return ppi->rpwinsta;
  1154. }
  1155. /***************************************************************************\
  1156. * _BuildNameList
  1157. *
  1158. * Builds a list of windowstation or desktop names.
  1159. *
  1160. * History:
  1161. * 05-17-94 JimA Created.
  1162. * 10-21-96 CLupu Added TERMINAL enumeration
  1163. \***************************************************************************/
  1164. NTSTATUS _BuildNameList(
  1165. PWINDOWSTATION pwinsta,
  1166. PNAMELIST ccxpNameList,
  1167. UINT cbNameList,
  1168. PUINT pcbNeeded)
  1169. {
  1170. PBYTE pobj;
  1171. PWCHAR ccxpwchDest, ccxpwchMax;
  1172. ACCESS_MASK amDesired;
  1173. POBJECT_HEADER pHead;
  1174. POBJECT_HEADER_NAME_INFO pNameInfo;
  1175. DWORD iNext;
  1176. NTSTATUS Status;
  1177. CONST GENERIC_MAPPING *pGenericMapping;
  1178. try {
  1179. ccxpNameList->cNames = 0;
  1180. ccxpwchDest = ccxpNameList->awchNames;
  1181. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1182. return STATUS_ACCESS_VIOLATION;
  1183. }
  1184. ccxpwchMax = (PWCHAR)((PBYTE)ccxpNameList + cbNameList - sizeof(WCHAR));
  1185. /*
  1186. * If we're enumerating windowstations, pwinsta is NULL. Otherwise,
  1187. * we're enumerating desktops.
  1188. */
  1189. if (pwinsta == NULL) {
  1190. pobj = (PBYTE)grpWinStaList;
  1191. amDesired = WINSTA_ENUMERATE;
  1192. pGenericMapping = &WinStaMapping;
  1193. iNext = FIELD_OFFSET(WINDOWSTATION, rpwinstaNext);
  1194. } else {
  1195. pobj = (PBYTE)pwinsta->rpdeskList;
  1196. amDesired = DESKTOP_ENUMERATE;
  1197. pGenericMapping = &DesktopMapping;
  1198. iNext = FIELD_OFFSET(DESKTOP, rpdeskNext);
  1199. }
  1200. Status = STATUS_SUCCESS;
  1201. *pcbNeeded = 0;
  1202. while (pobj != NULL) {
  1203. if (AccessCheckObject(pobj, amDesired, UserMode, pGenericMapping)) {
  1204. /*
  1205. * Find object name.
  1206. */
  1207. pHead = OBJECT_TO_OBJECT_HEADER(pobj);
  1208. pNameInfo = OBJECT_HEADER_TO_NAME_INFO(pHead);
  1209. if (pNameInfo == NULL) {
  1210. goto NEXT_ITERATION;
  1211. }
  1212. /*
  1213. * If we run out of space, reset the buffer and continue so we
  1214. * can compute the needed space.
  1215. */
  1216. if ((PWCHAR)((PBYTE)ccxpwchDest + pNameInfo->Name.Length +
  1217. sizeof(WCHAR)) >= ccxpwchMax) {
  1218. *pcbNeeded += (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList);
  1219. try {
  1220. ccxpwchDest = ccxpNameList->awchNames;
  1221. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1222. return STATUS_ACCESS_VIOLATION;
  1223. }
  1224. Status = STATUS_BUFFER_TOO_SMALL;
  1225. }
  1226. try {
  1227. /*
  1228. * If the entire buffer is sufficient for the new string,
  1229. * the copy operation is performed, otherwise the size of
  1230. * this new string is noted and the copy is skipped.
  1231. */
  1232. ccxpNameList->cNames++;
  1233. if ((PWCHAR)((PBYTE)ccxpwchDest + pNameInfo->Name.Length +
  1234. sizeof(WCHAR)) <= ccxpwchMax) {
  1235. /*
  1236. * Copy and terminate the string
  1237. */
  1238. RtlCopyMemory(ccxpwchDest, pNameInfo->Name.Buffer, pNameInfo->Name.Length);
  1239. (PBYTE)ccxpwchDest += pNameInfo->Name.Length;
  1240. UserAssert(ccxpwchDest <= (ccxpwchMax - sizeof(WCHAR)));
  1241. *ccxpwchDest++ = 0;
  1242. }
  1243. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1244. return STATUS_ACCESS_VIOLATION;
  1245. }
  1246. }
  1247. NEXT_ITERATION:
  1248. pobj = *(PBYTE*)(pobj + iNext);
  1249. }
  1250. /*
  1251. * Put an empty string on the end.
  1252. */
  1253. try {
  1254. UserAssert(ccxpwchDest <= (PWCHAR)((PBYTE)ccxpNameList + cbNameList - sizeof(WCHAR)));
  1255. *ccxpwchDest++ = 0;
  1256. ccxpNameList->cb = (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList);
  1257. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1258. return STATUS_ACCESS_VIOLATION;
  1259. }
  1260. *pcbNeeded += (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList);
  1261. return Status;
  1262. }
  1263. NTSTATUS ReferenceWindowStation(
  1264. PETHREAD Thread,
  1265. HWINSTA hwinsta,
  1266. ACCESS_MASK amDesiredAccess,
  1267. PWINDOWSTATION *ppwinsta,
  1268. BOOL fUseDesktop)
  1269. {
  1270. PPROCESSINFO ppi;
  1271. PTHREADINFO pti;
  1272. PWINDOWSTATION pwinsta = NULL;
  1273. NTSTATUS Status;
  1274. /*
  1275. * We prefer to use the thread's desktop to dictate which windowstation to
  1276. * use rather than the process. This allows NetDDE, which has threads
  1277. * running under different desktops on different windowstations but whose
  1278. * process is set to only one of these windowstations, to get global atoms
  1279. * properly without having to change its process windowstation a billion
  1280. * times and synchronize.
  1281. */
  1282. ppi = PpiFromProcess(PsGetThreadProcess(Thread));
  1283. pti = PtiFromThread(Thread);
  1284. /*
  1285. * First, try to get the windowstation from the pti, and then from the
  1286. * ppi.
  1287. */
  1288. if (ppi != NULL) {
  1289. if (!fUseDesktop || pti == NULL || pti->rpdesk == NULL ||
  1290. ppi->rpwinsta == pti->rpdesk->rpwinstaParent) {
  1291. /*
  1292. * Use the windowstation assigned to the process.
  1293. */
  1294. pwinsta = ppi->rpwinsta;
  1295. if (pwinsta != NULL) {
  1296. RETURN_IF_ACCESS_DENIED(ppi->amwinsta, amDesiredAccess,
  1297. STATUS_ACCESS_DENIED);
  1298. }
  1299. }
  1300. /*
  1301. * If we aren't using the process' windowstation, try to go through
  1302. * the thread's desktop.
  1303. */
  1304. if (pwinsta == NULL && pti != NULL && pti->rpdesk != NULL) {
  1305. /*
  1306. * Perform access check the parent windowstation. This
  1307. * is an expensive operation.
  1308. */
  1309. pwinsta = pti->rpdesk->rpwinstaParent;
  1310. if (!AccessCheckObject(pwinsta, amDesiredAccess, KernelMode, &WinStaMapping))
  1311. return STATUS_ACCESS_DENIED;
  1312. }
  1313. }
  1314. /*
  1315. * If we still don't have a windowstation and a handle was passed in, use
  1316. * it.
  1317. */
  1318. if (pwinsta == NULL) {
  1319. if (hwinsta != NULL) {
  1320. Status = ObReferenceObjectByHandle(hwinsta,
  1321. amDesiredAccess,
  1322. *ExWindowStationObjectType,
  1323. KernelMode,
  1324. &pwinsta,
  1325. NULL);
  1326. if (!NT_SUCCESS(Status)) {
  1327. return Status;
  1328. }
  1329. ObDereferenceObject(pwinsta);
  1330. } else {
  1331. return STATUS_NOT_FOUND;
  1332. }
  1333. }
  1334. *ppwinsta = pwinsta;
  1335. return STATUS_SUCCESS;
  1336. }
  1337. /***************************************************************************\
  1338. * _SetWindowStationUser
  1339. *
  1340. * Private API for winlogon to associate a windowstation with a user.
  1341. *
  1342. * History:
  1343. * 06-27-94 JimA Created.
  1344. \***************************************************************************/
  1345. BOOL _SetWindowStationUser(
  1346. PWINDOWSTATION pwinsta,
  1347. PLUID pluidUser,
  1348. PSID ccxpsidUser,
  1349. DWORD cbsidUser)
  1350. {
  1351. /*
  1352. * Make sure the caller is the logon process.
  1353. */
  1354. if (PsGetCurrentProcessId() != gpidLogon) {
  1355. RIPERR0(ERROR_ACCESS_DENIED,
  1356. RIP_WARNING,
  1357. "_SetWindowStationUser: Caller must be in the logon process");
  1358. return FALSE;
  1359. }
  1360. if (pwinsta->psidUser != NULL) {
  1361. UserFreePool(pwinsta->psidUser);
  1362. }
  1363. if (ccxpsidUser != NULL) {
  1364. pwinsta->psidUser = UserAllocPoolWithQuota(cbsidUser, TAG_SECURITY);
  1365. if (pwinsta->psidUser == NULL) {
  1366. RIPERR0(ERROR_OUTOFMEMORY,
  1367. RIP_WARNING,
  1368. "Memory allocation failed in _SetWindowStationUser");
  1369. return FALSE;
  1370. }
  1371. try {
  1372. RtlCopyMemory(pwinsta->psidUser, ccxpsidUser, cbsidUser);
  1373. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  1374. UserFreePool(pwinsta->psidUser);
  1375. pwinsta->psidUser = NULL;
  1376. return FALSE;
  1377. }
  1378. } else {
  1379. pwinsta->psidUser = NULL;
  1380. }
  1381. pwinsta->luidUser = *pluidUser;
  1382. return TRUE;
  1383. }
  1384. /***************************************************************************\
  1385. * _LockWorkStation (API)
  1386. *
  1387. * locks the workstation. This API just posts a message to winlogon
  1388. * and winlogon does all the work
  1389. *
  1390. * History:
  1391. * 06-11-97 CLupu Created.
  1392. \***************************************************************************/
  1393. BOOL _LockWorkStation(
  1394. VOID)
  1395. {
  1396. UserAssert(gspwndLogonNotify != NULL);
  1397. _PostMessage(gspwndLogonNotify,
  1398. WM_LOGONNOTIFY, LOGON_LOCKWORKSTATION, LOCK_NORMAL);
  1399. return TRUE;
  1400. }