| // Copyright 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/win/sid.h" |
| |
| #include <windows.h> |
| |
| #include <sddl.h> |
| #include <stdlib.h> |
| |
| #include "base/check.h" |
| #include "base/cxx17_backports.h" |
| #include "base/notreached.h" |
| #include "base/rand_util.h" |
| #include "base/win/scoped_handle.h" |
| #include "base/win/scoped_localalloc.h" |
| #include "base/win/windows_version.h" |
| |
| namespace base { |
| namespace win { |
| |
| namespace { |
| |
| absl::optional<DWORD> WellKnownCapabilityToRid(WellKnownCapability capability) { |
| switch (capability) { |
| case WellKnownCapability::kInternetClient: |
| return SECURITY_CAPABILITY_INTERNET_CLIENT; |
| case WellKnownCapability::kInternetClientServer: |
| return SECURITY_CAPABILITY_INTERNET_CLIENT_SERVER; |
| case WellKnownCapability::kPrivateNetworkClientServer: |
| return SECURITY_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER; |
| case WellKnownCapability::kPicturesLibrary: |
| return SECURITY_CAPABILITY_PICTURES_LIBRARY; |
| case WellKnownCapability::kVideosLibrary: |
| return SECURITY_CAPABILITY_VIDEOS_LIBRARY; |
| case WellKnownCapability::kMusicLibrary: |
| return SECURITY_CAPABILITY_MUSIC_LIBRARY; |
| case WellKnownCapability::kDocumentsLibrary: |
| return SECURITY_CAPABILITY_DOCUMENTS_LIBRARY; |
| case WellKnownCapability::kEnterpriseAuthentication: |
| return SECURITY_CAPABILITY_ENTERPRISE_AUTHENTICATION; |
| case WellKnownCapability::kSharedUserCertificates: |
| return SECURITY_CAPABILITY_SHARED_USER_CERTIFICATES; |
| case WellKnownCapability::kRemovableStorage: |
| return SECURITY_CAPABILITY_REMOVABLE_STORAGE; |
| case WellKnownCapability::kAppointments: |
| return SECURITY_CAPABILITY_APPOINTMENTS; |
| case WellKnownCapability::kContacts: |
| return SECURITY_CAPABILITY_CONTACTS; |
| } |
| return absl::nullopt; |
| } |
| |
| absl::optional<WELL_KNOWN_SID_TYPE> WellKnownSidToEnum(WellKnownSid sid) { |
| switch (sid) { |
| case WellKnownSid::kNull: |
| return WinNullSid; |
| case WellKnownSid::kWorld: |
| return WinWorldSid; |
| case WellKnownSid::kCreatorOwner: |
| return WinCreatorOwnerSid; |
| case WellKnownSid::kNetwork: |
| return WinNetworkSid; |
| case WellKnownSid::kBatch: |
| return WinBatchSid; |
| case WellKnownSid::kInteractive: |
| return WinInteractiveSid; |
| case WellKnownSid::kService: |
| return WinServiceSid; |
| case WellKnownSid::kAnonymous: |
| return WinAnonymousSid; |
| case WellKnownSid::kSelf: |
| return WinSelfSid; |
| case WellKnownSid::kAuthenticatedUser: |
| return WinAuthenticatedUserSid; |
| case WellKnownSid::kRestricted: |
| return WinRestrictedCodeSid; |
| case WellKnownSid::kLocalSystem: |
| return WinLocalSystemSid; |
| case WellKnownSid::kLocalService: |
| return WinLocalServiceSid; |
| case WellKnownSid::kNetworkService: |
| return WinNetworkServiceSid; |
| case WellKnownSid::kBuiltinAdministrators: |
| return WinBuiltinAdministratorsSid; |
| case WellKnownSid::kBuiltinUsers: |
| return WinBuiltinUsersSid; |
| case WellKnownSid::kBuiltinGuests: |
| return WinBuiltinGuestsSid; |
| case WellKnownSid::kUntrustedLabel: |
| return WinUntrustedLabelSid; |
| case WellKnownSid::kLowLabel: |
| return WinLowLabelSid; |
| case WellKnownSid::kMediumLabel: |
| return WinMediumLabelSid; |
| case WellKnownSid::kHighLabel: |
| return WinHighLabelSid; |
| case WellKnownSid::kSystemLabel: |
| return WinSystemLabelSid; |
| case WellKnownSid::kWriteRestricted: |
| return WinWriteRestrictedCodeSid; |
| case WellKnownSid::kCreatorOwnerRights: |
| return WinCreatorOwnerRightsSid; |
| case WellKnownSid::kAllApplicationPackages: |
| return WinBuiltinAnyPackageSid; |
| case WellKnownSid::kAllRestrictedApplicationPackages: |
| // This should be handled by FromKnownSid. |
| NOTREACHED(); |
| break; |
| } |
| return absl::nullopt; |
| } |
| |
| absl::optional<Sid> FromSubAuthorities( |
| PSID_IDENTIFIER_AUTHORITY identifier_authority, |
| BYTE sub_authority_count, |
| PDWORD sub_authorities) { |
| BYTE sid[SECURITY_MAX_SID_SIZE]; |
| if (!::InitializeSid(sid, identifier_authority, sub_authority_count)) |
| return absl::nullopt; |
| |
| for (DWORD index = 0; index < sub_authority_count; ++index) { |
| PDWORD sub_authority = ::GetSidSubAuthority(sid, index); |
| *sub_authority = sub_authorities[index]; |
| } |
| return Sid::FromPSID(sid); |
| } |
| |
| template <typename T> |
| absl::optional<std::vector<Sid>> FromVector( |
| const std::vector<T>& values, |
| absl::optional<Sid> (*create_sid)(T)) { |
| std::vector<Sid> converted_sids; |
| converted_sids.reserve(values.size()); |
| for (T value : values) { |
| auto sid = create_sid(value); |
| if (!sid) |
| return absl::nullopt; |
| converted_sids.push_back(std::move(*sid)); |
| } |
| return converted_sids; |
| } |
| |
| } // namespace |
| |
| Sid::Sid(const void* sid, size_t length) |
| : sid_(static_cast<const char*>(sid), |
| static_cast<const char*>(sid) + length) { |
| DCHECK(::IsValidSid(GetPSID())); |
| } |
| |
| absl::optional<Sid> Sid::FromKnownCapability(WellKnownCapability capability) { |
| absl::optional<DWORD> capability_rid = WellKnownCapabilityToRid(capability); |
| if (!capability_rid) |
| return absl::nullopt; |
| SID_IDENTIFIER_AUTHORITY capability_authority = { |
| SECURITY_APP_PACKAGE_AUTHORITY}; |
| DWORD sub_authorities[] = {SECURITY_CAPABILITY_BASE_RID, *capability_rid}; |
| return FromSubAuthorities(&capability_authority, size(sub_authorities), |
| sub_authorities); |
| } |
| |
| absl::optional<Sid> Sid::FromNamedCapability(const wchar_t* capability_name) { |
| DCHECK_GE(GetVersion(), Version::WIN10); |
| |
| if (!capability_name || !*capability_name) |
| return absl::nullopt; |
| |
| typedef decltype( |
| ::DeriveCapabilitySidsFromName)* DeriveCapabilitySidsFromNameFunc; |
| static const DeriveCapabilitySidsFromNameFunc derive_capability_sids = |
| []() -> DeriveCapabilitySidsFromNameFunc { |
| HMODULE module = GetModuleHandle(L"api-ms-win-security-base-l1-2-2.dll"); |
| if (!module) |
| return nullptr; |
| |
| return reinterpret_cast<DeriveCapabilitySidsFromNameFunc>( |
| ::GetProcAddress(module, "DeriveCapabilitySidsFromName")); |
| }(); |
| if (!derive_capability_sids) |
| return absl::nullopt; |
| |
| // Pre-reserve some space for SID deleters. |
| std::vector<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; |
| |
| if (!derive_capability_sids(capability_name, &capability_groups, |
| &capability_group_count, &capability_sids, |
| &capability_sid_count)) { |
| return absl::nullopt; |
| } |
| |
| 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]); |
| } |
| |
| if (capability_sid_count < 1) |
| return absl::nullopt; |
| |
| return FromPSID(capability_sids[0]); |
| } |
| |
| absl::optional<Sid> Sid::FromKnownSid(WellKnownSid type) { |
| if (type == WellKnownSid::kAllRestrictedApplicationPackages) { |
| SID_IDENTIFIER_AUTHORITY package_authority = { |
| SECURITY_APP_PACKAGE_AUTHORITY}; |
| DWORD sub_authorities[] = {SECURITY_APP_PACKAGE_BASE_RID, |
| SECURITY_BUILTIN_PACKAGE_ANY_RESTRICTED_PACKAGE}; |
| return FromSubAuthorities(&package_authority, 2, sub_authorities); |
| } |
| |
| BYTE sid[SECURITY_MAX_SID_SIZE]; |
| DWORD size_sid = SECURITY_MAX_SID_SIZE; |
| absl::optional<WELL_KNOWN_SID_TYPE> known_sid = WellKnownSidToEnum(type); |
| if (!known_sid) |
| return absl::nullopt; |
| if (!::CreateWellKnownSid(*known_sid, nullptr, sid, &size_sid)) |
| return absl::nullopt; |
| |
| return Sid(sid, size_sid); |
| } |
| |
| absl::optional<Sid> Sid::FromSddlString(const wchar_t* sddl_sid) { |
| PSID psid = nullptr; |
| if (!::ConvertStringSidToSid(sddl_sid, &psid)) |
| return absl::nullopt; |
| return FromPSID(TakeLocalAlloc(psid).get()); |
| } |
| |
| absl::optional<Sid> Sid::FromPSID(PSID sid) { |
| DCHECK(sid); |
| if (!sid || !::IsValidSid(sid)) |
| return absl::nullopt; |
| return Sid(sid, ::GetLengthSid(sid)); |
| } |
| |
| absl::optional<Sid> Sid::GenerateRandomSid() { |
| SID_IDENTIFIER_AUTHORITY package_authority = {SECURITY_NULL_SID_AUTHORITY}; |
| DWORD sub_authorities[4] = {}; |
| RandBytes(&sub_authorities, sizeof(sub_authorities)); |
| return FromSubAuthorities(&package_authority, _countof(sub_authorities), |
| sub_authorities); |
| } |
| |
| absl::optional<Sid> Sid::FromIntegrityLevel(DWORD integrity_level) { |
| SID_IDENTIFIER_AUTHORITY package_authority = { |
| SECURITY_MANDATORY_LABEL_AUTHORITY}; |
| return FromSubAuthorities(&package_authority, 1, &integrity_level); |
| } |
| |
| absl::optional<std::vector<Sid>> Sid::FromSddlStringVector( |
| const std::vector<const wchar_t*>& sddl_sids) { |
| return FromVector(sddl_sids, Sid::FromSddlString); |
| } |
| |
| absl::optional<std::vector<Sid>> Sid::FromNamedCapabilityVector( |
| const std::vector<const wchar_t*>& capability_names) { |
| return FromVector(capability_names, Sid::FromNamedCapability); |
| } |
| |
| absl::optional<std::vector<Sid>> Sid::FromKnownCapabilityVector( |
| const std::vector<WellKnownCapability>& capabilities) { |
| return FromVector(capabilities, Sid::FromKnownCapability); |
| } |
| |
| absl::optional<std::vector<Sid>> Sid::FromKnownSidVector( |
| const std::vector<WellKnownSid>& sids) { |
| return FromVector(sids, Sid::FromKnownSid); |
| } |
| |
| Sid::Sid(Sid&& sid) = default; |
| Sid& Sid::operator=(Sid&&) = default; |
| Sid::~Sid() = default; |
| |
| PSID Sid::GetPSID() const { |
| DCHECK(!sid_.empty()); |
| return const_cast<char*>(sid_.data()); |
| } |
| |
| // Converts the SID to an SDDL format string. |
| absl::optional<std::wstring> Sid::ToSddlString() const { |
| LPWSTR sid = nullptr; |
| if (!::ConvertSidToStringSid(GetPSID(), &sid)) |
| return absl::nullopt; |
| return TakeLocalAlloc(sid).get(); |
| } |
| |
| Sid Sid::Clone() const { |
| return Sid(sid_.data(), sid_.size()); |
| } |
| |
| bool Sid::Equal(PSID sid) const { |
| return !!::EqualSid(GetPSID(), sid); |
| } |
| |
| bool Sid::operator==(const Sid& sid) const { |
| return Equal(sid.GetPSID()); |
| } |
| |
| bool Sid::operator!=(const Sid& sid) const { |
| return !(operator==(sid)); |
| } |
| |
| } // namespace win |
| } // namespace base |