340 lines
13 KiB
C++
340 lines
13 KiB
C++
// 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
|