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
InsertEntry(const AclXattrEntry & entry)53 int Acl::InsertEntry(const AclXattrEntry &entry)
54 {
55 if (entries.size() >= ENTRIES_MAX_NUM) {
56 errno = EAGAIN;
57 return -1;
58 }
59
60 switch (entry.tag) {
61 case ACL_TAG::GROUP_OBJ:
62 case ACL_TAG::USER_OBJ:
63 case ACL_TAG::MASK:
64 case ACL_TAG::OTHER:
65 entries.insert(entry);
66 break;
67 case ACL_TAG::USER:
68 case ACL_TAG::GROUP:
69 entries.insert(entry); // must before ReCalcMaskPerm()
70 maskDemand++;
71 /*
72 * In either case there's no or already one ACL_MASK entry in the set,
73 * we need to re-calculate MASK's permission and *insert* it (to replace
74 * the old one in latter case since we can't change std::set's element
75 * in-place). So do the following unconditionally.
76 *
77 * Be warned: do _NOT_ combine the following into one line, otherwise
78 * you can't pass the !!genius!! CI coding style check.
79 */
80 entries.insert(
81 { ACL_TAG::MASK, ReCalcMaskPerm(), ACL_UNDEFINED_ID }
82 );
83 break;
84 default:
85 errno = EINVAL;
86 return -1;
87 }
88 return 0;
89 }
90
Serialize(size_t & bufSize)91 char *Acl::Serialize(size_t &bufSize)
92 {
93 if (!IsValid()) {
94 errno = EINVAL;
95 return nullptr;
96 }
97
98 /* clear possible previous allocation */
99 if (buf != nullptr) {
100 delete[] buf;
101 buf = nullptr;
102 }
103
104 bufSize = sizeof(AclXattrHeader) + sizeof(AclXattrEntry) * entries.size();
105 if (bufSize > BUF_MAX_SIZE) {
106 bufSize = 0;
107 errno = EINVAL;
108 return nullptr;
109 }
110 buf = new (std::nothrow) char[bufSize];
111 if (buf == nullptr) {
112 errno = ENOMEM;
113 return nullptr;
114 }
115 auto err = memcpy_s(buf, bufSize, &header, sizeof(AclXattrHeader));
116 if (err != EOK) {
117 errno = err;
118 delete[] buf;
119 buf = nullptr;
120 return nullptr;
121 }
122
123 size_t restSize = bufSize - sizeof(AclXattrHeader);
124 AclXattrEntry *ptr = reinterpret_cast<AclXattrEntry *>(buf + sizeof(AclXattrHeader));
125 for (const auto &e : entries) {
126 auto err = memcpy_s(ptr++, restSize, &e, sizeof(AclXattrEntry));
127 if (err != EOK) {
128 errno = err;
129 delete[] buf;
130 buf = nullptr;
131 return nullptr;
132 }
133 restSize -= sizeof(AclXattrEntry);
134 }
135 return buf;
136 }
137
DeSerialize(const char * p,size_t size)138 int Acl::DeSerialize(const char *p, size_t size)
139 {
140 if (size > BUF_MAX_SIZE || size < sizeof(AclXattrHeader)) {
141 errno = EINVAL;
142 return -1;
143 }
144 header = *reinterpret_cast<const AclXattrHeader *>(p);
145 size -= sizeof(AclXattrHeader);
146 p += sizeof(AclXattrHeader);
147
148 /*
149 * `e->tag != ACL_TAG::UNDEFINED` is unreliable outside the buffer, so check
150 * it after checking the size of remaining buffer.
151 */
152 for (const AclXattrEntry *e = reinterpret_cast<const AclXattrEntry *>(p);
153 size >= sizeof(AclXattrEntry) && LeToCpu(e->tag) != ACL_TAG::UNDEFINED;
154 e++) {
155 InsertEntry(*e);
156 size -= sizeof(AclXattrEntry);
157 }
158 if (size != 0) {
159 entries.clear();
160 header = { 0 };
161 errno = EINVAL;
162 return -1;
163 }
164
165 return 0;
166 }
167
~Acl()168 Acl::~Acl()
169 {
170 if (buf != nullptr) {
171 delete[] buf;
172 buf = nullptr;
173 }
174 }
175 } // STORAGE_DAEMON
176 } // OHOS
177