1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "file_sharing/acl.h"
16
17 #include <cerrno>
18 #include <new>
19 #include <type_traits>
20 #include "file_sharing/endian.h"
21 #include "securec.h"
22
23 namespace OHOS {
24 namespace StorageDaemon {
ReCalcMaskPerm()25 ACL_PERM Acl::ReCalcMaskPerm()
26 {
27 ACL_PERM perm;
28 for (const auto &e : entries) {
29 if (e.tag == ACL_TAG::USER || e.tag == ACL_TAG::GROUP_OBJ || e.tag == ACL_TAG::GROUP) {
30 perm.Merge(e.perm);
31 }
32 }
33 return perm;
34 }
35
IsEmpty()36 bool Acl::IsEmpty()
37 {
38 return entries.empty();
39 }
40
IsValid()41 bool Acl::IsValid()
42 {
43 if (!entries.count(ACL_TAG::USER_OBJ) || !entries.count(ACL_TAG::GROUP_OBJ) ||
44 !entries.count(ACL_TAG::OTHER)) {
45 return false;
46 }
47 if (maskDemand && !entries.count(ACL_TAG::MASK)) {
48 return false;
49 }
50 return true;
51 }
52
CompareInsertEntry(const AclXattrEntry & entry)53 void Acl::CompareInsertEntry(const AclXattrEntry &entry)
54 {
55 if (entries.count(entry)) {
56 auto it = entries.find(entry);
57 entries.erase(it);
58 }
59 if (entry.perm.IsReadable() || entry.perm.IsWritable() || entry.perm.IsExecutable()) {
60 entries.insert(entry);
61 }
62 }
63
SetMaskEntry()64 void Acl::SetMaskEntry()
65 {
66 auto it = std::find_if(entries.begin(), entries.end(),
67 [] (const AclXattrEntry e) { return e.tag == ACL_TAG::GROUP; });
68 if (it != entries.end()) {
69 // if has GROUP entry, update MASK entry
70 maskDemand = 1;
71 } else {
72 // if no GROUP entry, remove MASK entry
73 maskDemand = 0;
74 }
75 /*
76 * In either case there's no or already one ACL_MASK entry in the set,
77 * we need to re-calculate MASK's permission and *insert* it (to replace
78 * the old one in latter case since we can't change std::set's element
79 * in-place). So do the following unconditionally.
80 *
81 * Be warned: do _NOT_ combine the following into one line, otherwise
82 * you can't pass the !!genius!! CI coding style check.
83 */
84 CompareInsertEntry(
85 { ACL_TAG::MASK, ReCalcMaskPerm(), ACL_UNDEFINED_ID }
86 );
87 }
88
InsertEntry(const AclXattrEntry & entry)89 int Acl::InsertEntry(const AclXattrEntry &entry)
90 {
91 if (entries.size() >= ENTRIES_MAX_NUM) {
92 errno = EAGAIN;
93 return -1;
94 }
95
96 switch (entry.tag) {
97 case ACL_TAG::GROUP_OBJ:
98 case ACL_TAG::USER_OBJ:
99 case ACL_TAG::MASK:
100 case ACL_TAG::OTHER:
101 entries.insert(entry);
102 break;
103 case ACL_TAG::USER:
104 case ACL_TAG::GROUP:
105 CompareInsertEntry(entry); // must before ReCalcMaskPerm()
106 SetMaskEntry();
107 break;
108 default:
109 errno = EINVAL;
110 return -1;
111 }
112 return 0;
113 }
114
Serialize(size_t & bufSize)115 char *Acl::Serialize(size_t &bufSize)
116 {
117 if (!IsValid()) {
118 errno = EINVAL;
119 return nullptr;
120 }
121
122 /* clear possible previous allocation */
123 if (buf != nullptr) {
124 delete[] buf;
125 buf = nullptr;
126 }
127
128 bufSize = sizeof(AclXattrHeader) + sizeof(AclXattrEntry) * entries.size();
129 if (bufSize > BUF_MAX_SIZE) {
130 bufSize = 0;
131 errno = EINVAL;
132 return nullptr;
133 }
134 buf = new (std::nothrow) char[bufSize];
135 if (buf == nullptr) {
136 errno = ENOMEM;
137 return nullptr;
138 }
139 auto err = memcpy_s(buf, bufSize, &header, sizeof(AclXattrHeader));
140 if (err != EOK) {
141 errno = err;
142 delete[] buf;
143 buf = nullptr;
144 return nullptr;
145 }
146
147 size_t restSize = bufSize - sizeof(AclXattrHeader);
148 AclXattrEntry *ptr = reinterpret_cast<AclXattrEntry *>(buf + sizeof(AclXattrHeader));
149 for (const auto &e : entries) {
150 err = memcpy_s(ptr++, restSize, &e, sizeof(AclXattrEntry));
151 if (err != EOK) {
152 errno = err;
153 delete[] buf;
154 buf = nullptr;
155 return nullptr;
156 }
157 restSize -= sizeof(AclXattrEntry);
158 }
159 return buf;
160 }
161
DeSerialize(const char * p,size_t size)162 int Acl::DeSerialize(const char *p, size_t size)
163 {
164 if (size > BUF_MAX_SIZE || size < sizeof(AclXattrHeader)) {
165 errno = EINVAL;
166 return -1;
167 }
168 header = *reinterpret_cast<const AclXattrHeader *>(p);
169 size -= sizeof(AclXattrHeader);
170 p += sizeof(AclXattrHeader);
171
172 /*
173 * `e->tag != ACL_TAG::UNDEFINED` is unreliable outside the buffer, so check
174 * it after checking the size of remaining buffer.
175 */
176 for (const AclXattrEntry *e = reinterpret_cast<const AclXattrEntry *>(p);
177 size >= sizeof(AclXattrEntry) && LeToCpu(e->tag) != ACL_TAG::UNDEFINED;
178 e++) {
179 InsertEntry(*e);
180 size -= sizeof(AclXattrEntry);
181 }
182 if (size < 0) {
183 entries.clear();
184 header = { 0 };
185 errno = EINVAL;
186 return -1;
187 }
188
189 return 0;
190 }
191
~Acl()192 Acl::~Acl()
193 {
194 if (buf != nullptr) {
195 delete[] buf;
196 buf = nullptr;
197 }
198 }
199 } // STORAGE_DAEMON
200 } // OHOS
201