| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file contains unit tests for the RestrictedToken. |
| |
| #include "sandbox/win/src/restricted_token.h" |
| |
| #include <windows.h> |
| |
| #include <optional> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/ranges/algorithm.h" |
| #include "base/win/access_control_list.h" |
| #include "base/win/access_token.h" |
| #include "base/win/scoped_handle.h" |
| #include "base/win/security_descriptor.h" |
| #include "base/win/security_util.h" |
| #include "base/win/sid.h" |
| #include "sandbox/win/src/acl.h" |
| #include "sandbox/win/src/restricted_token_utils.h" |
| #include "sandbox/win/tests/common/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace sandbox { |
| |
| namespace { |
| |
| void TestDefaultDacl(bool restricted_required, bool additional_sid_required) { |
| RestrictedToken token; |
| |
| if (!restricted_required) |
| token.SetLockdownDefaultDacl(); |
| base::win::Sid additional_sid(base::win::WellKnownSid::kBuiltinGuests); |
| base::win::Sid additional_sid2(base::win::WellKnownSid::kBatch); |
| if (additional_sid_required) { |
| token.AddDefaultDaclSid( |
| additional_sid, base::win::SecurityAccessMode::kGrant, READ_CONTROL); |
| token.AddDefaultDaclSid(additional_sid2, |
| base::win::SecurityAccessMode::kDeny, GENERIC_ALL); |
| } |
| |
| token.AddRestrictingSid(base::win::WellKnownSid::kWorld); |
| auto restricted_token = *token.GetRestrictedToken(); |
| auto dacl = *restricted_token.DefaultDacl(); |
| |
| EXPECT_EQ(restricted_required, |
| IsSidInDacl(dacl, true, GENERIC_ALL, |
| base::win::Sid(base::win::WellKnownSid::kRestricted))); |
| EXPECT_EQ(additional_sid_required, |
| IsSidInDacl(dacl, true, READ_CONTROL, additional_sid)); |
| EXPECT_EQ(additional_sid_required, |
| IsSidInDacl(dacl, false, GENERIC_ALL, additional_sid2)); |
| auto logon_sid = restricted_token.LogonId(); |
| if (logon_sid) { |
| EXPECT_EQ(restricted_required, |
| IsSidInDacl(dacl, true, std::nullopt, *logon_sid)); |
| } |
| } |
| |
| // Checks if a sid is or is not in the restricting list of the restricted token. |
| // Asserts if it's not the case. If count is a positive number, the number of |
| // elements in the restricting sids list has to be equal. |
| void CheckRestrictingSid(const base::win::AccessToken& token, |
| const base::win::Sid& sid, |
| int count, |
| bool check_present = true) { |
| auto restricted_sids = token.RestrictedSids(); |
| if (count >= 0) |
| ASSERT_EQ(static_cast<unsigned>(count), restricted_sids.size()); |
| |
| bool present = false; |
| for (const base::win::AccessToken::Group& group : restricted_sids) { |
| if (group.GetSid() == sid) { |
| present = true; |
| break; |
| } |
| } |
| |
| ASSERT_EQ(present, check_present); |
| } |
| |
| void CheckRestrictingSid(const base::win::AccessToken& token, |
| base::win::WellKnownSid known_sid, |
| int count) { |
| CheckRestrictingSid(token, base::win::Sid(known_sid), count); |
| } |
| |
| DWORD GetMandatoryPolicy(const base::win::AccessToken& token) { |
| std::optional<base::win::SecurityDescriptor> sd = |
| base::win::SecurityDescriptor::FromHandle( |
| token.get(), base::win::SecurityObjectType::kKernel, |
| LABEL_SECURITY_INFORMATION); |
| CHECK(sd); |
| PACL sacl = sd->sacl()->get(); |
| for (DWORD ace_index = 0; ace_index < sacl->AceCount; ++ace_index) { |
| PSYSTEM_MANDATORY_LABEL_ACE ace; |
| |
| if (::GetAce(sacl, ace_index, reinterpret_cast<LPVOID*>(&ace)) && |
| ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) { |
| return ace->Mask; |
| } |
| } |
| return 0; |
| } |
| |
| base::win::AccessToken GetPrimaryToken(ACCESS_MASK desired_access) { |
| return *base::win::AccessToken::FromCurrentProcess(false, TOKEN_DUPLICATE) |
| ->DuplicatePrimary(desired_access); |
| } |
| |
| void CheckUniqueSid(TokenLevel level, bool check_present) { |
| std::optional<base::win::Sid> random_sid = |
| base::win::Sid::GenerateRandomSid(); |
| auto token = *CreateRestrictedToken(level, INTEGRITY_LEVEL_LAST, |
| TokenType::kPrimary, false, random_sid); |
| CheckRestrictingSid(token, *random_sid, -1, check_present); |
| auto dacl = *token.DefaultDacl(); |
| EXPECT_TRUE(IsSidInDacl(dacl, true, GENERIC_ALL, *random_sid)); |
| EXPECT_TRUE(IsSidInDacl( |
| dacl, true, READ_CONTROL, |
| base::win::Sid(base::win::WellKnownSid::kCreatorOwnerRights))); |
| } |
| |
| void CheckIntegrityLevel(IntegrityLevel integrity_level) { |
| std::optional<base::win::AccessToken> token = CreateRestrictedToken( |
| USER_LOCKDOWN, integrity_level, TokenType::kPrimary, false, std::nullopt); |
| ASSERT_TRUE(token); |
| std::optional<DWORD> rid = GetIntegrityLevelRid(integrity_level); |
| if (rid) { |
| EXPECT_EQ(token->IntegrityLevel(), *rid); |
| } else { |
| EXPECT_EQ(token->IntegrityLevel(), GetPrimaryToken(0).IntegrityLevel()); |
| } |
| } |
| |
| void CheckPrivileges(TokenLevel level, bool delete_all, bool remove_traversal) { |
| std::optional<base::win::AccessToken> token = CreateRestrictedToken( |
| level, INTEGRITY_LEVEL_LAST, TokenType::kPrimary, false, std::nullopt); |
| ASSERT_TRUE(token); |
| std::vector<base::win::AccessToken::Privilege> privs = token->Privileges(); |
| if (remove_traversal) { |
| EXPECT_EQ(privs.size(), 0U); |
| } else if (delete_all) { |
| EXPECT_EQ(privs.size(), 1U); |
| EXPECT_EQ(privs[0].GetName(), SE_CHANGE_NOTIFY_NAME); |
| } else { |
| std::vector<base::win::AccessToken::Privilege> primary_privs = |
| GetPrimaryToken(0).Privileges(); |
| ASSERT_EQ(privs.size(), primary_privs.size()); |
| for (size_t i = 0; i < privs.size(); ++i) { |
| EXPECT_EQ(privs[i].GetLuid(), primary_privs[i].GetLuid()); |
| } |
| } |
| } |
| |
| void CheckRestricted(const base::win::AccessToken& token, |
| const std::vector<base::win::Sid>& sids) { |
| std::vector<base::win::AccessToken::Group> restricted = |
| token.RestrictedSids(); |
| ASSERT_EQ(sids.size(), restricted.size()); |
| for (size_t i = 0; i < sids.size(); ++i) { |
| EXPECT_EQ(sids[i], restricted[i].GetSid()) |
| << *sids[i].ToSddlString() + L" != " + |
| *restricted[i].GetSid().ToSddlString(); |
| } |
| } |
| |
| void CheckRestricted(TokenLevel level, |
| const std::vector<base::win::WellKnownSid>& known_sids, |
| bool user, |
| bool logon) { |
| std::optional<base::win::AccessToken> token = CreateRestrictedToken( |
| level, INTEGRITY_LEVEL_LAST, TokenType::kPrimary, false, std::nullopt); |
| std::vector<base::win::Sid> sids = |
| base::win::Sid::FromKnownSidVector(known_sids); |
| if (user) { |
| sids.push_back(token->User()); |
| } |
| if (logon) { |
| std::optional<base::win::Sid> logon_sid = token->LogonId(); |
| if (logon_sid) { |
| sids.push_back(logon_sid->Clone()); |
| } |
| } |
| CheckRestricted(*token, sids); |
| } |
| |
| void CompareDenyOnly( |
| TokenLevel level, |
| const std::vector<base::win::WellKnownSid>& known_exceptions, |
| bool allow_all, |
| bool user) { |
| std::optional<base::win::AccessToken> token = CreateRestrictedToken( |
| level, INTEGRITY_LEVEL_LAST, TokenType::kPrimary, false, std::nullopt); |
| ASSERT_TRUE(token); |
| std::vector<base::win::Sid> exceptions = |
| base::win::Sid::FromKnownSidVector(known_exceptions); |
| std::vector<base::win::AccessToken::Group> groups = |
| GetPrimaryToken(0).Groups(); |
| std::vector<base::win::AccessToken::Group> compare_groups = token->Groups(); |
| ASSERT_EQ(groups.size(), compare_groups.size()); |
| for (size_t i = 0; i < groups.size(); ++i) { |
| const base::win::Sid& group_sid = groups[i].GetSid(); |
| ASSERT_EQ(group_sid, compare_groups[i].GetSid()); |
| if (groups[i].IsLogonId() || groups[i].IsIntegrity() || |
| groups[i].IsDenyOnly() || compare_groups[i].IsDenyOnly() || allow_all) { |
| continue; |
| } |
| EXPECT_NE(base::ranges::find(exceptions, group_sid), exceptions.end()); |
| } |
| EXPECT_EQ(user, token->UserGroup().IsDenyOnly()); |
| } |
| |
| } // namespace |
| |
| // Tests default initialization of the class. |
| TEST(RestrictedTokenTest, DefaultInit) { |
| RestrictedToken token_default; |
| std::optional<base::win::AccessToken> restricted_token = |
| token_default.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| |
| // Get the current process token. |
| std::optional<base::win::AccessToken> access_token = |
| base::win::AccessToken::FromCurrentProcess(); |
| ASSERT_TRUE(access_token); |
| // Check if both token have the same owner and user. |
| EXPECT_EQ(restricted_token->User(), access_token->User()); |
| EXPECT_EQ(restricted_token->Owner(), access_token->Owner()); |
| EXPECT_FALSE(restricted_token->IsImpersonation()); |
| EXPECT_FALSE(restricted_token->IsRestricted()); |
| EXPECT_EQ(DWORD{TOKEN_ALL_ACCESS}, |
| base::win::GetGrantedAccess(restricted_token->get())); |
| } |
| |
| // Verifies that the token created is valid. |
| TEST(RestrictedTokenTest, ResultToken) { |
| RestrictedToken token; |
| token.AddRestrictingSid(base::win::WellKnownSid::kWorld); |
| |
| std::optional<base::win::AccessToken> restricted_token = |
| token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| EXPECT_TRUE(restricted_token->IsRestricted()); |
| EXPECT_FALSE(restricted_token->IsImpersonation()); |
| } |
| |
| // Verifies that the token created has "Restricted" in its default dacl. |
| TEST(RestrictedTokenTest, DefaultDacl) { |
| TestDefaultDacl(true, false); |
| } |
| |
| // Verifies that the token created does not have "Restricted" in its default |
| // dacl. |
| TEST(RestrictedTokenTest, DefaultDaclLockdown) { |
| TestDefaultDacl(false, false); |
| } |
| |
| // Verifies that the token created has an additional SID in its default dacl. |
| TEST(RestrictedTokenTest, DefaultDaclWithAddition) { |
| TestDefaultDacl(true, true); |
| } |
| |
| // Verifies that the token created does not have "Restricted" in its default |
| // dacl and also has an additional SID. |
| TEST(RestrictedTokenTest, DefaultDaclLockdownWithAddition) { |
| TestDefaultDacl(false, true); |
| } |
| |
| // Tests the method "AddSidForDenyOnly". |
| TEST(RestrictedTokenTest, DenySid) { |
| RestrictedToken token; |
| |
| token.AddSidForDenyOnly(base::win::WellKnownSid::kWorld); |
| std::optional<base::win::AccessToken> restricted_token = |
| token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| base::win::Sid sid(base::win::WellKnownSid::kWorld); |
| bool found_sid = false; |
| for (const base::win::AccessToken::Group& group : |
| restricted_token->Groups()) { |
| if (sid == group.GetSid()) { |
| ASSERT_TRUE(group.IsDenyOnly()); |
| found_sid = true; |
| } |
| } |
| ASSERT_TRUE(found_sid); |
| } |
| |
| // Tests the method "AddAllSidsForDenyOnly". |
| TEST(RestrictedTokenTest, DenySids) { |
| RestrictedToken token; |
| |
| token.AddAllSidsForDenyOnly({}); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| bool found_sid = false; |
| // Verify that all sids are really gone. |
| for (const base::win::AccessToken::Group& group : |
| restricted_token->Groups()) { |
| if (group.IsLogonId() || group.IsIntegrity()) |
| continue; |
| ASSERT_TRUE(group.IsDenyOnly()); |
| found_sid = true; |
| } |
| // Check we at least found one SID. |
| ASSERT_TRUE(found_sid); |
| } |
| |
| // Tests the method "AddAllSidsForDenyOnly" using an exception list. |
| TEST(RestrictedTokenTest, DenySidsException) { |
| RestrictedToken token; |
| |
| std::vector<base::win::Sid> sids_exception = |
| base::win::Sid::FromKnownSidVector({base::win::WellKnownSid::kWorld}); |
| token.AddAllSidsForDenyOnly(sids_exception); |
| |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| |
| bool found_sid = false; |
| // Verify that all sids are really gone. |
| for (const base::win::AccessToken::Group& group : |
| restricted_token->Groups()) { |
| if (group.IsLogonId() || group.IsIntegrity()) |
| continue; |
| if (sids_exception[0] == group.GetSid()) { |
| ASSERT_FALSE(group.IsDenyOnly()); |
| // Check we at least found one SID. |
| found_sid = true; |
| } else { |
| ASSERT_TRUE(group.IsDenyOnly()); |
| } |
| } |
| ASSERT_TRUE(found_sid); |
| } |
| |
| // Tests test method AddOwnerSidForDenyOnly. |
| TEST(RestrictedTokenTest, DenyOwnerSid) { |
| RestrictedToken token; |
| token.AddUserSidForDenyOnly(); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| EXPECT_TRUE(restricted_token->UserGroup().IsDenyOnly()); |
| } |
| |
| // Tests the method DeleteAllPrivileges. |
| TEST(RestrictedTokenTest, DeleteAllPrivileges) { |
| RestrictedToken token; |
| token.DeleteAllPrivileges(/*remove_traversal_privilege=*/true); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| EXPECT_TRUE(restricted_token->Privileges().empty()); |
| } |
| |
| // Tests the method DeleteAllPrivileges with an exception list. |
| TEST(RestrictedTokenTest, DeleteAllPrivilegesException) { |
| RestrictedToken token; |
| token.DeleteAllPrivileges(/*remove_traversal_privilege=*/false); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| auto privileges = restricted_token->Privileges(); |
| ASSERT_EQ(1U, privileges.size()); |
| EXPECT_EQ(privileges[0].GetName(), SE_CHANGE_NOTIFY_NAME); |
| } |
| |
| // Tests the method AddRestrictingSid. |
| TEST(RestrictedTokenTest, AddRestrictingSid) { |
| RestrictedToken token; |
| token.AddRestrictingSid(base::win::WellKnownSid::kWorld); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| CheckRestrictingSid(*restricted_token, base::win::WellKnownSid::kWorld, 1); |
| } |
| |
| // Tests the method AddRestrictingSidCurrentUser. |
| TEST(RestrictedTokenTest, AddRestrictingSidCurrentUser) { |
| RestrictedToken token; |
| |
| token.AddRestrictingSidCurrentUser(); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| CheckRestrictingSid(*restricted_token, restricted_token->User(), 1); |
| } |
| |
| // Tests the method AddRestrictingSidLogonSession. |
| TEST(RestrictedTokenTest, AddRestrictingSidLogonSession) { |
| RestrictedToken token; |
| |
| token.AddRestrictingSidLogonSession(); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| auto session = restricted_token->LogonId(); |
| if (!session) { |
| ASSERT_EQ(static_cast<DWORD>(ERROR_NOT_FOUND), ::GetLastError()); |
| return; |
| } |
| |
| CheckRestrictingSid(*restricted_token, *session, 1); |
| } |
| |
| // Tests adding a lot of restricting sids. |
| TEST(RestrictedTokenTest, AddMultipleRestrictingSids) { |
| RestrictedToken token; |
| |
| token.AddRestrictingSidCurrentUser(); |
| token.AddRestrictingSidLogonSession(); |
| token.AddRestrictingSid(base::win::WellKnownSid::kWorld); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| ASSERT_EQ(3u, restricted_token->RestrictedSids().size()); |
| } |
| |
| // Tests the method "AddRestrictingSidAllSids". |
| TEST(RestrictedTokenTest, AddAllSidToRestrictingSids) { |
| RestrictedToken token; |
| |
| token.AddRestrictingSidAllSids(); |
| auto restricted_token = token.GetRestrictedToken(); |
| ASSERT_TRUE(restricted_token); |
| |
| // Verify that all group sids are in the restricting sid list. |
| for (const base::win::AccessToken::Group& group : |
| restricted_token->Groups()) { |
| if (!group.IsIntegrity()) |
| CheckRestrictingSid(*restricted_token, group.GetSid(), -1); |
| } |
| |
| CheckRestrictingSid(*restricted_token, restricted_token->User(), -1); |
| } |
| |
| TEST(RestrictedTokenTest, LockdownDefaultDaclNoLogonSid) { |
| ASSERT_TRUE(::ImpersonateAnonymousToken(::GetCurrentThread())); |
| std::optional<base::win::AccessToken> anonymous_token = |
| base::win::AccessToken::FromCurrentThread(/*open_as_self=*/true, |
| TOKEN_ALL_ACCESS); |
| ::RevertToSelf(); |
| ASSERT_TRUE(anonymous_token); |
| // Verify that the anonymous token doesn't have the logon sid. |
| ASSERT_FALSE(anonymous_token->LogonId()); |
| |
| RestrictedToken token; |
| token.SetLockdownDefaultDacl(); |
| |
| ASSERT_TRUE(token.GetRestrictedTokenForTesting(*anonymous_token)); |
| } |
| |
| TEST(RestrictedTokenTest, HardenProcessIntegrityLevelPolicy) { |
| base::win::AccessToken token = GetPrimaryToken(0); |
| EXPECT_EQ(HardenTokenIntegrityLevelPolicy(token), DWORD{ERROR_ACCESS_DENIED}); |
| token = GetPrimaryToken(READ_CONTROL | WRITE_OWNER); |
| DWORD current_policy = GetMandatoryPolicy(token); |
| EXPECT_EQ(HardenTokenIntegrityLevelPolicy(token), DWORD{ERROR_SUCCESS}); |
| EXPECT_EQ(GetMandatoryPolicy(token), |
| current_policy | SYSTEM_MANDATORY_LABEL_NO_READ_UP | |
| SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP); |
| } |
| |
| TEST(RestrictedTokenTest, TokenType) { |
| std::optional<base::win::AccessToken> token = |
| CreateRestrictedToken(USER_LOCKDOWN, INTEGRITY_LEVEL_LAST, |
| TokenType::kPrimary, false, std::nullopt); |
| ASSERT_TRUE(token); |
| EXPECT_FALSE(token->IsImpersonation()); |
| EXPECT_EQ(DWORD{TOKEN_ALL_ACCESS}, base::win::GetGrantedAccess(token->get())); |
| token = CreateRestrictedToken(USER_LOCKDOWN, INTEGRITY_LEVEL_LAST, |
| TokenType::kImpersonation, false, std::nullopt); |
| ASSERT_TRUE(token); |
| EXPECT_TRUE(token->IsImpersonation()); |
| EXPECT_EQ(token->ImpersonationLevel(), |
| base::win::SecurityImpersonationLevel::kImpersonation); |
| EXPECT_EQ(DWORD{TOKEN_ALL_ACCESS}, base::win::GetGrantedAccess(token->get())); |
| } |
| |
| TEST(RestrictedTokenTest, UniqueSid) { |
| CheckUniqueSid(USER_UNPROTECTED, false); |
| CheckUniqueSid(USER_RESTRICTED_SAME_ACCESS, false); |
| CheckUniqueSid(USER_RESTRICTED_NON_ADMIN, true); |
| CheckUniqueSid(USER_INTERACTIVE, true); |
| CheckUniqueSid(USER_LIMITED, true); |
| CheckUniqueSid(USER_LOCKDOWN, true); |
| } |
| |
| TEST(RestrictedTokenTest, IntegrityLevel) { |
| CheckIntegrityLevel(INTEGRITY_LEVEL_LAST); |
| CheckIntegrityLevel(INTEGRITY_LEVEL_MEDIUM); |
| CheckIntegrityLevel(INTEGRITY_LEVEL_MEDIUM_LOW); |
| CheckIntegrityLevel(INTEGRITY_LEVEL_LOW); |
| CheckIntegrityLevel(INTEGRITY_LEVEL_BELOW_LOW); |
| CheckIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED); |
| } |
| |
| TEST(RestrictedTokenTest, Privileges) { |
| CheckPrivileges(USER_UNPROTECTED, false, false); |
| CheckPrivileges(USER_RESTRICTED_SAME_ACCESS, false, false); |
| CheckPrivileges(USER_RESTRICTED_NON_ADMIN, true, false); |
| CheckPrivileges(USER_INTERACTIVE, true, false); |
| CheckPrivileges(USER_LIMITED, true, false); |
| CheckPrivileges(USER_LOCKDOWN, true, true); |
| } |
| |
| TEST(RestrictedTokenTest, Restricted) { |
| CheckRestricted(USER_UNPROTECTED, {}, false, false); |
| CheckRestricted( |
| USER_RESTRICTED_NON_ADMIN, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kInteractive, |
| base::win::WellKnownSid::kAuthenticatedUser, |
| base::win::WellKnownSid::kRestricted}, |
| true, true); |
| CheckRestricted( |
| USER_INTERACTIVE, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kRestricted}, |
| true, true); |
| CheckRestricted( |
| USER_LIMITED, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kRestricted}, |
| false, true); |
| CheckRestricted(USER_LOCKDOWN, {base::win::WellKnownSid::kNull}, false, |
| false); |
| |
| std::optional<base::win::AccessToken> token = |
| CreateRestrictedToken(USER_RESTRICTED_SAME_ACCESS, INTEGRITY_LEVEL_LAST, |
| TokenType::kPrimary, false, std::nullopt); |
| ASSERT_TRUE(token); |
| std::vector<base::win::Sid> sids; |
| sids.push_back(token->User()); |
| for (const base::win::AccessToken::Group& group : token->Groups()) { |
| if (!group.IsIntegrity()) { |
| sids.push_back(group.GetSid().Clone()); |
| } |
| } |
| CheckRestricted(*token, sids); |
| } |
| |
| TEST(RestrictedTokenTest, DenyOnly) { |
| CompareDenyOnly(USER_UNPROTECTED, {}, true, false); |
| CompareDenyOnly(USER_RESTRICTED_SAME_ACCESS, {}, true, false); |
| CompareDenyOnly( |
| USER_RESTRICTED_NON_ADMIN, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kInteractive, |
| base::win::WellKnownSid::kAuthenticatedUser}, |
| false, false); |
| CompareDenyOnly( |
| USER_INTERACTIVE, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kInteractive, |
| base::win::WellKnownSid::kAuthenticatedUser}, |
| false, false); |
| CompareDenyOnly( |
| USER_LIMITED, |
| {base::win::WellKnownSid::kBuiltinUsers, base::win::WellKnownSid::kWorld, |
| base::win::WellKnownSid::kInteractive}, |
| false, false); |
| CompareDenyOnly(USER_LOCKDOWN, {}, false, true); |
| } |
| |
| } // namespace sandbox |