// Copyright 2022 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/access_control_list.h" #include #include #include #include #include "base/check.h" #include "base/logging.h" #include "base/notreached.h" #include "base/numerics/checked_math.h" #include "base/win/scoped_localalloc.h" namespace base::win { namespace { std::unique_ptr AclToBuffer(const ACL* acl) { if (!acl) { return nullptr; } size_t size = acl->AclSize; DCHECK(size >= sizeof(*acl)); std::unique_ptr ptr = std::make_unique(size); memcpy(ptr.get(), acl, size); return ptr; } std::unique_ptr EmptyAclToBuffer() { ACL acl = {}; acl.AclRevision = ACL_REVISION; acl.AclSize = static_cast(sizeof(acl)); return AclToBuffer(&acl); } ACCESS_MODE ConvertAccessMode(SecurityAccessMode access_mode) { switch (access_mode) { case SecurityAccessMode::kGrant: return GRANT_ACCESS; case SecurityAccessMode::kSet: return SET_ACCESS; case SecurityAccessMode::kDeny: return DENY_ACCESS; case SecurityAccessMode::kRevoke: return REVOKE_ACCESS; } } std::unique_ptr AddACEToAcl( ACL* old_acl, const std::vector& entries) { std::vector access_entries(entries.size()); auto entries_interator = access_entries.begin(); for (const ExplicitAccessEntry& entry : entries) { EXPLICIT_ACCESS& new_access = *entries_interator++; new_access.grfAccessMode = ConvertAccessMode(entry.mode()); new_access.grfAccessPermissions = entry.access_mask(); new_access.grfInheritance = entry.inheritance(); ::BuildTrusteeWithSid(&new_access.Trustee, entry.sid().GetPSID()); } PACL new_acl = nullptr; DWORD error = ::SetEntriesInAcl(checked_cast(access_entries.size()), access_entries.data(), old_acl, &new_acl); if (error != ERROR_SUCCESS) { ::SetLastError(error); DPLOG(ERROR) << "Failed adding ACEs to ACL"; return nullptr; } auto new_acl_ptr = TakeLocalAlloc(new_acl); return AclToBuffer(new_acl_ptr.get()); } } // namespace ExplicitAccessEntry ExplicitAccessEntry::Clone() const { return ExplicitAccessEntry{sid_, mode_, access_mask_, inheritance_}; } ExplicitAccessEntry::ExplicitAccessEntry(const Sid& sid, SecurityAccessMode mode, DWORD access_mask, DWORD inheritance) : sid_(sid.Clone()), mode_(mode), access_mask_(access_mask), inheritance_(inheritance) {} ExplicitAccessEntry::ExplicitAccessEntry(WellKnownSid known_sid, SecurityAccessMode mode, DWORD access_mask, DWORD inheritance) : ExplicitAccessEntry(Sid(known_sid), mode, access_mask, inheritance) {} ExplicitAccessEntry::ExplicitAccessEntry(ExplicitAccessEntry&&) = default; ExplicitAccessEntry& ExplicitAccessEntry::operator=(ExplicitAccessEntry&&) = default; ExplicitAccessEntry::~ExplicitAccessEntry() = default; absl::optional AccessControlList::FromPACL(ACL* acl) { if (acl && !::IsValidAcl(acl)) { ::SetLastError(ERROR_INVALID_ACL); return absl::nullopt; } return AccessControlList{acl}; } absl::optional AccessControlList::FromMandatoryLabel( DWORD integrity_level, DWORD inheritance, DWORD mandatory_policy) { Sid sid = Sid::FromIntegrityLevel(integrity_level); // Get total ACL length. SYSTEM_MANDATORY_LABEL_ACE contains the first DWORD // of the SID so remove it from total. DWORD length = sizeof(ACL) + sizeof(SYSTEM_MANDATORY_LABEL_ACE) + ::GetLengthSid(sid.GetPSID()) - sizeof(DWORD); std::unique_ptr sacl_ptr = std::make_unique(length); PACL sacl = reinterpret_cast(sacl_ptr.get()); if (!::InitializeAcl(sacl, length, ACL_REVISION)) { return absl::nullopt; } if (!::AddMandatoryAce(sacl, ACL_REVISION, inheritance, mandatory_policy, sid.GetPSID())) { return absl::nullopt; } DCHECK(::IsValidAcl(sacl)); AccessControlList ret; ret.acl_ = std::move(sacl_ptr); return ret; } AccessControlList::AccessControlList() : acl_(EmptyAclToBuffer()) {} AccessControlList::AccessControlList(AccessControlList&&) = default; AccessControlList& AccessControlList::operator=(AccessControlList&&) = default; AccessControlList::~AccessControlList() = default; bool AccessControlList::SetEntries( const std::vector& entries) { if (entries.empty()) return true; std::unique_ptr acl = AddACEToAcl(get(), entries); if (!acl) return false; acl_ = std::move(acl); return true; } bool AccessControlList::SetEntry(const Sid& sid, SecurityAccessMode mode, DWORD access_mask, DWORD inheritance) { std::vector ace_list; ace_list.emplace_back(sid, mode, access_mask, inheritance); return SetEntries(ace_list); } AccessControlList AccessControlList::Clone() const { return AccessControlList{get()}; } void AccessControlList::Clear() { acl_ = EmptyAclToBuffer(); } AccessControlList::AccessControlList(const ACL* acl) : acl_(AclToBuffer(acl)) {} } // namespace base::win