mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
[WINLOGON][WIN32K]
Move the shutdown privilege check from winlogon to win32k (function "UserInitiateShutdown") as it should be done. [WIN32K] - Introduce the pair of UserInitiateShutdown/UserEndShutdown calls that should be called when WINSRV starts a shutdown (and when it finishes it). In particular it is in UserInitiateShutdown that we need to check whether the caller has the rights to perform a shutdown (it should also have a valid window station). - Remove the ROS-specific TWOPARAM_ROUTINE_EXITREACTOS call that is traded for Win2k3-compatible call to UserInitiateShutdown. [WINSRV] Hackfix our current ExitWindowsEx functionality (based on a patch by Alex made against r46050 for win32csr) to make it "compatible" with the improvements in win32k: impersonate the caller and call the UserInitiateShutdown win32k system call (instead of the TWOPARAM_ROUTINE_EXITREACTOS). More will come later on. [USER32] Win32k can require performing shutdown in an asynchronous way (needed also on WINSRV side) so we need to put all the code in a worker thread. Part 8/X (part 6 was r65693 and part 7 was r66186). CORE-8322 #comment Start to add Alex' win32csr shutdown patch in WINSRV; fixes for winlogon and additions to win32k. svn path=/trunk/; revision=66192
This commit is contained in:
parent
8e988cc2f3
commit
b8d8fbdc9d
8 changed files with 449 additions and 132 deletions
|
@ -1148,67 +1148,6 @@ UnregisterHotKeys(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static
|
||||
NTSTATUS
|
||||
CheckForShutdownPrivilege(
|
||||
IN DWORD RequestingProcessId)
|
||||
{
|
||||
HANDLE Process;
|
||||
HANDLE Token;
|
||||
BOOL CheckResult;
|
||||
PPRIVILEGE_SET PrivSet;
|
||||
|
||||
TRACE("CheckForShutdownPrivilege()\n");
|
||||
|
||||
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, RequestingProcessId);
|
||||
if (!Process)
|
||||
{
|
||||
WARN("OpenProcess() failed with error %lu\n", GetLastError());
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
if (!OpenProcessToken(Process, TOKEN_QUERY, &Token))
|
||||
{
|
||||
WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
|
||||
CloseHandle(Process);
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
CloseHandle(Process);
|
||||
PrivSet = HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES));
|
||||
if (!PrivSet)
|
||||
{
|
||||
ERR("Failed to allocate mem for privilege set\n");
|
||||
CloseHandle(Token);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
PrivSet->PrivilegeCount = 1;
|
||||
PrivSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
|
||||
if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &PrivSet->Privilege[0].Luid))
|
||||
{
|
||||
WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
|
||||
HeapFree(GetProcessHeap(), 0, PrivSet);
|
||||
CloseHandle(Token);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (!PrivilegeCheck(Token, PrivSet, &CheckResult))
|
||||
{
|
||||
WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
|
||||
HeapFree(GetProcessHeap(), 0, PrivSet);
|
||||
CloseHandle(Token);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, PrivSet);
|
||||
CloseHandle(Token);
|
||||
|
||||
if (!CheckResult)
|
||||
{
|
||||
WARN("SE_SHUTDOWN privilege not enabled\n");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
HandleMessageBeep(UINT uType)
|
||||
|
@ -1337,13 +1276,40 @@ SASWindowProc(
|
|||
UINT Action = Flags & EWX_ACTION_MASK;
|
||||
DWORD wlxAction;
|
||||
|
||||
TRACE("\tFlags : 0x%lx\n", lParam);
|
||||
|
||||
/*
|
||||
* Our caller (USERSRV) should have added the shutdown flag
|
||||
* when setting also poweroff or reboot.
|
||||
*/
|
||||
if (Action & (EWX_POWEROFF | EWX_REBOOT))
|
||||
{
|
||||
if ((Action & EWX_SHUTDOWN) == 0)
|
||||
{
|
||||
ERR("Missing EWX_SHUTDOWN flag for poweroff or reboot; action 0x%x\n", Action);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Now we can locally remove it for performing checks */
|
||||
Action &= ~EWX_SHUTDOWN;
|
||||
}
|
||||
|
||||
/* Check parameters */
|
||||
switch (Action)
|
||||
{
|
||||
case EWX_LOGOFF: wlxAction = WLX_SAS_ACTION_LOGOFF; break;
|
||||
case EWX_SHUTDOWN: wlxAction = WLX_SAS_ACTION_SHUTDOWN; break;
|
||||
case EWX_REBOOT: wlxAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT; break;
|
||||
case EWX_POWEROFF: wlxAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; break;
|
||||
case EWX_LOGOFF:
|
||||
wlxAction = WLX_SAS_ACTION_LOGOFF;
|
||||
break;
|
||||
case EWX_SHUTDOWN:
|
||||
wlxAction = WLX_SAS_ACTION_SHUTDOWN;
|
||||
break;
|
||||
case EWX_REBOOT:
|
||||
wlxAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
|
||||
break;
|
||||
case EWX_POWEROFF:
|
||||
wlxAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ERR("Invalid ExitWindows action 0x%x\n", Action);
|
||||
|
@ -1351,15 +1317,7 @@ SASWindowProc(
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// FIXME: This check must be done by Win32k, not by us!
|
||||
if (WLX_SHUTTINGDOWN(wlxAction))
|
||||
{
|
||||
NTSTATUS Status = CheckForShutdownPrivilege(wParam);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
}
|
||||
#endif
|
||||
/* Now do the shutdown action proper */
|
||||
DoGenericAction(Session, wlxAction);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -3439,9 +3439,8 @@ NtUserYieldTask(VOID);
|
|||
#define ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING 0xfffe000d
|
||||
#define ONEPARAM_ROUTINE_GETDESKTOPMAPPING 0xfffe000e
|
||||
#define TWOPARAM_ROUTINE_SETMENUBARHEIGHT 0xfffd0050
|
||||
#define TWOPARAM_ROUTINE_EXITREACTOS 0xfffd0051
|
||||
#define TWOPARAM_ROUTINE_SETGUITHRDHANDLE 0xfffd0052
|
||||
#define HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE 0xfffd0053
|
||||
#define TWOPARAM_ROUTINE_SETGUITHRDHANDLE 0xfffd0051
|
||||
#define HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE 0xfffd0052
|
||||
#define MSQ_STATE_CAPTURE 0x1
|
||||
#define MSQ_STATE_ACTIVE 0x2
|
||||
#define MSQ_STATE_FOCUS 0x3
|
||||
|
|
|
@ -412,7 +412,7 @@ NtUserConsoleControl(
|
|||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
/* Allow only Console Server to perform this operation (via CSRSS) */
|
||||
/* Allow only the Console Server to perform this operation (via CSRSS) */
|
||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
|
@ -770,7 +770,6 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PETHREAD Thread;
|
||||
HANDLE CsrPortHandle;
|
||||
|
||||
/* Allow only CSRSS to perform this operation */
|
||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||
|
@ -792,24 +791,24 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
case UserThreadInitiateShutdown:
|
||||
{
|
||||
ERR("Shutdown initiated\n");
|
||||
STUB;
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
if (ThreadInformationLength != sizeof(ULONG))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
Status = UserInitiateShutdown(Thread, (PULONG)ThreadInformation);
|
||||
break;
|
||||
}
|
||||
|
||||
case UserThreadEndShutdown:
|
||||
{
|
||||
NTSTATUS ShutdownStatus;
|
||||
|
||||
ERR("Shutdown ended\n");
|
||||
STUB;
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
case UserThreadCsrApiPort:
|
||||
{
|
||||
ERR("Set CSR API Port for Win32k\n");
|
||||
|
||||
if (ThreadInformationLength != sizeof(HANDLE))
|
||||
if (ThreadInformationLength != sizeof(ShutdownStatus))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
|
@ -818,7 +817,37 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
Status = STATUS_SUCCESS;
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ThreadInformation, sizeof(HANDLE), sizeof(PVOID));
|
||||
ProbeForRead(ThreadInformation, sizeof(ShutdownStatus), sizeof(PVOID));
|
||||
ShutdownStatus = *(NTSTATUS*)ThreadInformation;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = UserEndShutdown(Thread, ShutdownStatus);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case UserThreadCsrApiPort:
|
||||
{
|
||||
HANDLE CsrPortHandle;
|
||||
|
||||
ERR("Set CSR API Port for Win32k\n");
|
||||
|
||||
if (ThreadInformationLength != sizeof(CsrPortHandle))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ThreadInformation, sizeof(CsrPortHandle), sizeof(PVOID));
|
||||
CsrPortHandle = *(PHANDLE)ThreadInformation;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
|
@ -828,9 +857,8 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
_SEH2_END;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = InitCsrApiPort(CsrPortHandle);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <win32k.h>
|
||||
// DBG_DEFAULT_CHANNEL(UserShutdown);
|
||||
DBG_DEFAULT_CHANNEL(UserShutdown);
|
||||
|
||||
/*
|
||||
* Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
|
||||
|
@ -85,4 +85,172 @@ IntClientShutdown(IN PWND pWindow,
|
|||
return lResult;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
GetProcessLuid(IN PETHREAD Thread OPTIONAL,
|
||||
OUT PLUID Luid)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PACCESS_TOKEN Token;
|
||||
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
|
||||
BOOLEAN CopyOnOpen, EffectiveOnly;
|
||||
|
||||
if (Thread == NULL)
|
||||
Thread = PsGetCurrentThread();
|
||||
|
||||
/* Use a thread token */
|
||||
Token = PsReferenceImpersonationToken(Thread,
|
||||
&CopyOnOpen,
|
||||
&EffectiveOnly,
|
||||
&ImpersonationLevel);
|
||||
if (Token == NULL)
|
||||
{
|
||||
/* We don't have a thread token, use a process token */
|
||||
Token = PsReferencePrimaryToken(PsGetThreadProcess(Thread));
|
||||
|
||||
/* If no token, fail */
|
||||
if (Token == NULL)
|
||||
return STATUS_NO_TOKEN;
|
||||
}
|
||||
|
||||
/* Query the LUID */
|
||||
Status = SeQueryAuthenticationIdToken(Token, Luid);
|
||||
|
||||
/* Get rid of the token and return */
|
||||
ObDereferenceObject(Token);
|
||||
return Status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
HasPrivilege(IN PPRIVILEGE_SET Privilege)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
||||
|
||||
/* Capture and lock the security subject context */
|
||||
SeCaptureSubjectContext(&SubjectContext);
|
||||
SeLockSubjectContext(&SubjectContext);
|
||||
|
||||
/* Do privilege check */
|
||||
Result = SePrivilegeCheck(Privilege, &SubjectContext, UserMode);
|
||||
|
||||
/* Audit the privilege */
|
||||
#if 0
|
||||
SePrivilegeObjectAuditAlarm(NULL,
|
||||
&SubjectContext,
|
||||
0,
|
||||
Privilege,
|
||||
Result,
|
||||
UserMode);
|
||||
#endif
|
||||
|
||||
/* Unlock and release the security subject context and return */
|
||||
SeUnlockSubjectContext(&SubjectContext);
|
||||
SeReleaseSubjectContext(&SubjectContext);
|
||||
return Result;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
UserInitiateShutdown(IN PETHREAD Thread,
|
||||
IN OUT PULONG pFlags)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG Flags = *pFlags;
|
||||
LUID CallerLuid;
|
||||
// LUID SystemLuid = SYSTEM_LUID;
|
||||
static PRIVILEGE_SET ShutdownPrivilege =
|
||||
{
|
||||
1, PRIVILEGE_SET_ALL_NECESSARY,
|
||||
{ {{SE_SHUTDOWN_PRIVILEGE, 0}, 0} }
|
||||
};
|
||||
|
||||
PPROCESSINFO ppi;
|
||||
|
||||
ERR("UserInitiateShutdown\n");
|
||||
|
||||
if(hwndSAS == NULL)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
/* Get the caller's LUID */
|
||||
Status = GetProcessLuid(Thread, &CallerLuid);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("GetProcessLuid failed\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// FIXME: Check if this is the System LUID, and adjust flags if needed.
|
||||
// if (RtlEqualLuid(&CallerLuid, &SystemLuid)) { Flags = ...; }
|
||||
*pFlags = Flags;
|
||||
|
||||
/* Retrieve the Win32 process info */
|
||||
ppi = PsGetProcessWin32Process(PsGetThreadProcess(Thread));
|
||||
if (ppi == NULL)
|
||||
return STATUS_INVALID_HANDLE;
|
||||
|
||||
/* If the caller is not Winlogon, do some security checks */
|
||||
if (PsGetThreadProcessId(Thread) != gpidLogon)
|
||||
{
|
||||
// FIXME: Play again with flags...
|
||||
*pFlags = Flags;
|
||||
|
||||
/* Check whether the current process is attached to a window station */
|
||||
if (ppi->prpwinsta == NULL)
|
||||
return STATUS_INVALID_HANDLE;
|
||||
|
||||
/* Check whether the window station of the current process can send exit requests */
|
||||
if (!RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_EXITWINDOWS))
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
/*
|
||||
* NOTE: USERSRV automatically adds the shutdown flag when we poweroff or reboot.
|
||||
*
|
||||
* If the caller wants to shutdown / reboot / power-off...
|
||||
*/
|
||||
if (Flags & EWX_SHUTDOWN)
|
||||
{
|
||||
/* ... check whether it has shutdown privilege */
|
||||
if (!HasPrivilege(&ShutdownPrivilege))
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* ... but if it just wants to log-off, in case its
|
||||
* window station is a non-IO one, fail the call.
|
||||
*/
|
||||
if (ppi->prpwinsta->Flags & WSS_NOIO)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the caller is not Winlogon, notify it to perform the real shutdown */
|
||||
if (PsGetThreadProcessId(Thread) != gpidLogon)
|
||||
{
|
||||
// FIXME: HACK!! Do more checks!!
|
||||
UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOGOFF, (LPARAM)Flags);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
// If we reach this point, that means it's Winlogon that triggered the shutdown.
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* Update and save the shutdown flags globally for renotifying Winlogon
|
||||
* if needed, when calling EndShutdown.
|
||||
*/
|
||||
*pFlags = Flags;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
UserEndShutdown(IN PETHREAD Thread,
|
||||
IN NTSTATUS ShutdownStatus)
|
||||
{
|
||||
ERR("UserEndShutdown\n");
|
||||
STUB;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -4,3 +4,11 @@ LRESULT
|
|||
IntClientShutdown(IN PWND pWindow,
|
||||
IN WPARAM wParam,
|
||||
IN LPARAM lParam);
|
||||
|
||||
NTSTATUS
|
||||
UserInitiateShutdown(IN PETHREAD Thread,
|
||||
IN OUT PULONG pFlags);
|
||||
|
||||
NTSTATUS
|
||||
UserEndShutdown(IN PETHREAD Thread,
|
||||
IN NTSTATUS ShutdownStatus);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include <win32k.h>
|
||||
|
||||
#include <winlogon.h>
|
||||
|
||||
DBG_DEFAULT_CHANNEL(UserMisc);
|
||||
|
||||
/* Registered logon process ID */
|
||||
|
@ -449,18 +447,6 @@ NtUserCallTwoParam(
|
|||
|
||||
case TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK:
|
||||
RETURN( IntUnhookWindowsHook((int)Param1, (HOOKPROC)Param2));
|
||||
|
||||
case TWOPARAM_ROUTINE_EXITREACTOS:
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Param1 /* ProcessId */);
|
||||
|
||||
if(hwndSAS == NULL)
|
||||
{
|
||||
ASSERT(hwndSAS);
|
||||
RETURN(STATUS_NOT_FOUND);
|
||||
}
|
||||
RETURN(co_IntSendMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOGOFF, Param2 /* Flags */));
|
||||
}
|
||||
}
|
||||
ERR("Calling invalid routine number 0x%x in NtUserCallTwoParam(), Param1=0x%x Parm2=0x%x\n",
|
||||
Routine, Param1, Param2);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <wine/debug.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(user32);
|
||||
|
||||
/*
|
||||
* Sequence of events:
|
||||
*
|
||||
|
@ -61,6 +63,130 @@
|
|||
* the kernel and executive shutdown by calling NtShutdownSystem.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT uFlags;
|
||||
DWORD dwReserved;
|
||||
} EXIT_REACTOS_DATA, *PEXIT_REACTOS_DATA;
|
||||
|
||||
static BOOL
|
||||
ExitWindowsWorker(UINT uFlags,
|
||||
DWORD dwReserved,
|
||||
BOOL bCalledFromThread);
|
||||
|
||||
static DWORD
|
||||
WINAPI
|
||||
ExitWindowsThread(LPVOID Param)
|
||||
{
|
||||
DWORD dwExitCode;
|
||||
PEXIT_REACTOS_DATA ExitData = (PEXIT_REACTOS_DATA)Param;
|
||||
|
||||
/* Do the exit asynchronously */
|
||||
if (ExitWindowsWorker(ExitData->uFlags, ExitData->dwReserved, TRUE))
|
||||
dwExitCode = ERROR_SUCCESS;
|
||||
else
|
||||
dwExitCode = GetLastError();
|
||||
|
||||
ExitThread(dwExitCode);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ExitWindowsWorker(UINT uFlags,
|
||||
DWORD dwReserved,
|
||||
BOOL bCalledFromThread)
|
||||
{
|
||||
EXIT_REACTOS_DATA ExitData;
|
||||
HANDLE hExitThread;
|
||||
DWORD ExitCode;
|
||||
MSG msg;
|
||||
|
||||
USER_API_MESSAGE ApiMessage;
|
||||
PUSER_EXIT_REACTOS ExitReactosRequest = &ApiMessage.Data.ExitReactosRequest;
|
||||
|
||||
/*
|
||||
* 1- FIXME: Call NtUserCallOneParam(uFlags, ONEPARAM_ROUTINE_PREPAREFORLOGOFF);
|
||||
* If success we can continue, otherwise we must fail.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2- Send the Exit request to CSRSS (and to Win32k indirectly).
|
||||
* We can shutdown synchronously or asynchronously.
|
||||
*/
|
||||
|
||||
// ExitReactosRequest->LastError = ERROR_SUCCESS;
|
||||
ExitReactosRequest->Flags = uFlags;
|
||||
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpExitWindowsEx),
|
||||
sizeof(*ExitReactosRequest));
|
||||
|
||||
/* Set the last error accordingly */
|
||||
if (NT_SUCCESS(ApiMessage.Status) || ApiMessage.Status == STATUS_CANT_WAIT)
|
||||
{
|
||||
if (ExitReactosRequest->LastError != ERROR_SUCCESS)
|
||||
UserSetLastError(ExitReactosRequest->LastError);
|
||||
}
|
||||
else
|
||||
{
|
||||
UserSetLastNTError(ApiMessage.Status);
|
||||
ExitReactosRequest->Success = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case CSR call succeeded and we did a synchronous exit
|
||||
* (STATUS_CANT_WAIT is considered as a non-success status),
|
||||
* return the real state of the operation now.
|
||||
*/
|
||||
if (NT_SUCCESS(ApiMessage.Status))
|
||||
return ExitReactosRequest->Success;
|
||||
|
||||
/*
|
||||
* In case something failed: we have a non-success status and:
|
||||
* - either we were doing a synchronous exit (Status != STATUS_CANT_WAIT), or
|
||||
* - we were doing an asynchronous exit because we were called recursively via
|
||||
* another thread but we failed to exit,
|
||||
* then bail out immediately, otherwise we would enter an infinite loop of exit requests.
|
||||
*
|
||||
* On the contrary if we need to do an asynchronous exit (Status == STATUS_CANT_WAIT
|
||||
* and not called recursively via another thread), then continue and do the exit.
|
||||
*/
|
||||
if (ApiMessage.Status != STATUS_CANT_WAIT || bCalledFromThread)
|
||||
{
|
||||
UserSetLastNTError(ApiMessage.Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3- Win32k wants us to perform an asynchronous exit. Run the request in a thread.
|
||||
* (ApiMessage.Status == STATUS_CANT_WAIT and not already called from a thread)
|
||||
*/
|
||||
ExitData.uFlags = uFlags;
|
||||
ExitData.dwReserved = dwReserved;
|
||||
hExitThread = CreateThread(NULL, 0, ExitWindowsThread, &ExitData, 0, NULL);
|
||||
if (hExitThread == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Pump and discard any input events sent to the app(s) */
|
||||
while (MsgWaitForMultipleObjectsEx(1, &hExitThread, INFINITE, QS_ALLINPUT, 0))
|
||||
{
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
/* Finally, return to caller */
|
||||
if (!GetExitCodeThread(hExitThread, &ExitCode))
|
||||
ExitCode = GetLastError();
|
||||
|
||||
CloseHandle(hExitThread);
|
||||
|
||||
if (ExitCode != ERROR_SUCCESS)
|
||||
UserSetLastError(ExitCode);
|
||||
|
||||
return (ExitCode == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
@ -68,23 +194,17 @@ BOOL WINAPI
|
|||
ExitWindowsEx(UINT uFlags,
|
||||
DWORD dwReserved)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
USER_API_MESSAGE ApiMessage;
|
||||
/*
|
||||
* FIXME:
|
||||
* 1- Calling the Exit worker must be done under certain conditions.
|
||||
* We may also need to warn the user if there are other people logged
|
||||
* on this computer (see http://pve.proxmox.com/wiki/Windows_2003_guest_best_practices )
|
||||
* 2- Call SrvRecordShutdownReason.
|
||||
*/
|
||||
|
||||
ApiMessage.Data.ExitReactosRequest.Flags = uFlags;
|
||||
// ApiMessage.Data.ExitReactosRequest.Reserved = dwReserved;
|
||||
return ExitWindowsWorker(uFlags, dwReserved, FALSE);
|
||||
|
||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpExitWindowsEx),
|
||||
sizeof(USER_EXIT_REACTOS));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
UserSetLastNTError(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
/* FIXME: Call SrvRecordShutdownReason if we failed */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -778,6 +778,7 @@ InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
|
|||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
// FIXME: HAAAAACK!!
|
||||
DPRINT1("FIXME: Need to close all user processes!\n");
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
|
@ -896,12 +897,34 @@ InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
|
|||
}
|
||||
|
||||
static NTSTATUS FASTCALL
|
||||
UserExitReactos(DWORD UserProcessId, UINT Flags)
|
||||
UserExitReactos(PCSR_THREAD CsrThread, UINT Flags)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
LUID CallerLuid;
|
||||
|
||||
/* FIXME Inside 2000 says we should impersonate the caller here */
|
||||
Status = NtUserCallTwoParam(UserProcessId, Flags, TWOPARAM_ROUTINE_EXITREACTOS);
|
||||
// FIXME: HACK!!
|
||||
|
||||
/*
|
||||
* Retrieve the caller's LUID so that we can only shutdown
|
||||
* processes in the caller's LUID.
|
||||
*/
|
||||
if (!CsrImpersonateClient(NULL))
|
||||
return STATUS_BAD_IMPERSONATION_LEVEL;
|
||||
|
||||
Status = CsrGetProcessLuid(NULL, &CallerLuid);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status);
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
DPRINT1("Caller LUID is: %lx.%lx\n", CallerLuid.HighPart, CallerLuid.LowPart);
|
||||
|
||||
/* Notify Win32k and potentially Winlogon of the shutdown */
|
||||
Status = NtUserSetInformationThread(CsrThread->ThreadHandle,
|
||||
UserThreadInitiateShutdown,
|
||||
&Flags, sizeof(Flags));
|
||||
DPRINT1("Win32k says: %lx\n", Status);
|
||||
|
||||
/* If the message isn't handled, the return value is 0, so 0 doesn't indicate
|
||||
success. Success is indicated by a 1 return value, if anything besides 0
|
||||
|
@ -915,6 +938,10 @@ UserExitReactos(DWORD UserProcessId, UINT Flags)
|
|||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DPRINT1("SrvExitWindowsEx returned 0x%08x\n", Status);
|
||||
|
||||
Quit:
|
||||
CsrRevertToSelf();
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -938,19 +965,42 @@ UserClientShutdown(IN PCSR_PROCESS CsrProcess,
|
|||
|
||||
CSR_API(SrvExitWindowsEx)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PUSER_EXIT_REACTOS ExitReactosRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.ExitReactosRequest;
|
||||
PCSR_THREAD CsrThread = CsrGetClientThread();
|
||||
ULONG Flags = ExitReactosRequest->Flags;
|
||||
|
||||
if (0 == (ExitReactosRequest->Flags & EWX_INTERNAL_FLAG))
|
||||
/*
|
||||
* Check for flags validity
|
||||
*/
|
||||
|
||||
DWORD ProcessId = HandleToUlong(CsrThread->ClientId.UniqueProcess);
|
||||
DWORD ThreadId = HandleToUlong(CsrThread->ClientId.UniqueThread);
|
||||
|
||||
DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
|
||||
ProcessId, ThreadId, Flags);
|
||||
|
||||
/* Implicitely add the shutdown flag when we poweroff or reboot */
|
||||
if (Flags & (EWX_POWEROFF | EWX_REBOOT))
|
||||
Flags |= EWX_SHUTDOWN;
|
||||
|
||||
|
||||
// FIXME: Everything else starting after this line is a HAAACK!!
|
||||
|
||||
|
||||
if (0 == (Flags & EWX_INTERNAL_FLAG))
|
||||
{
|
||||
return UserExitReactos((DWORD_PTR) ApiMessage->Header.ClientId.UniqueProcess,
|
||||
ExitReactosRequest->Flags);
|
||||
Status = UserExitReactos(CsrThread, Flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InternalExitReactos((DWORD_PTR) ApiMessage->Header.ClientId.UniqueProcess,
|
||||
(DWORD_PTR) ApiMessage->Header.ClientId.UniqueThread,
|
||||
ExitReactosRequest->Flags);
|
||||
// EWX_INTERNAL_FLAG --> For Winlogon only!!
|
||||
// FIXME: This is just a big HAAAACK!!
|
||||
Status = InternalExitReactos(ProcessId, ThreadId, Flags);
|
||||
}
|
||||
|
||||
ExitReactosRequest->Success = NT_SUCCESS(Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
CSR_API(SrvEndTask)
|
||||
|
|
Loading…
Reference in a new issue