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