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 */ 2029