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