• 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 "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 &currentUid)
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