f373b1cedfc17e7accf9849fd7befdab88e27aab
[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 KPROCESSOR_MODE AccessMode = UserMode;
516
517 TRACE("NtUserCreateWindowStation called\n");
518
519 /* Capture window station name */
520 _SEH2_TRY
521 {
522 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
523 LocalObjectAttributes = *ObjectAttributes;
524 if (LocalObjectAttributes.ObjectName ||
525 LocalObjectAttributes.RootDirectory
526 /* &&
527 LocalObjectAttributes.ObjectName->Buffer &&
528 LocalObjectAttributes.ObjectName->Length > 0 */)
529 {
530 Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName,
531 LocalObjectAttributes.ObjectName);
532 LocalObjectAttributes.ObjectName = &WindowStationName;
533 }
534 else
535 {
536 LocalObjectAttributes.ObjectName = NULL;
537 Status = STATUS_SUCCESS;
538 }
539 }
540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
541 {
542 Status =_SEH2_GetExceptionCode();
543 }
544 _SEH2_END
545
546 if (!NT_SUCCESS(Status))
547 {
548 ERR("Failed reading or capturing window station name, Status 0x%08lx\n", Status);
549 SetLastNtError(Status);
550 return NULL;
551 }
552
553 /*
554 * If the caller did not provide a window station name, build a new one
555 * based on the logon session identifier for the calling process.
556 */
557 if (!LocalObjectAttributes.ObjectName)
558 {
559 LUID CallerLuid;
560 WCHAR ServiceWinStaName[MAX_PATH];
561
562 /* Retrieve the LUID of the current process */
563 Status = GetProcessLuid(NULL, NULL, &CallerLuid);
564 if (!NT_SUCCESS(Status))
565 {
566 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status);
567 SetLastNtError(Status);
568 return NULL;
569 }
570
571 /* Build a valid window station name from the LUID */
572 Status = RtlStringCbPrintfW(ServiceWinStaName,
573 sizeof(ServiceWinStaName),
574 L"%wZ\\Service-0x%x-%x$",
575 &gustrWindowStationsDir,
576 CallerLuid.HighPart,
577 CallerLuid.LowPart);
578 if (!NT_SUCCESS(Status))
579 {
580 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
581 SetLastNtError(Status);
582 return NULL;
583 }
584
585 WindowStationName.Length = wcslen(ServiceWinStaName) * sizeof(WCHAR);
586 WindowStationName.MaximumLength =
587 WindowStationName.Length + sizeof(UNICODE_NULL);
588 WindowStationName.Buffer =
589 ExAllocatePoolWithTag(PagedPool,
590 WindowStationName.MaximumLength,
591 TAG_STRING);
592 if (!WindowStationName.Buffer)
593 {
594 Status = STATUS_NO_MEMORY;
595 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
596 SetLastNtError(Status);
597 return NULL;
598 }
599 RtlStringCbCopyW(WindowStationName.Buffer,
600 WindowStationName.MaximumLength,
601 ServiceWinStaName);
602 LocalObjectAttributes.ObjectName = &WindowStationName;
603 AccessMode = KernelMode;
604 }
605
606 // TODO: Capture and use the SecurityQualityOfService!
607
608 Status = IntCreateWindowStation(&hWinSta,
609 &LocalObjectAttributes,
610 AccessMode,
611 dwDesiredAccess,
612 Unknown2,
613 Unknown3,
614 Unknown4,
615 Unknown5,
616 Unknown6);
617
618 // FIXME! Because in some situations we store the allocated window station name
619 // inside the window station, we must not free it now! We know this fact when
620 // IntCreateWindowStation() sets LocalObjectAttributes.ObjectName to NULL.
621 // This hack must be removed once we just use the stored Ob name instead
622 // (in which case we will always free the allocated name here).
623 if (LocalObjectAttributes.ObjectName)
624 ExFreePoolWithTag(LocalObjectAttributes.ObjectName->Buffer, TAG_STRING);
625
626 if (NT_SUCCESS(Status))
627 {
628 TRACE("NtUserCreateWindowStation created a window station with handle 0x%p\n", hWinSta);
629 }
630 else
631 {
632 ASSERT(hWinSta == NULL);
633 TRACE("NtUserCreateWindowStation failed to create a window station!\n");
634 }
635
636 return hWinSta;
637 }
638
639 /*
640 * NtUserOpenWindowStation
641 *
642 * Opens an existing window station.
643 *
644 * Parameters
645 * lpszWindowStationName
646 * Name of the existing window station.
647 *
648 * dwDesiredAccess
649 * Requested type of access.
650 *
651 * Return Value
652 * If the function succeeds, the return value is the handle to the
653 * specified window station. If the function fails, the return value
654 * is NULL.
655 *
656 * Remarks
657 * The returned handle can be closed with NtUserCloseWindowStation.
658 *
659 * Status
660 * @implemented
661 */
662
663 HWINSTA APIENTRY
664 NtUserOpenWindowStation(
665 POBJECT_ATTRIBUTES ObjectAttributes,
666 ACCESS_MASK dwDesiredAccess)
667 {
668 HWINSTA hwinsta;
669 NTSTATUS Status;
670
671 Status = ObOpenObjectByName(ObjectAttributes,
672 ExWindowStationObjectType,
673 UserMode,
674 NULL,
675 dwDesiredAccess,
676 NULL,
677 (PVOID*)&hwinsta);
678
679 if (!NT_SUCCESS(Status))
680 {
681 ERR("NtUserOpenWindowStation failed\n");
682 SetLastNtError(Status);
683 return 0;
684 }
685
686 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
687
688 return hwinsta;
689 }
690
691 /*
692 * NtUserCloseWindowStation
693 *
694 * Closes a window station handle.
695 *
696 * Parameters
697 * hWinSta
698 * Handle to the window station.
699 *
700 * Return Value
701 * Status
702 *
703 * Remarks
704 * The window station handle can be created with NtUserCreateWindowStation
705 * or NtUserOpenWindowStation. Attemps to close a handle to the window
706 * station assigned to the calling process will fail.
707 *
708 * Status
709 * @implemented
710 */
711
712 BOOL
713 APIENTRY
714 NtUserCloseWindowStation(
715 HWINSTA hWinSta)
716 {
717 PWINSTATION_OBJECT Object;
718 NTSTATUS Status;
719
720 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
721
722 if (hWinSta == UserGetProcessWindowStation())
723 {
724 ERR("Attempted to close process window station\n");
725 return FALSE;
726 }
727
728 Status = IntValidateWindowStationHandle(hWinSta,
729 UserMode,
730 0,
731 &Object,
732 0);
733
734 if (!NT_SUCCESS(Status))
735 {
736 ERR("Validation of window station handle (%p) failed\n", hWinSta);
737 return FALSE;
738 }
739
740 ObDereferenceObject(Object);
741
742 TRACE("Closing window station handle (%p)\n", hWinSta);
743
744 Status = ObCloseHandle(hWinSta, UserMode);
745 if (!NT_SUCCESS(Status))
746 {
747 SetLastNtError(Status);
748 return FALSE;
749 }
750
751 return TRUE;
752 }
753
754 /*
755 * NtUserGetObjectInformation
756 *
757 * The NtUserGetObjectInformation function retrieves information about a
758 * window station or desktop object.
759 *
760 * Parameters
761 * hObj
762 * Handle to the window station or desktop object for which to
763 * return information. This can be a handle of type HDESK or HWINSTA
764 * (for example, a handle returned by NtUserCreateWindowStation,
765 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
766 *
767 * nIndex
768 * Specifies the object information to be retrieved.
769 *
770 * pvInfo
771 * Pointer to a buffer to receive the object information.
772 *
773 * nLength
774 * Specifies the size, in bytes, of the buffer pointed to by the
775 * pvInfo parameter.
776 *
777 * lpnLengthNeeded
778 * Pointer to a variable receiving the number of bytes required to
779 * store the requested information. If this variable's value is
780 * greater than the value of the nLength parameter when the function
781 * returns, the function returns FALSE, and none of the information
782 * is copied to the pvInfo buffer. If the value of the variable pointed
783 * to by lpnLengthNeeded is less than or equal to the value of nLength,
784 * the entire information block is copied.
785 *
786 * Return Value
787 * If the function succeeds, the return value is nonzero. If the function
788 * fails, the return value is zero.
789 *
790 * Status
791 * @unimplemented
792 */
793
794 BOOL APIENTRY
795 NtUserGetObjectInformation(
796 HANDLE hObject,
797 DWORD nIndex,
798 PVOID pvInformation,
799 DWORD nLength,
800 PDWORD nLengthNeeded)
801 {
802 NTSTATUS Status;
803 PWINSTATION_OBJECT WinStaObject = NULL;
804 PDESKTOP DesktopObject = NULL;
805 USEROBJECTFLAGS ObjectFlags;
806 PVOID pvData = NULL;
807 SIZE_T nDataSize = 0;
808
809 _SEH2_TRY
810 {
811 if (nLengthNeeded)
812 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
813 ProbeForWrite(pvInformation, nLength, 1);
814 }
815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
816 {
817 SetLastNtError(_SEH2_GetExceptionCode());
818 return FALSE;
819 }
820 _SEH2_END;
821
822 /* Try window station */
823 TRACE("Trying to open window station %p\n", hObject);
824 Status = ObReferenceObjectByHandle(hObject,
825 0,
826 ExWindowStationObjectType,
827 UserMode,
828 (PVOID*)&WinStaObject,
829 NULL);
830
831 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
832 {
833 /* Try desktop */
834 TRACE("Trying to open desktop %p\n", hObject);
835 WinStaObject = NULL;
836 Status = IntValidateDesktopHandle(hObject,
837 UserMode,
838 0,
839 &DesktopObject);
840 }
841
842 if (!NT_SUCCESS(Status))
843 {
844 ERR("Failed: 0x%x\n", Status);
845 goto Exit;
846 }
847
848 TRACE("WinSta or Desktop opened!\n");
849
850 /* Get data */
851 switch (nIndex)
852 {
853 case UOI_FLAGS:
854 {
855 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
856 ULONG BytesWritten;
857
858 ObjectFlags.fReserved = FALSE;
859
860 /* Check whether this handle is inheritable */
861 Status = ZwQueryObject(hObject,
862 ObjectHandleFlagInformation,
863 &HandleInfo,
864 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
865 &BytesWritten);
866 if (!NT_SUCCESS(Status))
867 {
868 ERR("ZwQueryObject failed, Status 0x%08lx\n", Status);
869 break;
870 }
871 ObjectFlags.fInherit = HandleInfo.Inherit;
872
873 ObjectFlags.dwFlags = 0;
874 if (WinStaObject != NULL)
875 {
876 if (!(WinStaObject->Flags & WSS_NOIO))
877 ObjectFlags.dwFlags |= WSF_VISIBLE;
878 }
879 else if (DesktopObject != NULL)
880 {
881 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
882 }
883 else
884 {
885 ERR("No associated WinStaObject nor DesktopObject!\n");
886 }
887
888 pvData = &ObjectFlags;
889 nDataSize = sizeof(ObjectFlags);
890 Status = STATUS_SUCCESS;
891 break;
892 }
893
894 case UOI_NAME:
895 {
896 // FIXME: Use either ObQueryNameString() or read directly that name inside the Object section!
897 if (WinStaObject != NULL)
898 {
899 pvData = WinStaObject->Name.Buffer;
900 nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
901 Status = STATUS_SUCCESS;
902 }
903 else if (DesktopObject != NULL)
904 {
905 pvData = DesktopObject->pDeskInfo->szDesktopName;
906 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
907 Status = STATUS_SUCCESS;
908 }
909 else
910 {
911 Status = STATUS_INVALID_PARAMETER;
912 }
913 break;
914 }
915
916 case UOI_TYPE:
917 {
918 if (WinStaObject != NULL)
919 {
920 pvData = L"WindowStation";
921 nDataSize = sizeof(L"WindowStation");
922 Status = STATUS_SUCCESS;
923 }
924 else if (DesktopObject != NULL)
925 {
926 pvData = L"Desktop";
927 nDataSize = sizeof(L"Desktop");
928 Status = STATUS_SUCCESS;
929 }
930 else
931 {
932 Status = STATUS_INVALID_PARAMETER;
933 }
934 break;
935 }
936
937 case UOI_USER_SID:
938 Status = STATUS_NOT_IMPLEMENTED;
939 ERR("UOI_USER_SID unimplemented!\n");
940 break;
941
942 default:
943 Status = STATUS_INVALID_PARAMETER;
944 break;
945 }
946
947 Exit:
948 if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
949 Status = STATUS_BUFFER_TOO_SMALL;
950
951 _SEH2_TRY
952 {
953 if (nLengthNeeded)
954 *nLengthNeeded = nDataSize;
955
956 /* Try to copy data to caller */
957 if (Status == STATUS_SUCCESS)
958 {
959 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
960 RtlCopyMemory(pvInformation, pvData, nDataSize);
961 }
962 }
963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
964 {
965 Status = _SEH2_GetExceptionCode();
966 }
967 _SEH2_END;
968
969 /* Release objects */
970 if (DesktopObject != NULL)
971 ObDereferenceObject(DesktopObject);
972 if (WinStaObject != NULL)
973 ObDereferenceObject(WinStaObject);
974
975 if (!NT_SUCCESS(Status))
976 {
977 SetLastNtError(Status);
978 return FALSE;
979 }
980
981 return TRUE;
982 }
983
984 /*
985 * NtUserSetObjectInformation
986 *
987 * The NtUserSetObjectInformation function sets information about a
988 * window station or desktop object.
989 *
990 * Parameters
991 * hObj
992 * Handle to the window station or desktop object for which to set
993 * object information. This value can be a handle of type HDESK or
994 * HWINSTA.
995 *
996 * nIndex
997 * Specifies the object information to be set.
998 *
999 * pvInfo
1000 * Pointer to a buffer containing the object information.
1001 *
1002 * nLength
1003 * Specifies the size, in bytes, of the information contained in the
1004 * buffer pointed to by pvInfo.
1005 *
1006 * Return Value
1007 * If the function succeeds, the return value is nonzero. If the function
1008 * fails the return value is zero.
1009 *
1010 * Status
1011 * @unimplemented
1012 */
1013
1014 BOOL
1015 APIENTRY
1016 NtUserSetObjectInformation(
1017 HANDLE hObject,
1018 DWORD nIndex,
1019 PVOID pvInformation,
1020 DWORD nLength)
1021 {
1022 /* FIXME: ZwQueryObject */
1023 /* FIXME: ZwSetInformationObject */
1024 SetLastNtError(STATUS_UNSUCCESSFUL);
1025 return FALSE;
1026 }
1027
1028
1029
1030
1031 HWINSTA FASTCALL
1032 UserGetProcessWindowStation(VOID)
1033 {
1034 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1035
1036 return ppi->hwinsta;
1037 }
1038
1039
1040 /*
1041 * NtUserGetProcessWindowStation
1042 *
1043 * Returns a handle to the current process window station.
1044 *
1045 * Return Value
1046 * If the function succeeds, the return value is handle to the window
1047 * station assigned to the current process. If the function fails, the
1048 * return value is NULL.
1049 *
1050 * Status
1051 * @implemented
1052 */
1053
1054 HWINSTA APIENTRY
1055 NtUserGetProcessWindowStation(VOID)
1056 {
1057 return UserGetProcessWindowStation();
1058 }
1059
1060 BOOL FASTCALL
1061 UserSetProcessWindowStation(HWINSTA hWindowStation)
1062 {
1063 PPROCESSINFO ppi;
1064 NTSTATUS Status;
1065 HWINSTA hwinstaOld;
1066 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1067 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
1068
1069 ppi = PsGetCurrentProcessWin32Process();
1070
1071 /* Reference the new window station */
1072 if (hWindowStation != NULL)
1073 {
1074 Status = IntValidateWindowStationHandle(hWindowStation,
1075 UserMode,
1076 0,
1077 &NewWinSta,
1078 &ObjectHandleInfo);
1079 if (!NT_SUCCESS(Status))
1080 {
1081 TRACE("Validation of window station handle (%p) failed\n",
1082 hWindowStation);
1083 SetLastNtError(Status);
1084 return FALSE;
1085 }
1086 }
1087
1088 OldWinSta = ppi->prpwinsta;
1089 hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
1090
1091 /* Dereference the previous window station */
1092 if (OldWinSta != NULL)
1093 {
1094 ObDereferenceObject(OldWinSta);
1095 }
1096
1097 /* Check if we have a stale handle (it should happen for console apps) */
1098 if (hwinstaOld != ppi->hwinsta)
1099 {
1100 ObCloseHandle(hwinstaOld, UserMode);
1101 }
1102
1103 /*
1104 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
1105 */
1106
1107 PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
1108
1109 ppi->prpwinsta = NewWinSta;
1110 ppi->hwinsta = hWindowStation;
1111 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
1112 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
1113
1114 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
1115 {
1116 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
1117 }
1118 else
1119 {
1120 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
1121 }
1122
1123 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
1124 {
1125 ppi->W32PF_flags |= W32PF_IOWINSTA;
1126 }
1127 else // Might be closed if the handle is null.
1128 {
1129 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
1130 }
1131 return TRUE;
1132 }
1133
1134 /*
1135 * NtUserSetProcessWindowStation
1136 *
1137 * Assigns a window station to the current process.
1138 *
1139 * Parameters
1140 * hWinSta
1141 * Handle to the window station.
1142 *
1143 * Return Value
1144 * Status
1145 *
1146 * Status
1147 * @implemented
1148 */
1149
1150 BOOL APIENTRY
1151 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1152 {
1153 BOOL ret;
1154
1155 UserEnterExclusive();
1156
1157 ret = UserSetProcessWindowStation(hWindowStation);
1158
1159 UserLeave();
1160
1161 return ret;
1162 }
1163
1164 /*
1165 * NtUserLockWindowStation
1166 *
1167 * Locks switching desktops. Only the logon application is allowed to call this function.
1168 *
1169 * Status
1170 * @implemented
1171 */
1172
1173 BOOL APIENTRY
1174 NtUserLockWindowStation(HWINSTA hWindowStation)
1175 {
1176 PWINSTATION_OBJECT Object;
1177 NTSTATUS Status;
1178
1179 TRACE("About to set process window station with handle (%p)\n",
1180 hWindowStation);
1181
1182 if (gpidLogon != PsGetCurrentProcessId())
1183 {
1184 ERR("Unauthorized process attempted to lock the window station!\n");
1185 EngSetLastError(ERROR_ACCESS_DENIED);
1186 return FALSE;
1187 }
1188
1189 Status = IntValidateWindowStationHandle(hWindowStation,
1190 UserMode,
1191 0,
1192 &Object,
1193 0);
1194 if (!NT_SUCCESS(Status))
1195 {
1196 TRACE("Validation of window station handle (%p) failed\n",
1197 hWindowStation);
1198 SetLastNtError(Status);
1199 return FALSE;
1200 }
1201
1202 Object->Flags |= WSS_LOCKED;
1203
1204 ObDereferenceObject(Object);
1205 return TRUE;
1206 }
1207
1208 /*
1209 * NtUserUnlockWindowStation
1210 *
1211 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1212 *
1213 * Status
1214 * @implemented
1215 */
1216
1217 BOOL APIENTRY
1218 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1219 {
1220 PWINSTATION_OBJECT Object;
1221 NTSTATUS Status;
1222 BOOL Ret;
1223
1224 TRACE("About to set process window station with handle (%p)\n",
1225 hWindowStation);
1226
1227 if (gpidLogon != PsGetCurrentProcessId())
1228 {
1229 ERR("Unauthorized process attempted to unlock the window station!\n");
1230 EngSetLastError(ERROR_ACCESS_DENIED);
1231 return FALSE;
1232 }
1233
1234 Status = IntValidateWindowStationHandle(hWindowStation,
1235 UserMode,
1236 0,
1237 &Object,
1238 0);
1239 if (!NT_SUCCESS(Status))
1240 {
1241 TRACE("Validation of window station handle (%p) failed\n",
1242 hWindowStation);
1243 SetLastNtError(Status);
1244 return FALSE;
1245 }
1246
1247 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1248 Object->Flags &= ~WSS_LOCKED;
1249
1250 ObDereferenceObject(Object);
1251 return Ret;
1252 }
1253
1254 static NTSTATUS FASTCALL
1255 BuildWindowStationNameList(
1256 ULONG dwSize,
1257 PVOID lpBuffer,
1258 PULONG pRequiredSize)
1259 {
1260 OBJECT_ATTRIBUTES ObjectAttributes;
1261 NTSTATUS Status;
1262 HANDLE DirectoryHandle;
1263 char InitialBuffer[256], *Buffer;
1264 ULONG Context, ReturnLength, BufferSize;
1265 DWORD EntryCount;
1266 POBJECT_DIRECTORY_INFORMATION DirEntry;
1267 WCHAR NullWchar;
1268
1269 //
1270 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1271 // with judicious parameters one can create window stations elsewhere
1272 // than in Windows\WindowStations directory, Win32k definitely MUST
1273 // maintain a list of window stations it has created, and not rely
1274 // on the enumeration of Windows\WindowStations !!!
1275 //
1276
1277 /*
1278 * Try to open the directory.
1279 */
1280 InitializeObjectAttributes(&ObjectAttributes,
1281 &gustrWindowStationsDir,
1282 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1283 NULL,
1284 NULL);
1285
1286 Status = ZwOpenDirectoryObject(&DirectoryHandle,
1287 DIRECTORY_QUERY,
1288 &ObjectAttributes);
1289
1290 if (!NT_SUCCESS(Status))
1291 {
1292 return Status;
1293 }
1294
1295 /* First try to query the directory using a fixed-size buffer */
1296 Context = 0;
1297 Buffer = NULL;
1298 Status = ZwQueryDirectoryObject(DirectoryHandle,
1299 InitialBuffer,
1300 sizeof(InitialBuffer),
1301 FALSE,
1302 TRUE,
1303 &Context,
1304 &ReturnLength);
1305 if (NT_SUCCESS(Status))
1306 {
1307 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1308 FALSE, &Context, NULL))
1309 {
1310 /* Our fixed-size buffer is large enough */
1311 Buffer = InitialBuffer;
1312 }
1313 }
1314
1315 if (NULL == Buffer)
1316 {
1317 /* Need a larger buffer, check how large exactly */
1318 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1319 &ReturnLength);
1320 if (!NT_SUCCESS(Status))
1321 {
1322 ERR("ZwQueryDirectoryObject failed\n");
1323 ZwClose(DirectoryHandle);
1324 return Status;
1325 }
1326
1327 BufferSize = ReturnLength;
1328 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1329 if (NULL == Buffer)
1330 {
1331 ZwClose(DirectoryHandle);
1332 return STATUS_NO_MEMORY;
1333 }
1334
1335 /* We should have a sufficiently large buffer now */
1336 Context = 0;
1337 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1338 FALSE, TRUE, &Context, &ReturnLength);
1339 if (! NT_SUCCESS(Status) ||
1340 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1341 FALSE, &Context, NULL))
1342 {
1343 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1344 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1345 ZwClose(DirectoryHandle);
1346 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1347 }
1348 }
1349
1350 ZwClose(DirectoryHandle);
1351
1352 /*
1353 * Count the required size of buffer.
1354 */
1355 ReturnLength = sizeof(DWORD);
1356 EntryCount = 0;
1357 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1358 0 != DirEntry->Name.Length;
1359 DirEntry++)
1360 {
1361 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1362 EntryCount++;
1363 }
1364 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1365 if (NULL != pRequiredSize)
1366 {
1367 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1368 if (! NT_SUCCESS(Status))
1369 {
1370 if (Buffer != InitialBuffer)
1371 {
1372 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1373 }
1374 return STATUS_BUFFER_TOO_SMALL;
1375 }
1376 }
1377
1378 /*
1379 * Check if the supplied buffer is large enough.
1380 */
1381 if (dwSize < ReturnLength)
1382 {
1383 if (Buffer != InitialBuffer)
1384 {
1385 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1386 }
1387 return STATUS_BUFFER_TOO_SMALL;
1388 }
1389
1390 /*
1391 * Generate the resulting buffer contents.
1392 */
1393 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1394 if (! NT_SUCCESS(Status))
1395 {
1396 if (Buffer != InitialBuffer)
1397 {
1398 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1399 }
1400 return Status;
1401 }
1402 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1403
1404 NullWchar = L'\0';
1405 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1406 0 != DirEntry->Name.Length;
1407 DirEntry++)
1408 {
1409 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1410 if (! NT_SUCCESS(Status))
1411 {
1412 if (Buffer != InitialBuffer)
1413 {
1414 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1415 }
1416 return Status;
1417 }
1418 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1419 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1420 if (! NT_SUCCESS(Status))
1421 {
1422 if (Buffer != InitialBuffer)
1423 {
1424 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1425 }
1426 return Status;
1427 }
1428 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1429 }
1430
1431 /*
1432 * Clean up
1433 */
1434 if (Buffer != InitialBuffer)
1435 {
1436 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1437 }
1438
1439 return STATUS_SUCCESS;
1440 }
1441
1442 static NTSTATUS FASTCALL
1443 BuildDesktopNameList(
1444 HWINSTA hWindowStation,
1445 ULONG dwSize,
1446 PVOID lpBuffer,
1447 PULONG pRequiredSize)
1448 {
1449 NTSTATUS Status;
1450 PWINSTATION_OBJECT WindowStation;
1451 PLIST_ENTRY DesktopEntry;
1452 PDESKTOP DesktopObject;
1453 DWORD EntryCount;
1454 ULONG ReturnLength;
1455 WCHAR NullWchar;
1456 UNICODE_STRING DesktopName;
1457
1458 Status = IntValidateWindowStationHandle(hWindowStation,
1459 UserMode,
1460 0,
1461 &WindowStation,
1462 0);
1463 if (! NT_SUCCESS(Status))
1464 {
1465 return Status;
1466 }
1467
1468 /*
1469 * Count the required size of buffer.
1470 */
1471 ReturnLength = sizeof(DWORD);
1472 EntryCount = 0;
1473 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1474 DesktopEntry != &WindowStation->DesktopListHead;
1475 DesktopEntry = DesktopEntry->Flink)
1476 {
1477 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1478 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1479 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1480 EntryCount++;
1481 }
1482 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1483 if (NULL != pRequiredSize)
1484 {
1485 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1486 if (! NT_SUCCESS(Status))
1487 {
1488 ObDereferenceObject(WindowStation);
1489 return STATUS_BUFFER_TOO_SMALL;
1490 }
1491 }
1492
1493 /*
1494 * Check if the supplied buffer is large enough.
1495 */
1496 if (dwSize < ReturnLength)
1497 {
1498 ObDereferenceObject(WindowStation);
1499 return STATUS_BUFFER_TOO_SMALL;
1500 }
1501
1502 /*
1503 * Generate the resulting buffer contents.
1504 */
1505 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1506 if (! NT_SUCCESS(Status))
1507 {
1508 ObDereferenceObject(WindowStation);
1509 return Status;
1510 }
1511 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1512
1513 NullWchar = L'\0';
1514 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1515 DesktopEntry != &WindowStation->DesktopListHead;
1516 DesktopEntry = DesktopEntry->Flink)
1517 {
1518 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1519 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1520 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1521 if (! NT_SUCCESS(Status))
1522 {
1523 ObDereferenceObject(WindowStation);
1524 return Status;
1525 }
1526 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1527 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1528 if (! NT_SUCCESS(Status))
1529 {
1530 ObDereferenceObject(WindowStation);
1531 return Status;
1532 }
1533 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1534 }
1535
1536 /*
1537 * Clean up and return
1538 */
1539 ObDereferenceObject(WindowStation);
1540 return STATUS_SUCCESS;
1541 }
1542
1543 /*
1544 * NtUserBuildNameList
1545 *
1546 * Function used for enumeration of desktops or window stations.
1547 *
1548 * Parameters
1549 * hWinSta
1550 * For enumeration of window stations this parameter must be set to
1551 * zero. Otherwise it's handle for window station.
1552 *
1553 * dwSize
1554 * Size of buffer passed by caller.
1555 *
1556 * lpBuffer
1557 * Buffer passed by caller. If the function succeeds, the buffer is
1558 * filled with window station/desktop count (in first DWORD) and
1559 * NULL-terminated window station/desktop names.
1560 *
1561 * pRequiredSize
1562 * If the function succeeds, this is the number of bytes copied.
1563 * Otherwise it's size of buffer needed for function to succeed.
1564 *
1565 * Status
1566 * @implemented
1567 */
1568
1569 NTSTATUS APIENTRY
1570 NtUserBuildNameList(
1571 HWINSTA hWindowStation,
1572 ULONG dwSize,
1573 PVOID lpBuffer,
1574 PULONG pRequiredSize)
1575 {
1576 /* The WindowStation name list and desktop name list are build in completely
1577 different ways. Call the appropriate function */
1578 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1579 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1580 }
1581
1582 /*
1583 * @implemented
1584 */
1585 BOOL APIENTRY
1586 NtUserSetLogonNotifyWindow(HWND hWnd)
1587 {
1588 if (gpidLogon != PsGetCurrentProcessId())
1589 {
1590 return FALSE;
1591 }
1592
1593 if (!IntIsWindow(hWnd))
1594 {
1595 return FALSE;
1596 }
1597
1598 hwndSAS = hWnd;
1599
1600 return TRUE;
1601 }
1602
1603 BOOL
1604 APIENTRY
1605 NtUserLockWorkStation(VOID)
1606 {
1607 BOOL ret;
1608 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1609
1610 UserEnterExclusive();
1611
1612 if (pti->rpdesk == IntGetActiveDesktop())
1613 {
1614 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1615 }
1616 else
1617 {
1618 ret = FALSE;
1619 }
1620
1621 UserLeave();
1622
1623 return ret;
1624 }
1625
1626 BOOL
1627 NTAPI
1628 NtUserSetWindowStationUser(
1629 IN HWINSTA hWindowStation,
1630 IN PLUID pluid,
1631 IN PSID psid OPTIONAL,
1632 IN DWORD size)
1633 {
1634 BOOL Ret = FALSE;
1635 NTSTATUS Status;
1636 PWINSTATION_OBJECT WindowStation = NULL;
1637 LUID luidUser;
1638
1639 UserEnterExclusive();
1640
1641 if (gpidLogon != PsGetCurrentProcessId())
1642 {
1643 EngSetLastError(ERROR_ACCESS_DENIED);
1644 goto Leave;
1645 }
1646
1647 /* Validate the window station */
1648 Status = IntValidateWindowStationHandle(hWindowStation,
1649 UserMode,
1650 0,
1651 &WindowStation,
1652 NULL);
1653 if (!NT_SUCCESS(Status))
1654 {
1655 goto Leave;
1656 }
1657
1658 /* Capture the user LUID */
1659 _SEH2_TRY
1660 {
1661 ProbeForRead(pluid, sizeof(LUID), 1);
1662 luidUser = *pluid;
1663 }
1664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1665 {
1666 Status = _SEH2_GetExceptionCode();
1667 _SEH2_YIELD(goto Leave);
1668 }
1669 _SEH2_END;
1670
1671 /* Reset the window station user LUID */
1672 RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
1673
1674 /* Reset the window station user SID */
1675 if (WindowStation->psidUser)
1676 {
1677 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1678 WindowStation->psidUser = NULL;
1679 }
1680
1681 /* Copy the new user SID if one has been provided */
1682 if (psid)
1683 {
1684 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
1685 if (WindowStation->psidUser == NULL)
1686 {
1687 EngSetLastError(ERROR_OUTOFMEMORY);
1688 goto Leave;
1689 }
1690
1691 Status = STATUS_SUCCESS;
1692 _SEH2_TRY
1693 {
1694 ProbeForRead(psid, size, 1);
1695 RtlCopyMemory(WindowStation->psidUser, psid, size);
1696 }
1697 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1698 {
1699 Status = _SEH2_GetExceptionCode();
1700 }
1701 _SEH2_END;
1702
1703 if (!NT_SUCCESS(Status))
1704 {
1705 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1706 WindowStation->psidUser = NULL;
1707 goto Leave;
1708 }
1709 }
1710
1711 /* Copy the new user LUID */
1712 WindowStation->luidUser = luidUser;
1713
1714 Ret = TRUE;
1715
1716 Leave:
1717 if (WindowStation)
1718 ObDereferenceObject(WindowStation);
1719
1720 UserLeave();
1721 return Ret;
1722 }
1723
1724
1725 /* EOF */