Send proper messages/events to processes during logoff and kill them if they
authorGé van Geldorp <ge@gse.nl>
Thu, 1 Dec 2005 22:29:57 +0000 (22:29 +0000)
committerGé van Geldorp <ge@gse.nl>
Thu, 1 Dec 2005 22:29:57 +0000 (22:29 +0000)
dont self-destruct.
Work in progress, not complete yet. Committed so others can work on it too.

svn path=/trunk/; revision=19815

12 files changed:
reactos/include/reactos/winlogon.h
reactos/lib/user32/misc/exit.c
reactos/subsys/csrss/win32csr/conio.c
reactos/subsys/csrss/win32csr/dllmain.c
reactos/subsys/csrss/win32csr/exitros.c
reactos/subsys/csrss/win32csr/resource.h [new file with mode: 0755]
reactos/subsys/csrss/win32csr/win32csr.rc
reactos/subsys/csrss/win32csr/win32csr.xml
reactos/subsys/system/winlogon/sas.c
reactos/subsys/system/winlogon/winlogon.c
reactos/subsys/system/winlogon/winlogon.h
reactos/subsys/system/winlogon/wlx.c

index f5fc460..4c00b67 100644 (file)
 #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 */
 
index fe38e55..e8a0ed9 100644 (file)
  * 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
  *   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
index b2cc24f..1d1ebff 100644 (file)
@@ -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)++]
 
index b4fb3f7..d42d3d5 100644 (file)
@@ -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)
 {
index e8e5e80..b172447 100644 (file)
@@ -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)
+    {
+      Status = STATUS_SUCCESS;
+    }
+  else if (0 == Status)
+    {
+      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 = STATUS_SUCCESS;
+      Request->Status = UserExitReactos((DWORD) Request->Header.ClientId.UniqueProcess,
+                                        Request->Data.ExitReactosRequest.Flags);
     }
-  else if (0 == Request->Status)
+  else
     {
-      Request->Status = STATUS_NOT_IMPLEMENTED;
+      Request->Status = InternalExitReactos((DWORD) Request->Header.ClientId.UniqueProcess,
+                                            (DWORD) Request->Header.ClientId.UniqueThread,
+                                            Request->Data.ExitReactosRequest.Flags);
     }
 
   return Request->Status;
diff --git a/reactos/subsys/csrss/win32csr/resource.h b/reactos/subsys/csrss/win32csr/resource.h
new file mode 100755 (executable)
index 0000000..ed15b50
--- /dev/null
@@ -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 */
index aab4057..aabf87b 100644 (file)
@@ -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
index bd24f5b..f7c19a1 100644 (file)
@@ -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>
index 24dedb5..7c3b646 100644 (file)
@@ -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:
     {
index 2cb92bd..fb541a9 100644 (file)
@@ -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);
 
index 9413761..d8422cf 100644 (file)
@@ -140,6 +140,7 @@ typedef struct _WLSESSION
   HDESK WinlogonDesktop;
   HDESK ScreenSaverDesktop;
   LUID LogonId;
+  HANDLE UserToken;
 } WLSESSION, *PWLSESSION;
 
 extern HINSTANCE hAppInstance;
index 6d8df8f..f996165 100644 (file)
@@ -18,6 +18,8 @@
 
 #define Unimplemented DbgPrint("WL: %S() at %S:%i unimplemented!\n", __FUNCTION__, __FILE__, __LINE__)
 
+#define WINLOGON_DESKTOP   L"Winlogon"
+
 /*
  * @implemented
  */