• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "acl.h"
16 
17 #include <cerrno>
18 #include <new>
19 #include <type_traits>
20 #include <sys/stat.h>
21 #include <sys/xattr.h>
22 
23 #include "medialibrary_errno.h"
24 #include "media_log.h"
25 #include "securec.h"
26 
27 namespace OHOS {
28 namespace Media {
ReCalcMaskPerm()29 ACL_PERM Acl::ReCalcMaskPerm()
30 {
31     ACL_PERM perm;
32     for (const auto &e : entries) {
33         if (e.tag == ACL_TAG::USER || e.tag == ACL_TAG::GROUP_OBJ || e.tag == ACL_TAG::GROUP) {
34             perm.Merge(e.perm);
35         }
36     }
37     return perm;
38 }
39 
IsEmpty()40 bool Acl::IsEmpty()
41 {
42     return entries.empty();
43 }
44 
IsValid()45 bool Acl::IsValid()
46 {
47     if (!entries.count(ACL_TAG::USER_OBJ) || !entries.count(ACL_TAG::GROUP_OBJ) ||
48             !entries.count(ACL_TAG::OTHER)) {
49         return false;
50     }
51     if (maskDemand && !entries.count(ACL_TAG::MASK)) {
52         return false;
53     }
54     return true;
55 }
56 
CompareInsertEntry(const AclXattrEntry & entry)57 void Acl::CompareInsertEntry(const AclXattrEntry &entry)
58 {
59     if (entries.count(entry)) {
60         auto it = entries.find(entry);
61         entries.erase(it);
62     }
63     if (entry.perm.IsReadable() || entry.perm.IsWritable() || entry.perm.IsExecutable()) {
64         entries.insert(entry);
65     }
66 }
67 
InsertEntry(const AclXattrEntry & entry)68 int Acl::InsertEntry(const AclXattrEntry &entry)
69 {
70     if (entries.size() >= ENTRIES_MAX_NUM) {
71         errno = EAGAIN;
72         return E_ERR;
73     }
74     CompareInsertEntry(entry); // must before ReCalcMaskPerm()
75 
76     maskDemand++;
77     /*
78         * In either case there's no or already one ACL_MASK entry in the set,
79         * we need to re-calculate MASK's permission and *insert* it (to replace
80         * the old one in latter case since we can't change std::set's element
81         * in-place). So do the following unconditionally.
82         *
83         * Be warned: do _NOT_ combine the following into one line, otherwise
84         * you can't pass the !!genius!! CI coding style check.
85         */
86     CompareInsertEntry(
87         { ACL_TAG::MASK, ReCalcMaskPerm(), ACL_UNDEFINED_ID }
88     );
89     return E_OK;
90 }
91 
Serialize(size_t & bufSize)92 char *Acl::Serialize(size_t &bufSize)
93 {
94     if (!IsValid()) {
95         errno = EINVAL;
96         return nullptr;
97     }
98 
99     /* clear possible previous allocation */
100     if (buf != nullptr) {
101         delete[] buf;
102         buf = nullptr;
103     }
104 
105     bufSize = sizeof(AclXattrHeader) + sizeof(AclXattrEntry) * entries.size();
106     if (bufSize > BUF_MAX_SIZE) {
107         bufSize = 0;
108         errno = EINVAL;
109         return nullptr;
110     }
111     buf = new (std::nothrow) char[bufSize];
112     if (buf == nullptr) {
113         errno = ENOMEM;
114         return nullptr;
115     }
116     auto err = memcpy_s(buf, bufSize, &header, sizeof(AclXattrHeader));
117     if (err != EOK) {
118         errno = err;
119         delete[] buf;
120         buf = nullptr;
121         return nullptr;
122     }
123 
124     size_t restSize = bufSize - sizeof(AclXattrHeader);
125     AclXattrEntry *ptr = reinterpret_cast<AclXattrEntry *>(buf + sizeof(AclXattrHeader));
126     for (const auto &e : entries) {
127         auto err = memcpy_s(ptr++, restSize, &e, sizeof(AclXattrEntry));
128         if (err != EOK) {
129             errno = err;
130             delete[] buf;
131             buf = nullptr;
132             return nullptr;
133         }
134         restSize -= sizeof(AclXattrEntry);
135     }
136     return buf;
137 }
138 
AclFromMode(const std::string & file)139 Acl AclFromMode(const std::string &file)
140 {
141     Acl acl;
142     struct stat st;
143 
144     if (stat(file.c_str(), &st) == -1) {
145         return acl;
146     }
147 
148     acl.InsertEntry(
149         {
150         .tag = ACL_TAG::USER_OBJ,
151         .perm = (st.st_mode & S_IRWXU) >> 6,
152         .id = ACL_UNDEFINED_ID,
153         }
154     );
155     acl.InsertEntry(
156         {
157         .tag = ACL_TAG::GROUP_OBJ,
158         .perm = (st.st_mode & S_IRWXG) >> 3,
159         .id = ACL_UNDEFINED_ID,
160         }
161     );
162     acl.InsertEntry(
163         {
164         .tag = ACL_TAG::OTHER,
165         .perm = (st.st_mode & S_IRWXO),
166         .id = ACL_UNDEFINED_ID,
167         }
168     );
169 
170     return acl;
171 }
172 
InitSandboxEntry(AclXattrEntry & entry)173 void InitSandboxEntry(AclXattrEntry &entry)
174 {
175     entry.tag = ACL_TAG::GROUP;
176     entry.id = THUMB_ACL_GROUP;
177     entry.perm.SetR();
178     entry.perm.SetE();
179 }
180 
AclSetDefault()181 int32_t Acl::AclSetDefault()
182 {
183     AclXattrEntry entry = {};
184     InitSandboxEntry(entry);
185 
186     /* init acl from file's mode */
187     Acl acl = AclFromMode(THUMB_DIR);
188     if (acl.IsEmpty()) {
189         MEDIA_ERR_LOG("Failed to generate ACL from file's mode: %{public}s", std::strerror(errno));
190         return E_ERR;
191     }
192 
193     /* add new entry into set */
194     if (acl.InsertEntry(entry) == E_ERR) {
195         MEDIA_ERR_LOG("Failed to insert new entry into ACL: %{public}s", std::strerror(errno));
196         return E_ERR;
197     }
198 
199     /* transform to binary and write to file */
200     size_t bufSize;
201     char *buf = acl.Serialize(bufSize);
202     if (buf == nullptr) {
203         MEDIA_ERR_LOG("Failed to serialize ACL into binary: %{public}s", std::strerror(errno));
204         return E_ERR;
205     }
206     if (setxattr(THUMB_DIR.c_str(), ACL_XATTR_DEFAULT, buf, bufSize, 0) == -1) {
207         MEDIA_ERR_LOG("Failed to write into file's xattr: %{public}s", std::strerror(errno));
208         return E_ERR;
209     }
210     return E_OK;
211 }
212 
~Acl()213 Acl::~Acl()
214 {
215     if (buf != nullptr) {
216         delete[] buf;
217         buf = nullptr;
218     }
219 }
220 } // MEDIA
221 } // OHOS
222