Record MTU discovery packets in net-internals log.
[chromium-blink-merge.git] / sandbox / win / src / restricted_token.cc
blobd94ca06ef65902841e74f3288e3a17809464bf1c
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"
13 namespace sandbox {
15 RestrictedToken::RestrictedToken()
16 : effective_token_(NULL),
17 integrity_level_(INTEGRITY_LEVEL_LAST),
18 init_(false) {
21 RestrictedToken::~RestrictedToken() {
22 if (effective_token_)
23 CloseHandle(effective_token_);
26 unsigned RestrictedToken::Init(const HANDLE effective_token) {
27 if (init_)
28 return ERROR_ALREADY_INITIALIZED;
30 if (effective_token) {
31 // We duplicate the handle to be able to use it even if the original handle
32 // is closed.
33 HANDLE effective_token_dup;
34 if (::DuplicateHandle(::GetCurrentProcess(),
35 effective_token,
36 ::GetCurrentProcess(),
37 &effective_token_dup,
39 FALSE,
40 DUPLICATE_SAME_ACCESS)) {
41 effective_token_ = effective_token_dup;
42 } else {
43 return ::GetLastError();
45 } else {
46 if (!::OpenProcessToken(::GetCurrentProcess(),
47 TOKEN_ALL_ACCESS,
48 &effective_token_))
49 return ::GetLastError();
52 init_ = true;
53 return ERROR_SUCCESS;
56 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
57 DCHECK(init_);
58 if (!init_)
59 return ERROR_NO_TOKEN;
61 size_t deny_size = sids_for_deny_only_.size();
62 size_t restrict_size = sids_to_restrict_.size();
63 size_t privileges_size = privileges_to_disable_.size();
65 SID_AND_ATTRIBUTES *deny_only_array = NULL;
66 if (deny_size) {
67 deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
69 for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
70 deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
71 deny_only_array[i].Sid =
72 const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
76 SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
77 if (restrict_size) {
78 sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
80 for (unsigned int i = 0; i < restrict_size; ++i) {
81 sids_to_restrict_array[i].Attributes = 0;
82 sids_to_restrict_array[i].Sid =
83 const_cast<SID*>(sids_to_restrict_[i].GetPSID());
87 LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
88 if (privileges_size) {
89 privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
91 for (unsigned int i = 0; i < privileges_size; ++i) {
92 privileges_to_disable_array[i].Attributes = 0;
93 privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
97 BOOL result = TRUE;
98 HANDLE new_token = NULL;
99 // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
100 // if a token has ben restricted given the limiations of IsTokenRestricted()
101 // but it appears that in Windows 7 it hints the AppLocker subsystem to
102 // leave us alone.
103 if (deny_size || restrict_size || privileges_size) {
104 result = ::CreateRestrictedToken(effective_token_,
105 SANDBOX_INERT,
106 static_cast<DWORD>(deny_size),
107 deny_only_array,
108 static_cast<DWORD>(privileges_size),
109 privileges_to_disable_array,
110 static_cast<DWORD>(restrict_size),
111 sids_to_restrict_array,
112 &new_token);
113 } else {
114 // Duplicate the token even if it's not modified at this point
115 // because any subsequent changes to this token would also affect the
116 // current process.
117 result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
118 SecurityIdentification, TokenPrimary,
119 &new_token);
122 if (deny_only_array)
123 delete[] deny_only_array;
125 if (sids_to_restrict_array)
126 delete[] sids_to_restrict_array;
128 if (privileges_to_disable_array)
129 delete[] privileges_to_disable_array;
131 if (!result)
132 return ::GetLastError();
134 // Modify the default dacl on the token to contain Restricted and the user.
135 if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
136 return ::GetLastError();
138 if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
139 return ::GetLastError();
141 DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
142 if (ERROR_SUCCESS != error)
143 return error;
145 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
146 new_token,
147 ::GetCurrentProcess(),
148 token_handle,
149 TOKEN_ALL_ACCESS,
150 FALSE, // Don't inherit.
153 if (new_token != effective_token_)
154 ::CloseHandle(new_token);
156 if (!status)
157 return ::GetLastError();
159 return ERROR_SUCCESS;
162 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
163 HANDLE *token_handle) const {
164 DCHECK(init_);
165 if (!init_)
166 return ERROR_NO_TOKEN;
168 HANDLE restricted_token_handle;
169 unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
170 if (ERROR_SUCCESS != err_code)
171 return err_code;
173 HANDLE impersonation_token;
174 if (!::DuplicateToken(restricted_token_handle,
175 SecurityImpersonation,
176 &impersonation_token)) {
177 ::CloseHandle(restricted_token_handle);
178 return ::GetLastError();
181 ::CloseHandle(restricted_token_handle);
183 BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
184 impersonation_token,
185 ::GetCurrentProcess(),
186 token_handle,
187 TOKEN_ALL_ACCESS,
188 FALSE, // Don't inherit.
191 ::CloseHandle(impersonation_token);
193 if (!status)
194 return ::GetLastError();
196 return ERROR_SUCCESS;
199 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
200 DCHECK(init_);
201 if (!init_)
202 return ERROR_NO_TOKEN;
204 TOKEN_GROUPS *token_groups = NULL;
205 DWORD size = 0;
207 BOOL result = ::GetTokenInformation(effective_token_,
208 TokenGroups,
209 NULL, // No buffer.
210 0, // Size is 0.
211 &size);
212 if (!size)
213 return ::GetLastError();
215 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
216 result = ::GetTokenInformation(effective_token_,
217 TokenGroups,
218 token_groups,
219 size,
220 &size);
221 if (!result) {
222 delete[] reinterpret_cast<BYTE*>(token_groups);
223 return ::GetLastError();
226 // Build the list of the deny only group SIDs
227 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
228 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
229 (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
230 bool should_ignore = false;
231 if (exceptions) {
232 for (unsigned int j = 0; j < exceptions->size(); ++j) {
233 if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
234 token_groups->Groups[i].Sid)) {
235 should_ignore = true;
236 break;
240 if (!should_ignore) {
241 sids_for_deny_only_.push_back(
242 reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
247 delete[] reinterpret_cast<BYTE*>(token_groups);
249 return ERROR_SUCCESS;
252 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
253 DCHECK(init_);
254 if (!init_)
255 return ERROR_NO_TOKEN;
257 sids_for_deny_only_.push_back(sid);
258 return ERROR_SUCCESS;
261 unsigned RestrictedToken::AddUserSidForDenyOnly() {
262 DCHECK(init_);
263 if (!init_)
264 return ERROR_NO_TOKEN;
266 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
267 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
269 BOOL result = ::GetTokenInformation(effective_token_,
270 TokenUser,
271 token_user,
272 size,
273 &size);
275 if (!result) {
276 delete[] reinterpret_cast<BYTE*>(token_user);
277 return ::GetLastError();
280 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
281 sids_for_deny_only_.push_back(user);
283 delete[] reinterpret_cast<BYTE*>(token_user);
285 return ERROR_SUCCESS;
288 unsigned RestrictedToken::DeleteAllPrivileges(
289 const std::vector<base::string16> *exceptions) {
290 DCHECK(init_);
291 if (!init_)
292 return ERROR_NO_TOKEN;
294 // Get the list of privileges in the token
295 TOKEN_PRIVILEGES *token_privileges = NULL;
296 DWORD size = 0;
298 BOOL result = ::GetTokenInformation(effective_token_,
299 TokenPrivileges,
300 NULL, // No buffer.
301 0, // Size is 0.
302 &size);
303 if (!size)
304 return ::GetLastError();
306 token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
307 result = ::GetTokenInformation(effective_token_,
308 TokenPrivileges,
309 token_privileges,
310 size,
311 &size);
312 if (!result) {
313 delete[] reinterpret_cast<BYTE *>(token_privileges);
314 return ::GetLastError();
318 // Build the list of privileges to disable
319 for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
320 bool should_ignore = false;
321 if (exceptions) {
322 for (unsigned int j = 0; j < exceptions->size(); ++j) {
323 LUID luid = {0};
324 ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
325 if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
326 token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
327 should_ignore = true;
328 break;
332 if (!should_ignore) {
333 privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
337 delete[] reinterpret_cast<BYTE *>(token_privileges);
339 return ERROR_SUCCESS;
342 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
343 DCHECK(init_);
344 if (!init_)
345 return ERROR_NO_TOKEN;
347 LUID luid = {0};
348 if (LookupPrivilegeValue(NULL, privilege, &luid))
349 privileges_to_disable_.push_back(luid);
350 else
351 return ::GetLastError();
353 return ERROR_SUCCESS;
356 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
357 DCHECK(init_);
358 if (!init_)
359 return ERROR_NO_TOKEN;
361 sids_to_restrict_.push_back(sid); // No attributes
362 return ERROR_SUCCESS;
365 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
366 DCHECK(init_);
367 if (!init_)
368 return ERROR_NO_TOKEN;
370 TOKEN_GROUPS *token_groups = NULL;
371 DWORD size = 0;
373 BOOL result = ::GetTokenInformation(effective_token_,
374 TokenGroups,
375 NULL, // No buffer.
376 0, // Size is 0.
377 &size);
378 if (!size)
379 return ::GetLastError();
381 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
382 result = ::GetTokenInformation(effective_token_,
383 TokenGroups,
384 token_groups,
385 size,
386 &size);
387 if (!result) {
388 delete[] reinterpret_cast<BYTE*>(token_groups);
389 return ::GetLastError();
392 SID *logon_sid = NULL;
393 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
394 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
395 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
396 break;
400 if (logon_sid)
401 sids_to_restrict_.push_back(logon_sid);
403 delete[] reinterpret_cast<BYTE*>(token_groups);
405 return ERROR_SUCCESS;
408 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
409 DCHECK(init_);
410 if (!init_)
411 return ERROR_NO_TOKEN;
413 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
414 TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
416 BOOL result = ::GetTokenInformation(effective_token_,
417 TokenUser,
418 token_user,
419 size,
420 &size);
422 if (!result) {
423 delete[] reinterpret_cast<BYTE*>(token_user);
424 return ::GetLastError();
427 Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
428 sids_to_restrict_.push_back(user);
430 delete[] reinterpret_cast<BYTE*>(token_user);
432 return ERROR_SUCCESS;
435 unsigned RestrictedToken::AddRestrictingSidAllSids() {
436 DCHECK(init_);
437 if (!init_)
438 return ERROR_NO_TOKEN;
440 // Add the current user to the list.
441 unsigned error = AddRestrictingSidCurrentUser();
442 if (ERROR_SUCCESS != error)
443 return error;
445 TOKEN_GROUPS *token_groups = NULL;
446 DWORD size = 0;
448 // Get the buffer size required.
449 BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
450 &size);
451 if (!size)
452 return ::GetLastError();
454 token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
455 result = ::GetTokenInformation(effective_token_,
456 TokenGroups,
457 token_groups,
458 size,
459 &size);
460 if (!result) {
461 delete[] reinterpret_cast<BYTE*>(token_groups);
462 return ::GetLastError();
465 // Build the list of restricting sids from all groups.
466 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
467 if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
468 AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
471 delete[] reinterpret_cast<BYTE*>(token_groups);
473 return ERROR_SUCCESS;
476 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
477 integrity_level_ = integrity_level;
478 return ERROR_SUCCESS;
481 } // namespace sandbox