Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenexitros.c
Go to the documentation of this file.
00001 /* $Id: exitros.c 55696 2012-02-19 03:51:36Z ion $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS CSRSS subsystem 00005 * FILE: subsys/csrss/win32csr/exitros.c 00006 * PURPOSE: Logout/shutdown 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 #define NDEBUG 00011 #include "w32csr.h" 00012 #include <sddl.h> 00013 #include "resource.h" 00014 #include <debug.h> 00015 00016 static HWND LogonNotifyWindow = NULL; 00017 static HANDLE LogonProcess = NULL; 00018 00019 CSR_API(CsrRegisterLogonProcess) 00020 { 00021 if (Request->Data.RegisterLogonProcessRequest.Register) 00022 { 00023 if (0 != LogonProcess) 00024 { 00025 return STATUS_LOGON_SESSION_EXISTS; 00026 } 00027 LogonProcess = Request->Data.RegisterLogonProcessRequest.ProcessId; 00028 } 00029 else 00030 { 00031 if (Request->Header.ClientId.UniqueProcess != LogonProcess) 00032 { 00033 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n", 00034 LogonProcess, Request->Header.ClientId.UniqueProcess); 00035 return STATUS_NOT_LOGON_PROCESS; 00036 } 00037 LogonProcess = 0; 00038 } 00039 00040 return STATUS_SUCCESS; 00041 } 00042 00043 CSR_API(CsrSetLogonNotifyWindow) 00044 { 00045 DWORD WindowCreator; 00046 00047 if (0 == GetWindowThreadProcessId(Request->Data.SetLogonNotifyWindowRequest.LogonNotifyWindow, 00048 &WindowCreator)) 00049 { 00050 DPRINT1("Can't get window creator\n"); 00051 return STATUS_INVALID_HANDLE; 00052 } 00053 if (WindowCreator != (DWORD_PTR)LogonProcess) 00054 { 00055 DPRINT1("Trying to register window not created by winlogon as notify window\n"); 00056 return STATUS_ACCESS_DENIED; 00057 } 00058 00059 LogonNotifyWindow = Request->Data.SetLogonNotifyWindowRequest.LogonNotifyWindow; 00060 00061 return STATUS_SUCCESS; 00062 } 00063 00064 typedef struct tagSHUTDOWN_SETTINGS 00065 { 00066 BOOL AutoEndTasks; 00067 DWORD HungAppTimeout; 00068 DWORD WaitToKillAppTimeout; 00069 } SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS; 00070 00071 #define DEFAULT_AUTO_END_TASKS FALSE 00072 #define DEFAULT_HUNG_APP_TIMEOUT 5000 00073 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000 00074 00075 typedef struct tagNOTIFY_CONTEXT 00076 { 00077 DWORD ProcessId; 00078 UINT Msg; 00079 WPARAM wParam; 00080 LPARAM lParam; 00081 HDESK Desktop; 00082 DWORD StartTime; 00083 DWORD QueryResult; 00084 HWND Dlg; 00085 DWORD EndNowResult; 00086 BOOL ShowUI; 00087 HANDLE UIThread; 00088 HWND WndClient; 00089 PSHUTDOWN_SETTINGS ShutdownSettings; 00090 LPTHREAD_START_ROUTINE SendMessageProc; 00091 } NOTIFY_CONTEXT, *PNOTIFY_CONTEXT; 00092 00093 #define QUERY_RESULT_ABORT 0 00094 #define QUERY_RESULT_CONTINUE 1 00095 #define QUERY_RESULT_TIMEOUT 2 00096 #define QUERY_RESULT_ERROR 3 00097 #define QUERY_RESULT_FORCE 4 00098 00099 static void FASTCALL 00100 UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext) 00101 { 00102 DWORD Passed; 00103 00104 Passed = GetTickCount() - NotifyContext->StartTime; 00105 Passed -= NotifyContext->ShutdownSettings->HungAppTimeout; 00106 if (NotifyContext->ShutdownSettings->WaitToKillAppTimeout < Passed) 00107 { 00108 Passed = NotifyContext->ShutdownSettings->WaitToKillAppTimeout; 00109 } 00110 SendMessageW(ProgressBar, PBM_SETPOS, Passed / 2, 0); 00111 } 00112 00113 static INT_PTR CALLBACK 00114 EndNowDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam) 00115 { 00116 INT_PTR Result; 00117 PNOTIFY_CONTEXT NotifyContext; 00118 HWND ProgressBar; 00119 DWORD TitleLength; 00120 int Len; 00121 LPWSTR Title; 00122 00123 switch(Msg) 00124 { 00125 case WM_INITDIALOG: 00126 NotifyContext = (PNOTIFY_CONTEXT) lParam; 00127 NotifyContext->EndNowResult = QUERY_RESULT_ABORT; 00128 SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR) lParam); 00129 TitleLength = SendMessageW(NotifyContext->WndClient, WM_GETTEXTLENGTH, 00130 0, 0) + 00131 GetWindowTextLengthW(Dlg); 00132 Title = HeapAlloc(Win32CsrApiHeap, 0, (TitleLength + 1) * sizeof(WCHAR)); 00133 if (NULL != Title) 00134 { 00135 Len = GetWindowTextW(Dlg, Title, TitleLength + 1); 00136 SendMessageW(NotifyContext->WndClient, WM_GETTEXT, 00137 TitleLength + 1 - Len, (LPARAM) (Title + Len)); 00138 SetWindowTextW(Dlg, Title); 00139 HeapFree(Win32CsrApiHeap, 0, Title); 00140 } 00141 ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS); 00142 SendMessageW(ProgressBar, PBM_SETRANGE32, 0, 00143 NotifyContext->ShutdownSettings->WaitToKillAppTimeout / 2); 00144 UpdateProgressBar(ProgressBar, NotifyContext); 00145 SetTimer(Dlg, 0, 200, NULL); 00146 Result = FALSE; 00147 break; 00148 00149 case WM_TIMER: 00150 NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER); 00151 ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS); 00152 UpdateProgressBar(ProgressBar, NotifyContext); 00153 Result = TRUE; 00154 break; 00155 00156 case WM_COMMAND: 00157 if (BN_CLICKED == HIWORD(wParam) && IDC_END_NOW == LOWORD(wParam)) 00158 { 00159 NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER); 00160 NotifyContext->EndNowResult = QUERY_RESULT_FORCE; 00161 SendMessageW(Dlg, WM_CLOSE, 0, 0); 00162 Result = TRUE; 00163 } 00164 else 00165 { 00166 Result = FALSE; 00167 } 00168 break; 00169 00170 case WM_CLOSE: 00171 DestroyWindow(Dlg); 00172 Result = TRUE; 00173 break; 00174 00175 case WM_DESTROY: 00176 NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER); 00177 NotifyContext->Dlg = NULL; 00178 KillTimer(Dlg, 0); 00179 PostQuitMessage(NotifyContext->EndNowResult); 00180 Result = TRUE; 00181 break; 00182 00183 default: 00184 Result = FALSE; 00185 break; 00186 } 00187 00188 return Result; 00189 } 00190 00191 typedef void (WINAPI *INITCOMMONCONTROLS_PROC)(void); 00192 00193 static void 00194 CallInitCommonControls() 00195 { 00196 static BOOL Initialized = FALSE; 00197 HMODULE Lib; 00198 INITCOMMONCONTROLS_PROC InitProc; 00199 00200 if (Initialized) 00201 { 00202 return; 00203 } 00204 00205 Lib = LoadLibraryW(L"COMCTL32.DLL"); 00206 if (NULL == Lib) 00207 { 00208 return; 00209 } 00210 InitProc = (INITCOMMONCONTROLS_PROC) GetProcAddress(Lib, "InitCommonControls"); 00211 if (NULL == InitProc) 00212 { 00213 return; 00214 } 00215 00216 (*InitProc)(); 00217 00218 Initialized = TRUE; 00219 } 00220 00221 static DWORD WINAPI 00222 EndNowThreadProc(LPVOID Parameter) 00223 { 00224 PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) Parameter; 00225 MSG Msg; 00226 00227 SetThreadDesktop(NotifyContext->Desktop); 00228 SwitchDesktop(NotifyContext->Desktop); 00229 CallInitCommonControls(); 00230 NotifyContext->Dlg = CreateDialogParam(GetModuleHandleW(L"win32csr"), 00231 MAKEINTRESOURCE(IDD_END_NOW), NULL, 00232 EndNowDlgProc, (LPARAM) NotifyContext); 00233 if (NULL == NotifyContext->Dlg) 00234 { 00235 return 0; 00236 } 00237 ShowWindow(NotifyContext->Dlg, SW_SHOWNORMAL); 00238 00239 while (GetMessageW(&Msg, NULL, 0, 0)) 00240 { 00241 if (! IsDialogMessage(NotifyContext->Dlg, &Msg)) 00242 { 00243 TranslateMessage(&Msg); 00244 DispatchMessageW(&Msg); 00245 } 00246 } 00247 00248 return Msg.wParam; 00249 } 00250 00251 typedef struct tagMESSAGE_CONTEXT 00252 { 00253 HWND Wnd; 00254 UINT Msg; 00255 WPARAM wParam; 00256 LPARAM lParam; 00257 DWORD Timeout; 00258 } MESSAGE_CONTEXT, *PMESSAGE_CONTEXT; 00259 00260 static DWORD WINAPI 00261 SendQueryEndSession(LPVOID Parameter) 00262 { 00263 PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter; 00264 DWORD_PTR Result; 00265 00266 if (SendMessageTimeoutW(Context->Wnd, WM_QUERYENDSESSION, Context->wParam, 00267 Context->lParam, SMTO_NORMAL, Context->Timeout, 00268 &Result)) 00269 { 00270 return Result ? QUERY_RESULT_CONTINUE : QUERY_RESULT_ABORT; 00271 } 00272 00273 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR; 00274 } 00275 00276 static DWORD WINAPI 00277 SendEndSession(LPVOID Parameter) 00278 { 00279 PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter; 00280 DWORD_PTR Result; 00281 00282 if (Context->wParam) 00283 { 00284 if (SendMessageTimeoutW(Context->Wnd, WM_ENDSESSION, Context->wParam, 00285 Context->lParam, SMTO_NORMAL, Context->Timeout, 00286 &Result)) 00287 { 00288 return QUERY_RESULT_CONTINUE; 00289 } 00290 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR; 00291 } 00292 else 00293 { 00294 SendMessage(Context->Wnd, WM_ENDSESSION, Context->wParam, 00295 Context->lParam); 00296 return QUERY_RESULT_CONTINUE; 00297 } 00298 } 00299 00300 static BOOL CALLBACK 00301 NotifyTopLevelEnum(HWND Wnd, LPARAM lParam) 00302 { 00303 PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) lParam; 00304 MESSAGE_CONTEXT MessageContext; 00305 DWORD Now, Passed; 00306 DWORD Timeout, WaitStatus; 00307 DWORD ProcessId; 00308 HANDLE MessageThread; 00309 HANDLE Threads[2]; 00310 00311 if (0 == GetWindowThreadProcessId(Wnd, &ProcessId)) 00312 { 00313 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00314 return FALSE; 00315 } 00316 00317 if (ProcessId == NotifyContext->ProcessId) 00318 { 00319 Now = GetTickCount(); 00320 if (0 == NotifyContext->StartTime) 00321 { 00322 NotifyContext->StartTime = Now; 00323 } 00324 /* Note: Passed is computed correctly even when GetTickCount() wraps due 00325 to unsigned arithmetic */ 00326 Passed = Now - NotifyContext->StartTime; 00327 MessageContext.Wnd = Wnd; 00328 MessageContext.Msg = NotifyContext->Msg; 00329 MessageContext.wParam = NotifyContext->wParam; 00330 MessageContext.lParam = NotifyContext->lParam; 00331 MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout; 00332 if (! NotifyContext->ShutdownSettings->AutoEndTasks) 00333 { 00334 MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout; 00335 } 00336 if (Passed < MessageContext.Timeout) 00337 { 00338 MessageContext.Timeout -= Passed; 00339 MessageThread = CreateThread(NULL, 0, NotifyContext->SendMessageProc, 00340 (LPVOID) &MessageContext, 0, NULL); 00341 if (NULL == MessageThread) 00342 { 00343 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00344 return FALSE; 00345 } 00346 Timeout = NotifyContext->ShutdownSettings->HungAppTimeout; 00347 if (Passed < Timeout) 00348 { 00349 Timeout -= Passed; 00350 WaitStatus = WaitForSingleObjectEx(MessageThread, Timeout, FALSE); 00351 } 00352 else 00353 { 00354 WaitStatus = WAIT_TIMEOUT; 00355 } 00356 if (WAIT_TIMEOUT == WaitStatus) 00357 { 00358 NotifyContext->WndClient = Wnd; 00359 if (NULL == NotifyContext->UIThread && NotifyContext->ShowUI) 00360 { 00361 NotifyContext->UIThread = CreateThread(NULL, 0, 00362 EndNowThreadProc, 00363 (LPVOID) NotifyContext, 00364 0, NULL); 00365 } 00366 Threads[0] = MessageThread; 00367 Threads[1] = NotifyContext->UIThread; 00368 WaitStatus = WaitForMultipleObjectsEx(NULL == NotifyContext->UIThread ? 00369 1 : 2, 00370 Threads, FALSE, INFINITE, 00371 FALSE); 00372 if (WAIT_OBJECT_0 == WaitStatus) 00373 { 00374 if (! GetExitCodeThread(MessageThread, &NotifyContext->QueryResult)) 00375 { 00376 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00377 } 00378 } 00379 else if (WAIT_OBJECT_0 + 1 == WaitStatus) 00380 { 00381 if (! GetExitCodeThread(NotifyContext->UIThread, 00382 &NotifyContext->QueryResult)) 00383 { 00384 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00385 } 00386 } 00387 else 00388 { 00389 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00390 } 00391 if (WAIT_OBJECT_0 != WaitStatus) 00392 { 00393 TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT); 00394 } 00395 } 00396 else if (WAIT_OBJECT_0 == WaitStatus) 00397 { 00398 if (! GetExitCodeThread(MessageThread, 00399 &NotifyContext->QueryResult)) 00400 { 00401 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00402 } 00403 } 00404 else 00405 { 00406 NotifyContext->QueryResult = QUERY_RESULT_ERROR; 00407 } 00408 CloseHandle(MessageThread); 00409 } 00410 else 00411 { 00412 NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT; 00413 } 00414 } 00415 00416 return QUERY_RESULT_CONTINUE == NotifyContext->QueryResult; 00417 } 00418 00419 static BOOL CALLBACK 00420 NotifyDesktopEnum(LPWSTR DesktopName, LPARAM lParam) 00421 { 00422 PNOTIFY_CONTEXT Context = (PNOTIFY_CONTEXT) lParam; 00423 00424 Context->Desktop = OpenDesktopW(DesktopName, 0, FALSE, 00425 DESKTOP_ENUMERATE | DESKTOP_SWITCHDESKTOP); 00426 if (NULL == Context->Desktop) 00427 { 00428 DPRINT1("OpenDesktop failed with error %d\n", GetLastError()); 00429 Context->QueryResult = QUERY_RESULT_ERROR; 00430 return FALSE; 00431 } 00432 00433 EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam); 00434 00435 CloseDesktop(Context->Desktop); 00436 00437 return QUERY_RESULT_CONTINUE == Context->QueryResult; 00438 } 00439 00440 static BOOL FASTCALL 00441 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context) 00442 { 00443 HWINSTA WindowStation; 00444 00445 WindowStation = GetProcessWindowStation(); 00446 if (NULL == WindowStation) 00447 { 00448 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError()); 00449 return TRUE; 00450 } 00451 00452 EnumDesktopsW(WindowStation, NotifyDesktopEnum, (LPARAM) Context); 00453 00454 return TRUE; 00455 } 00456 00457 static BOOL FASTCALL 00458 NotifyAndTerminateProcess(PCSR_PROCESS ProcessData, 00459 PSHUTDOWN_SETTINGS ShutdownSettings, 00460 UINT Flags) 00461 { 00462 NOTIFY_CONTEXT Context; 00463 HANDLE Process; 00464 DWORD QueryResult = QUERY_RESULT_CONTINUE; 00465 00466 Context.QueryResult = QUERY_RESULT_CONTINUE; 00467 00468 if (0 == (Flags & EWX_FORCE)) 00469 { 00470 if (NULL != ProcessData->Console) 00471 { 00472 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, ProcessData, 00473 ShutdownSettings->WaitToKillAppTimeout); 00474 } 00475 else 00476 { 00477 Context.ProcessId = (DWORD_PTR) ProcessData->ClientId.UniqueProcess; 00478 Context.wParam = 0; 00479 Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ? 00480 ENDSESSION_LOGOFF : 0); 00481 Context.StartTime = 0; 00482 Context.UIThread = NULL; 00483 Context.ShowUI = DtbgIsDesktopVisible(); 00484 Context.Dlg = NULL; 00485 Context.ShutdownSettings = ShutdownSettings; 00486 Context.SendMessageProc = SendQueryEndSession; 00487 00488 NotifyTopLevelWindows(&Context); 00489 00490 Context.wParam = (QUERY_RESULT_ABORT != Context.QueryResult); 00491 Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ? 00492 ENDSESSION_LOGOFF : 0); 00493 Context.SendMessageProc = SendEndSession; 00494 Context.ShowUI = DtbgIsDesktopVisible() && 00495 (QUERY_RESULT_ABORT != Context.QueryResult); 00496 QueryResult = Context.QueryResult; 00497 Context.QueryResult = QUERY_RESULT_CONTINUE; 00498 00499 NotifyTopLevelWindows(&Context); 00500 00501 if (NULL != Context.UIThread) 00502 { 00503 if (NULL != Context.Dlg) 00504 { 00505 SendMessageW(Context.Dlg, WM_CLOSE, 0, 0); 00506 } 00507 else 00508 { 00509 TerminateThread(Context.UIThread, QUERY_RESULT_ERROR); 00510 } 00511 CloseHandle(Context.UIThread); 00512 } 00513 } 00514 00515 if (QUERY_RESULT_ABORT == QueryResult) 00516 { 00517 return FALSE; 00518 } 00519 } 00520 00521 /* Terminate this process */ 00522 Process = OpenProcess(PROCESS_TERMINATE, FALSE, 00523 (DWORD_PTR) ProcessData->ClientId.UniqueProcess); 00524 if (NULL == Process) 00525 { 00526 DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess, 00527 GetLastError()); 00528 return TRUE; 00529 } 00530 TerminateProcess(Process, 0); 00531 CloseHandle(Process); 00532 00533 return TRUE; 00534 } 00535 00536 typedef struct tagPROCESS_ENUM_CONTEXT 00537 { 00538 UINT ProcessCount; 00539 PCSR_PROCESS *ProcessData; 00540 TOKEN_ORIGIN TokenOrigin; 00541 DWORD ShellProcess; 00542 DWORD CsrssProcess; 00543 } PROCESS_ENUM_CONTEXT, *PPROCESS_ENUM_CONTEXT; 00544 00545 static NTSTATUS WINAPI 00546 ExitReactosProcessEnum(PCSR_PROCESS ProcessData, PVOID Data) 00547 { 00548 HANDLE Process; 00549 HANDLE Token; 00550 TOKEN_ORIGIN Origin; 00551 DWORD ReturnLength; 00552 PPROCESS_ENUM_CONTEXT Context = (PPROCESS_ENUM_CONTEXT) Data; 00553 PCSR_PROCESS *NewData; 00554 00555 /* Do not kill winlogon or csrss */ 00556 if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->CsrssProcess || 00557 ProcessData->ClientId.UniqueProcess == LogonProcess) 00558 { 00559 return STATUS_SUCCESS; 00560 } 00561 00562 /* Get the login session of this process */ 00563 Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, 00564 (DWORD_PTR) ProcessData->ClientId.UniqueProcess); 00565 if (NULL == Process) 00566 { 00567 DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess, 00568 GetLastError()); 00569 return STATUS_UNSUCCESSFUL; 00570 } 00571 00572 if (! OpenProcessToken(Process, TOKEN_QUERY, &Token)) 00573 { 00574 DPRINT1("Unable to open token for process %d, error %d\n", 00575 ProcessData->ClientId.UniqueProcess, GetLastError()); 00576 CloseHandle(Process); 00577 return STATUS_UNSUCCESSFUL; 00578 } 00579 CloseHandle(Process); 00580 00581 if (! GetTokenInformation(Token, TokenOrigin, &Origin, 00582 sizeof(TOKEN_ORIGIN), &ReturnLength)) 00583 { 00584 DPRINT1("GetTokenInformation failed for process %d with error %d\n", 00585 ProcessData->ClientId.UniqueProcess, GetLastError()); 00586 CloseHandle(Token); 00587 return STATUS_UNSUCCESSFUL; 00588 } 00589 CloseHandle(Token); 00590 00591 /* This process will be killed if it's in the correct logon session */ 00592 if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession), 00593 &(Origin.OriginatingLogonSession))) 00594 { 00595 /* Kill the shell process last */ 00596 if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->ShellProcess) 00597 { 00598 ProcessData->ShutdownLevel = 0; 00599 } 00600 NewData = HeapAlloc(Win32CsrApiHeap, 0, (Context->ProcessCount + 1) 00601 * sizeof(PCSR_PROCESS)); 00602 if (NULL == NewData) 00603 { 00604 return STATUS_NO_MEMORY; 00605 } 00606 if (0 != Context->ProcessCount) 00607 { 00608 memcpy(NewData, Context->ProcessData, 00609 Context->ProcessCount * sizeof(PCSR_PROCESS)); 00610 HeapFree(Win32CsrApiHeap, 0, Context->ProcessData); 00611 } 00612 Context->ProcessData = NewData; 00613 Context->ProcessData[Context->ProcessCount] = ProcessData; 00614 Context->ProcessCount++; 00615 } 00616 00617 return STATUS_SUCCESS; 00618 } 00619 00620 static int 00621 ProcessDataCompare(const void *Elem1, const void *Elem2) 00622 { 00623 const PCSR_PROCESS *ProcessData1 = (PCSR_PROCESS *) Elem1; 00624 const PCSR_PROCESS *ProcessData2 = (PCSR_PROCESS *) Elem2; 00625 00626 if ((*ProcessData1)->ShutdownLevel < (*ProcessData2)->ShutdownLevel) 00627 { 00628 return +1; 00629 } 00630 else if ((*ProcessData2)->ShutdownLevel < (*ProcessData1)->ShutdownLevel) 00631 { 00632 return -1; 00633 } 00634 else if ((*ProcessData1)->ClientId.UniqueProcess < (*ProcessData2)->ClientId.UniqueProcess) 00635 { 00636 return +1; 00637 } 00638 else if ((*ProcessData2)->ClientId.UniqueProcess < (*ProcessData1)->ClientId.UniqueProcess) 00639 { 00640 return -1; 00641 } 00642 00643 return 0; 00644 } 00645 00646 static DWORD FASTCALL 00647 GetShutdownSetting(HKEY DesktopKey, LPCWSTR ValueName, DWORD DefaultValue) 00648 { 00649 BYTE ValueBuffer[16]; 00650 LONG ErrCode; 00651 DWORD Type; 00652 DWORD ValueSize; 00653 UNICODE_STRING StringValue; 00654 ULONG Value; 00655 00656 ValueSize = sizeof(ValueBuffer); 00657 ErrCode = RegQueryValueExW(DesktopKey, ValueName, NULL, &Type, ValueBuffer, 00658 &ValueSize); 00659 if (ERROR_SUCCESS != ErrCode) 00660 { 00661 DPRINT("GetShutdownSetting for %S failed with error code %ld\n", 00662 ValueName, ErrCode); 00663 return DefaultValue; 00664 } 00665 00666 if (REG_SZ == Type) 00667 { 00668 RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer); 00669 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value))) 00670 { 00671 DPRINT1("Unable to convert value %S for setting %S\n", 00672 StringValue.Buffer, ValueName); 00673 return DefaultValue; 00674 } 00675 return (DWORD) Value; 00676 } 00677 else if (REG_DWORD == Type) 00678 { 00679 return *((DWORD *) ValueBuffer); 00680 } 00681 00682 DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName); 00683 return DefaultValue; 00684 } 00685 00686 static void FASTCALL 00687 LoadShutdownSettings(PSID Sid, PSHUTDOWN_SETTINGS ShutdownSettings) 00688 { 00689 static WCHAR Subkey[] = L"\\Control Panel\\Desktop"; 00690 LPWSTR StringSid; 00691 WCHAR InitialKeyName[128]; 00692 LPWSTR KeyName; 00693 HKEY DesktopKey; 00694 LONG ErrCode; 00695 00696 ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS; 00697 ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT; 00698 ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT; 00699 00700 if (! ConvertSidToStringSidW(Sid, &StringSid)) 00701 { 00702 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n", 00703 GetLastError()); 00704 return; 00705 } 00706 if (wcslen(StringSid) + wcslen(Subkey) + 1 <= 00707 sizeof(InitialKeyName) / sizeof(WCHAR)) 00708 { 00709 KeyName = InitialKeyName; 00710 } 00711 else 00712 { 00713 KeyName = HeapAlloc(Win32CsrApiHeap, 0, 00714 (wcslen(StringSid) + wcslen(Subkey) + 1) * 00715 sizeof(WCHAR)); 00716 if (NULL == KeyName) 00717 { 00718 DPRINT1("Failed to allocate memory, using default shutdown settings\n"); 00719 LocalFree(StringSid); 00720 return; 00721 } 00722 } 00723 wcscat(wcscpy(KeyName, StringSid), Subkey); 00724 LocalFree(StringSid); 00725 00726 ErrCode = RegOpenKeyExW(HKEY_USERS, KeyName, 0, KEY_QUERY_VALUE, &DesktopKey); 00727 if (KeyName != InitialKeyName) 00728 { 00729 HeapFree(Win32CsrApiHeap, 0, KeyName); 00730 } 00731 if (ERROR_SUCCESS != ErrCode) 00732 { 00733 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode); 00734 return; 00735 } 00736 00737 ShutdownSettings->AutoEndTasks = (BOOL) GetShutdownSetting(DesktopKey, L"AutoEndTasks", 00738 (DWORD) DEFAULT_AUTO_END_TASKS); 00739 ShutdownSettings->HungAppTimeout = GetShutdownSetting(DesktopKey, 00740 L"HungAppTimeout", 00741 DEFAULT_HUNG_APP_TIMEOUT); 00742 ShutdownSettings->WaitToKillAppTimeout = GetShutdownSetting(DesktopKey, 00743 L"WaitToKillAppTimeout", 00744 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT); 00745 00746 RegCloseKey(DesktopKey); 00747 } 00748 00749 static NTSTATUS FASTCALL 00750 InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags) 00751 { 00752 HANDLE CallerThread; 00753 HANDLE CallerToken; 00754 NTSTATUS Status; 00755 PROCESS_ENUM_CONTEXT Context; 00756 DWORD ReturnLength; 00757 HWND ShellWnd; 00758 UINT ProcessIndex; 00759 char FixedUserInfo[64]; 00760 TOKEN_USER *UserInfo; 00761 SHUTDOWN_SETTINGS ShutdownSettings; 00762 00763 if (ProcessId != (DWORD_PTR) LogonProcess) 00764 { 00765 DPRINT1("Internal ExitWindowsEx call not from winlogon\n"); 00766 return STATUS_ACCESS_DENIED; 00767 } 00768 00769 DPRINT1("FIXME: Need to close all user processes!\n"); 00770 return STATUS_SUCCESS; 00771 00772 CallerThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, ThreadId); 00773 if (NULL == CallerThread) 00774 { 00775 DPRINT1("OpenThread failed with error %d\n", GetLastError()); 00776 return STATUS_UNSUCCESSFUL; 00777 } 00778 if (! OpenThreadToken(CallerThread, TOKEN_QUERY, FALSE, &CallerToken)) 00779 { 00780 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError()); 00781 CloseHandle(CallerThread); 00782 return STATUS_UNSUCCESSFUL; 00783 } 00784 CloseHandle(CallerThread); 00785 00786 Context.ProcessCount = 0; 00787 Context.ProcessData = NULL; 00788 if (! GetTokenInformation(CallerToken, TokenOrigin, &Context.TokenOrigin, 00789 sizeof(TOKEN_ORIGIN), &ReturnLength)) 00790 { 00791 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError()); 00792 CloseHandle(CallerToken); 00793 return STATUS_UNSUCCESSFUL; 00794 } 00795 if (! GetTokenInformation(CallerToken, TokenUser, FixedUserInfo, 00796 sizeof(FixedUserInfo), &ReturnLength)) 00797 { 00798 if (sizeof(FixedUserInfo) < ReturnLength) 00799 { 00800 UserInfo = HeapAlloc(Win32CsrApiHeap, 0, ReturnLength); 00801 if (NULL == UserInfo) 00802 { 00803 DPRINT1("Unable to allocate %u bytes for user info\n", 00804 (unsigned) ReturnLength); 00805 CloseHandle(CallerToken); 00806 return STATUS_NO_MEMORY; 00807 } 00808 if (! GetTokenInformation(CallerToken, TokenUser, UserInfo, 00809 ReturnLength, &ReturnLength)) 00810 { 00811 DPRINT1("GetTokenInformation failed with error %d\n", 00812 GetLastError()); 00813 HeapFree(Win32CsrApiHeap, 0, UserInfo); 00814 CloseHandle(CallerToken); 00815 return STATUS_UNSUCCESSFUL; 00816 } 00817 } 00818 else 00819 { 00820 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError()); 00821 CloseHandle(CallerToken); 00822 return STATUS_UNSUCCESSFUL; 00823 } 00824 } 00825 else 00826 { 00827 UserInfo = (TOKEN_USER *) FixedUserInfo; 00828 } 00829 CloseHandle(CallerToken); 00830 LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings); 00831 if (UserInfo != (TOKEN_USER *) FixedUserInfo) 00832 { 00833 HeapFree(Win32CsrApiHeap, 0, UserInfo); 00834 } 00835 Context.CsrssProcess = GetCurrentProcessId(); 00836 ShellWnd = GetShellWindow(); 00837 if (NULL == ShellWnd) 00838 { 00839 DPRINT("No shell present\n"); 00840 Context.ShellProcess = 0; 00841 } 00842 else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess)) 00843 { 00844 DPRINT1("Can't get process id of shell window\n"); 00845 Context.ShellProcess = 0; 00846 } 00847 00848 Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context); 00849 if (! NT_SUCCESS(Status)) 00850 { 00851 DPRINT1("Failed to enumerate registered processes, status 0x%x\n", 00852 Status); 00853 if (NULL != Context.ProcessData) 00854 { 00855 HeapFree(Win32CsrApiHeap, 0, Context.ProcessData); 00856 } 00857 return Status; 00858 } 00859 00860 qsort(Context.ProcessData, Context.ProcessCount, sizeof(PCSR_PROCESS), 00861 ProcessDataCompare); 00862 00863 /* Terminate processes, stop if we find one kicking and screaming it doesn't 00864 want to die */ 00865 Status = STATUS_SUCCESS; 00866 for (ProcessIndex = 0; 00867 ProcessIndex < Context.ProcessCount && NT_SUCCESS(Status); 00868 ProcessIndex++) 00869 { 00870 if (! NotifyAndTerminateProcess(Context.ProcessData[ProcessIndex], 00871 &ShutdownSettings, Flags)) 00872 { 00873 Status = STATUS_REQUEST_ABORTED; 00874 } 00875 } 00876 00877 /* Cleanup */ 00878 if (NULL != Context.ProcessData) 00879 { 00880 HeapFree(Win32CsrApiHeap, 0, Context.ProcessData); 00881 } 00882 00883 return Status; 00884 } 00885 00886 static NTSTATUS FASTCALL 00887 UserExitReactos(DWORD UserProcessId, UINT Flags) 00888 { 00889 NTSTATUS Status; 00890 00891 if (NULL == LogonNotifyWindow) 00892 { 00893 DPRINT1("No LogonNotifyWindow registered\n"); 00894 return STATUS_NOT_FOUND; 00895 } 00896 00897 /* FIXME Inside 2000 says we should impersonate the caller here */ 00898 Status = SendMessageW(LogonNotifyWindow, PM_WINLOGON_EXITWINDOWS, 00899 (WPARAM) UserProcessId, 00900 (LPARAM) Flags); 00901 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate 00902 success. Success is indicated by a 1 return value, if anything besides 0 00903 or 1 it's a NTSTATUS value */ 00904 if (1 == Status) 00905 { 00906 Status = STATUS_SUCCESS; 00907 } 00908 else if (0 == Status) 00909 { 00910 Status = STATUS_NOT_IMPLEMENTED; 00911 } 00912 00913 return Status; 00914 } 00915 00916 CSR_API(CsrExitReactos) 00917 { 00918 if (0 == (Request->Data.ExitReactosRequest.Flags & EWX_INTERNAL_FLAG)) 00919 { 00920 return UserExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess, 00921 Request->Data.ExitReactosRequest.Flags); 00922 } 00923 else 00924 { 00925 return InternalExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess, 00926 (DWORD_PTR) Request->Header.ClientId.UniqueThread, 00927 Request->Data.ExitReactosRequest.Flags); 00928 } 00929 } 00930 00931 /* EOF */ Generated on Sat May 26 2012 04:37:33 for ReactOS by
1.7.6.1
|