[WIN32K:NTUSER] Split NtUserCreateWindowStation() into the part that captures the...
[reactos.git] / win32ss / user / ntuser / winsta.c
index 1187e44..eb3ca30 100644 (file)
@@ -47,11 +47,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 +64,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 +81,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);
@@ -96,7 +99,7 @@ UserCreateWinstaDirectory(VOID)
 /* OBJECT CALLBACKS  **********************************************************/
 
 NTSTATUS
-APIENTRY
+NTAPI
 IntWinStaObjectDelete(
     _In_ PVOID Parameters)
 {
@@ -117,7 +120,7 @@ IntWinStaObjectDelete(
 }
 
 NTSTATUS
-APIENTRY
+NTAPI
 IntWinStaObjectParse(
     _In_ PVOID Parameters)
 {
@@ -183,7 +186,7 @@ IntWinStaObjectParse(
 
 NTSTATUS
 NTAPI
-IntWinstaOkToClose(
+IntWinStaOkToClose(
     _In_ PVOID Parameters)
 {
     PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
@@ -370,7 +373,7 @@ CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
  *    lpSecurity
  *       Security descriptor
  *
- *    Unknown3, Unknown4, Unknown5
+ *    Unknown3, Unknown4, Unknown5, Unknown6
  *       Unused
  *
  * Return Value
@@ -379,116 +382,100 @@ CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
  *    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 ACCESS_MASK dwDesiredAccess,
     DWORD Unknown2,
     DWORD Unknown3,
     DWORD Unknown4,
     DWORD Unknown5,
     DWORD Unknown6)
 {
-    UNICODE_STRING WindowStationName;
-    PWINSTATION_OBJECT WindowStationObject;
-    HWINSTA WindowStation;
     NTSTATUS Status;
+    HWINSTA WindowStation;
+    PWINSTATION_OBJECT WindowStationObject;
 
-    TRACE("NtUserCreateWindowStation called\n");
+    TRACE("IntCreateWindowStation called\n");
+
+    ASSERT(phWinSta);
+    *phWinSta = NULL;
 
     Status = ObOpenObjectByName(ObjectAttributes,
                                 ExWindowStationObjectType,
-                                UserMode,
+                                AccessMode,
                                 NULL,
                                 dwDesiredAccess,
                                 NULL,
                                 (PVOID*)&WindowStation);
-
     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 = WindowStation;
+        return Status;
     }
 
     /*
-     * No existing window station found, try to create new one
+     * No existing window station found, try to create 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(KernelMode,
                             ExWindowStationObjectType,
                             ObjectAttributes,
-                            UserMode,
+                            AccessMode,
                             NULL,
                             sizeof(WINSTATION_OBJECT),
                             0,
                             0,
                             (PVOID*)&WindowStationObject);
-
     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 with %lx for window station %wZ\n",
+            Status, ObjectAttributes->ObjectName);
+        SetLastNtError(Status);
+        return Status;
     }
 
     /* Initialize the window station */
     RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
 
     InitializeListHead(&WindowStationObject->DesktopListHead);
-    WindowStationObject->Name = WindowStationName;
+    WindowStationObject->Name = *ObjectAttributes->ObjectName;
+    ObjectAttributes->ObjectName = NULL; // FIXME! (see NtUserCreateWindowStation())
     WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
     Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
     if (!NT_SUCCESS(Status))
     {
-        ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, &WindowStationName);
+        ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, ObjectAttributes->ObjectName);
         ObDereferenceObject(WindowStationObject);
-        SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-        return 0;
+        SetLastNtError(Status);
+        return Status;
     }
 
-    Status = ObInsertObject((PVOID)WindowStationObject,
+    Status = ObInsertObject(WindowStationObject,
                             NULL,
                             dwDesiredAccess,
                             0,
                             NULL,
                             (PVOID*)&WindowStation);
-
     if (!NT_SUCCESS(Status))
     {
         ERR("ObInsertObject failed with %lx for window station\n", Status);
-        SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-        return 0;
+        SetLastNtError(Status);
+        return Status;
     }
 
+    // FIXME! TODO: Add this new window station to a linked list
+
     if (InputWindowStation == NULL)
     {
         ERR("Initializing input window station\n");
@@ -503,9 +490,84 @@ NtUserCreateWindowStation(
         WindowStationObject->Flags |= WSS_NOIO;
     }
 
-    TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
-          WindowStation, &WindowStationObject->Name, WindowStation);
-    return WindowStation;
+    TRACE("IntCreateWindowStation created object 0x%p with name %wZ handle 0x%p\n",
+          WindowStationObject, &WindowStationObject->Name, WindowStation);
+
+    *phWinSta = WindowStation;
+    return STATUS_SUCCESS;
+}
+
+HWINSTA
+APIENTRY
+NtUserCreateWindowStation(
+    IN POBJECT_ATTRIBUTES ObjectAttributes,
+    IN ACCESS_MASK dwDesiredAccess,
+    DWORD Unknown2,
+    DWORD Unknown3,
+    DWORD Unknown4,
+    DWORD Unknown5,
+    DWORD Unknown6)
+{
+    NTSTATUS Status;
+    HWINSTA hWinSta;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    UNICODE_STRING WindowStationName;
+
+    TRACE("NtUserCreateWindowStation called\n");
+
+    /* Capture window station name */
+    _SEH2_TRY
+    {
+        ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
+        LocalObjectAttributes = *ObjectAttributes;
+        Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName,
+                                                       LocalObjectAttributes.ObjectName);
+        LocalObjectAttributes.ObjectName = &WindowStationName;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status =_SEH2_GetExceptionCode();
+    }
+    _SEH2_END
+
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Failed reading or capturing window station name, Status 0x%08lx\n", Status);
+        SetLastNtError(Status);
+        return NULL;
+    }
+
+    // TODO: Capture and use the SecurityQualityOfService!
+
+    Status = IntCreateWindowStation(&hWinSta,
+                                    &LocalObjectAttributes,
+                                    UserMode,
+                                    dwDesiredAccess,
+                                    Unknown2,
+                                    Unknown3,
+                                    Unknown4,
+                                    Unknown5,
+                                    Unknown6);
+
+    // FIXME! Because in some situations we store the allocated window station name
+    // inside the window station, we must not free it now! We know this fact when
+    // IntCreateWindowStation() sets LocalObjectAttributes.ObjectName to NULL.
+    // This hack must be removed once we just use the stored Ob name instead
+    // (in which case we will always free the allocated name here).
+    if (LocalObjectAttributes.ObjectName)
+        ExFreePoolWithTag(LocalObjectAttributes.ObjectName->Buffer, TAG_STRING);
+
+    if (NT_SUCCESS(Status))
+    {
+        TRACE("NtUserCreateWindowStation created a window station with handle 0x%p\n", hWinSta);
+    }
+    else
+    {
+        ASSERT(hWinSta == NULL);
+        TRACE("NtUserCreateWindowStation failed to create a window station!\n");
+    }
+
+    return hWinSta;
 }
 
 /*
@@ -717,27 +779,55 @@ NtUserGetObjectInformation(
         goto Exit;
     }
 
-    TRACE("WinSta or Desktop opened!!\n");
+    TRACE("WinSta or Desktop opened!\n");
 
     /* Get data */
     switch (nIndex)
     {
         case UOI_FLAGS:
         {
-            /* This is a default implementation that does almost nothing */
-            ObjectFlags.fInherit = FALSE;
+            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.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;
-            ERR("UOI_FLAGS unimplemented!\n");
             break;
         }
 
         case UOI_NAME:
         {
+            // FIXME: Use either ObQueryNameString() or read directly that name inside the Object section!
             if (WinStaObject != NULL)
             {
                 pvData = WinStaObject->Name.Buffer;
@@ -913,7 +1003,7 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
     ppi = PsGetCurrentProcessWin32Process();
 
     /* Reference the new window station */
-    if(hWindowStation !=NULL)
+    if (hWindowStation != NULL)
     {
         Status = IntValidateWindowStationHandle(hWindowStation,
                                                 UserMode,
@@ -933,13 +1023,13 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
     hwinstaOld = 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)
+    if (hwinstaOld != ppi->hwinsta)
     {
         ObCloseHandle(hwinstaOld, UserMode);
     }
@@ -964,7 +1054,7 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
         ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
     }
 
-    if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
+    if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO))
     {
         ppi->W32PF_flags |= W32PF_IOWINSTA;
     }
@@ -1110,6 +1200,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.
      */
@@ -1459,16 +1557,18 @@ NtUserLockWorkStation(VOID)
     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();
 
@@ -1478,53 +1578,79 @@ NtUserSetWindowStationUser(
         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;
 }