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