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