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
) {
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
24 HANDLE effective_token_dup
;
25 if (::DuplicateHandle(::GetCurrentProcess(),
27 ::GetCurrentProcess(),
31 DUPLICATE_SAME_ACCESS
)) {
32 effective_token_
= effective_token_dup
;
34 return ::GetLastError();
37 if (!::OpenProcessToken(::GetCurrentProcess(),
40 return ::GetLastError();
47 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE
*token_handle
) const {
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
;
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
;
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
];
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
94 if (deny_size
|| restrict_size
|| privileges_size
) {
95 result
= ::CreateRestrictedToken(effective_token_
,
97 static_cast<DWORD
>(deny_size
),
99 static_cast<DWORD
>(privileges_size
),
100 privileges_to_disable_array
,
101 static_cast<DWORD
>(restrict_size
),
102 sids_to_restrict_array
,
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
108 result
= ::DuplicateTokenEx(effective_token_
, TOKEN_ALL_ACCESS
, NULL
,
109 SecurityIdentification
, TokenPrimary
,
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
;
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
)
136 BOOL status
= ::DuplicateHandle(::GetCurrentProcess(),
138 ::GetCurrentProcess(),
141 FALSE
, // Don't inherit.
144 if (new_token
!= effective_token_
)
145 ::CloseHandle(new_token
);
148 return ::GetLastError();
150 return ERROR_SUCCESS
;
153 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
154 HANDLE
*token_handle
) const {
157 return ERROR_NO_TOKEN
;
159 HANDLE restricted_token_handle
;
160 unsigned err_code
= GetRestrictedTokenHandle(&restricted_token_handle
);
161 if (ERROR_SUCCESS
!= 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(),
176 ::GetCurrentProcess(),
179 FALSE
, // Don't inherit.
182 ::CloseHandle(impersonation_token
);
185 return ::GetLastError();
187 return ERROR_SUCCESS
;
190 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector
<Sid
> *exceptions
) {
193 return ERROR_NO_TOKEN
;
195 TOKEN_GROUPS
*token_groups
= NULL
;
198 BOOL result
= ::GetTokenInformation(effective_token_
,
204 return ::GetLastError();
206 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
207 result
= ::GetTokenInformation(effective_token_
,
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;
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;
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
) {
246 return ERROR_NO_TOKEN
;
248 sids_for_deny_only_
.push_back(sid
);
249 return ERROR_SUCCESS
;
252 unsigned RestrictedToken::AddUserSidForDenyOnly() {
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_
,
267 delete[] reinterpret_cast<BYTE
*>(token_user
);
268 return ::GetLastError();
271 Sid user
= reinterpret_cast<SID
*>(token_user
->User
.Sid
);
272 sids_for_deny_only_
.push_back(user
);
274 delete[] reinterpret_cast<BYTE
*>(token_user
);
276 return ERROR_SUCCESS
;
279 unsigned RestrictedToken::DeleteAllPrivileges(
280 const std::vector
<std::wstring
> *exceptions
) {
283 return ERROR_NO_TOKEN
;
285 // Get the list of privileges in the token
286 TOKEN_PRIVILEGES
*token_privileges
= NULL
;
289 BOOL result
= ::GetTokenInformation(effective_token_
,
295 return ::GetLastError();
297 token_privileges
= reinterpret_cast<TOKEN_PRIVILEGES
*>(new BYTE
[size
]);
298 result
= ::GetTokenInformation(effective_token_
,
304 delete[] reinterpret_cast<BYTE
*>(token_privileges
);
305 return ::GetLastError();
309 // Build the list of privileges to disable
310 for (unsigned int i
= 0; i
< token_privileges
->PrivilegeCount
; ++i
) {
311 bool should_ignore
= false;
313 for (unsigned int j
= 0; j
< exceptions
->size(); ++j
) {
315 ::LookupPrivilegeValue(NULL
, (*exceptions
)[j
].c_str(), &luid
);
316 if (token_privileges
->Privileges
[i
].Luid
.HighPart
== luid
.HighPart
&&
317 token_privileges
->Privileges
[i
].Luid
.LowPart
== luid
.LowPart
) {
318 should_ignore
= true;
323 if (!should_ignore
) {
324 privileges_to_disable_
.push_back(token_privileges
->Privileges
[i
].Luid
);
328 delete[] reinterpret_cast<BYTE
*>(token_privileges
);
330 return ERROR_SUCCESS
;
333 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege
) {
336 return ERROR_NO_TOKEN
;
339 if (LookupPrivilegeValue(NULL
, privilege
, &luid
))
340 privileges_to_disable_
.push_back(luid
);
342 return ::GetLastError();
344 return ERROR_SUCCESS
;
347 unsigned RestrictedToken::AddRestrictingSid(const Sid
&sid
) {
350 return ERROR_NO_TOKEN
;
352 sids_to_restrict_
.push_back(sid
); // No attributes
353 return ERROR_SUCCESS
;
356 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
359 return ERROR_NO_TOKEN
;
361 TOKEN_GROUPS
*token_groups
= NULL
;
364 BOOL result
= ::GetTokenInformation(effective_token_
,
370 return ::GetLastError();
372 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
373 result
= ::GetTokenInformation(effective_token_
,
379 delete[] reinterpret_cast<BYTE
*>(token_groups
);
380 return ::GetLastError();
383 SID
*logon_sid
= NULL
;
384 for (unsigned int i
= 0; i
< token_groups
->GroupCount
; ++i
) {
385 if ((token_groups
->Groups
[i
].Attributes
& SE_GROUP_LOGON_ID
) != 0) {
386 logon_sid
= static_cast<SID
*>(token_groups
->Groups
[i
].Sid
);
392 sids_to_restrict_
.push_back(logon_sid
);
394 delete[] reinterpret_cast<BYTE
*>(token_groups
);
396 return ERROR_SUCCESS
;
399 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
402 return ERROR_NO_TOKEN
;
404 DWORD size
= sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
;
405 TOKEN_USER
* token_user
= reinterpret_cast<TOKEN_USER
*>(new BYTE
[size
]);
407 BOOL result
= ::GetTokenInformation(effective_token_
,
414 delete[] reinterpret_cast<BYTE
*>(token_user
);
415 return ::GetLastError();
418 Sid user
= reinterpret_cast<SID
*>(token_user
->User
.Sid
);
419 sids_to_restrict_
.push_back(user
);
421 delete[] reinterpret_cast<BYTE
*>(token_user
);
423 return ERROR_SUCCESS
;
426 unsigned RestrictedToken::AddRestrictingSidAllSids() {
429 return ERROR_NO_TOKEN
;
431 // Add the current user to the list.
432 unsigned error
= AddRestrictingSidCurrentUser();
433 if (ERROR_SUCCESS
!= error
)
436 TOKEN_GROUPS
*token_groups
= NULL
;
439 // Get the buffer size required.
440 BOOL result
= ::GetTokenInformation(effective_token_
, TokenGroups
, NULL
, 0,
443 return ::GetLastError();
445 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
446 result
= ::GetTokenInformation(effective_token_
,
452 delete[] reinterpret_cast<BYTE
*>(token_groups
);
453 return ::GetLastError();
456 // Build the list of restricting sids from all groups.
457 for (unsigned int i
= 0; i
< token_groups
->GroupCount
; ++i
) {
458 if ((token_groups
->Groups
[i
].Attributes
& SE_GROUP_INTEGRITY
) == 0)
459 AddRestrictingSid(reinterpret_cast<SID
*>(token_groups
->Groups
[i
].Sid
));
462 delete[] reinterpret_cast<BYTE
*>(token_groups
);
464 return ERROR_SUCCESS
;
467 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level
) {
468 integrity_level_
= integrity_level
;
469 return ERROR_SUCCESS
;
472 } // namespace sandbox