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