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 "file_share.h"
16
17 #include <dirent.h>
18 #include <fcntl.h>
19 #include <stack>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "accesstoken_kit.h"
26 #include "hap_token_info.h"
27 #include "log.h"
28 #include "sandbox_helper.h"
29 #include "uri.h"
30
31 namespace OHOS {
32 namespace AppFileService {
33 #define DIR_MODE (S_IRWXU | S_IXGRP | S_IXOTH)
34 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
35 #define READ_URI_PERMISSION OHOS::AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION
36 #define WRITE_URI_PERMISSION OHOS::AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION
37
38 enum ShareFileType {
39 DIR_TYPE = 0,
40 FILE_TYPE = 1,
41 };
42
43 namespace {
44 const string FILE_SCHEME = "file";
45 const string DATA_APP_EL2_PATH = "/data/service/el2/";
46 const string SHARE_R_PATH = "/r/";
47 const string SHARE_RW_PATH = "/rw/";
48 const string SHARE_PATH = "/share/";
49 }
50
51 struct FileShareInfo {
52 string providerBundleName_;
53 string targetBundleName_;
54 string providerLowerPath_;
55 string providerSandboxPath_;
56 vector<string> sharePath_;
57 string currentUid_;
58 ShareFileType type_;
59 };
60
GetTargetInfo(uint32_t tokenId,string & bundleName,string & currentUid)61 static int32_t GetTargetInfo(uint32_t tokenId, string &bundleName, string ¤tUid)
62 {
63 Security::AccessToken::HapTokenInfo hapInfo;
64 int32_t result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo);
65 if (result != 0) {
66 LOGE("Failed to get hap token info %{public}d", result);
67 return result;
68 }
69 bundleName = hapInfo.bundleName;
70 currentUid = to_string(hapInfo.userID);
71
72 int index = hapInfo.instIndex;
73 if (index != 0) {
74 bundleName = to_string(index) + "_" + bundleName;
75 }
76 return 0;
77 }
78
GetProviderInfo(string uriStr,FileShareInfo & info)79 static void GetProviderInfo(string uriStr, FileShareInfo &info)
80 {
81 Uri uri(uriStr);
82 info.providerBundleName_ = uri.GetAuthority();
83 info.providerSandboxPath_ = uri.GetPath();
84 }
85
IsExistDir(const string & path)86 static bool IsExistDir(const string &path)
87 {
88 struct stat buf = {};
89 if (stat(path.c_str(), &buf) != 0) {
90 return false;
91 }
92 return S_ISDIR(buf.st_mode);
93 }
94
IsExistFile(const string & path)95 static bool IsExistFile(const string &path)
96 {
97 struct stat buf = {};
98 if (stat(path.c_str(), &buf) != 0) {
99 LOGE("Get path stat failed, path: %s err %{public}d", path.c_str(), errno);
100 return false;
101 }
102 return S_ISREG(buf.st_mode);
103 }
104
GetSharePath(FileShareInfo & info,uint32_t flag)105 static void GetSharePath(FileShareInfo &info, uint32_t flag)
106 {
107 string shareRPath = DATA_APP_EL2_PATH + info.currentUid_ + SHARE_PATH +info.targetBundleName_ +
108 SHARE_R_PATH + info.providerBundleName_ + info.providerSandboxPath_;
109 string shareRWPath = DATA_APP_EL2_PATH + info.currentUid_ + SHARE_PATH +info.targetBundleName_ +
110 SHARE_RW_PATH + info.providerBundleName_ + info.providerSandboxPath_;
111 if ((flag & WRITE_URI_PERMISSION) == WRITE_URI_PERMISSION) {
112 info.sharePath_.push_back(shareRWPath);
113 info.sharePath_.push_back(shareRPath);
114 } else if ((flag & READ_URI_PERMISSION) == READ_URI_PERMISSION) {
115 info.sharePath_.push_back(shareRPath);
116 }
117 }
118
GetShareFileType(FileShareInfo & info)119 static int32_t GetShareFileType(FileShareInfo &info)
120 {
121 if (IsExistFile(info.providerLowerPath_)) {
122 info.type_ = ShareFileType::FILE_TYPE;
123 return 0;
124 } else if (IsExistDir(info.providerLowerPath_)) {
125 info.type_ = ShareFileType::DIR_TYPE;
126 return 0;
127 }
128 return -ENOENT;
129 }
130
GetFileShareInfo(const string & uri,uint32_t tokenId,uint32_t flag,FileShareInfo & info)131 static int32_t GetFileShareInfo(const string &uri, uint32_t tokenId, uint32_t flag, FileShareInfo &info)
132 {
133 int32_t ret = 0;
134 ret = GetTargetInfo(tokenId, info.targetBundleName_, info.currentUid_);
135 if (ret != 0) {
136 LOGE("Failed to get target info %{public}d", ret);
137 return ret;
138 }
139
140 GetProviderInfo(uri, info);
141
142 ret = SandboxHelper::GetPhysicalPath(uri, info.currentUid_, info.providerLowerPath_);
143 if (ret != 0) {
144 LOGE("Failed to get lower path %{public}d", ret);
145 return ret;
146 }
147
148 ret = GetShareFileType(info);
149 if (ret != 0) {
150 LOGE("Failed to get share file type %{public}d", ret);
151 return ret;
152 }
153
154 GetSharePath(info, flag);
155 return 0;
156 }
157
MakeDir(const string & path)158 static bool MakeDir(const string &path)
159 {
160 string::size_type index = 0;
161 string subPath;
162 do {
163 index = path.find('/', index + 1);
164 if (index == string::npos) {
165 subPath = path;
166 } else {
167 subPath = path.substr(0, index);
168 }
169
170 if (access(subPath.c_str(), 0) != 0) {
171 if (mkdir(subPath.c_str(), DIR_MODE) != 0) {
172 LOGE("Failed to make dir with %{public}d", errno);
173 return false;
174 }
175 }
176 } while (index != string::npos);
177
178 return true;
179 }
180
DeleteExistShareFile(const string & path)181 static void DeleteExistShareFile(const string &path)
182 {
183 if (access(path.c_str(), F_OK) == 0) {
184 if (umount2(path.c_str(), MNT_DETACH) != 0) {
185 LOGE("Umount failed with %{public}d", errno);
186 }
187 remove(path.c_str());
188 }
189 }
190
PreparePreShareDir(FileShareInfo & info)191 static int32_t PreparePreShareDir(FileShareInfo &info)
192 {
193 if (!SandboxHelper::CheckValidPath(info.providerLowerPath_)) {
194 LOGE("Invalid share path with %{private}s", info.providerLowerPath_.c_str());
195 return -EINVAL;
196 }
197
198 for (size_t i = 0; i < info.sharePath_.size(); i++) {
199 if (access(info.sharePath_[i].c_str(), F_OK) != 0) {
200 string sharePathDir = info.sharePath_[i];
201 size_t posLast = info.sharePath_[i].find_last_of("/");
202 sharePathDir = info.sharePath_[i].substr(0, posLast);
203 if (!MakeDir(sharePathDir.c_str())) {
204 LOGE("Make dir failed with %{public}d", errno);
205 return -errno;
206 }
207 } else {
208 DeleteExistShareFile(info.sharePath_[i]);
209 }
210 }
211 return 0;
212 }
213
CreateShareFile(const string & uri,uint32_t tokenId,uint32_t flag)214 int32_t CreateShareFile(const string &uri, uint32_t tokenId, uint32_t flag)
215 {
216 FileShareInfo info;
217 string decodeUri = SandboxHelper::Decode(uri);
218 LOGD("CreateShareFile begin with uri %{private}s decodeUri %{private}s",
219 uri.c_str(), decodeUri.c_str());
220 int32_t ret = GetFileShareInfo(decodeUri, tokenId, flag, info);
221 if (ret != 0) {
222 LOGE("Failed to get FileShareInfo with %{public}d", ret);
223 return ret;
224 }
225
226 if ((ret = PreparePreShareDir(info)) != 0) {
227 LOGE("PreparePreShareDir failed");
228 return ret;
229 }
230
231 for (size_t i = 0; i < info.sharePath_.size(); i++) {
232 if (info.type_ == ShareFileType::FILE_TYPE) {
233 if ((ret = creat(info.sharePath_[i].c_str(), FILE_MODE)) < 0) {
234 LOGE("Create file failed with %{public}d", errno);
235 return -errno;
236 }
237 close(ret);
238 } else {
239 LOGE("Invalid argument not support dir to share");
240 return -EINVAL;
241 }
242
243 if (mount(info.providerLowerPath_.c_str(), info.sharePath_[i].c_str(),
244 nullptr, MS_BIND, nullptr) != 0) {
245 LOGE("Mount failed with %{public}d", errno);
246 return -errno;
247 }
248 }
249 LOGI("Create Share File Successfully!");
250 return 0;
251 }
252
DelSharePath(const string & delPath)253 static void DelSharePath(const string &delPath)
254 {
255 if (!SandboxHelper::CheckValidPath(delPath)) {
256 LOGE("DelSharePath, umount path is invalid, path = %{private}s", delPath.c_str());
257 return;
258 }
259
260 if (access(delPath.c_str(), F_OK) == 0) {
261 if (umount2(delPath.c_str(), MNT_DETACH) != 0) {
262 LOGE("DelSharePath, umount failed with %{public}d", errno);
263 }
264 remove(delPath.c_str());
265 }
266 }
267
UmountDelUris(vector<string> sharePathList,string currentUid,string bundleNameSelf)268 static void UmountDelUris(vector<string> sharePathList, string currentUid, string bundleNameSelf)
269 {
270 string delPathPrefix = DATA_APP_EL2_PATH + currentUid + SHARE_PATH + bundleNameSelf;
271 for (size_t i = 0; i < sharePathList.size(); i++) {
272 Uri uri(SandboxHelper::Decode(sharePathList[i]));
273 string path = uri.GetPath();
274 string bundleName = uri.GetAuthority();
275
276 string delRPath = delPathPrefix + SHARE_R_PATH + bundleName + path;
277 DelSharePath(delRPath);
278
279 string delRWPath = delPathPrefix + SHARE_RW_PATH + bundleName + path;
280 DelSharePath(delRWPath);
281 }
282 }
283
DeleteShareFile(uint32_t tokenId,vector<string> sharePathList)284 int32_t DeleteShareFile(uint32_t tokenId, vector<string> sharePathList)
285 {
286 string bundleName;
287 string currentUid;
288 int32_t ret = GetTargetInfo(tokenId, bundleName, currentUid);
289 if (ret != 0) {
290 LOGE("Failed to delete share file %{public}d", -EINVAL);
291 return -EINVAL;
292 }
293 UmountDelUris(sharePathList, currentUid, bundleName);
294
295 LOGI("Delete Share File Successfully!");
296 return 0;
297 }
298 } // namespace AppFileService
299 } // namespace OHOS