• 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     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