| // Copyright 2021 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 sid class. |
| |
| #include "base/win/sid.h" |
| |
| #include <windows.h> |
| |
| #include <sddl.h> |
| |
| #include "base/ranges/algorithm.h" |
| #include "base/win/atl.h" |
| #include "base/win/scoped_handle.h" |
| #include "base/win/scoped_localalloc.h" |
| #include "base/win/win_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace base::win { |
| |
| namespace { |
| |
| bool EqualSid(const absl::optional<Sid>& sid, const ATL::CSid& compare_sid) { |
| if (!sid) |
| return false; |
| return sid->Equal(const_cast<SID*>(compare_sid.GetPSID())); |
| } |
| |
| bool EqualSid(const Sid& sid, const std::wstring& sddl_sid) { |
| PSID compare_sid; |
| if (!::ConvertStringSidToSid(sddl_sid.c_str(), &compare_sid)) { |
| return false; |
| } |
| auto sid_ptr = TakeLocalAlloc(compare_sid); |
| return sid.Equal(sid_ptr.get()); |
| } |
| |
| bool EqualSid(const absl::optional<Sid>& sid, WELL_KNOWN_SID_TYPE known_sid) { |
| if (!sid) |
| return false; |
| char known_sid_buffer[SECURITY_MAX_SID_SIZE] = {}; |
| DWORD size = SECURITY_MAX_SID_SIZE; |
| if (!::CreateWellKnownSid(known_sid, nullptr, known_sid_buffer, &size)) |
| return false; |
| |
| return sid->Equal(known_sid_buffer); |
| } |
| |
| bool TestSidVector(absl::optional<std::vector<Sid>> sids, |
| const std::vector<std::wstring>& sddl) { |
| return sids && ranges::equal(*sids, sddl, |
| [](const Sid& sid, const std::wstring& sddl) { |
| return EqualSid(sid, sddl); |
| }); |
| } |
| |
| bool TestFromSddlStringVector(const std::vector<std::wstring> sddl) { |
| return TestSidVector(Sid::FromSddlStringVector(sddl), sddl); |
| } |
| |
| bool EqualNamedCapSid(const Sid& sid, const std::wstring& capability_name) { |
| typedef decltype(::DeriveCapabilitySidsFromName)* |
| DeriveCapabilitySidsFromNameFunc; |
| static const DeriveCapabilitySidsFromNameFunc derive_capability_sids = |
| []() -> DeriveCapabilitySidsFromNameFunc { |
| HMODULE module = GetModuleHandle(L"api-ms-win-security-base-l1-2-2.dll"); |
| CHECK(module); |
| return reinterpret_cast<DeriveCapabilitySidsFromNameFunc>( |
| ::GetProcAddress(module, "DeriveCapabilitySidsFromName")); |
| }(); |
| CHECK(derive_capability_sids); |
| |
| // Pre-reserve some space for SID deleters. |
| std::vector<base::win::ScopedLocalAlloc> deleter_list; |
| deleter_list.reserve(16); |
| |
| PSID* capability_groups = nullptr; |
| DWORD capability_group_count = 0; |
| PSID* capability_sids = nullptr; |
| DWORD capability_sid_count = 0; |
| |
| CHECK(derive_capability_sids(capability_name.c_str(), &capability_groups, |
| &capability_group_count, &capability_sids, |
| &capability_sid_count)); |
| deleter_list.emplace_back(capability_groups); |
| deleter_list.emplace_back(capability_sids); |
| |
| for (DWORD i = 0; i < capability_group_count; ++i) { |
| deleter_list.emplace_back(capability_groups[i]); |
| } |
| for (DWORD i = 0; i < capability_sid_count; ++i) { |
| deleter_list.emplace_back(capability_sids[i]); |
| } |
| |
| CHECK_GE(capability_sid_count, 1U); |
| return sid.Equal(capability_sids[0]); |
| } |
| |
| struct KnownCapabilityTestEntry { |
| WellKnownCapability capability; |
| const wchar_t* sddl_sid; |
| }; |
| |
| struct KnownSidTestEntry { |
| WellKnownSid sid; |
| WELL_KNOWN_SID_TYPE well_known_sid; |
| }; |
| |
| } // namespace |
| |
| // Tests the creation of a Sid. |
| TEST(SidTest, Initializers) { |
| ATL::CSid sid_world = ATL::Sids::World(); |
| PSID sid_world_pointer = const_cast<SID*>(sid_world.GetPSID()); |
| |
| // Check the PSID constructor. |
| absl::optional<Sid> sid_sid_star = Sid::FromPSID(sid_world_pointer); |
| ASSERT_TRUE(EqualSid(sid_sid_star, sid_world)); |
| |
| char invalid_sid[16] = {}; |
| ASSERT_FALSE(Sid::FromPSID(invalid_sid)); |
| |
| absl::optional<Sid> sid_sddl = Sid::FromSddlString(L"S-1-1-0"); |
| ASSERT_TRUE(sid_sddl); |
| ASSERT_TRUE(EqualSid(sid_sddl, sid_world)); |
| } |
| |
| TEST(SidTest, KnownCapability) { |
| const KnownCapabilityTestEntry capabilities[] = { |
| {WellKnownCapability::kInternetClient, L"S-1-15-3-1"}, |
| {WellKnownCapability::kInternetClientServer, L"S-1-15-3-2"}, |
| {WellKnownCapability::kPrivateNetworkClientServer, L"S-1-15-3-3"}, |
| {WellKnownCapability::kPicturesLibrary, L"S-1-15-3-4"}, |
| {WellKnownCapability::kVideosLibrary, L"S-1-15-3-5"}, |
| {WellKnownCapability::kMusicLibrary, L"S-1-15-3-6"}, |
| {WellKnownCapability::kDocumentsLibrary, L"S-1-15-3-7"}, |
| {WellKnownCapability::kEnterpriseAuthentication, L"S-1-15-3-8"}, |
| {WellKnownCapability::kSharedUserCertificates, L"S-1-15-3-9"}, |
| {WellKnownCapability::kRemovableStorage, L"S-1-15-3-10"}, |
| {WellKnownCapability::kAppointments, L"S-1-15-3-11"}, |
| {WellKnownCapability::kContacts, L"S-1-15-3-12"}, |
| }; |
| |
| for (auto capability : capabilities) { |
| EXPECT_TRUE(EqualSid(Sid::FromKnownCapability(capability.capability), |
| capability.sddl_sid)) |
| << "Known Capability: " << capability.sddl_sid; |
| EXPECT_TRUE(EqualSid(Sid(capability.capability), capability.sddl_sid)) |
| << "Known Capability: " << capability.sddl_sid; |
| } |
| } |
| |
| TEST(SidTest, NamedCapability) { |
| const std::wstring capabilities[] = {L"", |
| L"InternetClient", |
| L"InternetClientServer", |
| L"PrivateNetworkClientServer", |
| L"PicturesLibrary", |
| L"VideosLibrary", |
| L"MusicLibrary", |
| L"DocumentsLibrary", |
| L"EnterpriseAuthentication", |
| L"SharedUserCertificates", |
| L"RemovableStorage", |
| L"Appointments", |
| L"Contacts", |
| L"registryRead", |
| L"lpacCryptoServices"}; |
| |
| for (const std::wstring& capability : capabilities) { |
| EXPECT_TRUE( |
| EqualNamedCapSid(Sid::FromNamedCapability(capability), capability)) |
| << "Named Capability: " << capability; |
| } |
| } |
| |
| TEST(SidTest, KnownSids) { |
| const KnownSidTestEntry known_sids[] = { |
| {WellKnownSid::kNull, ::WinNullSid}, |
| {WellKnownSid::kWorld, ::WinWorldSid}, |
| {WellKnownSid::kCreatorOwner, ::WinCreatorOwnerSid}, |
| {WellKnownSid::kNetwork, ::WinNetworkSid}, |
| {WellKnownSid::kBatch, ::WinBatchSid}, |
| {WellKnownSid::kInteractive, ::WinInteractiveSid}, |
| {WellKnownSid::kService, ::WinServiceSid}, |
| {WellKnownSid::kAnonymous, ::WinAnonymousSid}, |
| {WellKnownSid::kSelf, ::WinSelfSid}, |
| {WellKnownSid::kAuthenticatedUser, ::WinAuthenticatedUserSid}, |
| {WellKnownSid::kRestricted, ::WinRestrictedCodeSid}, |
| {WellKnownSid::kLocalSystem, ::WinLocalSystemSid}, |
| {WellKnownSid::kLocalService, ::WinLocalServiceSid}, |
| {WellKnownSid::kNetworkService, ::WinNetworkServiceSid}, |
| {WellKnownSid::kBuiltinAdministrators, ::WinBuiltinAdministratorsSid}, |
| {WellKnownSid::kBuiltinUsers, ::WinBuiltinUsersSid}, |
| {WellKnownSid::kBuiltinGuests, ::WinBuiltinGuestsSid}, |
| {WellKnownSid::kUntrustedLabel, ::WinUntrustedLabelSid}, |
| {WellKnownSid::kLowLabel, ::WinLowLabelSid}, |
| {WellKnownSid::kMediumLabel, ::WinMediumLabelSid}, |
| {WellKnownSid::kHighLabel, ::WinHighLabelSid}, |
| {WellKnownSid::kSystemLabel, ::WinSystemLabelSid}, |
| {WellKnownSid::kWriteRestricted, ::WinWriteRestrictedCodeSid}, |
| {WellKnownSid::kCreatorOwnerRights, ::WinCreatorOwnerRightsSid}, |
| {WellKnownSid::kAllApplicationPackages, ::WinBuiltinAnyPackageSid}}; |
| |
| for (auto known_sid : known_sids) { |
| EXPECT_TRUE( |
| EqualSid(Sid::FromKnownSid(known_sid.sid), known_sid.well_known_sid)) |
| << "Known Sid: " << static_cast<int>(known_sid.sid); |
| EXPECT_TRUE(EqualSid(Sid(known_sid.sid), known_sid.well_known_sid)) |
| << "Known Sid: " << static_cast<int>(known_sid.sid); |
| } |
| |
| EXPECT_TRUE(EqualSid( |
| Sid::FromKnownSid(WellKnownSid::kAllRestrictedApplicationPackages), |
| L"S-1-15-2-2")); |
| } |
| |
| TEST(SidTest, SddlString) { |
| absl::optional<Sid> sid_sddl = Sid::FromSddlString(L"S-1-1-0"); |
| ASSERT_TRUE(sid_sddl); |
| absl::optional<std::wstring> sddl_str = sid_sddl->ToSddlString(); |
| ASSERT_TRUE(sddl_str); |
| ASSERT_EQ(L"S-1-1-0", *sddl_str); |
| ASSERT_FALSE(Sid::FromSddlString(L"X-1-1-0")); |
| ASSERT_FALSE(Sid::FromSddlString(L"")); |
| } |
| |
| TEST(SidTest, RandomSid) { |
| Sid sid1 = Sid::GenerateRandomSid(); |
| Sid sid2 = Sid::GenerateRandomSid(); |
| EXPECT_NE(sid1, sid2); |
| } |
| |
| TEST(SidTest, FromIntegrityLevel) { |
| ASSERT_TRUE(EqualSid( |
| Sid::FromIntegrityLevel(SECURITY_MANDATORY_UNTRUSTED_RID), L"S-1-16-0")); |
| ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_LOW_RID), |
| L"S-1-16-4096")); |
| ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_MEDIUM_RID), |
| L"S-1-16-8192")); |
| ASSERT_TRUE( |
| EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_MEDIUM_PLUS_RID), |
| L"S-1-16-8448")); |
| ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_HIGH_RID), |
| L"S-1-16-12288")); |
| ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_SYSTEM_RID), |
| L"S-1-16-16384")); |
| ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(1234), L"S-1-16-1234")); |
| } |
| |
| TEST(SidTest, FromSddlStringVector) { |
| ASSERT_TRUE( |
| TestFromSddlStringVector({L"S-1-1-0", L"S-1-15-2-2", L"S-1-15-3-2"})); |
| ASSERT_FALSE( |
| TestFromSddlStringVector({L"S-1-1-0", L"X-1-15-2-2", L"S-1-15-3-2"})); |
| ASSERT_FALSE(TestFromSddlStringVector({L""})); |
| ASSERT_TRUE(TestFromSddlStringVector({})); |
| } |
| |
| TEST(SidTest, FromNamedCapabilityVector) { |
| std::vector<std::wstring> capabilities = {L"", |
| L"InternetClient", |
| L"InternetClientServer", |
| L"PrivateNetworkClientServer", |
| L"PicturesLibrary", |
| L"VideosLibrary", |
| L"MusicLibrary", |
| L"DocumentsLibrary", |
| L"EnterpriseAuthentication", |
| L"SharedUserCertificates", |
| L"RemovableStorage", |
| L"Appointments", |
| L"Contacts", |
| L"registryRead", |
| L"lpacCryptoServices"}; |
| |
| ASSERT_TRUE(ranges::equal(Sid::FromNamedCapabilityVector(capabilities), |
| capabilities, EqualNamedCapSid)); |
| EXPECT_EQ(Sid::FromNamedCapabilityVector({}).size(), 0U); |
| } |
| |
| TEST(SidTest, FromKnownCapabilityVector) { |
| ASSERT_TRUE(TestSidVector( |
| Sid::FromKnownCapabilityVector( |
| {WellKnownCapability::kInternetClient, |
| WellKnownCapability::kInternetClientServer, |
| WellKnownCapability::kPrivateNetworkClientServer, |
| WellKnownCapability::kPicturesLibrary, |
| WellKnownCapability::kVideosLibrary, |
| WellKnownCapability::kMusicLibrary, |
| WellKnownCapability::kDocumentsLibrary, |
| WellKnownCapability::kEnterpriseAuthentication, |
| WellKnownCapability::kSharedUserCertificates, |
| WellKnownCapability::kRemovableStorage, |
| WellKnownCapability::kAppointments, WellKnownCapability::kContacts}), |
| {L"S-1-15-3-1", L"S-1-15-3-2", L"S-1-15-3-3", L"S-1-15-3-4", |
| L"S-1-15-3-5", L"S-1-15-3-6", L"S-1-15-3-7", L"S-1-15-3-8", |
| L"S-1-15-3-9", L"S-1-15-3-10", L"S-1-15-3-11", L"S-1-15-3-12"})); |
| |
| ASSERT_FALSE(TestSidVector( |
| Sid::FromKnownCapabilityVector({WellKnownCapability::kInternetClient}), |
| {L"S-1-1-0"})); |
| } |
| |
| TEST(SidTest, FromKnownSidVector) { |
| ASSERT_TRUE(TestSidVector( |
| Sid::FromKnownSidVector({WellKnownSid::kNull, WellKnownSid::kWorld}), |
| {L"S-1-0-0", L"S-1-1-0"})); |
| |
| ASSERT_FALSE(TestSidVector(Sid::FromKnownSidVector({WellKnownSid::kNull}), |
| {L"S-1-1-0"})); |
| } |
| |
| TEST(SidTest, Equal) { |
| Sid world_sid = Sid::FromKnownSid(WellKnownSid::kWorld); |
| EXPECT_EQ(world_sid, world_sid); |
| auto world_sid_sddl = Sid::FromSddlString(L"S-1-1-0"); |
| ASSERT_TRUE(world_sid_sddl); |
| EXPECT_EQ(world_sid, world_sid_sddl); |
| EXPECT_EQ(world_sid_sddl, world_sid); |
| EXPECT_TRUE(world_sid.Equal(world_sid_sddl->GetPSID())); |
| EXPECT_TRUE(world_sid_sddl->Equal(world_sid.GetPSID())); |
| Sid null_sid = Sid::FromKnownSid(WellKnownSid::kNull); |
| EXPECT_NE(world_sid, null_sid); |
| EXPECT_NE(null_sid, world_sid); |
| EXPECT_FALSE(world_sid.Equal(null_sid.GetPSID())); |
| EXPECT_FALSE(null_sid.Equal(world_sid.GetPSID())); |
| } |
| |
| TEST(SidTest, Clone) { |
| Sid world_sid = Sid::FromKnownSid(WellKnownSid::kWorld); |
| auto world_sid_clone = world_sid.Clone(); |
| EXPECT_NE(world_sid.GetPSID(), world_sid_clone.GetPSID()); |
| EXPECT_EQ(world_sid, world_sid_clone); |
| } |
| |
| } // namespace base::win |