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 bufSize = sizeof(AclXattrHeader) + sizeof(AclXattrEntry) * entries.size();
126 if (bufSize > BUF_MAX_SIZE) {
127 bufSize = 0;
128 errno = EINVAL;
129 return nullptr;
130 }
131 buf = new (std::nothrow) char[bufSize];
132 if (buf == nullptr) {
133 errno = ENOMEM;
134 return nullptr;
135 }
136 auto err = memcpy_s(buf, bufSize, &header, sizeof(AclXattrHeader));
137 if (err != EOK) {
138 errno = err;
139 delete[] buf;
140 buf = nullptr;
141 return nullptr;
142 }
143
144 size_t restSize = bufSize - sizeof(AclXattrHeader);
145 AclXattrEntry *ptr = reinterpret_cast<AclXattrEntry *>(buf + sizeof(AclXattrHeader));
146 for (const auto &e : entries) {
147 err = memcpy_s(ptr++, restSize, &e, sizeof(AclXattrEntry));
148 if (err != EOK) {
149 errno = err;
150 delete[] buf;
151 buf = nullptr;
152 return nullptr;
153 }
154 restSize -= sizeof(AclXattrEntry);
155 }
156 return buf;
157 }
158
DeSerialize(const char * p,size_t size)159 int Acl::DeSerialize(const char *p, size_t size)
160 {
161 if (p == nullptr || size > BUF_MAX_SIZE || size < sizeof(AclXattrHeader)) {
162 errno = EINVAL;
163 return -1;
164 }
165 header = *reinterpret_cast<const AclXattrHeader *>(p);
166 size -= sizeof(AclXattrHeader);
167 p += sizeof(AclXattrHeader);
168
169 /*
170 * `e->tag != ACL_TAG::UNDEFINED` is unreliable outside the buffer, so check
171 * it after checking the size of remaining buffer.
172 */
173 for (const AclXattrEntry *e = reinterpret_cast<const AclXattrEntry *>(p);
174 size >= sizeof(AclXattrEntry) && LeToCpu(e->tag) != ACL_TAG::UNDEFINED;
175 e++) {
176 InsertEntry(*e);
177 size -= sizeof(AclXattrEntry);
178 }
179 if (size < 0) {
180 entries.clear();
181 header = { 0 };
182 errno = EINVAL;
183 return -1;
184 }
185
186 return 0;
187 }
188
~Acl()189 Acl::~Acl()
190 {
191 if (buf != nullptr) {
192 delete[] buf;
193 buf = nullptr;
194 }
195 }
196 } // STORAGE_DAEMON
197 } // OHOS
198