• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AclToBuffer(const ACL * acl)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 
EmptyAclToBuffer()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 
ConvertAccessMode(SecurityAccessMode access_mode)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 
AddACEToAcl(ACL * old_acl,const std::vector<ExplicitAccessEntry> & entries)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 
Clone() const81 ExplicitAccessEntry ExplicitAccessEntry::Clone() const {
82   return ExplicitAccessEntry{sid_, mode_, access_mask_, inheritance_};
83 }
84 
ExplicitAccessEntry(const Sid & sid,SecurityAccessMode mode,DWORD access_mask,DWORD inheritance)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 
ExplicitAccessEntry(WellKnownSid known_sid,SecurityAccessMode mode,DWORD access_mask,DWORD inheritance)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 
FromPACL(ACL * acl)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 
FromMandatoryLabel(DWORD integrity_level,DWORD inheritance,DWORD mandatory_policy)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 
AccessControlList()140 AccessControlList::AccessControlList() : acl_(EmptyAclToBuffer()) {}
141 AccessControlList::AccessControlList(AccessControlList&&) = default;
142 AccessControlList& AccessControlList::operator=(AccessControlList&&) = default;
143 AccessControlList::~AccessControlList() = default;
144 
SetEntries(const std::vector<ExplicitAccessEntry> & entries)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 
SetEntry(const Sid & sid,SecurityAccessMode mode,DWORD access_mask,DWORD inheritance)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 
Clone() const167 AccessControlList AccessControlList::Clone() const {
168   return AccessControlList{get()};
169 }
170 
Clear()171 void AccessControlList::Clear() {
172   acl_ = EmptyAclToBuffer();
173 }
174 
AccessControlList(const ACL * acl)175 AccessControlList::AccessControlList(const ACL* acl) : acl_(AclToBuffer(acl)) {}
176 
177 }  // namespace base::win
178