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