X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=win32ss%2Fuser%2Fntuser%2Fwinsta.c;h=033c7a1e77928113f766e62fe9070a950c0d8e13;hp=44a8f405051c6989d73cad9fabb0da152241c95e;hb=ca24df9c85ac0883cce43641c9083aa0ef03d9f4;hpb=b003d68ca58ce94766141c779332e4c42b7fc430 diff --git a/win32ss/user/ntuser/winsta.c b/win32ss/user/ntuser/winsta.c index 44a8f405051..033c7a1e779 100644 --- a/win32ss/user/ntuser/winsta.c +++ b/win32ss/user/ntuser/winsta.c @@ -14,7 +14,10 @@ DBG_DEFAULT_CHANNEL(UserWinsta); /* GLOBALS *******************************************************************/ -/* Currently active window station */ +/* + * The currently active window station. This is the + * only one interactive window station on the system. + */ PWINSTATION_OBJECT InputWindowStation = NULL; /* Winlogon SAS window */ @@ -47,11 +50,11 @@ NTSTATUS NTAPI UserCreateWinstaDirectory(VOID) { - PPEB Peb; NTSTATUS Status; - WCHAR wstrWindowStationsDir[MAX_PATH]; + PPEB Peb; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE hWinstaDir; + WCHAR wstrWindowStationsDir[MAX_PATH]; /* Create the WindowStations directory and cache its path for later use */ Peb = NtCurrentPeb(); @@ -64,11 +67,14 @@ UserCreateWinstaDirectory(VOID) } else { - swprintf(wstrWindowStationsDir, - L"%ws\\%lu%ws", - SESSION_DIR, - Peb->SessionId, - WINSTA_OBJ_DIR); + Status = RtlStringCbPrintfW(wstrWindowStationsDir, + sizeof(wstrWindowStationsDir), + L"%ws\\%lu%ws", + SESSION_DIR, + Peb->SessionId, + WINSTA_OBJ_DIR); + if (!NT_SUCCESS(Status)) + return Status; if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir)) { @@ -78,10 +84,10 @@ UserCreateWinstaDirectory(VOID) InitializeObjectAttributes(&ObjectAttributes, &gustrWindowStationsDir, - 0, + OBJ_KERNEL_HANDLE, NULL, NULL); - Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes); + Status = ZwCreateDirectoryObject(&hWinstaDir, DIRECTORY_CREATE_OBJECT, &ObjectAttributes); if (!NT_SUCCESS(Status)) { ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status); @@ -93,7 +99,7 @@ UserCreateWinstaDirectory(VOID) return Status; } -/* OBJECT CALLBACKS **********************************************************/ +/* OBJECT CALLBACKS ***********************************************************/ NTSTATUS NTAPI @@ -103,7 +109,18 @@ IntWinStaObjectDelete( PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters; PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object; - TRACE("Deleting window station (0x%p)\n", WinSta); + TRACE("Deleting window station 0x%p\n", WinSta); + + if (WinSta == InputWindowStation) + { + ERR("WARNING: Deleting the interactive window station '%wZ'!\n", + &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(InputWindowStation))->Name)); + + /* Only Winlogon can close and delete the interactive window station */ + ASSERT(gpidLogon == PsGetCurrentProcessId()); + + InputWindowStation = NULL; + } WinSta->Flags |= WSS_DYING; @@ -111,8 +128,6 @@ IntWinStaObjectDelete( RtlDestroyAtomTable(WinSta->AtomTable); - RtlFreeUnicodeString(&WinSta->Name); - return STATUS_SUCCESS; } @@ -191,7 +206,7 @@ IntWinStaOkToClose( ppi = PsGetCurrentProcessWin32Process(); - if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta)) + if (ppi && (OkToCloseParameters->Handle == ppi->hwinsta)) { return STATUS_ACCESS_DENIED; } @@ -256,7 +271,7 @@ co_IntInitializeDesktopGraphics(VOID) } GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC); - if (! IntCreatePrimarySurface()) + if (!IntCreatePrimarySurface()) { return FALSE; } @@ -266,6 +281,12 @@ co_IntInitializeDesktopGraphics(VOID) NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT)); GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC); + /* Update the system metrics */ + InitMetrics(); + + /* Set new size of the monitor */ + UserUpdateMonitorSize((HDEV)gppdevPrimary); + /* Update the SERVERINFO */ gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes; gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes; @@ -278,7 +299,9 @@ co_IntInitializeDesktopGraphics(VOID) gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY; } else + { gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY; + } // Font is realized and this dc was previously set to internal DC_ATTR. gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar); gpsi->tmSysFont = tmw; @@ -383,125 +406,405 @@ CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess) * @implemented */ -HWINSTA APIENTRY -NtUserCreateWindowStation( - POBJECT_ATTRIBUTES ObjectAttributes, - ACCESS_MASK dwDesiredAccess, +NTSTATUS +FASTCALL +IntCreateWindowStation( + OUT HWINSTA* phWinSta, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE AccessMode, + IN KPROCESSOR_MODE OwnerMode, + IN ACCESS_MASK dwDesiredAccess, DWORD Unknown2, DWORD Unknown3, DWORD Unknown4, DWORD Unknown5, DWORD Unknown6) { - UNICODE_STRING WindowStationName; - PWINSTATION_OBJECT WindowStationObject; - HWINSTA WindowStation; NTSTATUS Status; + HWINSTA hWinSta; + PWINSTATION_OBJECT WindowStation; - TRACE("NtUserCreateWindowStation called\n"); + TRACE("IntCreateWindowStation called\n"); + + ASSERT(phWinSta); + *phWinSta = NULL; Status = ObOpenObjectByName(ObjectAttributes, ExWindowStationObjectType, - UserMode, + AccessMode, NULL, dwDesiredAccess, NULL, - (PVOID*)&WindowStation); - + (PVOID*)&hWinSta); if (NT_SUCCESS(Status)) { - TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName); - return (HWINSTA)WindowStation; + TRACE("IntCreateWindowStation opened window station '%wZ'\n", + ObjectAttributes->ObjectName); + *phWinSta = hWinSta; + return Status; } /* - * No existing window station found, try to create new one + * No existing window station found, try to create a new one. */ - /* Capture window station name */ - _SEH2_TRY - { - ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1); - Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status =_SEH2_GetExceptionCode(); - } - _SEH2_END - - if (! NT_SUCCESS(Status)) - { - ERR("Failed reading capturing window station name\n"); - SetLastNtError(Status); - return NULL; - } - /* Create the window station object */ - Status = ObCreateObject(UserMode, + Status = ObCreateObject(AccessMode, ExWindowStationObjectType, ObjectAttributes, - UserMode, + OwnerMode, NULL, sizeof(WINSTATION_OBJECT), 0, 0, - (PVOID*)&WindowStationObject); - + (PVOID*)&WindowStation); if (!NT_SUCCESS(Status)) { - ERR("ObCreateObject failed with %lx for window station %wZ\n", Status, &WindowStationName); - ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING); - SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); - return 0; + ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n", + ObjectAttributes->ObjectName, Status); + SetLastNtError(Status); + return Status; } /* Initialize the window station */ - RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT)); + RtlZeroMemory(WindowStation, sizeof(WINSTATION_OBJECT)); - InitializeListHead(&WindowStationObject->DesktopListHead); - WindowStationObject->Name = WindowStationName; - WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId; - Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable); + InitializeListHead(&WindowStation->DesktopListHead); + WindowStation->dwSessionId = NtCurrentPeb()->SessionId; + Status = RtlCreateAtomTable(37, &WindowStation->AtomTable); if (!NT_SUCCESS(Status)) { - ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, &WindowStationName); - ObDereferenceObject(WindowStationObject); - SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); - return 0; + ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n", + ObjectAttributes->ObjectName, Status); + ObDereferenceObject(WindowStation); + SetLastNtError(Status); + return Status; } - Status = ObInsertObject((PVOID)WindowStationObject, + Status = ObInsertObject(WindowStation, NULL, dwDesiredAccess, 0, NULL, - (PVOID*)&WindowStation); - + (PVOID*)&hWinSta); if (!NT_SUCCESS(Status)) { - ERR("ObInsertObject failed with %lx for window station\n", Status); - SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); - return 0; + ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status); + SetLastNtError(Status); + return Status; } + // FIXME! TODO: Add this new window station to a linked list + if (InputWindowStation == NULL) { ERR("Initializing input window station\n"); - InputWindowStation = WindowStationObject; - WindowStationObject->Flags &= ~WSS_NOIO; + /* Only Winlogon can create the interactive window station */ + ASSERT(gpidLogon == PsGetCurrentProcessId()); + + InputWindowStation = WindowStation; + WindowStation->Flags &= ~WSS_NOIO; InitCursorImpl(); + + UserCreateSystemThread(ST_DESKTOP_THREAD); + UserCreateSystemThread(ST_RIT); + + /* Desktop functions require the desktop thread running so wait for it to initialize */ + UserLeaveCo(); + KeWaitForSingleObject(gpDesktopThreadStartedEvent, + UserRequest, + UserMode, + FALSE, + NULL); + UserEnterCo(); + } + else + { + WindowStation->Flags |= WSS_NOIO; + } + + TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n", + ObjectAttributes->ObjectName, WindowStation, hWinSta); + + *phWinSta = hWinSta; + EngSetLastError(ERROR_SUCCESS); + + return STATUS_SUCCESS; +} + +static VOID +FreeUserModeWindowStationName( + IN OUT PUNICODE_STRING WindowStationName, + IN PUNICODE_STRING TebStaticUnicodeString, + IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL, + IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL) +{ + SIZE_T MemSize = 0; + + /* Try to restore the user's UserModeObjectAttributes */ + if (UserModeObjectAttributes && LocalObjectAttributes) + { + _SEH2_TRY + { + ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); + *UserModeObjectAttributes = *LocalObjectAttributes; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + NOTHING; + } + _SEH2_END; + } + + /* Free the user-mode memory */ + if (WindowStationName && (WindowStationName != TebStaticUnicodeString)) + { + ZwFreeVirtualMemory(ZwCurrentProcess(), + (PVOID*)&WindowStationName, + &MemSize, + MEM_RELEASE); + } +} + +static NTSTATUS +BuildUserModeWindowStationName( + IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes, + IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes, + OUT PUNICODE_STRING* WindowStationName, + OUT PUNICODE_STRING* TebStaticUnicodeString) +{ + NTSTATUS Status; + SIZE_T MemSize; + + LUID CallerLuid; + PTEB Teb; + USHORT StrSize; + + *WindowStationName = NULL; + *TebStaticUnicodeString = NULL; + + /* Retrieve the current process LUID */ + Status = GetProcessLuid(NULL, NULL, &CallerLuid); + if (!NT_SUCCESS(Status)) + { + ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status); + return Status; + } + + /* Compute the needed string size */ + MemSize = _scwprintf(L"%wZ\\Service-0x%x-%x$", + &gustrWindowStationsDir, + CallerLuid.HighPart, + CallerLuid.LowPart); + MemSize = MemSize * sizeof(WCHAR) + sizeof(UNICODE_NULL); + if (MemSize > MAXUSHORT) + { + ERR("Window station name length is too long.\n"); + return STATUS_NAME_TOO_LONG; + } + StrSize = (USHORT)MemSize; + + /* + * Check whether it's short enough so that we can use the static buffer + * in the TEB. Otherwise continue with virtual memory allocation. + */ + Teb = NtCurrentTeb(); + if (Teb && (StrSize <= sizeof(Teb->StaticUnicodeBuffer))) + { + /* We can use the TEB's static unicode string */ + ASSERT(Teb->StaticUnicodeString.Buffer == Teb->StaticUnicodeBuffer); + ASSERT(Teb->StaticUnicodeString.MaximumLength == sizeof(Teb->StaticUnicodeBuffer)); + + /* Remember the TEB's static unicode string address for later */ + *TebStaticUnicodeString = &Teb->StaticUnicodeString; + + *WindowStationName = *TebStaticUnicodeString; + (*WindowStationName)->Length = 0; + } + else + { + /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */ + MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID)); + + /* Allocate the memory in user-mode */ + Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), + (PVOID*)WindowStationName, + 0, + &MemSize, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status); + return Status; + } + + RtlInitEmptyUnicodeString(*WindowStationName, + (PWCHAR)((ULONG_PTR)*WindowStationName + + ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))), + StrSize); + } + + /* Build a valid window station name from the LUID */ + Status = RtlStringCbPrintfW((*WindowStationName)->Buffer, + (*WindowStationName)->MaximumLength, + L"%wZ\\Service-0x%x-%x$", + &gustrWindowStationsDir, + CallerLuid.HighPart, + CallerLuid.LowPart); + if (!NT_SUCCESS(Status)) + { + ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status); + goto Quit; + } + (*WindowStationName)->Length = (USHORT)(wcslen((*WindowStationName)->Buffer) * sizeof(WCHAR)); + + /* Try to update the user's UserModeObjectAttributes */ + _SEH2_TRY + { + ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); + *LocalObjectAttributes = *UserModeObjectAttributes; + + UserModeObjectAttributes->ObjectName = *WindowStationName; + UserModeObjectAttributes->RootDirectory = NULL; + + Status = STATUS_SUCCESS; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + +Quit: + if (!NT_SUCCESS(Status)) + { + /* Release the window station name */ + FreeUserModeWindowStationName(*WindowStationName, + *TebStaticUnicodeString, + NULL, NULL); + } + + return Status; +} + +HWINSTA +APIENTRY +NtUserCreateWindowStation( + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ACCESS_MASK dwDesiredAccess, + DWORD Unknown2, + DWORD Unknown3, + DWORD Unknown4, + DWORD Unknown5, + DWORD Unknown6) +{ + NTSTATUS Status = STATUS_SUCCESS; + HWINSTA hWinSta = NULL; + OBJECT_ATTRIBUTES LocalObjectAttributes; + PUNICODE_STRING WindowStationName = NULL; + PUNICODE_STRING TebStaticUnicodeString = NULL; + KPROCESSOR_MODE OwnerMode = UserMode; + + TRACE("NtUserCreateWindowStation called\n"); + + /* Capture the object attributes and the window station name */ + _SEH2_TRY + { + ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); + LocalObjectAttributes = *ObjectAttributes; + if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES)) + { + ERR("Invalid ObjectAttributes length!\n"); + Status = STATUS_INVALID_PARAMETER; + _SEH2_LEAVE; + } + + /* + * Check whether the caller provided a window station name together + * with a RootDirectory handle. + * + * If the caller did not provide a window station name, build a new one + * based on the logon session identifier for the calling process. + * The new name is allocated in user-mode, as the rest of ObjectAttributes + * already is, so that the validation performed by the Object Manager + * can be done adequately. + */ + if ((LocalObjectAttributes.ObjectName == NULL || + LocalObjectAttributes.ObjectName->Buffer == NULL || + LocalObjectAttributes.ObjectName->Length == 0 || + LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL) + /* && + LocalObjectAttributes.RootDirectory == NULL */) + { + /* No, build the new window station name */ + Status = BuildUserModeWindowStationName(ObjectAttributes, + &LocalObjectAttributes, + &WindowStationName, + &TebStaticUnicodeString); + if (!NT_SUCCESS(Status)) + { + ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status); + _SEH2_LEAVE; + } + OwnerMode = KernelMode; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status =_SEH2_GetExceptionCode(); + ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status); + } + _SEH2_END; + + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + return NULL; + } + + UserEnterExclusive(); + + /* Create the window station */ + Status = IntCreateWindowStation(&hWinSta, + ObjectAttributes, + UserMode, + OwnerMode, + dwDesiredAccess, + Unknown2, + Unknown3, + Unknown4, + Unknown5, + Unknown6); + UserLeave(); + + if (NT_SUCCESS(Status)) + { + TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n", + ObjectAttributes->ObjectName, hWinSta); } else { - WindowStationObject->Flags |= WSS_NOIO; + ASSERT(hWinSta == NULL); + ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n", + ObjectAttributes->ObjectName, Status); } - TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n", - WindowStation, &WindowStationObject->Name, WindowStation); - return WindowStation; + /* Try to restore the user's ObjectAttributes and release the window station name */ + FreeUserModeWindowStationName(WindowStationName, + TebStaticUnicodeString, + (OwnerMode == KernelMode ? ObjectAttributes : NULL), + &LocalObjectAttributes); + + if (!NT_SUCCESS(Status)) + { + ASSERT(hWinSta == NULL); + SetLastNtError(Status); + } + + return hWinSta; } /* @@ -528,32 +831,130 @@ NtUserCreateWindowStation( * @implemented */ -HWINSTA APIENTRY +HWINSTA +APIENTRY NtUserOpenWindowStation( - POBJECT_ATTRIBUTES ObjectAttributes, - ACCESS_MASK dwDesiredAccess) + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ACCESS_MASK dwDesiredAccess) { - HWINSTA hwinsta; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; + HWINSTA hWinSta = NULL; + OBJECT_ATTRIBUTES LocalObjectAttributes; + PUNICODE_STRING WindowStationName = NULL; + PUNICODE_STRING TebStaticUnicodeString = NULL; + KPROCESSOR_MODE OwnerMode = UserMode; + TRACE("NtUserOpenWindowStation called\n"); + + /* Capture the object attributes and the window station name */ + _SEH2_TRY + { + ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); + LocalObjectAttributes = *ObjectAttributes; + if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES)) + { + ERR("Invalid ObjectAttributes length!\n"); + Status = STATUS_INVALID_PARAMETER; + _SEH2_LEAVE; + } + + /* + * Check whether the caller did not provide a window station name, + * or provided the special "Service-0x00000000-00000000$" name. + * + * NOTE: On Windows, the special "Service-0x00000000-00000000$" string + * is used instead of an empty name (observed when API-monitoring + * OpenWindowStation() called with an empty window station name). + */ + if ((LocalObjectAttributes.ObjectName == NULL || + LocalObjectAttributes.ObjectName->Buffer == NULL || + LocalObjectAttributes.ObjectName->Length == 0 || + LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL) + /* && + LocalObjectAttributes.RootDirectory == NULL */) + { + /* No, remember that for later */ + LocalObjectAttributes.ObjectName = NULL; + } + if (LocalObjectAttributes.ObjectName && + LocalObjectAttributes.ObjectName->Length == + sizeof(L"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL) && + _wcsnicmp(LocalObjectAttributes.ObjectName->Buffer, + L"Service-0x00000000-00000000$", + LocalObjectAttributes.ObjectName->Length / sizeof(WCHAR)) == 0) + { + /* No, remember that for later */ + LocalObjectAttributes.ObjectName = NULL; + } + + /* + * If the caller did not provide a window station name, build a new one + * based on the logon session identifier for the calling process. + * The new name is allocated in user-mode, as the rest of ObjectAttributes + * already is, so that the validation performed by the Object Manager + * can be done adequately. + */ + if (!LocalObjectAttributes.ObjectName) + { + /* No, build the new window station name */ + Status = BuildUserModeWindowStationName(ObjectAttributes, + &LocalObjectAttributes, + &WindowStationName, + &TebStaticUnicodeString); + if (!NT_SUCCESS(Status)) + { + ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status); + _SEH2_LEAVE; + } + OwnerMode = KernelMode; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status =_SEH2_GetExceptionCode(); + ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status); + } + _SEH2_END; + + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + return NULL; + } + + /* Open the window station */ Status = ObOpenObjectByName(ObjectAttributes, ExWindowStationObjectType, UserMode, NULL, dwDesiredAccess, NULL, - (PVOID*)&hwinsta); + (PVOID*)&hWinSta); + if (NT_SUCCESS(Status)) + { + TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n", + ObjectAttributes->ObjectName, hWinSta); + } + else + { + ASSERT(hWinSta == NULL); + ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n", + ObjectAttributes->ObjectName, Status); + } + + /* Try to restore the user's ObjectAttributes and release the window station name */ + FreeUserModeWindowStationName(WindowStationName, + TebStaticUnicodeString, + (OwnerMode == KernelMode ? ObjectAttributes : NULL), + &LocalObjectAttributes); if (!NT_SUCCESS(Status)) { - ERR("NtUserOpenWindowStation failed\n"); + ASSERT(hWinSta == NULL); SetLastNtError(Status); - return 0; } - TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta); - - return hwinsta; + return hWinSta; } /* @@ -570,7 +971,7 @@ NtUserOpenWindowStation( * * Remarks * The window station handle can be created with NtUserCreateWindowStation - * or NtUserOpenWindowStation. Attemps to close a handle to the window + * or NtUserOpenWindowStation. Attempts to close a handle to the window * station assigned to the calling process will fail. * * Status @@ -597,8 +998,7 @@ NtUserCloseWindowStation( UserMode, 0, &Object, - 0); - + NULL); if (!NT_SUCCESS(Status)) { ERR("Validation of window station handle (%p) failed\n", hWinSta); @@ -670,7 +1070,11 @@ NtUserGetObjectInformation( NTSTATUS Status; PWINSTATION_OBJECT WinStaObject = NULL; PDESKTOP DesktopObject = NULL; + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO NameInfo; + OBJECT_HANDLE_INFORMATION HandleInfo; USEROBJECTFLAGS ObjectFlags; + PUNICODE_STRING pStrNameU = NULL; PVOID pvData = NULL; SIZE_T nDataSize = 0; @@ -688,13 +1092,13 @@ NtUserGetObjectInformation( _SEH2_END; /* Try window station */ - TRACE("Trying to open window station %p\n", hObject); + TRACE("Trying to open window station 0x%p\n", hObject); Status = ObReferenceObjectByHandle(hObject, 0, ExWindowStationObjectType, UserMode, (PVOID*)&WinStaObject, - NULL); + &HandleInfo); if (Status == STATUS_OBJECT_TYPE_MISMATCH) { @@ -720,23 +1124,8 @@ NtUserGetObjectInformation( { case UOI_FLAGS: { - OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo; - ULONG BytesWritten; - ObjectFlags.fReserved = FALSE; - - /* Check whether this handle is inheritable */ - Status = ZwQueryObject(hObject, - ObjectHandleFlagInformation, - &HandleInfo, - sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION), - &BytesWritten); - if (!NT_SUCCESS(Status)) - { - ERR("ZwQueryObject failed, Status 0x%08lx\n", Status); - break; - } - ObjectFlags.fInherit = HandleInfo.Inherit; + ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT); ObjectFlags.dwFlags = 0; if (WinStaObject != NULL) @@ -763,8 +1152,22 @@ NtUserGetObjectInformation( { if (WinStaObject != NULL) { - pvData = WinStaObject->Name.Buffer; - nDataSize = WinStaObject->Name.Length + sizeof(WCHAR); + ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject); + NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + + if (NameInfo && (NameInfo->Name.Length > 0)) + { + /* Named window station */ + pStrNameU = &NameInfo->Name; + nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL); + } + else + { + /* Unnamed window station (should never happen!) */ + ASSERT(FALSE); + pStrNameU = NULL; + nDataSize = sizeof(UNICODE_NULL); + } Status = STATUS_SUCCESS; } else if (DesktopObject != NULL) @@ -784,14 +1187,16 @@ NtUserGetObjectInformation( { if (WinStaObject != NULL) { - pvData = L"WindowStation"; - nDataSize = sizeof(L"WindowStation"); + ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject); + pStrNameU = &ObjectHeader->Type->Name; + nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL); Status = STATUS_SUCCESS; } else if (DesktopObject != NULL) { - pvData = L"Desktop"; - nDataSize = sizeof(L"Desktop"); + ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject); + pStrNameU = &ObjectHeader->Type->Name; + nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL); Status = STATUS_SUCCESS; } else @@ -821,10 +1226,25 @@ Exit: *nLengthNeeded = nDataSize; /* Try to copy data to caller */ - if (Status == STATUS_SUCCESS) + if (Status == STATUS_SUCCESS && (nDataSize > 0)) { TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize); - RtlCopyMemory(pvInformation, pvData, nDataSize); + if (pvData) + { + /* Copy the data */ + RtlCopyMemory(pvInformation, pvData, nDataSize); + } + else if (pStrNameU) + { + /* Copy and NULL-terminate the string */ + RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length); + ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL; + } + else + { + /* Zero the memory */ + RtlZeroMemory(pvInformation, nDataSize); + } } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) @@ -893,8 +1313,6 @@ NtUserSetObjectInformation( } - - HWINSTA FASTCALL UserGetProcessWindowStation(VOID) { @@ -927,11 +1345,11 @@ NtUserGetProcessWindowStation(VOID) BOOL FASTCALL UserSetProcessWindowStation(HWINSTA hWindowStation) { - PPROCESSINFO ppi; NTSTATUS Status; - HWINSTA hwinstaOld; + PPROCESSINFO ppi; OBJECT_HANDLE_INFORMATION ObjectHandleInfo; PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta; + HWINSTA hCacheWinSta; ppi = PsGetCurrentProcessWin32Process(); @@ -945,15 +1363,14 @@ UserSetProcessWindowStation(HWINSTA hWindowStation) &ObjectHandleInfo); if (!NT_SUCCESS(Status)) { - TRACE("Validation of window station handle (%p) failed\n", - hWindowStation); + TRACE("Validation of window station handle 0x%p failed\n", hWindowStation); SetLastNtError(Status); return FALSE; } } OldWinSta = ppi->prpwinsta; - hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess); + hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess); /* Dereference the previous window station */ if (OldWinSta != NULL) @@ -961,17 +1378,64 @@ UserSetProcessWindowStation(HWINSTA hWindowStation) ObDereferenceObject(OldWinSta); } - /* Check if we have a stale handle (it should happen for console apps) */ - if (hwinstaOld != ppi->hwinsta) - { - ObCloseHandle(hwinstaOld, UserMode); - } - /* - * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects. + * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects? */ - PsSetProcessWindowStation(ppi->peProcess, hWindowStation); + /* Close the cached EPROCESS window station handle if needed */ + if (hCacheWinSta != NULL) + { + /* Reference the window station */ + Status = ObReferenceObjectByHandle(hCacheWinSta, + 0, + ExWindowStationObjectType, + UserMode, + (PVOID*)&OldWinSta, + NULL); + if (!NT_SUCCESS(Status)) + { + ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status); + /* We failed, reset the cache */ + hCacheWinSta = NULL; + PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta); + } + else + { + /* + * Close the old handle and reset the cache only + * if we are setting a different window station. + */ + if (NewWinSta != OldWinSta) + { + ObCloseHandle(hCacheWinSta, UserMode); + hCacheWinSta = NULL; + PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta); + } + + /* Dereference the window station */ + ObDereferenceObject(OldWinSta); + } + } + + /* Duplicate and save a new cached EPROCESS window station handle */ + if ((hCacheWinSta == NULL) && (hWindowStation != NULL)) + { + Status = ZwDuplicateObject(ZwCurrentProcess(), + hWindowStation, + ZwCurrentProcess(), + (PHANDLE)&hCacheWinSta, + 0, + 0, + DUPLICATE_SAME_ACCESS); + if (!NT_SUCCESS(Status)) + { + ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status); + } + else + { + PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta); + } + } ppi->prpwinsta = NewWinSta; ppi->hwinsta = hWindowStation; @@ -991,7 +1455,7 @@ UserSetProcessWindowStation(HWINSTA hWindowStation) { ppi->W32PF_flags |= W32PF_IOWINSTA; } - else // Might be closed if the handle is null. + else /* Might be closed if the handle is NULL */ { ppi->W32PF_flags &= ~W32PF_IOWINSTA; } @@ -1057,7 +1521,7 @@ NtUserLockWindowStation(HWINSTA hWindowStation) UserMode, 0, &Object, - 0); + NULL); if (!NT_SUCCESS(Status)) { TRACE("Validation of window station handle (%p) failed\n", @@ -1102,7 +1566,7 @@ NtUserUnlockWindowStation(HWINSTA hWindowStation) UserMode, 0, &Object, - 0); + NULL); if (!NT_SUCCESS(Status)) { TRACE("Validation of window station handle (%p) failed\n", @@ -1133,6 +1597,14 @@ BuildWindowStationNameList( POBJECT_DIRECTORY_INFORMATION DirEntry; WCHAR NullWchar; + // + // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation + // with judicious parameters one can create window stations elsewhere + // than in Windows\WindowStations directory, Win32k definitely MUST + // maintain a list of window stations it has created, and not rely + // on the enumeration of Windows\WindowStations !!! + // + /* * Try to open the directory. */ @@ -1318,7 +1790,7 @@ BuildDesktopNameList( UserMode, 0, &WindowStation, - 0); + NULL); if (! NT_SUCCESS(Status)) { return Status; @@ -1580,5 +2052,4 @@ Leave: return Ret; } - /* EOF */