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"
9 #include "base/logging.h"
10 #include "sandbox/src/acl.h"
11 #include "sandbox/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(),
29 DUPLICATE_SAME_ACCESS
,
31 0)) { // no special options
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_
,
266 Sid user
= reinterpret_cast<SID
*>(token_user
->User
.Sid
);
267 delete[] reinterpret_cast<BYTE
*>(token_user
);
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
) {
280 return ERROR_NO_TOKEN
;
282 // Get the list of privileges in the token
283 TOKEN_PRIVILEGES
*token_privileges
= NULL
;
286 BOOL result
= ::GetTokenInformation(effective_token_
,
292 return ::GetLastError();
294 token_privileges
= reinterpret_cast<TOKEN_PRIVILEGES
*>(new BYTE
[size
]);
295 result
= ::GetTokenInformation(effective_token_
,
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;
310 for (unsigned int j
= 0; j
< exceptions
->size(); ++j
) {
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;
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
) {
332 return ERROR_NO_TOKEN
;
335 if (LookupPrivilegeValue(NULL
, privilege
, &luid
))
336 privileges_to_disable_
.push_back(luid
);
338 return ::GetLastError();
340 return ERROR_SUCCESS
;
343 unsigned RestrictedToken::AddRestrictingSid(const Sid
&sid
) {
346 return ERROR_NO_TOKEN
;
348 sids_to_restrict_
.push_back(sid
); // No attributes
349 return ERROR_SUCCESS
;
352 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
355 return ERROR_NO_TOKEN
;
357 TOKEN_GROUPS
*token_groups
= NULL
;
360 BOOL result
= ::GetTokenInformation(effective_token_
,
366 return ::GetLastError();
368 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
369 result
= ::GetTokenInformation(effective_token_
,
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
);
388 sids_to_restrict_
.push_back(logon_sid
);
390 delete[] reinterpret_cast<BYTE
*>(token_groups
);
392 return ERROR_SUCCESS
;
395 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
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_
,
409 Sid user
= reinterpret_cast<SID
*>(token_user
->User
.Sid
);
410 delete[] reinterpret_cast<BYTE
*>(token_user
);
414 return ::GetLastError();
416 sids_to_restrict_
.push_back(user
);
417 return ERROR_SUCCESS
;
420 unsigned RestrictedToken::AddRestrictingSidAllSids() {
423 return ERROR_NO_TOKEN
;
425 // Add the current user to the list.
426 unsigned error
= AddRestrictingSidCurrentUser();
427 if (ERROR_SUCCESS
!= error
)
430 TOKEN_GROUPS
*token_groups
= NULL
;
433 // Get the buffer size required.
434 BOOL result
= ::GetTokenInformation(effective_token_
, TokenGroups
, NULL
, 0,
437 return ::GetLastError();
439 token_groups
= reinterpret_cast<TOKEN_GROUPS
*>(new BYTE
[size
]);
440 result
= ::GetTokenInformation(effective_token_
,
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