access_control_list.cc (5614B)
1 // Copyright 2022 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 #include "base/win/access_control_list.h" 6 7 #include <aclapi.h> 8 #include <windows.h> 9 10 #include <utility> 11 #include <vector> 12 13 #include "base/check.h" 14 #include "base/logging.h" 15 #include "base/notreached.h" 16 #include "base/numerics/checked_math.h" 17 #include "base/win/scoped_localalloc.h" 18 19 namespace base::win { 20 21 namespace { 22 23 std::unique_ptr<uint8_t[]> AclToBuffer(const ACL* acl) { 24 if (!acl) { 25 return nullptr; 26 } 27 size_t size = acl->AclSize; 28 DCHECK(size >= sizeof(*acl)); 29 std::unique_ptr<uint8_t[]> ptr = std::make_unique<uint8_t[]>(size); 30 memcpy(ptr.get(), acl, size); 31 return ptr; 32 } 33 34 std::unique_ptr<uint8_t[]> EmptyAclToBuffer() { 35 ACL acl = {}; 36 acl.AclRevision = ACL_REVISION; 37 acl.AclSize = static_cast<WORD>(sizeof(acl)); 38 return AclToBuffer(&acl); 39 } 40 41 ACCESS_MODE ConvertAccessMode(SecurityAccessMode access_mode) { 42 switch (access_mode) { 43 case SecurityAccessMode::kGrant: 44 return GRANT_ACCESS; 45 case SecurityAccessMode::kSet: 46 return SET_ACCESS; 47 case SecurityAccessMode::kDeny: 48 return DENY_ACCESS; 49 case SecurityAccessMode::kRevoke: 50 return REVOKE_ACCESS; 51 } 52 } 53 54 std::unique_ptr<uint8_t[]> AddACEToAcl( 55 ACL* old_acl, 56 const std::vector<ExplicitAccessEntry>& entries) { 57 std::vector<EXPLICIT_ACCESS> access_entries(entries.size()); 58 auto entries_interator = access_entries.begin(); 59 for (const ExplicitAccessEntry& entry : entries) { 60 EXPLICIT_ACCESS& new_access = *entries_interator++; 61 new_access.grfAccessMode = ConvertAccessMode(entry.mode()); 62 new_access.grfAccessPermissions = entry.access_mask(); 63 new_access.grfInheritance = entry.inheritance(); 64 ::BuildTrusteeWithSid(&new_access.Trustee, entry.sid().GetPSID()); 65 } 66 67 PACL new_acl = nullptr; 68 DWORD error = ::SetEntriesInAcl(checked_cast<ULONG>(access_entries.size()), 69 access_entries.data(), old_acl, &new_acl); 70 if (error != ERROR_SUCCESS) { 71 ::SetLastError(error); 72 DPLOG(ERROR) << "Failed adding ACEs to ACL"; 73 return nullptr; 74 } 75 auto new_acl_ptr = TakeLocalAlloc(new_acl); 76 return AclToBuffer(new_acl_ptr.get()); 77 } 78 79 } // namespace 80 81 ExplicitAccessEntry ExplicitAccessEntry::Clone() const { 82 return ExplicitAccessEntry{sid_, mode_, access_mask_, inheritance_}; 83 } 84 85 ExplicitAccessEntry::ExplicitAccessEntry(const Sid& sid, 86 SecurityAccessMode mode, 87 DWORD access_mask, 88 DWORD inheritance) 89 : sid_(sid.Clone()), 90 mode_(mode), 91 access_mask_(access_mask), 92 inheritance_(inheritance) {} 93 94 ExplicitAccessEntry::ExplicitAccessEntry(WellKnownSid known_sid, 95 SecurityAccessMode mode, 96 DWORD access_mask, 97 DWORD inheritance) 98 : ExplicitAccessEntry(Sid(known_sid), mode, access_mask, inheritance) {} 99 100 ExplicitAccessEntry::ExplicitAccessEntry(ExplicitAccessEntry&&) = default; 101 ExplicitAccessEntry& ExplicitAccessEntry::operator=(ExplicitAccessEntry&&) = 102 default; 103 ExplicitAccessEntry::~ExplicitAccessEntry() = default; 104 105 absl::optional<AccessControlList> AccessControlList::FromPACL(ACL* acl) { 106 if (acl && !::IsValidAcl(acl)) { 107 ::SetLastError(ERROR_INVALID_ACL); 108 return absl::nullopt; 109 } 110 return AccessControlList{acl}; 111 } 112 113 absl::optional<AccessControlList> AccessControlList::FromMandatoryLabel( 114 DWORD integrity_level, 115 DWORD inheritance, 116 DWORD mandatory_policy) { 117 Sid sid = Sid::FromIntegrityLevel(integrity_level); 118 // Get total ACL length. SYSTEM_MANDATORY_LABEL_ACE contains the first DWORD 119 // of the SID so remove it from total. 120 DWORD length = sizeof(ACL) + sizeof(SYSTEM_MANDATORY_LABEL_ACE) + 121 ::GetLengthSid(sid.GetPSID()) - sizeof(DWORD); 122 std::unique_ptr<uint8_t[]> sacl_ptr = std::make_unique<uint8_t[]>(length); 123 PACL sacl = reinterpret_cast<PACL>(sacl_ptr.get()); 124 125 if (!::InitializeAcl(sacl, length, ACL_REVISION)) { 126 return absl::nullopt; 127 } 128 129 if (!::AddMandatoryAce(sacl, ACL_REVISION, inheritance, mandatory_policy, 130 sid.GetPSID())) { 131 return absl::nullopt; 132 } 133 134 DCHECK(::IsValidAcl(sacl)); 135 AccessControlList ret; 136 ret.acl_ = std::move(sacl_ptr); 137 return ret; 138 } 139 140 AccessControlList::AccessControlList() : acl_(EmptyAclToBuffer()) {} 141 AccessControlList::AccessControlList(AccessControlList&&) = default; 142 AccessControlList& AccessControlList::operator=(AccessControlList&&) = default; 143 AccessControlList::~AccessControlList() = default; 144 145 bool AccessControlList::SetEntries( 146 const std::vector<ExplicitAccessEntry>& entries) { 147 if (entries.empty()) 148 return true; 149 150 std::unique_ptr<uint8_t[]> acl = AddACEToAcl(get(), entries); 151 if (!acl) 152 return false; 153 154 acl_ = std::move(acl); 155 return true; 156 } 157 158 bool AccessControlList::SetEntry(const Sid& sid, 159 SecurityAccessMode mode, 160 DWORD access_mask, 161 DWORD inheritance) { 162 std::vector<ExplicitAccessEntry> ace_list; 163 ace_list.emplace_back(sid, mode, access_mask, inheritance); 164 return SetEntries(ace_list); 165 } 166 167 AccessControlList AccessControlList::Clone() const { 168 return AccessControlList{get()}; 169 } 170 171 void AccessControlList::Clear() { 172 acl_ = EmptyAclToBuffer(); 173 } 174 175 AccessControlList::AccessControlList(const ACL* acl) : acl_(AclToBuffer(acl)) {} 176 177 } // namespace base::win