xref: /reactos/win32ss/user/ntuser/winsta.c (revision 3c774903)
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 /* Currently active window station */
18 PWINSTATION_OBJECT InputWindowStation = NULL;
19 
20 /* Winlogon SAS window */
21 HWND hwndSAS = NULL;
22 
23 /* Full path to WindowStations directory */
24 UNICODE_STRING gustrWindowStationsDir;
25 
26 /* INITIALIZATION FUNCTIONS ****************************************************/
27 
28 INIT_FUNCTION
29 NTSTATUS
30 NTAPI
31 InitWindowStationImpl(VOID)
32 {
33     GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
34                                                 WINSTA_WRITE,
35                                                 WINSTA_EXECUTE,
36                                                 WINSTA_ACCESS_ALL};
37 
38     /* Set Winsta Object Attributes */
39     ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
40     ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
41     ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
42 
43     return STATUS_SUCCESS;
44 }
45 
46 NTSTATUS
47 NTAPI
48 UserCreateWinstaDirectory(VOID)
49 {
50     PPEB Peb;
51     NTSTATUS Status;
52     WCHAR wstrWindowStationsDir[MAX_PATH];
53     OBJECT_ATTRIBUTES ObjectAttributes;
54     HANDLE hWinstaDir;
55 
56     /* Create the WindowStations directory and cache its path for later use */
57     Peb = NtCurrentPeb();
58     if(Peb->SessionId == 0)
59     {
60         if (!RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR))
61         {
62             return STATUS_INSUFFICIENT_RESOURCES;
63         }
64     }
65     else
66     {
67         swprintf(wstrWindowStationsDir,
68                  L"%ws\\%lu%ws",
69                  SESSION_DIR,
70                  Peb->SessionId,
71                  WINSTA_OBJ_DIR);
72 
73         if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
74         {
75             return STATUS_INSUFFICIENT_RESOURCES;
76         }
77     }
78 
79     InitializeObjectAttributes(&ObjectAttributes,
80                                &gustrWindowStationsDir,
81                                0,
82                                NULL,
83                                NULL);
84     Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes);
85     if (!NT_SUCCESS(Status))
86     {
87         ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir,  Status);
88         return Status;
89     }
90 
91     TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir, Peb->SessionId);
92 
93     return Status;
94 }
95 
96 /* OBJECT CALLBACKS  **********************************************************/
97 
98 NTSTATUS
99 APIENTRY
100 IntWinStaObjectDelete(
101     _In_ PVOID Parameters)
102 {
103     PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
104     PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
105 
106     TRACE("Deleting window station (0x%p)\n", WinSta);
107 
108     WinSta->Flags |= WSS_DYING;
109 
110     UserEmptyClipboardData(WinSta);
111 
112     RtlDestroyAtomTable(WinSta->AtomTable);
113 
114     RtlFreeUnicodeString(&WinSta->Name);
115 
116     return STATUS_SUCCESS;
117 }
118 
119 NTSTATUS
120 APIENTRY
121 IntWinStaObjectParse(
122     _In_ PVOID Parameters)
123 {
124     PWIN32_PARSEMETHOD_PARAMETERS ParseParameters = Parameters;
125     PUNICODE_STRING RemainingName = ParseParameters->RemainingName;
126 
127     /* Assume we don't find anything */
128     *ParseParameters->Object = NULL;
129 
130     /* Check for an empty name */
131     if (!RemainingName->Length)
132     {
133         /* Make sure this is a window station, can't parse a desktop now */
134         if (ParseParameters->ObjectType != ExWindowStationObjectType)
135         {
136             /* Fail */
137             return STATUS_OBJECT_TYPE_MISMATCH;
138         }
139 
140         /* Reference the window station and return */
141         ObReferenceObject(ParseParameters->ParseObject);
142         *ParseParameters->Object = ParseParameters->ParseObject;
143         return STATUS_SUCCESS;
144     }
145 
146     /* Check for leading slash */
147     if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
148     {
149         /* Skip it */
150         RemainingName->Buffer++;
151         RemainingName->Length -= sizeof(WCHAR);
152         RemainingName->MaximumLength -= sizeof(WCHAR);
153     }
154 
155     /* Check if there is still a slash */
156     if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
157     {
158         /* In this case, fail */
159         return STATUS_OBJECT_PATH_INVALID;
160     }
161 
162     /*
163      * Check if we are parsing a desktop.
164      */
165     if (ParseParameters->ObjectType == ExDesktopObjectType)
166     {
167         /* Then call the desktop parse routine */
168         return IntDesktopObjectParse(ParseParameters->ParseObject,
169                                      ParseParameters->ObjectType,
170                                      ParseParameters->AccessState,
171                                      ParseParameters->AccessMode,
172                                      ParseParameters->Attributes,
173                                      ParseParameters->CompleteName,
174                                      RemainingName,
175                                      ParseParameters->Context,
176                                      ParseParameters->SecurityQos,
177                                      ParseParameters->Object);
178     }
179 
180     /* Should hopefully never get here */
181     return STATUS_OBJECT_TYPE_MISMATCH;
182 }
183 
184 NTSTATUS
185 NTAPI
186 IntWinstaOkToClose(
187     _In_ PVOID Parameters)
188 {
189     PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
190     PPROCESSINFO ppi;
191 
192     ppi = PsGetCurrentProcessWin32Process();
193 
194     if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
195     {
196         return STATUS_ACCESS_DENIED;
197     }
198 
199     return STATUS_SUCCESS;
200 }
201 
202 /* PRIVATE FUNCTIONS **********************************************************/
203 
204 /*
205  * IntValidateWindowStationHandle
206  *
207  * Validates the window station handle.
208  *
209  * Remarks
210  *    If the function succeeds, the handle remains referenced. If the
211  *    fucntion fails, last error is set.
212  */
213 
214 NTSTATUS FASTCALL
215 IntValidateWindowStationHandle(
216     HWINSTA WindowStation,
217     KPROCESSOR_MODE AccessMode,
218     ACCESS_MASK DesiredAccess,
219     PWINSTATION_OBJECT *Object,
220     POBJECT_HANDLE_INFORMATION pObjectHandleInfo)
221 {
222     NTSTATUS Status;
223 
224     if (WindowStation == NULL)
225     {
226         ERR("Invalid window station handle\n");
227         EngSetLastError(ERROR_INVALID_HANDLE);
228         return STATUS_INVALID_HANDLE;
229     }
230 
231     Status = ObReferenceObjectByHandle(WindowStation,
232                                        DesiredAccess,
233                                        ExWindowStationObjectType,
234                                        AccessMode,
235                                        (PVOID*)Object,
236                                        pObjectHandleInfo);
237 
238     if (!NT_SUCCESS(Status))
239         SetLastNtError(Status);
240 
241     return Status;
242 }
243 
244 BOOL FASTCALL
245 co_IntInitializeDesktopGraphics(VOID)
246 {
247     TEXTMETRICW tmw;
248     UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
249     PDESKTOP pdesk;
250 
251     ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
252     if (NULL == ScreenDeviceContext)
253     {
254         IntDestroyPrimarySurface();
255         return FALSE;
256     }
257     GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
258 
259     if (! IntCreatePrimarySurface())
260     {
261         return FALSE;
262     }
263 
264     hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
265 
266     NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
267     GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
268 
269     /* Update the SERVERINFO */
270     gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
271     gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
272     gpsi->Planes        = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
273     gpsi->BitsPixel     = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
274     gpsi->BitCount      = gpsi->Planes * gpsi->BitsPixel;
275     gpsi->dmLogPixels   = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
276     if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
277     {
278         gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
279     }
280     else
281         gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
282     // Font is realized and this dc was previously set to internal DC_ATTR.
283     gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
284     gpsi->tmSysFont     = tmw;
285 
286     /* Put the pointer in the center of the screen */
287     gpsi->ptCursor.x = gpsi->aiSysMet[SM_CXSCREEN] / 2;
288     gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
289 
290     /* Attach monitor */
291     UserAttachMonitor((HDEV)gppdevPrimary);
292 
293     /* Setup the cursor */
294     co_IntLoadDefaultCursors();
295 
296     /* Setup the icons */
297     co_IntSetWndIcons();
298 
299     /* Setup Menu */
300     MenuInit();
301 
302     /* Show the desktop */
303     pdesk = IntGetActiveDesktop();
304     ASSERT(pdesk);
305     co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
306 
307     return TRUE;
308 }
309 
310 VOID FASTCALL
311 IntEndDesktopGraphics(VOID)
312 {
313     if (NULL != ScreenDeviceContext)
314     {  // No need to allocate a new dcattr.
315         GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
316         GreDeleteObject(ScreenDeviceContext);
317         ScreenDeviceContext = NULL;
318     }
319     IntHideDesktop(IntGetActiveDesktop());
320     IntDestroyPrimarySurface();
321 }
322 
323 HDC FASTCALL
324 IntGetScreenDC(VOID)
325 {
326     return ScreenDeviceContext;
327 }
328 
329 BOOL FASTCALL
330 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
331 {
332     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
333     if ( gpidLogon != PsGetCurrentProcessId() )
334     {
335         if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
336         {
337             ERR("Requires Interactive Window Station\n");
338             EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
339             return FALSE;
340         }
341         if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
342         {
343             ERR("Access Denied\n");
344             EngSetLastError(ERROR_ACCESS_DENIED);
345             return FALSE;
346         }
347     }
348     return TRUE;
349 }
350 
351 
352 /* PUBLIC FUNCTIONS ***********************************************************/
353 
354 /*
355  * NtUserCreateWindowStation
356  *
357  * Creates a new window station.
358  *
359  * Parameters
360  *    lpszWindowStationName
361  *       Pointer to a null-terminated string specifying the name of the
362  *       window station to be created. Window station names are
363  *       case-insensitive and cannot contain backslash characters (\).
364  *       Only members of the Administrators group are allowed to specify a
365  *       name.
366  *
367  *    dwDesiredAccess
368  *       Requested type of access
369  *
370  *    lpSecurity
371  *       Security descriptor
372  *
373  *    Unknown3, Unknown4, Unknown5
374  *       Unused
375  *
376  * Return Value
377  *    If the function succeeds, the return value is a handle to the newly
378  *    created window station. If the specified window station already
379  *    exists, the function succeeds and returns a handle to the existing
380  *    window station. If the function fails, the return value is NULL.
381  *
382  * Todo
383  *    Correct the prototype to match the Windows one (with 7 parameters
384  *    on Windows XP).
385  *
386  * Status
387  *    @implemented
388  */
389 
390 HWINSTA APIENTRY
391 NtUserCreateWindowStation(
392     POBJECT_ATTRIBUTES ObjectAttributes,
393     ACCESS_MASK dwDesiredAccess,
394     DWORD Unknown2,
395     DWORD Unknown3,
396     DWORD Unknown4,
397     DWORD Unknown5,
398     DWORD Unknown6)
399 {
400     UNICODE_STRING WindowStationName;
401     PWINSTATION_OBJECT WindowStationObject;
402     HWINSTA WindowStation;
403     NTSTATUS Status;
404 
405     TRACE("NtUserCreateWindowStation called\n");
406 
407     Status = ObOpenObjectByName(ObjectAttributes,
408                                 ExWindowStationObjectType,
409                                 UserMode,
410                                 NULL,
411                                 dwDesiredAccess,
412                                 NULL,
413                                 (PVOID*)&WindowStation);
414 
415     if (NT_SUCCESS(Status))
416     {
417         TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName);
418         return (HWINSTA)WindowStation;
419     }
420 
421     /*
422      * No existing window station found, try to create new one
423      */
424 
425     /* Capture window station name */
426     _SEH2_TRY
427     {
428         ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
429         Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName);
430     }
431     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
432     {
433         Status =_SEH2_GetExceptionCode();
434     }
435     _SEH2_END
436 
437     if (! NT_SUCCESS(Status))
438     {
439         ERR("Failed reading capturing window station name\n");
440         SetLastNtError(Status);
441         return NULL;
442     }
443 
444     /* Create the window station object */
445     Status = ObCreateObject(UserMode,
446                             ExWindowStationObjectType,
447                             ObjectAttributes,
448                             UserMode,
449                             NULL,
450                             sizeof(WINSTATION_OBJECT),
451                             0,
452                             0,
453                             (PVOID*)&WindowStationObject);
454 
455     if (!NT_SUCCESS(Status))
456     {
457         ERR("ObCreateObject failed with %lx for window station %wZ\n", Status, &WindowStationName);
458         ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
459         SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
460         return 0;
461     }
462 
463     /* Initialize the window station */
464     RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
465 
466     InitializeListHead(&WindowStationObject->DesktopListHead);
467     WindowStationObject->Name = WindowStationName;
468     WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
469     Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
470     if (!NT_SUCCESS(Status))
471     {
472         ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, &WindowStationName);
473         ObDereferenceObject(WindowStationObject);
474         SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
475         return 0;
476     }
477 
478     Status = ObInsertObject((PVOID)WindowStationObject,
479                             NULL,
480                             dwDesiredAccess,
481                             0,
482                             NULL,
483                             (PVOID*)&WindowStation);
484 
485     if (!NT_SUCCESS(Status))
486     {
487         ERR("ObInsertObject failed with %lx for window station\n", Status);
488         SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
489         return 0;
490     }
491 
492     if (InputWindowStation == NULL)
493     {
494         ERR("Initializing input window station\n");
495         InputWindowStation = WindowStationObject;
496 
497         WindowStationObject->Flags &= ~WSS_NOIO;
498 
499         InitCursorImpl();
500     }
501     else
502     {
503         WindowStationObject->Flags |= WSS_NOIO;
504     }
505 
506     TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
507           WindowStation, &WindowStationObject->Name, WindowStation);
508     return WindowStation;
509 }
510 
511 /*
512  * NtUserOpenWindowStation
513  *
514  * Opens an existing window station.
515  *
516  * Parameters
517  *    lpszWindowStationName
518  *       Name of the existing window station.
519  *
520  *    dwDesiredAccess
521  *       Requested type of access.
522  *
523  * Return Value
524  *    If the function succeeds, the return value is the handle to the
525  *    specified window station. If the function fails, the return value
526  *    is NULL.
527  *
528  * Remarks
529  *    The returned handle can be closed with NtUserCloseWindowStation.
530  *
531  * Status
532  *    @implemented
533  */
534 
535 HWINSTA APIENTRY
536 NtUserOpenWindowStation(
537     POBJECT_ATTRIBUTES ObjectAttributes,
538     ACCESS_MASK dwDesiredAccess)
539 {
540     HWINSTA hwinsta;
541     NTSTATUS Status;
542 
543     Status = ObOpenObjectByName(ObjectAttributes,
544                                 ExWindowStationObjectType,
545                                 UserMode,
546                                 NULL,
547                                 dwDesiredAccess,
548                                 NULL,
549                                 (PVOID*)&hwinsta);
550 
551     if (!NT_SUCCESS(Status))
552     {
553         ERR("NtUserOpenWindowStation failed\n");
554         SetLastNtError(Status);
555         return 0;
556     }
557 
558     TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
559 
560     return hwinsta;
561 }
562 
563 /*
564  * NtUserCloseWindowStation
565  *
566  * Closes a window station handle.
567  *
568  * Parameters
569  *    hWinSta
570  *       Handle to the window station.
571  *
572  * Return Value
573  *    Status
574  *
575  * Remarks
576  *    The window station handle can be created with NtUserCreateWindowStation
577  *    or NtUserOpenWindowStation. Attemps to close a handle to the window
578  *    station assigned to the calling process will fail.
579  *
580  * Status
581  *    @implemented
582  */
583 
584 BOOL
585 APIENTRY
586 NtUserCloseWindowStation(
587     HWINSTA hWinSta)
588 {
589     PWINSTATION_OBJECT Object;
590     NTSTATUS Status;
591 
592     TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
593 
594     if (hWinSta == UserGetProcessWindowStation())
595     {
596         ERR("Attempted to close process window station\n");
597         return FALSE;
598     }
599 
600     Status = IntValidateWindowStationHandle(hWinSta,
601                                             UserMode,
602                                             0,
603                                             &Object,
604                                             0);
605 
606     if (!NT_SUCCESS(Status))
607     {
608         ERR("Validation of window station handle (%p) failed\n", hWinSta);
609         return FALSE;
610     }
611 
612     ObDereferenceObject(Object);
613 
614     TRACE("Closing window station handle (%p)\n", hWinSta);
615 
616     Status = ObCloseHandle(hWinSta, UserMode);
617     if (!NT_SUCCESS(Status))
618     {
619         SetLastNtError(Status);
620         return FALSE;
621     }
622 
623     return TRUE;
624 }
625 
626 /*
627  * NtUserGetObjectInformation
628  *
629  * The NtUserGetObjectInformation function retrieves information about a
630  * window station or desktop object.
631  *
632  * Parameters
633  *    hObj
634  *       Handle to the window station or desktop object for which to
635  *       return information. This can be a handle of type HDESK or HWINSTA
636  *       (for example, a handle returned by NtUserCreateWindowStation,
637  *       NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
638  *
639  *    nIndex
640  *       Specifies the object information to be retrieved.
641  *
642  *    pvInfo
643  *       Pointer to a buffer to receive the object information.
644  *
645  *    nLength
646  *       Specifies the size, in bytes, of the buffer pointed to by the
647  *       pvInfo parameter.
648  *
649  *    lpnLengthNeeded
650  *       Pointer to a variable receiving the number of bytes required to
651  *       store the requested information. If this variable's value is
652  *       greater than the value of the nLength parameter when the function
653  *       returns, the function returns FALSE, and none of the information
654  *       is copied to the pvInfo buffer. If the value of the variable pointed
655  *       to by lpnLengthNeeded is less than or equal to the value of nLength,
656  *       the entire information block is copied.
657  *
658  * Return Value
659  *    If the function succeeds, the return value is nonzero. If the function
660  *    fails, the return value is zero.
661  *
662  * Status
663  *    @unimplemented
664  */
665 
666 BOOL APIENTRY
667 NtUserGetObjectInformation(
668     HANDLE hObject,
669     DWORD nIndex,
670     PVOID pvInformation,
671     DWORD nLength,
672     PDWORD nLengthNeeded)
673 {
674     NTSTATUS Status;
675     PWINSTATION_OBJECT WinStaObject = NULL;
676     PDESKTOP DesktopObject = NULL;
677     USEROBJECTFLAGS ObjectFlags;
678     PVOID pvData = NULL;
679     SIZE_T nDataSize = 0;
680 
681     _SEH2_TRY
682     {
683         if (nLengthNeeded)
684             ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
685         ProbeForWrite(pvInformation, nLength, 1);
686     }
687     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
688     {
689         SetLastNtError(_SEH2_GetExceptionCode());
690         return FALSE;
691     }
692     _SEH2_END;
693 
694     /* Try window station */
695     TRACE("Trying to open window station %p\n", hObject);
696     Status = ObReferenceObjectByHandle(hObject,
697                                        0,
698                                        ExWindowStationObjectType,
699                                        UserMode,
700                                        (PVOID*)&WinStaObject,
701                                        NULL);
702 
703     if (Status == STATUS_OBJECT_TYPE_MISMATCH)
704     {
705         /* Try desktop */
706         TRACE("Trying to open desktop %p\n", hObject);
707         WinStaObject = NULL;
708         Status = IntValidateDesktopHandle(hObject,
709                                           UserMode,
710                                           0,
711                                           &DesktopObject);
712     }
713 
714     if (!NT_SUCCESS(Status))
715     {
716         ERR("Failed: 0x%x\n", Status);
717         goto Exit;
718     }
719 
720     TRACE("WinSta or Desktop opened!!\n");
721 
722     /* Get data */
723     switch (nIndex)
724     {
725         case UOI_FLAGS:
726         {
727             /* This is a default implementation that does almost nothing */
728             ObjectFlags.fInherit = FALSE;
729             ObjectFlags.fReserved = FALSE;
730             ObjectFlags.dwFlags = 0;
731 
732             pvData = &ObjectFlags;
733             nDataSize = sizeof(ObjectFlags);
734             Status = STATUS_SUCCESS;
735             ERR("UOI_FLAGS unimplemented!\n");
736             break;
737         }
738 
739         case UOI_NAME:
740         {
741             if (WinStaObject != NULL)
742             {
743                 pvData = WinStaObject->Name.Buffer;
744                 nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
745                 Status = STATUS_SUCCESS;
746             }
747             else if (DesktopObject != NULL)
748             {
749                 pvData = DesktopObject->pDeskInfo->szDesktopName;
750                 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
751                 Status = STATUS_SUCCESS;
752             }
753             else
754             {
755                 Status = STATUS_INVALID_PARAMETER;
756             }
757             break;
758         }
759 
760         case UOI_TYPE:
761         {
762             if (WinStaObject != NULL)
763             {
764                 pvData = L"WindowStation";
765                 nDataSize = sizeof(L"WindowStation");
766                 Status = STATUS_SUCCESS;
767             }
768             else if (DesktopObject != NULL)
769             {
770                 pvData = L"Desktop";
771                 nDataSize = sizeof(L"Desktop");
772                 Status = STATUS_SUCCESS;
773             }
774             else
775             {
776                 Status = STATUS_INVALID_PARAMETER;
777             }
778             break;
779         }
780 
781         case UOI_USER_SID:
782             Status = STATUS_NOT_IMPLEMENTED;
783             ERR("UOI_USER_SID unimplemented!\n");
784             break;
785 
786         default:
787             Status = STATUS_INVALID_PARAMETER;
788             break;
789     }
790 
791 Exit:
792     if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
793         Status = STATUS_BUFFER_TOO_SMALL;
794 
795     _SEH2_TRY
796     {
797         if (nLengthNeeded)
798             *nLengthNeeded = nDataSize;
799 
800         /* Try to copy data to caller */
801         if (Status == STATUS_SUCCESS)
802         {
803             TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
804             RtlCopyMemory(pvInformation, pvData, nDataSize);
805         }
806     }
807     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
808     {
809         Status = _SEH2_GetExceptionCode();
810     }
811     _SEH2_END;
812 
813     /* Release objects */
814     if (DesktopObject != NULL)
815         ObDereferenceObject(DesktopObject);
816     if (WinStaObject != NULL)
817         ObDereferenceObject(WinStaObject);
818 
819     if (!NT_SUCCESS(Status))
820     {
821         SetLastNtError(Status);
822         return FALSE;
823     }
824 
825     return TRUE;
826 }
827 
828 /*
829  * NtUserSetObjectInformation
830  *
831  * The NtUserSetObjectInformation function sets information about a
832  * window station or desktop object.
833  *
834  * Parameters
835  *    hObj
836  *       Handle to the window station or desktop object for which to set
837  *       object information. This value can be a handle of type HDESK or
838  *       HWINSTA.
839  *
840  *    nIndex
841  *       Specifies the object information to be set.
842  *
843  *    pvInfo
844  *       Pointer to a buffer containing the object information.
845  *
846  *    nLength
847  *       Specifies the size, in bytes, of the information contained in the
848  *       buffer pointed to by pvInfo.
849  *
850  * Return Value
851  *    If the function succeeds, the return value is nonzero. If the function
852  *    fails the return value is zero.
853  *
854  * Status
855  *    @unimplemented
856  */
857 
858 BOOL
859 APIENTRY
860 NtUserSetObjectInformation(
861     HANDLE hObject,
862     DWORD nIndex,
863     PVOID pvInformation,
864     DWORD nLength)
865 {
866     /* FIXME: ZwQueryObject */
867     /* FIXME: ZwSetInformationObject */
868     SetLastNtError(STATUS_UNSUCCESSFUL);
869     return FALSE;
870 }
871 
872 
873 
874 
875 HWINSTA FASTCALL
876 UserGetProcessWindowStation(VOID)
877 {
878     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
879 
880     return ppi->hwinsta;
881 }
882 
883 
884 /*
885  * NtUserGetProcessWindowStation
886  *
887  * Returns a handle to the current process window station.
888  *
889  * Return Value
890  *    If the function succeeds, the return value is handle to the window
891  *    station assigned to the current process. If the function fails, the
892  *    return value is NULL.
893  *
894  * Status
895  *    @implemented
896  */
897 
898 HWINSTA APIENTRY
899 NtUserGetProcessWindowStation(VOID)
900 {
901     return UserGetProcessWindowStation();
902 }
903 
904 BOOL FASTCALL
905 UserSetProcessWindowStation(HWINSTA hWindowStation)
906 {
907     PPROCESSINFO ppi;
908     NTSTATUS Status;
909     HWINSTA hwinstaOld;
910     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
911     PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
912 
913     ppi = PsGetCurrentProcessWin32Process();
914 
915     /* Reference the new window station */
916     if(hWindowStation !=NULL)
917     {
918         Status = IntValidateWindowStationHandle(hWindowStation,
919                                                 UserMode,
920                                                 0,
921                                                 &NewWinSta,
922                                                 &ObjectHandleInfo);
923         if (!NT_SUCCESS(Status))
924         {
925             TRACE("Validation of window station handle (%p) failed\n",
926                   hWindowStation);
927             SetLastNtError(Status);
928             return FALSE;
929         }
930     }
931 
932     OldWinSta = ppi->prpwinsta;
933     hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
934 
935     /* Dereference the previous window station */
936     if(OldWinSta != NULL)
937     {
938         ObDereferenceObject(OldWinSta);
939     }
940 
941     /* Check if we have a stale handle (it should happen for console apps) */
942     if(hwinstaOld != ppi->hwinsta)
943     {
944         ObCloseHandle(hwinstaOld, UserMode);
945     }
946 
947     /*
948      * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
949      */
950 
951     PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
952 
953     ppi->prpwinsta = NewWinSta;
954     ppi->hwinsta = hWindowStation;
955     ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
956     TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
957 
958     if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
959     {
960         ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
961     }
962     else
963     {
964         ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
965     }
966 
967     if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
968     {
969         ppi->W32PF_flags |= W32PF_IOWINSTA;
970     }
971     else // Might be closed if the handle is null.
972     {
973         ppi->W32PF_flags &= ~W32PF_IOWINSTA;
974     }
975     return TRUE;
976 }
977 
978 /*
979  * NtUserSetProcessWindowStation
980  *
981  * Assigns a window station to the current process.
982  *
983  * Parameters
984  *    hWinSta
985  *       Handle to the window station.
986  *
987  * Return Value
988  *    Status
989  *
990  * Status
991  *    @implemented
992  */
993 
994 BOOL APIENTRY
995 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
996 {
997     BOOL ret;
998 
999     UserEnterExclusive();
1000 
1001     ret = UserSetProcessWindowStation(hWindowStation);
1002 
1003     UserLeave();
1004 
1005     return ret;
1006 }
1007 
1008 /*
1009  * NtUserLockWindowStation
1010  *
1011  * Locks switching desktops. Only the logon application is allowed to call this function.
1012  *
1013  * Status
1014  *    @implemented
1015  */
1016 
1017 BOOL APIENTRY
1018 NtUserLockWindowStation(HWINSTA hWindowStation)
1019 {
1020     PWINSTATION_OBJECT Object;
1021     NTSTATUS Status;
1022 
1023     TRACE("About to set process window station with handle (%p)\n",
1024           hWindowStation);
1025 
1026     if (gpidLogon != PsGetCurrentProcessId())
1027     {
1028         ERR("Unauthorized process attempted to lock the window station!\n");
1029         EngSetLastError(ERROR_ACCESS_DENIED);
1030         return FALSE;
1031     }
1032 
1033     Status = IntValidateWindowStationHandle(hWindowStation,
1034                                             UserMode,
1035                                             0,
1036                                             &Object,
1037                                             0);
1038     if (!NT_SUCCESS(Status))
1039     {
1040         TRACE("Validation of window station handle (%p) failed\n",
1041               hWindowStation);
1042         SetLastNtError(Status);
1043         return FALSE;
1044     }
1045 
1046     Object->Flags |= WSS_LOCKED;
1047 
1048     ObDereferenceObject(Object);
1049     return TRUE;
1050 }
1051 
1052 /*
1053  * NtUserUnlockWindowStation
1054  *
1055  * Unlocks switching desktops. Only the logon application is allowed to call this function.
1056  *
1057  * Status
1058  *    @implemented
1059  */
1060 
1061 BOOL APIENTRY
1062 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1063 {
1064     PWINSTATION_OBJECT Object;
1065     NTSTATUS Status;
1066     BOOL Ret;
1067 
1068     TRACE("About to set process window station with handle (%p)\n",
1069           hWindowStation);
1070 
1071     if (gpidLogon != PsGetCurrentProcessId())
1072     {
1073         ERR("Unauthorized process attempted to unlock the window station!\n");
1074         EngSetLastError(ERROR_ACCESS_DENIED);
1075         return FALSE;
1076     }
1077 
1078     Status = IntValidateWindowStationHandle(hWindowStation,
1079                                             UserMode,
1080                                             0,
1081                                             &Object,
1082                                             0);
1083     if (!NT_SUCCESS(Status))
1084     {
1085         TRACE("Validation of window station handle (%p) failed\n",
1086               hWindowStation);
1087         SetLastNtError(Status);
1088         return FALSE;
1089     }
1090 
1091     Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1092     Object->Flags &= ~WSS_LOCKED;
1093 
1094     ObDereferenceObject(Object);
1095     return Ret;
1096 }
1097 
1098 static NTSTATUS FASTCALL
1099 BuildWindowStationNameList(
1100     ULONG dwSize,
1101     PVOID lpBuffer,
1102     PULONG pRequiredSize)
1103 {
1104     OBJECT_ATTRIBUTES ObjectAttributes;
1105     NTSTATUS Status;
1106     HANDLE DirectoryHandle;
1107     char InitialBuffer[256], *Buffer;
1108     ULONG Context, ReturnLength, BufferSize;
1109     DWORD EntryCount;
1110     POBJECT_DIRECTORY_INFORMATION DirEntry;
1111     WCHAR NullWchar;
1112 
1113     /*
1114      * Try to open the directory.
1115      */
1116     InitializeObjectAttributes(&ObjectAttributes,
1117                                &gustrWindowStationsDir,
1118                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1119                                NULL,
1120                                NULL);
1121 
1122     Status = ZwOpenDirectoryObject(&DirectoryHandle,
1123                                    DIRECTORY_QUERY,
1124                                    &ObjectAttributes);
1125 
1126     if (!NT_SUCCESS(Status))
1127     {
1128         return Status;
1129     }
1130 
1131     /* First try to query the directory using a fixed-size buffer */
1132     Context = 0;
1133     Buffer = NULL;
1134     Status = ZwQueryDirectoryObject(DirectoryHandle,
1135                                     InitialBuffer,
1136                                     sizeof(InitialBuffer),
1137                                     FALSE,
1138                                     TRUE,
1139                                     &Context,
1140                                     &ReturnLength);
1141     if (NT_SUCCESS(Status))
1142     {
1143         if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1144                                                              FALSE, &Context, NULL))
1145         {
1146             /* Our fixed-size buffer is large enough */
1147             Buffer = InitialBuffer;
1148         }
1149     }
1150 
1151     if (NULL == Buffer)
1152     {
1153         /* Need a larger buffer, check how large exactly */
1154         Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1155                                         &ReturnLength);
1156         if (!NT_SUCCESS(Status))
1157         {
1158             ERR("ZwQueryDirectoryObject failed\n");
1159             ZwClose(DirectoryHandle);
1160             return Status;
1161         }
1162 
1163         BufferSize = ReturnLength;
1164         Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1165         if (NULL == Buffer)
1166         {
1167             ZwClose(DirectoryHandle);
1168             return STATUS_NO_MEMORY;
1169         }
1170 
1171         /* We should have a sufficiently large buffer now */
1172         Context = 0;
1173         Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1174                                         FALSE, TRUE, &Context, &ReturnLength);
1175         if (! NT_SUCCESS(Status) ||
1176               STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1177                                                                FALSE, &Context, NULL))
1178         {
1179             /* Something went wrong, maybe someone added a directory entry? Just give up. */
1180             ExFreePoolWithTag(Buffer, TAG_WINSTA);
1181             ZwClose(DirectoryHandle);
1182             return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1183         }
1184     }
1185 
1186     ZwClose(DirectoryHandle);
1187 
1188     /*
1189      * Count the required size of buffer.
1190      */
1191     ReturnLength = sizeof(DWORD);
1192     EntryCount = 0;
1193     for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1194          0 != DirEntry->Name.Length;
1195          DirEntry++)
1196     {
1197         ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1198         EntryCount++;
1199     }
1200     TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1201     if (NULL != pRequiredSize)
1202     {
1203         Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1204         if (! NT_SUCCESS(Status))
1205         {
1206             if (Buffer != InitialBuffer)
1207             {
1208                 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1209             }
1210             return STATUS_BUFFER_TOO_SMALL;
1211         }
1212     }
1213 
1214     /*
1215      * Check if the supplied buffer is large enough.
1216      */
1217     if (dwSize < ReturnLength)
1218     {
1219         if (Buffer != InitialBuffer)
1220         {
1221             ExFreePoolWithTag(Buffer, TAG_WINSTA);
1222         }
1223         return STATUS_BUFFER_TOO_SMALL;
1224     }
1225 
1226     /*
1227      * Generate the resulting buffer contents.
1228      */
1229     Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1230     if (! NT_SUCCESS(Status))
1231     {
1232         if (Buffer != InitialBuffer)
1233         {
1234             ExFreePoolWithTag(Buffer, TAG_WINSTA);
1235         }
1236         return Status;
1237     }
1238     lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1239 
1240     NullWchar = L'\0';
1241     for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1242          0 != DirEntry->Name.Length;
1243          DirEntry++)
1244     {
1245         Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1246         if (! NT_SUCCESS(Status))
1247         {
1248             if (Buffer != InitialBuffer)
1249             {
1250                 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1251             }
1252             return Status;
1253         }
1254         lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1255         Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1256         if (! NT_SUCCESS(Status))
1257         {
1258             if (Buffer != InitialBuffer)
1259             {
1260                 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1261             }
1262             return Status;
1263         }
1264         lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1265     }
1266 
1267     /*
1268      * Clean up
1269      */
1270     if (Buffer != InitialBuffer)
1271     {
1272         ExFreePoolWithTag(Buffer, TAG_WINSTA);
1273     }
1274 
1275     return STATUS_SUCCESS;
1276 }
1277 
1278 static NTSTATUS FASTCALL
1279 BuildDesktopNameList(
1280     HWINSTA hWindowStation,
1281     ULONG dwSize,
1282     PVOID lpBuffer,
1283     PULONG pRequiredSize)
1284 {
1285     NTSTATUS Status;
1286     PWINSTATION_OBJECT WindowStation;
1287     PLIST_ENTRY DesktopEntry;
1288     PDESKTOP DesktopObject;
1289     DWORD EntryCount;
1290     ULONG ReturnLength;
1291     WCHAR NullWchar;
1292     UNICODE_STRING DesktopName;
1293 
1294     Status = IntValidateWindowStationHandle(hWindowStation,
1295                                             UserMode,
1296                                             0,
1297                                             &WindowStation,
1298                                             0);
1299     if (! NT_SUCCESS(Status))
1300     {
1301         return Status;
1302     }
1303 
1304     /*
1305      * Count the required size of buffer.
1306      */
1307     ReturnLength = sizeof(DWORD);
1308     EntryCount = 0;
1309     for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1310          DesktopEntry != &WindowStation->DesktopListHead;
1311          DesktopEntry = DesktopEntry->Flink)
1312     {
1313         DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1314         RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1315         ReturnLength += DesktopName.Length + sizeof(WCHAR);
1316         EntryCount++;
1317     }
1318     TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1319     if (NULL != pRequiredSize)
1320     {
1321         Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1322         if (! NT_SUCCESS(Status))
1323         {
1324             ObDereferenceObject(WindowStation);
1325             return STATUS_BUFFER_TOO_SMALL;
1326         }
1327     }
1328 
1329     /*
1330      * Check if the supplied buffer is large enough.
1331      */
1332     if (dwSize < ReturnLength)
1333     {
1334         ObDereferenceObject(WindowStation);
1335         return STATUS_BUFFER_TOO_SMALL;
1336     }
1337 
1338     /*
1339      * Generate the resulting buffer contents.
1340      */
1341     Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1342     if (! NT_SUCCESS(Status))
1343     {
1344         ObDereferenceObject(WindowStation);
1345         return Status;
1346     }
1347     lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1348 
1349     NullWchar = L'\0';
1350     for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1351          DesktopEntry != &WindowStation->DesktopListHead;
1352          DesktopEntry = DesktopEntry->Flink)
1353     {
1354         DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1355         RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1356         Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1357         if (! NT_SUCCESS(Status))
1358         {
1359             ObDereferenceObject(WindowStation);
1360             return Status;
1361         }
1362         lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1363         Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1364         if (! NT_SUCCESS(Status))
1365         {
1366             ObDereferenceObject(WindowStation);
1367             return Status;
1368         }
1369         lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1370     }
1371 
1372     /*
1373      * Clean up and return
1374      */
1375     ObDereferenceObject(WindowStation);
1376     return STATUS_SUCCESS;
1377 }
1378 
1379 /*
1380  * NtUserBuildNameList
1381  *
1382  * Function used for enumeration of desktops or window stations.
1383  *
1384  * Parameters
1385  *    hWinSta
1386  *       For enumeration of window stations this parameter must be set to
1387  *       zero. Otherwise it's handle for window station.
1388  *
1389  *    dwSize
1390  *       Size of buffer passed by caller.
1391  *
1392  *    lpBuffer
1393  *       Buffer passed by caller. If the function succeeds, the buffer is
1394  *       filled with window station/desktop count (in first DWORD) and
1395  *       NULL-terminated window station/desktop names.
1396  *
1397  *    pRequiredSize
1398  *       If the function succeeds, this is the number of bytes copied.
1399  *       Otherwise it's size of buffer needed for function to succeed.
1400  *
1401  * Status
1402  *    @implemented
1403  */
1404 
1405 NTSTATUS APIENTRY
1406 NtUserBuildNameList(
1407     HWINSTA hWindowStation,
1408     ULONG dwSize,
1409     PVOID lpBuffer,
1410     PULONG pRequiredSize)
1411 {
1412     /* The WindowStation name list and desktop name list are build in completely
1413        different ways. Call the appropriate function */
1414     return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1415            BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1416 }
1417 
1418 /*
1419  * @implemented
1420  */
1421 BOOL APIENTRY
1422 NtUserSetLogonNotifyWindow(HWND hWnd)
1423 {
1424     if (gpidLogon != PsGetCurrentProcessId())
1425     {
1426         return FALSE;
1427     }
1428 
1429     if (!IntIsWindow(hWnd))
1430     {
1431         return FALSE;
1432     }
1433 
1434     hwndSAS = hWnd;
1435 
1436     return TRUE;
1437 }
1438 
1439 BOOL
1440 APIENTRY
1441 NtUserLockWorkStation(VOID)
1442 {
1443     BOOL ret;
1444     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1445 
1446     UserEnterExclusive();
1447 
1448     if (pti->rpdesk == IntGetActiveDesktop())
1449     {
1450         ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1451     }
1452     else
1453     {
1454         ret = FALSE;
1455     }
1456 
1457     UserLeave();
1458 
1459     return ret;
1460 }
1461 
1462 BOOL APIENTRY
1463 NtUserSetWindowStationUser(
1464     HWINSTA hWindowStation,
1465     PLUID pluid,
1466     PSID psid,
1467     DWORD size)
1468 {
1469     NTSTATUS Status;
1470     PWINSTATION_OBJECT WindowStation = NULL;
1471     BOOL Ret = FALSE;
1472 
1473     UserEnterExclusive();
1474 
1475     if (gpidLogon != PsGetCurrentProcessId())
1476     {
1477         EngSetLastError(ERROR_ACCESS_DENIED);
1478         goto Leave;
1479     }
1480 
1481     Status = IntValidateWindowStationHandle(hWindowStation,
1482                                             UserMode,
1483                                             0,
1484                                             &WindowStation,
1485                                             0);
1486     if (!NT_SUCCESS(Status))
1487     {
1488         goto Leave;
1489     }
1490 
1491     if (WindowStation->psidUser)
1492     {
1493         ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1494     }
1495 
1496     WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
1497     if (WindowStation->psidUser == NULL)
1498     {
1499         EngSetLastError(ERROR_OUTOFMEMORY);
1500         goto Leave;
1501     }
1502 
1503     _SEH2_TRY
1504     {
1505         ProbeForRead( psid, size, 1);
1506         ProbeForRead( pluid, sizeof(LUID), 1);
1507 
1508         RtlCopyMemory(WindowStation->psidUser, psid, size);
1509         WindowStation->luidUser = *pluid;
1510     }
1511     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1512     {
1513         Status = _SEH2_GetExceptionCode();
1514     }
1515     _SEH2_END;
1516 
1517     if (!NT_SUCCESS(Status))
1518     {
1519         ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1520         WindowStation->psidUser = 0;
1521         goto Leave;
1522     }
1523 
1524     Ret = TRUE;
1525 
1526 Leave:
1527     if (WindowStation) ObDereferenceObject(WindowStation);
1528     UserLeave();
1529     return Ret;
1530 }
1531 
1532 
1533 /* EOF */
1534