• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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