blob: a11d9bbbeb51714b73c30a425fef9e7c00444815 [file] [log] [blame]
// 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