Update V8 to version 4.3.37.
[chromium-blink-merge.git] / sandbox / win / src / restricted_token.cc
blob3960926f4d792829fe3b7fe260335fdc62b549eb
1 // Copyright (c) 2012 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.
5 #include "sandbox/win/src/restricted_token.h"
7 #include <vector>
9 #include "base/logging.h"
10 #include "sandbox/win/src/acl.h"
11 #include "sandbox/win/src/win_utils.h"
14 namespace sandbox {
16 unsigned RestrictedToken::Init(const HANDLE effective_token) {
17 if (init_)
18 return ERROR_ALREADY_INITIALIZED;
20 if (effective_token) {
21 // We duplicate the handle to be able to use it even if the original handle
22 // is closed.
23 HANDLE effective_token_dup;
24 if (::DuplicateHandle(::GetCurrentProcess(),
25 effective_token,
26 ::GetCurrentProcess(),
27 &effective_token_dup,
29 FALSE,
30 DUPLICATE_SAME_ACCESS)) {
31 effective_token_ = effective_token_dup;
32 } else {
33 return ::GetLastError();
35 } else {
36 if (!::OpenProcessToken(::GetCurrentProcess(),
37 TOKEN_ALL_ACCESS,
38 &effective_token_))
39 return ::GetLastError();
42 init_ = true;
43 return ERROR_SUCCESS;
46 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
47 DCHECK(init_);
48 if (!init_)
49 return ERROR_NO_TOKEN;
51 size_t deny_size = sids_for_deny_only_.size();
52 size_t restrict_size = sids_to_restrict_.size();
53 size_t privileges_size = privileges_to_disable_.size();
55 SID_AND_ATTRIBUTES *deny_only_array = NULL;
56 if (deny_size) {
57 deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
59 for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
60 deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
61 deny_only_array[i].Sid =
62 const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
66 SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
67 if (restrict_size) {
68 sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
70 for (unsigned int i = 0; i < restrict_size; ++i) {
71 sids_to_restrict_array[i].Attributes = 0;
72 sids_to_restrict_array[i].Sid =
73 const_cast<SID*>(sids_to_restrict_[i].GetPSID());
77 LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
78 if (privileges_size) {
79 privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
81 for (unsigned int i = 0; i < privileges_size; ++i) {
82 privileges_to_disable_array[i].Attributes = 0;
83 privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
87 BOOL result = TRUE;
88 HANDLE new_token = NULL;
89 // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
90 // if a token has ben restricted given the limiations of IsTokenRestricted()
91 // but it appears that in Windows 7 it hints the AppLocker subsystem to
92 // leave us alone.
93 if (deny_size || restrict_size || privileges_size) {
94 result = ::CreateRestrictedToken(effective_token_,
95 SANDBOX_INERT,
96 static_cast<DWORD>(deny_size),
97 deny_only_array,
98 static_cast<DWORD>(privileges_size),
99 privileges_to_disable_array,
100 static_cast<DWORD>(restrict_size),
101 sids_to_restrict_array,
102 &new_token);
103 } else {
104 // Duplicate the token even if it's not modified at this point
105 // because any subsequent changes to this token would also affect the
106 // current process.
107 result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
108 SecurityIdentification, TokenPrimary,
109 &new_token);
112 if (deny_only_array)
113 delete[] deny_only_array;
115 if (sids_to_restrict_array)
116 delete[] sids_to_restrict_array;
118 if (privileges_to_disable_array)
119 delete[] privileges_to_disable_array;
121 if (!result)
122 return ::GetLastError();
124 // Modify the default dacl on the token to contain Restricted and the user.
125 if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
126 return ::GetLastError();
128 if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
129 return ::GetLastError();
131 DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
132 if (ERROR_SUCCESS != error)
133 return error;
135 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
136 new_token,
137 ::GetCurrentProcess(),
138 token_handle,
139 TOKEN_ALL_ACCESS,
140 FALSE, // Don't inherit.
143 if (new_token != effective_token_)
144 ::CloseHandle(new_token);
146 if (!status)
147 return ::GetLastError();
149 return ERROR_SUCCESS;
152 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
153 HANDLE *token_handle) const {
154 DCHECK(init_);
155 if (!init_)
156 return ERROR_NO_TOKEN;
158 HANDLE restricted_token_handle;
159 unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
160 if (ERROR_SUCCESS != err_code)
161 return err_code;
163 HANDLE impersonation_token;
164 if (!::DuplicateToken(restricted_token_handle,
165 SecurityImpersonation,
166 &impersonation_token)) {
167 ::CloseHandle(restricted_token_handle);
168 return ::GetLastError();
171 ::CloseHandle(restricted_token_handle);
173 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
174 impersonation_token,
175 ::GetCurrentProcess(),
176 token_handle,
177 TOKEN_ALL_ACCESS,
178 FALSE, // Don't inherit.
181 ::CloseHandle(impersonation_token);
183 if (!status)
184 return ::GetLastError();
186 return ERROR_SUCCESS;
189 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
190 DCHECK(init_);
191 if (!init_)
192 return ERROR_NO_TOKEN;
194 TOKEN_GROUPS *token_groups = NULL;
195 DWORD size = 0;
197 BOOL result = ::GetTokenInformation(effective_token_,
198 TokenGroups,
199 NULL, // No buffer.
200 0, // Size is 0.
201 &size);
202 if (!size)
203 return ::GetLastError();
205 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
206 result = ::GetTokenInformation(effective_token_,
207 TokenGroups,
208 token_groups,
209 size,
210 &size);
211 if (!result) {
212 delete[] reinterpret_cast<BYTE*>(token_groups);
213 return ::GetLastError();
216 // Build the list of the deny only group SIDs
217 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
218 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
219 (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
220 bool should_ignore = false;
221 if (exceptions) {
222 for (unsigned int j = 0; j < exceptions->size(); ++j) {
223 if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
224 token_groups->Groups[i].Sid)) {
225 should_ignore = true;
226 break;
230 if (!should_ignore) {
231 sids_for_deny_only_.push_back(
232 reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
237 delete[] reinterpret_cast<BYTE*>(token_groups);
239 return ERROR_SUCCESS;
242 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
243 DCHECK(init_);
244 if (!init_)
245 return ERROR_NO_TOKEN;
247 sids_for_deny_only_.push_back(sid);
248 return ERROR_SUCCESS;
251 unsigned RestrictedToken::AddUserSidForDenyOnly() {
252 DCHECK(init_);
253 if (!init_)
254 return ERROR_NO_TOKEN;
256 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
257 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
259 BOOL result = ::GetTokenInformation(effective_token_,
260 TokenUser,
261 token_user,
262 size,
263 &size);
265 if (!result) {
266 delete[] reinterpret_cast<BYTE*>(token_user);
267 return ::GetLastError();
270 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
271 sids_for_deny_only_.push_back(user);
273 delete[] reinterpret_cast<BYTE*>(token_user);
275 return ERROR_SUCCESS;
278 unsigned RestrictedToken::DeleteAllPrivileges(
279 const std::vector<base::string16> *exceptions) {
280 DCHECK(init_);
281 if (!init_)
282 return ERROR_NO_TOKEN;
284 // Get the list of privileges in the token
285 TOKEN_PRIVILEGES *token_privileges = NULL;
286 DWORD size = 0;
288 BOOL result = ::GetTokenInformation(effective_token_,
289 TokenPrivileges,
290 NULL, // No buffer.
291 0, // Size is 0.
292 &size);
293 if (!size)
294 return ::GetLastError();
296 token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
297 result = ::GetTokenInformation(effective_token_,
298 TokenPrivileges,
299 token_privileges,
300 size,
301 &size);
302 if (!result) {
303 delete[] reinterpret_cast<BYTE *>(token_privileges);
304 return ::GetLastError();
308 // Build the list of privileges to disable
309 for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
310 bool should_ignore = false;
311 if (exceptions) {
312 for (unsigned int j = 0; j < exceptions->size(); ++j) {
313 LUID luid = {0};
314 ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
315 if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
316 token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
317 should_ignore = true;
318 break;
322 if (!should_ignore) {
323 privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
327 delete[] reinterpret_cast<BYTE *>(token_privileges);
329 return ERROR_SUCCESS;
332 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
333 DCHECK(init_);
334 if (!init_)
335 return ERROR_NO_TOKEN;
337 LUID luid = {0};
338 if (LookupPrivilegeValue(NULL, privilege, &luid))
339 privileges_to_disable_.push_back(luid);
340 else
341 return ::GetLastError();
343 return ERROR_SUCCESS;
346 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
347 DCHECK(init_);
348 if (!init_)
349 return ERROR_NO_TOKEN;
351 sids_to_restrict_.push_back(sid); // No attributes
352 return ERROR_SUCCESS;
355 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
356 DCHECK(init_);
357 if (!init_)
358 return ERROR_NO_TOKEN;
360 TOKEN_GROUPS *token_groups = NULL;
361 DWORD size = 0;
363 BOOL result = ::GetTokenInformation(effective_token_,
364 TokenGroups,
365 NULL, // No buffer.
366 0, // Size is 0.
367 &size);
368 if (!size)
369 return ::GetLastError();
371 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
372 result = ::GetTokenInformation(effective_token_,
373 TokenGroups,
374 token_groups,
375 size,
376 &size);
377 if (!result) {
378 delete[] reinterpret_cast<BYTE*>(token_groups);
379 return ::GetLastError();
382 SID *logon_sid = NULL;
383 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
384 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
385 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
386 break;
390 if (logon_sid)
391 sids_to_restrict_.push_back(logon_sid);
393 delete[] reinterpret_cast<BYTE*>(token_groups);
395 return ERROR_SUCCESS;
398 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
399 DCHECK(init_);
400 if (!init_)
401 return ERROR_NO_TOKEN;
403 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
404 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
406 BOOL result = ::GetTokenInformation(effective_token_,
407 TokenUser,
408 token_user,
409 size,
410 &size);
412 if (!result) {
413 delete[] reinterpret_cast<BYTE*>(token_user);
414 return ::GetLastError();
417 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
418 sids_to_restrict_.push_back(user);
420 delete[] reinterpret_cast<BYTE*>(token_user);
422 return ERROR_SUCCESS;
425 unsigned RestrictedToken::AddRestrictingSidAllSids() {
426 DCHECK(init_);
427 if (!init_)
428 return ERROR_NO_TOKEN;
430 // Add the current user to the list.
431 unsigned error = AddRestrictingSidCurrentUser();
432 if (ERROR_SUCCESS != error)
433 return error;
435 TOKEN_GROUPS *token_groups = NULL;
436 DWORD size = 0;
438 // Get the buffer size required.
439 BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
440 &size);
441 if (!size)
442 return ::GetLastError();
444 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
445 result = ::GetTokenInformation(effective_token_,
446 TokenGroups,
447 token_groups,
448 size,
449 &size);
450 if (!result) {
451 delete[] reinterpret_cast<BYTE*>(token_groups);
452 return ::GetLastError();
455 // Build the list of restricting sids from all groups.
456 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
457 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
458 AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
461 delete[] reinterpret_cast<BYTE*>(token_groups);
463 return ERROR_SUCCESS;
466 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
467 integrity_level_ = integrity_level;
468 return ERROR_SUCCESS;
471 } // namespace sandbox