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