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"
9 #include "base/logging.h"
10 #include "sandbox/win/src/acl.h"
11 #include "sandbox/win/src/win_utils.h"
15 RestrictedToken::RestrictedToken()
16 : effective_token_(NULL
),
17 integrity_level_(INTEGRITY_LEVEL_LAST
),
21 RestrictedToken::~RestrictedToken() {
23 CloseHandle(effective_token_
);
26 unsigned RestrictedToken::Init(const HANDLE effective_token
) {
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
33 HANDLE effective_token_dup
;
34 if (::DuplicateHandle(::GetCurrentProcess(),
36 ::GetCurrentProcess(),
40 DUPLICATE_SAME_ACCESS
)) {
41 effective_token_
= effective_token_dup
;
43 return ::GetLastError();
46 if (!::OpenProcessToken(::GetCurrentProcess(),
49 return ::GetLastError();
56 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE
*token_handle
) const {
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
;
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
;
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
];
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
103 if (deny_size
|| restrict_size
|| privileges_size
) {
104 result
= ::CreateRestrictedToken(effective_token_
,
106 static_cast<DWORD
>(deny_size
),
108 static_cast<DWORD
>(privileges_size
),
109 privileges_to_disable_array
,
110 static_cast<DWORD
>(restrict_size
),
111 sids_to_restrict_array
,
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
117 result
= ::DuplicateTokenEx(effective_token_
, TOKEN_ALL_ACCESS
, NULL
,
118 SecurityIdentification
, TokenPrimary
,
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
;
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
)
145 BOOL status
= ::DuplicateHandle(::GetCurrentProcess(),
147 ::GetCurrentProcess(),
150 FALSE
, // Don't inherit.
153 if (new_token
!= effective_token_
)
154 ::CloseHandle(new_token
);
157 return ::GetLastError();
159 return ERROR_SUCCESS
;
162 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
163 HANDLE
*token_handle
) const {
166 return ERROR_NO_TOKEN
;
168 HANDLE restricted_token_handle
;
169 unsigned err_code
= GetRestrictedTokenHandle(&restricted_token_handle
);
170 if (ERROR_SUCCESS
!= 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(),
185 ::GetCurrentProcess(),
188 FALSE
, // Don't inherit.
191 ::CloseHandle(impersonation_token
);
194 return ::GetLastError();
196 return ERROR_SUCCESS
;
199 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector
<Sid
> *exceptions
) {
202 return ERROR_NO_TOKEN
;
204 TOKEN_GROUPS
*token_groups
= NULL
;
207 BOOL result
= ::GetTokenInformation(effective_token_
,
213 return ::GetLastError();
215 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
216 result
= ::GetTokenInformation(effective_token_
,
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;
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;
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
) {
255 return ERROR_NO_TOKEN
;
257 sids_for_deny_only_
.push_back(sid
);
258 return ERROR_SUCCESS
;
261 unsigned RestrictedToken::AddUserSidForDenyOnly() {
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_
,
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
) {
292 return ERROR_NO_TOKEN
;
294 // Get the list of privileges in the token
295 TOKEN_PRIVILEGES
*token_privileges
= NULL
;
298 BOOL result
= ::GetTokenInformation(effective_token_
,
304 return ::GetLastError();
306 token_privileges
= reinterpret_cast<TOKEN_PRIVILEGES
*>(new BYTE
[size
]);
307 result
= ::GetTokenInformation(effective_token_
,
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;
322 for (unsigned int j
= 0; j
< exceptions
->size(); ++j
) {
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;
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
) {
345 return ERROR_NO_TOKEN
;
348 if (LookupPrivilegeValue(NULL
, privilege
, &luid
))
349 privileges_to_disable_
.push_back(luid
);
351 return ::GetLastError();
353 return ERROR_SUCCESS
;
356 unsigned RestrictedToken::AddRestrictingSid(const Sid
&sid
) {
359 return ERROR_NO_TOKEN
;
361 sids_to_restrict_
.push_back(sid
); // No attributes
362 return ERROR_SUCCESS
;
365 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
368 return ERROR_NO_TOKEN
;
370 TOKEN_GROUPS
*token_groups
= NULL
;
373 BOOL result
= ::GetTokenInformation(effective_token_
,
379 return ::GetLastError();
381 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
382 result
= ::GetTokenInformation(effective_token_
,
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
);
401 sids_to_restrict_
.push_back(logon_sid
);
403 delete[] reinterpret_cast<BYTE
*>(token_groups
);
405 return ERROR_SUCCESS
;
408 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
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_
,
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() {
438 return ERROR_NO_TOKEN
;
440 // Add the current user to the list.
441 unsigned error
= AddRestrictingSidCurrentUser();
442 if (ERROR_SUCCESS
!= error
)
445 TOKEN_GROUPS
*token_groups
= NULL
;
448 // Get the buffer size required.
449 BOOL result
= ::GetTokenInformation(effective_token_
, TokenGroups
, NULL
, 0,
452 return ::GetLastError();
454 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
455 result
= ::GetTokenInformation(effective_token_
,
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