[WIN32K:NTUSER] In UserSetProcessWindowStation(), use a duplicated window station...
[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 NULL);
975 if (!NT_SUCCESS(Status))
976 {
977 ERR("Validation of window station handle (%p) failed\n", hWinSta);
978 return FALSE;
979 }
980
981 ObDereferenceObject(Object);
982
983 TRACE("Closing window station handle (%p)\n", hWinSta);
984
985 Status = ObCloseHandle(hWinSta, UserMode);
986 if (!NT_SUCCESS(Status))
987 {
988 SetLastNtError(Status);
989 return FALSE;
990 }
991
992 return TRUE;
993 }
994
995 /*
996 * NtUserGetObjectInformation
997 *
998 * The NtUserGetObjectInformation function retrieves information about a
999 * window station or desktop object.
1000 *
1001 * Parameters
1002 * hObj
1003 * Handle to the window station or desktop object for which to
1004 * return information. This can be a handle of type HDESK or HWINSTA
1005 * (for example, a handle returned by NtUserCreateWindowStation,
1006 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1007 *
1008 * nIndex
1009 * Specifies the object information to be retrieved.
1010 *
1011 * pvInfo
1012 * Pointer to a buffer to receive the object information.
1013 *
1014 * nLength
1015 * Specifies the size, in bytes, of the buffer pointed to by the
1016 * pvInfo parameter.
1017 *
1018 * lpnLengthNeeded
1019 * Pointer to a variable receiving the number of bytes required to
1020 * store the requested information. If this variable's value is
1021 * greater than the value of the nLength parameter when the function
1022 * returns, the function returns FALSE, and none of the information
1023 * is copied to the pvInfo buffer. If the value of the variable pointed
1024 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1025 * the entire information block is copied.
1026 *
1027 * Return Value
1028 * If the function succeeds, the return value is nonzero. If the function
1029 * fails, the return value is zero.
1030 *
1031 * Status
1032 * @unimplemented
1033 */
1034
1035 BOOL APIENTRY
1036 NtUserGetObjectInformation(
1037 HANDLE hObject,
1038 DWORD nIndex,
1039 PVOID pvInformation,
1040 DWORD nLength,
1041 PDWORD nLengthNeeded)
1042 {
1043 NTSTATUS Status;
1044 PWINSTATION_OBJECT WinStaObject = NULL;
1045 PDESKTOP DesktopObject = NULL;
1046 POBJECT_HEADER ObjectHeader;
1047 POBJECT_HEADER_NAME_INFO NameInfo;
1048 OBJECT_HANDLE_INFORMATION HandleInfo;
1049 USEROBJECTFLAGS ObjectFlags;
1050 PUNICODE_STRING pStrNameU = NULL;
1051 PVOID pvData = NULL;
1052 SIZE_T nDataSize = 0;
1053
1054 _SEH2_TRY
1055 {
1056 if (nLengthNeeded)
1057 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
1058 ProbeForWrite(pvInformation, nLength, 1);
1059 }
1060 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1061 {
1062 SetLastNtError(_SEH2_GetExceptionCode());
1063 return FALSE;
1064 }
1065 _SEH2_END;
1066
1067 /* Try window station */
1068 TRACE("Trying to open window station 0x%p\n", hObject);
1069 Status = ObReferenceObjectByHandle(hObject,
1070 0,
1071 ExWindowStationObjectType,
1072 UserMode,
1073 (PVOID*)&WinStaObject,
1074 &HandleInfo);
1075
1076 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
1077 {
1078 /* Try desktop */
1079 TRACE("Trying to open desktop %p\n", hObject);
1080 WinStaObject = NULL;
1081 Status = IntValidateDesktopHandle(hObject,
1082 UserMode,
1083 0,
1084 &DesktopObject);
1085 }
1086
1087 if (!NT_SUCCESS(Status))
1088 {
1089 ERR("Failed: 0x%x\n", Status);
1090 goto Exit;
1091 }
1092
1093 TRACE("WinSta or Desktop opened!\n");
1094
1095 /* Get data */
1096 switch (nIndex)
1097 {
1098 case UOI_FLAGS:
1099 {
1100 ObjectFlags.fReserved = FALSE;
1101 ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
1102
1103 ObjectFlags.dwFlags = 0;
1104 if (WinStaObject != NULL)
1105 {
1106 if (!(WinStaObject->Flags & WSS_NOIO))
1107 ObjectFlags.dwFlags |= WSF_VISIBLE;
1108 }
1109 else if (DesktopObject != NULL)
1110 {
1111 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1112 }
1113 else
1114 {
1115 ERR("No associated WinStaObject nor DesktopObject!\n");
1116 }
1117
1118 pvData = &ObjectFlags;
1119 nDataSize = sizeof(ObjectFlags);
1120 Status = STATUS_SUCCESS;
1121 break;
1122 }
1123
1124 case UOI_NAME:
1125 {
1126 if (WinStaObject != NULL)
1127 {
1128 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1129 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1130
1131 if (NameInfo && (NameInfo->Name.Length > 0))
1132 {
1133 /* Named window station */
1134 pStrNameU = &NameInfo->Name;
1135 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1136 }
1137 else
1138 {
1139 /* Unnamed window station (should never happen!) */
1140 ASSERT(FALSE);
1141 pStrNameU = NULL;
1142 nDataSize = sizeof(UNICODE_NULL);
1143 }
1144 Status = STATUS_SUCCESS;
1145 }
1146 else if (DesktopObject != NULL)
1147 {
1148 pvData = DesktopObject->pDeskInfo->szDesktopName;
1149 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
1150 Status = STATUS_SUCCESS;
1151 }
1152 else
1153 {
1154 Status = STATUS_INVALID_PARAMETER;
1155 }
1156 break;
1157 }
1158
1159 case UOI_TYPE:
1160 {
1161 if (WinStaObject != NULL)
1162 {
1163 ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
1164 pStrNameU = &ObjectHeader->Type->Name;
1165 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1166 Status = STATUS_SUCCESS;
1167 }
1168 else if (DesktopObject != NULL)
1169 {
1170 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject);
1171 pStrNameU = &ObjectHeader->Type->Name;
1172 nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
1173 Status = STATUS_SUCCESS;
1174 }
1175 else
1176 {
1177 Status = STATUS_INVALID_PARAMETER;
1178 }
1179 break;
1180 }
1181
1182 case UOI_USER_SID:
1183 Status = STATUS_NOT_IMPLEMENTED;
1184 ERR("UOI_USER_SID unimplemented!\n");
1185 break;
1186
1187 default:
1188 Status = STATUS_INVALID_PARAMETER;
1189 break;
1190 }
1191
1192 Exit:
1193 if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
1194 Status = STATUS_BUFFER_TOO_SMALL;
1195
1196 _SEH2_TRY
1197 {
1198 if (nLengthNeeded)
1199 *nLengthNeeded = nDataSize;
1200
1201 /* Try to copy data to caller */
1202 if (Status == STATUS_SUCCESS && (nDataSize > 0))
1203 {
1204 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
1205 if (pvData)
1206 {
1207 /* Copy the data */
1208 RtlCopyMemory(pvInformation, pvData, nDataSize);
1209 }
1210 else if (pStrNameU)
1211 {
1212 /* Copy and NULL-terminate the string */
1213 RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length);
1214 ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
1215 }
1216 else
1217 {
1218 /* Zero the memory */
1219 RtlZeroMemory(pvInformation, nDataSize);
1220 }
1221 }
1222 }
1223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1224 {
1225 Status = _SEH2_GetExceptionCode();
1226 }
1227 _SEH2_END;
1228
1229 /* Release objects */
1230 if (DesktopObject != NULL)
1231 ObDereferenceObject(DesktopObject);
1232 if (WinStaObject != NULL)
1233 ObDereferenceObject(WinStaObject);
1234
1235 if (!NT_SUCCESS(Status))
1236 {
1237 SetLastNtError(Status);
1238 return FALSE;
1239 }
1240
1241 return TRUE;
1242 }
1243
1244 /*
1245 * NtUserSetObjectInformation
1246 *
1247 * The NtUserSetObjectInformation function sets information about a
1248 * window station or desktop object.
1249 *
1250 * Parameters
1251 * hObj
1252 * Handle to the window station or desktop object for which to set
1253 * object information. This value can be a handle of type HDESK or
1254 * HWINSTA.
1255 *
1256 * nIndex
1257 * Specifies the object information to be set.
1258 *
1259 * pvInfo
1260 * Pointer to a buffer containing the object information.
1261 *
1262 * nLength
1263 * Specifies the size, in bytes, of the information contained in the
1264 * buffer pointed to by pvInfo.
1265 *
1266 * Return Value
1267 * If the function succeeds, the return value is nonzero. If the function
1268 * fails the return value is zero.
1269 *
1270 * Status
1271 * @unimplemented
1272 */
1273
1274 BOOL
1275 APIENTRY
1276 NtUserSetObjectInformation(
1277 HANDLE hObject,
1278 DWORD nIndex,
1279 PVOID pvInformation,
1280 DWORD nLength)
1281 {
1282 /* FIXME: ZwQueryObject */
1283 /* FIXME: ZwSetInformationObject */
1284 SetLastNtError(STATUS_UNSUCCESSFUL);
1285 return FALSE;
1286 }
1287
1288
1289 HWINSTA FASTCALL
1290 UserGetProcessWindowStation(VOID)
1291 {
1292 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1293
1294 return ppi->hwinsta;
1295 }
1296
1297
1298 /*
1299 * NtUserGetProcessWindowStation
1300 *
1301 * Returns a handle to the current process window station.
1302 *
1303 * Return Value
1304 * If the function succeeds, the return value is handle to the window
1305 * station assigned to the current process. If the function fails, the
1306 * return value is NULL.
1307 *
1308 * Status
1309 * @implemented
1310 */
1311
1312 HWINSTA APIENTRY
1313 NtUserGetProcessWindowStation(VOID)
1314 {
1315 return UserGetProcessWindowStation();
1316 }
1317
1318 BOOL FASTCALL
1319 UserSetProcessWindowStation(HWINSTA hWindowStation)
1320 {
1321 NTSTATUS Status;
1322 PPROCESSINFO ppi;
1323 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1324 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
1325 HWINSTA hCacheWinSta;
1326
1327 ppi = PsGetCurrentProcessWin32Process();
1328
1329 /* Reference the new window station */
1330 if (hWindowStation != NULL)
1331 {
1332 Status = IntValidateWindowStationHandle(hWindowStation,
1333 UserMode,
1334 0,
1335 &NewWinSta,
1336 &ObjectHandleInfo);
1337 if (!NT_SUCCESS(Status))
1338 {
1339 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
1340 SetLastNtError(Status);
1341 return FALSE;
1342 }
1343 }
1344
1345 OldWinSta = ppi->prpwinsta;
1346 hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
1347
1348 /* Dereference the previous window station */
1349 if (OldWinSta != NULL)
1350 {
1351 ObDereferenceObject(OldWinSta);
1352 }
1353
1354 /*
1355 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1356 */
1357
1358 /* Close the cached EPROCESS window station handle if needed */
1359 if (hCacheWinSta != NULL)
1360 {
1361 /* Reference the window station */
1362 Status = ObReferenceObjectByHandle(hCacheWinSta,
1363 0,
1364 ExWindowStationObjectType,
1365 UserMode,
1366 (PVOID*)&OldWinSta,
1367 NULL);
1368 if (!NT_SUCCESS(Status))
1369 {
1370 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
1371 /* We failed, reset the cache */
1372 hCacheWinSta = NULL;
1373 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1374 }
1375 else
1376 {
1377 /*
1378 * Close the old handle and reset the cache only
1379 * if we are setting a different window station.
1380 */
1381 if (NewWinSta != OldWinSta)
1382 {
1383 ObCloseHandle(hCacheWinSta, UserMode);
1384 hCacheWinSta = NULL;
1385 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1386 }
1387
1388 /* Dereference the window station */
1389 ObDereferenceObject(OldWinSta);
1390 }
1391 }
1392
1393 /* Duplicate and save a new cached EPROCESS window station handle */
1394 if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
1395 {
1396 Status = ZwDuplicateObject(ZwCurrentProcess(),
1397 hWindowStation,
1398 ZwCurrentProcess(),
1399 (PHANDLE)&hCacheWinSta,
1400 0,
1401 0,
1402 DUPLICATE_SAME_ACCESS);
1403 if (!NT_SUCCESS(Status))
1404 {
1405 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
1406 }
1407 else
1408 {
1409 PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
1410 }
1411 }
1412
1413 ppi->prpwinsta = NewWinSta;
1414 ppi->hwinsta = hWindowStation;
1415 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
1416 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
1417
1418 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
1419 {
1420 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
1421 }
1422 else
1423 {
1424 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
1425 }
1426
1427 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
1428 {
1429 ppi->W32PF_flags |= W32PF_IOWINSTA;
1430 }
1431 else /* Might be closed if the handle is NULL */
1432 {
1433 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
1434 }
1435 return TRUE;
1436 }
1437
1438 /*
1439 * NtUserSetProcessWindowStation
1440 *
1441 * Assigns a window station to the current process.
1442 *
1443 * Parameters
1444 * hWinSta
1445 * Handle to the window station.
1446 *
1447 * Return Value
1448 * Status
1449 *
1450 * Status
1451 * @implemented
1452 */
1453
1454 BOOL APIENTRY
1455 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1456 {
1457 BOOL ret;
1458
1459 UserEnterExclusive();
1460
1461 ret = UserSetProcessWindowStation(hWindowStation);
1462
1463 UserLeave();
1464
1465 return ret;
1466 }
1467
1468 /*
1469 * NtUserLockWindowStation
1470 *
1471 * Locks switching desktops. Only the logon application is allowed to call this function.
1472 *
1473 * Status
1474 * @implemented
1475 */
1476
1477 BOOL APIENTRY
1478 NtUserLockWindowStation(HWINSTA hWindowStation)
1479 {
1480 PWINSTATION_OBJECT Object;
1481 NTSTATUS Status;
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 lock 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 NULL);
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 Object->Flags |= WSS_LOCKED;
1507
1508 ObDereferenceObject(Object);
1509 return TRUE;
1510 }
1511
1512 /*
1513 * NtUserUnlockWindowStation
1514 *
1515 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1516 *
1517 * Status
1518 * @implemented
1519 */
1520
1521 BOOL APIENTRY
1522 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1523 {
1524 PWINSTATION_OBJECT Object;
1525 NTSTATUS Status;
1526 BOOL Ret;
1527
1528 TRACE("About to set process window station with handle (%p)\n",
1529 hWindowStation);
1530
1531 if (gpidLogon != PsGetCurrentProcessId())
1532 {
1533 ERR("Unauthorized process attempted to unlock the window station!\n");
1534 EngSetLastError(ERROR_ACCESS_DENIED);
1535 return FALSE;
1536 }
1537
1538 Status = IntValidateWindowStationHandle(hWindowStation,
1539 UserMode,
1540 0,
1541 &Object,
1542 NULL);
1543 if (!NT_SUCCESS(Status))
1544 {
1545 TRACE("Validation of window station handle (%p) failed\n",
1546 hWindowStation);
1547 SetLastNtError(Status);
1548 return FALSE;
1549 }
1550
1551 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1552 Object->Flags &= ~WSS_LOCKED;
1553
1554 ObDereferenceObject(Object);
1555 return Ret;
1556 }
1557
1558 static NTSTATUS FASTCALL
1559 BuildWindowStationNameList(
1560 ULONG dwSize,
1561 PVOID lpBuffer,
1562 PULONG pRequiredSize)
1563 {
1564 OBJECT_ATTRIBUTES ObjectAttributes;
1565 NTSTATUS Status;
1566 HANDLE DirectoryHandle;
1567 char InitialBuffer[256], *Buffer;
1568 ULONG Context, ReturnLength, BufferSize;
1569 DWORD EntryCount;
1570 POBJECT_DIRECTORY_INFORMATION DirEntry;
1571 WCHAR NullWchar;
1572
1573 //
1574 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1575 // with judicious parameters one can create window stations elsewhere
1576 // than in Windows\WindowStations directory, Win32k definitely MUST
1577 // maintain a list of window stations it has created, and not rely
1578 // on the enumeration of Windows\WindowStations !!!
1579 //
1580
1581 /*
1582 * Try to open the directory.
1583 */
1584 InitializeObjectAttributes(&ObjectAttributes,
1585 &gustrWindowStationsDir,
1586 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1587 NULL,
1588 NULL);
1589
1590 Status = ZwOpenDirectoryObject(&DirectoryHandle,
1591 DIRECTORY_QUERY,
1592 &ObjectAttributes);
1593
1594 if (!NT_SUCCESS(Status))
1595 {
1596 return Status;
1597 }
1598
1599 /* First try to query the directory using a fixed-size buffer */
1600 Context = 0;
1601 Buffer = NULL;
1602 Status = ZwQueryDirectoryObject(DirectoryHandle,
1603 InitialBuffer,
1604 sizeof(InitialBuffer),
1605 FALSE,
1606 TRUE,
1607 &Context,
1608 &ReturnLength);
1609 if (NT_SUCCESS(Status))
1610 {
1611 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1612 FALSE, &Context, NULL))
1613 {
1614 /* Our fixed-size buffer is large enough */
1615 Buffer = InitialBuffer;
1616 }
1617 }
1618
1619 if (NULL == Buffer)
1620 {
1621 /* Need a larger buffer, check how large exactly */
1622 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1623 &ReturnLength);
1624 if (!NT_SUCCESS(Status))
1625 {
1626 ERR("ZwQueryDirectoryObject failed\n");
1627 ZwClose(DirectoryHandle);
1628 return Status;
1629 }
1630
1631 BufferSize = ReturnLength;
1632 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1633 if (NULL == Buffer)
1634 {
1635 ZwClose(DirectoryHandle);
1636 return STATUS_NO_MEMORY;
1637 }
1638
1639 /* We should have a sufficiently large buffer now */
1640 Context = 0;
1641 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1642 FALSE, TRUE, &Context, &ReturnLength);
1643 if (! NT_SUCCESS(Status) ||
1644 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1645 FALSE, &Context, NULL))
1646 {
1647 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1648 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1649 ZwClose(DirectoryHandle);
1650 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1651 }
1652 }
1653
1654 ZwClose(DirectoryHandle);
1655
1656 /*
1657 * Count the required size of buffer.
1658 */
1659 ReturnLength = sizeof(DWORD);
1660 EntryCount = 0;
1661 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1662 0 != DirEntry->Name.Length;
1663 DirEntry++)
1664 {
1665 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1666 EntryCount++;
1667 }
1668 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1669 if (NULL != pRequiredSize)
1670 {
1671 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1672 if (! NT_SUCCESS(Status))
1673 {
1674 if (Buffer != InitialBuffer)
1675 {
1676 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1677 }
1678 return STATUS_BUFFER_TOO_SMALL;
1679 }
1680 }
1681
1682 /*
1683 * Check if the supplied buffer is large enough.
1684 */
1685 if (dwSize < ReturnLength)
1686 {
1687 if (Buffer != InitialBuffer)
1688 {
1689 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1690 }
1691 return STATUS_BUFFER_TOO_SMALL;
1692 }
1693
1694 /*
1695 * Generate the resulting buffer contents.
1696 */
1697 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1698 if (! NT_SUCCESS(Status))
1699 {
1700 if (Buffer != InitialBuffer)
1701 {
1702 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1703 }
1704 return Status;
1705 }
1706 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1707
1708 NullWchar = L'\0';
1709 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer;
1710 0 != DirEntry->Name.Length;
1711 DirEntry++)
1712 {
1713 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1714 if (! NT_SUCCESS(Status))
1715 {
1716 if (Buffer != InitialBuffer)
1717 {
1718 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1719 }
1720 return Status;
1721 }
1722 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1723 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1724 if (! NT_SUCCESS(Status))
1725 {
1726 if (Buffer != InitialBuffer)
1727 {
1728 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1729 }
1730 return Status;
1731 }
1732 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1733 }
1734
1735 /*
1736 * Clean up
1737 */
1738 if (Buffer != InitialBuffer)
1739 {
1740 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1741 }
1742
1743 return STATUS_SUCCESS;
1744 }
1745
1746 static NTSTATUS FASTCALL
1747 BuildDesktopNameList(
1748 HWINSTA hWindowStation,
1749 ULONG dwSize,
1750 PVOID lpBuffer,
1751 PULONG pRequiredSize)
1752 {
1753 NTSTATUS Status;
1754 PWINSTATION_OBJECT WindowStation;
1755 PLIST_ENTRY DesktopEntry;
1756 PDESKTOP DesktopObject;
1757 DWORD EntryCount;
1758 ULONG ReturnLength;
1759 WCHAR NullWchar;
1760 UNICODE_STRING DesktopName;
1761
1762 Status = IntValidateWindowStationHandle(hWindowStation,
1763 UserMode,
1764 0,
1765 &WindowStation,
1766 NULL);
1767 if (! NT_SUCCESS(Status))
1768 {
1769 return Status;
1770 }
1771
1772 /*
1773 * Count the required size of buffer.
1774 */
1775 ReturnLength = sizeof(DWORD);
1776 EntryCount = 0;
1777 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1778 DesktopEntry != &WindowStation->DesktopListHead;
1779 DesktopEntry = DesktopEntry->Flink)
1780 {
1781 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1782 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1783 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1784 EntryCount++;
1785 }
1786 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1787 if (NULL != pRequiredSize)
1788 {
1789 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1790 if (! NT_SUCCESS(Status))
1791 {
1792 ObDereferenceObject(WindowStation);
1793 return STATUS_BUFFER_TOO_SMALL;
1794 }
1795 }
1796
1797 /*
1798 * Check if the supplied buffer is large enough.
1799 */
1800 if (dwSize < ReturnLength)
1801 {
1802 ObDereferenceObject(WindowStation);
1803 return STATUS_BUFFER_TOO_SMALL;
1804 }
1805
1806 /*
1807 * Generate the resulting buffer contents.
1808 */
1809 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1810 if (! NT_SUCCESS(Status))
1811 {
1812 ObDereferenceObject(WindowStation);
1813 return Status;
1814 }
1815 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1816
1817 NullWchar = L'\0';
1818 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1819 DesktopEntry != &WindowStation->DesktopListHead;
1820 DesktopEntry = DesktopEntry->Flink)
1821 {
1822 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1823 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1824 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1825 if (! NT_SUCCESS(Status))
1826 {
1827 ObDereferenceObject(WindowStation);
1828 return Status;
1829 }
1830 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1831 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1832 if (! NT_SUCCESS(Status))
1833 {
1834 ObDereferenceObject(WindowStation);
1835 return Status;
1836 }
1837 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1838 }
1839
1840 /*
1841 * Clean up and return
1842 */
1843 ObDereferenceObject(WindowStation);
1844 return STATUS_SUCCESS;
1845 }
1846
1847 /*
1848 * NtUserBuildNameList
1849 *
1850 * Function used for enumeration of desktops or window stations.
1851 *
1852 * Parameters
1853 * hWinSta
1854 * For enumeration of window stations this parameter must be set to
1855 * zero. Otherwise it's handle for window station.
1856 *
1857 * dwSize
1858 * Size of buffer passed by caller.
1859 *
1860 * lpBuffer
1861 * Buffer passed by caller. If the function succeeds, the buffer is
1862 * filled with window station/desktop count (in first DWORD) and
1863 * NULL-terminated window station/desktop names.
1864 *
1865 * pRequiredSize
1866 * If the function succeeds, this is the number of bytes copied.
1867 * Otherwise it's size of buffer needed for function to succeed.
1868 *
1869 * Status
1870 * @implemented
1871 */
1872
1873 NTSTATUS APIENTRY
1874 NtUserBuildNameList(
1875 HWINSTA hWindowStation,
1876 ULONG dwSize,
1877 PVOID lpBuffer,
1878 PULONG pRequiredSize)
1879 {
1880 /* The WindowStation name list and desktop name list are build in completely
1881 different ways. Call the appropriate function */
1882 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1883 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1884 }
1885
1886 /*
1887 * @implemented
1888 */
1889 BOOL APIENTRY
1890 NtUserSetLogonNotifyWindow(HWND hWnd)
1891 {
1892 if (gpidLogon != PsGetCurrentProcessId())
1893 {
1894 return FALSE;
1895 }
1896
1897 if (!IntIsWindow(hWnd))
1898 {
1899 return FALSE;
1900 }
1901
1902 hwndSAS = hWnd;
1903
1904 return TRUE;
1905 }
1906
1907 BOOL
1908 APIENTRY
1909 NtUserLockWorkStation(VOID)
1910 {
1911 BOOL ret;
1912 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1913
1914 UserEnterExclusive();
1915
1916 if (pti->rpdesk == IntGetActiveDesktop())
1917 {
1918 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1919 }
1920 else
1921 {
1922 ret = FALSE;
1923 }
1924
1925 UserLeave();
1926
1927 return ret;
1928 }
1929
1930 BOOL
1931 NTAPI
1932 NtUserSetWindowStationUser(
1933 IN HWINSTA hWindowStation,
1934 IN PLUID pluid,
1935 IN PSID psid OPTIONAL,
1936 IN DWORD size)
1937 {
1938 BOOL Ret = FALSE;
1939 NTSTATUS Status;
1940 PWINSTATION_OBJECT WindowStation = NULL;
1941 LUID luidUser;
1942
1943 UserEnterExclusive();
1944
1945 if (gpidLogon != PsGetCurrentProcessId())
1946 {
1947 EngSetLastError(ERROR_ACCESS_DENIED);
1948 goto Leave;
1949 }
1950
1951 /* Validate the window station */
1952 Status = IntValidateWindowStationHandle(hWindowStation,
1953 UserMode,
1954 0,
1955 &WindowStation,
1956 NULL);
1957 if (!NT_SUCCESS(Status))
1958 {
1959 goto Leave;
1960 }
1961
1962 /* Capture the user LUID */
1963 _SEH2_TRY
1964 {
1965 ProbeForRead(pluid, sizeof(LUID), 1);
1966 luidUser = *pluid;
1967 }
1968 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1969 {
1970 Status = _SEH2_GetExceptionCode();
1971 _SEH2_YIELD(goto Leave);
1972 }
1973 _SEH2_END;
1974
1975 /* Reset the window station user LUID */
1976 RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
1977
1978 /* Reset the window station user SID */
1979 if (WindowStation->psidUser)
1980 {
1981 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1982 WindowStation->psidUser = NULL;
1983 }
1984
1985 /* Copy the new user SID if one has been provided */
1986 if (psid)
1987 {
1988 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
1989 if (WindowStation->psidUser == NULL)
1990 {
1991 EngSetLastError(ERROR_OUTOFMEMORY);
1992 goto Leave;
1993 }
1994
1995 Status = STATUS_SUCCESS;
1996 _SEH2_TRY
1997 {
1998 ProbeForRead(psid, size, 1);
1999 RtlCopyMemory(WindowStation->psidUser, psid, size);
2000 }
2001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2002 {
2003 Status = _SEH2_GetExceptionCode();
2004 }
2005 _SEH2_END;
2006
2007 if (!NT_SUCCESS(Status))
2008 {
2009 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
2010 WindowStation->psidUser = NULL;
2011 goto Leave;
2012 }
2013 }
2014
2015 /* Copy the new user LUID */
2016 WindowStation->luidUser = luidUser;
2017
2018 Ret = TRUE;
2019
2020 Leave:
2021 if (WindowStation)
2022 ObDereferenceObject(WindowStation);
2023
2024 UserLeave();
2025 return Ret;
2026 }
2027
2028 /* EOF */