xref: /reactos/base/applications/taskmgr/endproc.c (revision 5d1be078)
1 /*
2  * PROJECT:     ReactOS Task Manager
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Process Termination.
5  * COPYRIGHT:   Copyright 1999-2001 Brian Palmer <brianp@reactos.org>
6  *              Copyright 2005 Klemens Friedl <frik85@reactos.at>
7  *              Copyright 2014 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
8  */
9 
10 #include "precomp.h"
11 
12 #define NTOS_MODE_USER
13 #include <ndk/psfuncs.h>
14 
ProcessPage_OnEndProcess(void)15 void ProcessPage_OnEndProcess(void)
16 {
17     DWORD   dwProcessId;
18     HANDLE  hProcess;
19     WCHAR   szTitle[256];
20     WCHAR   strErrorText[260];
21 
22     dwProcessId = GetSelectedProcessId();
23 
24     if (dwProcessId == 0)
25         return;
26 
27     hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
28 
29     /* forbid killing system processes even if we have privileges -- sigh, windows kludge! */
30     if (hProcess && IsCriticalProcess(hProcess))
31     {
32         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
33         LoadStringW(hInst, IDS_MSG_CLOSESYSTEMPROCESS, strErrorText, 256);
34         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONWARNING|MB_TOPMOST);
35         CloseHandle(hProcess);
36         return;
37     }
38 
39     /* if this is a standard process just ask for confirmation before doing it */
40     LoadStringW(hInst, IDS_MSG_WARNINGTERMINATING, strErrorText, 256);
41     LoadStringW(hInst, IDS_MSG_TASKMGRWARNING, szTitle, 256);
42     if (!ConfirmMessageBox(hMainWnd, strErrorText, szTitle, MB_YESNO|MB_ICONWARNING|MB_TOPMOST))
43     {
44         if (hProcess) CloseHandle(hProcess);
45         return;
46     }
47 
48     /* no such process or not enough privileges to open its token */
49     if (!hProcess)
50     {
51         GetLastErrorText(strErrorText, 260);
52         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
53         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONSTOP|MB_TOPMOST);
54         return;
55     }
56 
57     /* try to kill it, and notify the user if didn't work */
58     if (!TerminateProcess(hProcess, 1))
59     {
60         GetLastErrorText(strErrorText, 260);
61         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
62         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONSTOP|MB_TOPMOST);
63     }
64 
65     CloseHandle(hProcess);
66 }
67 
IsCriticalProcess(HANDLE hProcess)68 BOOL IsCriticalProcess(HANDLE hProcess)
69 {
70     NTSTATUS status;
71     ULONG BreakOnTermination;
72 
73     /* return early if the process handle does not exist */
74     if (!hProcess)
75         return FALSE;
76 
77     /* the important system processes that we don't want to let the user
78        kill come marked as critical, this simplifies the check greatly.
79 
80        a critical process brings the system down when is terminated:
81        <http://www.geoffchappell.com/studies/windows/win32/ntdll/api/rtl/peb/setprocessiscritical.htm> */
82 
83     status = NtQueryInformationProcess(hProcess,
84                                        ProcessBreakOnTermination,
85                                        &BreakOnTermination,
86                                        sizeof(ULONG),
87                                        NULL);
88 
89     if (NT_SUCCESS(status) && BreakOnTermination)
90         return TRUE;
91 
92     return FALSE;
93 }
94 
ShutdownProcessTreeHelper(HANDLE hSnapshot,HANDLE hParentProcess,DWORD dwParentPID)95 BOOL ShutdownProcessTreeHelper(HANDLE hSnapshot, HANDLE hParentProcess, DWORD dwParentPID)
96 {
97     HANDLE hChildHandle;
98     PROCESSENTRY32W ProcessEntry = {0};
99     ProcessEntry.dwSize = sizeof(ProcessEntry);
100 
101     if (Process32FirstW(hSnapshot, &ProcessEntry))
102     {
103         do
104         {
105             if (ProcessEntry.th32ParentProcessID == dwParentPID)
106             {
107                 hChildHandle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
108                                            FALSE,
109                                            ProcessEntry.th32ProcessID);
110                 if (!hChildHandle || IsCriticalProcess(hChildHandle))
111                 {
112                     if (hChildHandle)
113                     {
114                         CloseHandle(hChildHandle);
115                     }
116                     continue;
117                 }
118                 if (!ShutdownProcessTreeHelper(hSnapshot, hChildHandle, ProcessEntry.th32ProcessID))
119                 {
120                     CloseHandle(hChildHandle);
121                     return FALSE;
122                 }
123                 CloseHandle(hChildHandle);
124             }
125         } while (Process32NextW(hSnapshot, &ProcessEntry));
126     }
127 
128     return TerminateProcess(hParentProcess, 0);
129 }
130 
ShutdownProcessTree(HANDLE hParentProcess,DWORD dwParentPID)131 BOOL ShutdownProcessTree(HANDLE hParentProcess, DWORD dwParentPID)
132 {
133     HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
134     BOOL bResult;
135 
136     if (!hSnapshot)
137     {
138         return FALSE;
139     }
140 
141     bResult = ShutdownProcessTreeHelper(hSnapshot, hParentProcess, dwParentPID);
142     CloseHandle(hSnapshot);
143     return bResult;
144 }
145 
ProcessPage_OnEndProcessTree(void)146 void ProcessPage_OnEndProcessTree(void)
147 {
148     DWORD   dwProcessId;
149     HANDLE  hProcess;
150     WCHAR   szTitle[256];
151     WCHAR   strErrorText[260];
152 
153     dwProcessId = GetSelectedProcessId();
154 
155     if (dwProcessId == 0)
156         return;
157 
158     hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
159 
160     /* forbid killing system processes even if we have privileges -- sigh, windows kludge! */
161     if (hProcess && IsCriticalProcess(hProcess))
162     {
163         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
164         LoadStringW(hInst, IDS_MSG_CLOSESYSTEMPROCESS, strErrorText, 256);
165         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONWARNING|MB_TOPMOST);
166         CloseHandle(hProcess);
167         return;
168     }
169 
170     LoadStringW(hInst, IDS_MSG_WARNINGTERMINATING, strErrorText, 256);
171     LoadStringW(hInst, IDS_MSG_TASKMGRWARNING, szTitle, 256);
172     if (!ConfirmMessageBox(hMainWnd, strErrorText, szTitle, MB_YESNO|MB_ICONWARNING))
173     {
174         if (hProcess) CloseHandle(hProcess);
175         return;
176     }
177 
178     if (!hProcess)
179     {
180         GetLastErrorText(strErrorText, 260);
181         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
182         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONSTOP);
183         return;
184     }
185 
186     if (!ShutdownProcessTree(hProcess, dwProcessId))
187     {
188         GetLastErrorText(strErrorText, 260);
189         LoadStringW(hInst, IDS_MSG_UNABLETERMINATEPRO, szTitle, 256);
190         MessageBoxW(hMainWnd, strErrorText, szTitle, MB_OK|MB_ICONSTOP);
191     }
192 
193     CloseHandle(hProcess);
194 }
195