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