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 /*
18 * The currently active window station. This is the
19 * only one interactive window station on the system.
20 */
21 PWINSTATION_OBJECT InputWindowStation = NULL;
22
23 /* Winlogon SAS window */
24 HWND hwndSAS = NULL;
25
26 /* Full path to WindowStations directory */
27 UNICODE_STRING gustrWindowStationsDir;
28
29 /* INITIALIZATION FUNCTIONS ****************************************************/
30
31 CODE_SEG("INIT")
32 NTSTATUS
33 NTAPI
InitWindowStationImpl(VOID)34 InitWindowStationImpl(VOID)
35 {
36 GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
37 WINSTA_WRITE,
38 WINSTA_EXECUTE,
39 WINSTA_ACCESS_ALL};
40
41 /* Set Winsta Object Attributes */
42 ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
43 ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
44 ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
45
46 return STATUS_SUCCESS;
47 }
48
49 NTSTATUS
50 NTAPI
UserCreateWinstaDirectory(VOID)51 UserCreateWinstaDirectory(VOID)
52 {
53 NTSTATUS Status;
54 PPEB Peb;
55 OBJECT_ATTRIBUTES ObjectAttributes;
56 HANDLE hWinstaDir;
57 WCHAR wstrWindowStationsDir[MAX_PATH];
58
59 /* Create the WindowStations directory and cache its path for later use */
60 Peb = NtCurrentPeb();
61 if(Peb->SessionId == 0)
62 {
63 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR))
64 {
65 return STATUS_INSUFFICIENT_RESOURCES;
66 }
67 }
68 else
69 {
70 Status = RtlStringCbPrintfW(wstrWindowStationsDir,
71 sizeof(wstrWindowStationsDir),
72 L"%ws\\%lu%ws",
73 SESSION_DIR,
74 Peb->SessionId,
75 WINSTA_OBJ_DIR);
76 if (!NT_SUCCESS(Status))
77 return Status;
78
79 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
80 {
81 return STATUS_INSUFFICIENT_RESOURCES;
82 }
83 }
84
85 InitializeObjectAttributes(&ObjectAttributes,
86 &gustrWindowStationsDir,
87 OBJ_KERNEL_HANDLE,
88 NULL,
89 NULL);
90 Status = ZwCreateDirectoryObject(&hWinstaDir, DIRECTORY_CREATE_OBJECT, &ObjectAttributes);
91 if (!NT_SUCCESS(Status))
92 {
93 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status);
94 return Status;
95 }
96
97 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir, Peb->SessionId);
98
99 return Status;
100 }
101
102 /* OBJECT CALLBACKS ***********************************************************/
103
104 NTSTATUS
105 NTAPI
IntWinStaObjectDelete(_In_ PVOID Parameters)106 IntWinStaObjectDelete(
107 _In_ PVOID Parameters)
108 {
109 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
110 PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
111
112 TRACE("Deleting window station 0x%p\n", WinSta);
113
114 if (WinSta == InputWindowStation)
115 {
116 ERR("WARNING: Deleting the interactive window station '%wZ'!\n",
117 &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(InputWindowStation))->Name));
118
119 /* Only Winlogon can close and delete the interactive window station */
120 ASSERT(gpidLogon == PsGetCurrentProcessId());
121
122 InputWindowStation = NULL;
123 }
124
125 WinSta->Flags |= WSS_DYING;
126
127 UserEmptyClipboardData(WinSta);
128
129 RtlDestroyAtomTable(WinSta->AtomTable);
130
131 UserAssignmentUnlock((PVOID*)&WinSta->spklList);
132
133 return STATUS_SUCCESS;
134 }
135
136 NTSTATUS
137 NTAPI
IntWinStaObjectParse(_In_ PVOID Parameters)138 IntWinStaObjectParse(
139 _In_ PVOID Parameters)
140 {
141 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters = Parameters;
142 PUNICODE_STRING RemainingName = ParseParameters->RemainingName;
143
144 /* Assume we don't find anything */
145 *ParseParameters->Object = NULL;
146
147 /* Check for an empty name */
148 if (!RemainingName->Length)
149 {
150 /* Make sure this is a window station, can't parse a desktop now */
151 if (ParseParameters->ObjectType != ExWindowStationObjectType)
152 {
153 /* Fail */
154 return STATUS_OBJECT_TYPE_MISMATCH;
155 }
156
157 /* Reference the window station and return */
158 ObReferenceObject(ParseParameters->ParseObject);
159 *ParseParameters->Object = ParseParameters->ParseObject;
160 return STATUS_SUCCESS;
161 }
162
163 /* Check for leading slash */
164 if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
165 {
166 /* Skip it */
167 RemainingName->Buffer++;
168 RemainingName->Length -= sizeof(WCHAR);
169 RemainingName->MaximumLength -= sizeof(WCHAR);
170 }
171
172 /* Check if there is still a slash */
173 if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
174 {
175 /* In this case, fail */
176 return STATUS_OBJECT_PATH_INVALID;
177 }
178
179 /*
180 * Check if we are parsing a desktop.
181 */
182 if (ParseParameters->ObjectType == ExDesktopObjectType)
183 {
184 /* Then call the desktop parse routine */
185 return IntDesktopObjectParse(ParseParameters->ParseObject,
186 ParseParameters->ObjectType,
187 ParseParameters->AccessState,
188 ParseParameters->AccessMode,
189 ParseParameters->Attributes,
190 ParseParameters->CompleteName,
191 RemainingName,
192 ParseParameters->Context,
193 ParseParameters->SecurityQos,
194 ParseParameters->Object);
195 }
196
197 /* Should hopefully never get here */
198 return STATUS_OBJECT_TYPE_MISMATCH;
199 }
200
201 NTSTATUS
202 NTAPI
IntWinStaOkToClose(_In_ PVOID Parameters)203 IntWinStaOkToClose(
204 _In_ PVOID Parameters)
205 {
206 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
207 PPROCESSINFO ppi;
208
209 ppi = PsGetCurrentProcessWin32Process();
210
211 if (ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
212 {
213 return STATUS_ACCESS_DENIED;
214 }
215
216 return STATUS_SUCCESS;
217 }
218
219 /* PRIVATE FUNCTIONS **********************************************************/
220
221 /*
222 * IntValidateWindowStationHandle
223 *
224 * Validates the window station handle.
225 *
226 * Remarks
227 * If the function succeeds, the handle remains referenced. If the
228 * fucntion fails, last error is set.
229 */
230
231 NTSTATUS FASTCALL
IntValidateWindowStationHandle(HWINSTA WindowStation,KPROCESSOR_MODE AccessMode,ACCESS_MASK DesiredAccess,PWINSTATION_OBJECT * Object,POBJECT_HANDLE_INFORMATION pObjectHandleInfo)232 IntValidateWindowStationHandle(
233 HWINSTA WindowStation,
234 KPROCESSOR_MODE AccessMode,
235 ACCESS_MASK DesiredAccess,
236 PWINSTATION_OBJECT *Object,
237 POBJECT_HANDLE_INFORMATION pObjectHandleInfo)
238 {
239 NTSTATUS Status;
240
241 if (WindowStation == NULL)
242 {
243 ERR("Invalid window station handle\n");
244 EngSetLastError(ERROR_INVALID_HANDLE);
245 return STATUS_INVALID_HANDLE;
246 }
247
248 Status = ObReferenceObjectByHandle(WindowStation,
249 DesiredAccess,
250 ExWindowStationObjectType,
251 AccessMode,
252 (PVOID*)Object,
253 pObjectHandleInfo);
254
255 if (!NT_SUCCESS(Status))
256 SetLastNtError(Status);
257
258 return Status;
259 }
260
261 BOOL FASTCALL
co_IntInitializeDesktopGraphics(VOID)262 co_IntInitializeDesktopGraphics(VOID)
263 {
264 TEXTMETRICW tmw;
265 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
266 PDESKTOP pdesk;
267
268 if (PDEVOBJ_lChangeDisplaySettings(NULL, NULL, NULL, &gpmdev, TRUE) != DISP_CHANGE_SUCCESSFUL)
269 {
270 ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
271 return FALSE;
272 }
273
274 ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
275 if (NULL == ScreenDeviceContext)
276 {
277 IntDestroyPrimarySurface();
278 return FALSE;
279 }
280 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
281
282 if (!IntCreatePrimarySurface())
283 {
284 return FALSE;
285 }
286
287 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
288
289 NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
290 GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
291
292 /* Update the system metrics */
293 InitMetrics();
294
295 /* Set new size of the monitor */
296 UserUpdateMonitorSize((HDEV)gpmdev->ppdevGlobal);
297
298 /* Update the SERVERINFO */
299 gpsi->aiSysMet[SM_CXSCREEN] = gpmdev->ppdevGlobal->gdiinfo.ulHorzRes;
300 gpsi->aiSysMet[SM_CYSCREEN] = gpmdev->ppdevGlobal->gdiinfo.ulVertRes;
301 gpsi->Planes = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
302 gpsi->BitsPixel = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
303 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
304 gpsi->dmLogPixels = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
305 if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
306 {
307 gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
308 }
309 else
310 {
311 gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
312 }
313 // Font is realized and this dc was previously set to internal DC_ATTR.
314 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
315 gpsi->tmSysFont = tmw;
316
317 /* Put the pointer in the center of the screen */
318 gpsi->ptCursor.x = gpsi->aiSysMet[SM_CXSCREEN] / 2;
319 gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
320
321 /* Attach monitor */
322 UserAttachMonitor((HDEV)gpmdev->ppdevGlobal);
323
324 /* Setup the cursor */
325 co_IntLoadDefaultCursors();
326
327 /* Setup the icons */
328 co_IntSetWndIcons();
329
330 /* Setup Menu */
331 MenuInit();
332
333 /* Show the desktop */
334 pdesk = IntGetActiveDesktop();
335 ASSERT(pdesk);
336 co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
337
338 /* HACK: display wallpaper on all secondary displays */
339 {
340 PGRAPHICS_DEVICE pGraphicsDevice;
341 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
342 UNICODE_STRING DisplayName;
343 HDC hdc;
344 ULONG iDevNum;
345
346 for (iDevNum = 1; (pGraphicsDevice = EngpFindGraphicsDevice(NULL, iDevNum)) != NULL; iDevNum++)
347 {
348 RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName);
349 hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE);
350 IntPaintDesktop(hdc);
351 }
352 }
353
354 return TRUE;
355 }
356
357 VOID FASTCALL
IntEndDesktopGraphics(VOID)358 IntEndDesktopGraphics(VOID)
359 {
360 if (NULL != ScreenDeviceContext)
361 { // No need to allocate a new dcattr.
362 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
363 GreDeleteObject(ScreenDeviceContext);
364 ScreenDeviceContext = NULL;
365 }
366 IntHideDesktop(IntGetActiveDesktop());
367 IntDestroyPrimarySurface();
368 }
369
370 HDC FASTCALL
IntGetScreenDC(VOID)371 IntGetScreenDC(VOID)
372 {
373 return ScreenDeviceContext;
374 }
375
376 BOOL FASTCALL
CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)377 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
378 {
379 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
380 if ( gpidLogon != PsGetCurrentProcessId() )
381 {
382 if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
383 {
384 ERR("Requires Interactive Window Station\n");
385 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
386 return FALSE;
387 }
388 if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
389 {
390 ERR("Access Denied\n");
391 EngSetLastError(ERROR_ACCESS_DENIED);
392 return FALSE;
393 }
394 }
395 return TRUE;
396 }
397
398 // Win: _GetProcessWindowStation
399 PWINSTATION_OBJECT FASTCALL
IntGetProcessWindowStation(HWINSTA * phWinSta OPTIONAL)400 IntGetProcessWindowStation(HWINSTA *phWinSta OPTIONAL)
401 {
402 PWINSTATION_OBJECT pWinSta;
403 PPROCESSINFO ppi = GetW32ProcessInfo();
404 HWINSTA hWinSta = ppi->hwinsta;
405 if (phWinSta)
406 *phWinSta = hWinSta;
407 IntValidateWindowStationHandle(hWinSta, UserMode, 0, &pWinSta, 0);
408 return pWinSta;
409 }
410
411 /* PUBLIC FUNCTIONS ***********************************************************/
412
413 /*
414 * NtUserCreateWindowStation
415 *
416 * Creates a new window station.
417 *
418 * Parameters
419 * lpszWindowStationName
420 * Pointer to a null-terminated string specifying the name of the
421 * window station to be created. Window station names are
422 * case-insensitive and cannot contain backslash characters (\).
423 * Only members of the Administrators group are allowed to specify a
424 * name.
425 *
426 * dwDesiredAccess
427 * Requested type of access
428 *
429 * lpSecurity
430 * Security descriptor
431 *
432 * Unknown3, Unknown4, Unknown5, Unknown6
433 * Unused
434 *
435 * Return Value
436 * If the function succeeds, the return value is a handle to the newly
437 * created window station. If the specified window station already
438 * exists, the function succeeds and returns a handle to the existing
439 * window station. If the function fails, the return value is NULL.
440 *
441 * Status
442 * @implemented
443 */
444
445 NTSTATUS
446 FASTCALL
IntCreateWindowStation(OUT HWINSTA * phWinSta,IN POBJECT_ATTRIBUTES ObjectAttributes,IN KPROCESSOR_MODE AccessMode,IN KPROCESSOR_MODE OwnerMode,IN ACCESS_MASK dwDesiredAccess,DWORD Unknown2,DWORD Unknown3,DWORD Unknown4,DWORD Unknown5,DWORD Unknown6)447 IntCreateWindowStation(
448 OUT HWINSTA* phWinSta,
449 IN POBJECT_ATTRIBUTES ObjectAttributes,
450 IN KPROCESSOR_MODE AccessMode,
451 IN KPROCESSOR_MODE OwnerMode,
452 IN ACCESS_MASK dwDesiredAccess,
453 DWORD Unknown2,
454 DWORD Unknown3,
455 DWORD Unknown4,
456 DWORD Unknown5,
457 DWORD Unknown6)
458 {
459 NTSTATUS Status;
460 HWINSTA hWinSta;
461 PWINSTATION_OBJECT WindowStation;
462
463 TRACE("IntCreateWindowStation called\n");
464
465 ASSERT(phWinSta);
466 *phWinSta = NULL;
467
468 Status = ObOpenObjectByName(ObjectAttributes,
469 ExWindowStationObjectType,
470 AccessMode,
471 NULL,
472 dwDesiredAccess,
473 NULL,
474 (PVOID*)&hWinSta);
475 if (NT_SUCCESS(Status))
476 {
477 TRACE("IntCreateWindowStation opened window station '%wZ'\n",
478 ObjectAttributes->ObjectName);
479 *phWinSta = hWinSta;
480 return Status;
481 }
482
483 /*
484 * No existing window station found, try to create a new one.
485 */
486
487 /* Create the window station object */
488 Status = ObCreateObject(AccessMode,
489 ExWindowStationObjectType,
490 ObjectAttributes,
491 OwnerMode,
492 NULL,
493 sizeof(WINSTATION_OBJECT),
494 0,
495 0,
496 (PVOID*)&WindowStation);
497 if (!NT_SUCCESS(Status))
498 {
499 ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
500 ObjectAttributes->ObjectName, Status);
501 SetLastNtError(Status);
502 return Status;
503 }
504
505 /* Initialize the window station */
506 RtlZeroMemory(WindowStation, sizeof(WINSTATION_OBJECT));
507
508 InitializeListHead(&WindowStation->DesktopListHead);
509 WindowStation->dwSessionId = NtCurrentPeb()->SessionId;
510 Status = RtlCreateAtomTable(37, &WindowStation->AtomTable);
511 if (!NT_SUCCESS(Status))
512 {
513 ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
514 ObjectAttributes->ObjectName, Status);
515 ObDereferenceObject(WindowStation);
516 SetLastNtError(Status);
517 return Status;
518 }
519
520 Status = ObInsertObject(WindowStation,
521 NULL,
522 dwDesiredAccess,
523 0,
524 NULL,
525 (PVOID*)&hWinSta);
526 if (!NT_SUCCESS(Status))
527 {
528 ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status);
529 SetLastNtError(Status);
530 return Status;
531 }
532
533 // FIXME! TODO: Add this new window station to a linked list
534
535 if (InputWindowStation == NULL)
536 {
537 ERR("Initializing input window station\n");
538
539 /* Only Winlogon can create the interactive window station */
540 ASSERT(gpidLogon == PsGetCurrentProcessId());
541
542 InputWindowStation = WindowStation;
543 WindowStation->Flags &= ~WSS_NOIO;
544
545 InitCursorImpl();
546
547 UserCreateSystemThread(ST_DESKTOP_THREAD);
548 UserCreateSystemThread(ST_RIT);
549
550 /* Desktop functions require the desktop thread running so wait for it to initialize */
551 UserLeaveCo();
552 KeWaitForSingleObject(gpDesktopThreadStartedEvent,
553 UserRequest,
554 UserMode,
555 FALSE,
556 NULL);
557 UserEnterCo();
558 }
559 else
560 {
561 WindowStation->Flags |= WSS_NOIO;
562 }
563
564 TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
565 ObjectAttributes->ObjectName, WindowStation, hWinSta);
566
567 *phWinSta = hWinSta;
568 EngSetLastError(ERROR_SUCCESS);
569
570 return STATUS_SUCCESS;
571 }
572
573 static VOID
FreeUserModeWindowStationName(IN OUT PUNICODE_STRING WindowStationName,IN PUNICODE_STRING TebStaticUnicodeString,IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL,IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL)574 FreeUserModeWindowStationName(
575 IN OUT PUNICODE_STRING WindowStationName,
576 IN PUNICODE_STRING TebStaticUnicodeString,
577 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL,
578 IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL)
579 {
580 SIZE_T MemSize = 0;
581
582 /* Try to restore the user's UserModeObjectAttributes */
583 if (UserModeObjectAttributes && LocalObjectAttributes)
584 {
585 _SEH2_TRY
586 {
587 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
588 *UserModeObjectAttributes = *LocalObjectAttributes;
589 }
590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
591 {
592 NOTHING;
593 }
594 _SEH2_END;
595 }
596
597 /* Free the user-mode memory */
598 if (WindowStationName && (WindowStationName != TebStaticUnicodeString))
599 {
600 ZwFreeVirtualMemory(ZwCurrentProcess(),
601 (PVOID*)&WindowStationName,
602 &MemSize,
603 MEM_RELEASE);
604 }
605 }
606
607 static NTSTATUS
BuildUserModeWindowStationName(IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes,IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes,OUT PUNICODE_STRING * WindowStationName,OUT PUNICODE_STRING * TebStaticUnicodeString)608 BuildUserModeWindowStationName(
609 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes,
610 IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes,
611 OUT PUNICODE_STRING* WindowStationName,
612 OUT PUNICODE_STRING* TebStaticUnicodeString)
613 {
614 NTSTATUS Status;
615 SIZE_T MemSize;
616
617 LUID CallerLuid;
618 PTEB Teb;
619 USHORT StrSize;
620
621 *WindowStationName = NULL;
622 *TebStaticUnicodeString = NULL;
623
624 /* Retrieve the current process LUID */
625 Status = GetProcessLuid(NULL, NULL, &CallerLuid);
626 if (!NT_SUCCESS(Status))
627 {
628 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status);
629 return Status;
630 }
631
632 /* Compute the needed string size */
633 MemSize = _scwprintf(L"%wZ\\Service-0x%x-%x$",
634 &gustrWindowStationsDir,
635 CallerLuid.HighPart,
636 CallerLuid.LowPart);
637 MemSize = MemSize * sizeof(WCHAR) + sizeof(UNICODE_NULL);
638 if (MemSize > MAXUSHORT)
639 {
640 ERR("Window station name length is too long.\n");
641 return STATUS_NAME_TOO_LONG;
642 }
643 StrSize = (USHORT)MemSize;
644
645 /*
646 * Check whether it's short enough so that we can use the static buffer
647 * in the TEB. Otherwise continue with virtual memory allocation.
648 */
649 Teb = NtCurrentTeb();
650 if (Teb && (StrSize <= sizeof(Teb->StaticUnicodeBuffer)))
651 {
652 /* We can use the TEB's static unicode string */
653 ASSERT(Teb->StaticUnicodeString.Buffer == Teb->StaticUnicodeBuffer);
654 ASSERT(Teb->StaticUnicodeString.MaximumLength == sizeof(Teb->StaticUnicodeBuffer));
655
656 /* Remember the TEB's static unicode string address for later */
657 *TebStaticUnicodeString = &Teb->StaticUnicodeString;
658
659 *WindowStationName = *TebStaticUnicodeString;
660 (*WindowStationName)->Length = 0;
661 }
662 else
663 {
664 /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
665 MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID));
666
667 /* Allocate the memory in user-mode */
668 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
669 (PVOID*)WindowStationName,
670 0,
671 &MemSize,
672 MEM_COMMIT,
673 PAGE_READWRITE);
674 if (!NT_SUCCESS(Status))
675 {
676 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status);
677 return Status;
678 }
679
680 RtlInitEmptyUnicodeString(*WindowStationName,
681 (PWCHAR)((ULONG_PTR)*WindowStationName +
682 ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))),
683 StrSize);
684 }
685
686 /* Build a valid window station name from the LUID */
687 Status = RtlStringCbPrintfW((*WindowStationName)->Buffer,
688 (*WindowStationName)->MaximumLength,
689 L"%wZ\\Service-0x%x-%x$",
690 &gustrWindowStationsDir,
691 CallerLuid.HighPart,
692 CallerLuid.LowPart);
693 if (!NT_SUCCESS(Status))
694 {
695 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
696 goto Quit;
697 }
698 (*WindowStationName)->Length = (USHORT)(wcslen((*WindowStationName)->Buffer) * sizeof(WCHAR));
699
700 /* Try to update the user's UserModeObjectAttributes */
701 _SEH2_TRY
702 {
703 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
704 *LocalObjectAttributes = *UserModeObjectAttributes;
705
706 UserModeObjectAttributes->ObjectName = *WindowStationName;
707 UserModeObjectAttributes->RootDirectory = NULL;
708
709 Status = STATUS_SUCCESS;
710 }
711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
712 {
713 Status = _SEH2_GetExceptionCode();
714 }
715 _SEH2_END;
716
717 Quit:
718 if (!NT_SUCCESS(Status))
719 {
720 /* Release the window station name */
721 FreeUserModeWindowStationName(*WindowStationName,
722 *TebStaticUnicodeString,
723 NULL, NULL);
724 }
725
726 return Status;
727 }
728
729 HWINSTA
730 APIENTRY
NtUserCreateWindowStation(IN POBJECT_ATTRIBUTES ObjectAttributes,IN ACCESS_MASK dwDesiredAccess,DWORD Unknown2,DWORD Unknown3,DWORD Unknown4,DWORD Unknown5,DWORD Unknown6)731 NtUserCreateWindowStation(
732 IN POBJECT_ATTRIBUTES ObjectAttributes,
733 IN ACCESS_MASK dwDesiredAccess,
734 DWORD Unknown2,
735 DWORD Unknown3,
736 DWORD Unknown4,
737 DWORD Unknown5,
738 DWORD Unknown6)
739 {
740 NTSTATUS Status = STATUS_SUCCESS;
741 HWINSTA hWinSta = NULL;
742 OBJECT_ATTRIBUTES LocalObjectAttributes;
743 PUNICODE_STRING WindowStationName = NULL;
744 PUNICODE_STRING TebStaticUnicodeString = NULL;
745 KPROCESSOR_MODE OwnerMode = UserMode;
746
747 TRACE("NtUserCreateWindowStation called\n");
748
749 /* Capture the object attributes and the window station name */
750 _SEH2_TRY
751 {
752 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
753 LocalObjectAttributes = *ObjectAttributes;
754 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
755 {
756 ERR("Invalid ObjectAttributes length!\n");
757 Status = STATUS_INVALID_PARAMETER;
758 _SEH2_LEAVE;
759 }
760
761 /*
762 * Check whether the caller provided a window station name together
763 * with a RootDirectory handle.
764 *
765 * If the caller did not provide a window station name, build a new one
766 * based on the logon session identifier for the calling process.
767 * The new name is allocated in user-mode, as the rest of ObjectAttributes
768 * already is, so that the validation performed by the Object Manager
769 * can be done adequately.
770 */
771 if ((LocalObjectAttributes.ObjectName == NULL ||
772 LocalObjectAttributes.ObjectName->Buffer == NULL ||
773 LocalObjectAttributes.ObjectName->Length == 0 ||
774 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
775 /* &&
776 LocalObjectAttributes.RootDirectory == NULL */)
777 {
778 /* No, build the new window station name */
779 Status = BuildUserModeWindowStationName(ObjectAttributes,
780 &LocalObjectAttributes,
781 &WindowStationName,
782 &TebStaticUnicodeString);
783 if (!NT_SUCCESS(Status))
784 {
785 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
786 _SEH2_LEAVE;
787 }
788 OwnerMode = KernelMode;
789 }
790 }
791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
792 {
793 Status =_SEH2_GetExceptionCode();
794 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
795 }
796 _SEH2_END;
797
798 if (!NT_SUCCESS(Status))
799 {
800 SetLastNtError(Status);
801 return NULL;
802 }
803
804 UserEnterExclusive();
805
806 /* Create the window station */
807 Status = IntCreateWindowStation(&hWinSta,
808 ObjectAttributes,
809 UserMode,
810 OwnerMode,
811 dwDesiredAccess,
812 Unknown2,
813 Unknown3,
814 Unknown4,
815 Unknown5,
816 Unknown6);
817 UserLeave();
818
819 if (NT_SUCCESS(Status))
820 {
821 TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
822 ObjectAttributes->ObjectName, hWinSta);
823 }
824 else
825 {
826 ASSERT(hWinSta == NULL);
827 ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
828 ObjectAttributes->ObjectName, Status);
829 }
830
831 /* Try to restore the user's ObjectAttributes and release the window station name */
832 FreeUserModeWindowStationName(WindowStationName,
833 TebStaticUnicodeString,
834 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
835 &LocalObjectAttributes);
836
837 if (!NT_SUCCESS(Status))
838 {
839 ASSERT(hWinSta == NULL);
840 SetLastNtError(Status);
841 }
842
843 return hWinSta;
844 }
845
846 /*
847 * NtUserOpenWindowStation
848 *
849 * Opens an existing window station.
850 *
851 * Parameters
852 * lpszWindowStationName
853 * Name of the existing window station.
854 *
855 * dwDesiredAccess
856 * Requested type of access.
857 *
858 * Return Value
859 * If the function succeeds, the return value is the handle to the
860 * specified window station. If the function fails, the return value
861 * is NULL.
862 *
863 * Remarks
864 * The returned handle can be closed with NtUserCloseWindowStation.
865 *
866 * Status
867 * @implemented
868 */
869
870 HWINSTA
871 APIENTRY
NtUserOpenWindowStation(IN POBJECT_ATTRIBUTES ObjectAttributes,IN ACCESS_MASK dwDesiredAccess)872 NtUserOpenWindowStation(
873 IN POBJECT_ATTRIBUTES ObjectAttributes,
874 IN ACCESS_MASK dwDesiredAccess)
875 {
876 NTSTATUS Status = STATUS_SUCCESS;
877 HWINSTA hWinSta = NULL;
878 OBJECT_ATTRIBUTES LocalObjectAttributes;
879 PUNICODE_STRING WindowStationName = NULL;
880 PUNICODE_STRING TebStaticUnicodeString = NULL;
881 KPROCESSOR_MODE OwnerMode = UserMode;
882
883 TRACE("NtUserOpenWindowStation called\n");
884
885 /* Capture the object attributes and the window station name */
886 _SEH2_TRY
887 {
888 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
889 LocalObjectAttributes = *ObjectAttributes;
890 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
891 {
892 ERR("Invalid ObjectAttributes length!\n");
893 Status = STATUS_INVALID_PARAMETER;
894 _SEH2_LEAVE;
895 }
896
897 /*
898 * Check whether the caller did not provide a window station name,
899 * or provided the special "Service-0x00000000-00000000$" name.
900 *
901 * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
902 * is used instead of an empty name (observed when API-monitoring
903 * OpenWindowStation() called with an empty window station name).
904 */
905 if ((LocalObjectAttributes.ObjectName == NULL ||
906 LocalObjectAttributes.ObjectName->Buffer == NULL ||
907 LocalObjectAttributes.ObjectName->Length == 0 ||
908 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
909 /* &&
910 LocalObjectAttributes.RootDirectory == NULL */)
911 {
912 /* No, remember that for later */
913 LocalObjectAttributes.ObjectName = NULL;
914 }
915 if (LocalObjectAttributes.ObjectName &&
916 LocalObjectAttributes.ObjectName->Length ==
917 sizeof(L"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL) &&
918 _wcsnicmp(LocalObjectAttributes.ObjectName->Buffer,
919 L"Service-0x00000000-00000000$",
920 LocalObjectAttributes.ObjectName->Length / sizeof(WCHAR)) == 0)
921 {
922 /* No, remember that for later */
923 LocalObjectAttributes.ObjectName = NULL;
924 }
925
926 /*
927 * If the caller did not provide a window station name, build a new one
928 * based on the logon session identifier for the calling process.
929 * The new name is allocated in user-mode, as the rest of ObjectAttributes
930 * already is, so that the validation performed by the Object Manager
931 * can be done adequately.
932 */
933 if (!LocalObjectAttributes.ObjectName)
934 {
935 /* No, build the new window station name */
936 Status = BuildUserModeWindowStationName(ObjectAttributes,
937 &LocalObjectAttributes,
938 &WindowStationName,
939 &TebStaticUnicodeString);
940 if (!NT_SUCCESS(Status))
941 {
942 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
943 _SEH2_LEAVE;
944 }
945 OwnerMode = KernelMode;
946 }
947 }
948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
949 {
950 Status =_SEH2_GetExceptionCode();
951 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
952 }
953 _SEH2_END;
954
955 if (!NT_SUCCESS(Status))
956 {
957 SetLastNtError(Status);
958 return NULL;
959 }
960
961 /* Open the window station */
962 Status = ObOpenObjectByName(ObjectAttributes,
963 ExWindowStationObjectType,
964 UserMode,
965 NULL,
966 dwDesiredAccess,
967 NULL,
968 (PVOID*)&hWinSta);
969 if (NT_SUCCESS(Status))
970 {
971 TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
972 ObjectAttributes->ObjectName, hWinSta);
973 }
974 else
975 {
976 ASSERT(hWinSta == NULL);
977 ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
978 ObjectAttributes->ObjectName, Status);
979 }
980
981 /* Try to restore the user's ObjectAttributes and release the window station name */
982 FreeUserModeWindowStationName(WindowStationName,
983 TebStaticUnicodeString,
984 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
985 &LocalObjectAttributes);
986
987 if (!NT_SUCCESS(Status))
988 {
989 ASSERT(hWinSta == NULL);
990 SetLastNtError(Status);
991 }
992
993 return hWinSta;
994 }
995
996 /*
997 * NtUserCloseWindowStation
998 *
999 * Closes a window station handle.
1000 *
1001 * Parameters
1002 * hWinSta
1003 * Handle to the window station.
1004 *
1005 * Return Value
1006 * Status
1007 *
1008 * Remarks
1009 * The window station handle can be created with NtUserCreateWindowStation
1010 * or NtUserOpenWindowStation. Attempts to close a handle to the window
1011 * station assigned to the calling process will fail.
1012 *
1013 * Status
1014 * @implemented
1015 */
1016
1017 BOOL
1018 APIENTRY
NtUserCloseWindowStation(HWINSTA hWinSta)1019 NtUserCloseWindowStation(
1020 HWINSTA hWinSta)
1021 {
1022 PWINSTATION_OBJECT Object;
1023 NTSTATUS Status;
1024
1025 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
1026
1027 if (hWinSta == UserGetProcessWindowStation())
1028 {
1029 ERR("Attempted to close process window station\n");
1030 return FALSE;
1031 }
1032
1033 Status = IntValidateWindowStationHandle(hWinSta,
1034 UserMode,
1035 0,
1036 &Object,
1037 NULL);
1038 if (!NT_SUCCESS(Status))
1039 {
1040 ERR("Validation of window station handle (%p) failed\n", hWinSta);
1041 return FALSE;
1042 }
1043
1044 ObDereferenceObject(Object);
1045
1046 TRACE("Closing window station handle (%p)\n", hWinSta);
1047
1048 Status = ObCloseHandle(hWinSta, UserMode);
1049 if (!NT_SUCCESS(Status))
1050 {
1051 SetLastNtError(Status);
1052 return FALSE;
1053 }
1054
1055 return TRUE;
1056 }
1057
1058 /*
1059 * NtUserGetObjectInformation
1060 *
1061 * The NtUserGetObjectInformation function retrieves information about a
1062 * window station or desktop object.
1063 *
1064 * Parameters
1065 * hObj
1066 * Handle to the window station or desktop object for which to
1067 * return information. This can be a handle of type HDESK or HWINSTA
1068 * (for example, a handle returned by NtUserCreateWindowStation,
1069 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1070 *
1071 * nIndex
1072 * Specifies the object information to be retrieved.
1073 *
1074 * pvInfo
1075 * Pointer to a buffer to receive the object information.
1076 *
1077 * nLength
1078 * Specifies the size, in bytes, of the buffer pointed to by the
1079 * pvInfo parameter.
1080 *
1081 * lpnLengthNeeded
1082 * Pointer to a variable receiving the number of bytes required to
1083 * store the requested information. If this variable's value is
1084 * greater than the value of the nLength parameter when the function
1085 * returns, the function returns FALSE, and none of the information
1086 * is copied to the pvInfo buffer. If the value of the variable pointed
1087 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1088 * the entire information block is copied.
1089 *
1090 * Return Value
1091 * If the function succeeds, the return value is nonzero. If the function
1092 * fails, the return value is zero.
1093 *
1094 * Status
1095 * @unimplemented
1096 */
1097
1098 BOOL APIENTRY
NtUserGetObjectInformation(HANDLE hObject,DWORD nIndex,PVOID pvInformation,DWORD nLength,PDWORD nLengthNeeded)1099 NtUserGetObjectInformation(
1100 HANDLE hObject,
1101 DWORD nIndex,
1102 PVOID pvInformation,
1103 DWORD nLength,
1104 PDWORD nLengthNeeded)
1105 {
1106 NTSTATUS Status;
1107 PWINSTATION_OBJECT WinStaObject = NULL;
1108 PDESKTOP DesktopObject = NULL;
1109 POBJECT_HEADER ObjectHeader;
1110 POBJECT_HEADER_NAME_INFO NameInfo;
1111 OBJECT_HANDLE_INFORMATION HandleInfo;
1112 USEROBJECTFLAGS ObjectFlags;
1113 PUNICODE_STRING pStrNameU = NULL;
1114 PVOID pvData = NULL;
1115 SIZE_T nDataSize = 0;
1116
1117 _SEH2_TRY
1118 {
1119 if (nLengthNeeded)
1120 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
1121 ProbeForWrite(pvInformation, nLength, 1);
1122 }
1123 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1124 {
1125 SetLastNtError(_SEH2_GetExceptionCode());
1126 return FALSE;
1127 }
1128 _SEH2_END;
1129
1130 /* Try window station */
1131 TRACE("Trying to open window station 0x%p\n", hObject);
1132 Status = ObReferenceObjectByHandle(hObject,
1133 0,
1134 ExWindowStationObjectType,
1135 UserMode,
1136 (PVOID*)&WinStaObject,
1137 &HandleInfo);
1138
1139 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
1140 {
1141 /* Try desktop */
1142 TRACE("Trying to open desktop %p\n", hObject);
1143 WinStaObject = NULL;
1144 Status = IntValidateDesktopHandle(hObject,
1145 UserMode,
1146 0,
1147 &DesktopObject);
1148 }
1149
1150 if (!NT_SUCCESS(Status))
1151 {
1152 ERR("Failed: 0x%x\n", Status);
1153 goto Exit;
1154 }
1155
1156 TRACE("WinSta or Desktop opened!\n");
1157
1158 /* Get data */
1159 switch (nIndex)
1160 {
1161 case UOI_FLAGS:
1162 {
1163 ObjectFlags.fReserved = FALSE;
1164 ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
1165
1166 ObjectFlags.dwFlags = 0;
1167 if (WinStaObject != NULL)
1168 {
1169 if (!(WinStaObject->Flags & WSS_NOIO))
1170 ObjectFlags.dwFlags |= WSF_VISIBLE;
1171 }
1172 else if (DesktopObject != NULL)
1173 {
1174 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1175 }
1176 else
1177 {
1178 ERR("No associated WinStaObject nor DesktopObject!\n");
1179 }
1180
1181 pvData = &ObjectFlags;
1182 nDataSize = sizeof(ObjectFlags);
1183 Status = STATUS_SUCCESS;
1184 break;
1185 }
1186
1187 case UOI_NAME:
1188 {
1189 if (WinStaObject != NULL)
1190 {
1191 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1192 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1193
1194 if (NameInfo && (NameInfo->Name.Length > 0))
1195 {
1196 /* Named window station */
1197 pStrNameU = &NameInfo->Name;
1198 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1199 }
1200 else
1201 {
1202 /* Unnamed window station (should never happen!) */
1203 ASSERT(FALSE);
1204 pStrNameU = NULL;
1205 nDataSize = sizeof(UNICODE_NULL);
1206 }
1207 Status = STATUS_SUCCESS;
1208 }
1209 else if (DesktopObject != NULL)
1210 {
1211 pvData = DesktopObject->pDeskInfo->szDesktopName;
1212 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
1213 Status = STATUS_SUCCESS;
1214 }
1215 else
1216 {
1217 Status = STATUS_INVALID_PARAMETER;
1218 }
1219 break;
1220 }
1221
1222 case UOI_TYPE:
1223 {
1224 if (WinStaObject != NULL)
1225 {
1226 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1227 pStrNameU = &ObjectHeader->Type->Name;
1228 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1229 Status = STATUS_SUCCESS;
1230 }
1231 else if (DesktopObject != NULL)
1232 {
1233 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject);
1234 pStrNameU = &ObjectHeader->Type->Name;
1235 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1236 Status = STATUS_SUCCESS;
1237 }
1238 else
1239 {
1240 Status = STATUS_INVALID_PARAMETER;
1241 }
1242 break;
1243 }
1244
1245 case UOI_USER_SID:
1246 Status = STATUS_NOT_IMPLEMENTED;
1247 ERR("UOI_USER_SID unimplemented!\n");
1248 break;
1249
1250 default:
1251 Status = STATUS_INVALID_PARAMETER;
1252 break;
1253 }
1254
1255 Exit:
1256 if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
1257 Status = STATUS_BUFFER_TOO_SMALL;
1258
1259 _SEH2_TRY
1260 {
1261 if (nLengthNeeded)
1262 *nLengthNeeded = nDataSize;
1263
1264 /* Try to copy data to caller */
1265 if (Status == STATUS_SUCCESS && (nDataSize > 0))
1266 {
1267 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
1268 if (pvData)
1269 {
1270 /* Copy the data */
1271 RtlCopyMemory(pvInformation, pvData, nDataSize);
1272 }
1273 else if (pStrNameU)
1274 {
1275 /* Copy and NULL-terminate the string */
1276 RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length);
1277 ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
1278 }
1279 else
1280 {
1281 /* Zero the memory */
1282 RtlZeroMemory(pvInformation, nDataSize);
1283 }
1284 }
1285 }
1286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1287 {
1288 Status = _SEH2_GetExceptionCode();
1289 }
1290 _SEH2_END;
1291
1292 /* Release objects */
1293 if (DesktopObject != NULL)
1294 ObDereferenceObject(DesktopObject);
1295 if (WinStaObject != NULL)
1296 ObDereferenceObject(WinStaObject);
1297
1298 if (!NT_SUCCESS(Status))
1299 {
1300 SetLastNtError(Status);
1301 return FALSE;
1302 }
1303
1304 return TRUE;
1305 }
1306
1307 /*
1308 * NtUserSetObjectInformation
1309 *
1310 * The NtUserSetObjectInformation function sets information about a
1311 * window station or desktop object.
1312 *
1313 * Parameters
1314 * hObj
1315 * Handle to the window station or desktop object for which to set
1316 * object information. This value can be a handle of type HDESK or
1317 * HWINSTA.
1318 *
1319 * nIndex
1320 * Specifies the object information to be set.
1321 *
1322 * pvInfo
1323 * Pointer to a buffer containing the object information.
1324 *
1325 * nLength
1326 * Specifies the size, in bytes, of the information contained in the
1327 * buffer pointed to by pvInfo.
1328 *
1329 * Return Value
1330 * If the function succeeds, the return value is nonzero. If the function
1331 * fails the return value is zero.
1332 *
1333 * Status
1334 * @unimplemented
1335 */
1336
1337 BOOL
1338 APIENTRY
NtUserSetObjectInformation(HANDLE hObject,DWORD nIndex,PVOID pvInformation,DWORD nLength)1339 NtUserSetObjectInformation(
1340 HANDLE hObject,
1341 DWORD nIndex,
1342 PVOID pvInformation,
1343 DWORD nLength)
1344 {
1345 /* FIXME: ZwQueryObject */
1346 /* FIXME: ZwSetInformationObject */
1347 SetLastNtError(STATUS_UNSUCCESSFUL);
1348 return FALSE;
1349 }
1350
1351
1352 HWINSTA FASTCALL
UserGetProcessWindowStation(VOID)1353 UserGetProcessWindowStation(VOID)
1354 {
1355 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1356
1357 return ppi->hwinsta;
1358 }
1359
1360
1361 /*
1362 * NtUserGetProcessWindowStation
1363 *
1364 * Returns a handle to the current process window station.
1365 *
1366 * Return Value
1367 * If the function succeeds, the return value is handle to the window
1368 * station assigned to the current process. If the function fails, the
1369 * return value is NULL.
1370 *
1371 * Status
1372 * @implemented
1373 */
1374
1375 HWINSTA APIENTRY
NtUserGetProcessWindowStation(VOID)1376 NtUserGetProcessWindowStation(VOID)
1377 {
1378 return UserGetProcessWindowStation();
1379 }
1380
1381 BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation)1382 UserSetProcessWindowStation(HWINSTA hWindowStation)
1383 {
1384 NTSTATUS Status;
1385 PPROCESSINFO ppi;
1386 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1387 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
1388 HWINSTA hCacheWinSta;
1389
1390 ppi = PsGetCurrentProcessWin32Process();
1391
1392 /* Reference the new window station */
1393 if (hWindowStation != NULL)
1394 {
1395 Status = IntValidateWindowStationHandle(hWindowStation,
1396 UserMode,
1397 0,
1398 &NewWinSta,
1399 &ObjectHandleInfo);
1400 if (!NT_SUCCESS(Status))
1401 {
1402 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
1403 SetLastNtError(Status);
1404 return FALSE;
1405 }
1406 }
1407
1408 OldWinSta = ppi->prpwinsta;
1409 hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
1410
1411 /* Dereference the previous window station */
1412 if (OldWinSta != NULL)
1413 {
1414 ObDereferenceObject(OldWinSta);
1415 }
1416
1417 /*
1418 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1419 */
1420
1421 /* Close the cached EPROCESS window station handle if needed */
1422 if (hCacheWinSta != NULL)
1423 {
1424 /* Reference the window station */
1425 Status = ObReferenceObjectByHandle(hCacheWinSta,
1426 0,
1427 ExWindowStationObjectType,
1428 UserMode,
1429 (PVOID*)&OldWinSta,
1430 NULL);
1431 if (!NT_SUCCESS(Status))
1432 {
1433 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
1434 /* We failed, reset the cache */
1435 hCacheWinSta = NULL;
1436 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1437 }
1438 else
1439 {
1440 /*
1441 * Close the old handle and reset the cache only
1442 * if we are setting a different window station.
1443 */
1444 if (NewWinSta != OldWinSta)
1445 {
1446 ObCloseHandle(hCacheWinSta, UserMode);
1447 hCacheWinSta = NULL;
1448 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1449 }
1450
1451 /* Dereference the window station */
1452 ObDereferenceObject(OldWinSta);
1453 }
1454 }
1455
1456 /* Duplicate and save a new cached EPROCESS window station handle */
1457 if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
1458 {
1459 Status = ZwDuplicateObject(ZwCurrentProcess(),
1460 hWindowStation,
1461 ZwCurrentProcess(),
1462 (PHANDLE)&hCacheWinSta,
1463 0,
1464 0,
1465 DUPLICATE_SAME_ACCESS);
1466 if (!NT_SUCCESS(Status))
1467 {
1468 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
1469 }
1470 else
1471 {
1472 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1473 }
1474 }
1475
1476 ppi->prpwinsta = NewWinSta;
1477 ppi->hwinsta = hWindowStation;
1478 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
1479 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
1480
1481 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
1482 {
1483 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
1484 }
1485 else
1486 {
1487 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
1488 }
1489
1490 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
1491 {
1492 ppi->W32PF_flags |= W32PF_IOWINSTA;
1493 }
1494 else /* Might be closed if the handle is NULL */
1495 {
1496 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
1497 }
1498 return TRUE;
1499 }
1500
1501 /*
1502 * NtUserSetProcessWindowStation
1503 *
1504 * Assigns a window station to the current process.
1505 *
1506 * Parameters
1507 * hWinSta
1508 * Handle to the window station.
1509 *
1510 * Return Value
1511 * Status
1512 *
1513 * Status
1514 * @implemented
1515 */
1516
1517 BOOL APIENTRY
NtUserSetProcessWindowStation(HWINSTA hWindowStation)1518 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1519 {
1520 BOOL ret;
1521
1522 UserEnterExclusive();
1523
1524 ret = UserSetProcessWindowStation(hWindowStation);
1525
1526 UserLeave();
1527
1528 return ret;
1529 }
1530
1531 /*
1532 * NtUserLockWindowStation
1533 *
1534 * Locks switching desktops. Only the logon application is allowed to call this function.
1535 *
1536 * Status
1537 * @implemented
1538 */
1539
1540 BOOL APIENTRY
NtUserLockWindowStation(HWINSTA hWindowStation)1541 NtUserLockWindowStation(HWINSTA hWindowStation)
1542 {
1543 PWINSTATION_OBJECT Object;
1544 NTSTATUS Status;
1545
1546 TRACE("About to set process window station with handle (%p)\n",
1547 hWindowStation);
1548
1549 if (gpidLogon != PsGetCurrentProcessId())
1550 {
1551 ERR("Unauthorized process attempted to lock the window station!\n");
1552 EngSetLastError(ERROR_ACCESS_DENIED);
1553 return FALSE;
1554 }
1555
1556 Status = IntValidateWindowStationHandle(hWindowStation,
1557 UserMode,
1558 0,
1559 &Object,
1560 NULL);
1561 if (!NT_SUCCESS(Status))
1562 {
1563 TRACE("Validation of window station handle (%p) failed\n",
1564 hWindowStation);
1565 SetLastNtError(Status);
1566 return FALSE;
1567 }
1568
1569 Object->Flags |= WSS_LOCKED;
1570
1571 ObDereferenceObject(Object);
1572 return TRUE;
1573 }
1574
1575 /*
1576 * NtUserUnlockWindowStation
1577 *
1578 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1579 *
1580 * Status
1581 * @implemented
1582 */
1583
1584 BOOL APIENTRY
NtUserUnlockWindowStation(HWINSTA hWindowStation)1585 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1586 {
1587 PWINSTATION_OBJECT Object;
1588 NTSTATUS Status;
1589 BOOL Ret;
1590
1591 TRACE("About to set process window station with handle (%p)\n",
1592 hWindowStation);
1593
1594 if (gpidLogon != PsGetCurrentProcessId())
1595 {
1596 ERR("Unauthorized process attempted to unlock the window station!\n");
1597 EngSetLastError(ERROR_ACCESS_DENIED);
1598 return FALSE;
1599 }
1600
1601 Status = IntValidateWindowStationHandle(hWindowStation,
1602 UserMode,
1603 0,
1604 &Object,
1605 NULL);
1606 if (!NT_SUCCESS(Status))
1607 {
1608 TRACE("Validation of window station handle (%p) failed\n",
1609 hWindowStation);
1610 SetLastNtError(Status);
1611 return FALSE;
1612 }
1613
1614 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1615 Object->Flags &= ~WSS_LOCKED;
1616
1617 ObDereferenceObject(Object);
1618 return Ret;
1619 }
1620
1621 static NTSTATUS FASTCALL
BuildWindowStationNameList(ULONG dwSize,PVOID lpBuffer,PULONG pRequiredSize)1622 BuildWindowStationNameList(
1623 ULONG dwSize,
1624 PVOID lpBuffer,
1625 PULONG pRequiredSize)
1626 {
1627 OBJECT_ATTRIBUTES ObjectAttributes;
1628 NTSTATUS Status;
1629 HANDLE DirectoryHandle;
1630 char InitialBuffer[256], *Buffer;
1631 ULONG Context, ReturnLength, BufferSize;
1632 DWORD EntryCount;
1633 POBJECT_DIRECTORY_INFORMATION DirEntry;
1634 WCHAR NullWchar;
1635
1636 //
1637 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1638 // with judicious parameters one can create window stations elsewhere
1639 // than in Windows\WindowStations directory, Win32k definitely MUST
1640 // maintain a list of window stations it has created, and not rely
1641 // on the enumeration of Windows\WindowStations !!!
1642 //
1643
1644 /*
1645 * Try to open the directory.
1646 */
1647 InitializeObjectAttributes(&ObjectAttributes,
1648 &gustrWindowStationsDir,
1649 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1650 NULL,
1651 NULL);
1652
1653 Status = ZwOpenDirectoryObject(&DirectoryHandle,
1654 DIRECTORY_QUERY,
1655 &ObjectAttributes);
1656
1657 if (!NT_SUCCESS(Status))
1658 {
1659 return Status;
1660 }
1661
1662 /* First try to query the directory using a fixed-size buffer */
1663 Context = 0;
1664 Buffer = NULL;
1665 Status = ZwQueryDirectoryObject(DirectoryHandle,
1666 InitialBuffer,
1667 sizeof(InitialBuffer),
1668 FALSE,
1669 TRUE,
1670 &Context,
1671 &ReturnLength);
1672 if (NT_SUCCESS(Status))
1673 {
1674 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1675 FALSE, &Context, NULL))
1676 {
1677 /* Our fixed-size buffer is large enough */
1678 Buffer = InitialBuffer;
1679 }
1680 }
1681
1682 if (NULL == Buffer)
1683 {
1684 /* Need a larger buffer, check how large exactly */
1685 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1686 &ReturnLength);
1687 if (!NT_SUCCESS(Status))
1688 {
1689 ERR("ZwQueryDirectoryObject failed\n");
1690 ZwClose(DirectoryHandle);
1691 return Status;
1692 }
1693
1694 BufferSize = ReturnLength;
1695 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1696 if (NULL == Buffer)
1697 {
1698 ZwClose(DirectoryHandle);
1699 return STATUS_NO_MEMORY;
1700 }
1701
1702 /* We should have a sufficiently large buffer now */
1703 Context = 0;
1704 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1705 FALSE, TRUE, &Context, &ReturnLength);
1706 if (! NT_SUCCESS(Status) ||
1707 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1708 FALSE, &Context, NULL))
1709 {
1710 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1711 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1712 ZwClose(DirectoryHandle);
1713 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1714 }
1715 }
1716
1717 ZwClose(DirectoryHandle);
1718
1719 /*
1720 * Count the required size of buffer.
1721 */
1722 ReturnLength = sizeof(DWORD);
1723 EntryCount = 0;
1724 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1725 0 != DirEntry->Name.Length;
1726 DirEntry++)
1727 {
1728 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1729 EntryCount++;
1730 }
1731 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1732 if (NULL != pRequiredSize)
1733 {
1734 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1735 if (! NT_SUCCESS(Status))
1736 {
1737 if (Buffer != InitialBuffer)
1738 {
1739 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1740 }
1741 return STATUS_BUFFER_TOO_SMALL;
1742 }
1743 }
1744
1745 /*
1746 * Check if the supplied buffer is large enough.
1747 */
1748 if (dwSize < ReturnLength)
1749 {
1750 if (Buffer != InitialBuffer)
1751 {
1752 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1753 }
1754 return STATUS_BUFFER_TOO_SMALL;
1755 }
1756
1757 /*
1758 * Generate the resulting buffer contents.
1759 */
1760 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1761 if (! NT_SUCCESS(Status))
1762 {
1763 if (Buffer != InitialBuffer)
1764 {
1765 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1766 }
1767 return Status;
1768 }
1769 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1770
1771 NullWchar = L'\0';
1772 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1773 0 != DirEntry->Name.Length;
1774 DirEntry++)
1775 {
1776 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1777 if (! NT_SUCCESS(Status))
1778 {
1779 if (Buffer != InitialBuffer)
1780 {
1781 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1782 }
1783 return Status;
1784 }
1785 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1786 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1787 if (! NT_SUCCESS(Status))
1788 {
1789 if (Buffer != InitialBuffer)
1790 {
1791 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1792 }
1793 return Status;
1794 }
1795 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1796 }
1797
1798 /*
1799 * Clean up
1800 */
1801 if (Buffer != InitialBuffer)
1802 {
1803 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1804 }
1805
1806 return STATUS_SUCCESS;
1807 }
1808
1809 static NTSTATUS FASTCALL
BuildDesktopNameList(HWINSTA hWindowStation,ULONG dwSize,PVOID lpBuffer,PULONG pRequiredSize)1810 BuildDesktopNameList(
1811 HWINSTA hWindowStation,
1812 ULONG dwSize,
1813 PVOID lpBuffer,
1814 PULONG pRequiredSize)
1815 {
1816 NTSTATUS Status;
1817 PWINSTATION_OBJECT WindowStation;
1818 PLIST_ENTRY DesktopEntry;
1819 PDESKTOP DesktopObject;
1820 DWORD EntryCount;
1821 ULONG ReturnLength;
1822 WCHAR NullWchar;
1823 UNICODE_STRING DesktopName;
1824
1825 Status = IntValidateWindowStationHandle(hWindowStation,
1826 UserMode,
1827 0,
1828 &WindowStation,
1829 NULL);
1830 if (! NT_SUCCESS(Status))
1831 {
1832 return Status;
1833 }
1834
1835 /*
1836 * Count the required size of buffer.
1837 */
1838 ReturnLength = sizeof(DWORD);
1839 EntryCount = 0;
1840 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1841 DesktopEntry != &WindowStation->DesktopListHead;
1842 DesktopEntry = DesktopEntry->Flink)
1843 {
1844 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1845 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1846 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1847 EntryCount++;
1848 }
1849 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1850 if (NULL != pRequiredSize)
1851 {
1852 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1853 if (! NT_SUCCESS(Status))
1854 {
1855 ObDereferenceObject(WindowStation);
1856 return STATUS_BUFFER_TOO_SMALL;
1857 }
1858 }
1859
1860 /*
1861 * Check if the supplied buffer is large enough.
1862 */
1863 if (dwSize < ReturnLength)
1864 {
1865 ObDereferenceObject(WindowStation);
1866 return STATUS_BUFFER_TOO_SMALL;
1867 }
1868
1869 /*
1870 * Generate the resulting buffer contents.
1871 */
1872 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1873 if (! NT_SUCCESS(Status))
1874 {
1875 ObDereferenceObject(WindowStation);
1876 return Status;
1877 }
1878 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1879
1880 NullWchar = L'\0';
1881 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1882 DesktopEntry != &WindowStation->DesktopListHead;
1883 DesktopEntry = DesktopEntry->Flink)
1884 {
1885 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1886 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1887 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1888 if (! NT_SUCCESS(Status))
1889 {
1890 ObDereferenceObject(WindowStation);
1891 return Status;
1892 }
1893 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1894 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1895 if (! NT_SUCCESS(Status))
1896 {
1897 ObDereferenceObject(WindowStation);
1898 return Status;
1899 }
1900 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1901 }
1902
1903 /*
1904 * Clean up and return
1905 */
1906 ObDereferenceObject(WindowStation);
1907 return STATUS_SUCCESS;
1908 }
1909
1910 /*
1911 * NtUserBuildNameList
1912 *
1913 * Function used for enumeration of desktops or window stations.
1914 *
1915 * Parameters
1916 * hWinSta
1917 * For enumeration of window stations this parameter must be set to
1918 * zero. Otherwise it's handle for window station.
1919 *
1920 * dwSize
1921 * Size of buffer passed by caller.
1922 *
1923 * lpBuffer
1924 * Buffer passed by caller. If the function succeeds, the buffer is
1925 * filled with window station/desktop count (in first DWORD) and
1926 * NULL-terminated window station/desktop names.
1927 *
1928 * pRequiredSize
1929 * If the function succeeds, this is the number of bytes copied.
1930 * Otherwise it's size of buffer needed for function to succeed.
1931 *
1932 * Status
1933 * @implemented
1934 */
1935
1936 NTSTATUS APIENTRY
NtUserBuildNameList(HWINSTA hWindowStation,ULONG dwSize,PVOID lpBuffer,PULONG pRequiredSize)1937 NtUserBuildNameList(
1938 HWINSTA hWindowStation,
1939 ULONG dwSize,
1940 PVOID lpBuffer,
1941 PULONG pRequiredSize)
1942 {
1943 /* The WindowStation name list and desktop name list are build in completely
1944 different ways. Call the appropriate function */
1945 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1946 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1947 }
1948
1949 /*
1950 * @implemented
1951 */
1952 BOOL APIENTRY
NtUserSetLogonNotifyWindow(HWND hWnd)1953 NtUserSetLogonNotifyWindow(HWND hWnd)
1954 {
1955 if (gpidLogon != PsGetCurrentProcessId())
1956 {
1957 return FALSE;
1958 }
1959
1960 if (!IntIsWindow(hWnd))
1961 {
1962 return FALSE;
1963 }
1964
1965 hwndSAS = hWnd;
1966
1967 return TRUE;
1968 }
1969
1970 BOOL
1971 APIENTRY
NtUserLockWorkStation(VOID)1972 NtUserLockWorkStation(VOID)
1973 {
1974 BOOL ret;
1975 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1976
1977 UserEnterExclusive();
1978
1979 if (pti->rpdesk == IntGetActiveDesktop())
1980 {
1981 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1982 }
1983 else
1984 {
1985 ret = FALSE;
1986 }
1987
1988 UserLeave();
1989
1990 return ret;
1991 }
1992
1993 BOOL
1994 NTAPI
NtUserSetWindowStationUser(IN HWINSTA hWindowStation,IN PLUID pluid,IN PSID psid OPTIONAL,IN DWORD size)1995 NtUserSetWindowStationUser(
1996 IN HWINSTA hWindowStation,
1997 IN PLUID pluid,
1998 IN PSID psid OPTIONAL,
1999 IN DWORD size)
2000 {
2001 BOOL Ret = FALSE;
2002 NTSTATUS Status;
2003 PWINSTATION_OBJECT WindowStation = NULL;
2004 LUID luidUser;
2005
2006 UserEnterExclusive();
2007
2008 if (gpidLogon != PsGetCurrentProcessId())
2009 {
2010 EngSetLastError(ERROR_ACCESS_DENIED);
2011 goto Leave;
2012 }
2013
2014 /* Validate the window station */
2015 Status = IntValidateWindowStationHandle(hWindowStation,
2016 UserMode,
2017 0,
2018 &WindowStation,
2019 NULL);
2020 if (!NT_SUCCESS(Status))
2021 {
2022 goto Leave;
2023 }
2024
2025 /* Capture the user LUID */
2026 _SEH2_TRY
2027 {
2028 ProbeForRead(pluid, sizeof(LUID), 1);
2029 luidUser = *pluid;
2030 }
2031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2032 {
2033 Status = _SEH2_GetExceptionCode();
2034 _SEH2_YIELD(goto Leave);
2035 }
2036 _SEH2_END;
2037
2038 /* Reset the window station user LUID */
2039 RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
2040
2041 /* Reset the window station user SID */
2042 if (WindowStation->psidUser)
2043 {
2044 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2045 WindowStation->psidUser = NULL;
2046 }
2047
2048 /* Copy the new user SID if one has been provided */
2049 if (psid)
2050 {
2051 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
2052 if (WindowStation->psidUser == NULL)
2053 {
2054 EngSetLastError(ERROR_OUTOFMEMORY);
2055 goto Leave;
2056 }
2057
2058 Status = STATUS_SUCCESS;
2059 _SEH2_TRY
2060 {
2061 ProbeForRead(psid, size, 1);
2062 RtlCopyMemory(WindowStation->psidUser, psid, size);
2063 }
2064 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2065 {
2066 Status = _SEH2_GetExceptionCode();
2067 }
2068 _SEH2_END;
2069
2070 if (!NT_SUCCESS(Status))
2071 {
2072 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2073 WindowStation->psidUser = NULL;
2074 goto Leave;
2075 }
2076 }
2077
2078 /* Copy the new user LUID */
2079 WindowStation->luidUser = luidUser;
2080
2081 Ret = TRUE;
2082
2083 Leave:
2084 if (WindowStation)
2085 ObDereferenceObject(WindowStation);
2086
2087 UserLeave();
2088 return Ret;
2089 }
2090
2091 /* EOF */
2092