diff --git a/reactos/ntoskrnl/ex/win32k.c b/reactos/ntoskrnl/ex/win32k.c index ef914065e86..9cd929996c9 100644 --- a/reactos/ntoskrnl/ex/win32k.c +++ b/reactos/ntoskrnl/ex/win32k.c @@ -37,10 +37,46 @@ GENERIC_MAPPING ExpDesktopMapping = PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse = NULL; PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete = NULL; +PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpWindowStationObjectOkToClose = NULL; +PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpDesktopObjectOkToClose = NULL; PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete = NULL; /* FUNCTIONS ****************************************************************/ +NTSTATUS +NTAPI +ExpDesktopOkToClose( IN PEPROCESS Process OPTIONAL, + IN PVOID Object, + IN HANDLE Handle, + IN KPROCESSOR_MODE AccessMode) +{ + WIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters; + + Parameters.Process = Process; + Parameters.Object = Object; + Parameters.Handle = Handle; + Parameters.PreviousMode = AccessMode; + + return ExpDesktopObjectOkToClose(&Parameters); +} + +NTSTATUS +NTAPI +ExpWindowStationOkToClose( IN PEPROCESS Process OPTIONAL, + IN PVOID Object, + IN HANDLE Handle, + IN KPROCESSOR_MODE AccessMode) +{ + WIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters; + + Parameters.Process = Process; + Parameters.Object = Object; + Parameters.Handle = Handle; + Parameters.PreviousMode = AccessMode; + + return ExpWindowStationObjectOkToClose(&Parameters); +} + VOID NTAPI ExpWinStaObjectDelete(PVOID DeletedObject) @@ -114,6 +150,7 @@ ExpWin32kInit(VOID) ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete; ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse; + ObjectTypeInitializer.OkayToCloseProcedure = ExpWindowStationOkToClose; ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, @@ -124,6 +161,7 @@ ExpWin32kInit(VOID) ObjectTypeInitializer.GenericMapping = ExpDesktopMapping; ObjectTypeInitializer.DeleteProcedure = ExpDesktopDelete; ObjectTypeInitializer.ParseProcedure = NULL; + ObjectTypeInitializer.OkayToCloseProcedure = ExpDesktopOkToClose; ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index 20d15651d4c..e19d020aa30 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -1752,7 +1752,6 @@ ObpCloseHandle(IN HANDLE Handle, /* Detach and return success */ if (AttachedToProcess) KeUnstackDetachProcess(&ApcState); - Status = STATUS_SUCCESS; } else { diff --git a/reactos/ntoskrnl/ps/win32.c b/reactos/ntoskrnl/ps/win32.c index 3a5c2c5b900..19dd4e9c43d 100644 --- a/reactos/ntoskrnl/ps/win32.c +++ b/reactos/ntoskrnl/ps/win32.c @@ -20,6 +20,8 @@ PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL; PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch = NULL; extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse; extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete; +extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpWindowStationObjectOkToClose; +extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpDesktopObjectOkToClose; extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete; extern PKWIN32_POWEREVENT_CALLOUT PopEventCallout; @@ -116,6 +118,8 @@ PsEstablishWin32Callouts(IN PWIN32_CALLOUTS_FPNS CalloutData) PspW32ThreadCallout = CalloutData->ThreadCallout; ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure; ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure; + ExpWindowStationObjectOkToClose = CalloutData->WindowStationOkToCloseProcedure; + ExpDesktopObjectOkToClose = CalloutData->DesktopOkToCloseProcedure; ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure; PopEventCallout = CalloutData->PowerEventCallout; KeGdiFlushUserBatch = CalloutData->BatchFlushRoutine; diff --git a/reactos/subsystems/win32/win32k/include/desktop.h b/reactos/subsystems/win32/win32k/include/desktop.h index 388a0f4c23c..82607df23dc 100644 --- a/reactos/subsystems/win32/win32k/include/desktop.h +++ b/reactos/subsystems/win32/win32k/include/desktop.h @@ -69,6 +69,9 @@ IntDesktopObjectParse(IN PVOID ParseObject, VOID APIENTRY IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters); +NTSTATUS NTAPI +IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters); + LRESULT CALLBACK IntDesktopWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); diff --git a/reactos/subsystems/win32/win32k/include/win32.h b/reactos/subsystems/win32/win32k/include/win32.h index 521ef7a407c..2e43ec1517f 100644 --- a/reactos/subsystems/win32/win32k/include/win32.h +++ b/reactos/subsystems/win32/win32k/include/win32.h @@ -166,6 +166,7 @@ typedef struct _PROCESSINFO PCLS pclsPrivateList; PCLS pclsPublicList; INT cThreads; + HDESK hdeskStartup; DWORD dwhmodLibLoadedMask; HANDLE ahmodLibLoaded[CLIBS]; struct _WINSTATION_OBJECT *prpwinsta; diff --git a/reactos/subsystems/win32/win32k/include/winsta.h b/reactos/subsystems/win32/win32k/include/winsta.h index c40d14bf419..01a5fb77543 100644 --- a/reactos/subsystems/win32/win32k/include/winsta.h +++ b/reactos/subsystems/win32/win32k/include/winsta.h @@ -82,6 +82,9 @@ NTSTATUS APIENTRY IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters); +NTSTATUS NTAPI +IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters); + NTSTATUS FASTCALL IntValidateWindowStationHandle( HWINSTA WindowStation, @@ -106,4 +109,7 @@ IntGetFullWindowStationName( PWINSTATION_OBJECT FASTCALL IntGetWinStaObj(VOID); +BOOL FASTCALL +UserSetProcessWindowStation(HWINSTA hWindowStation); + /* EOF */ diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index a9202233735..1bff6e3f3b9 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -119,6 +119,7 @@ Win32kProcessCallback(struct _EPROCESS *Process, { DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql()); Win32Process->W32PF_flags |= W32PF_TERMINATED; + if (Win32Process->InputIdleEvent) { EngFreeMem((PVOID)Win32Process->InputIdleEvent); @@ -144,6 +145,9 @@ Win32kProcessCallback(struct _EPROCESS *Process, { LogonProcess = NULL; } + + UserSetProcessWindowStation(NULL); + } RETURN( STATUS_SUCCESS); @@ -220,25 +224,14 @@ Win32kThreadCallback(struct _ETHREAD *Thread, { if(hWinSta != NULL) { - if(Process != CsrProcess) + if(!UserSetProcessWindowStation(hWinSta)) { - HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL); - if(hProcessWinSta != NULL) - { - /* our process is already assigned to a different window station, we don't need the handle anymore */ - NtClose(hWinSta); - } - } - else - { - NtClose(hWinSta); + DPRINT1("Failed to set process window station\n"); } } if (hDesk != NULL) { - Win32Thread->rpdesk = NULL; - Win32Thread->hdesk = NULL; if (!IntSetThreadDesktop(hDesk, FALSE)) { DPRINT1("Unable to set thread desktop\n"); @@ -441,6 +434,8 @@ DriverEntry( CalloutData.ProcessCallout = Win32kProcessCallback; CalloutData.ThreadCallout = Win32kThreadCallback; CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch; + CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose; + CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose; /* Register our per-process and per-thread structures. */ PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData); diff --git a/reactos/subsystems/win32/win32k/ntuser/desktop.c b/reactos/subsystems/win32/win32k/ntuser/desktop.c index 0a240ad7772..e414e7e55bf 100644 --- a/reactos/subsystems/win32/win32k/ntuser/desktop.c +++ b/reactos/subsystems/win32/win32k/ntuser/desktop.c @@ -168,6 +168,29 @@ IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters) IntFreeDesktopHeap(Desktop); } +NTSTATUS NTAPI +IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters) +{ + PTHREADINFO pti; + + pti = PsGetCurrentThreadWin32Thread(); + + if( pti == NULL) + { + /* This happens when we leak desktop handles */ + return TRUE; + } + + /* Do not allow the current desktop or the initial desktop to be closed */ + if( Parameters->Handle == pti->ppi->hdeskStartup || + Parameters->Handle == pti->hdesk) + { + return FALSE; + } + + return TRUE; +} + /* PRIVATE FUNCTIONS **********************************************************/ INIT_FUNCTION diff --git a/reactos/subsystems/win32/win32k/ntuser/winsta.c b/reactos/subsystems/win32/win32k/ntuser/winsta.c index d4f4643f4ed..b22a9d7e2ea 100644 --- a/reactos/subsystems/win32/win32k/ntuser/winsta.c +++ b/reactos/subsystems/win32/win32k/ntuser/winsta.c @@ -187,6 +187,21 @@ IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters) return STATUS_OBJECT_TYPE_MISMATCH; } +NTSTATUS NTAPI +IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters) +{ + PPROCESSINFO ppi; + + ppi = PsGetCurrentProcessWin32Process(); + + if(Parameters->Handle == ppi->hwinsta) + { + return FALSE; + } + + return TRUE; +} + /* PRIVATE FUNCTIONS **********************************************************/ /* @@ -915,6 +930,57 @@ IntGetWinStaObj(VOID) return WinStaObj; } +BOOL FASTCALL +UserSetProcessWindowStation(HWINSTA hWindowStation) +{ + PPROCESSINFO ppi; + NTSTATUS Status; + HWINSTA hwinstaOld; + PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta; + + ppi = PsGetCurrentProcessWin32Process(); + + if(hWindowStation !=NULL) + { + Status = IntValidateWindowStationHandle( hWindowStation, + KernelMode, + 0, + &NewWinSta); + if (!NT_SUCCESS(Status)) + { + DPRINT("Validation of window station handle (0x%X) failed\n", + hWindowStation); + SetLastNtError(Status); + return FALSE; + } + } + + OldWinSta = ppi->prpwinsta; + hwinstaOld = ppi->hwinsta; + + /* + * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects + */ + + InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation); + + ppi->prpwinsta = NewWinSta; + ppi->hwinsta = hWindowStation; + + + if(OldWinSta != NULL) + { + ObDereferenceObject(OldWinSta); + } + + if(hwinstaOld != NULL) + { + ZwClose(hwinstaOld); + } + + return TRUE; +} + /* * NtUserSetProcessWindowStation * @@ -934,44 +1000,15 @@ IntGetWinStaObj(VOID) BOOL APIENTRY NtUserSetProcessWindowStation(HWINSTA hWindowStation) { - PWINSTATION_OBJECT NewWinSta; - NTSTATUS Status; + BOOL ret; - DPRINT("About to set process window station with handle (0x%X)\n", - hWindowStation); + UserEnterExclusive(); - if(PsGetCurrentProcess() == CsrProcess) - { - DPRINT1("CSRSS is not allowed to change it's window station!!!\n"); - EngSetLastError(ERROR_ACCESS_DENIED); - return FALSE; - } + ret = UserSetProcessWindowStation(hWindowStation); - Status = IntValidateWindowStationHandle( - hWindowStation, - KernelMode, - 0, - &NewWinSta); + UserLeave(); - if (!NT_SUCCESS(Status)) - { - DPRINT("Validation of window station handle (0x%X) failed\n", - hWindowStation); - SetLastNtError(Status); - return FALSE; - } - - /* - * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects - */ - - /* FIXME - dereference the old window station, etc... */ - InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation); - - DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n", - PsGetCurrentProcess()->Win32WindowStation); - - return TRUE; + return ret; } /*