ash: Extend launcher first button to include leading inset.
[chromium-blink-merge.git] / sandbox / src / restricted_token.cc
blobbac8816094c48ab2a61c19533a1fe8baada80e68
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.
5 #include "sandbox/src/restricted_token.h"
7 #include <vector>
9 #include "base/logging.h"
10 #include "sandbox/src/acl.h"
11 #include "sandbox/src/win_utils.h"
14 namespace sandbox {
16 unsigned RestrictedToken::Init(const HANDLE effective_token) {
17 DCHECK(!init_);
18 if (init_)
19 return ERROR_ALREADY_INITIALIZED;
21 if (effective_token) {
22 // We duplicate the handle to be able to use it even if the original handle
23 // is closed.
24 HANDLE effective_token_dup;
25 if (::DuplicateHandle(::GetCurrentProcess(),
26 effective_token,
27 ::GetCurrentProcess(),
28 &effective_token_dup,
29 DUPLICATE_SAME_ACCESS,
30 FALSE,
31 0)) { // no special options
32 effective_token_ = effective_token_dup;
33 } else {
34 return ::GetLastError();
36 } else {
37 if (!::OpenProcessToken(::GetCurrentProcess(),
38 TOKEN_ALL_ACCESS,
39 &effective_token_))
40 return ::GetLastError();
43 init_ = true;
44 return ERROR_SUCCESS;
47 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
48 DCHECK(init_);
49 if (!init_)
50 return ERROR_NO_TOKEN;
52 size_t deny_size = sids_for_deny_only_.size();
53 size_t restrict_size = sids_to_restrict_.size();
54 size_t privileges_size = privileges_to_disable_.size();
56 SID_AND_ATTRIBUTES *deny_only_array = NULL;
57 if (deny_size) {
58 deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
60 for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
61 deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
62 deny_only_array[i].Sid =
63 const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
67 SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
68 if (restrict_size) {
69 sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
71 for (unsigned int i = 0; i < restrict_size; ++i) {
72 sids_to_restrict_array[i].Attributes = 0;
73 sids_to_restrict_array[i].Sid =
74 const_cast<SID*>(sids_to_restrict_[i].GetPSID());
78 LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
79 if (privileges_size) {
80 privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
82 for (unsigned int i = 0; i < privileges_size; ++i) {
83 privileges_to_disable_array[i].Attributes = 0;
84 privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
88 BOOL result = TRUE;
89 HANDLE new_token = NULL;
90 // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
91 // if a token has ben restricted given the limiations of IsTokenRestricted()
92 // but it appears that in Windows 7 it hints the AppLocker subsystem to
93 // leave us alone.
94 if (deny_size || restrict_size || privileges_size) {
95 result = ::CreateRestrictedToken(effective_token_,
96 SANDBOX_INERT,
97 static_cast<DWORD>(deny_size),
98 deny_only_array,
99 static_cast<DWORD>(privileges_size),
100 privileges_to_disable_array,
101 static_cast<DWORD>(restrict_size),
102 sids_to_restrict_array,
103 &new_token);
104 } else {
105 // Duplicate the token even if it's not modified at this point
106 // because any subsequent changes to this token would also affect the
107 // current process.
108 result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
109 SecurityIdentification, TokenPrimary,
110 &new_token);
113 if (deny_only_array)
114 delete[] deny_only_array;
116 if (sids_to_restrict_array)
117 delete[] sids_to_restrict_array;
119 if (privileges_to_disable_array)
120 delete[] privileges_to_disable_array;
122 if (!result)
123 return ::GetLastError();
125 // Modify the default dacl on the token to contain Restricted and the user.
126 if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
127 return ::GetLastError();
129 if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
130 return ::GetLastError();
132 DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
133 if (ERROR_SUCCESS != error)
134 return error;
136 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
137 new_token,
138 ::GetCurrentProcess(),
139 token_handle,
140 TOKEN_ALL_ACCESS,
141 FALSE, // Don't inherit.
144 if (new_token != effective_token_)
145 ::CloseHandle(new_token);
147 if (!status)
148 return ::GetLastError();
150 return ERROR_SUCCESS;
153 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
154 HANDLE *token_handle) const {
155 DCHECK(init_);
156 if (!init_)
157 return ERROR_NO_TOKEN;
159 HANDLE restricted_token_handle;
160 unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
161 if (ERROR_SUCCESS != err_code)
162 return err_code;
164 HANDLE impersonation_token;
165 if (!::DuplicateToken(restricted_token_handle,
166 SecurityImpersonation,
167 &impersonation_token)) {
168 ::CloseHandle(restricted_token_handle);
169 return ::GetLastError();
172 ::CloseHandle(restricted_token_handle);
174 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
175 impersonation_token,
176 ::GetCurrentProcess(),
177 token_handle,
178 TOKEN_ALL_ACCESS,
179 FALSE, // Don't inherit.
182 ::CloseHandle(impersonation_token);
184 if (!status)
185 return ::GetLastError();
187 return ERROR_SUCCESS;
190 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
191 DCHECK(init_);
192 if (!init_)
193 return ERROR_NO_TOKEN;
195 TOKEN_GROUPS *token_groups = NULL;
196 DWORD size = 0;
198 BOOL result = ::GetTokenInformation(effective_token_,
199 TokenGroups,
200 NULL, // No buffer.
201 0, // Size is 0.
202 &size);
203 if (!size)
204 return ::GetLastError();
206 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
207 result = ::GetTokenInformation(effective_token_,
208 TokenGroups,
209 token_groups,
210 size,
211 &size);
212 if (!result) {
213 delete[] reinterpret_cast<BYTE*>(token_groups);
214 return ::GetLastError();
217 // Build the list of the deny only group SIDs
218 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
219 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
220 (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
221 bool should_ignore = false;
222 if (exceptions) {
223 for (unsigned int j = 0; j < exceptions->size(); ++j) {
224 if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
225 token_groups->Groups[i].Sid)) {
226 should_ignore = true;
227 break;
231 if (!should_ignore) {
232 sids_for_deny_only_.push_back(
233 reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
238 delete[] reinterpret_cast<BYTE*>(token_groups);
240 return ERROR_SUCCESS;
243 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
244 DCHECK(init_);
245 if (!init_)
246 return ERROR_NO_TOKEN;
248 sids_for_deny_only_.push_back(sid);
249 return ERROR_SUCCESS;
252 unsigned RestrictedToken::AddUserSidForDenyOnly() {
253 DCHECK(init_);
254 if (!init_)
255 return ERROR_NO_TOKEN;
257 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
258 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
260 BOOL result = ::GetTokenInformation(effective_token_,
261 TokenUser,
262 token_user,
263 size,
264 &size);
266 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
267 delete[] reinterpret_cast<BYTE*>(token_user);
269 if (!result)
270 return ::GetLastError();
272 sids_for_deny_only_.push_back(user);
273 return ERROR_SUCCESS;
276 unsigned RestrictedToken::DeleteAllPrivileges(
277 const std::vector<std::wstring> *exceptions) {
278 DCHECK(init_);
279 if (!init_)
280 return ERROR_NO_TOKEN;
282 // Get the list of privileges in the token
283 TOKEN_PRIVILEGES *token_privileges = NULL;
284 DWORD size = 0;
286 BOOL result = ::GetTokenInformation(effective_token_,
287 TokenPrivileges,
288 NULL, // No buffer.
289 0, // Size is 0.
290 &size);
291 if (!size)
292 return ::GetLastError();
294 token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
295 result = ::GetTokenInformation(effective_token_,
296 TokenPrivileges,
297 token_privileges,
298 size,
299 &size);
300 if (!result) {
301 delete[] reinterpret_cast<BYTE *>(token_privileges);
302 return ::GetLastError();
306 // Build the list of privileges to disable
307 for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
308 bool should_ignore = false;
309 if (exceptions) {
310 for (unsigned int j = 0; j < exceptions->size(); ++j) {
311 LUID luid = {0};
312 ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
313 if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
314 token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
315 should_ignore = true;
316 break;
320 if (!should_ignore) {
321 privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
325 delete[] reinterpret_cast<BYTE *>(token_privileges);
326 return ERROR_SUCCESS;
329 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
330 DCHECK(init_);
331 if (!init_)
332 return ERROR_NO_TOKEN;
334 LUID luid = {0};
335 if (LookupPrivilegeValue(NULL, privilege, &luid))
336 privileges_to_disable_.push_back(luid);
337 else
338 return ::GetLastError();
340 return ERROR_SUCCESS;
343 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
344 DCHECK(init_);
345 if (!init_)
346 return ERROR_NO_TOKEN;
348 sids_to_restrict_.push_back(sid); // No attributes
349 return ERROR_SUCCESS;
352 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
353 DCHECK(init_);
354 if (!init_)
355 return ERROR_NO_TOKEN;
357 TOKEN_GROUPS *token_groups = NULL;
358 DWORD size = 0;
360 BOOL result = ::GetTokenInformation(effective_token_,
361 TokenGroups,
362 NULL, // No buffer.
363 0, // Size is 0.
364 &size);
365 if (!size)
366 return ::GetLastError();
368 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
369 result = ::GetTokenInformation(effective_token_,
370 TokenGroups,
371 token_groups,
372 size,
373 &size);
374 if (!result) {
375 delete[] reinterpret_cast<BYTE*>(token_groups);
376 return ::GetLastError();
379 SID *logon_sid = NULL;
380 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
381 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
382 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
383 break;
387 if (logon_sid)
388 sids_to_restrict_.push_back(logon_sid);
390 delete[] reinterpret_cast<BYTE*>(token_groups);
392 return ERROR_SUCCESS;
395 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
396 DCHECK(init_);
397 if (!init_)
398 return ERROR_NO_TOKEN;
400 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
401 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
403 BOOL result = ::GetTokenInformation(effective_token_,
404 TokenUser,
405 token_user,
406 size,
407 &size);
409 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
410 delete[] reinterpret_cast<BYTE*>(token_user);
413 if (!result)
414 return ::GetLastError();
416 sids_to_restrict_.push_back(user);
417 return ERROR_SUCCESS;
420 unsigned RestrictedToken::AddRestrictingSidAllSids() {
421 DCHECK(init_);
422 if (!init_)
423 return ERROR_NO_TOKEN;
425 // Add the current user to the list.
426 unsigned error = AddRestrictingSidCurrentUser();
427 if (ERROR_SUCCESS != error)
428 return error;
430 TOKEN_GROUPS *token_groups = NULL;
431 DWORD size = 0;
433 // Get the buffer size required.
434 BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
435 &size);
436 if (!size)
437 return ::GetLastError();
439 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
440 result = ::GetTokenInformation(effective_token_,
441 TokenGroups,
442 token_groups,
443 size,
444 &size);
445 if (!result) {
446 delete[] reinterpret_cast<BYTE*>(token_groups);
447 return ::GetLastError();
450 // Build the list of restricting sids from all groups.
451 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
452 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
453 AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
456 delete[] reinterpret_cast<BYTE*>(token_groups);
458 return ERROR_SUCCESS;
461 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
462 integrity_level_ = integrity_level;
463 return ERROR_SUCCESS;
466 } // namespace sandbox