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