| Index: sandbox/win/src/restricted_token.cc
|
| diff --git a/sandbox/win/src/restricted_token.cc b/sandbox/win/src/restricted_token.cc
|
| deleted file mode 100644
|
| index ea84d867ba622c4c9393783428aee6beb3a394ca..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/restricted_token.cc
|
| +++ /dev/null
|
| @@ -1,438 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "sandbox/win/src/restricted_token.h"
|
| -
|
| -#include <stddef.h>
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "sandbox/win/src/acl.h"
|
| -#include "sandbox/win/src/win_utils.h"
|
| -
|
| -namespace {
|
| -
|
| -// Calls GetTokenInformation with the desired |info_class| and returns a buffer
|
| -// with the result.
|
| -scoped_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token,
|
| - TOKEN_INFORMATION_CLASS info_class,
|
| - DWORD* error) {
|
| - // Get the required buffer size.
|
| - DWORD size = 0;
|
| - ::GetTokenInformation(token.Get(), info_class, NULL, 0, &size);
|
| - if (!size) {
|
| - *error = ::GetLastError();
|
| - return nullptr;
|
| - }
|
| -
|
| - scoped_ptr<BYTE[]> buffer(new BYTE[size]);
|
| - if (!::GetTokenInformation(token.Get(), info_class, buffer.get(), size,
|
| - &size)) {
|
| - *error = ::GetLastError();
|
| - return nullptr;
|
| - }
|
| -
|
| - *error = ERROR_SUCCESS;
|
| - return buffer;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace sandbox {
|
| -
|
| -RestrictedToken::RestrictedToken()
|
| - : integrity_level_(INTEGRITY_LEVEL_LAST),
|
| - init_(false),
|
| - lockdown_default_dacl_(false) {}
|
| -
|
| -RestrictedToken::~RestrictedToken() {
|
| -}
|
| -
|
| -DWORD RestrictedToken::Init(const HANDLE effective_token) {
|
| - if (init_)
|
| - return ERROR_ALREADY_INITIALIZED;
|
| -
|
| - HANDLE temp_token;
|
| - if (effective_token) {
|
| - // We duplicate the handle to be able to use it even if the original handle
|
| - // is closed.
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), effective_token,
|
| - ::GetCurrentProcess(), &temp_token,
|
| - 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
| - return ::GetLastError();
|
| - }
|
| - } else {
|
| - if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
|
| - &temp_token)) {
|
| - return ::GetLastError();
|
| - }
|
| - }
|
| - effective_token_.Set(temp_token);
|
| -
|
| - init_ = true;
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::GetRestrictedToken(
|
| - base::win::ScopedHandle* token) const {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - size_t deny_size = sids_for_deny_only_.size();
|
| - size_t restrict_size = sids_to_restrict_.size();
|
| - size_t privileges_size = privileges_to_disable_.size();
|
| -
|
| - SID_AND_ATTRIBUTES *deny_only_array = NULL;
|
| - if (deny_size) {
|
| - deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
|
| -
|
| - for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
|
| - deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
|
| - deny_only_array[i].Sid =
|
| - const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
|
| - }
|
| - }
|
| -
|
| - SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
|
| - if (restrict_size) {
|
| - sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
|
| -
|
| - for (unsigned int i = 0; i < restrict_size; ++i) {
|
| - sids_to_restrict_array[i].Attributes = 0;
|
| - sids_to_restrict_array[i].Sid =
|
| - const_cast<SID*>(sids_to_restrict_[i].GetPSID());
|
| - }
|
| - }
|
| -
|
| - LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
|
| - if (privileges_size) {
|
| - privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
|
| -
|
| - for (unsigned int i = 0; i < privileges_size; ++i) {
|
| - privileges_to_disable_array[i].Attributes = 0;
|
| - privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
|
| - }
|
| - }
|
| -
|
| - BOOL result = TRUE;
|
| - HANDLE new_token_handle = NULL;
|
| - // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
|
| - // if a token has ben restricted given the limiations of IsTokenRestricted()
|
| - // but it appears that in Windows 7 it hints the AppLocker subsystem to
|
| - // leave us alone.
|
| - if (deny_size || restrict_size || privileges_size) {
|
| - result = ::CreateRestrictedToken(effective_token_.Get(),
|
| - SANDBOX_INERT,
|
| - static_cast<DWORD>(deny_size),
|
| - deny_only_array,
|
| - static_cast<DWORD>(privileges_size),
|
| - privileges_to_disable_array,
|
| - static_cast<DWORD>(restrict_size),
|
| - sids_to_restrict_array,
|
| - &new_token_handle);
|
| - } else {
|
| - // Duplicate the token even if it's not modified at this point
|
| - // because any subsequent changes to this token would also affect the
|
| - // current process.
|
| - result = ::DuplicateTokenEx(effective_token_.Get(), TOKEN_ALL_ACCESS, NULL,
|
| - SecurityIdentification, TokenPrimary,
|
| - &new_token_handle);
|
| - }
|
| - auto last_error = ::GetLastError();
|
| -
|
| - if (deny_only_array)
|
| - delete[] deny_only_array;
|
| -
|
| - if (sids_to_restrict_array)
|
| - delete[] sids_to_restrict_array;
|
| -
|
| - if (privileges_to_disable_array)
|
| - delete[] privileges_to_disable_array;
|
| -
|
| - if (!result)
|
| - return last_error;
|
| -
|
| - base::win::ScopedHandle new_token(new_token_handle);
|
| -
|
| - if (lockdown_default_dacl_) {
|
| - // Don't add Restricted sid and also remove logon sid access.
|
| - if (!RevokeLogonSidFromDefaultDacl(new_token.Get()))
|
| - return ::GetLastError();
|
| - } else {
|
| - // Modify the default dacl on the token to contain Restricted.
|
| - if (!AddSidToDefaultDacl(new_token.Get(), WinRestrictedCodeSid,
|
| - GRANT_ACCESS, GENERIC_ALL)) {
|
| - return ::GetLastError();
|
| - }
|
| - }
|
| -
|
| - // Add user to default dacl.
|
| - if (!AddUserSidToDefaultDacl(new_token.Get(), GENERIC_ALL))
|
| - return ::GetLastError();
|
| -
|
| - DWORD error = SetTokenIntegrityLevel(new_token.Get(), integrity_level_);
|
| - if (ERROR_SUCCESS != error)
|
| - return error;
|
| -
|
| - HANDLE token_handle;
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), new_token.Get(),
|
| - ::GetCurrentProcess(), &token_handle,
|
| - TOKEN_ALL_ACCESS, FALSE, // Don't inherit.
|
| - 0)) {
|
| - return ::GetLastError();
|
| - }
|
| -
|
| - token->Set(token_handle);
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::GetRestrictedTokenForImpersonation(
|
| - base::win::ScopedHandle* token) const {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - base::win::ScopedHandle restricted_token;
|
| - DWORD err_code = GetRestrictedToken(&restricted_token);
|
| - if (ERROR_SUCCESS != err_code)
|
| - return err_code;
|
| -
|
| - HANDLE impersonation_token_handle;
|
| - if (!::DuplicateToken(restricted_token.Get(),
|
| - SecurityImpersonation,
|
| - &impersonation_token_handle)) {
|
| - return ::GetLastError();
|
| - }
|
| - base::win::ScopedHandle impersonation_token(impersonation_token_handle);
|
| -
|
| - HANDLE token_handle;
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), impersonation_token.Get(),
|
| - ::GetCurrentProcess(), &token_handle,
|
| - TOKEN_ALL_ACCESS, FALSE, // Don't inherit.
|
| - 0)) {
|
| - return ::GetLastError();
|
| - }
|
| -
|
| - token->Set(token_handle);
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - DWORD error;
|
| - scoped_ptr<BYTE[]> buffer =
|
| - GetTokenInfo(effective_token_, TokenGroups, &error);
|
| -
|
| - if (!buffer)
|
| - return error;
|
| -
|
| - TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
|
| -
|
| - // Build the list of the deny only group SIDs
|
| - for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
|
| - if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
|
| - (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
|
| - bool should_ignore = false;
|
| - if (exceptions) {
|
| - for (unsigned int j = 0; j < exceptions->size(); ++j) {
|
| - if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
|
| - token_groups->Groups[i].Sid)) {
|
| - should_ignore = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (!should_ignore) {
|
| - sids_for_deny_only_.push_back(
|
| - reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
|
| - }
|
| - }
|
| - }
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - sids_for_deny_only_.push_back(sid);
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddUserSidForDenyOnly() {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
|
| - scoped_ptr<BYTE[]> buffer(new BYTE[size]);
|
| - TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
|
| -
|
| - BOOL result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
|
| - token_user, size, &size);
|
| -
|
| - if (!result)
|
| - return ::GetLastError();
|
| -
|
| - Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
|
| - sids_for_deny_only_.push_back(user);
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::DeleteAllPrivileges(
|
| - const std::vector<base::string16> *exceptions) {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - DWORD error;
|
| - scoped_ptr<BYTE[]> buffer =
|
| - GetTokenInfo(effective_token_, TokenPrivileges, &error);
|
| -
|
| - if (!buffer)
|
| - return error;
|
| -
|
| - TOKEN_PRIVILEGES* token_privileges =
|
| - reinterpret_cast<TOKEN_PRIVILEGES*>(buffer.get());
|
| -
|
| - // Build the list of privileges to disable
|
| - for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
|
| - bool should_ignore = false;
|
| - if (exceptions) {
|
| - for (unsigned int j = 0; j < exceptions->size(); ++j) {
|
| - LUID luid = {0};
|
| - ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
|
| - if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
|
| - token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
|
| - should_ignore = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (!should_ignore) {
|
| - privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
|
| - }
|
| - }
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - LUID luid = {0};
|
| - if (LookupPrivilegeValue(NULL, privilege, &luid))
|
| - privileges_to_disable_.push_back(luid);
|
| - else
|
| - return ::GetLastError();
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddRestrictingSid(const Sid &sid) {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - sids_to_restrict_.push_back(sid); // No attributes
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddRestrictingSidLogonSession() {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - DWORD error;
|
| - scoped_ptr<BYTE[]> buffer =
|
| - GetTokenInfo(effective_token_, TokenGroups, &error);
|
| -
|
| - if (!buffer)
|
| - return error;
|
| -
|
| - TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
|
| -
|
| - SID *logon_sid = NULL;
|
| - for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
|
| - if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
|
| - logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (logon_sid)
|
| - sids_to_restrict_.push_back(logon_sid);
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddRestrictingSidCurrentUser() {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
|
| - scoped_ptr<BYTE[]> buffer(new BYTE[size]);
|
| - TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
|
| -
|
| - BOOL result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
|
| - token_user, size, &size);
|
| -
|
| - if (!result)
|
| - return ::GetLastError();
|
| -
|
| - Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
|
| - sids_to_restrict_.push_back(user);
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::AddRestrictingSidAllSids() {
|
| - DCHECK(init_);
|
| - if (!init_)
|
| - return ERROR_NO_TOKEN;
|
| -
|
| - // Add the current user to the list.
|
| - DWORD error = AddRestrictingSidCurrentUser();
|
| - if (ERROR_SUCCESS != error)
|
| - return error;
|
| -
|
| - scoped_ptr<BYTE[]> buffer =
|
| - GetTokenInfo(effective_token_, TokenGroups, &error);
|
| -
|
| - if (!buffer)
|
| - return error;
|
| -
|
| - TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
|
| -
|
| - // Build the list of restricting sids from all groups.
|
| - for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
|
| - if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
|
| - AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
|
| - }
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -DWORD RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
|
| - integrity_level_ = integrity_level;
|
| - return ERROR_SUCCESS;
|
| -}
|
| -
|
| -void RestrictedToken::SetLockdownDefaultDacl() {
|
| - lockdown_default_dacl_ = true;
|
| -}
|
| -
|
| -} // namespace sandbox
|
|
|