311 lines
11 KiB
C++
311 lines
11 KiB
C++
|
|
// Copyright 2021 The Chromium Authors
|
||
|
|
// 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 <stdint.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
|
||
|
|
#include <iterator>
|
||
|
|
#include <map>
|
||
|
|
#include <utility>
|
||
|
|
|
||
|
|
#include "base/check.h"
|
||
|
|
#include "base/no_destructor.h"
|
||
|
|
#include "base/rand_util.h"
|
||
|
|
#include "base/ranges/algorithm.h"
|
||
|
|
#include "base/strings/string_util_win.h"
|
||
|
|
#include "base/win/scoped_handle.h"
|
||
|
|
#include "base/win/scoped_localalloc.h"
|
||
|
|
#include "base/win/windows_version.h"
|
||
|
|
#include "third_party/boringssl/src/include/openssl/crypto.h"
|
||
|
|
#include "third_party/boringssl/src/include/openssl/sha.h"
|
||
|
|
|
||
|
|
namespace base::win {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
template <typename Iterator>
|
||
|
|
Sid FromSubAuthorities(const SID_IDENTIFIER_AUTHORITY& identifier_authority,
|
||
|
|
size_t sub_authority_count,
|
||
|
|
Iterator sub_authorities) {
|
||
|
|
DCHECK(sub_authority_count <= SID_MAX_SUB_AUTHORITIES);
|
||
|
|
BYTE sid_buffer[SECURITY_MAX_SID_SIZE];
|
||
|
|
SID* sid = reinterpret_cast<SID*>(sid_buffer);
|
||
|
|
sid->Revision = SID_REVISION;
|
||
|
|
sid->SubAuthorityCount = static_cast<UCHAR>(sub_authority_count);
|
||
|
|
sid->IdentifierAuthority = identifier_authority;
|
||
|
|
for (size_t index = 0; index < sub_authority_count; ++index) {
|
||
|
|
sid->SubAuthority[index] = static_cast<DWORD>(*sub_authorities++);
|
||
|
|
}
|
||
|
|
DCHECK(::IsValidSid(sid));
|
||
|
|
return *Sid::FromPSID(sid);
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid FromSubAuthorities(const SID_IDENTIFIER_AUTHORITY& identifier_authority,
|
||
|
|
std::initializer_list<int32_t> sub_authorities) {
|
||
|
|
return FromSubAuthorities(identifier_authority, sub_authorities.size(),
|
||
|
|
sub_authorities.begin());
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid FromNtAuthority(std::initializer_list<int32_t> sub_authorities) {
|
||
|
|
return FromSubAuthorities(SECURITY_NT_AUTHORITY, sub_authorities);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t 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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
Sid::Sid(const void* sid, size_t length)
|
||
|
|
: sid_(static_cast<const char*>(sid),
|
||
|
|
static_cast<const char*>(sid) + length) {
|
||
|
|
DCHECK(::IsValidSid(GetPSID()));
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid Sid::FromKnownCapability(WellKnownCapability capability) {
|
||
|
|
int32_t capability_rid = WellKnownCapabilityToRid(capability);
|
||
|
|
return FromSubAuthorities(SECURITY_APP_PACKAGE_AUTHORITY,
|
||
|
|
{SECURITY_CAPABILITY_BASE_RID, capability_rid});
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid Sid::FromNamedCapability(const std::wstring& capability_name) {
|
||
|
|
static const base::NoDestructor<std::map<std::wstring, WellKnownCapability>>
|
||
|
|
known_capabilities(
|
||
|
|
{{L"INTERNETCLIENT", WellKnownCapability::kInternetClient},
|
||
|
|
{L"INTERNETCLIENTSERVER",
|
||
|
|
WellKnownCapability::kInternetClientServer},
|
||
|
|
{L"PRIVATENETWORKCLIENTSERVER",
|
||
|
|
WellKnownCapability::kPrivateNetworkClientServer},
|
||
|
|
{L"PICTURESLIBRARY", WellKnownCapability::kPicturesLibrary},
|
||
|
|
{L"VIDEOSLIBRARY", WellKnownCapability::kVideosLibrary},
|
||
|
|
{L"MUSICLIBRARY", WellKnownCapability::kMusicLibrary},
|
||
|
|
{L"DOCUMENTSLIBRARY", WellKnownCapability::kDocumentsLibrary},
|
||
|
|
{L"ENTERPRISEAUTHENTICATION",
|
||
|
|
WellKnownCapability::kEnterpriseAuthentication},
|
||
|
|
{L"SHAREDUSERCERTIFICATES",
|
||
|
|
WellKnownCapability::kSharedUserCertificates},
|
||
|
|
{L"REMOVABLESTORAGE", WellKnownCapability::kRemovableStorage},
|
||
|
|
{L"APPOINTMENTS", WellKnownCapability::kAppointments},
|
||
|
|
{L"CONTACTS", WellKnownCapability::kContacts}});
|
||
|
|
|
||
|
|
std::wstring cap_upper = base::ToUpperASCII(capability_name);
|
||
|
|
auto known_cap = known_capabilities->find(cap_upper);
|
||
|
|
if (known_cap != known_capabilities->end()) {
|
||
|
|
return FromKnownCapability(known_cap->second);
|
||
|
|
}
|
||
|
|
CRYPTO_library_init();
|
||
|
|
static_assert((SHA256_DIGEST_LENGTH / sizeof(DWORD)) ==
|
||
|
|
SECURITY_APP_PACKAGE_RID_COUNT);
|
||
|
|
DWORD rids[(SHA256_DIGEST_LENGTH / sizeof(DWORD)) + 2];
|
||
|
|
rids[0] = SECURITY_CAPABILITY_BASE_RID;
|
||
|
|
rids[1] = SECURITY_CAPABILITY_APP_RID;
|
||
|
|
|
||
|
|
SHA256(reinterpret_cast<const uint8_t*>(cap_upper.c_str()),
|
||
|
|
cap_upper.size() * sizeof(wchar_t),
|
||
|
|
reinterpret_cast<uint8_t*>(&rids[2]));
|
||
|
|
return FromSubAuthorities(SECURITY_APP_PACKAGE_AUTHORITY, std::size(rids),
|
||
|
|
rids);
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid Sid::FromKnownSid(WellKnownSid type) {
|
||
|
|
switch (type) {
|
||
|
|
case WellKnownSid::kNull:
|
||
|
|
return FromSubAuthorities(SECURITY_NULL_SID_AUTHORITY,
|
||
|
|
{SECURITY_NULL_RID});
|
||
|
|
case WellKnownSid::kWorld:
|
||
|
|
return FromSubAuthorities(SECURITY_WORLD_SID_AUTHORITY,
|
||
|
|
{SECURITY_WORLD_RID});
|
||
|
|
case WellKnownSid::kCreatorOwner:
|
||
|
|
return FromSubAuthorities(SECURITY_CREATOR_SID_AUTHORITY,
|
||
|
|
{SECURITY_CREATOR_OWNER_RID});
|
||
|
|
case WellKnownSid::kCreatorOwnerRights:
|
||
|
|
return FromSubAuthorities(SECURITY_CREATOR_SID_AUTHORITY,
|
||
|
|
{SECURITY_CREATOR_OWNER_RIGHTS_RID});
|
||
|
|
case WellKnownSid::kNetwork:
|
||
|
|
return FromNtAuthority({SECURITY_NETWORK_RID});
|
||
|
|
case WellKnownSid::kBatch:
|
||
|
|
return FromNtAuthority({SECURITY_BATCH_RID});
|
||
|
|
case WellKnownSid::kInteractive:
|
||
|
|
return FromNtAuthority({SECURITY_INTERACTIVE_RID});
|
||
|
|
case WellKnownSid::kService:
|
||
|
|
return FromNtAuthority({SECURITY_SERVICE_RID});
|
||
|
|
case WellKnownSid::kAnonymous:
|
||
|
|
return FromNtAuthority({SECURITY_ANONYMOUS_LOGON_RID});
|
||
|
|
case WellKnownSid::kSelf:
|
||
|
|
return FromNtAuthority({SECURITY_PRINCIPAL_SELF_RID});
|
||
|
|
case WellKnownSid::kAuthenticatedUser:
|
||
|
|
return FromNtAuthority({SECURITY_AUTHENTICATED_USER_RID});
|
||
|
|
case WellKnownSid::kRestricted:
|
||
|
|
return FromNtAuthority({SECURITY_RESTRICTED_CODE_RID});
|
||
|
|
case WellKnownSid::kWriteRestricted:
|
||
|
|
return FromNtAuthority({SECURITY_WRITE_RESTRICTED_CODE_RID});
|
||
|
|
case WellKnownSid::kLocalSystem:
|
||
|
|
return FromNtAuthority({SECURITY_LOCAL_SYSTEM_RID});
|
||
|
|
case WellKnownSid::kLocalService:
|
||
|
|
return FromNtAuthority({SECURITY_LOCAL_SERVICE_RID});
|
||
|
|
case WellKnownSid::kNetworkService:
|
||
|
|
return FromNtAuthority({SECURITY_NETWORK_SERVICE_RID});
|
||
|
|
case WellKnownSid::kBuiltinAdministrators:
|
||
|
|
return FromNtAuthority(
|
||
|
|
{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS});
|
||
|
|
case WellKnownSid::kBuiltinUsers:
|
||
|
|
return FromNtAuthority(
|
||
|
|
{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS});
|
||
|
|
case WellKnownSid::kBuiltinGuests:
|
||
|
|
return FromNtAuthority(
|
||
|
|
{SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS});
|
||
|
|
case WellKnownSid::kUntrustedLabel:
|
||
|
|
return FromIntegrityLevel(SECURITY_MANDATORY_UNTRUSTED_RID);
|
||
|
|
case WellKnownSid::kLowLabel:
|
||
|
|
return FromIntegrityLevel(SECURITY_MANDATORY_LOW_RID);
|
||
|
|
case WellKnownSid::kMediumLabel:
|
||
|
|
return FromIntegrityLevel(SECURITY_MANDATORY_MEDIUM_RID);
|
||
|
|
case WellKnownSid::kHighLabel:
|
||
|
|
return FromIntegrityLevel(SECURITY_MANDATORY_HIGH_RID);
|
||
|
|
case WellKnownSid::kSystemLabel:
|
||
|
|
return FromIntegrityLevel(SECURITY_MANDATORY_SYSTEM_RID);
|
||
|
|
case WellKnownSid::kAllApplicationPackages:
|
||
|
|
return FromSubAuthorities(SECURITY_APP_PACKAGE_AUTHORITY,
|
||
|
|
{SECURITY_APP_PACKAGE_BASE_RID,
|
||
|
|
SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE});
|
||
|
|
case WellKnownSid::kAllRestrictedApplicationPackages:
|
||
|
|
return FromSubAuthorities(
|
||
|
|
SECURITY_APP_PACKAGE_AUTHORITY,
|
||
|
|
{SECURITY_APP_PACKAGE_BASE_RID,
|
||
|
|
SECURITY_BUILTIN_PACKAGE_ANY_RESTRICTED_PACKAGE});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
absl::optional<Sid> Sid::FromSddlString(const std::wstring& sddl_sid) {
|
||
|
|
PSID psid = nullptr;
|
||
|
|
if (!::ConvertStringSidToSid(sddl_sid.c_str(), &psid)) {
|
||
|
|
return absl::nullopt;
|
||
|
|
}
|
||
|
|
auto psid_alloc = TakeLocalAlloc(psid);
|
||
|
|
return FromPSID(psid_alloc.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
absl::optional<Sid> Sid::FromPSID(PSID sid) {
|
||
|
|
DCHECK(sid);
|
||
|
|
if (!sid || !::IsValidSid(sid))
|
||
|
|
return absl::nullopt;
|
||
|
|
return Sid(sid, ::GetLengthSid(sid));
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid Sid::GenerateRandomSid() {
|
||
|
|
DWORD sub_authorities[4] = {};
|
||
|
|
RandBytes(&sub_authorities, sizeof(sub_authorities));
|
||
|
|
return FromSubAuthorities(SECURITY_NULL_SID_AUTHORITY,
|
||
|
|
std::size(sub_authorities), sub_authorities);
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid Sid::FromIntegrityLevel(DWORD integrity_level) {
|
||
|
|
return FromSubAuthorities(SECURITY_MANDATORY_LABEL_AUTHORITY, 1,
|
||
|
|
&integrity_level);
|
||
|
|
}
|
||
|
|
|
||
|
|
absl::optional<std::vector<Sid>> Sid::FromSddlStringVector(
|
||
|
|
const std::vector<std::wstring>& sddl_sids) {
|
||
|
|
std::vector<Sid> converted_sids;
|
||
|
|
converted_sids.reserve(sddl_sids.size());
|
||
|
|
for (const std::wstring& sddl_sid : sddl_sids) {
|
||
|
|
absl::optional<Sid> sid = FromSddlString(sddl_sid);
|
||
|
|
if (!sid)
|
||
|
|
return absl::nullopt;
|
||
|
|
converted_sids.push_back(std::move(*sid));
|
||
|
|
}
|
||
|
|
return converted_sids;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<Sid> Sid::FromNamedCapabilityVector(
|
||
|
|
const std::vector<std::wstring>& capability_names) {
|
||
|
|
std::vector<Sid> sids;
|
||
|
|
ranges::transform(capability_names, std::back_inserter(sids),
|
||
|
|
FromNamedCapability);
|
||
|
|
return sids;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<Sid> Sid::FromKnownCapabilityVector(
|
||
|
|
const std::vector<WellKnownCapability>& capabilities) {
|
||
|
|
std::vector<Sid> sids;
|
||
|
|
ranges::transform(capabilities, std::back_inserter(sids),
|
||
|
|
FromKnownCapability);
|
||
|
|
return sids;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<Sid> Sid::FromKnownSidVector(
|
||
|
|
const std::vector<WellKnownSid>& known_sids) {
|
||
|
|
std::vector<Sid> sids;
|
||
|
|
ranges::transform(known_sids, std::back_inserter(sids), FromKnownSid);
|
||
|
|
return sids;
|
||
|
|
}
|
||
|
|
|
||
|
|
Sid::Sid(WellKnownSid known_sid) : Sid(FromKnownSid(known_sid)) {}
|
||
|
|
Sid::Sid(WellKnownCapability known_capability)
|
||
|
|
: Sid(FromKnownCapability(known_capability)) {}
|
||
|
|
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());
|
||
|
|
}
|
||
|
|
|
||
|
|
absl::optional<std::wstring> Sid::ToSddlString() const {
|
||
|
|
LPWSTR sid = nullptr;
|
||
|
|
if (!::ConvertSidToStringSid(GetPSID(), &sid))
|
||
|
|
return absl::nullopt;
|
||
|
|
auto sid_ptr = TakeLocalAlloc(sid);
|
||
|
|
return sid_ptr.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 base::win
|