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