/* 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 */
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();
}
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))
{
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);
return Status;
}
-/* OBJECT CALLBACKS **********************************************************/
+/* OBJECT CALLBACKS ***********************************************************/
NTSTATUS
-APIENTRY
+NTAPI
IntWinStaObjectDelete(
_In_ PVOID Parameters)
{
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;
RtlDestroyAtomTable(WinSta->AtomTable);
- RtlFreeUnicodeString(&WinSta->Name);
-
return STATUS_SUCCESS;
}
NTSTATUS
-APIENTRY
+NTAPI
IntWinStaObjectParse(
_In_ PVOID Parameters)
{
NTSTATUS
NTAPI
-IntWinstaOkToClose(
+IntWinStaOkToClose(
_In_ PVOID Parameters)
{
PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
ppi = PsGetCurrentProcessWin32Process();
- if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
+ if (ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
{
return STATUS_ACCESS_DENIED;
}
* lpSecurity
* Security descriptor
*
- * Unknown3, Unknown4, Unknown5
+ * Unknown3, Unknown4, Unknown5, Unknown6
* Unused
*
* Return Value
* exists, the function succeeds and returns a handle to the existing
* window station. If the function fails, the return value is NULL.
*
- * Todo
- * Correct the prototype to match the Windows one (with 7 parameters
- * on Windows XP).
- *
* Status
* @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();
}
else
{
- WindowStationObject->Flags |= WSS_NOIO;
+ WindowStation->Flags |= WSS_NOIO;
}
- TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
- WindowStation, &WindowStationObject->Name, WindowStation);
- return WindowStation;
+ TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
+ ObjectAttributes->ObjectName, WindowStation, hWinSta);
+
+ *phWinSta = hWinSta;
+ 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;
+ }
+
+ /* Create the window station */
+ Status = IntCreateWindowStation(&hWinSta,
+ ObjectAttributes,
+ UserMode,
+ OwnerMode,
+ dwDesiredAccess,
+ Unknown2,
+ Unknown3,
+ Unknown4,
+ Unknown5,
+ Unknown6);
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
+ ObjectAttributes->ObjectName, hWinSta);
+ }
+ else
+ {
+ ASSERT(hWinSta == NULL);
+ ERR("NtUserCreateWindowStation failed to create 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))
+ {
+ ASSERT(hWinSta == NULL);
+ SetLastNtError(Status);
+ }
+
+ return hWinSta;
}
/*
* @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;
}
/*
*
* 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
UserMode,
0,
&Object,
- 0);
-
+ NULL);
if (!NT_SUCCESS(Status))
{
ERR("Validation of window station handle (%p) failed\n", hWinSta);
DWORD nLength,
PDWORD nLengthNeeded)
{
- PWINSTATION_OBJECT WinStaObject;
- PDESKTOP DesktopObject = NULL;
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;
- DWORD nDataSize = 0;
+ SIZE_T nDataSize = 0;
_SEH2_TRY
{
}
_SEH2_END;
- /* try windowstation */
- TRACE("Trying to open window station %p\n", hObject);
+ /* Try window station */
+ 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)
{
- /* try desktop */
+ /* Try desktop */
TRACE("Trying to open desktop %p\n", hObject);
WinStaObject = NULL;
Status = IntValidateDesktopHandle(hObject,
goto Exit;
}
- TRACE("WinSta or Desktop opened!!\n");
+ TRACE("WinSta or Desktop opened!\n");
- /* get data */
+ /* Get data */
switch (nIndex)
{
case UOI_FLAGS:
- Status = STATUS_NOT_IMPLEMENTED;
- ERR("UOI_FLAGS unimplemented!\n");
+ {
+ ObjectFlags.fReserved = FALSE;
+ ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
+
+ ObjectFlags.dwFlags = 0;
+ if (WinStaObject != NULL)
+ {
+ if (!(WinStaObject->Flags & WSS_NOIO))
+ ObjectFlags.dwFlags |= WSF_VISIBLE;
+ }
+ else if (DesktopObject != NULL)
+ {
+ FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
+ }
+ else
+ {
+ ERR("No associated WinStaObject nor DesktopObject!\n");
+ }
+
+ pvData = &ObjectFlags;
+ nDataSize = sizeof(ObjectFlags);
+ Status = STATUS_SUCCESS;
break;
+ }
case UOI_NAME:
+ {
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)
Status = STATUS_SUCCESS;
}
else
+ {
Status = STATUS_INVALID_PARAMETER;
+ }
break;
+ }
case UOI_TYPE:
+ {
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
+ {
Status = STATUS_INVALID_PARAMETER;
+ }
break;
+ }
case UOI_USER_SID:
Status = STATUS_NOT_IMPLEMENTED;
}
Exit:
- if (Status == STATUS_SUCCESS && nLength < nDataSize)
+ if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
Status = STATUS_BUFFER_TOO_SMALL;
_SEH2_TRY
if (nLengthNeeded)
*nLengthNeeded = nDataSize;
- /* try to copy data to caller */
- if (Status == STATUS_SUCCESS)
+ /* Try to copy data to caller */
+ 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)
}
_SEH2_END;
- /* release objects */
- if (WinStaObject != NULL)
- ObDereferenceObject(WinStaObject);
+ /* Release objects */
if (DesktopObject != NULL)
ObDereferenceObject(DesktopObject);
+ if (WinStaObject != NULL)
+ ObDereferenceObject(WinStaObject);
if (!NT_SUCCESS(Status))
{
}
-
-
HWINSTA FASTCALL
UserGetProcessWindowStation(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();
/* Reference the new window station */
- if(hWindowStation !=NULL)
+ if (hWindowStation != NULL)
{
Status = IntValidateWindowStationHandle(hWindowStation,
UserMode,
&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)
+ if (OldWinSta != NULL)
{
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;
ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
}
- if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
+ if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
{
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;
}
UserMode,
0,
&Object,
- 0);
+ NULL);
if (!NT_SUCCESS(Status))
{
TRACE("Validation of window station handle (%p) failed\n",
UserMode,
0,
&Object,
- 0);
+ NULL);
if (!NT_SUCCESS(Status))
{
TRACE("Validation of window station handle (%p) failed\n",
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.
*/
UserMode,
0,
&WindowStation,
- 0);
+ NULL);
if (! NT_SUCCESS(Status))
{
return Status;
return ret;
}
-BOOL APIENTRY
+BOOL
+NTAPI
NtUserSetWindowStationUser(
- HWINSTA hWindowStation,
- PLUID pluid,
- PSID psid,
- DWORD size)
+ IN HWINSTA hWindowStation,
+ IN PLUID pluid,
+ IN PSID psid OPTIONAL,
+ IN DWORD size)
{
+ BOOL Ret = FALSE;
NTSTATUS Status;
PWINSTATION_OBJECT WindowStation = NULL;
- BOOL Ret = FALSE;
+ LUID luidUser;
UserEnterExclusive();
goto Leave;
}
+ /* Validate the window station */
Status = IntValidateWindowStationHandle(hWindowStation,
UserMode,
0,
&WindowStation,
- 0);
+ NULL);
if (!NT_SUCCESS(Status))
{
goto Leave;
}
- if (WindowStation->psidUser)
- {
- ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
- }
-
- WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
- if (WindowStation->psidUser == NULL)
- {
- EngSetLastError(ERROR_OUTOFMEMORY);
- goto Leave;
- }
-
+ /* Capture the user LUID */
_SEH2_TRY
{
- ProbeForRead( psid, size, 1);
- ProbeForRead( pluid, sizeof(LUID), 1);
-
- RtlCopyMemory(WindowStation->psidUser, psid, size);
- WindowStation->luidUser = *pluid;
+ ProbeForRead(pluid, sizeof(LUID), 1);
+ luidUser = *pluid;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Leave);
}
_SEH2_END;
- if (!NT_SUCCESS(Status))
+ /* Reset the window station user LUID */
+ RtlZeroMemory(&WindowStation->luidUser, sizeof(LUID));
+
+ /* Reset the window station user SID */
+ if (WindowStation->psidUser)
{
ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
- WindowStation->psidUser = 0;
- goto Leave;
+ WindowStation->psidUser = NULL;
}
+ /* Copy the new user SID if one has been provided */
+ if (psid)
+ {
+ WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
+ if (WindowStation->psidUser == NULL)
+ {
+ EngSetLastError(ERROR_OUTOFMEMORY);
+ goto Leave;
+ }
+
+ Status = STATUS_SUCCESS;
+ _SEH2_TRY
+ {
+ ProbeForRead(psid, size, 1);
+ RtlCopyMemory(WindowStation->psidUser, psid, size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
+ WindowStation->psidUser = NULL;
+ goto Leave;
+ }
+ }
+
+ /* Copy the new user LUID */
+ WindowStation->luidUser = luidUser;
+
Ret = TRUE;
Leave:
- if (WindowStation) ObDereferenceObject(WindowStation);
+ if (WindowStation)
+ ObDereferenceObject(WindowStation);
+
UserLeave();
return Ret;
}
-
/* EOF */