mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +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;
|
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
|
BOOL
|
||||||
WINAPI
|
WINAPI
|
||||||
HandleMessageBeep(UINT uType)
|
HandleMessageBeep(UINT uType)
|
||||||
|
@ -1337,13 +1276,40 @@ SASWindowProc(
|
||||||
UINT Action = Flags & EWX_ACTION_MASK;
|
UINT Action = Flags & EWX_ACTION_MASK;
|
||||||
DWORD wlxAction;
|
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 */
|
/* Check parameters */
|
||||||
switch (Action)
|
switch (Action)
|
||||||
{
|
{
|
||||||
case EWX_LOGOFF: wlxAction = WLX_SAS_ACTION_LOGOFF; break;
|
case EWX_LOGOFF:
|
||||||
case EWX_SHUTDOWN: wlxAction = WLX_SAS_ACTION_SHUTDOWN; break;
|
wlxAction = WLX_SAS_ACTION_LOGOFF;
|
||||||
case EWX_REBOOT: wlxAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT; break;
|
break;
|
||||||
case EWX_POWEROFF: wlxAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 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:
|
default:
|
||||||
{
|
{
|
||||||
ERR("Invalid ExitWindows action 0x%x\n", Action);
|
ERR("Invalid ExitWindows action 0x%x\n", Action);
|
||||||
|
@ -1351,15 +1317,7 @@ SASWindowProc(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
/* Now do the shutdown action proper */
|
||||||
// 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
|
|
||||||
DoGenericAction(Session, wlxAction);
|
DoGenericAction(Session, wlxAction);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3439,9 +3439,8 @@ NtUserYieldTask(VOID);
|
||||||
#define ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING 0xfffe000d
|
#define ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING 0xfffe000d
|
||||||
#define ONEPARAM_ROUTINE_GETDESKTOPMAPPING 0xfffe000e
|
#define ONEPARAM_ROUTINE_GETDESKTOPMAPPING 0xfffe000e
|
||||||
#define TWOPARAM_ROUTINE_SETMENUBARHEIGHT 0xfffd0050
|
#define TWOPARAM_ROUTINE_SETMENUBARHEIGHT 0xfffd0050
|
||||||
#define TWOPARAM_ROUTINE_EXITREACTOS 0xfffd0051
|
#define TWOPARAM_ROUTINE_SETGUITHRDHANDLE 0xfffd0051
|
||||||
#define TWOPARAM_ROUTINE_SETGUITHRDHANDLE 0xfffd0052
|
#define HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE 0xfffd0052
|
||||||
#define HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE 0xfffd0053
|
|
||||||
#define MSQ_STATE_CAPTURE 0x1
|
#define MSQ_STATE_CAPTURE 0x1
|
||||||
#define MSQ_STATE_ACTIVE 0x2
|
#define MSQ_STATE_ACTIVE 0x2
|
||||||
#define MSQ_STATE_FOCUS 0x3
|
#define MSQ_STATE_FOCUS 0x3
|
||||||
|
|
|
@ -412,7 +412,7 @@ NtUserConsoleControl(
|
||||||
{
|
{
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
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)
|
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||||
return STATUS_ACCESS_DENIED;
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
@ -770,7 +770,6 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
||||||
{
|
{
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
PETHREAD Thread;
|
PETHREAD Thread;
|
||||||
HANDLE CsrPortHandle;
|
|
||||||
|
|
||||||
/* Allow only CSRSS to perform this operation */
|
/* Allow only CSRSS to perform this operation */
|
||||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||||
|
@ -792,24 +791,24 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
||||||
case UserThreadInitiateShutdown:
|
case UserThreadInitiateShutdown:
|
||||||
{
|
{
|
||||||
ERR("Shutdown initiated\n");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UserThreadEndShutdown:
|
case UserThreadEndShutdown:
|
||||||
{
|
{
|
||||||
|
NTSTATUS ShutdownStatus;
|
||||||
|
|
||||||
ERR("Shutdown ended\n");
|
ERR("Shutdown ended\n");
|
||||||
STUB;
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case UserThreadCsrApiPort:
|
if (ThreadInformationLength != sizeof(ShutdownStatus))
|
||||||
{
|
|
||||||
ERR("Set CSR API Port for Win32k\n");
|
|
||||||
|
|
||||||
if (ThreadInformationLength != sizeof(HANDLE))
|
|
||||||
{
|
{
|
||||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||||
break;
|
break;
|
||||||
|
@ -818,7 +817,37 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
_SEH2_TRY
|
_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;
|
CsrPortHandle = *(PHANDLE)ThreadInformation;
|
||||||
}
|
}
|
||||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
@ -828,9 +857,8 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
||||||
_SEH2_END;
|
_SEH2_END;
|
||||||
|
|
||||||
if (NT_SUCCESS(Status))
|
if (NT_SUCCESS(Status))
|
||||||
{
|
|
||||||
Status = InitCsrApiPort(CsrPortHandle);
|
Status = InitCsrApiPort(CsrPortHandle);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <win32k.h>
|
#include <win32k.h>
|
||||||
// DBG_DEFAULT_CHANNEL(UserShutdown);
|
DBG_DEFAULT_CHANNEL(UserShutdown);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
|
* Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
|
||||||
|
@ -85,4 +85,172 @@ IntClientShutdown(IN PWND pWindow,
|
||||||
return lResult;
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -4,3 +4,11 @@ LRESULT
|
||||||
IntClientShutdown(IN PWND pWindow,
|
IntClientShutdown(IN PWND pWindow,
|
||||||
IN WPARAM wParam,
|
IN WPARAM wParam,
|
||||||
IN LPARAM lParam);
|
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 <win32k.h>
|
||||||
|
|
||||||
#include <winlogon.h>
|
|
||||||
|
|
||||||
DBG_DEFAULT_CHANNEL(UserMisc);
|
DBG_DEFAULT_CHANNEL(UserMisc);
|
||||||
|
|
||||||
/* Registered logon process ID */
|
/* Registered logon process ID */
|
||||||
|
@ -449,18 +447,6 @@ NtUserCallTwoParam(
|
||||||
|
|
||||||
case TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK:
|
case TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK:
|
||||||
RETURN( IntUnhookWindowsHook((int)Param1, (HOOKPROC)Param2));
|
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",
|
ERR("Calling invalid routine number 0x%x in NtUserCallTwoParam(), Param1=0x%x Parm2=0x%x\n",
|
||||||
Routine, Param1, Param2);
|
Routine, Param1, Param2);
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <wine/debug.h>
|
#include <wine/debug.h>
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(user32);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sequence of events:
|
* Sequence of events:
|
||||||
*
|
*
|
||||||
|
@ -61,6 +63,130 @@
|
||||||
* the kernel and executive shutdown by calling NtShutdownSystem.
|
* 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
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
@ -68,23 +194,17 @@ BOOL WINAPI
|
||||||
ExitWindowsEx(UINT uFlags,
|
ExitWindowsEx(UINT uFlags,
|
||||||
DWORD dwReserved)
|
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;
|
return ExitWindowsWorker(uFlags, dwReserved, FALSE);
|
||||||
// ApiMessage.Data.ExitReactosRequest.Reserved = dwReserved;
|
|
||||||
|
|
||||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
/* FIXME: Call SrvRecordShutdownReason if we failed */
|
||||||
NULL,
|
|
||||||
CSR_CREATE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpExitWindowsEx),
|
|
||||||
sizeof(USER_EXIT_REACTOS));
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
UserSetLastNTError(Status);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -778,6 +778,7 @@ InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
|
||||||
return STATUS_ACCESS_DENIED;
|
return STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: HAAAAACK!!
|
||||||
DPRINT1("FIXME: Need to close all user processes!\n");
|
DPRINT1("FIXME: Need to close all user processes!\n");
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
@ -896,12 +897,34 @@ InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS FASTCALL
|
static NTSTATUS FASTCALL
|
||||||
UserExitReactos(DWORD UserProcessId, UINT Flags)
|
UserExitReactos(PCSR_THREAD CsrThread, UINT Flags)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
LUID CallerLuid;
|
||||||
|
|
||||||
/* FIXME Inside 2000 says we should impersonate the caller here */
|
// FIXME: HACK!!
|
||||||
Status = NtUserCallTwoParam(UserProcessId, Flags, TWOPARAM_ROUTINE_EXITREACTOS);
|
|
||||||
|
/*
|
||||||
|
* 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
|
/* 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
|
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;
|
Status = STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DPRINT1("SrvExitWindowsEx returned 0x%08x\n", Status);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
CsrRevertToSelf();
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,19 +965,42 @@ UserClientShutdown(IN PCSR_PROCESS CsrProcess,
|
||||||
|
|
||||||
CSR_API(SrvExitWindowsEx)
|
CSR_API(SrvExitWindowsEx)
|
||||||
{
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
PUSER_EXIT_REACTOS ExitReactosRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.ExitReactosRequest;
|
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,
|
Status = UserExitReactos(CsrThread, Flags);
|
||||||
ExitReactosRequest->Flags);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return InternalExitReactos((DWORD_PTR) ApiMessage->Header.ClientId.UniqueProcess,
|
// EWX_INTERNAL_FLAG --> For Winlogon only!!
|
||||||
(DWORD_PTR) ApiMessage->Header.ClientId.UniqueThread,
|
// FIXME: This is just a big HAAAACK!!
|
||||||
ExitReactosRequest->Flags);
|
Status = InternalExitReactos(ProcessId, ThreadId, Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExitReactosRequest->Success = NT_SUCCESS(Status);
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSR_API(SrvEndTask)
|
CSR_API(SrvEndTask)
|
||||||
|
|
Loading…
Reference in a new issue