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