OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/win/scoped_handle.h" | |
6 #include "base/win/scoped_process_information.h" | |
7 #include "base/win/windows_version.h" | |
8 #include "sandbox/win/src/restricted_token_utils.h" | |
9 | |
10 // launcher.exe is an application used to launch another application with a | |
11 // restricted token. This is to be used for testing only. | |
12 // The parameters are the level of security of the primary token, the | |
13 // impersonation token and the job object along with the command line to | |
14 // execute. | |
15 // See the usage (launcher.exe without parameters) for the correct format. | |
16 | |
17 namespace { | |
18 | |
19 // Starts the process described by the input parameter command_line in a job | |
20 // with a restricted token. Also set the main thread of this newly created | |
21 // process to impersonate a user with more rights so it can initialize | |
22 // correctly. | |
23 // | |
24 // Parameters: primary_level is the security level of the primary token. | |
25 // impersonation_level is the security level of the impersonation token used | |
26 // to initialize the process. job_level is the security level of the job | |
27 // object used to encapsulate the process. | |
28 // | |
29 // The output parameter job_handle is the handle to the job object. Closing this | |
30 // handle will kill the process started. | |
31 // | |
32 // Note: The process started with this function has to call RevertToSelf() as | |
33 // soon as possible to stop using the impersonation token and start being | |
34 // secure. | |
35 // | |
36 // Note: The Unicode version of this function will fail if the command_line | |
37 // parameter is a const string. | |
38 DWORD StartRestrictedProcessInJob(wchar_t* command_line, | |
39 TokenLevel primary_level, | |
40 TokenLevel impersonation_level, | |
41 JobLevel job_level, | |
42 base::win::ScopedHandle* job_handle) { | |
43 Job job; | |
44 DWORD err_code = job.Init(job_level, NULL, 0, 0); | |
45 if (ERROR_SUCCESS != err_code) | |
46 return err_code; | |
47 | |
48 if (JOB_UNPROTECTED != job_level) { | |
49 // Share the Desktop handle to be able to use MessageBox() in the sandboxed | |
50 // application. | |
51 err_code = job.UserHandleGrantAccess(GetDesktopWindow()); | |
52 if (ERROR_SUCCESS != err_code) | |
53 return err_code; | |
54 } | |
55 | |
56 // Create the primary (restricted) token for the process | |
57 base::win::ScopedHandle primary_token; | |
58 err_code = sandbox::CreateRestrictedToken(primary_level, INTEGRITY_LEVEL_LAST, | |
59 PRIMARY, &primary_token); | |
60 if (ERROR_SUCCESS != err_code) | |
61 return err_code; | |
62 | |
63 | |
64 // Create the impersonation token (restricted) to be able to start the | |
65 // process. | |
66 base::win::ScopedHandle impersonation_token; | |
67 err_code = sandbox::CreateRestrictedToken(impersonation_level, | |
68 INTEGRITY_LEVEL_LAST, | |
69 IMPERSONATION, | |
70 &impersonation_token); | |
71 if (ERROR_SUCCESS != err_code) | |
72 return err_code; | |
73 | |
74 // Start the process | |
75 STARTUPINFO startup_info = {0}; | |
76 PROCESS_INFORMATION temp_process_info = {}; | |
77 DWORD flags = CREATE_SUSPENDED; | |
78 | |
79 if (base::win::GetVersion() < base::win::VERSION_WIN8) { | |
80 // Windows 8 implements nested jobs, but for older systems we need to | |
81 // break out of any job we're in to enforce our restrictions. | |
82 flags |= CREATE_BREAKAWAY_FROM_JOB; | |
83 } | |
84 | |
85 if (!::CreateProcessAsUser(primary_token.Get(), | |
86 NULL, // No application name. | |
87 command_line, | |
88 NULL, // No security attribute. | |
89 NULL, // No thread attribute. | |
90 FALSE, // Do not inherit handles. | |
91 flags, | |
92 NULL, // Use the environment of the caller. | |
93 NULL, // Use current directory of the caller. | |
94 &startup_info, | |
95 &temp_process_info)) { | |
96 return ::GetLastError(); | |
97 } | |
98 base::win::ScopedProcessInformation process_info(temp_process_info); | |
99 | |
100 // Change the token of the main thread of the new process for the | |
101 // impersonation token with more rights. | |
102 { | |
103 HANDLE temp_thread = process_info.thread_handle(); | |
104 if (!::SetThreadToken(&temp_thread, impersonation_token.Get())) { | |
105 auto last_error = ::GetLastError(); | |
106 ::TerminateProcess(process_info.process_handle(), | |
107 0); // exit code | |
108 return last_error; | |
109 } | |
110 } | |
111 | |
112 err_code = job.AssignProcessToJob(process_info.process_handle()); | |
113 if (ERROR_SUCCESS != err_code) { | |
114 auto last_error = ::GetLastError(); | |
115 ::TerminateProcess(process_info.process_handle(), | |
116 0); // exit code | |
117 return last_error; | |
118 } | |
119 | |
120 // Start the application | |
121 ::ResumeThread(process_info.thread_handle()); | |
122 | |
123 *job_handle = job.Take(); | |
124 | |
125 return ERROR_SUCCESS; | |
126 } | |
127 | |
128 } // namespace | |
129 | |
130 #define PARAM_IS(y) (argc > i) && (_wcsicmp(argv[i], y) == 0) | |
131 | |
132 void PrintUsage(const wchar_t *application_name) { | |
133 wprintf(L"\n\nUsage: \n %ls --main level --init level --job level cmd_line ", | |
134 application_name); | |
135 wprintf(L"\n\n Levels : \n\tLOCKDOWN \n\tRESTRICTED " | |
136 L"\n\tLIMITED_USER \n\tINTERACTIVE_USER \n\tNON_ADMIN \n\tUNPROTECTED"); | |
137 wprintf(L"\n\n main: Security level of the main token"); | |
138 wprintf(L"\n init: Security level of the impersonation token"); | |
139 wprintf(L"\n job: Security level of the job object"); | |
140 } | |
141 | |
142 bool GetTokenLevelFromString(const wchar_t *param, | |
143 sandbox::TokenLevel* level) { | |
144 if (_wcsicmp(param, L"LOCKDOWN") == 0) { | |
145 *level = sandbox::USER_LOCKDOWN; | |
146 } else if (_wcsicmp(param, L"RESTRICTED") == 0) { | |
147 *level = sandbox::USER_RESTRICTED; | |
148 } else if (_wcsicmp(param, L"LIMITED_USER") == 0) { | |
149 *level = sandbox::USER_LIMITED; | |
150 } else if (_wcsicmp(param, L"INTERACTIVE_USER") == 0) { | |
151 *level = sandbox::USER_INTERACTIVE; | |
152 } else if (_wcsicmp(param, L"NON_ADMIN") == 0) { | |
153 *level = sandbox::USER_NON_ADMIN; | |
154 } else if (_wcsicmp(param, L"USER_RESTRICTED_SAME_ACCESS") == 0) { | |
155 *level = sandbox::USER_RESTRICTED_SAME_ACCESS; | |
156 } else if (_wcsicmp(param, L"UNPROTECTED") == 0) { | |
157 *level = sandbox::USER_UNPROTECTED; | |
158 } else { | |
159 return false; | |
160 } | |
161 | |
162 return true; | |
163 } | |
164 | |
165 bool GetJobLevelFromString(const wchar_t *param, sandbox::JobLevel* level) { | |
166 if (_wcsicmp(param, L"LOCKDOWN") == 0) { | |
167 *level = sandbox::JOB_LOCKDOWN; | |
168 } else if (_wcsicmp(param, L"RESTRICTED") == 0) { | |
169 *level = sandbox::JOB_RESTRICTED; | |
170 } else if (_wcsicmp(param, L"LIMITED_USER") == 0) { | |
171 *level = sandbox::JOB_LIMITED_USER; | |
172 } else if (_wcsicmp(param, L"INTERACTIVE_USER") == 0) { | |
173 *level = sandbox::JOB_INTERACTIVE; | |
174 } else if (_wcsicmp(param, L"NON_ADMIN") == 0) { | |
175 wprintf(L"\nNON_ADMIN is not a supported job type"); | |
176 return false; | |
177 } else if (_wcsicmp(param, L"UNPROTECTED") == 0) { | |
178 *level = sandbox::JOB_UNPROTECTED; | |
179 } else { | |
180 return false; | |
181 } | |
182 | |
183 return true; | |
184 } | |
185 | |
186 int wmain(int argc, wchar_t *argv[]) { | |
187 // Extract the filename from the path. | |
188 wchar_t *app_name = wcsrchr(argv[0], L'\\'); | |
189 if (!app_name) { | |
190 app_name = argv[0]; | |
191 } else { | |
192 app_name++; | |
193 } | |
194 | |
195 // no argument | |
196 if (argc == 1) { | |
197 PrintUsage(app_name); | |
198 return -1; | |
199 } | |
200 | |
201 sandbox::TokenLevel primary_level = sandbox::USER_LOCKDOWN; | |
202 sandbox::TokenLevel impersonation_level = | |
203 sandbox::USER_RESTRICTED_SAME_ACCESS; | |
204 sandbox::JobLevel job_level = sandbox::JOB_LOCKDOWN; | |
205 ATL::CString command_line; | |
206 | |
207 // parse command line. | |
208 for (int i = 1; i < argc; ++i) { | |
209 if (PARAM_IS(L"--main")) { | |
210 i++; | |
211 if (argc > i) { | |
212 if (!GetTokenLevelFromString(argv[i], &primary_level)) { | |
213 wprintf(L"\nAbord, Unrecognized main token level \"%ls\"", argv[i]); | |
214 PrintUsage(app_name); | |
215 return -1; | |
216 } | |
217 } | |
218 } else if (PARAM_IS(L"--init")) { | |
219 i++; | |
220 if (argc > i) { | |
221 if (!GetTokenLevelFromString(argv[i], &impersonation_level)) { | |
222 wprintf(L"\nAbord, Unrecognized init token level \"%ls\"", argv[i]); | |
223 PrintUsage(app_name); | |
224 return -1; | |
225 } | |
226 } | |
227 } else if (PARAM_IS(L"--job")) { | |
228 i++; | |
229 if (argc > i) { | |
230 if (!GetJobLevelFromString(argv[i], &job_level)) { | |
231 wprintf(L"\nAbord, Unrecognized job security level \"%ls\"", argv[i]); | |
232 PrintUsage(app_name); | |
233 return -1; | |
234 } | |
235 } | |
236 } else { | |
237 if (command_line.GetLength()) { | |
238 command_line += L' '; | |
239 } | |
240 command_line += argv[i]; | |
241 } | |
242 } | |
243 | |
244 if (!command_line.GetLength()) { | |
245 wprintf(L"\nAbord, No command line specified"); | |
246 PrintUsage(app_name); | |
247 return -1; | |
248 } | |
249 | |
250 wprintf(L"\nLaunching command line: \"%ls\"\n", command_line.GetBuffer()); | |
251 | |
252 base::win::ScopedHandle job_handle; | |
253 DWORD err_code = StartRestrictedProcessInJob( | |
254 command_line.GetBuffer(), | |
255 primary_level, | |
256 impersonation_level, | |
257 job_level, | |
258 &job_handle); | |
259 if (ERROR_SUCCESS != err_code) { | |
260 wprintf(L"\nAbord, Error %d while launching command line.", err_code); | |
261 return -1; | |
262 } | |
263 | |
264 wprintf(L"\nPress any key to continue."); | |
265 while(!_kbhit()) { | |
266 Sleep(100); | |
267 } | |
268 | |
269 return 0; | |
270 } | |
OLD | NEW |