[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:
Hermès Bélusca-Maïto 2015-02-07 15:26:42 +00:00
parent 8e988cc2f3
commit b8d8fbdc9d
8 changed files with 449 additions and 132 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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);

View file

@ -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);

View file

@ -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 */
}
/*

View file

@ -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)