⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exitros.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
  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;
    }

  DPRINT1("FIXME: Need to close all user processes!\n");
  return STATUS_SUCCESS;

  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");
      return STATUS_NOT_FOUND;
    }

  /* FIXME Inside 2000 says we should impersonate the caller here */
  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 = 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;
}

/* EOF */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -