ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

exitros.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.