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