• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file contains unit tests for the sid class.
6 
7 #include "base/win/sid.h"
8 
9 #include <windows.h>
10 
11 #include <sddl.h>
12 
13 #include "base/ranges/algorithm.h"
14 #include "base/win/atl.h"
15 #include "base/win/scoped_handle.h"
16 #include "base/win/scoped_localalloc.h"
17 #include "base/win/win_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
20 
21 namespace base::win {
22 
23 namespace {
24 
EqualSid(const absl::optional<Sid> & sid,const ATL::CSid & compare_sid)25 bool EqualSid(const absl::optional<Sid>& sid, const ATL::CSid& compare_sid) {
26   if (!sid)
27     return false;
28   return sid->Equal(const_cast<SID*>(compare_sid.GetPSID()));
29 }
30 
EqualSid(const Sid & sid,const std::wstring & sddl_sid)31 bool EqualSid(const Sid& sid, const std::wstring& sddl_sid) {
32   PSID compare_sid;
33   if (!::ConvertStringSidToSid(sddl_sid.c_str(), &compare_sid)) {
34     return false;
35   }
36   auto sid_ptr = TakeLocalAlloc(compare_sid);
37   return sid.Equal(sid_ptr.get());
38 }
39 
EqualSid(const absl::optional<Sid> & sid,WELL_KNOWN_SID_TYPE known_sid)40 bool EqualSid(const absl::optional<Sid>& sid, WELL_KNOWN_SID_TYPE known_sid) {
41   if (!sid)
42     return false;
43   char known_sid_buffer[SECURITY_MAX_SID_SIZE] = {};
44   DWORD size = SECURITY_MAX_SID_SIZE;
45   if (!::CreateWellKnownSid(known_sid, nullptr, known_sid_buffer, &size))
46     return false;
47 
48   return sid->Equal(known_sid_buffer);
49 }
50 
TestSidVector(absl::optional<std::vector<Sid>> sids,const std::vector<std::wstring> & sddl)51 bool TestSidVector(absl::optional<std::vector<Sid>> sids,
52                    const std::vector<std::wstring>& sddl) {
53   return sids && ranges::equal(*sids, sddl,
54                                [](const Sid& sid, const std::wstring& sddl) {
55                                  return EqualSid(sid, sddl);
56                                });
57 }
58 
TestFromSddlStringVector(const std::vector<std::wstring> sddl)59 bool TestFromSddlStringVector(const std::vector<std::wstring> sddl) {
60   return TestSidVector(Sid::FromSddlStringVector(sddl), sddl);
61 }
62 
EqualNamedCapSid(const Sid & sid,const std::wstring & capability_name)63 bool EqualNamedCapSid(const Sid& sid, const std::wstring& capability_name) {
64   typedef decltype(::DeriveCapabilitySidsFromName)*
65       DeriveCapabilitySidsFromNameFunc;
66   static const DeriveCapabilitySidsFromNameFunc derive_capability_sids =
67       []() -> DeriveCapabilitySidsFromNameFunc {
68     HMODULE module = GetModuleHandle(L"api-ms-win-security-base-l1-2-2.dll");
69     CHECK(module);
70     return reinterpret_cast<DeriveCapabilitySidsFromNameFunc>(
71         ::GetProcAddress(module, "DeriveCapabilitySidsFromName"));
72   }();
73   CHECK(derive_capability_sids);
74 
75   // Pre-reserve some space for SID deleters.
76   std::vector<base::win::ScopedLocalAlloc> deleter_list;
77   deleter_list.reserve(16);
78 
79   PSID* capability_groups = nullptr;
80   DWORD capability_group_count = 0;
81   PSID* capability_sids = nullptr;
82   DWORD capability_sid_count = 0;
83 
84   CHECK(derive_capability_sids(capability_name.c_str(), &capability_groups,
85                                &capability_group_count, &capability_sids,
86                                &capability_sid_count));
87   deleter_list.emplace_back(capability_groups);
88   deleter_list.emplace_back(capability_sids);
89 
90   for (DWORD i = 0; i < capability_group_count; ++i) {
91     deleter_list.emplace_back(capability_groups[i]);
92   }
93   for (DWORD i = 0; i < capability_sid_count; ++i) {
94     deleter_list.emplace_back(capability_sids[i]);
95   }
96 
97   CHECK_GE(capability_sid_count, 1U);
98   return sid.Equal(capability_sids[0]);
99 }
100 
101 struct KnownCapabilityTestEntry {
102   WellKnownCapability capability;
103   const wchar_t* sddl_sid;
104 };
105 
106 struct KnownSidTestEntry {
107   WellKnownSid sid;
108   WELL_KNOWN_SID_TYPE well_known_sid;
109 };
110 
111 }  // namespace
112 
113 // Tests the creation of a Sid.
TEST(SidTest,Initializers)114 TEST(SidTest, Initializers) {
115   ATL::CSid sid_world = ATL::Sids::World();
116   PSID sid_world_pointer = const_cast<SID*>(sid_world.GetPSID());
117 
118   // Check the PSID constructor.
119   absl::optional<Sid> sid_sid_star = Sid::FromPSID(sid_world_pointer);
120   ASSERT_TRUE(EqualSid(sid_sid_star, sid_world));
121 
122   char invalid_sid[16] = {};
123   ASSERT_FALSE(Sid::FromPSID(invalid_sid));
124 
125   absl::optional<Sid> sid_sddl = Sid::FromSddlString(L"S-1-1-0");
126   ASSERT_TRUE(sid_sddl);
127   ASSERT_TRUE(EqualSid(sid_sddl, sid_world));
128 }
129 
TEST(SidTest,KnownCapability)130 TEST(SidTest, KnownCapability) {
131   const KnownCapabilityTestEntry capabilities[] = {
132       {WellKnownCapability::kInternetClient, L"S-1-15-3-1"},
133       {WellKnownCapability::kInternetClientServer, L"S-1-15-3-2"},
134       {WellKnownCapability::kPrivateNetworkClientServer, L"S-1-15-3-3"},
135       {WellKnownCapability::kPicturesLibrary, L"S-1-15-3-4"},
136       {WellKnownCapability::kVideosLibrary, L"S-1-15-3-5"},
137       {WellKnownCapability::kMusicLibrary, L"S-1-15-3-6"},
138       {WellKnownCapability::kDocumentsLibrary, L"S-1-15-3-7"},
139       {WellKnownCapability::kEnterpriseAuthentication, L"S-1-15-3-8"},
140       {WellKnownCapability::kSharedUserCertificates, L"S-1-15-3-9"},
141       {WellKnownCapability::kRemovableStorage, L"S-1-15-3-10"},
142       {WellKnownCapability::kAppointments, L"S-1-15-3-11"},
143       {WellKnownCapability::kContacts, L"S-1-15-3-12"},
144   };
145 
146   for (auto capability : capabilities) {
147     EXPECT_TRUE(EqualSid(Sid::FromKnownCapability(capability.capability),
148                          capability.sddl_sid))
149         << "Known Capability: " << capability.sddl_sid;
150     EXPECT_TRUE(EqualSid(Sid(capability.capability), capability.sddl_sid))
151         << "Known Capability: " << capability.sddl_sid;
152   }
153 }
154 
TEST(SidTest,NamedCapability)155 TEST(SidTest, NamedCapability) {
156   const std::wstring capabilities[] = {L"",
157                                        L"InternetClient",
158                                        L"InternetClientServer",
159                                        L"PrivateNetworkClientServer",
160                                        L"PicturesLibrary",
161                                        L"VideosLibrary",
162                                        L"MusicLibrary",
163                                        L"DocumentsLibrary",
164                                        L"EnterpriseAuthentication",
165                                        L"SharedUserCertificates",
166                                        L"RemovableStorage",
167                                        L"Appointments",
168                                        L"Contacts",
169                                        L"registryRead",
170                                        L"lpacCryptoServices"};
171 
172   for (const std::wstring& capability : capabilities) {
173     EXPECT_TRUE(
174         EqualNamedCapSid(Sid::FromNamedCapability(capability), capability))
175         << "Named Capability: " << capability;
176   }
177 }
178 
TEST(SidTest,KnownSids)179 TEST(SidTest, KnownSids) {
180   const KnownSidTestEntry known_sids[] = {
181       {WellKnownSid::kNull, ::WinNullSid},
182       {WellKnownSid::kWorld, ::WinWorldSid},
183       {WellKnownSid::kCreatorOwner, ::WinCreatorOwnerSid},
184       {WellKnownSid::kNetwork, ::WinNetworkSid},
185       {WellKnownSid::kBatch, ::WinBatchSid},
186       {WellKnownSid::kInteractive, ::WinInteractiveSid},
187       {WellKnownSid::kService, ::WinServiceSid},
188       {WellKnownSid::kAnonymous, ::WinAnonymousSid},
189       {WellKnownSid::kSelf, ::WinSelfSid},
190       {WellKnownSid::kAuthenticatedUser, ::WinAuthenticatedUserSid},
191       {WellKnownSid::kRestricted, ::WinRestrictedCodeSid},
192       {WellKnownSid::kLocalSystem, ::WinLocalSystemSid},
193       {WellKnownSid::kLocalService, ::WinLocalServiceSid},
194       {WellKnownSid::kNetworkService, ::WinNetworkServiceSid},
195       {WellKnownSid::kBuiltinAdministrators, ::WinBuiltinAdministratorsSid},
196       {WellKnownSid::kBuiltinUsers, ::WinBuiltinUsersSid},
197       {WellKnownSid::kBuiltinGuests, ::WinBuiltinGuestsSid},
198       {WellKnownSid::kUntrustedLabel, ::WinUntrustedLabelSid},
199       {WellKnownSid::kLowLabel, ::WinLowLabelSid},
200       {WellKnownSid::kMediumLabel, ::WinMediumLabelSid},
201       {WellKnownSid::kHighLabel, ::WinHighLabelSid},
202       {WellKnownSid::kSystemLabel, ::WinSystemLabelSid},
203       {WellKnownSid::kWriteRestricted, ::WinWriteRestrictedCodeSid},
204       {WellKnownSid::kCreatorOwnerRights, ::WinCreatorOwnerRightsSid},
205       {WellKnownSid::kAllApplicationPackages, ::WinBuiltinAnyPackageSid}};
206 
207   for (auto known_sid : known_sids) {
208     EXPECT_TRUE(
209         EqualSid(Sid::FromKnownSid(known_sid.sid), known_sid.well_known_sid))
210         << "Known Sid: " << static_cast<int>(known_sid.sid);
211     EXPECT_TRUE(EqualSid(Sid(known_sid.sid), known_sid.well_known_sid))
212         << "Known Sid: " << static_cast<int>(known_sid.sid);
213   }
214 
215   EXPECT_TRUE(EqualSid(
216       Sid::FromKnownSid(WellKnownSid::kAllRestrictedApplicationPackages),
217       L"S-1-15-2-2"));
218 }
219 
TEST(SidTest,SddlString)220 TEST(SidTest, SddlString) {
221   absl::optional<Sid> sid_sddl = Sid::FromSddlString(L"S-1-1-0");
222   ASSERT_TRUE(sid_sddl);
223   absl::optional<std::wstring> sddl_str = sid_sddl->ToSddlString();
224   ASSERT_TRUE(sddl_str);
225   ASSERT_EQ(L"S-1-1-0", *sddl_str);
226   ASSERT_FALSE(Sid::FromSddlString(L"X-1-1-0"));
227   ASSERT_FALSE(Sid::FromSddlString(L""));
228 }
229 
TEST(SidTest,RandomSid)230 TEST(SidTest, RandomSid) {
231   Sid sid1 = Sid::GenerateRandomSid();
232   Sid sid2 = Sid::GenerateRandomSid();
233   EXPECT_NE(sid1, sid2);
234 }
235 
TEST(SidTest,FromIntegrityLevel)236 TEST(SidTest, FromIntegrityLevel) {
237   ASSERT_TRUE(EqualSid(
238       Sid::FromIntegrityLevel(SECURITY_MANDATORY_UNTRUSTED_RID), L"S-1-16-0"));
239   ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_LOW_RID),
240                        L"S-1-16-4096"));
241   ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_MEDIUM_RID),
242                        L"S-1-16-8192"));
243   ASSERT_TRUE(
244       EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_MEDIUM_PLUS_RID),
245                L"S-1-16-8448"));
246   ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_HIGH_RID),
247                        L"S-1-16-12288"));
248   ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(SECURITY_MANDATORY_SYSTEM_RID),
249                        L"S-1-16-16384"));
250   ASSERT_TRUE(EqualSid(Sid::FromIntegrityLevel(1234), L"S-1-16-1234"));
251 }
252 
TEST(SidTest,FromSddlStringVector)253 TEST(SidTest, FromSddlStringVector) {
254   ASSERT_TRUE(
255       TestFromSddlStringVector({L"S-1-1-0", L"S-1-15-2-2", L"S-1-15-3-2"}));
256   ASSERT_FALSE(
257       TestFromSddlStringVector({L"S-1-1-0", L"X-1-15-2-2", L"S-1-15-3-2"}));
258   ASSERT_FALSE(TestFromSddlStringVector({L""}));
259   ASSERT_TRUE(TestFromSddlStringVector({}));
260 }
261 
TEST(SidTest,FromNamedCapabilityVector)262 TEST(SidTest, FromNamedCapabilityVector) {
263   std::vector<std::wstring> capabilities = {L"",
264                                             L"InternetClient",
265                                             L"InternetClientServer",
266                                             L"PrivateNetworkClientServer",
267                                             L"PicturesLibrary",
268                                             L"VideosLibrary",
269                                             L"MusicLibrary",
270                                             L"DocumentsLibrary",
271                                             L"EnterpriseAuthentication",
272                                             L"SharedUserCertificates",
273                                             L"RemovableStorage",
274                                             L"Appointments",
275                                             L"Contacts",
276                                             L"registryRead",
277                                             L"lpacCryptoServices"};
278 
279   ASSERT_TRUE(ranges::equal(Sid::FromNamedCapabilityVector(capabilities),
280                             capabilities, EqualNamedCapSid));
281   EXPECT_EQ(Sid::FromNamedCapabilityVector({}).size(), 0U);
282 }
283 
TEST(SidTest,FromKnownCapabilityVector)284 TEST(SidTest, FromKnownCapabilityVector) {
285   ASSERT_TRUE(TestSidVector(
286       Sid::FromKnownCapabilityVector(
287           {WellKnownCapability::kInternetClient,
288            WellKnownCapability::kInternetClientServer,
289            WellKnownCapability::kPrivateNetworkClientServer,
290            WellKnownCapability::kPicturesLibrary,
291            WellKnownCapability::kVideosLibrary,
292            WellKnownCapability::kMusicLibrary,
293            WellKnownCapability::kDocumentsLibrary,
294            WellKnownCapability::kEnterpriseAuthentication,
295            WellKnownCapability::kSharedUserCertificates,
296            WellKnownCapability::kRemovableStorage,
297            WellKnownCapability::kAppointments, WellKnownCapability::kContacts}),
298       {L"S-1-15-3-1", L"S-1-15-3-2", L"S-1-15-3-3", L"S-1-15-3-4",
299        L"S-1-15-3-5", L"S-1-15-3-6", L"S-1-15-3-7", L"S-1-15-3-8",
300        L"S-1-15-3-9", L"S-1-15-3-10", L"S-1-15-3-11", L"S-1-15-3-12"}));
301 
302   ASSERT_FALSE(TestSidVector(
303       Sid::FromKnownCapabilityVector({WellKnownCapability::kInternetClient}),
304       {L"S-1-1-0"}));
305 }
306 
TEST(SidTest,FromKnownSidVector)307 TEST(SidTest, FromKnownSidVector) {
308   ASSERT_TRUE(TestSidVector(
309       Sid::FromKnownSidVector({WellKnownSid::kNull, WellKnownSid::kWorld}),
310       {L"S-1-0-0", L"S-1-1-0"}));
311 
312   ASSERT_FALSE(TestSidVector(Sid::FromKnownSidVector({WellKnownSid::kNull}),
313                              {L"S-1-1-0"}));
314 }
315 
TEST(SidTest,Equal)316 TEST(SidTest, Equal) {
317   Sid world_sid = Sid::FromKnownSid(WellKnownSid::kWorld);
318   EXPECT_EQ(world_sid, world_sid);
319   auto world_sid_sddl = Sid::FromSddlString(L"S-1-1-0");
320   ASSERT_TRUE(world_sid_sddl);
321   EXPECT_EQ(world_sid, world_sid_sddl);
322   EXPECT_EQ(world_sid_sddl, world_sid);
323   EXPECT_TRUE(world_sid.Equal(world_sid_sddl->GetPSID()));
324   EXPECT_TRUE(world_sid_sddl->Equal(world_sid.GetPSID()));
325   Sid null_sid = Sid::FromKnownSid(WellKnownSid::kNull);
326   EXPECT_NE(world_sid, null_sid);
327   EXPECT_NE(null_sid, world_sid);
328   EXPECT_FALSE(world_sid.Equal(null_sid.GetPSID()));
329   EXPECT_FALSE(null_sid.Equal(world_sid.GetPSID()));
330 }
331 
TEST(SidTest,Clone)332 TEST(SidTest, Clone) {
333   Sid world_sid = Sid::FromKnownSid(WellKnownSid::kWorld);
334   auto world_sid_clone = world_sid.Clone();
335   EXPECT_NE(world_sid.GetPSID(), world_sid_clone.GetPSID());
336   EXPECT_EQ(world_sid, world_sid_clone);
337 }
338 
339 }  // namespace base::win
340