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