[WIN32SS:NTUSER] Completely update the metrics in co_IntInitializeDesktopGraphics().
[reactos.git] / win32ss / user / ntuser / winsta.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window stations
5 * FILE: win32ss/user/ntuser/winsta.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * TODO: The process window station is created on
8 * the first USER32/GDI32 call not related
9 * to window station/desktop handling
10 */
11
12 #include <win32k.h>
13 DBG_DEFAULT_CHANNEL(UserWinsta);
14
15 /* GLOBALS *******************************************************************/
16
17 /*
18 * The currently active window station. This is the
19 * only one interactive window station on the system.
20 */
21 PWINSTATION_OBJECT InputWindowStation = NULL;
22
23 /* Winlogon SAS window */
24 HWND hwndSAS = NULL;
25
26 /* Full path to WindowStations directory */
27 UNICODE_STRING gustrWindowStationsDir;
28
29 /* INITIALIZATION FUNCTIONS ****************************************************/
30
31 INIT_FUNCTION
32 NTSTATUS
33 NTAPI
34 InitWindowStationImpl(VOID)
35 {
36 GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
37 WINSTA_WRITE,
38 WINSTA_EXECUTE,
39 WINSTA_ACCESS_ALL};
40
41 /* Set Winsta Object Attributes */
42 ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
43 ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
44 ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
45
46 return STATUS_SUCCESS;
47 }
48
49 NTSTATUS
50 NTAPI
51 UserCreateWinstaDirectory(VOID)
52 {
53 NTSTATUS Status;
54 PPEB Peb;
55 OBJECT_ATTRIBUTES ObjectAttributes;
56 HANDLE hWinstaDir;
57 WCHAR wstrWindowStationsDir[MAX_PATH];
58
59 /* Create the WindowStations directory and cache its path for later use */
60 Peb = NtCurrentPeb();
61 if(Peb->SessionId == 0)
62 {
63 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR))
64 {
65 return STATUS_INSUFFICIENT_RESOURCES;
66 }
67 }
68 else
69 {
70 Status = RtlStringCbPrintfW(wstrWindowStationsDir,
71 sizeof(wstrWindowStationsDir),
72 L"%ws\\%lu%ws",
73 SESSION_DIR,
74 Peb->SessionId,
75 WINSTA_OBJ_DIR);
76 if (!NT_SUCCESS(Status))
77 return Status;
78
79 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
80 {
81 return STATUS_INSUFFICIENT_RESOURCES;
82 }
83 }
84
85 InitializeObjectAttributes(&ObjectAttributes,
86 &gustrWindowStationsDir,
87 OBJ_KERNEL_HANDLE,
88 NULL,
89 NULL);
90 Status = ZwCreateDirectoryObject(&hWinstaDir, DIRECTORY_CREATE_OBJECT, &ObjectAttributes);
91 if (!NT_SUCCESS(Status))
92 {
93 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status);
94 return Status;
95 }
96
97 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir, Peb->SessionId);
98
99 return Status;
100 }
101
102 /* OBJECT CALLBACKS ***********************************************************/
103
104 NTSTATUS
105 NTAPI
106 IntWinStaObjectDelete(
107 _In_ PVOID Parameters)
108 {
109 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
110 PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
111
112 TRACE("Deleting window station 0x%p\n", WinSta);
113
114 if (WinSta == InputWindowStation)
115 {
116 ERR("WARNING: Deleting the interactive window station '%wZ'!\n",
117 &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(InputWindowStation))->Name));
118
119 /* Only Winlogon can close and delete the interactive window station */
120 ASSERT(gpidLogon == PsGetCurrentProcessId());
121
122 InputWindowStation = NULL;
123 }
124
125 WinSta->Flags |= WSS_DYING;
126
127 UserEmptyClipboardData(WinSta);
128
129 RtlDestroyAtomTable(WinSta->AtomTable);
130
131 return STATUS_SUCCESS;
132 }
133
134 NTSTATUS
135 NTAPI
136 IntWinStaObjectParse(
137 _In_ PVOID Parameters)
138 {
139 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters = Parameters;
140 PUNICODE_STRING RemainingName = ParseParameters->RemainingName;
141
142 /* Assume we don't find anything */
143 *ParseParameters->Object = NULL;
144
145 /* Check for an empty name */
146 if (!RemainingName->Length)
147 {
148 /* Make sure this is a window station, can't parse a desktop now */
149 if (ParseParameters->ObjectType != ExWindowStationObjectType)
150 {
151 /* Fail */
152 return STATUS_OBJECT_TYPE_MISMATCH;
153 }
154
155 /* Reference the window station and return */
156 ObReferenceObject(ParseParameters->ParseObject);
157 *ParseParameters->Object = ParseParameters->ParseObject;
158 return STATUS_SUCCESS;
159 }
160
161 /* Check for leading slash */
162 if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
163 {
164 /* Skip it */
165 RemainingName->Buffer++;
166 RemainingName->Length -= sizeof(WCHAR);
167 RemainingName->MaximumLength -= sizeof(WCHAR);
168 }
169
170 /* Check if there is still a slash */
171 if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
172 {
173 /* In this case, fail */
174 return STATUS_OBJECT_PATH_INVALID;
175 }
176
177 /*
178 * Check if we are parsing a desktop.
179 */
180 if (ParseParameters->ObjectType == ExDesktopObjectType)
181 {
182 /* Then call the desktop parse routine */
183 return IntDesktopObjectParse(ParseParameters->ParseObject,
184 ParseParameters->ObjectType,
185 ParseParameters->AccessState,
186 ParseParameters->AccessMode,
187 ParseParameters->Attributes,
188 ParseParameters->CompleteName,
189 RemainingName,
190 ParseParameters->Context,
191 ParseParameters->SecurityQos,
192 ParseParameters->Object);
193 }
194
195 /* Should hopefully never get here */
196 return STATUS_OBJECT_TYPE_MISMATCH;
197 }
198
199 NTSTATUS
200 NTAPI
201 IntWinStaOkToClose(
202 _In_ PVOID Parameters)
203 {
204 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
205 PPROCESSINFO ppi;
206
207 ppi = PsGetCurrentProcessWin32Process();
208
209 if (ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
210 {
211 return STATUS_ACCESS_DENIED;
212 }
213
214 return STATUS_SUCCESS;
215 }
216
217 /* PRIVATE FUNCTIONS **********************************************************/
218
219 /*
220 * IntValidateWindowStationHandle
221 *
222 * Validates the window station handle.
223 *
224 * Remarks
225 * If the function succeeds, the handle remains referenced. If the
226 * fucntion fails, last error is set.
227 */
228
229 NTSTATUS FASTCALL
230 IntValidateWindowStationHandle(
231 HWINSTA WindowStation,
232 KPROCESSOR_MODE AccessMode,
233 ACCESS_MASK DesiredAccess,
234 PWINSTATION_OBJECT *Object,
235 POBJECT_HANDLE_INFORMATION pObjectHandleInfo)
236 {
237 NTSTATUS Status;
238
239 if (WindowStation == NULL)
240 {
241 ERR("Invalid window station handle\n");
242 EngSetLastError(ERROR_INVALID_HANDLE);
243 return STATUS_INVALID_HANDLE;
244 }
245
246 Status = ObReferenceObjectByHandle(WindowStation,
247 DesiredAccess,
248 ExWindowStationObjectType,
249 AccessMode,
250 (PVOID*)Object,
251 pObjectHandleInfo);
252
253 if (!NT_SUCCESS(Status))
254 SetLastNtError(Status);
255
256 return Status;
257 }
258
259 BOOL FASTCALL
260 co_IntInitializeDesktopGraphics(VOID)
261 {
262 TEXTMETRICW tmw;
263 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
264 PDESKTOP pdesk;
265
266 ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
267 if (NULL == ScreenDeviceContext)
268 {
269 IntDestroyPrimarySurface();
270 return FALSE;
271 }
272 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
273
274 if (!IntCreatePrimarySurface())
275 {
276 return FALSE;
277 }
278
279 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
280
281 NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
282 GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
283
284 /* Update the system metrics */
285 InitMetrics();
286
287 /* Set new size of the monitor */
288 UserUpdateMonitorSize((HDEV)gppdevPrimary);
289
290 /* Update the SERVERINFO */
291 gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
292 gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
293 gpsi->Planes = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
294 gpsi->BitsPixel = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
295 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
296 gpsi->dmLogPixels = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
297 if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
298 {
299 gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
300 }
301 else
302 {
303 gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
304 }
305 // Font is realized and this dc was previously set to internal DC_ATTR.
306 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
307 gpsi->tmSysFont = tmw;
308
309 /* Put the pointer in the center of the screen */
310 gpsi->ptCursor.x = gpsi->aiSysMet[SM_CXSCREEN] / 2;
311 gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
312
313 /* Attach monitor */
314 UserAttachMonitor((HDEV)gppdevPrimary);
315
316 /* Setup the cursor */
317 co_IntLoadDefaultCursors();
318
319 /* Setup the icons */
320 co_IntSetWndIcons();
321
322 /* Setup Menu */
323 MenuInit();
324
325 /* Show the desktop */
326 pdesk = IntGetActiveDesktop();
327 ASSERT(pdesk);
328 co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
329
330 return TRUE;
331 }
332
333 VOID FASTCALL
334 IntEndDesktopGraphics(VOID)
335 {
336 if (NULL != ScreenDeviceContext)
337 { // No need to allocate a new dcattr.
338 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
339 GreDeleteObject(ScreenDeviceContext);
340 ScreenDeviceContext = NULL;
341 }
342 IntHideDesktop(IntGetActiveDesktop());
343 IntDestroyPrimarySurface();
344 }
345
346 HDC FASTCALL
347 IntGetScreenDC(VOID)
348 {
349 return ScreenDeviceContext;
350 }
351
352 BOOL FASTCALL
353 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
354 {
355 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
356 if ( gpidLogon != PsGetCurrentProcessId() )
357 {
358 if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
359 {
360 ERR("Requires Interactive Window Station\n");
361 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
362 return FALSE;
363 }
364 if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
365 {
366 ERR("Access Denied\n");
367 EngSetLastError(ERROR_ACCESS_DENIED);
368 return FALSE;
369 }
370 }
371 return TRUE;
372 }
373
374
375 /* PUBLIC FUNCTIONS ***********************************************************/
376
377 /*
378 * NtUserCreateWindowStation
379 *
380 * Creates a new window station.
381 *
382 * Parameters
383 * lpszWindowStationName
384 * Pointer to a null-terminated string specifying the name of the
385 * window station to be created. Window station names are
386 * case-insensitive and cannot contain backslash characters (\).
387 * Only members of the Administrators group are allowed to specify a
388 * name.
389 *
390 * dwDesiredAccess
391 * Requested type of access
392 *
393 * lpSecurity
394 * Security descriptor
395 *
396 * Unknown3, Unknown4, Unknown5, Unknown6
397 * Unused
398 *
399 * Return Value
400 * If the function succeeds, the return value is a handle to the newly
401 * created window station. If the specified window station already
402 * exists, the function succeeds and returns a handle to the existing
403 * window station. If the function fails, the return value is NULL.
404 *
405 * Status
406 * @implemented
407 */
408
409 NTSTATUS
410 FASTCALL
411 IntCreateWindowStation(
412 OUT HWINSTA* phWinSta,
413 IN POBJECT_ATTRIBUTES ObjectAttributes,
414 IN KPROCESSOR_MODE AccessMode,
415 IN KPROCESSOR_MODE OwnerMode,
416 IN ACCESS_MASK dwDesiredAccess,
417 DWORD Unknown2,
418 DWORD Unknown3,
419 DWORD Unknown4,
420 DWORD Unknown5,
421 DWORD Unknown6)
422 {
423 NTSTATUS Status;
424 HWINSTA hWinSta;
425 PWINSTATION_OBJECT WindowStation;
426
427 TRACE("IntCreateWindowStation called\n");
428
429 ASSERT(phWinSta);
430 *phWinSta = NULL;
431
432 Status = ObOpenObjectByName(ObjectAttributes,
433 ExWindowStationObjectType,
434 AccessMode,
435 NULL,
436 dwDesiredAccess,
437 NULL,
438 (PVOID*)&hWinSta);
439 if (NT_SUCCESS(Status))
440 {
441 TRACE("IntCreateWindowStation opened window station '%wZ'\n",
442 ObjectAttributes->ObjectName);
443 *phWinSta = hWinSta;
444 return Status;
445 }
446
447 /*
448 * No existing window station found, try to create a new one.
449 */
450
451 /* Create the window station object */
452 Status = ObCreateObject(AccessMode,
453 ExWindowStationObjectType,
454 ObjectAttributes,
455 OwnerMode,
456 NULL,
457 sizeof(WINSTATION_OBJECT),
458 0,
459 0,
460 (PVOID*)&WindowStation);
461 if (!NT_SUCCESS(Status))
462 {
463 ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
464 ObjectAttributes->ObjectName, Status);
465 SetLastNtError(Status);
466 return Status;
467 }
468
469 /* Initialize the window station */
470 RtlZeroMemory(WindowStation, sizeof(WINSTATION_OBJECT));
471
472 InitializeListHead(&WindowStation->DesktopListHead);
473 WindowStation->dwSessionId = NtCurrentPeb()->SessionId;
474 Status = RtlCreateAtomTable(37, &WindowStation->AtomTable);
475 if (!NT_SUCCESS(Status))
476 {
477 ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
478 ObjectAttributes->ObjectName, Status);
479 ObDereferenceObject(WindowStation);
480 SetLastNtError(Status);
481 return Status;
482 }
483
484 Status = ObInsertObject(WindowStation,
485 NULL,
486 dwDesiredAccess,
487 0,
488 NULL,
489 (PVOID*)&hWinSta);
490 if (!NT_SUCCESS(Status))
491 {
492 ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status);
493 SetLastNtError(Status);
494 return Status;
495 }
496
497 // FIXME! TODO: Add this new window station to a linked list
498
499 if (InputWindowStation == NULL)
500 {
501 ERR("Initializing input window station\n");
502
503 /* Only Winlogon can create the interactive window station */
504 ASSERT(gpidLogon == PsGetCurrentProcessId());
505
506 InputWindowStation = WindowStation;
507 WindowStation->Flags &= ~WSS_NOIO;
508
509 InitCursorImpl();
510
511 UserCreateSystemThread(ST_DESKTOP_THREAD);
512 UserCreateSystemThread(ST_RIT);
513
514 /* Desktop functions require the desktop thread running so wait for it to initialize */
515 UserLeaveCo();
516 KeWaitForSingleObject(gpDesktopThreadStartedEvent,
517 UserRequest,
518 UserMode,
519 FALSE,
520 NULL);
521 UserEnterCo();
522 }
523 else
524 {
525 WindowStation->Flags |= WSS_NOIO;
526 }
527
528 TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
529 ObjectAttributes->ObjectName, WindowStation, hWinSta);
530
531 *phWinSta = hWinSta;
532 EngSetLastError(ERROR_SUCCESS);
533
534 return STATUS_SUCCESS;
535 }
536
537 static VOID
538 FreeUserModeWindowStationName(
539 IN OUT PUNICODE_STRING WindowStationName,
540 IN PUNICODE_STRING TebStaticUnicodeString,
541 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL,
542 IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL)
543 {
544 SIZE_T MemSize = 0;
545
546 /* Try to restore the user's UserModeObjectAttributes */
547 if (UserModeObjectAttributes && LocalObjectAttributes)
548 {
549 _SEH2_TRY
550 {
551 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
552 *UserModeObjectAttributes = *LocalObjectAttributes;
553 }
554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
555 {
556 NOTHING;
557 }
558 _SEH2_END;
559 }
560
561 /* Free the user-mode memory */
562 if (WindowStationName && (WindowStationName != TebStaticUnicodeString))
563 {
564 ZwFreeVirtualMemory(ZwCurrentProcess(),
565 (PVOID*)&WindowStationName,
566 &MemSize,
567 MEM_RELEASE);
568 }
569 }
570
571 static NTSTATUS
572 BuildUserModeWindowStationName(
573 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes,
574 IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes,
575 OUT PUNICODE_STRING* WindowStationName,
576 OUT PUNICODE_STRING* TebStaticUnicodeString)
577 {
578 NTSTATUS Status;
579 SIZE_T MemSize;
580
581 LUID CallerLuid;
582 PTEB Teb;
583 USHORT StrSize;
584
585 *WindowStationName = NULL;
586 *TebStaticUnicodeString = NULL;
587
588 /* Retrieve the current process LUID */
589 Status = GetProcessLuid(NULL, NULL, &CallerLuid);
590 if (!NT_SUCCESS(Status))
591 {
592 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status);
593 return Status;
594 }
595
596 /* Compute the needed string size */
597 MemSize = _scwprintf(L"%wZ\\Service-0x%x-%x$",
598 &gustrWindowStationsDir,
599 CallerLuid.HighPart,
600 CallerLuid.LowPart);
601 MemSize = MemSize * sizeof(WCHAR) + sizeof(UNICODE_NULL);
602 if (MemSize > MAXUSHORT)
603 {
604 ERR("Window station name length is too long.\n");
605 return STATUS_NAME_TOO_LONG;
606 }
607 StrSize = (USHORT)MemSize;
608
609 /*
610 * Check whether it's short enough so that we can use the static buffer
611 * in the TEB. Otherwise continue with virtual memory allocation.
612 */
613 Teb = NtCurrentTeb();
614 if (Teb && (StrSize <= sizeof(Teb->StaticUnicodeBuffer)))
615 {
616 /* We can use the TEB's static unicode string */
617 ASSERT(Teb->StaticUnicodeString.Buffer == Teb->StaticUnicodeBuffer);
618 ASSERT(Teb->StaticUnicodeString.MaximumLength == sizeof(Teb->StaticUnicodeBuffer));
619
620 /* Remember the TEB's static unicode string address for later */
621 *TebStaticUnicodeString = &Teb->StaticUnicodeString;
622
623 *WindowStationName = *TebStaticUnicodeString;
624 (*WindowStationName)->Length = 0;
625 }
626 else
627 {
628 /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
629 MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID));
630
631 /* Allocate the memory in user-mode */
632 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
633 (PVOID*)WindowStationName,
634 0,
635 &MemSize,
636 MEM_COMMIT,
637 PAGE_READWRITE);
638 if (!NT_SUCCESS(Status))
639 {
640 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status);
641 return Status;
642 }
643
644 RtlInitEmptyUnicodeString(*WindowStationName,
645 (PWCHAR)((ULONG_PTR)*WindowStationName +
646 ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))),
647 StrSize);
648 }
649
650 /* Build a valid window station name from the LUID */
651 Status = RtlStringCbPrintfW((*WindowStationName)->Buffer,
652 (*WindowStationName)->MaximumLength,
653 L"%wZ\\Service-0x%x-%x$",
654 &gustrWindowStationsDir,
655 CallerLuid.HighPart,
656 CallerLuid.LowPart);
657 if (!NT_SUCCESS(Status))
658 {
659 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
660 goto Quit;
661 }
662 (*WindowStationName)->Length = (USHORT)(wcslen((*WindowStationName)->Buffer) * sizeof(WCHAR));
663
664 /* Try to update the user's UserModeObjectAttributes */
665 _SEH2_TRY
666 {
667 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
668 *LocalObjectAttributes = *UserModeObjectAttributes;
669
670 UserModeObjectAttributes->ObjectName = *WindowStationName;
671 UserModeObjectAttributes->RootDirectory = NULL;
672
673 Status = STATUS_SUCCESS;
674 }
675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
676 {
677 Status = _SEH2_GetExceptionCode();
678 }
679 _SEH2_END;
680
681 Quit:
682 if (!NT_SUCCESS(Status))
683 {
684 /* Release the window station name */
685 FreeUserModeWindowStationName(*WindowStationName,
686 *TebStaticUnicodeString,
687 NULL, NULL);
688 }
689
690 return Status;
691 }
692
693 HWINSTA
694 APIENTRY
695 NtUserCreateWindowStation(
696 IN POBJECT_ATTRIBUTES ObjectAttributes,
697 IN ACCESS_MASK dwDesiredAccess,
698 DWORD Unknown2,
699 DWORD Unknown3,
700 DWORD Unknown4,
701 DWORD Unknown5,
702 DWORD Unknown6)
703 {
704 NTSTATUS Status = STATUS_SUCCESS;
705 HWINSTA hWinSta = NULL;
706 OBJECT_ATTRIBUTES LocalObjectAttributes;
707 PUNICODE_STRING WindowStationName = NULL;
708 PUNICODE_STRING TebStaticUnicodeString = NULL;
709 KPROCESSOR_MODE OwnerMode = UserMode;
710
711 TRACE("NtUserCreateWindowStation called\n");
712
713 /* Capture the object attributes and the window station name */
714 _SEH2_TRY
715 {
716 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
717 LocalObjectAttributes = *ObjectAttributes;
718 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
719 {
720 ERR("Invalid ObjectAttributes length!\n");
721 Status = STATUS_INVALID_PARAMETER;
722 _SEH2_LEAVE;
723 }
724
725 /*
726 * Check whether the caller provided a window station name together
727 * with a RootDirectory handle.
728 *
729 * If the caller did not provide a window station name, build a new one
730 * based on the logon session identifier for the calling process.
731 * The new name is allocated in user-mode, as the rest of ObjectAttributes
732 * already is, so that the validation performed by the Object Manager
733 * can be done adequately.
734 */
735 if ((LocalObjectAttributes.ObjectName == NULL ||
736 LocalObjectAttributes.ObjectName->Buffer == NULL ||
737 LocalObjectAttributes.ObjectName->Length == 0 ||
738 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
739 /* &&
740 LocalObjectAttributes.RootDirectory == NULL */)
741 {
742 /* No, build the new window station name */
743 Status = BuildUserModeWindowStationName(ObjectAttributes,
744 &LocalObjectAttributes,
745 &WindowStationName,
746 &TebStaticUnicodeString);
747 if (!NT_SUCCESS(Status))
748 {
749 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
750 _SEH2_LEAVE;
751 }
752 OwnerMode = KernelMode;
753 }
754 }
755 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
756 {
757 Status =_SEH2_GetExceptionCode();
758 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
759 }
760 _SEH2_END;
761
762 if (!NT_SUCCESS(Status))
763 {
764 SetLastNtError(Status);
765 return NULL;
766 }
767
768 UserEnterExclusive();
769
770 /* Create the window station */
771 Status = IntCreateWindowStation(&hWinSta,
772 ObjectAttributes,
773 UserMode,
774 OwnerMode,
775 dwDesiredAccess,
776 Unknown2,
777 Unknown3,
778 Unknown4,
779 Unknown5,
780 Unknown6);
781 UserLeave();
782
783 if (NT_SUCCESS(Status))
784 {
785 TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
786 ObjectAttributes->ObjectName, hWinSta);
787 }
788 else
789 {
790 ASSERT(hWinSta == NULL);
791 ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
792 ObjectAttributes->ObjectName, Status);
793 }
794
795 /* Try to restore the user's ObjectAttributes and release the window station name */
796 FreeUserModeWindowStationName(WindowStationName,
797 TebStaticUnicodeString,
798 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
799 &LocalObjectAttributes);
800
801 if (!NT_SUCCESS(Status))
802 {
803 ASSERT(hWinSta == NULL);
804 SetLastNtError(Status);
805 }
806
807 return hWinSta;
808 }
809
810 /*
811 * NtUserOpenWindowStation
812 *
813 * Opens an existing window station.
814 *
815 * Parameters
816 * lpszWindowStationName
817 * Name of the existing window station.
818 *
819 * dwDesiredAccess
820 * Requested type of access.
821 *
822 * Return Value
823 * If the function succeeds, the return value is the handle to the
824 * specified window station. If the function fails, the return value
825 * is NULL.
826 *
827 * Remarks
828 * The returned handle can be closed with NtUserCloseWindowStation.
829 *
830 * Status
831 * @implemented
832 */
833
834 HWINSTA
835 APIENTRY
836 NtUserOpenWindowStation(
837 IN POBJECT_ATTRIBUTES ObjectAttributes,
838 IN ACCESS_MASK dwDesiredAccess)
839 {
840 NTSTATUS Status = STATUS_SUCCESS;
841 HWINSTA hWinSta = NULL;
842 OBJECT_ATTRIBUTES LocalObjectAttributes;
843 PUNICODE_STRING WindowStationName = NULL;
844 PUNICODE_STRING TebStaticUnicodeString = NULL;
845 KPROCESSOR_MODE OwnerMode = UserMode;
846
847 TRACE("NtUserOpenWindowStation called\n");
848
849 /* Capture the object attributes and the window station name */
850 _SEH2_TRY
851 {
852 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
853 LocalObjectAttributes = *ObjectAttributes;
854 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
855 {
856 ERR("Invalid ObjectAttributes length!\n");
857 Status = STATUS_INVALID_PARAMETER;
858 _SEH2_LEAVE;
859 }
860
861 /*
862 * Check whether the caller did not provide a window station name,
863 * or provided the special "Service-0x00000000-00000000$" name.
864 *
865 * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
866 * is used instead of an empty name (observed when API-monitoring
867 * OpenWindowStation() called with an empty window station name).
868 */
869 if ((LocalObjectAttributes.ObjectName == NULL ||
870 LocalObjectAttributes.ObjectName->Buffer == NULL ||
871 LocalObjectAttributes.ObjectName->Length == 0 ||
872 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
873 /* &&
874 LocalObjectAttributes.RootDirectory == NULL */)
875 {
876 /* No, remember that for later */
877 LocalObjectAttributes.ObjectName = NULL;
878 }
879 if (LocalObjectAttributes.ObjectName &&
880 LocalObjectAttributes.ObjectName->Length ==
881 sizeof(L"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL) &&
882 _wcsnicmp(LocalObjectAttributes.ObjectName->Buffer,
883 L"Service-0x00000000-00000000$",
884 LocalObjectAttributes.ObjectName->Length / sizeof(WCHAR)) == 0)
885 {
886 /* No, remember that for later */
887 LocalObjectAttributes.ObjectName = NULL;
888 }
889
890 /*
891 * If the caller did not provide a window station name, build a new one
892 * based on the logon session identifier for the calling process.
893 * The new name is allocated in user-mode, as the rest of ObjectAttributes
894 * already is, so that the validation performed by the Object Manager
895 * can be done adequately.
896 */
897 if (!LocalObjectAttributes.ObjectName)
898 {
899 /* No, build the new window station name */
900 Status = BuildUserModeWindowStationName(ObjectAttributes,
901 &LocalObjectAttributes,
902 &WindowStationName,
903 &TebStaticUnicodeString);
904 if (!NT_SUCCESS(Status))
905 {
906 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
907 _SEH2_LEAVE;
908 }
909 OwnerMode = KernelMode;
910 }
911 }
912 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
913 {
914 Status =_SEH2_GetExceptionCode();
915 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
916 }
917 _SEH2_END;
918
919 if (!NT_SUCCESS(Status))
920 {
921 SetLastNtError(Status);
922 return NULL;
923 }
924
925 /* Open the window station */
926 Status = ObOpenObjectByName(ObjectAttributes,
927 ExWindowStationObjectType,
928 UserMode,
929 NULL,
930 dwDesiredAccess,
931 NULL,
932 (PVOID*)&hWinSta);
933 if (NT_SUCCESS(Status))
934 {
935 TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
936 ObjectAttributes->ObjectName, hWinSta);
937 }
938 else
939 {
940 ASSERT(hWinSta == NULL);
941 ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
942 ObjectAttributes->ObjectName, Status);
943 }
944
945 /* Try to restore the user's ObjectAttributes and release the window station name */
946 FreeUserModeWindowStationName(WindowStationName,
947 TebStaticUnicodeString,
948 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
949 &LocalObjectAttributes);
950
951 if (!NT_SUCCESS(Status))
952 {
953 ASSERT(hWinSta == NULL);
954 SetLastNtError(Status);
955 }
956
957 return hWinSta;
958 }
959
960 /*
961 * NtUserCloseWindowStation
962 *
963 * Closes a window station handle.
964 *
965 * Parameters
966 * hWinSta
967 * Handle to the window station.
968 *
969 * Return Value
970 * Status
971 *
972 * Remarks
973 * The window station handle can be created with NtUserCreateWindowStation
974 * or NtUserOpenWindowStation. Attempts to close a handle to the window
975 * station assigned to the calling process will fail.
976 *
977 * Status
978 * @implemented
979 */
980
981 BOOL
982 APIENTRY
983 NtUserCloseWindowStation(
984 HWINSTA hWinSta)
985 {
986 PWINSTATION_OBJECT Object;
987 NTSTATUS Status;
988
989 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
990
991 if (hWinSta == UserGetProcessWindowStation())
992 {
993 ERR("Attempted to close process window station\n");
994 return FALSE;
995 }
996
997 Status = IntValidateWindowStationHandle(hWinSta,
998 UserMode,
999 0,
1000 &Object,
1001 NULL);
1002 if (!NT_SUCCESS(Status))
1003 {
1004 ERR("Validation of window station handle (%p) failed\n", hWinSta);
1005 return FALSE;
1006 }
1007
1008 ObDereferenceObject(Object);
1009
1010 TRACE("Closing window station handle (%p)\n", hWinSta);
1011
1012 Status = ObCloseHandle(hWinSta, UserMode);
1013 if (!NT_SUCCESS(Status))
1014 {
1015 SetLastNtError(Status);
1016 return FALSE;
1017 }
1018
1019 return TRUE;
1020 }
1021
1022 /*
1023 * NtUserGetObjectInformation
1024 *
1025 * The NtUserGetObjectInformation function retrieves information about a
1026 * window station or desktop object.
1027 *
1028 * Parameters
1029 * hObj
1030 * Handle to the window station or desktop object for which to
1031 * return information. This can be a handle of type HDESK or HWINSTA
1032 * (for example, a handle returned by NtUserCreateWindowStation,
1033 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1034 *
1035 * nIndex
1036 * Specifies the object information to be retrieved.
1037 *
1038 * pvInfo
1039 * Pointer to a buffer to receive the object information.
1040 *
1041 * nLength
1042 * Specifies the size, in bytes, of the buffer pointed to by the
1043 * pvInfo parameter.
1044 *
1045 * lpnLengthNeeded
1046 * Pointer to a variable receiving the number of bytes required to
1047 * store the requested information. If this variable's value is
1048 * greater than the value of the nLength parameter when the function
1049 * returns, the function returns FALSE, and none of the information
1050 * is copied to the pvInfo buffer. If the value of the variable pointed
1051 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1052 * the entire information block is copied.
1053 *
1054 * Return Value
1055 * If the function succeeds, the return value is nonzero. If the function
1056 * fails, the return value is zero.
1057 *
1058 * Status
1059 * @unimplemented
1060 */
1061
1062 BOOL APIENTRY
1063 NtUserGetObjectInformation(
1064 HANDLE hObject,
1065 DWORD nIndex,
1066 PVOID pvInformation,
1067 DWORD nLength,
1068 PDWORD nLengthNeeded)
1069 {
1070 NTSTATUS Status;
1071 PWINSTATION_OBJECT WinStaObject = NULL;
1072 PDESKTOP DesktopObject = NULL;
1073 POBJECT_HEADER ObjectHeader;
1074 POBJECT_HEADER_NAME_INFO NameInfo;
1075 OBJECT_HANDLE_INFORMATION HandleInfo;
1076 USEROBJECTFLAGS ObjectFlags;
1077 PUNICODE_STRING pStrNameU = NULL;
1078 PVOID pvData = NULL;
1079 SIZE_T nDataSize = 0;
1080
1081 _SEH2_TRY
1082 {
1083 if (nLengthNeeded)
1084 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
1085 ProbeForWrite(pvInformation, nLength, 1);
1086 }
1087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1088 {
1089 SetLastNtError(_SEH2_GetExceptionCode());
1090 return FALSE;
1091 }
1092 _SEH2_END;
1093
1094 /* Try window station */
1095 TRACE("Trying to open window station 0x%p\n", hObject);
1096 Status = ObReferenceObjectByHandle(hObject,
1097 0,
1098 ExWindowStationObjectType,
1099 UserMode,
1100 (PVOID*)&WinStaObject,
1101 &HandleInfo);
1102
1103 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
1104 {
1105 /* Try desktop */
1106 TRACE("Trying to open desktop %p\n", hObject);
1107 WinStaObject = NULL;
1108 Status = IntValidateDesktopHandle(hObject,
1109 UserMode,
1110 0,
1111 &DesktopObject);
1112 }
1113
1114 if (!NT_SUCCESS(Status))
1115 {
1116 ERR("Failed: 0x%x\n", Status);
1117 goto Exit;
1118 }
1119
1120 TRACE("WinSta or Desktop opened!\n");
1121
1122 /* Get data */
1123 switch (nIndex)
1124 {
1125 case UOI_FLAGS:
1126 {
1127 ObjectFlags.fReserved = FALSE;
1128 ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
1129
1130 ObjectFlags.dwFlags = 0;
1131 if (WinStaObject != NULL)
1132 {
1133 if (!(WinStaObject->Flags & WSS_NOIO))
1134 ObjectFlags.dwFlags |= WSF_VISIBLE;
1135 }
1136 else if (DesktopObject != NULL)
1137 {
1138 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1139 }
1140 else
1141 {
1142 ERR("No associated WinStaObject nor DesktopObject!\n");
1143 }
1144
1145 pvData = &ObjectFlags;
1146 nDataSize = sizeof(ObjectFlags);
1147 Status = STATUS_SUCCESS;
1148 break;
1149 }
1150
1151 case UOI_NAME:
1152 {
1153 if (WinStaObject != NULL)
1154 {
1155 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1156 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1157
1158 if (NameInfo && (NameInfo->Name.Length > 0))
1159 {
1160 /* Named window station */
1161 pStrNameU = &NameInfo->Name;
1162 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1163 }
1164 else
1165 {
1166 /* Unnamed window station (should never happen!) */
1167 ASSERT(FALSE);
1168 pStrNameU = NULL;
1169 nDataSize = sizeof(UNICODE_NULL);
1170 }
1171 Status = STATUS_SUCCESS;
1172 }
1173 else if (DesktopObject != NULL)
1174 {
1175 pvData = DesktopObject->pDeskInfo->szDesktopName;
1176 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
1177 Status = STATUS_SUCCESS;
1178 }
1179 else
1180 {
1181 Status = STATUS_INVALID_PARAMETER;
1182 }
1183 break;
1184 }
1185
1186 case UOI_TYPE:
1187 {
1188 if (WinStaObject != NULL)
1189 {
1190 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1191 pStrNameU = &ObjectHeader->Type->Name;
1192 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1193 Status = STATUS_SUCCESS;
1194 }
1195 else if (DesktopObject != NULL)
1196 {
1197 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject);
1198 pStrNameU = &ObjectHeader->Type->Name;
1199 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1200 Status = STATUS_SUCCESS;
1201 }
1202 else
1203 {
1204 Status = STATUS_INVALID_PARAMETER;
1205 }
1206 break;
1207 }
1208
1209 case UOI_USER_SID:
1210 Status = STATUS_NOT_IMPLEMENTED;
1211 ERR("UOI_USER_SID unimplemented!\n");
1212 break;
1213
1214 default:
1215 Status = STATUS_INVALID_PARAMETER;
1216 break;
1217 }
1218
1219 Exit:
1220 if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
1221 Status = STATUS_BUFFER_TOO_SMALL;
1222
1223 _SEH2_TRY
1224 {
1225 if (nLengthNeeded)
1226 *nLengthNeeded = nDataSize;
1227
1228 /* Try to copy data to caller */
1229 if (Status == STATUS_SUCCESS && (nDataSize > 0))
1230 {
1231 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
1232 if (pvData)
1233 {
1234 /* Copy the data */
1235 RtlCopyMemory(pvInformation, pvData, nDataSize);
1236 }
1237 else if (pStrNameU)
1238 {
1239 /* Copy and NULL-terminate the string */
1240 RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length);
1241 ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
1242 }
1243 else
1244 {
1245 /* Zero the memory */
1246 RtlZeroMemory(pvInformation, nDataSize);
1247 }
1248 }
1249 }
1250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1251 {
1252 Status = _SEH2_GetExceptionCode();
1253 }
1254 _SEH2_END;
1255
1256 /* Release objects */
1257 if (DesktopObject != NULL)
1258 ObDereferenceObject(DesktopObject);
1259 if (WinStaObject != NULL)
1260 ObDereferenceObject(WinStaObject);
1261
1262 if (!NT_SUCCESS(Status))
1263 {
1264 SetLastNtError(Status);
1265 return FALSE;
1266 }
1267
1268 return TRUE;
1269 }
1270
1271 /*
1272 * NtUserSetObjectInformation
1273 *
1274 * The NtUserSetObjectInformation function sets information about a
1275 * window station or desktop object.
1276 *
1277 * Parameters
1278 * hObj
1279 * Handle to the window station or desktop object for which to set
1280 * object information. This value can be a handle of type HDESK or
1281 * HWINSTA.
1282 *
1283 * nIndex
1284 * Specifies the object information to be set.
1285 *
1286 * pvInfo
1287 * Pointer to a buffer containing the object information.
1288 *
1289 * nLength
1290 * Specifies the size, in bytes, of the information contained in the
1291 * buffer pointed to by pvInfo.
1292 *
1293 * Return Value
1294 * If the function succeeds, the return value is nonzero. If the function
1295 * fails the return value is zero.
1296 *
1297 * Status
1298 * @unimplemented
1299 */
1300
1301 BOOL
1302 APIENTRY
1303 NtUserSetObjectInformation(
1304 HANDLE hObject,
1305 DWORD nIndex,
1306 PVOID pvInformation,
1307 DWORD nLength)
1308 {
1309 /* FIXME: ZwQueryObject */
1310 /* FIXME: ZwSetInformationObject */
1311 SetLastNtError(STATUS_UNSUCCESSFUL);
1312 return FALSE;
1313 }
1314
1315
1316 HWINSTA FASTCALL
1317 UserGetProcessWindowStation(VOID)
1318 {
1319 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1320
1321 return ppi->hwinsta;
1322 }
1323
1324
1325 /*
1326 * NtUserGetProcessWindowStation
1327 *
1328 * Returns a handle to the current process window station.
1329 *
1330 * Return Value
1331 * If the function succeeds, the return value is handle to the window
1332 * station assigned to the current process. If the function fails, the
1333 * return value is NULL.
1334 *
1335 * Status
1336 * @implemented
1337 */
1338
1339 HWINSTA APIENTRY
1340 NtUserGetProcessWindowStation(VOID)
1341 {
1342 return UserGetProcessWindowStation();
1343 }
1344
1345 BOOL FASTCALL
1346 UserSetProcessWindowStation(HWINSTA hWindowStation)
1347 {
1348 NTSTATUS Status;
1349 PPROCESSINFO ppi;
1350 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1351 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
1352 HWINSTA hCacheWinSta;
1353
1354 ppi = PsGetCurrentProcessWin32Process();
1355
1356 /* Reference the new window station */
1357 if (hWindowStation != NULL)
1358 {
1359 Status = IntValidateWindowStationHandle(hWindowStation,
1360 UserMode,
1361 0,
1362 &NewWinSta,
1363 &ObjectHandleInfo);
1364 if (!NT_SUCCESS(Status))
1365 {
1366 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
1367 SetLastNtError(Status);
1368 return FALSE;
1369 }
1370 }
1371
1372 OldWinSta = ppi->prpwinsta;
1373 hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
1374
1375 /* Dereference the previous window station */
1376 if (OldWinSta != NULL)
1377 {
1378 ObDereferenceObject(OldWinSta);
1379 }
1380
1381 /*
1382 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1383 */
1384
1385 /* Close the cached EPROCESS window station handle if needed */
1386 if (hCacheWinSta != NULL)
1387 {
1388 /* Reference the window station */
1389 Status = ObReferenceObjectByHandle(hCacheWinSta,
1390 0,
1391 ExWindowStationObjectType,
1392 UserMode,
1393 (PVOID*)&OldWinSta,
1394 NULL);
1395 if (!NT_SUCCESS(Status))
1396 {
1397 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
1398 /* We failed, reset the cache */
1399 hCacheWinSta = NULL;
1400 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1401 }
1402 else
1403 {
1404 /*
1405 * Close the old handle and reset the cache only
1406 * if we are setting a different window station.
1407 */
1408 if (NewWinSta != OldWinSta)
1409 {
1410 ObCloseHandle(hCacheWinSta, UserMode);
1411 hCacheWinSta = NULL;
1412 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1413 }
1414
1415 /* Dereference the window station */
1416 ObDereferenceObject(OldWinSta);
1417 }
1418 }
1419
1420 /* Duplicate and save a new cached EPROCESS window station handle */
1421 if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
1422 {
1423 Status = ZwDuplicateObject(ZwCurrentProcess(),
1424 hWindowStation,
1425 ZwCurrentProcess(),
1426 (PHANDLE)&hCacheWinSta,
1427 0,
1428 0,
1429 DUPLICATE_SAME_ACCESS);
1430 if (!NT_SUCCESS(Status))
1431 {
1432 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
1433 }
1434 else
1435 {
1436 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1437 }
1438 }
1439
1440 ppi->prpwinsta = NewWinSta;
1441 ppi->hwinsta = hWindowStation;
1442 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
1443 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
1444
1445 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
1446 {
1447 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
1448 }
1449 else
1450 {
1451 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
1452 }
1453
1454 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
1455 {
1456 ppi->W32PF_flags |= W32PF_IOWINSTA;
1457 }
1458 else /* Might be closed if the handle is NULL */
1459 {
1460 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
1461 }
1462 return TRUE;
1463 }
1464
1465 /*
1466 * NtUserSetProcessWindowStation
1467 *
1468 * Assigns a window station to the current process.
1469 *
1470 * Parameters
1471 * hWinSta
1472 * Handle to the window station.
1473 *
1474 * Return Value
1475 * Status
1476 *
1477 * Status
1478 * @implemented
1479 */
1480
1481 BOOL APIENTRY
1482 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1483 {
1484 BOOL ret;
1485
1486 UserEnterExclusive();
1487
1488 ret = UserSetProcessWindowStation(hWindowStation);
1489
1490 UserLeave();
1491
1492 return ret;
1493 }
1494
1495 /*
1496 * NtUserLockWindowStation
1497 *
1498 * Locks switching desktops. Only the logon application is allowed to call this function.
1499 *
1500 * Status
1501 * @implemented
1502 */
1503
1504 BOOL APIENTRY
1505 NtUserLockWindowStation(HWINSTA hWindowStation)
1506 {
1507 PWINSTATION_OBJECT Object;
1508 NTSTATUS Status;
1509
1510 TRACE("About to set process window station with handle (%p)\n",
1511 hWindowStation);
1512
1513 if (gpidLogon != PsGetCurrentProcessId())
1514 {
1515 ERR("Unauthorized process attempted to lock the window station!\n");
1516 EngSetLastError(ERROR_ACCESS_DENIED);
1517 return FALSE;
1518 }
1519
1520 Status = IntValidateWindowStationHandle(hWindowStation,
1521 UserMode,
1522 0,
1523 &Object,
1524 NULL);
1525 if (!NT_SUCCESS(Status))
1526 {
1527 TRACE("Validation of window station handle (%p) failed\n",
1528 hWindowStation);
1529 SetLastNtError(Status);
1530 return FALSE;
1531 }
1532
1533 Object->Flags |= WSS_LOCKED;
1534
1535 ObDereferenceObject(Object);
1536 return TRUE;
1537 }
1538
1539 /*
1540 * NtUserUnlockWindowStation
1541 *
1542 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1543 *
1544 * Status
1545 * @implemented
1546 */
1547
1548 BOOL APIENTRY
1549 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1550 {
1551 PWINSTATION_OBJECT Object;
1552 NTSTATUS Status;
1553 BOOL Ret;
1554
1555 TRACE("About to set process window station with handle (%p)\n",
1556 hWindowStation);
1557
1558 if (gpidLogon != PsGetCurrentProcessId())
1559 {
1560 ERR("Unauthorized process attempted to unlock the window station!\n");
1561 EngSetLastError(ERROR_ACCESS_DENIED);
1562 return FALSE;
1563 }
1564
1565 Status = IntValidateWindowStationHandle(hWindowStation,
1566 UserMode,
1567 0,
1568 &Object,
1569 NULL);
1570 if (!NT_SUCCESS(Status))
1571 {
1572 TRACE("Validation of window station handle (%p) failed\n",
1573 hWindowStation);
1574 SetLastNtError(Status);
1575 return FALSE;
1576 }
1577
1578 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1579 Object->Flags &= ~WSS_LOCKED;
1580
1581 ObDereferenceObject(Object);
1582 return Ret;
1583 }
1584
1585 static NTSTATUS FASTCALL
1586 BuildWindowStationNameList(
1587 ULONG dwSize,
1588 PVOID lpBuffer,
1589 PULONG pRequiredSize)
1590 {
1591 OBJECT_ATTRIBUTES ObjectAttributes;
1592 NTSTATUS Status;
1593 HANDLE DirectoryHandle;
1594 char InitialBuffer[256], *Buffer;
1595 ULONG Context, ReturnLength, BufferSize;
1596 DWORD EntryCount;
1597 POBJECT_DIRECTORY_INFORMATION DirEntry;
1598 WCHAR NullWchar;
1599
1600 //
1601 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1602 // with judicious parameters one can create window stations elsewhere
1603 // than in Windows\WindowStations directory, Win32k definitely MUST
1604 // maintain a list of window stations it has created, and not rely
1605 // on the enumeration of Windows\WindowStations !!!
1606 //
1607
1608 /*
1609 * Try to open the directory.
1610 */
1611 InitializeObjectAttributes(&ObjectAttributes,
1612 &gustrWindowStationsDir,
1613 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1614 NULL,
1615 NULL);
1616
1617 Status = ZwOpenDirectoryObject(&DirectoryHandle,
1618 DIRECTORY_QUERY,
1619 &ObjectAttributes);
1620
1621 if (!NT_SUCCESS(Status))
1622 {
1623 return Status;
1624 }
1625
1626 /* First try to query the directory using a fixed-size buffer */
1627 Context = 0;
1628 Buffer = NULL;
1629 Status = ZwQueryDirectoryObject(DirectoryHandle,
1630 InitialBuffer,
1631 sizeof(InitialBuffer),
1632 FALSE,
1633 TRUE,
1634 &Context,
1635 &ReturnLength);
1636 if (NT_SUCCESS(Status))
1637 {
1638 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1639 FALSE, &Context, NULL))
1640 {
1641 /* Our fixed-size buffer is large enough */
1642 Buffer = InitialBuffer;
1643 }
1644 }
1645
1646 if (NULL == Buffer)
1647 {
1648 /* Need a larger buffer, check how large exactly */
1649 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1650 &ReturnLength);
1651 if (!NT_SUCCESS(Status))
1652 {
1653 ERR("ZwQueryDirectoryObject failed\n");
1654 ZwClose(DirectoryHandle);
1655 return Status;
1656 }
1657
1658 BufferSize = ReturnLength;
1659 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1660 if (NULL == Buffer)
1661 {
1662 ZwClose(DirectoryHandle);
1663 return STATUS_NO_MEMORY;
1664 }
1665
1666 /* We should have a sufficiently large buffer now */
1667 Context = 0;
1668 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1669 FALSE, TRUE, &Context, &ReturnLength);
1670 if (! NT_SUCCESS(Status) ||
1671 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1672 FALSE, &Context, NULL))
1673 {
1674 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1675 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1676 ZwClose(DirectoryHandle);
1677 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1678 }
1679 }
1680
1681 ZwClose(DirectoryHandle);
1682
1683 /*
1684 * Count the required size of buffer.
1685 */
1686 ReturnLength = sizeof(DWORD);
1687 EntryCount = 0;
1688 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1689 0 != DirEntry->Name.Length;
1690 DirEntry++)
1691 {
1692 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1693 EntryCount++;
1694 }
1695 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1696 if (NULL != pRequiredSize)
1697 {
1698 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1699 if (! NT_SUCCESS(Status))
1700 {
1701 if (Buffer != InitialBuffer)
1702 {
1703 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1704 }
1705 return STATUS_BUFFER_TOO_SMALL;
1706 }
1707 }
1708
1709 /*
1710 * Check if the supplied buffer is large enough.
1711 */
1712 if (dwSize < ReturnLength)
1713 {
1714 if (Buffer != InitialBuffer)
1715 {
1716 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1717 }
1718 return STATUS_BUFFER_TOO_SMALL;
1719 }
1720
1721 /*
1722 * Generate the resulting buffer contents.
1723 */
1724 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1725 if (! NT_SUCCESS(Status))
1726 {
1727 if (Buffer != InitialBuffer)
1728 {
1729 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1730 }
1731 return Status;
1732 }
1733 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1734
1735 NullWchar = L'\0';
1736 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1737 0 != DirEntry->Name.Length;
1738 DirEntry++)
1739 {
1740 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1741 if (! NT_SUCCESS(Status))
1742 {
1743 if (Buffer != InitialBuffer)
1744 {
1745 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1746 }
1747 return Status;
1748 }
1749 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1750 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1751 if (! NT_SUCCESS(Status))
1752 {
1753 if (Buffer != InitialBuffer)
1754 {
1755 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1756 }
1757 return Status;
1758 }
1759 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1760 }
1761
1762 /*
1763 * Clean up
1764 */
1765 if (Buffer != InitialBuffer)
1766 {
1767 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1768 }
1769
1770 return STATUS_SUCCESS;
1771 }
1772
1773 static NTSTATUS FASTCALL
1774 BuildDesktopNameList(
1775 HWINSTA hWindowStation,
1776 ULONG dwSize,
1777 PVOID lpBuffer,
1778 PULONG pRequiredSize)
1779 {
1780 NTSTATUS Status;
1781 PWINSTATION_OBJECT WindowStation;
1782 PLIST_ENTRY DesktopEntry;
1783 PDESKTOP DesktopObject;
1784 DWORD EntryCount;
1785 ULONG ReturnLength;
1786 WCHAR NullWchar;
1787 UNICODE_STRING DesktopName;
1788
1789 Status = IntValidateWindowStationHandle(hWindowStation,
1790 UserMode,
1791 0,
1792 &WindowStation,
1793 NULL);
1794 if (! NT_SUCCESS(Status))
1795 {
1796 return Status;
1797 }
1798
1799 /*
1800 * Count the required size of buffer.
1801 */
1802 ReturnLength = sizeof(DWORD);
1803 EntryCount = 0;
1804 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1805 DesktopEntry != &WindowStation->DesktopListHead;
1806 DesktopEntry = DesktopEntry->Flink)
1807 {
1808 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1809 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1810 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1811 EntryCount++;
1812 }
1813 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1814 if (NULL != pRequiredSize)
1815 {
1816 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1817 if (! NT_SUCCESS(Status))
1818 {
1819 ObDereferenceObject(WindowStation);
1820 return STATUS_BUFFER_TOO_SMALL;
1821 }
1822 }
1823
1824 /*
1825 * Check if the supplied buffer is large enough.
1826 */
1827 if (dwSize < ReturnLength)
1828 {
1829 ObDereferenceObject(WindowStation);
1830 return STATUS_BUFFER_TOO_SMALL;
1831 }
1832
1833 /*
1834 * Generate the resulting buffer contents.
1835 */
1836 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1837 if (! NT_SUCCESS(Status))
1838 {
1839 ObDereferenceObject(WindowStation);
1840 return Status;
1841 }
1842 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1843
1844 NullWchar = L'\0';
1845 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1846 DesktopEntry != &WindowStation->DesktopListHead;
1847 DesktopEntry = DesktopEntry->Flink)
1848 {
1849 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1850 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1851 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1852 if (! NT_SUCCESS(Status))
1853 {
1854 ObDereferenceObject(WindowStation);
1855 return Status;
1856 }
1857 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1858 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1859 if (! NT_SUCCESS(Status))
1860 {
1861 ObDereferenceObject(WindowStation);
1862 return Status;
1863 }
1864 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1865 }
1866
1867 /*
1868 * Clean up and return
1869 */
1870 ObDereferenceObject(WindowStation);
1871 return STATUS_SUCCESS;
1872 }
1873
1874 /*
1875 * NtUserBuildNameList
1876 *
1877 * Function used for enumeration of desktops or window stations.
1878 *
1879 * Parameters
1880 * hWinSta
1881 * For enumeration of window stations this parameter must be set to
1882 * zero. Otherwise it's handle for window station.
1883 *
1884 * dwSize
1885 * Size of buffer passed by caller.
1886 *
1887 * lpBuffer
1888 * Buffer passed by caller. If the function succeeds, the buffer is
1889 * filled with window station/desktop count (in first DWORD) and
1890 * NULL-terminated window station/desktop names.
1891 *
1892 * pRequiredSize
1893 * If the function succeeds, this is the number of bytes copied.
1894 * Otherwise it's size of buffer needed for function to succeed.
1895 *
1896 * Status
1897 * @implemented
1898 */
1899
1900 NTSTATUS APIENTRY
1901 NtUserBuildNameList(
1902 HWINSTA hWindowStation,
1903 ULONG dwSize,
1904 PVOID lpBuffer,
1905 PULONG pRequiredSize)
1906 {
1907 /* The WindowStation name list and desktop name list are build in completely
1908 different ways. Call the appropriate function */
1909 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1910 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1911 }
1912
1913 /*
1914 * @implemented
1915 */
1916 BOOL APIENTRY
1917 NtUserSetLogonNotifyWindow(HWND hWnd)
1918 {
1919 if (gpidLogon != PsGetCurrentProcessId())
1920 {
1921 return FALSE;
1922 }
1923
1924 if (!IntIsWindow(hWnd))
1925 {
1926 return FALSE;
1927 }
1928
1929 hwndSAS = hWnd;
1930
1931 return TRUE;
1932 }
1933
1934 BOOL
1935 APIENTRY
1936 NtUserLockWorkStation(VOID)
1937 {
1938 BOOL ret;
1939 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1940
1941 UserEnterExclusive();
1942
1943 if (pti->rpdesk == IntGetActiveDesktop())
1944 {
1945 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1946 }
1947 else
1948 {
1949 ret = FALSE;
1950 }
1951
1952 UserLeave();
1953
1954 return ret;
1955 }
1956
1957 BOOL
1958 NTAPI
1959 NtUserSetWindowStationUser(
1960 IN HWINSTA hWindowStation,
1961 IN PLUID pluid,
1962 IN PSID psid OPTIONAL,
1963 IN DWORD size)
1964 {
1965 BOOL Ret = FALSE;
1966 NTSTATUS Status;
1967 PWINSTATION_OBJECT WindowStation = NULL;
1968 LUID luidUser;
1969
1970 UserEnterExclusive();
1971
1972 if (gpidLogon != PsGetCurrentProcessId())
1973 {
1974 EngSetLastError(ERROR_ACCESS_DENIED);
1975 goto Leave;
1976 }
1977
1978 /* Validate the window station */
1979 Status = IntValidateWindowStationHandle(hWindowStation,
1980 UserMode,
1981 0,
1982 &WindowStation,
1983 NULL);
1984 if (!NT_SUCCESS(Status))
1985 {
1986 goto Leave;
1987 }
1988
1989 /* Capture the user LUID */
1990 _SEH2_TRY
1991 {
1992 ProbeForRead(pluid, sizeof(LUID), 1);
1993 luidUser = *pluid;
1994 }
1995 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1996 {
1997 Status = _SEH2_GetExceptionCode();
1998 _SEH2_YIELD(goto Leave);
1999 }
2000 _SEH2_END;
2001
2002 /* Reset the window station user LUID */
2003 RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
2004
2005 /* Reset the window station user SID */
2006 if (WindowStation->psidUser)
2007 {
2008 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2009 WindowStation->psidUser = NULL;
2010 }
2011
2012 /* Copy the new user SID if one has been provided */
2013 if (psid)
2014 {
2015 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
2016 if (WindowStation->psidUser == NULL)
2017 {
2018 EngSetLastError(ERROR_OUTOFMEMORY);
2019 goto Leave;
2020 }
2021
2022 Status = STATUS_SUCCESS;
2023 _SEH2_TRY
2024 {
2025 ProbeForRead(psid, size, 1);
2026 RtlCopyMemory(WindowStation->psidUser, psid, size);
2027 }
2028 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2029 {
2030 Status = _SEH2_GetExceptionCode();
2031 }
2032 _SEH2_END;
2033
2034 if (!NT_SUCCESS(Status))
2035 {
2036 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2037 WindowStation->psidUser = NULL;
2038 goto Leave;
2039 }
2040 }
2041
2042 /* Copy the new user LUID */
2043 WindowStation->luidUser = luidUser;
2044
2045 Ret = TRUE;
2046
2047 Leave:
2048 if (WindowStation)
2049 ObDereferenceObject(WindowStation);
2050
2051 UserLeave();
2052 return Ret;
2053 }
2054
2055 /* EOF */