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"
16 unsigned RestrictedToken::Init(const HANDLE effective_token
) {
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
23 HANDLE effective_token_dup
;
24 if (::DuplicateHandle(::GetCurrentProcess(),
26 ::GetCurrentProcess(),
30 DUPLICATE_SAME_ACCESS
)) {
31 effective_token_
= effective_token_dup
;
33 return ::GetLastError();
36 if (!::OpenProcessToken(::GetCurrentProcess(),
39 return ::GetLastError();
46 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE
*token_handle
) const {
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
;
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
;
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
];
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
93 if (deny_size
|| restrict_size
|| privileges_size
) {
94 result
= ::CreateRestrictedToken(effective_token_
,
96 static_cast<DWORD
>(deny_size
),
98 static_cast<DWORD
>(privileges_size
),
99 privileges_to_disable_array
,
100 static_cast<DWORD
>(restrict_size
),
101 sids_to_restrict_array
,
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
107 result
= ::DuplicateTokenEx(effective_token_
, TOKEN_ALL_ACCESS
, NULL
,
108 SecurityIdentification
, TokenPrimary
,
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
;
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
)
135 BOOL status
= ::DuplicateHandle(::GetCurrentProcess(),
137 ::GetCurrentProcess(),
140 FALSE
, // Don't inherit.
143 if (new_token
!= effective_token_
)
144 ::CloseHandle(new_token
);
147 return ::GetLastError();
149 return ERROR_SUCCESS
;
152 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
153 HANDLE
*token_handle
) const {
156 return ERROR_NO_TOKEN
;
158 HANDLE restricted_token_handle
;
159 unsigned err_code
= GetRestrictedTokenHandle(&restricted_token_handle
);
160 if (ERROR_SUCCESS
!= 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(),
175 ::GetCurrentProcess(),
178 FALSE
, // Don't inherit.
181 ::CloseHandle(impersonation_token
);
184 return ::GetLastError();
186 return ERROR_SUCCESS
;
189 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector
<Sid
> *exceptions
) {
192 return ERROR_NO_TOKEN
;
194 TOKEN_GROUPS
*token_groups
= NULL
;
197 BOOL result
= ::GetTokenInformation(effective_token_
,
203 return ::GetLastError();
205 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
206 result
= ::GetTokenInformation(effective_token_
,
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;
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;
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
) {
245 return ERROR_NO_TOKEN
;
247 sids_for_deny_only_
.push_back(sid
);
248 return ERROR_SUCCESS
;
251 unsigned RestrictedToken::AddUserSidForDenyOnly() {
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_
,
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
) {
282 return ERROR_NO_TOKEN
;
284 // Get the list of privileges in the token
285 TOKEN_PRIVILEGES
*token_privileges
= NULL
;
288 BOOL result
= ::GetTokenInformation(effective_token_
,
294 return ::GetLastError();
296 token_privileges
= reinterpret_cast<TOKEN_PRIVILEGES
*>(new BYTE
[size
]);
297 result
= ::GetTokenInformation(effective_token_
,
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;
312 for (unsigned int j
= 0; j
< exceptions
->size(); ++j
) {
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;
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
) {
335 return ERROR_NO_TOKEN
;
338 if (LookupPrivilegeValue(NULL
, privilege
, &luid
))
339 privileges_to_disable_
.push_back(luid
);
341 return ::GetLastError();
343 return ERROR_SUCCESS
;
346 unsigned RestrictedToken::AddRestrictingSid(const Sid
&sid
) {
349 return ERROR_NO_TOKEN
;
351 sids_to_restrict_
.push_back(sid
); // No attributes
352 return ERROR_SUCCESS
;
355 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
358 return ERROR_NO_TOKEN
;
360 TOKEN_GROUPS
*token_groups
= NULL
;
363 BOOL result
= ::GetTokenInformation(effective_token_
,
369 return ::GetLastError();
371 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
372 result
= ::GetTokenInformation(effective_token_
,
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
);
391 sids_to_restrict_
.push_back(logon_sid
);
393 delete[] reinterpret_cast<BYTE
*>(token_groups
);
395 return ERROR_SUCCESS
;
398 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
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_
,
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() {
428 return ERROR_NO_TOKEN
;
430 // Add the current user to the list.
431 unsigned error
= AddRestrictingSidCurrentUser();
432 if (ERROR_SUCCESS
!= error
)
435 TOKEN_GROUPS
*token_groups
= NULL
;
438 // Get the buffer size required.
439 BOOL result
= ::GetTokenInformation(effective_token_
, TokenGroups
, NULL
, 0,
442 return ::GetLastError();
444 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
445 result
= ::GetTokenInformation(effective_token_
,
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