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