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