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