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