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