mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 22:33:00 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
370
win32ss/user/ntuser/shutdown.c
Normal file
370
win32ss/user/ntuser/shutdown.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Win32k subsystem
|
||||
* PURPOSE: Shutdown routines
|
||||
* FILE: win32ss/user/ntuser/shutdown.c
|
||||
* PROGRAMER: Hermes Belusca
|
||||
*/
|
||||
|
||||
#include <win32k.h>
|
||||
|
||||
DBG_DEFAULT_CHANNEL(UserShutdown);
|
||||
|
||||
/* Our local copy of shutdown flags */
|
||||
static ULONG gdwShutdownFlags = 0;
|
||||
|
||||
/*
|
||||
* Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
|
||||
* CSRSS sends WM_CLIENTSHUTDOWN messages to top-level windows, and it is our job
|
||||
* to send WM_QUERYENDSESSION / WM_ENDSESSION messages in response.
|
||||
*/
|
||||
LRESULT
|
||||
IntClientShutdown(IN PWND pWindow,
|
||||
IN WPARAM wParam,
|
||||
IN LPARAM lParam)
|
||||
{
|
||||
LPARAM lParams;
|
||||
BOOL KillTimers;
|
||||
INT i;
|
||||
LRESULT lResult = MCSR_GOODFORSHUTDOWN;
|
||||
HWND *List;
|
||||
|
||||
KillTimers = wParam & MCS_ENDSESSION ? TRUE : FALSE;
|
||||
lParams = lParam & (ENDSESSION_LOGOFF | ENDSESSION_CRITICAL | ENDSESSION_CLOSEAPP);
|
||||
|
||||
/* First, send end sessions to children */
|
||||
List = IntWinListChildren(pWindow);
|
||||
|
||||
if (List)
|
||||
{
|
||||
for (i = 0; List[i]; i++)
|
||||
{
|
||||
PWND WndChild;
|
||||
|
||||
if (!(WndChild = UserGetWindowObject(List[i])))
|
||||
continue;
|
||||
|
||||
if (wParam & MCS_QUERYENDSESSION)
|
||||
{
|
||||
if (!co_IntSendMessage(WndChild->head.h, WM_QUERYENDSESSION, 0, lParams))
|
||||
{
|
||||
lResult = MCSR_DONOTSHUTDOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
co_IntSendMessage(WndChild->head.h, WM_ENDSESSION, KillTimers, lParams);
|
||||
if (KillTimers)
|
||||
{
|
||||
DestroyTimersForWindow(WndChild->head.pti, WndChild);
|
||||
}
|
||||
lResult = MCSR_SHUTDOWNFINISHED;
|
||||
}
|
||||
}
|
||||
ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
|
||||
if (lResult == MCSR_DONOTSHUTDOWN)
|
||||
return lResult;
|
||||
}
|
||||
|
||||
/* Send to the caller */
|
||||
if (wParam & MCS_QUERYENDSESSION)
|
||||
{
|
||||
if (!co_IntSendMessage(pWindow->head.h, WM_QUERYENDSESSION, 0, lParams))
|
||||
{
|
||||
lResult = MCSR_DONOTSHUTDOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
co_IntSendMessage(pWindow->head.h, WM_ENDSESSION, KillTimers, lParams);
|
||||
if (KillTimers)
|
||||
{
|
||||
DestroyTimersForWindow(pWindow->head.pti, pWindow);
|
||||
}
|
||||
lResult = MCSR_SHUTDOWNFINISHED;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BOOL
|
||||
NotifyLogon(IN HWND hWndSta,
|
||||
IN PLUID CallerLuid,
|
||||
IN ULONG Flags,
|
||||
IN NTSTATUS ShutdownStatus)
|
||||
{
|
||||
// LUID SystemLuid = SYSTEM_LUID;
|
||||
ULONG Notif, Param;
|
||||
|
||||
ERR("NotifyLogon(0x%lx, 0x%lx)\n", Flags, ShutdownStatus);
|
||||
|
||||
/* If no Winlogon notifications are needed, just return */
|
||||
if (Flags & EWX_NONOTIFY)
|
||||
return FALSE;
|
||||
|
||||
/* In case we cancelled the shutdown...*/
|
||||
if (Flags & EWX_SHUTDOWN_CANCELED)
|
||||
{
|
||||
/* ... send a LN_LOGOFF_CANCELED to Winlogon with the real cancel status... */
|
||||
Notif = LN_LOGOFF_CANCELED;
|
||||
Param = ShutdownStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ... otherwise it's a real logoff. Send the shutdown flags in that case. */
|
||||
Notif = LN_LOGOFF;
|
||||
Param = Flags;
|
||||
}
|
||||
|
||||
// FIXME: At the moment, always send the notifications... In real world some checks are done.
|
||||
// if (hwndSAS && ( (Flags & EWX_SHUTDOWN) || RtlEqualLuid(CallerLuid, &SystemLuid)) )
|
||||
if (hwndSAS)
|
||||
{
|
||||
TRACE("\tSending %s message to Winlogon\n", Notif == LN_LOGOFF ? "LN_LOGOFF" : "LN_LOGOFF_CANCELED");
|
||||
UserPostMessage(hwndSAS, WM_LOGONNOTIFY, Notif, (LPARAM)Param);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("hwndSAS == NULL\n");
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
TRACE("UserInitiateShutdown\n");
|
||||
|
||||
/* Get the caller's LUID */
|
||||
Status = GetProcessLuid(Thread, &CallerLuid);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("UserInitiateShutdown: GetProcessLuid failed\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this is the System LUID, and adjust flags if needed.
|
||||
* In particular, be sure there is no EWX_CALLER_SYSTEM flag
|
||||
* spuriously set (could be the sign of malicous app!).
|
||||
*/
|
||||
if (RtlEqualLuid(&CallerLuid, &SystemLuid))
|
||||
Flags |= EWX_CALLER_SYSTEM;
|
||||
else
|
||||
Flags &= ~EWX_CALLER_SYSTEM;
|
||||
|
||||
*pFlags = Flags;
|
||||
|
||||
/* Retrieve the Win32 process info */
|
||||
ppi = PsGetProcessWin32Process(PsGetThreadProcess(Thread));
|
||||
if (ppi == NULL)
|
||||
{
|
||||
ERR("UserInitiateShutdown: Failed to get win32 thread!\n");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* If the caller is not Winlogon, do some security checks */
|
||||
if (PsGetThreadProcessId(Thread) != gpidLogon)
|
||||
{
|
||||
/*
|
||||
* Here also, be sure there is no EWX_CALLER_WINLOGON flag
|
||||
* spuriously set (could be the sign of malicous app!).
|
||||
*/
|
||||
Flags &= ~EWX_CALLER_WINLOGON;
|
||||
|
||||
*pFlags = Flags;
|
||||
|
||||
/* Check whether the current process is attached to a window station */
|
||||
if (ppi->prpwinsta == NULL)
|
||||
{
|
||||
ERR("UserInitiateShutdown: Process is not attached to a desktop\n");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Check whether the window station of the current process can send exit requests */
|
||||
if (!RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_EXITWINDOWS))
|
||||
{
|
||||
ERR("UserInitiateShutdown: Caller doesn't have the rights to shutdown\n");
|
||||
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))
|
||||
{
|
||||
ERR("UserInitiateShutdown: Caller doesn't have the rights to shutdown\n");
|
||||
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)
|
||||
{
|
||||
ERR("UserInitiateShutdown: Caller doesn't have the rights to logoff\n");
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the caller is not Winlogon, possibly notify it to perform the real shutdown */
|
||||
if (PsGetThreadProcessId(Thread) != gpidLogon)
|
||||
{
|
||||
// FIXME: HACK!! Do more checks!!
|
||||
TRACE("UserInitiateShutdown: Notify Winlogon for shutdown\n");
|
||||
NotifyLogon(hwndSAS, &CallerLuid, Flags, STATUS_SUCCESS);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
// If we reach this point, that means it's Winlogon that triggered the shutdown.
|
||||
TRACE("UserInitiateShutdown: Winlogon is doing a shutdown\n");
|
||||
|
||||
/*
|
||||
* Update and save the shutdown flags globally for renotifying
|
||||
* Winlogon if needed, when calling EndShutdown.
|
||||
*/
|
||||
Flags |= EWX_CALLER_WINLOGON; // Winlogon is doing a shutdown, be sure the internal flag is set.
|
||||
*pFlags = Flags;
|
||||
|
||||
/* Save the shutdown flags now */
|
||||
gdwShutdownFlags = Flags;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
UserEndShutdown(IN PETHREAD Thread,
|
||||
IN NTSTATUS ShutdownStatus)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG Flags;
|
||||
LUID CallerLuid;
|
||||
|
||||
TRACE("UserEndShutdown called\n");
|
||||
|
||||
/*
|
||||
* FIXME: Some cleanup should be done when shutdown succeeds,
|
||||
* and some reset should be done when shutdown is cancelled.
|
||||
*/
|
||||
//STUB;
|
||||
|
||||
Status = GetProcessLuid(Thread, &CallerLuid);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("GetProcessLuid failed\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy the global flags because we're going to modify them for our purposes */
|
||||
Flags = gdwShutdownFlags;
|
||||
|
||||
if (NT_SUCCESS(ShutdownStatus))
|
||||
{
|
||||
/* Just report success, and keep the shutdown flags as they are */
|
||||
ShutdownStatus = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Report the status to Winlogon and say that we cancel the shutdown */
|
||||
Flags |= EWX_SHUTDOWN_CANCELED;
|
||||
// FIXME: Should we reset gdwShutdownFlags to 0 ??
|
||||
}
|
||||
|
||||
TRACE("UserEndShutdown: Notify Winlogon for end of shutdown\n");
|
||||
NotifyLogon(hwndSAS, &CallerLuid, Flags, ShutdownStatus);
|
||||
|
||||
/* Always return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue