Index: conio.c =================================================================== --- conio.c (révision 46050) +++ conio.c (copie de travail) @@ -58,7 +58,7 @@ { HANDLE Thread; - DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ProcessId); + DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x Dispatch: %p\n", ProcessData->ProcessId, ProcessData->CtrlDispatcher); if (ProcessData->CtrlDispatcher) { @@ -250,6 +250,10 @@ return STATUS_INVALID_PARAMETER; } + /* Set the Ctrl Dispatcher */ + ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher; + DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); + /* If we don't need a console, then get out of here */ if (!Request->Data.AllocConsoleRequest.ConsoleNeeded) { @@ -351,10 +355,6 @@ return Status; } - /* Set the Ctrl Dispatcher */ - ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher; - DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); - if (!NewConsole) { /* Insert into the list if it has not been added */ Index: dllmain.c =================================================================== --- dllmain.c (révision 46050) +++ dllmain.c (copie de travail) @@ -575,7 +575,91 @@ return TRUE; } +SHUTDOWN_SETTINGS ShutdownSettings; +ULONG +NTAPI +GetRegIntFromID(IN HANDLE KeyHandle, + IN PWCHAR Value, + IN ULONG Default) +{ + UNICODE_STRING ValueString; + ULONG Length; + UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32 * sizeof(WCHAR)]; + PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer; + NTSTATUS Status; + ULONG Return; + + /* Open the key */ + RtlInitUnicodeString(&ValueString, Value); + Status = NtQueryValueKey(KeyHandle, + &ValueString, + KeyValuePartialInformation, + PartialInfo, + sizeof(Buffer), + &Length); + if (NT_SUCCESS(Status)) + { + /* Convert to integer */ + RtlInitUnicodeString(&ValueString, (PWCHAR)PartialInfo->Data); + RtlUnicodeStringToInteger(&ValueString, 10, &Return); + } + else + { + /* Use default instead */ + Return = Default; + } + + /* Return the value */ + return Return; +} + +VOID +NTAPI +GetTimeouts(VOID) +{ + HANDLE KeyHandle; + UNICODE_STRING RegistryString; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + + /* Open the desktop key */ + RtlInitUnicodeString(&RegistryString, + L"\\Registry\\User\\.Default\\Control Panel\\Desktop"); + InitializeObjectAttributes(&ObjectAttributes, &RegistryString, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Read timeouts */ + ShutdownSettings.HungAppTimeout = GetRegIntFromID(KeyHandle, + L"HungAppTimeout", + DEFAULT_HUNG_APP_TIMEOUT); + ShutdownSettings.WaitToKillAppTimeout = GetRegIntFromID(KeyHandle, + L"WaitToKillAppTimeout", + DEFAULT_WAIT_TO_KILL_APP_TIMEOUT); + ShutdownSettings.AutoEndTasks = GetRegIntFromID(KeyHandle, + L"AutoEndTasks", + DEFAULT_AUTO_END_TASKS); + + /* Done */ + NtClose(KeyHandle); + } + + /* Now open the control key */ + RtlInitUnicodeString(&RegistryString, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Control"); + InitializeObjectAttributes(&ObjectAttributes, &RegistryString, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Read the services timeout */ + ShutdownSettings.WaitToKillServiceTimeout = GetRegIntFromID(KeyHandle, + L"WaitToKillServiceTimeout", + DEFAULT_WAIT_TO_KILL_SERVICE_TIMEOUT); + NtClose(KeyHandle); + } +} + BOOL WINAPI Win32CsrInitialization(PCSRSS_API_DEFINITION *ApiDefinitions, PCSRSS_OBJECT_DEFINITION *ObjectDefinitions, @@ -587,6 +671,8 @@ NTSTATUS Status; CsrExports = *Exports; Win32CsrApiHeap = CsrssApiHeap; + + GetTimeouts(); Status = NtUserInitialize(0 ,NULL, NULL); Index: w32csr.h =================================================================== --- w32csr.h (révision 46050) +++ w32csr.h (copie de travail) @@ -35,4 +35,18 @@ /* shared header with console.dll */ #include "console.h" + +typedef struct tagSHUTDOWN_SETTINGS +{ + BOOLEAN AutoEndTasks; + ULONG HungAppTimeout; + ULONG WaitToKillAppTimeout; + ULONG WaitToKillServiceTimeout; +} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS; + +#define DEFAULT_AUTO_END_TASKS FALSE +#define DEFAULT_HUNG_APP_TIMEOUT 5000 +#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 5000 +#define DEFAULT_WAIT_TO_KILL_SERVICE_TIMEOUT 20000 + /* EOF */ Index: exitros.c =================================================================== --- exitros.c (révision 46050) +++ exitros.c (copie de travail) @@ -68,17 +68,7 @@ return STATUS_SUCCESS; } -typedef struct tagSHUTDOWN_SETTINGS -{ - 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; @@ -103,6 +93,9 @@ #define QUERY_RESULT_ERROR 3 #define QUERY_RESULT_FORCE 4 +#if 0 + + static void FASTCALL UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext) { @@ -467,7 +460,7 @@ UINT Flags) { NOTIFY_CONTEXT Context; - HANDLE Process; + // HANDLE Process; DWORD QueryResult = QUERY_RESULT_CONTINUE; Context.QueryResult = QUERY_RESULT_CONTINUE; @@ -525,6 +518,7 @@ } } +#if 0 /* Terminate this process */ Process = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD_PTR) ProcessData->ProcessId); @@ -536,358 +530,664 @@ } TerminateProcess(Process, 0); CloseHandle(Process); - +#endif 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; +#endif -static NTSTATUS WINAPI -ExitReactosProcessEnum(PCSRSS_PROCESS_DATA ProcessData, PVOID Data) + +#define CsrShutdownProcesses(x,y) \ +{ \ + PVOID Context[2] = {x, (PVOID)y}; \ + Win32CsrEnumProcesses(ShutdownProcessCallback, &Context); \ +} + +#define CsrHeap RtlGetProcessHeap() + +NTSTATUS +NTAPI +CsrGetProcessLuid(HANDLE hProcess OPTIONAL, + PLUID Luid) { - HANDLE Process; - HANDLE Token; - TOKEN_ORIGIN Origin; - DWORD ReturnLength; - PPROCESS_ENUM_CONTEXT Context = (PPROCESS_ENUM_CONTEXT) Data; - PCSRSS_PROCESS_DATA *NewData; + HANDLE hToken = NULL; + NTSTATUS Status; + ULONG Length; + PTOKEN_STATISTICS TokenStats; - /* Do not kill winlogon or csrss */ - if ((DWORD_PTR) ProcessData->ProcessId == Context->CsrssProcess || - ProcessData->ProcessId == LogonProcess) + /* Check if we have a handle to a CSR Process */ + if (!hProcess) { - return STATUS_SUCCESS; - } + /* We don't, so try opening the Thread's Token */ + Status = NtOpenThreadToken(NtCurrentThread(), + TOKEN_QUERY, + FALSE, + &hToken); - /* Get the login session of this process */ - Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, - (DWORD_PTR) ProcessData->ProcessId); - if (NULL == Process) - { - DPRINT1("Unable to open process %d, error %d\n", ProcessData->ProcessId, - GetLastError()); - return STATUS_UNSUCCESSFUL; + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + /* If we got some other failure, then return and quit */ + if (Status != STATUS_NO_TOKEN) return Status; + + /* We don't have a Thread Token, use a Process Token */ + hProcess = NtCurrentProcess(); + hToken = NULL; + } } - if (! OpenProcessToken(Process, TOKEN_QUERY, &Token)) + /* Check if we have a token by now */ + if (!hToken) { - DPRINT1("Unable to open token for process %d, error %d\n", - ProcessData->ProcessId, GetLastError()); - CloseHandle(Process); - return STATUS_UNSUCCESSFUL; + /* No token yet, so open the Process Token */ + Status = NtOpenProcessToken(hProcess, + TOKEN_QUERY, + &hToken); + if (!NT_SUCCESS(Status)) + { + /* Still no token, return the error */ + return Status; + } } - CloseHandle(Process); - if (! GetTokenInformation(Token, TokenOrigin, &Origin, - sizeof(TOKEN_ORIGIN), &ReturnLength)) + /* Now get the size we'll need for the Token Information */ + Status = NtQueryInformationToken(hToken, + TokenStatistics, + NULL, + 0, + &Length); + + /* Allocate memory for the Token Info */ + if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length))) { - DPRINT1("GetTokenInformation failed for process %d with error %d\n", - ProcessData->ProcessId, GetLastError()); - CloseHandle(Token); - return STATUS_UNSUCCESSFUL; + /* Fail and close the token */ + NtClose(hToken); + return STATUS_NO_MEMORY; } - CloseHandle(Token); - /* This process will be killed if it's in the correct logon session */ - if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession), - &(Origin.OriginatingLogonSession))) + /* Now query the information */ + Status = NtQueryInformationToken(hToken, + TokenStatistics, + TokenStats, + Length, + &Length); + + /* Close the handle */ + NtClose(hToken); + + /* Check for success */ + if (NT_SUCCESS(Status)) { - /* Kill the shell process last */ - if ((DWORD_PTR) 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 the LUID */ + *Luid = TokenStats->AuthenticationId; } - return STATUS_SUCCESS; + /* Free the query information */ + RtlFreeHeap(CsrHeap, 0, TokenStats); + + /* Return the Status */ + return Status; } -static int -ProcessDataCompare(const void *Elem1, const void *Elem2) +SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = { - const PCSRSS_PROCESS_DATA *ProcessData1 = (PCSRSS_PROCESS_DATA *) Elem1; - const PCSRSS_PROCESS_DATA *ProcessData2 = (PCSRSS_PROCESS_DATA *) Elem2; + sizeof(SECURITY_QUALITY_OF_SERVICE), + SecurityImpersonation, + SECURITY_STATIC_TRACKING, + FALSE +}; - if ((*ProcessData1)->ShutdownLevel < (*ProcessData2)->ShutdownLevel) +BOOLEAN +NTAPI +CsrImpersonateClient(IN HANDLE ThreadHandle) +{ + NTSTATUS Status; + + + /* Make the call */ + Status = NtImpersonateThread(NtCurrentThread(), + ThreadHandle, + &CsrSecurityQos); + + if (!NT_SUCCESS(Status)) { - return +1; + /* Failure */ + return FALSE; } - 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; + /* Return Success */ + return TRUE; } -static DWORD FASTCALL -GetShutdownSetting(HKEY DesktopKey, LPCWSTR ValueName, DWORD DefaultValue) +BOOLEAN +NTAPI +CsrRevertToSelf(VOID) { - BYTE ValueBuffer[16]; - LONG ErrCode; - DWORD Type; - DWORD ValueSize; - UNICODE_STRING StringValue; - ULONG Value; + NTSTATUS Status; + HANDLE ImpersonationToken = NULL; - 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; - } + /* Impersonation has been totally removed, revert to ourselves */ + Status = NtSetInformationThread(NtCurrentThread(), + ThreadImpersonationToken, + &ImpersonationToken, + sizeof(HANDLE)); - if (REG_SZ == Type) + /* Return TRUE or FALSE */ + return NT_SUCCESS(Status); +} + +VOID +NTAPI +KillProcess(IN HANDLE ProcessHandle, + IN ULONG_PTR ProcessId) +{ + NTSTATUS Status; + LARGE_INTEGER Timeout; + + Status = NtTerminateProcess(ProcessHandle, CONTROL_C_EXIT); + if (NT_SUCCESS(Status)) { - RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer); - if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value))) + Timeout.QuadPart = -10000 * DEFAULT_HUNG_APP_TIMEOUT; + Status = NtWaitForSingleObject(ProcessHandle, FALSE, &Timeout); + if (Status != STATUS_WAIT_0) { - DPRINT1("Unable to convert value %S for setting %S\n", - StringValue.Buffer, ValueName); - return DefaultValue; + DPRINT1("KillProcess: wait for process %x failed with status %x", + ProcessId, Status); } - return (DWORD) Value; } - else if (REG_DWORD == Type) - { - return *((DWORD *) ValueBuffer); - } +} - DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName); - return DefaultValue; +DWORD +NTAPI +InternalWaitCancel(IN HANDLE ObjectHandle, + IN ULONG Timeout) +{ + HANDLE Handles[2]; + + Handles[0] = ObjectHandle; + //Handles[1] = CancelEvent; // not implemented + + return WaitForMultipleObjects(1, Handles, FALSE, Timeout); } -static void FASTCALL -LoadShutdownSettings(PSID Sid, PSHUTDOWN_SETTINGS ShutdownSettings) +HANDLE +NTAPI +InternalCreateCallbackThread(IN HANDLE hProcess, + IN LPTHREAD_START_ROUTINE lpfn, + IN ULONG_PTR dwData) { - static WCHAR Subkey[] = L"\\Control Panel\\Desktop"; - LPWSTR StringSid; - WCHAR InitialKeyName[128]; - LPWSTR KeyName; - HKEY DesktopKey; - LONG ErrCode; + LONG BasePriority; + HANDLE hThread, hToken; + PTOKEN_DEFAULT_DACL lpDaclDefault; + TOKEN_DEFAULT_DACL daclDefault; + ULONG cbDacl; + SECURITY_ATTRIBUTES attrThread; + SECURITY_DESCRIPTOR sd; + DWORD idThread; + NTSTATUS Status; - ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS; - ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT; - ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT; + hThread = NULL; - if (! ConvertSidToStringSidW(Sid, &StringSid)) - { - DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n", - GetLastError()); - return; + Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken); + if (!NT_SUCCESS(Status)) { + DPRINT1("NtOpenProcessToken failed, status = %x\n", Status); + return NULL; } - if (wcslen(StringSid) + wcslen(Subkey) + 1 <= - sizeof(InitialKeyName) / sizeof(WCHAR)) - { - KeyName = InitialKeyName; + + cbDacl = 0; + NtQueryInformationToken(hToken, + TokenDefaultDacl, + &daclDefault, + sizeof(daclDefault), + &cbDacl); + + lpDaclDefault = (PTOKEN_DEFAULT_DACL)LocalAlloc(LMEM_FIXED, cbDacl); + if (lpDaclDefault == NULL) { + DPRINT1("LocalAlloc failed for lpDaclDefault"); + goto closeexit; } - 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; - } + + Status = NtQueryInformationToken(hToken, + TokenDefaultDacl, + lpDaclDefault, + cbDacl, + &cbDacl); + if (!NT_SUCCESS(Status)) { + DPRINT1("NtQueryInformationToken failed, status = %x\n", Status); + goto freeexit; } - 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 (!NT_SUCCESS(RtlCreateSecurityDescriptor(&sd, + SECURITY_DESCRIPTOR_REVISION1))) { + ASSERT(FALSE); + goto freeexit; } - if (ERROR_SUCCESS != ErrCode) - { - DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode); - return; + + RtlSetDaclSecurityDescriptor(&sd, TRUE, lpDaclDefault->DefaultDacl, TRUE); + + attrThread.nLength = sizeof(attrThread); + attrThread.lpSecurityDescriptor = &sd; + attrThread.bInheritHandle = FALSE; + + GetLastError(); + //DPRINT1("Creating remote thread\n"); + hThread = CreateRemoteThread(hProcess, + &attrThread, + 0L, + lpfn, + (LPVOID)dwData, + 0, + &idThread); + //DPRINT1("Remote ctrl-c thread: %lx\n", hThread); + + if (hThread != NULL) { + BasePriority = THREAD_PRIORITY_HIGHEST; + NtSetInformationThread(hThread, + ThreadBasePriority, + &BasePriority, + sizeof(LONG)); } - 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); +freeexit: + //DPRINT1("freeing DACL\n"); + LocalFree((HANDLE)lpDaclDefault); - RegCloseKey(DesktopKey); +closeexit: +//DPRINT1("exiting\n"); + NtClose(hToken); + + return hThread; } -static NTSTATUS FASTCALL -InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags) +extern SHUTDOWN_SETTINGS ShutdownSettings; + +ULONG +NTAPI +CreateCtrlThread(IN HANDLE ProcessHandle, + IN ULONG EventType, + IN LPTHREAD_START_ROUTINE CtrlHandler, + IN BOOLEAN ForceProcess) { - 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_PTR) LogonProcess) + NTSTATUS Status; + HANDLE Thread; + ULONG EventFlags; + BOOLEAN ExitProcess, BreakEvent; + ULONG ThreadExitCode; + ULONG ProcessExitCode; + ULONG Timeout; + PROCESS_BASIC_INFORMATION BasicInfo; + PCSRSS_PROCESS_DATA Process; + ULONG ShutdownFlags; + + Status = NtQueryInformationProcess(ProcessHandle, + ProcessBasicInformation, + &BasicInfo, + sizeof(BasicInfo), + NULL); + //DPRINT1("Status: %lx. Pid: %lx\n", Status, BasicInfo.UniqueProcessId); + if (NT_SUCCESS(Status)) { - DPRINT1("Internal ExitWindowsEx call not from winlogon\n"); - return STATUS_ACCESS_DENIED; + CsrLockProcessByClientId((HANDLE)BasicInfo.UniqueProcessId, &Process); + //DPRINT1("Process found: %p\n", Process); + if (Process == NULL) + { + KillProcess(ProcessHandle, BasicInfo.UniqueProcessId); + return FALSE; + } } + else + { + KillProcess(ProcessHandle, 0); + return FALSE; + } + + ShutdownFlags = Process->ShutdownFlags; + + CsrUnlockProcess(Process); + + if (EventType != CTRL_C_EVENT && EventType != CTRL_BREAK_EVENT) + { + BreakEvent = FALSE; + } + else + { + BreakEvent = TRUE; + } - DPRINT1("FIXME: Need to close all user processes!\n"); - return STATUS_SUCCESS; + ExitProcess = TRUE; + EventFlags = 0; - CallerThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, ThreadId); - if (NULL == CallerThread) + if (ShutdownFlags & (CsrShutdownSystem | CsrShutdownOther)) { - DPRINT1("OpenThread failed with error %d\n", GetLastError()); - return STATUS_UNSUCCESSFUL; + // + // System context - make sure we don't cause it to exit, make + // sure we don't bring up retry dialogs. + // + //DPRINT1("This is a system app\n"); + + ExitProcess = FALSE; + ForceProcess = TRUE; + + // + // This EventFlag will be passed on down to the CtrlRoutine() + // on the client side. That way that side knows not to exit + // this process. + // + + EventFlags = 0x80000000; } - if (! OpenThreadToken(CallerThread, TOKEN_QUERY, FALSE, &CallerToken)) + + //DPRINT1("Creating thread\n"); + Thread = InternalCreateCallbackThread(ProcessHandle, + CtrlHandler, + EventType | EventFlags); + if (Thread == NULL) { - DPRINT1("OpenThreadToken failed with error %d\n", GetLastError()); - CloseHandle(CallerThread); - return STATUS_UNSUCCESSFUL; + DPRINT1("CONSRV: CreateRemoteThread failed %x\n",GetLastError()); + return FALSE; } - CloseHandle(CallerThread); - Context.ProcessCount = 0; - Context.ProcessData = NULL; - if (! GetTokenInformation(CallerToken, TokenOrigin, &Context.TokenOrigin, - sizeof(TOKEN_ORIGIN), &ReturnLength)) + if (EventType == CTRL_CLOSE_EVENT) { - DPRINT1("GetTokenInformation failed with error %d\n", GetLastError()); - CloseHandle(CallerToken); - return STATUS_UNSUCCESSFUL; + Timeout = ShutdownSettings.HungAppTimeout; } - if (! GetTokenInformation(CallerToken, TokenUser, FixedUserInfo, - sizeof(FixedUserInfo), &ReturnLength)) + else if (EventType == CTRL_LOGOFF_EVENT) { - if (sizeof(FixedUserInfo) < ReturnLength) + Timeout = ShutdownSettings.WaitToKillAppTimeout; + } + else if (EventType == CTRL_SHUTDOWN_EVENT) + { +// unfortunately, csrss owns this, not win32csr! +// if (BasicInfo.UniqueProcessId == ServicesProcessId) +// { +// Timeout = ShutdownSettings.WaitToKillServiceTimeout; +// } +// else { - UserInfo = HeapAlloc(Win32CsrApiHeap, 0, ReturnLength); - if (NULL == UserInfo) + Timeout = ShutdownSettings.WaitToKillAppTimeout; + } + } + else + { + DPRINT1("failed\n"); + CloseHandle(Thread); + return FALSE; + } + + // DPRINT1("timeout: %d\n", Timeout); + while (TRUE) + { + //DPRINT1("Waiting..\n"); + Status = InternalWaitCancel(Thread, Timeout); + if (Status == WAIT_TIMEOUT) + { + DPRINT1("Wait timed out!\n"); + } + else if (Status == 0) + { + ThreadExitCode = 0; + // DPRINT1("Getting exit codes\n"); + GetExitCodeThread(Thread, &ThreadExitCode); + GetExitCodeProcess(ProcessHandle, &ProcessExitCode); + //DPRINT1("Exit codes: %lx %lx\n", ThreadExitCode, ProcessExitCode); + + if ((ThreadExitCode == EventType && ProcessExitCode == STILL_ACTIVE)) { - DPRINT1("Unable to allocate %u bytes for user info\n", - (unsigned) ReturnLength); - CloseHandle(CallerToken); - return STATUS_NO_MEMORY; + //DPRINT1("Process still alive: %d\n", ForceProcess); + if (!ForceProcess) + { + //DPRINT1("Waiting on the process now...\n"); + Status = InternalWaitCancel(ProcessHandle, Timeout); + if (Status == 0) + { + //DPRINT1("All good\n"); + ExitProcess = FALSE; + } + else if (Status == WAIT_TIMEOUT) + { + DPRINT1("Process still not dead!!\n"); + } + } } - if (! GetTokenInformation(CallerToken, TokenUser, UserInfo, - ReturnLength, &ReturnLength)) + else { - DPRINT1("GetTokenInformation failed with error %d\n", - GetLastError()); - HeapFree(Win32CsrApiHeap, 0, UserInfo); - CloseHandle(CallerToken); - return STATUS_UNSUCCESSFUL; + ExitProcess = FALSE; } } - else + + // + // If we get here, we know that all wait conditions have + // been satisfied. Time to finish with the process. + // + + break; + } + + CloseHandle(Thread); + + // + // If the process is shutting down, mark it as terminated. + // This prevents the process from raising any hard error popups + // after we're done shutting it down. + // + //DPRINT1("Break: %lx\n", BreakEvent); + if (!BreakEvent && + !(ShutdownFlags & (CsrShutdownSystem | CsrShutdownOther))) + { + // DPRINT1("Exit: %lx\n", ExitProcess); + if (ExitProcess) { - DPRINT1("GetTokenInformation failed with error %d\n", GetLastError()); - CloseHandle(CallerToken); - return STATUS_UNSUCCESSFUL; + KillProcess(ProcessHandle, BasicInfo.UniqueProcessId); } } - else + + return TRUE; +} + +ULONG +NTAPI +NonConsoleProcessShutdown(IN PCSRSS_PROCESS_DATA Process, + IN ULONG Flags) +{ + BOOL Result; + HANDLE ProcessHandle; + ULONG CtrlEvent; + + /* Duplicate the process handle */ + //DPRINT1("Duplicating process handle\n"); + Result = DuplicateHandle(NtCurrentProcess(), + Process->Process, + NtCurrentProcess(), + &ProcessHandle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS); + if (!Result) ProcessHandle = Process->Process; + + /* Choose correct event */ + CtrlEvent = (Flags & EWX_SHUTDOWN) ? CTRL_SHUTDOWN_EVENT : CTRL_LOGOFF_EVENT; + //DPRINT1("Event to send: %lx\n", CtrlEvent); + + /* Create the thread to send it */ + //DPRINT1("Dispatcher: %p\n", Process->CtrlDispatcher); + if (Process->CtrlDispatcher) CreateCtrlThread(ProcessHandle, CtrlEvent, (PVOID)Process->CtrlDispatcher, TRUE); + + /* Close duplicated handle */ + //DPRINT1("Returned from ctrl thread\n"); + if (Result) CloseHandle(ProcessHandle); + + /* Done */ + return CsrShutdownCsrProcess; +} + +ULONG +NTAPI +ConsoleClientShutdown(IN PCSRSS_PROCESS_DATA Process, + IN ULONG Flags, + IN BOOLEAN FirstTry) +{ + PCSRSS_CONSOLE ProcessConsole; + + /* Read console data from process */ + ProcessConsole = Process->Console; + //DPRINT1("Console: %p\n", ProcessConsole); + if (!ProcessConsole) { - UserInfo = (TOKEN_USER *) FixedUserInfo; + /* On first pass, ignore the process since the GUI server should take it */ + //DPRINT1("Unknown process: %d\n", FirstTry); + if (FirstTry) return CsrShutdownNonCsrProcess; + + /* Call the generic handler */ + return NonConsoleProcessShutdown(Process, Flags); } - CloseHandle(CallerToken); - LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings); - if (UserInfo != (TOKEN_USER *) FixedUserInfo) + + /* Send a log-off event. In reality this should be way more complex */ + //DPRINT1("Using legacy CSR logoff event\n"); + ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, + Process, + ShutdownSettings.WaitToKillAppTimeout); + return CsrShutdownCsrProcess; +} + +NTSTATUS +NTAPI +ShutdownProcessCallback(IN PCSRSS_PROCESS_DATA ProcessData, + IN PVOID Data) +{ + BOOLEAN FirstTry = (ULONG_PTR)Data & 1; + PULONG Context = (PVOID)((ULONG_PTR)Data &~ 1); + ULONG Flags = Context[1]; + //DPRINT1("Called for: %p with flags: %lx (FIRST: %d)\n", ProcessData, Flags, FirstTry); + + /* hack: don't touch csrss */ + if (ProcessData->ProcessId == (HANDLE)GetCurrentProcessId()) return CsrShutdownNonCsrProcess; + + /* First let the console have at it */ + ConsoleClientShutdown(ProcessData, Flags, FirstTry); + + /* Then the user server */ + + //DPRINT1("Done\n"); + return (NTSTATUS)CsrShutdownNonCsrProcess; +} + +NTSTATUS +NTAPI +IntExitWindowsEx(IN PCLIENT_ID ClientId, + IN DWORD Flags) +{ + NTSTATUS Status; + LUID SessionLuid; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE ThreadHandle, ProcessHandle; + + return STATUS_SUCCESS; + + /* Only WinLogon can call this */ + if (ClientId->UniqueProcess != LogonProcess) { - HeapFree(Win32CsrApiHeap, 0, UserInfo); + DPRINT1("Internal ExitWindowsEx call not from winlogon\n"); + return STATUS_ACCESS_DENIED; } - Context.CsrssProcess = GetCurrentProcessId(); - ShellWnd = GetShellWindow(); - if (NULL == ShellWnd) + + /* Open handles to the thread and process */ + DPRINT("PID: %lx TID: %lx\n", ClientId->UniqueProcess, ClientId->UniqueThread); + InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); + Status = NtOpenThread(&ThreadHandle, + THREAD_ALL_ACCESS, + &ObjectAttributes, + ClientId); + if (!NT_SUCCESS(Status)) { - DPRINT("No shell present\n"); - Context.ShellProcess = 0; + DPRINT1("Get thread handle Failed\n"); + CsrRevertToSelf(); + return Status; } - else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess)) + + /* Open handles to the thread and process */ + Status = NtOpenProcess(&ProcessHandle, + PROCESS_ALL_ACCESS, + &ObjectAttributes, + ClientId); + if (!NT_SUCCESS(Status)) { - DPRINT1("Can't get process id of shell window\n"); - Context.ShellProcess = 0; + DPRINT1("Get process handle Failed\n"); + CsrRevertToSelf(); + return Status; } - - Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context); - if (! NT_SUCCESS(Status)) + + /* Impersonate the client */ + if (!CsrImpersonateClient(ThreadHandle)) { - DPRINT1("Failed to enumerate registered processes, status 0x%x\n", - Status); - if (NULL != Context.ProcessData) - { - HeapFree(Win32CsrApiHeap, 0, Context.ProcessData); - } - return Status; + DPRINT1("Impersonation failed\n"); + return STATUS_BAD_IMPERSONATION_LEVEL; } - - 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++) + + /* Get the LUID for this shutdown */ + Status = CsrGetProcessLuid(NULL, &SessionLuid); + if (!NT_SUCCESS(Status)) { - if (! NotifyAndTerminateProcess(Context.ProcessData[ProcessIndex], - &ShutdownSettings, Flags)) + DPRINT1("Get LUID Failed\n"); + CsrRevertToSelf(); + return Status; + } + + DPRINT("Session LUID is: %lx.%lx\n", SessionLuid.HighPart, SessionLuid.LowPart); + + /* Shutdown loop */ + while (TRUE) + { + /* Notify kernel mode user */ + Status = NtUserSetInformationThread(ThreadHandle, + UserThreadInitiateShutdown, + &Flags, + sizeof(Flags)); + DPRINT("Win32k says: %lx\n", Status); + switch (Status) { - Status = STATUS_REQUEST_ABORTED; + /* In progress already */ + case STATUS_PENDING: + + DPRINT1("Unwritten path\n"); + while (TRUE); + break; + + /* Abort */ + case STATUS_RETRY: + + DPRINT1("Unwritten path\n"); + while (TRUE); + break; + + /* Start a new thread */ + case STATUS_CANT_WAIT: + + DPRINT1("Unwritten path\n"); + while (TRUE); + break; + + default: + + ASSERT(Status == STATUS_SUCCESS); + break; } + + /* All good */ + break; } - /* Cleanup */ - if (NULL != Context.ProcessData) - { - HeapFree(Win32CsrApiHeap, 0, Context.ProcessData); - } + /* Call CSRSRV to perform the shutdown */ + CsrShutdownProcesses(&SessionLuid, Flags); + + /* Tell kernel mode user we're done */ + NtUserSetInformationThread(ThreadHandle, UserThreadEndShutdown, &Status, sizeof(Status)); - return Status; + /* Revert */ + CsrRevertToSelf(); + + /* Return exit status */ + return Status; } static NTSTATUS FASTCALL @@ -922,21 +1222,17 @@ CSR_API(CsrExitReactos) { - Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE); - Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - + 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)) + if (!(Request->Data.ExitReactosRequest.Flags & EWX_INTERNAL_FLAG)) { - return UserExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess, - Request->Data.ExitReactosRequest.Flags); + return UserExitReactos((DWORD) Request->Header.ClientId.UniqueProcess, + Request->Data.ExitReactosRequest.Flags); } - else - { - return InternalExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess, - (DWORD_PTR) Request->Header.ClientId.UniqueThread, - Request->Data.ExitReactosRequest.Flags); - } + + return IntExitWindowsEx(&Request->Header.ClientId, Request->Data.ExitReactosRequest.Flags); } /* EOF */