mirror of
https://github.com/reactos/reactos.git
synced 2024-07-01 18:24:24 +00:00
Send proper messages/events to processes during logoff and kill them if they
dont self-destruct. Work in progress, not complete yet. Committed so others can work on it too. svn path=/trunk/; revision=19815
This commit is contained in:
parent
3fb8c3f6ed
commit
ddfc8192ca
|
@ -10,15 +10,12 @@
|
|||
#ifndef REACTOS_WINLOGON_H_INCLUDED
|
||||
#define REACTOS_WINLOGON_H_INCLUDED
|
||||
|
||||
#define WINLOGON_DESKTOP L"Winlogon"
|
||||
#define WINLOGON_SAS_CLASS L"SAS window class"
|
||||
#define WINLOGON_SAS_TITLE L"SAS"
|
||||
|
||||
#define PM_WINLOGON_EXITWINDOWS WM_APP
|
||||
|
||||
#define EWX_INTERNAL_FLAG 0x10000
|
||||
#define EWX_INTERNAL_FLAG 0x10000
|
||||
#define EWX_INTERNAL_KILL_USER_APPS (EWX_INTERNAL_FLAG | 0x100)
|
||||
#define EWX_INTERNAL_KILL_ALL_APPS (EWX_INTERNAL_FLAG | 0x200)
|
||||
#define EWX_INTERNAL_FLAG_LOGOFF 0x1000
|
||||
|
||||
#endif /* REACTOS_WINLOGON_H_INCLUDED */
|
||||
|
||||
|
|
|
@ -13,11 +13,9 @@
|
|||
* Sequence of events:
|
||||
*
|
||||
* - App (usually explorer) calls ExitWindowsEx()
|
||||
* - ExitWindowsEx() sends a message to CSRSS (note: investigation shows it
|
||||
* doesn't transfer to kernel mode)
|
||||
* - ExitWindowsEx() sends a message to CSRSS
|
||||
* - CSRSS impersonates the caller and sends a message to a hidden WinLogon window
|
||||
* - WinLogon sends a SAS event to the GINA, asking for permission (e.g. if the
|
||||
* required rights are granted) to proceed
|
||||
* - WinLogon checks if the caller has the required privileges
|
||||
* - WinLogon enters pending log-out state
|
||||
* - WinLogon impersonates the interactive user and calls ExitWindowsEx() again,
|
||||
* passing some special internal flags
|
||||
|
@ -28,7 +26,7 @@
|
|||
* CSRSS will put up a dialog box asking if the process should be terminated.
|
||||
* Using the registry key HKCU\Control Panel\Desktop\AutoEndTask you can
|
||||
* specify that the dialog box shouldn't be shown and CSRSS should just
|
||||
* terminates the thread. If the the WM_ENDSESSION message is processed
|
||||
* terminate the thread. If the the WM_ENDSESSION message is processed
|
||||
* but the thread doesn't terminate within the timeout specified by
|
||||
* HKCU\Control Panel\Desktop\WaitToKillAppTimeout CSRSS will terminate
|
||||
* the thread. When all the top-level windows have been destroyed CSRSS
|
||||
|
@ -53,15 +51,13 @@
|
|||
* dialog boxes or kill threads/processes. Same for console processes,
|
||||
* using the CTRL_SHUTDOWN_EVENT. The Service Control Manager is one of
|
||||
* these console processes and has a special timeout value WaitToKillServiceTimeout.
|
||||
* - WinLogon calls ADVAPI32.InitiateSystemShutdown()
|
||||
* - ADVAPI32.InitiateSystemShutdown*() issues a "InitiateSystemShutdown" request
|
||||
* to the SM (SMSS API # 1)
|
||||
* - WinLogon issues a "InitiateSystemShutdown" request to the SM (SMSS API # 1)
|
||||
* - the SM propagates the shutdown request to every environment subsystem it
|
||||
* started since bootstrap time (still active ones, of course)
|
||||
* - each environment subsystem, on shutdown request, releases every resource
|
||||
* it aquired during its life (processes, memory etc), then dies
|
||||
* - when every environment subsystem has gone to bed, the SM actually initiates
|
||||
* to shutdown the kernel and executive by calling NtShutdownSystem.
|
||||
* the kernel and executive shutdown by calling NtShutdownSystem.
|
||||
*/
|
||||
/*
|
||||
* @implemented
|
||||
|
|
|
@ -56,7 +56,7 @@ ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Con
|
|||
}
|
||||
|
||||
VOID FASTCALL
|
||||
ConioConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
|
||||
ConioConsoleCtrlEventTimeout(DWORD Event, PCSRSS_PROCESS_DATA ProcessData, DWORD Timeout)
|
||||
{
|
||||
HANDLE Thread;
|
||||
|
||||
|
@ -73,10 +73,17 @@ ConioConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
|
|||
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
WaitForSingleObject(Thread, Timeout);
|
||||
CloseHandle(Thread);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FASTCALL
|
||||
ConioConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
|
||||
{
|
||||
ConioConsoleCtrlEventTimeout(Event, ProcessData, INFINITE);
|
||||
}
|
||||
|
||||
#define GET_CELL_BUFFER(b,o)\
|
||||
(b)->Buffer[(o)++]
|
||||
|
||||
|
|
|
@ -143,11 +143,18 @@ Win32CsrUnlockObject(Object_t *Object)
|
|||
|
||||
NTSTATUS FASTCALL
|
||||
Win32CsrReleaseObject(PCSRSS_PROCESS_DATA ProcessData,
|
||||
HANDLE Object)
|
||||
HANDLE Object)
|
||||
{
|
||||
return (CsrExports.CsrReleaseObjectProc)(ProcessData, Object);
|
||||
}
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc,
|
||||
PVOID Context)
|
||||
{
|
||||
return (CsrExports.CsrEnumProcessesProc)(EnumProc, Context);
|
||||
}
|
||||
|
||||
static BOOL STDCALL
|
||||
Win32CsrInitComplete(void)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include "w32csr.h"
|
||||
#include <sddl.h>
|
||||
#include "resource.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
@ -52,7 +54,8 @@ CSR_API(CsrSetLogonNotifyWindow)
|
|||
DWORD WindowCreator;
|
||||
|
||||
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
|
||||
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
|
||||
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) -
|
||||
sizeof(PORT_MESSAGE);
|
||||
|
||||
if (0 == GetWindowThreadProcessId(Request->Data.SetLogonNotifyWindowRequest.LogonNotifyWindow,
|
||||
&WindowCreator))
|
||||
|
@ -75,32 +78,871 @@ CSR_API(CsrSetLogonNotifyWindow)
|
|||
return Request->Status;
|
||||
}
|
||||
|
||||
CSR_API(CsrExitReactos)
|
||||
typedef struct tagSHUTDOWN_SETTINGS
|
||||
{
|
||||
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
|
||||
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
|
||||
BOOL AutoEndTasks;
|
||||
DWORD HungAppTimeout;
|
||||
DWORD WaitToKillAppTimeout;
|
||||
} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS;
|
||||
|
||||
#define DEFAULT_AUTO_END_TASKS FALSE
|
||||
#define DEFAULT_HUNG_APP_TIMEOUT 5000
|
||||
#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
|
||||
|
||||
typedef struct tagNOTIFY_CONTEXT
|
||||
{
|
||||
DWORD ProcessId;
|
||||
UINT Msg;
|
||||
WPARAM wParam;
|
||||
LPARAM lParam;
|
||||
HDESK Desktop;
|
||||
DWORD StartTime;
|
||||
DWORD QueryResult;
|
||||
HWND Dlg;
|
||||
DWORD EndNowResult;
|
||||
BOOL ShowUI;
|
||||
HANDLE UIThread;
|
||||
HWND WndClient;
|
||||
PSHUTDOWN_SETTINGS ShutdownSettings;
|
||||
LPTHREAD_START_ROUTINE SendMessageProc;
|
||||
} NOTIFY_CONTEXT, *PNOTIFY_CONTEXT;
|
||||
|
||||
#define QUERY_RESULT_ABORT 0
|
||||
#define QUERY_RESULT_CONTINUE 1
|
||||
#define QUERY_RESULT_TIMEOUT 2
|
||||
#define QUERY_RESULT_ERROR 3
|
||||
#define QUERY_RESULT_FORCE 4
|
||||
|
||||
static void FASTCALL
|
||||
UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext)
|
||||
{
|
||||
DWORD Passed;
|
||||
|
||||
Passed = GetTickCount() - NotifyContext->StartTime;
|
||||
Passed -= NotifyContext->ShutdownSettings->HungAppTimeout;
|
||||
if (NotifyContext->ShutdownSettings->WaitToKillAppTimeout < Passed)
|
||||
{
|
||||
Passed = NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
|
||||
}
|
||||
SendMessageW(ProgressBar, PBM_SETPOS, Passed / 2, 0);
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK
|
||||
EndNowDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
INT_PTR Result;
|
||||
PNOTIFY_CONTEXT NotifyContext;
|
||||
HWND ProgressBar;
|
||||
DWORD TitleLength;
|
||||
int Len;
|
||||
LPWSTR Title;
|
||||
|
||||
switch(Msg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
NotifyContext = (PNOTIFY_CONTEXT) lParam;
|
||||
NotifyContext->EndNowResult = QUERY_RESULT_ABORT;
|
||||
SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR) lParam);
|
||||
TitleLength = SendMessageW(NotifyContext->WndClient, WM_GETTEXTLENGTH,
|
||||
0, 0) +
|
||||
GetWindowTextLengthW(Dlg);
|
||||
Title = HeapAlloc(Win32CsrApiHeap, 0, (TitleLength + 1) * sizeof(WCHAR));
|
||||
if (NULL != Title)
|
||||
{
|
||||
Len = GetWindowTextW(Dlg, Title, TitleLength + 1);
|
||||
SendMessageW(NotifyContext->WndClient, WM_GETTEXT,
|
||||
TitleLength + 1 - Len, (LPARAM) (Title + Len));
|
||||
SetWindowTextW(Dlg, Title);
|
||||
HeapFree(Win32CsrApiHeap, 0, Title);
|
||||
}
|
||||
ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
|
||||
SendMessageW(ProgressBar, PBM_SETRANGE32, 0,
|
||||
NotifyContext->ShutdownSettings->WaitToKillAppTimeout / 2);
|
||||
UpdateProgressBar(ProgressBar, NotifyContext);
|
||||
SetTimer(Dlg, 0, 200, NULL);
|
||||
Result = FALSE;
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
|
||||
ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
|
||||
UpdateProgressBar(ProgressBar, NotifyContext);
|
||||
Result = TRUE;
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (BN_CLICKED == HIWORD(wParam) && IDC_END_NOW == LOWORD(wParam))
|
||||
{
|
||||
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
|
||||
NotifyContext->EndNowResult = QUERY_RESULT_FORCE;
|
||||
SendMessageW(Dlg, WM_CLOSE, 0, 0);
|
||||
Result = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(Dlg);
|
||||
Result = TRUE;
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
|
||||
NotifyContext->Dlg = NULL;
|
||||
KillTimer(Dlg, 0);
|
||||
PostQuitMessage(NotifyContext->EndNowResult);
|
||||
Result = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
Result = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
typedef void (STDCALL *INITCOMMONCONTROLS_PROC)(void);
|
||||
|
||||
static void FASTCALL
|
||||
CallInitCommonControls()
|
||||
{
|
||||
static BOOL Initialized = FALSE;
|
||||
HMODULE Lib;
|
||||
INITCOMMONCONTROLS_PROC InitProc;
|
||||
|
||||
if (Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Lib = LoadLibraryW(L"COMCTL32.DLL");
|
||||
if (NULL == Lib)
|
||||
{
|
||||
return;
|
||||
}
|
||||
InitProc = (INITCOMMONCONTROLS_PROC) GetProcAddress(Lib, "InitCommonControls");
|
||||
if (NULL == InitProc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(*InitProc)();
|
||||
|
||||
Initialized = TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
EndNowThreadProc(LPVOID Parameter)
|
||||
{
|
||||
PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) Parameter;
|
||||
MSG Msg;
|
||||
|
||||
SetThreadDesktop(NotifyContext->Desktop);
|
||||
SwitchDesktop(NotifyContext->Desktop);
|
||||
CallInitCommonControls();
|
||||
NotifyContext->Dlg = CreateDialogParam(Win32CsrDllHandle,
|
||||
MAKEINTRESOURCE(IDD_END_NOW), NULL,
|
||||
EndNowDlgProc, (LPARAM) NotifyContext);
|
||||
if (NULL == NotifyContext->Dlg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ShowWindow(NotifyContext->Dlg, SW_SHOWNORMAL);
|
||||
|
||||
while (GetMessageW(&Msg, NULL, 0, 0))
|
||||
{
|
||||
if (! IsDialogMessage(NotifyContext->Dlg, &Msg))
|
||||
{
|
||||
TranslateMessage(&Msg);
|
||||
DispatchMessageW(&Msg);
|
||||
}
|
||||
}
|
||||
|
||||
return Msg.wParam;
|
||||
}
|
||||
|
||||
typedef struct tagMESSAGE_CONTEXT
|
||||
{
|
||||
HWND Wnd;
|
||||
UINT Msg;
|
||||
WPARAM wParam;
|
||||
LPARAM lParam;
|
||||
DWORD Timeout;
|
||||
} MESSAGE_CONTEXT, *PMESSAGE_CONTEXT;
|
||||
|
||||
static DWORD WINAPI
|
||||
SendQueryEndSession(LPVOID Parameter)
|
||||
{
|
||||
PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
|
||||
LRESULT Result;
|
||||
|
||||
if (SendMessageTimeoutW(Context->Wnd, WM_QUERYENDSESSION, Context->wParam,
|
||||
Context->lParam, SMTO_NORMAL, Context->Timeout,
|
||||
&Result))
|
||||
{
|
||||
return Result ? QUERY_RESULT_CONTINUE : QUERY_RESULT_ABORT;
|
||||
}
|
||||
|
||||
return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
SendEndSession(LPVOID Parameter)
|
||||
{
|
||||
PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
|
||||
LRESULT Result;
|
||||
|
||||
if (Context->wParam)
|
||||
{
|
||||
if (SendMessageTimeoutW(Context->Wnd, WM_ENDSESSION, Context->wParam,
|
||||
Context->lParam, SMTO_NORMAL, Context->Timeout,
|
||||
&Result))
|
||||
{
|
||||
return QUERY_RESULT_CONTINUE;
|
||||
}
|
||||
return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(Context->Wnd, WM_ENDSESSION, Context->wParam,
|
||||
Context->lParam);
|
||||
return QUERY_RESULT_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK
|
||||
NotifyTopLevelEnum(HWND Wnd, LPARAM lParam)
|
||||
{
|
||||
PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) lParam;
|
||||
MESSAGE_CONTEXT MessageContext;
|
||||
DWORD Now, Passed;
|
||||
DWORD Timeout, WaitStatus;
|
||||
DWORD ProcessId;
|
||||
HANDLE MessageThread;
|
||||
HANDLE Threads[2];
|
||||
|
||||
if (0 == GetWindowThreadProcessId(Wnd, &ProcessId))
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ProcessId == NotifyContext->ProcessId)
|
||||
{
|
||||
Now = GetTickCount();
|
||||
if (0 == NotifyContext->StartTime)
|
||||
{
|
||||
NotifyContext->StartTime = Now;
|
||||
}
|
||||
/* Note: Passed is computed correctly even when GetTickCount() wraps due
|
||||
to unsigned arithmetic */
|
||||
Passed = Now - NotifyContext->StartTime;
|
||||
MessageContext.Wnd = Wnd;
|
||||
MessageContext.Msg = NotifyContext->Msg;
|
||||
MessageContext.wParam = NotifyContext->wParam;
|
||||
MessageContext.lParam = NotifyContext->lParam;
|
||||
MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
|
||||
if (! NotifyContext->ShutdownSettings->AutoEndTasks)
|
||||
{
|
||||
MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
|
||||
}
|
||||
if (Passed < MessageContext.Timeout)
|
||||
{
|
||||
MessageContext.Timeout -= Passed;
|
||||
MessageThread = CreateThread(NULL, 0, NotifyContext->SendMessageProc,
|
||||
(LPVOID) &MessageContext, 0, NULL);
|
||||
if (NULL == MessageThread)
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
|
||||
if (Passed < Timeout)
|
||||
{
|
||||
Timeout -= Passed;
|
||||
WaitStatus = WaitForSingleObjectEx(MessageThread, Timeout, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitStatus = WAIT_TIMEOUT;
|
||||
}
|
||||
if (WAIT_TIMEOUT == WaitStatus)
|
||||
{
|
||||
NotifyContext->WndClient = Wnd;
|
||||
if (NULL == NotifyContext->UIThread && NotifyContext->ShowUI)
|
||||
{
|
||||
NotifyContext->UIThread = CreateThread(NULL, 0,
|
||||
EndNowThreadProc,
|
||||
(LPVOID) NotifyContext,
|
||||
0, NULL);
|
||||
}
|
||||
Threads[0] = MessageThread;
|
||||
Threads[1] = NotifyContext->UIThread;
|
||||
WaitStatus = WaitForMultipleObjectsEx(NULL == NotifyContext->UIThread ?
|
||||
1 : 2,
|
||||
Threads, FALSE, INFINITE,
|
||||
FALSE);
|
||||
if (WAIT_OBJECT_0 == WaitStatus)
|
||||
{
|
||||
if (! GetExitCodeThread(MessageThread, &NotifyContext->QueryResult))
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
else if (WAIT_OBJECT_0 + 1 == WaitStatus)
|
||||
{
|
||||
if (! GetExitCodeThread(NotifyContext->UIThread,
|
||||
&NotifyContext->QueryResult))
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
}
|
||||
if (WAIT_OBJECT_0 != WaitStatus)
|
||||
{
|
||||
TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
else if (WAIT_OBJECT_0 == WaitStatus)
|
||||
{
|
||||
if (! GetExitCodeThread(MessageThread,
|
||||
&NotifyContext->QueryResult))
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
|
||||
}
|
||||
CloseHandle(MessageThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return QUERY_RESULT_CONTINUE == NotifyContext->QueryResult;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK
|
||||
NotifyDesktopEnum(LPWSTR DesktopName, LPARAM lParam)
|
||||
{
|
||||
PNOTIFY_CONTEXT Context = (PNOTIFY_CONTEXT) lParam;
|
||||
|
||||
Context->Desktop = OpenDesktopW(DesktopName, 0, FALSE,
|
||||
DESKTOP_ENUMERATE | DESKTOP_SWITCHDESKTOP);
|
||||
if (NULL == Context->Desktop)
|
||||
{
|
||||
DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
|
||||
Context->QueryResult = QUERY_RESULT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam);
|
||||
|
||||
CloseDesktop(Context->Desktop);
|
||||
|
||||
return QUERY_RESULT_CONTINUE == Context->QueryResult;
|
||||
}
|
||||
|
||||
static BOOL FASTCALL
|
||||
NotifyTopLevelWindows(PNOTIFY_CONTEXT Context)
|
||||
{
|
||||
HWINSTA WindowStation;
|
||||
|
||||
WindowStation = GetProcessWindowStation();
|
||||
if (NULL == WindowStation)
|
||||
{
|
||||
DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EnumDesktopsW(WindowStation, NotifyDesktopEnum, (LPARAM) Context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL FASTCALL
|
||||
NotifyAndTerminateProcess(PCSRSS_PROCESS_DATA ProcessData,
|
||||
PSHUTDOWN_SETTINGS ShutdownSettings,
|
||||
UINT Flags)
|
||||
{
|
||||
NOTIFY_CONTEXT Context;
|
||||
HANDLE Process;
|
||||
DWORD QueryResult = QUERY_RESULT_CONTINUE;
|
||||
|
||||
Context.QueryResult = QUERY_RESULT_CONTINUE;
|
||||
|
||||
if (0 == (Flags & EWX_FORCE))
|
||||
{
|
||||
if (NULL != ProcessData->Console)
|
||||
{
|
||||
ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, ProcessData,
|
||||
ShutdownSettings->WaitToKillAppTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.ProcessId = (DWORD) ProcessData->ProcessId;
|
||||
Context.wParam = 0;
|
||||
Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
|
||||
ENDSESSION_LOGOFF : 0);
|
||||
Context.StartTime = 0;
|
||||
Context.UIThread = NULL;
|
||||
Context.ShowUI = DtbgIsDesktopVisible();
|
||||
Context.Dlg = NULL;
|
||||
Context.ShutdownSettings = ShutdownSettings;
|
||||
Context.SendMessageProc = SendQueryEndSession;
|
||||
|
||||
NotifyTopLevelWindows(&Context);
|
||||
|
||||
Context.wParam = (QUERY_RESULT_ABORT != Context.QueryResult);
|
||||
Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
|
||||
ENDSESSION_LOGOFF : 0);
|
||||
Context.SendMessageProc = SendEndSession;
|
||||
Context.ShowUI = DtbgIsDesktopVisible() &&
|
||||
(QUERY_RESULT_ABORT != Context.QueryResult);
|
||||
QueryResult = Context.QueryResult;
|
||||
Context.QueryResult = QUERY_RESULT_CONTINUE;
|
||||
|
||||
NotifyTopLevelWindows(&Context);
|
||||
|
||||
if (NULL != Context.UIThread)
|
||||
{
|
||||
if (NULL != Context.Dlg)
|
||||
{
|
||||
SendMessageW(Context.Dlg, WM_CLOSE, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
TerminateThread(Context.UIThread, QUERY_RESULT_ERROR);
|
||||
}
|
||||
CloseHandle(Context.UIThread);
|
||||
}
|
||||
}
|
||||
|
||||
if (QUERY_RESULT_ABORT == QueryResult)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate this process */
|
||||
Process = OpenProcess(PROCESS_TERMINATE, FALSE,
|
||||
(DWORD) ProcessData->ProcessId);
|
||||
if (NULL == Process)
|
||||
{
|
||||
DPRINT1("Unable to open process %d, error %d\n", ProcessData->ProcessId,
|
||||
GetLastError());
|
||||
return TRUE;
|
||||
}
|
||||
TerminateProcess(Process, 0);
|
||||
CloseHandle(Process);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct tagPROCESS_ENUM_CONTEXT
|
||||
{
|
||||
UINT ProcessCount;
|
||||
PCSRSS_PROCESS_DATA *ProcessData;
|
||||
TOKEN_ORIGIN TokenOrigin;
|
||||
DWORD ShellProcess;
|
||||
DWORD CsrssProcess;
|
||||
} PROCESS_ENUM_CONTEXT, *PPROCESS_ENUM_CONTEXT;
|
||||
|
||||
static NTSTATUS STDCALL
|
||||
ExitReactosProcessEnum(PCSRSS_PROCESS_DATA ProcessData, PVOID Data)
|
||||
{
|
||||
HANDLE Process;
|
||||
HANDLE Token;
|
||||
TOKEN_ORIGIN Origin;
|
||||
DWORD ReturnLength;
|
||||
PPROCESS_ENUM_CONTEXT Context = (PPROCESS_ENUM_CONTEXT) Data;
|
||||
PCSRSS_PROCESS_DATA *NewData;
|
||||
|
||||
/* Do not kill winlogon or csrss */
|
||||
if ((DWORD) ProcessData->ProcessId == Context->CsrssProcess ||
|
||||
ProcessData->ProcessId == LogonProcess)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get the login session of this process */
|
||||
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
|
||||
(DWORD) ProcessData->ProcessId);
|
||||
if (NULL == Process)
|
||||
{
|
||||
DPRINT1("Unable to open process %d, error %d\n", ProcessData->ProcessId,
|
||||
GetLastError());
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (! OpenProcessToken(Process, TOKEN_QUERY, &Token))
|
||||
{
|
||||
DPRINT1("Unable to open token for process %d, error %d\n",
|
||||
ProcessData->ProcessId, GetLastError());
|
||||
CloseHandle(Process);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
CloseHandle(Process);
|
||||
|
||||
if (! GetTokenInformation(Token, TokenOrigin, &Origin,
|
||||
sizeof(TOKEN_ORIGIN), &ReturnLength))
|
||||
{
|
||||
DPRINT1("GetTokenInformation failed for process %d with error %d\n",
|
||||
ProcessData->ProcessId, GetLastError());
|
||||
CloseHandle(Token);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
CloseHandle(Token);
|
||||
|
||||
/* This process will be killed if it's in the correct logon session */
|
||||
if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession),
|
||||
&(Origin.OriginatingLogonSession)))
|
||||
{
|
||||
/* Kill the shell process last */
|
||||
if ((DWORD) ProcessData->ProcessId == Context->ShellProcess)
|
||||
{
|
||||
ProcessData->ShutdownLevel = 0;
|
||||
}
|
||||
NewData = HeapAlloc(Win32CsrApiHeap, 0, (Context->ProcessCount + 1)
|
||||
* sizeof(PCSRSS_PROCESS_DATA));
|
||||
if (NULL == NewData)
|
||||
{
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
if (0 != Context->ProcessCount)
|
||||
{
|
||||
memcpy(NewData, Context->ProcessData,
|
||||
Context->ProcessCount * sizeof(PCSRSS_PROCESS_DATA));
|
||||
HeapFree(Win32CsrApiHeap, 0, Context->ProcessData);
|
||||
}
|
||||
Context->ProcessData = NewData;
|
||||
Context->ProcessData[Context->ProcessCount] = ProcessData;
|
||||
Context->ProcessCount++;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
ProcessDataCompare(const void *Elem1, const void *Elem2)
|
||||
{
|
||||
const PCSRSS_PROCESS_DATA *ProcessData1 = (PCSRSS_PROCESS_DATA *) Elem1;
|
||||
const PCSRSS_PROCESS_DATA *ProcessData2 = (PCSRSS_PROCESS_DATA *) Elem2;
|
||||
|
||||
if ((*ProcessData1)->ShutdownLevel < (*ProcessData2)->ShutdownLevel)
|
||||
{
|
||||
return +1;
|
||||
}
|
||||
else if ((*ProcessData2)->ShutdownLevel < (*ProcessData1)->ShutdownLevel)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if ((*ProcessData1)->ProcessId < (*ProcessData2)->ProcessId)
|
||||
{
|
||||
return +1;
|
||||
}
|
||||
else if ((*ProcessData2)->ProcessId < (*ProcessData1)->ProcessId)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD FASTCALL
|
||||
GetShutdownSetting(HKEY DesktopKey, LPCWSTR ValueName, DWORD DefaultValue)
|
||||
{
|
||||
BYTE ValueBuffer[16];
|
||||
LONG ErrCode;
|
||||
DWORD Type;
|
||||
DWORD ValueSize;
|
||||
UNICODE_STRING StringValue;
|
||||
ULONG Value;
|
||||
|
||||
ValueSize = sizeof(ValueBuffer);
|
||||
ErrCode = RegQueryValueExW(DesktopKey, ValueName, NULL, &Type, ValueBuffer,
|
||||
&ValueSize);
|
||||
if (ERROR_SUCCESS != ErrCode)
|
||||
{
|
||||
DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
|
||||
ValueName, ErrCode);
|
||||
return DefaultValue;
|
||||
}
|
||||
|
||||
if (REG_SZ == Type)
|
||||
{
|
||||
RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer);
|
||||
if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value)))
|
||||
{
|
||||
DPRINT1("Unable to convert value %S for setting %S\n",
|
||||
StringValue.Buffer, ValueName);
|
||||
return DefaultValue;
|
||||
}
|
||||
return (DWORD) Value;
|
||||
}
|
||||
else if (REG_DWORD == Type)
|
||||
{
|
||||
return *((DWORD *) ValueBuffer);
|
||||
}
|
||||
|
||||
DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName);
|
||||
return DefaultValue;
|
||||
}
|
||||
|
||||
static void FASTCALL
|
||||
LoadShutdownSettings(PSID Sid, PSHUTDOWN_SETTINGS ShutdownSettings)
|
||||
{
|
||||
static WCHAR Subkey[] = L"\\Control Panel\\Desktop";
|
||||
LPWSTR StringSid;
|
||||
WCHAR InitialKeyName[128];
|
||||
LPWSTR KeyName;
|
||||
HKEY DesktopKey;
|
||||
LONG ErrCode;
|
||||
|
||||
ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS;
|
||||
ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT;
|
||||
ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT;
|
||||
|
||||
if (! ConvertSidToStringSidW(Sid, &StringSid))
|
||||
{
|
||||
DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
if (wcslen(StringSid) + wcslen(Subkey) + 1 <=
|
||||
sizeof(InitialKeyName) / sizeof(WCHAR))
|
||||
{
|
||||
KeyName = InitialKeyName;
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyName = HeapAlloc(Win32CsrApiHeap, 0,
|
||||
(wcslen(StringSid) + wcslen(Subkey) + 1) *
|
||||
sizeof(WCHAR));
|
||||
if (NULL == KeyName)
|
||||
{
|
||||
DPRINT1("Failed to allocate memory, using default shutdown settings\n");
|
||||
LocalFree(StringSid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
wcscat(wcscpy(KeyName, StringSid), Subkey);
|
||||
LocalFree(StringSid);
|
||||
|
||||
ErrCode = RegOpenKeyExW(HKEY_USERS, KeyName, 0, KEY_QUERY_VALUE, &DesktopKey);
|
||||
if (KeyName != InitialKeyName)
|
||||
{
|
||||
HeapFree(Win32CsrApiHeap, 0, KeyName);
|
||||
}
|
||||
if (ERROR_SUCCESS != ErrCode)
|
||||
{
|
||||
DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode);
|
||||
return;
|
||||
}
|
||||
|
||||
ShutdownSettings->AutoEndTasks = (BOOL) GetShutdownSetting(DesktopKey, L"AutoEndTasks",
|
||||
(DWORD) DEFAULT_AUTO_END_TASKS);
|
||||
ShutdownSettings->HungAppTimeout = GetShutdownSetting(DesktopKey,
|
||||
L"HungAppTimeout",
|
||||
DEFAULT_HUNG_APP_TIMEOUT);
|
||||
ShutdownSettings->WaitToKillAppTimeout = GetShutdownSetting(DesktopKey,
|
||||
L"WaitToKillAppTimeout",
|
||||
DEFAULT_WAIT_TO_KILL_APP_TIMEOUT);
|
||||
|
||||
RegCloseKey(DesktopKey);
|
||||
}
|
||||
|
||||
static NTSTATUS FASTCALL
|
||||
InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
|
||||
{
|
||||
HANDLE CallerThread;
|
||||
HANDLE CallerToken;
|
||||
NTSTATUS Status;
|
||||
PROCESS_ENUM_CONTEXT Context;
|
||||
DWORD ReturnLength;
|
||||
HWND ShellWnd;
|
||||
UINT ProcessIndex;
|
||||
char FixedUserInfo[64];
|
||||
TOKEN_USER *UserInfo;
|
||||
SHUTDOWN_SETTINGS ShutdownSettings;
|
||||
|
||||
if (ProcessId != (DWORD) LogonProcess)
|
||||
{
|
||||
DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
CallerThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, ThreadId);
|
||||
if (NULL == CallerThread)
|
||||
{
|
||||
DPRINT1("OpenThread failed with error %d\n", GetLastError());
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (! OpenThreadToken(CallerThread, TOKEN_QUERY, FALSE, &CallerToken))
|
||||
{
|
||||
DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
|
||||
CloseHandle(CallerThread);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
CloseHandle(CallerThread);
|
||||
|
||||
Context.ProcessCount = 0;
|
||||
Context.ProcessData = NULL;
|
||||
if (! GetTokenInformation(CallerToken, TokenOrigin, &Context.TokenOrigin,
|
||||
sizeof(TOKEN_ORIGIN), &ReturnLength))
|
||||
{
|
||||
DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
|
||||
CloseHandle(CallerToken);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
if (! GetTokenInformation(CallerToken, TokenUser, FixedUserInfo,
|
||||
sizeof(FixedUserInfo), &ReturnLength))
|
||||
{
|
||||
if (sizeof(FixedUserInfo) < ReturnLength)
|
||||
{
|
||||
UserInfo = HeapAlloc(Win32CsrApiHeap, 0, ReturnLength);
|
||||
if (NULL == UserInfo)
|
||||
{
|
||||
DPRINT1("Unable to allocate %u bytes for user info\n",
|
||||
(unsigned) ReturnLength);
|
||||
CloseHandle(CallerToken);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
if (! GetTokenInformation(CallerToken, TokenUser, UserInfo,
|
||||
ReturnLength, &ReturnLength))
|
||||
{
|
||||
DPRINT1("GetTokenInformation failed with error %d\n",
|
||||
GetLastError());
|
||||
HeapFree(Win32CsrApiHeap, 0, UserInfo);
|
||||
CloseHandle(CallerToken);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
|
||||
CloseHandle(CallerToken);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UserInfo = (TOKEN_USER *) FixedUserInfo;
|
||||
}
|
||||
CloseHandle(CallerToken);
|
||||
LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings);
|
||||
if (UserInfo != (TOKEN_USER *) FixedUserInfo)
|
||||
{
|
||||
HeapFree(Win32CsrApiHeap, 0, UserInfo);
|
||||
}
|
||||
Context.CsrssProcess = GetCurrentProcessId();
|
||||
ShellWnd = GetShellWindow();
|
||||
if (NULL == ShellWnd)
|
||||
{
|
||||
DPRINT("No shell present\n");
|
||||
Context.ShellProcess = 0;
|
||||
}
|
||||
else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess))
|
||||
{
|
||||
DPRINT1("Can't get process id of shell window\n");
|
||||
Context.ShellProcess = 0;
|
||||
}
|
||||
|
||||
Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context);
|
||||
if (! NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
|
||||
Status);
|
||||
if (NULL != Context.ProcessData)
|
||||
{
|
||||
HeapFree(Win32CsrApiHeap, 0, Context.ProcessData);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
qsort(Context.ProcessData, Context.ProcessCount, sizeof(PCSRSS_PROCESS_DATA),
|
||||
ProcessDataCompare);
|
||||
|
||||
/* Terminate processes, stop if we find one kicking and screaming it doesn't
|
||||
want to die */
|
||||
Status = STATUS_SUCCESS;
|
||||
for (ProcessIndex = 0;
|
||||
ProcessIndex < Context.ProcessCount && NT_SUCCESS(Status);
|
||||
ProcessIndex++)
|
||||
{
|
||||
if (! NotifyAndTerminateProcess(Context.ProcessData[ProcessIndex],
|
||||
&ShutdownSettings, Flags))
|
||||
{
|
||||
Status = STATUS_REQUEST_ABORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
if (NULL != Context.ProcessData)
|
||||
{
|
||||
HeapFree(Win32CsrApiHeap, 0, Context.ProcessData);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS FASTCALL
|
||||
UserExitReactos(DWORD UserProcessId, UINT Flags)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
if (NULL == LogonNotifyWindow)
|
||||
{
|
||||
DPRINT1("No LogonNotifyWindow registered\n");
|
||||
Request->Status = STATUS_NOT_FOUND;
|
||||
return Request->Status;
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* FIXME Inside 2000 says we should impersonate the caller here */
|
||||
Request->Status = SendMessageW(LogonNotifyWindow, PM_WINLOGON_EXITWINDOWS,
|
||||
(WPARAM) Request->Header.ClientId.UniqueProcess,
|
||||
(LPARAM) Request->Data.ExitReactosRequest.Flags);
|
||||
/* 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 or 1 it's a
|
||||
NTSTATUS value */
|
||||
if (1 == Request->Status)
|
||||
Status = SendMessageW(LogonNotifyWindow, PM_WINLOGON_EXITWINDOWS,
|
||||
(WPARAM) UserProcessId,
|
||||
(LPARAM) Flags);
|
||||
/* 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
|
||||
or 1 it's a NTSTATUS value */
|
||||
if (1 == Status)
|
||||
{
|
||||
Request->Status = STATUS_SUCCESS;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (0 == Request->Status)
|
||||
else if (0 == Status)
|
||||
{
|
||||
Request->Status = STATUS_NOT_IMPLEMENTED;
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
CSR_API(CsrExitReactos)
|
||||
{
|
||||
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
|
||||
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) -
|
||||
sizeof(PORT_MESSAGE);
|
||||
|
||||
if (0 == (Request->Data.ExitReactosRequest.Flags & EWX_INTERNAL_FLAG))
|
||||
{
|
||||
Request->Status = UserExitReactos((DWORD) Request->Header.ClientId.UniqueProcess,
|
||||
Request->Data.ExitReactosRequest.Flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
Request->Status = InternalExitReactos((DWORD) Request->Header.ClientId.UniqueProcess,
|
||||
(DWORD) Request->Header.ClientId.UniqueThread,
|
||||
Request->Data.ExitReactosRequest.Flags);
|
||||
}
|
||||
|
||||
return Request->Status;
|
||||
|
|
20
reactos/subsys/csrss/win32csr/resource.h
Executable file
20
reactos/subsys/csrss/win32csr/resource.h
Executable file
|
@ -0,0 +1,20 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Win32 subsystem
|
||||
* FILE: subsys/csrss/win32csr/resource.h
|
||||
* PURPOSE: Resource #defines
|
||||
*/
|
||||
|
||||
#ifndef WIN32CSR_RESOURCE_H_INCLUDED
|
||||
#define WIN32CSR_RESOURCE_H_INCLUDED
|
||||
|
||||
#define IDD_END_NOW 10
|
||||
|
||||
#define IDC_STATIC 100
|
||||
#define IDC_PROGRESS 101
|
||||
#define IDC_END_NOW 102
|
||||
|
||||
#endif /* WIN32CSR_RESOURCE_H_INCLUDED */
|
||||
|
||||
/* EOF */
|
|
@ -1,3 +1,6 @@
|
|||
#include <win32csr.h>
|
||||
#include "resource.h"
|
||||
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "CSRSS subsystem usermode code\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "win32csr\0"
|
||||
|
@ -5,3 +8,32 @@
|
|||
#include <reactos/version.rc>
|
||||
|
||||
1 ICON DISCARDABLE res/terminal.ico
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
IDD_END_NOW DIALOG DISCARDABLE 0, 0, 200, 95
|
||||
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "End Program - "
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Ending Program... Please wait",IDC_STATIC,7,7,186,11
|
||||
CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
|
||||
7,20,186,13
|
||||
LTEXT "If you choose to end the program immediately, you will lose any unsaved data. To end the program now, click End Now.",
|
||||
IDC_STATIC,7,40,186,26
|
||||
DEFPUSHBUTTON "&End Now",IDC_END_NOW,150,71,43,17
|
||||
END
|
||||
|
||||
IDD_NOT_RESPONDING DIALOG DISCARDABLE 0, 0, 192, 122
|
||||
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "End Program - "
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Cancel",IDCANCEL,142,98,43,17
|
||||
PUSHBUTTON "&End Now",IDC_END_NOW,78,98,43,17
|
||||
LTEXT "This program is not responding",IDC_STATIC,7,7,178,8
|
||||
LTEXT "To return to ReactOS and check the status of the program, click Cancel",
|
||||
IDC_STATIC,7,26,178,16
|
||||
LTEXT "If you choose to end the program immediately, you will loose any unsaved data. To end the program now, click End Now",
|
||||
IDC_STATIC,7,53,178,26
|
||||
END
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<include base="csrss">include</include>
|
||||
<define name="_DISABLE_TIDENTS" />
|
||||
<define name="__USE_W32API" />
|
||||
<define name="_WIN32_WINNT">0x0500</define>
|
||||
<library>ntdll</library>
|
||||
<library>kernel32</library>
|
||||
<library>user32</library>
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define WINLOGON_SAS_CLASS L"SAS window class"
|
||||
#define WINLOGON_SAS_TITLE L"SAS"
|
||||
|
||||
#define HK_CTRL_ALT_DEL 0
|
||||
#define HK_CTRL_SHIFT_ESC 1
|
||||
|
||||
|
@ -72,15 +75,50 @@ DestroySAS(PWLSESSION Session, HWND hwndSAS)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#define EWX_ACTION_MASK 0x0b
|
||||
#define EWX_ACTION_MASK 0xffffffeb
|
||||
#define EWX_FLAGS_MASK 0x00000014
|
||||
|
||||
typedef struct tagLOGOFF_SHUTDOWN_DATA
|
||||
{
|
||||
UINT Flags;
|
||||
PWLSESSION Session;
|
||||
} LOGOFF_SHUTDOWN_DATA, *PLOGOFF_SHUTDOWN_DATA;
|
||||
|
||||
static DWORD WINAPI
|
||||
LogoffShutdownThread(LPVOID Parameter)
|
||||
{
|
||||
PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA) Parameter;
|
||||
|
||||
if (! ImpersonateLoggedOnUser(LSData->Session->UserToken))
|
||||
{
|
||||
DPRINT1("ImpersonateLoggedOnUser failed with error %d\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
if (! ExitWindowsEx(EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK)
|
||||
| (EWX_LOGOFF == (LSData->Flags & EWX_ACTION_MASK) ? EWX_INTERNAL_FLAG_LOGOFF : 0),
|
||||
0))
|
||||
{
|
||||
DPRINT1("Unable to kill user apps, error %d\n", GetLastError());
|
||||
RevertToSelf();
|
||||
return 0;
|
||||
}
|
||||
RevertToSelf();
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, LSData);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static LRESULT
|
||||
HandleExitWindows(DWORD RequestingProcessId, UINT Flags)
|
||||
HandleExitWindows(PWLSESSION Session, DWORD RequestingProcessId, UINT Flags)
|
||||
{
|
||||
UINT Action;
|
||||
HANDLE Process;
|
||||
HANDLE Token;
|
||||
HANDLE Thread;
|
||||
BOOL CheckResult;
|
||||
PPRIVILEGE_SET PrivSet;
|
||||
PLOGOFF_SHUTDOWN_DATA LSData;
|
||||
|
||||
/* Check parameters */
|
||||
Action = Flags & EWX_ACTION_MASK;
|
||||
|
@ -139,7 +177,22 @@ HandleExitWindows(DWORD RequestingProcessId, UINT Flags)
|
|||
}
|
||||
}
|
||||
|
||||
/* FIXME actually start logoff/shutdown now */
|
||||
LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
|
||||
if (NULL == LSData)
|
||||
{
|
||||
DPRINT1("Failed to allocate mem for thread data\n");
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
LSData->Flags = Flags;
|
||||
LSData->Session = Session;
|
||||
Thread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID) LSData, 0, NULL);
|
||||
if (NULL == Thread)
|
||||
{
|
||||
DPRINT1("Unable to create shutdown thread, error %d\n", GetLastError());
|
||||
HeapFree(GetProcessHeap(), 0, LSData);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
CloseHandle(Thread);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -178,7 +231,7 @@ SASProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
case PM_WINLOGON_EXITWINDOWS:
|
||||
{
|
||||
return HandleExitWindows((DWORD) wParam, (UINT) lParam);
|
||||
return HandleExitWindows(Session, (DWORD) wParam, (UINT) lParam);
|
||||
}
|
||||
case WM_DESTROY:
|
||||
{
|
||||
|
|
|
@ -405,7 +405,6 @@ DoLogonUser (PWCHAR Name,
|
|||
STARTUPINFO StartupInfo;
|
||||
WCHAR CommandLine[MAX_PATH];
|
||||
WCHAR CurrentDirectory[MAX_PATH];
|
||||
HANDLE hToken;
|
||||
PROFILEINFOW ProfileInfo;
|
||||
BOOL Result;
|
||||
LPVOID lpEnvironment = NULL;
|
||||
|
@ -416,7 +415,7 @@ DoLogonUser (PWCHAR Name,
|
|||
Password,
|
||||
LOGON32_LOGON_INTERACTIVE,
|
||||
LOGON32_PROVIDER_DEFAULT,
|
||||
&hToken);
|
||||
&WLSession->UserToken);
|
||||
if (!Result)
|
||||
{
|
||||
DbgPrint ("WL: LogonUserW() failed\n");
|
||||
|
@ -434,24 +433,24 @@ DoLogonUser (PWCHAR Name,
|
|||
ProfileInfo.lpPolicyPath = NULL;
|
||||
ProfileInfo.hProfile = NULL;
|
||||
|
||||
if (!LoadUserProfileW (hToken,
|
||||
if (!LoadUserProfileW (WLSession->UserToken,
|
||||
&ProfileInfo))
|
||||
{
|
||||
DbgPrint ("WL: LoadUserProfileW() failed\n");
|
||||
CloseHandle (hToken);
|
||||
CloseHandle (WLSession->UserToken);
|
||||
RtlDestroyEnvironment (lpEnvironment);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CreateEnvironmentBlock (&lpEnvironment,
|
||||
hToken,
|
||||
WLSession->UserToken,
|
||||
TRUE))
|
||||
{
|
||||
DbgPrint ("WL: CreateEnvironmentBlock() failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ImpersonateLoggedOnUser(hToken))
|
||||
if (ImpersonateLoggedOnUser(WLSession->UserToken))
|
||||
{
|
||||
UpdatePerUserSystemParameters(0, TRUE);
|
||||
RevertToSelf();
|
||||
|
@ -467,7 +466,7 @@ DoLogonUser (PWCHAR Name,
|
|||
StartupInfo.cbReserved2 = 0;
|
||||
StartupInfo.lpReserved2 = 0;
|
||||
|
||||
Result = CreateProcessAsUserW (hToken,
|
||||
Result = CreateProcessAsUserW (WLSession->UserToken,
|
||||
NULL,
|
||||
GetUserInit (CommandLine),
|
||||
NULL,
|
||||
|
@ -481,14 +480,14 @@ DoLogonUser (PWCHAR Name,
|
|||
if (!Result)
|
||||
{
|
||||
DbgPrint ("WL: Failed to execute user shell %s\n", CommandLine);
|
||||
if (ImpersonateLoggedOnUser(hToken))
|
||||
if (ImpersonateLoggedOnUser(WLSession->UserToken))
|
||||
{
|
||||
UpdatePerUserSystemParameters(0, FALSE);
|
||||
RevertToSelf();
|
||||
}
|
||||
UnloadUserProfile (hToken,
|
||||
UnloadUserProfile (WLSession->UserToken,
|
||||
ProfileInfo.hProfile);
|
||||
CloseHandle (hToken);
|
||||
CloseHandle (WLSession->UserToken);
|
||||
DestroyEnvironmentBlock (lpEnvironment);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -511,17 +510,17 @@ DoLogonUser (PWCHAR Name,
|
|||
CloseHandle (ProcessInformation.hProcess);
|
||||
CloseHandle (ProcessInformation.hThread);
|
||||
|
||||
if (ImpersonateLoggedOnUser(hToken))
|
||||
if (ImpersonateLoggedOnUser(WLSession->UserToken))
|
||||
{
|
||||
UpdatePerUserSystemParameters(0, FALSE);
|
||||
RevertToSelf();
|
||||
}
|
||||
|
||||
/* Unload user profile */
|
||||
UnloadUserProfile (hToken,
|
||||
UnloadUserProfile (WLSession->UserToken,
|
||||
ProfileInfo.hProfile);
|
||||
|
||||
CloseHandle (hToken);
|
||||
CloseHandle (WLSession->UserToken);
|
||||
|
||||
RtlDestroyEnvironment (lpEnvironment);
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ typedef struct _WLSESSION
|
|||
HDESK WinlogonDesktop;
|
||||
HDESK ScreenSaverDesktop;
|
||||
LUID LogonId;
|
||||
HANDLE UserToken;
|
||||
} WLSESSION, *PWLSESSION;
|
||||
|
||||
extern HINSTANCE hAppInstance;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#define Unimplemented DbgPrint("WL: %S() at %S:%i unimplemented!\n", __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
#define WINLOGON_DESKTOP L"Winlogon"
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue