xref: /reactos/win32ss/user/ntuser/winsta.c (revision 08d10098)
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 */
2078