4c91558b49715b8782b159f2e7a7c2973db8fbd6
[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 /*
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
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
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
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
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
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
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
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
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
371 IntGetScreenDC(VOID)
372 {
373 return ScreenDeviceContext;
374 }
375
376 BOOL FASTCALL
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
399 /* PUBLIC FUNCTIONS ***********************************************************/
400
401 /*
402 * NtUserCreateWindowStation
403 *
404 * Creates a new window station.
405 *
406 * Parameters
407 * lpszWindowStationName
408 * Pointer to a null-terminated string specifying the name of the
409 * window station to be created. Window station names are
410 * case-insensitive and cannot contain backslash characters (\).
411 * Only members of the Administrators group are allowed to specify a
412 * name.
413 *
414 * dwDesiredAccess
415 * Requested type of access
416 *
417 * lpSecurity
418 * Security descriptor
419 *
420 * Unknown3, Unknown4, Unknown5, Unknown6
421 * Unused
422 *
423 * Return Value
424 * If the function succeeds, the return value is a handle to the newly
425 * created window station. If the specified window station already
426 * exists, the function succeeds and returns a handle to the existing
427 * window station. If the function fails, the return value is NULL.
428 *
429 * Status
430 * @implemented
431 */
432
433 NTSTATUS
434 FASTCALL
435 IntCreateWindowStation(
436 OUT HWINSTA* phWinSta,
437 IN POBJECT_ATTRIBUTES ObjectAttributes,
438 IN KPROCESSOR_MODE AccessMode,
439 IN KPROCESSOR_MODE OwnerMode,
440 IN ACCESS_MASK dwDesiredAccess,
441 DWORD Unknown2,
442 DWORD Unknown3,
443 DWORD Unknown4,
444 DWORD Unknown5,
445 DWORD Unknown6)
446 {
447 NTSTATUS Status;
448 HWINSTA hWinSta;
449 PWINSTATION_OBJECT WindowStation;
450
451 TRACE("IntCreateWindowStation called\n");
452
453 ASSERT(phWinSta);
454 *phWinSta = NULL;
455
456 Status = ObOpenObjectByName(ObjectAttributes,
457 ExWindowStationObjectType,
458 AccessMode,
459 NULL,
460 dwDesiredAccess,
461 NULL,
462 (PVOID*)&hWinSta);
463 if (NT_SUCCESS(Status))
464 {
465 TRACE("IntCreateWindowStation opened window station '%wZ'\n",
466 ObjectAttributes->ObjectName);
467 *phWinSta = hWinSta;
468 return Status;
469 }
470
471 /*
472 * No existing window station found, try to create a new one.
473 */
474
475 /* Create the window station object */
476 Status = ObCreateObject(AccessMode,
477 ExWindowStationObjectType,
478 ObjectAttributes,
479 OwnerMode,
480 NULL,
481 sizeof(WINSTATION_OBJECT),
482 0,
483 0,
484 (PVOID*)&WindowStation);
485 if (!NT_SUCCESS(Status))
486 {
487 ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
488 ObjectAttributes->ObjectName, Status);
489 SetLastNtError(Status);
490 return Status;
491 }
492
493 /* Initialize the window station */
494 RtlZeroMemory(WindowStation, sizeof(WINSTATION_OBJECT));
495
496 InitializeListHead(&WindowStation->DesktopListHead);
497 WindowStation->dwSessionId = NtCurrentPeb()->SessionId;
498 Status = RtlCreateAtomTable(37, &WindowStation->AtomTable);
499 if (!NT_SUCCESS(Status))
500 {
501 ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
502 ObjectAttributes->ObjectName, Status);
503 ObDereferenceObject(WindowStation);
504 SetLastNtError(Status);
505 return Status;
506 }
507
508 Status = ObInsertObject(WindowStation,
509 NULL,
510 dwDesiredAccess,
511 0,
512 NULL,
513 (PVOID*)&hWinSta);
514 if (!NT_SUCCESS(Status))
515 {
516 ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status);
517 SetLastNtError(Status);
518 return Status;
519 }
520
521 // FIXME! TODO: Add this new window station to a linked list
522
523 if (InputWindowStation == NULL)
524 {
525 ERR("Initializing input window station\n");
526
527 /* Only Winlogon can create the interactive window station */
528 ASSERT(gpidLogon == PsGetCurrentProcessId());
529
530 InputWindowStation = WindowStation;
531 WindowStation->Flags &= ~WSS_NOIO;
532
533 InitCursorImpl();
534
535 UserCreateSystemThread(ST_DESKTOP_THREAD);
536 UserCreateSystemThread(ST_RIT);
537
538 /* Desktop functions require the desktop thread running so wait for it to initialize */
539 UserLeaveCo();
540 KeWaitForSingleObject(gpDesktopThreadStartedEvent,
541 UserRequest,
542 UserMode,
543 FALSE,
544 NULL);
545 UserEnterCo();
546 }
547 else
548 {
549 WindowStation->Flags |= WSS_NOIO;
550 }
551
552 TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
553 ObjectAttributes->ObjectName, WindowStation, hWinSta);
554
555 *phWinSta = hWinSta;
556 EngSetLastError(ERROR_SUCCESS);
557
558 return STATUS_SUCCESS;
559 }
560
561 static VOID
562 FreeUserModeWindowStationName(
563 IN OUT PUNICODE_STRING WindowStationName,
564 IN PUNICODE_STRING TebStaticUnicodeString,
565 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL,
566 IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL)
567 {
568 SIZE_T MemSize = 0;
569
570 /* Try to restore the user's UserModeObjectAttributes */
571 if (UserModeObjectAttributes && LocalObjectAttributes)
572 {
573 _SEH2_TRY
574 {
575 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
576 *UserModeObjectAttributes = *LocalObjectAttributes;
577 }
578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
579 {
580 NOTHING;
581 }
582 _SEH2_END;
583 }
584
585 /* Free the user-mode memory */
586 if (WindowStationName && (WindowStationName != TebStaticUnicodeString))
587 {
588 ZwFreeVirtualMemory(ZwCurrentProcess(),
589 (PVOID*)&WindowStationName,
590 &MemSize,
591 MEM_RELEASE);
592 }
593 }
594
595 static NTSTATUS
596 BuildUserModeWindowStationName(
597 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes,
598 IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes,
599 OUT PUNICODE_STRING* WindowStationName,
600 OUT PUNICODE_STRING* TebStaticUnicodeString)
601 {
602 NTSTATUS Status;
603 SIZE_T MemSize;
604
605 LUID CallerLuid;
606 PTEB Teb;
607 USHORT StrSize;
608
609 *WindowStationName = NULL;
610 *TebStaticUnicodeString = NULL;
611
612 /* Retrieve the current process LUID */
613 Status = GetProcessLuid(NULL, NULL, &CallerLuid);
614 if (!NT_SUCCESS(Status))
615 {
616 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status);
617 return Status;
618 }
619
620 /* Compute the needed string size */
621 MemSize = _scwprintf(L"%wZ\\Service-0x%x-%x$",
622 &gustrWindowStationsDir,
623 CallerLuid.HighPart,
624 CallerLuid.LowPart);
625 MemSize = MemSize * sizeof(WCHAR) + sizeof(UNICODE_NULL);
626 if (MemSize > MAXUSHORT)
627 {
628 ERR("Window station name length is too long.\n");
629 return STATUS_NAME_TOO_LONG;
630 }
631 StrSize = (USHORT)MemSize;
632
633 /*
634 * Check whether it's short enough so that we can use the static buffer
635 * in the TEB. Otherwise continue with virtual memory allocation.
636 */
637 Teb = NtCurrentTeb();
638 if (Teb && (StrSize <= sizeof(Teb->StaticUnicodeBuffer)))
639 {
640 /* We can use the TEB's static unicode string */
641 ASSERT(Teb->StaticUnicodeString.Buffer == Teb->StaticUnicodeBuffer);
642 ASSERT(Teb->StaticUnicodeString.MaximumLength == sizeof(Teb->StaticUnicodeBuffer));
643
644 /* Remember the TEB's static unicode string address for later */
645 *TebStaticUnicodeString = &Teb->StaticUnicodeString;
646
647 *WindowStationName = *TebStaticUnicodeString;
648 (*WindowStationName)->Length = 0;
649 }
650 else
651 {
652 /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
653 MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID));
654
655 /* Allocate the memory in user-mode */
656 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
657 (PVOID*)WindowStationName,
658 0,
659 &MemSize,
660 MEM_COMMIT,
661 PAGE_READWRITE);
662 if (!NT_SUCCESS(Status))
663 {
664 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status);
665 return Status;
666 }
667
668 RtlInitEmptyUnicodeString(*WindowStationName,
669 (PWCHAR)((ULONG_PTR)*WindowStationName +
670 ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))),
671 StrSize);
672 }
673
674 /* Build a valid window station name from the LUID */
675 Status = RtlStringCbPrintfW((*WindowStationName)->Buffer,
676 (*WindowStationName)->MaximumLength,
677 L"%wZ\\Service-0x%x-%x$",
678 &gustrWindowStationsDir,
679 CallerLuid.HighPart,
680 CallerLuid.LowPart);
681 if (!NT_SUCCESS(Status))
682 {
683 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
684 goto Quit;
685 }
686 (*WindowStationName)->Length = (USHORT)(wcslen((*WindowStationName)->Buffer) * sizeof(WCHAR));
687
688 /* Try to update the user's UserModeObjectAttributes */
689 _SEH2_TRY
690 {
691 ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
692 *LocalObjectAttributes = *UserModeObjectAttributes;
693
694 UserModeObjectAttributes->ObjectName = *WindowStationName;
695 UserModeObjectAttributes->RootDirectory = NULL;
696
697 Status = STATUS_SUCCESS;
698 }
699 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
700 {
701 Status = _SEH2_GetExceptionCode();
702 }
703 _SEH2_END;
704
705 Quit:
706 if (!NT_SUCCESS(Status))
707 {
708 /* Release the window station name */
709 FreeUserModeWindowStationName(*WindowStationName,
710 *TebStaticUnicodeString,
711 NULL, NULL);
712 }
713
714 return Status;
715 }
716
717 HWINSTA
718 APIENTRY
719 NtUserCreateWindowStation(
720 IN POBJECT_ATTRIBUTES ObjectAttributes,
721 IN ACCESS_MASK dwDesiredAccess,
722 DWORD Unknown2,
723 DWORD Unknown3,
724 DWORD Unknown4,
725 DWORD Unknown5,
726 DWORD Unknown6)
727 {
728 NTSTATUS Status = STATUS_SUCCESS;
729 HWINSTA hWinSta = NULL;
730 OBJECT_ATTRIBUTES LocalObjectAttributes;
731 PUNICODE_STRING WindowStationName = NULL;
732 PUNICODE_STRING TebStaticUnicodeString = NULL;
733 KPROCESSOR_MODE OwnerMode = UserMode;
734
735 TRACE("NtUserCreateWindowStation called\n");
736
737 /* Capture the object attributes and the window station name */
738 _SEH2_TRY
739 {
740 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
741 LocalObjectAttributes = *ObjectAttributes;
742 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
743 {
744 ERR("Invalid ObjectAttributes length!\n");
745 Status = STATUS_INVALID_PARAMETER;
746 _SEH2_LEAVE;
747 }
748
749 /*
750 * Check whether the caller provided a window station name together
751 * with a RootDirectory handle.
752 *
753 * If the caller did not provide a window station name, build a new one
754 * based on the logon session identifier for the calling process.
755 * The new name is allocated in user-mode, as the rest of ObjectAttributes
756 * already is, so that the validation performed by the Object Manager
757 * can be done adequately.
758 */
759 if ((LocalObjectAttributes.ObjectName == NULL ||
760 LocalObjectAttributes.ObjectName->Buffer == NULL ||
761 LocalObjectAttributes.ObjectName->Length == 0 ||
762 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
763 /* &&
764 LocalObjectAttributes.RootDirectory == NULL */)
765 {
766 /* No, build the new window station name */
767 Status = BuildUserModeWindowStationName(ObjectAttributes,
768 &LocalObjectAttributes,
769 &WindowStationName,
770 &TebStaticUnicodeString);
771 if (!NT_SUCCESS(Status))
772 {
773 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
774 _SEH2_LEAVE;
775 }
776 OwnerMode = KernelMode;
777 }
778 }
779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
780 {
781 Status =_SEH2_GetExceptionCode();
782 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
783 }
784 _SEH2_END;
785
786 if (!NT_SUCCESS(Status))
787 {
788 SetLastNtError(Status);
789 return NULL;
790 }
791
792 UserEnterExclusive();
793
794 /* Create the window station */
795 Status = IntCreateWindowStation(&hWinSta,
796 ObjectAttributes,
797 UserMode,
798 OwnerMode,
799 dwDesiredAccess,
800 Unknown2,
801 Unknown3,
802 Unknown4,
803 Unknown5,
804 Unknown6);
805 UserLeave();
806
807 if (NT_SUCCESS(Status))
808 {
809 TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
810 ObjectAttributes->ObjectName, hWinSta);
811 }
812 else
813 {
814 ASSERT(hWinSta == NULL);
815 ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
816 ObjectAttributes->ObjectName, Status);
817 }
818
819 /* Try to restore the user's ObjectAttributes and release the window station name */
820 FreeUserModeWindowStationName(WindowStationName,
821 TebStaticUnicodeString,
822 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
823 &LocalObjectAttributes);
824
825 if (!NT_SUCCESS(Status))
826 {
827 ASSERT(hWinSta == NULL);
828 SetLastNtError(Status);
829 }
830
831 return hWinSta;
832 }
833
834 /*
835 * NtUserOpenWindowStation
836 *
837 * Opens an existing window station.
838 *
839 * Parameters
840 * lpszWindowStationName
841 * Name of the existing window station.
842 *
843 * dwDesiredAccess
844 * Requested type of access.
845 *
846 * Return Value
847 * If the function succeeds, the return value is the handle to the
848 * specified window station. If the function fails, the return value
849 * is NULL.
850 *
851 * Remarks
852 * The returned handle can be closed with NtUserCloseWindowStation.
853 *
854 * Status
855 * @implemented
856 */
857
858 HWINSTA
859 APIENTRY
860 NtUserOpenWindowStation(
861 IN POBJECT_ATTRIBUTES ObjectAttributes,
862 IN ACCESS_MASK dwDesiredAccess)
863 {
864 NTSTATUS Status = STATUS_SUCCESS;
865 HWINSTA hWinSta = NULL;
866 OBJECT_ATTRIBUTES LocalObjectAttributes;
867 PUNICODE_STRING WindowStationName = NULL;
868 PUNICODE_STRING TebStaticUnicodeString = NULL;
869 KPROCESSOR_MODE OwnerMode = UserMode;
870
871 TRACE("NtUserOpenWindowStation called\n");
872
873 /* Capture the object attributes and the window station name */
874 _SEH2_TRY
875 {
876 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
877 LocalObjectAttributes = *ObjectAttributes;
878 if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
879 {
880 ERR("Invalid ObjectAttributes length!\n");
881 Status = STATUS_INVALID_PARAMETER;
882 _SEH2_LEAVE;
883 }
884
885 /*
886 * Check whether the caller did not provide a window station name,
887 * or provided the special "Service-0x00000000-00000000$" name.
888 *
889 * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
890 * is used instead of an empty name (observed when API-monitoring
891 * OpenWindowStation() called with an empty window station name).
892 */
893 if ((LocalObjectAttributes.ObjectName == NULL ||
894 LocalObjectAttributes.ObjectName->Buffer == NULL ||
895 LocalObjectAttributes.ObjectName->Length == 0 ||
896 LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
897 /* &&
898 LocalObjectAttributes.RootDirectory == NULL */)
899 {
900 /* No, remember that for later */
901 LocalObjectAttributes.ObjectName = NULL;
902 }
903 if (LocalObjectAttributes.ObjectName &&
904 LocalObjectAttributes.ObjectName->Length ==
905 sizeof(L"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL) &&
906 _wcsnicmp(LocalObjectAttributes.ObjectName->Buffer,
907 L"Service-0x00000000-00000000$",
908 LocalObjectAttributes.ObjectName->Length / sizeof(WCHAR)) == 0)
909 {
910 /* No, remember that for later */
911 LocalObjectAttributes.ObjectName = NULL;
912 }
913
914 /*
915 * If the caller did not provide a window station name, build a new one
916 * based on the logon session identifier for the calling process.
917 * The new name is allocated in user-mode, as the rest of ObjectAttributes
918 * already is, so that the validation performed by the Object Manager
919 * can be done adequately.
920 */
921 if (!LocalObjectAttributes.ObjectName)
922 {
923 /* No, build the new window station name */
924 Status = BuildUserModeWindowStationName(ObjectAttributes,
925 &LocalObjectAttributes,
926 &WindowStationName,
927 &TebStaticUnicodeString);
928 if (!NT_SUCCESS(Status))
929 {
930 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
931 _SEH2_LEAVE;
932 }
933 OwnerMode = KernelMode;
934 }
935 }
936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
937 {
938 Status =_SEH2_GetExceptionCode();
939 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
940 }
941 _SEH2_END;
942
943 if (!NT_SUCCESS(Status))
944 {
945 SetLastNtError(Status);
946 return NULL;
947 }
948
949 /* Open the window station */
950 Status = ObOpenObjectByName(ObjectAttributes,
951 ExWindowStationObjectType,
952 UserMode,
953 NULL,
954 dwDesiredAccess,
955 NULL,
956 (PVOID*)&hWinSta);
957 if (NT_SUCCESS(Status))
958 {
959 TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
960 ObjectAttributes->ObjectName, hWinSta);
961 }
962 else
963 {
964 ASSERT(hWinSta == NULL);
965 ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
966 ObjectAttributes->ObjectName, Status);
967 }
968
969 /* Try to restore the user's ObjectAttributes and release the window station name */
970 FreeUserModeWindowStationName(WindowStationName,
971 TebStaticUnicodeString,
972 (OwnerMode == KernelMode ? ObjectAttributes : NULL),
973 &LocalObjectAttributes);
974
975 if (!NT_SUCCESS(Status))
976 {
977 ASSERT(hWinSta == NULL);
978 SetLastNtError(Status);
979 }
980
981 return hWinSta;
982 }
983
984 /*
985 * NtUserCloseWindowStation
986 *
987 * Closes a window station handle.
988 *
989 * Parameters
990 * hWinSta
991 * Handle to the window station.
992 *
993 * Return Value
994 * Status
995 *
996 * Remarks
997 * The window station handle can be created with NtUserCreateWindowStation
998 * or NtUserOpenWindowStation. Attempts to close a handle to the window
999 * station assigned to the calling process will fail.
1000 *
1001 * Status
1002 * @implemented
1003 */
1004
1005 BOOL
1006 APIENTRY
1007 NtUserCloseWindowStation(
1008 HWINSTA hWinSta)
1009 {
1010 PWINSTATION_OBJECT Object;
1011 NTSTATUS Status;
1012
1013 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
1014
1015 if (hWinSta == UserGetProcessWindowStation())
1016 {
1017 ERR("Attempted to close process window station\n");
1018 return FALSE;
1019 }
1020
1021 Status = IntValidateWindowStationHandle(hWinSta,
1022 UserMode,
1023 0,
1024 &Object,
1025 NULL);
1026 if (!NT_SUCCESS(Status))
1027 {
1028 ERR("Validation of window station handle (%p) failed\n", hWinSta);
1029 return FALSE;
1030 }
1031
1032 ObDereferenceObject(Object);
1033
1034 TRACE("Closing window station handle (%p)\n", hWinSta);
1035
1036 Status = ObCloseHandle(hWinSta, UserMode);
1037 if (!NT_SUCCESS(Status))
1038 {
1039 SetLastNtError(Status);
1040 return FALSE;
1041 }
1042
1043 return TRUE;
1044 }
1045
1046 /*
1047 * NtUserGetObjectInformation
1048 *
1049 * The NtUserGetObjectInformation function retrieves information about a
1050 * window station or desktop object.
1051 *
1052 * Parameters
1053 * hObj
1054 * Handle to the window station or desktop object for which to
1055 * return information. This can be a handle of type HDESK or HWINSTA
1056 * (for example, a handle returned by NtUserCreateWindowStation,
1057 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1058 *
1059 * nIndex
1060 * Specifies the object information to be retrieved.
1061 *
1062 * pvInfo
1063 * Pointer to a buffer to receive the object information.
1064 *
1065 * nLength
1066 * Specifies the size, in bytes, of the buffer pointed to by the
1067 * pvInfo parameter.
1068 *
1069 * lpnLengthNeeded
1070 * Pointer to a variable receiving the number of bytes required to
1071 * store the requested information. If this variable's value is
1072 * greater than the value of the nLength parameter when the function
1073 * returns, the function returns FALSE, and none of the information
1074 * is copied to the pvInfo buffer. If the value of the variable pointed
1075 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1076 * the entire information block is copied.
1077 *
1078 * Return Value
1079 * If the function succeeds, the return value is nonzero. If the function
1080 * fails, the return value is zero.
1081 *
1082 * Status
1083 * @unimplemented
1084 */
1085
1086 BOOL APIENTRY
1087 NtUserGetObjectInformation(
1088 HANDLE hObject,
1089 DWORD nIndex,
1090 PVOID pvInformation,
1091 DWORD nLength,
1092 PDWORD nLengthNeeded)
1093 {
1094 NTSTATUS Status;
1095 PWINSTATION_OBJECT WinStaObject = NULL;
1096 PDESKTOP DesktopObject = NULL;
1097 POBJECT_HEADER ObjectHeader;
1098 POBJECT_HEADER_NAME_INFO NameInfo;
1099 OBJECT_HANDLE_INFORMATION HandleInfo;
1100 USEROBJECTFLAGS ObjectFlags;
1101 PUNICODE_STRING pStrNameU = NULL;
1102 PVOID pvData = NULL;
1103 SIZE_T nDataSize = 0;
1104
1105 _SEH2_TRY
1106 {
1107 if (nLengthNeeded)
1108 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
1109 ProbeForWrite(pvInformation, nLength, 1);
1110 }
1111 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1112 {
1113 SetLastNtError(_SEH2_GetExceptionCode());
1114 return FALSE;
1115 }
1116 _SEH2_END;
1117
1118 /* Try window station */
1119 TRACE("Trying to open window station 0x%p\n", hObject);
1120 Status = ObReferenceObjectByHandle(hObject,
1121 0,
1122 ExWindowStationObjectType,
1123 UserMode,
1124 (PVOID*)&WinStaObject,
1125 &HandleInfo);
1126
1127 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
1128 {
1129 /* Try desktop */
1130 TRACE("Trying to open desktop %p\n", hObject);
1131 WinStaObject = NULL;
1132 Status = IntValidateDesktopHandle(hObject,
1133 UserMode,
1134 0,
1135 &DesktopObject);
1136 }
1137
1138 if (!NT_SUCCESS(Status))
1139 {
1140 ERR("Failed: 0x%x\n", Status);
1141 goto Exit;
1142 }
1143
1144 TRACE("WinSta or Desktop opened!\n");
1145
1146 /* Get data */
1147 switch (nIndex)
1148 {
1149 case UOI_FLAGS:
1150 {
1151 ObjectFlags.fReserved = FALSE;
1152 ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
1153
1154 ObjectFlags.dwFlags = 0;
1155 if (WinStaObject != NULL)
1156 {
1157 if (!(WinStaObject->Flags & WSS_NOIO))
1158 ObjectFlags.dwFlags |= WSF_VISIBLE;
1159 }
1160 else if (DesktopObject != NULL)
1161 {
1162 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1163 }
1164 else
1165 {
1166 ERR("No associated WinStaObject nor DesktopObject!\n");
1167 }
1168
1169 pvData = &ObjectFlags;
1170 nDataSize = sizeof(ObjectFlags);
1171 Status = STATUS_SUCCESS;
1172 break;
1173 }
1174
1175 case UOI_NAME:
1176 {
1177 if (WinStaObject != NULL)
1178 {
1179 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1180 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1181
1182 if (NameInfo && (NameInfo->Name.Length > 0))
1183 {
1184 /* Named window station */
1185 pStrNameU = &NameInfo->Name;
1186 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1187 }
1188 else
1189 {
1190 /* Unnamed window station (should never happen!) */
1191 ASSERT(FALSE);
1192 pStrNameU = NULL;
1193 nDataSize = sizeof(UNICODE_NULL);
1194 }
1195 Status = STATUS_SUCCESS;
1196 }
1197 else if (DesktopObject != NULL)
1198 {
1199 pvData = DesktopObject->pDeskInfo->szDesktopName;
1200 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
1201 Status = STATUS_SUCCESS;
1202 }
1203 else
1204 {
1205 Status = STATUS_INVALID_PARAMETER;
1206 }
1207 break;
1208 }
1209
1210 case UOI_TYPE:
1211 {
1212 if (WinStaObject != NULL)
1213 {
1214 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1215 pStrNameU = &ObjectHeader->Type->Name;
1216 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1217 Status = STATUS_SUCCESS;
1218 }
1219 else if (DesktopObject != NULL)
1220 {
1221 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject);
1222 pStrNameU = &ObjectHeader->Type->Name;
1223 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1224 Status = STATUS_SUCCESS;
1225 }
1226 else
1227 {
1228 Status = STATUS_INVALID_PARAMETER;
1229 }
1230 break;
1231 }
1232
1233 case UOI_USER_SID:
1234 Status = STATUS_NOT_IMPLEMENTED;
1235 ERR("UOI_USER_SID unimplemented!\n");
1236 break;
1237
1238 default:
1239 Status = STATUS_INVALID_PARAMETER;
1240 break;
1241 }
1242
1243 Exit:
1244 if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
1245 Status = STATUS_BUFFER_TOO_SMALL;
1246
1247 _SEH2_TRY
1248 {
1249 if (nLengthNeeded)
1250 *nLengthNeeded = nDataSize;
1251
1252 /* Try to copy data to caller */
1253 if (Status == STATUS_SUCCESS && (nDataSize > 0))
1254 {
1255 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
1256 if (pvData)
1257 {
1258 /* Copy the data */
1259 RtlCopyMemory(pvInformation, pvData, nDataSize);
1260 }
1261 else if (pStrNameU)
1262 {
1263 /* Copy and NULL-terminate the string */
1264 RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length);
1265 ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
1266 }
1267 else
1268 {
1269 /* Zero the memory */
1270 RtlZeroMemory(pvInformation, nDataSize);
1271 }
1272 }
1273 }
1274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1275 {
1276 Status = _SEH2_GetExceptionCode();
1277 }
1278 _SEH2_END;
1279
1280 /* Release objects */
1281 if (DesktopObject != NULL)
1282 ObDereferenceObject(DesktopObject);
1283 if (WinStaObject != NULL)
1284 ObDereferenceObject(WinStaObject);
1285
1286 if (!NT_SUCCESS(Status))
1287 {
1288 SetLastNtError(Status);
1289 return FALSE;
1290 }
1291
1292 return TRUE;
1293 }
1294
1295 /*
1296 * NtUserSetObjectInformation
1297 *
1298 * The NtUserSetObjectInformation function sets information about a
1299 * window station or desktop object.
1300 *
1301 * Parameters
1302 * hObj
1303 * Handle to the window station or desktop object for which to set
1304 * object information. This value can be a handle of type HDESK or
1305 * HWINSTA.
1306 *
1307 * nIndex
1308 * Specifies the object information to be set.
1309 *
1310 * pvInfo
1311 * Pointer to a buffer containing the object information.
1312 *
1313 * nLength
1314 * Specifies the size, in bytes, of the information contained in the
1315 * buffer pointed to by pvInfo.
1316 *
1317 * Return Value
1318 * If the function succeeds, the return value is nonzero. If the function
1319 * fails the return value is zero.
1320 *
1321 * Status
1322 * @unimplemented
1323 */
1324
1325 BOOL
1326 APIENTRY
1327 NtUserSetObjectInformation(
1328 HANDLE hObject,
1329 DWORD nIndex,
1330 PVOID pvInformation,
1331 DWORD nLength)
1332 {
1333 /* FIXME: ZwQueryObject */
1334 /* FIXME: ZwSetInformationObject */
1335 SetLastNtError(STATUS_UNSUCCESSFUL);
1336 return FALSE;
1337 }
1338
1339
1340 HWINSTA FASTCALL
1341 UserGetProcessWindowStation(VOID)
1342 {
1343 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1344
1345 return ppi->hwinsta;
1346 }
1347
1348
1349 /*
1350 * NtUserGetProcessWindowStation
1351 *
1352 * Returns a handle to the current process window station.
1353 *
1354 * Return Value
1355 * If the function succeeds, the return value is handle to the window
1356 * station assigned to the current process. If the function fails, the
1357 * return value is NULL.
1358 *
1359 * Status
1360 * @implemented
1361 */
1362
1363 HWINSTA APIENTRY
1364 NtUserGetProcessWindowStation(VOID)
1365 {
1366 return UserGetProcessWindowStation();
1367 }
1368
1369 BOOL FASTCALL
1370 UserSetProcessWindowStation(HWINSTA hWindowStation)
1371 {
1372 NTSTATUS Status;
1373 PPROCESSINFO ppi;
1374 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1375 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
1376 HWINSTA hCacheWinSta;
1377
1378 ppi = PsGetCurrentProcessWin32Process();
1379
1380 /* Reference the new window station */
1381 if (hWindowStation != NULL)
1382 {
1383 Status = IntValidateWindowStationHandle(hWindowStation,
1384 UserMode,
1385 0,
1386 &NewWinSta,
1387 &ObjectHandleInfo);
1388 if (!NT_SUCCESS(Status))
1389 {
1390 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
1391 SetLastNtError(Status);
1392 return FALSE;
1393 }
1394 }
1395
1396 OldWinSta = ppi->prpwinsta;
1397 hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
1398
1399 /* Dereference the previous window station */
1400 if (OldWinSta != NULL)
1401 {
1402 ObDereferenceObject(OldWinSta);
1403 }
1404
1405 /*
1406 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1407 */
1408
1409 /* Close the cached EPROCESS window station handle if needed */
1410 if (hCacheWinSta != NULL)
1411 {
1412 /* Reference the window station */
1413 Status = ObReferenceObjectByHandle(hCacheWinSta,
1414 0,
1415 ExWindowStationObjectType,
1416 UserMode,
1417 (PVOID*)&OldWinSta,
1418 NULL);
1419 if (!NT_SUCCESS(Status))
1420 {
1421 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
1422 /* We failed, reset the cache */
1423 hCacheWinSta = NULL;
1424 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1425 }
1426 else
1427 {
1428 /*
1429 * Close the old handle and reset the cache only
1430 * if we are setting a different window station.
1431 */
1432 if (NewWinSta != OldWinSta)
1433 {
1434 ObCloseHandle(hCacheWinSta, UserMode);
1435 hCacheWinSta = NULL;
1436 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1437 }
1438
1439 /* Dereference the window station */
1440 ObDereferenceObject(OldWinSta);
1441 }
1442 }
1443
1444 /* Duplicate and save a new cached EPROCESS window station handle */
1445 if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
1446 {
1447 Status = ZwDuplicateObject(ZwCurrentProcess(),
1448 hWindowStation,
1449 ZwCurrentProcess(),
1450 (PHANDLE)&hCacheWinSta,
1451 0,
1452 0,
1453 DUPLICATE_SAME_ACCESS);
1454 if (!NT_SUCCESS(Status))
1455 {
1456 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
1457 }
1458 else
1459 {
1460 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1461 }
1462 }
1463
1464 ppi->prpwinsta = NewWinSta;
1465 ppi->hwinsta = hWindowStation;
1466 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
1467 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
1468
1469 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
1470 {
1471 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
1472 }
1473 else
1474 {
1475 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
1476 }
1477
1478 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
1479 {
1480 ppi->W32PF_flags |= W32PF_IOWINSTA;
1481 }
1482 else /* Might be closed if the handle is NULL */
1483 {
1484 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
1485 }
1486 return TRUE;
1487 }
1488
1489 /*
1490 * NtUserSetProcessWindowStation
1491 *
1492 * Assigns a window station to the current process.
1493 *
1494 * Parameters
1495 * hWinSta
1496 * Handle to the window station.
1497 *
1498 * Return Value
1499 * Status
1500 *
1501 * Status
1502 * @implemented
1503 */
1504
1505 BOOL APIENTRY
1506 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1507 {
1508 BOOL ret;
1509
1510 UserEnterExclusive();
1511
1512 ret = UserSetProcessWindowStation(hWindowStation);
1513
1514 UserLeave();
1515
1516 return ret;
1517 }
1518
1519 /*
1520 * NtUserLockWindowStation
1521 *
1522 * Locks switching desktops. Only the logon application is allowed to call this function.
1523 *
1524 * Status
1525 * @implemented
1526 */
1527
1528 BOOL APIENTRY
1529 NtUserLockWindowStation(HWINSTA hWindowStation)
1530 {
1531 PWINSTATION_OBJECT Object;
1532 NTSTATUS Status;
1533
1534 TRACE("About to set process window station with handle (%p)\n",
1535 hWindowStation);
1536
1537 if (gpidLogon != PsGetCurrentProcessId())
1538 {
1539 ERR("Unauthorized process attempted to lock the window station!\n");
1540 EngSetLastError(ERROR_ACCESS_DENIED);
1541 return FALSE;
1542 }
1543
1544 Status = IntValidateWindowStationHandle(hWindowStation,
1545 UserMode,
1546 0,
1547 &Object,
1548 NULL);
1549 if (!NT_SUCCESS(Status))
1550 {
1551 TRACE("Validation of window station handle (%p) failed\n",
1552 hWindowStation);
1553 SetLastNtError(Status);
1554 return FALSE;
1555 }
1556
1557 Object->Flags |= WSS_LOCKED;
1558
1559 ObDereferenceObject(Object);
1560 return TRUE;
1561 }
1562
1563 /*
1564 * NtUserUnlockWindowStation
1565 *
1566 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1567 *
1568 * Status
1569 * @implemented
1570 */
1571
1572 BOOL APIENTRY
1573 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1574 {
1575 PWINSTATION_OBJECT Object;
1576 NTSTATUS Status;
1577 BOOL Ret;
1578
1579 TRACE("About to set process window station with handle (%p)\n",
1580 hWindowStation);
1581
1582 if (gpidLogon != PsGetCurrentProcessId())
1583 {
1584 ERR("Unauthorized process attempted to unlock the window station!\n");
1585 EngSetLastError(ERROR_ACCESS_DENIED);
1586 return FALSE;
1587 }
1588
1589 Status = IntValidateWindowStationHandle(hWindowStation,
1590 UserMode,
1591 0,
1592 &Object,
1593 NULL);
1594 if (!NT_SUCCESS(Status))
1595 {
1596 TRACE("Validation of window station handle (%p) failed\n",
1597 hWindowStation);
1598 SetLastNtError(Status);
1599 return FALSE;
1600 }
1601
1602 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1603 Object->Flags &= ~WSS_LOCKED;
1604
1605 ObDereferenceObject(Object);
1606 return Ret;
1607 }
1608
1609 static NTSTATUS FASTCALL
1610 BuildWindowStationNameList(
1611 ULONG dwSize,
1612 PVOID lpBuffer,
1613 PULONG pRequiredSize)
1614 {
1615 OBJECT_ATTRIBUTES ObjectAttributes;
1616 NTSTATUS Status;
1617 HANDLE DirectoryHandle;
1618 char InitialBuffer[256], *Buffer;
1619 ULONG Context, ReturnLength, BufferSize;
1620 DWORD EntryCount;
1621 POBJECT_DIRECTORY_INFORMATION DirEntry;
1622 WCHAR NullWchar;
1623
1624 //
1625 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1626 // with judicious parameters one can create window stations elsewhere
1627 // than in Windows\WindowStations directory, Win32k definitely MUST
1628 // maintain a list of window stations it has created, and not rely
1629 // on the enumeration of Windows\WindowStations !!!
1630 //
1631
1632 /*
1633 * Try to open the directory.
1634 */
1635 InitializeObjectAttributes(&ObjectAttributes,
1636 &gustrWindowStationsDir,
1637 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1638 NULL,
1639 NULL);
1640
1641 Status = ZwOpenDirectoryObject(&DirectoryHandle,
1642 DIRECTORY_QUERY,
1643 &ObjectAttributes);
1644
1645 if (!NT_SUCCESS(Status))
1646 {
1647 return Status;
1648 }
1649
1650 /* First try to query the directory using a fixed-size buffer */
1651 Context = 0;
1652 Buffer = NULL;
1653 Status = ZwQueryDirectoryObject(DirectoryHandle,
1654 InitialBuffer,
1655 sizeof(InitialBuffer),
1656 FALSE,
1657 TRUE,
1658 &Context,
1659 &ReturnLength);
1660 if (NT_SUCCESS(Status))
1661 {
1662 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1663 FALSE, &Context, NULL))
1664 {
1665 /* Our fixed-size buffer is large enough */
1666 Buffer = InitialBuffer;
1667 }
1668 }
1669
1670 if (NULL == Buffer)
1671 {
1672 /* Need a larger buffer, check how large exactly */
1673 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1674 &ReturnLength);
1675 if (!NT_SUCCESS(Status))
1676 {
1677 ERR("ZwQueryDirectoryObject failed\n");
1678 ZwClose(DirectoryHandle);
1679 return Status;
1680 }
1681
1682 BufferSize = ReturnLength;
1683 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1684 if (NULL == Buffer)
1685 {
1686 ZwClose(DirectoryHandle);
1687 return STATUS_NO_MEMORY;
1688 }
1689
1690 /* We should have a sufficiently large buffer now */
1691 Context = 0;
1692 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1693 FALSE, TRUE, &Context, &ReturnLength);
1694 if (! NT_SUCCESS(Status) ||
1695 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1696 FALSE, &Context, NULL))
1697 {
1698 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1699 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1700 ZwClose(DirectoryHandle);
1701 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1702 }
1703 }
1704
1705 ZwClose(DirectoryHandle);
1706
1707 /*
1708 * Count the required size of buffer.
1709 */
1710 ReturnLength = sizeof(DWORD);
1711 EntryCount = 0;
1712 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1713 0 != DirEntry->Name.Length;
1714 DirEntry++)
1715 {
1716 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1717 EntryCount++;
1718 }
1719 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1720 if (NULL != pRequiredSize)
1721 {
1722 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1723 if (! NT_SUCCESS(Status))
1724 {
1725 if (Buffer != InitialBuffer)
1726 {
1727 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1728 }
1729 return STATUS_BUFFER_TOO_SMALL;
1730 }
1731 }
1732
1733 /*
1734 * Check if the supplied buffer is large enough.
1735 */
1736 if (dwSize < ReturnLength)
1737 {
1738 if (Buffer != InitialBuffer)
1739 {
1740 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1741 }
1742 return STATUS_BUFFER_TOO_SMALL;
1743 }
1744
1745 /*
1746 * Generate the resulting buffer contents.
1747 */
1748 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1749 if (! NT_SUCCESS(Status))
1750 {
1751 if (Buffer != InitialBuffer)
1752 {
1753 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1754 }
1755 return Status;
1756 }
1757 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1758
1759 NullWchar = L'\0';
1760 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1761 0 != DirEntry->Name.Length;
1762 DirEntry++)
1763 {
1764 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1765 if (! NT_SUCCESS(Status))
1766 {
1767 if (Buffer != InitialBuffer)
1768 {
1769 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1770 }
1771 return Status;
1772 }
1773 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1774 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1775 if (! NT_SUCCESS(Status))
1776 {
1777 if (Buffer != InitialBuffer)
1778 {
1779 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1780 }
1781 return Status;
1782 }
1783 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1784 }
1785
1786 /*
1787 * Clean up
1788 */
1789 if (Buffer != InitialBuffer)
1790 {
1791 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1792 }
1793
1794 return STATUS_SUCCESS;
1795 }
1796
1797 static NTSTATUS FASTCALL
1798 BuildDesktopNameList(
1799 HWINSTA hWindowStation,
1800 ULONG dwSize,
1801 PVOID lpBuffer,
1802 PULONG pRequiredSize)
1803 {
1804 NTSTATUS Status;
1805 PWINSTATION_OBJECT WindowStation;
1806 PLIST_ENTRY DesktopEntry;
1807 PDESKTOP DesktopObject;
1808 DWORD EntryCount;
1809 ULONG ReturnLength;
1810 WCHAR NullWchar;
1811 UNICODE_STRING DesktopName;
1812
1813 Status = IntValidateWindowStationHandle(hWindowStation,
1814 UserMode,
1815 0,
1816 &WindowStation,
1817 NULL);
1818 if (! NT_SUCCESS(Status))
1819 {
1820 return Status;
1821 }
1822
1823 /*
1824 * Count the required size of buffer.
1825 */
1826 ReturnLength = sizeof(DWORD);
1827 EntryCount = 0;
1828 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1829 DesktopEntry != &WindowStation->DesktopListHead;
1830 DesktopEntry = DesktopEntry->Flink)
1831 {
1832 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1833 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1834 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1835 EntryCount++;
1836 }
1837 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1838 if (NULL != pRequiredSize)
1839 {
1840 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1841 if (! NT_SUCCESS(Status))
1842 {
1843 ObDereferenceObject(WindowStation);
1844 return STATUS_BUFFER_TOO_SMALL;
1845 }
1846 }
1847
1848 /*
1849 * Check if the supplied buffer is large enough.
1850 */
1851 if (dwSize < ReturnLength)
1852 {
1853 ObDereferenceObject(WindowStation);
1854 return STATUS_BUFFER_TOO_SMALL;
1855 }
1856
1857 /*
1858 * Generate the resulting buffer contents.
1859 */
1860 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1861 if (! NT_SUCCESS(Status))
1862 {
1863 ObDereferenceObject(WindowStation);
1864 return Status;
1865 }
1866 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1867
1868 NullWchar = L'\0';
1869 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1870 DesktopEntry != &WindowStation->DesktopListHead;
1871 DesktopEntry = DesktopEntry->Flink)
1872 {
1873 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1874 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1875 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1876 if (! NT_SUCCESS(Status))
1877 {
1878 ObDereferenceObject(WindowStation);
1879 return Status;
1880 }
1881 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1882 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1883 if (! NT_SUCCESS(Status))
1884 {
1885 ObDereferenceObject(WindowStation);
1886 return Status;
1887 }
1888 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1889 }
1890
1891 /*
1892 * Clean up and return
1893 */
1894 ObDereferenceObject(WindowStation);
1895 return STATUS_SUCCESS;
1896 }
1897
1898 /*
1899 * NtUserBuildNameList
1900 *
1901 * Function used for enumeration of desktops or window stations.
1902 *
1903 * Parameters
1904 * hWinSta
1905 * For enumeration of window stations this parameter must be set to
1906 * zero. Otherwise it's handle for window station.
1907 *
1908 * dwSize
1909 * Size of buffer passed by caller.
1910 *
1911 * lpBuffer
1912 * Buffer passed by caller. If the function succeeds, the buffer is
1913 * filled with window station/desktop count (in first DWORD) and
1914 * NULL-terminated window station/desktop names.
1915 *
1916 * pRequiredSize
1917 * If the function succeeds, this is the number of bytes copied.
1918 * Otherwise it's size of buffer needed for function to succeed.
1919 *
1920 * Status
1921 * @implemented
1922 */
1923
1924 NTSTATUS APIENTRY
1925 NtUserBuildNameList(
1926 HWINSTA hWindowStation,
1927 ULONG dwSize,
1928 PVOID lpBuffer,
1929 PULONG pRequiredSize)
1930 {
1931 /* The WindowStation name list and desktop name list are build in completely
1932 different ways. Call the appropriate function */
1933 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1934 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1935 }
1936
1937 /*
1938 * @implemented
1939 */
1940 BOOL APIENTRY
1941 NtUserSetLogonNotifyWindow(HWND hWnd)
1942 {
1943 if (gpidLogon != PsGetCurrentProcessId())
1944 {
1945 return FALSE;
1946 }
1947
1948 if (!IntIsWindow(hWnd))
1949 {
1950 return FALSE;
1951 }
1952
1953 hwndSAS = hWnd;
1954
1955 return TRUE;
1956 }
1957
1958 BOOL
1959 APIENTRY
1960 NtUserLockWorkStation(VOID)
1961 {
1962 BOOL ret;
1963 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1964
1965 UserEnterExclusive();
1966
1967 if (pti->rpdesk == IntGetActiveDesktop())
1968 {
1969 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1970 }
1971 else
1972 {
1973 ret = FALSE;
1974 }
1975
1976 UserLeave();
1977
1978 return ret;
1979 }
1980
1981 BOOL
1982 NTAPI
1983 NtUserSetWindowStationUser(
1984 IN HWINSTA hWindowStation,
1985 IN PLUID pluid,
1986 IN PSID psid OPTIONAL,
1987 IN DWORD size)
1988 {
1989 BOOL Ret = FALSE;
1990 NTSTATUS Status;
1991 PWINSTATION_OBJECT WindowStation = NULL;
1992 LUID luidUser;
1993
1994 UserEnterExclusive();
1995
1996 if (gpidLogon != PsGetCurrentProcessId())
1997 {
1998 EngSetLastError(ERROR_ACCESS_DENIED);
1999 goto Leave;
2000 }
2001
2002 /* Validate the window station */
2003 Status = IntValidateWindowStationHandle(hWindowStation,
2004 UserMode,
2005 0,
2006 &WindowStation,
2007 NULL);
2008 if (!NT_SUCCESS(Status))
2009 {
2010 goto Leave;
2011 }
2012
2013 /* Capture the user LUID */
2014 _SEH2_TRY
2015 {
2016 ProbeForRead(pluid, sizeof(LUID), 1);
2017 luidUser = *pluid;
2018 }
2019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2020 {
2021 Status = _SEH2_GetExceptionCode();
2022 _SEH2_YIELD(goto Leave);
2023 }
2024 _SEH2_END;
2025
2026 /* Reset the window station user LUID */
2027 RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
2028
2029 /* Reset the window station user SID */
2030 if (WindowStation->psidUser)
2031 {
2032 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2033 WindowStation->psidUser = NULL;
2034 }
2035
2036 /* Copy the new user SID if one has been provided */
2037 if (psid)
2038 {
2039 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
2040 if (WindowStation->psidUser == NULL)
2041 {
2042 EngSetLastError(ERROR_OUTOFMEMORY);
2043 goto Leave;
2044 }
2045
2046 Status = STATUS_SUCCESS;
2047 _SEH2_TRY
2048 {
2049 ProbeForRead(psid, size, 1);
2050 RtlCopyMemory(WindowStation->psidUser, psid, size);
2051 }
2052 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2053 {
2054 Status = _SEH2_GetExceptionCode();
2055 }
2056 _SEH2_END;
2057
2058 if (!NT_SUCCESS(Status))
2059 {
2060 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2061 WindowStation->psidUser = NULL;
2062 goto Leave;
2063 }
2064 }
2065
2066 /* Copy the new user LUID */
2067 WindowStation->luidUser = luidUser;
2068
2069 Ret = TRUE;
2070
2071 Leave:
2072 if (WindowStation)
2073 ObDereferenceObject(WindowStation);
2074
2075 UserLeave();
2076 return Ret;
2077 }
2078
2079 /* EOF */