• 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 
16 #include "sandbox_helper.h"
17 
18 #include <iomanip>
19 #include <sstream>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "log.h"
24 #include "json_utils.h"
25 #include "uri.h"
26 
27 using namespace std;
28 
29 namespace OHOS {
30 namespace AppFileService {
31 namespace {
32     const string PACKAGE_NAME_FLAG = "<PackageName>";
33     const string CURRENT_USER_ID_FLAG = "<currentUserId>";
34     const string PHYSICAL_PATH_KEY = "src-path";
35     const string SANDBOX_PATH_KEY = "sandbox-path";
36     const string MOUNT_PATH_MAP_KEY = "mount-path-map";
37     const string SANDBOX_JSON_FILE_PATH = "/etc/app_file_service/file_share_sandbox.json";
38     const std::string SHAER_PATH_HEAD = "/mnt/hmdfs/";
39     const std::string SHAER_PATH_MID = "/account/cloud_merge_view/files/";
40     const string FILE_MANAGER_URI_HEAD = "/storage/";
41     const string FILE_MANAGER_AUTHORITY = "docs";
42     const string DLP_MANAGER_BUNDLE_NAME = "com.ohos.dlpmanager";
43     const string FUSE_URI_HEAD = "/mnt/data/fuse";
44     const string BACKFLASH = "/";
45     const string MEDIA = "media";
46     const string NETWORK_ID_FLAG = "<networkId>";
47     const string LOCAL = "local";
48     const int ASSET_IN_BUCKET_NUM_MAX = 1000;
49     const int ASSET_DIR_START_NUM = 16;
50 }
51 
52 struct MediaUriInfo {
53     string mediaType;
54     string fileId;
55     string realName;
56     string displayName;
57 };
58 
59 std::unordered_map<std::string, std::string> SandboxHelper::sandboxPathMap_;
60 std::mutex SandboxHelper::mapMutex_;
61 
Encode(const string & uri)62 string SandboxHelper::Encode(const string &uri)
63 {
64     const unordered_set<char> uriCompentsSet = {
65         '/', '-', '_', '.', '!',
66         '~', '*', '(', ')', '\''
67     };
68     const int32_t encodeLen = 2;
69     ostringstream outPutStream;
70     outPutStream.fill('0');
71     outPutStream << std::hex;
72 
73     for (unsigned char tmpChar : uri) {
74         if (std::isalnum(tmpChar) || uriCompentsSet.find(tmpChar) != uriCompentsSet.end()) {
75             outPutStream << tmpChar;
76         } else {
77             outPutStream << std::uppercase;
78             outPutStream << '%' << std::setw(encodeLen) << static_cast<unsigned int>(tmpChar);
79             outPutStream << std::nouppercase;
80         }
81     }
82 
83     return outPutStream.str();
84 }
85 
Decode(const string & uri)86 string SandboxHelper::Decode(const string &uri)
87 {
88     std::ostringstream outPutStream;
89     const int32_t encodeLen = 2;
90     size_t index = 0;
91     while (index < uri.length()) {
92         if (uri[index] == '%') {
93             int hex = 0;
94             std::istringstream inputStream(uri.substr(index + 1, encodeLen));
95             inputStream >> std::hex >> hex;
96             outPutStream << static_cast<char>(hex);
97             index += encodeLen + 1;
98         } else {
99             outPutStream << uri[index];
100             index++;
101         }
102     }
103 
104     return outPutStream.str();
105 }
106 
GetLowerPath(string & lowerPathHead,const string & lowerPathTail,const string & userId,const string & bundleName,const string & networkId)107 static string GetLowerPath(string &lowerPathHead, const string &lowerPathTail,
108                            const string &userId, const string &bundleName,
109                            const string &networkId)
110 {
111     if (lowerPathHead.find(CURRENT_USER_ID_FLAG) != string::npos) {
112         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(CURRENT_USER_ID_FLAG),
113                                               CURRENT_USER_ID_FLAG.length(), userId);
114     }
115 
116     if (lowerPathHead.find(PACKAGE_NAME_FLAG) != string::npos) {
117         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(PACKAGE_NAME_FLAG),
118                                               PACKAGE_NAME_FLAG.length(), bundleName);
119     }
120 
121     if (lowerPathHead.find(NETWORK_ID_FLAG) != string::npos) {
122         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(NETWORK_ID_FLAG),
123                                               NETWORK_ID_FLAG.length(), networkId);
124     }
125 
126     return lowerPathHead + lowerPathTail;
127 }
128 
GetSandboxPathMap()129 bool SandboxHelper::GetSandboxPathMap()
130 {
131     lock_guard<mutex> lock(mapMutex_);
132     if (sandboxPathMap_.size() > 0) {
133         return true;
134     }
135 
136     nlohmann::json jsonObj;
137     int ret = JsonUtils::GetJsonObjFromPath(jsonObj, SANDBOX_JSON_FILE_PATH);
138     if (ret != 0) {
139         LOGE("Get json object failed with %{public}d", ret);
140         return false;
141     }
142 
143     if (jsonObj.find(MOUNT_PATH_MAP_KEY) == jsonObj.end()) {
144         LOGE("Json object find mount path map failed");
145         return false;
146     }
147 
148     nlohmann::json mountPathMap = jsonObj[MOUNT_PATH_MAP_KEY];
149     for (size_t i = 0; i < mountPathMap.size(); i++) {
150         string srcPath = mountPathMap[i][PHYSICAL_PATH_KEY];
151         string sandboxPath = mountPathMap[i][SANDBOX_PATH_KEY];
152         sandboxPathMap_[sandboxPath] = srcPath;
153     }
154 
155     if (sandboxPathMap_.size() == 0) {
156         return false;
157     }
158 
159     return true;
160 }
161 
GetPathSuffix(const std::string & path,string & pathSuffix)162 static int32_t GetPathSuffix(const std::string &path, string &pathSuffix)
163 {
164     size_t pos = path.rfind('.');
165     if (pos != string::npos) {
166         pathSuffix = path.substr(pos);
167         return 0;
168     }
169     return -EINVAL;
170 }
171 
CalAssetBucket(const int32_t & fileId)172 static int32_t CalAssetBucket(const int32_t &fileId)
173 {
174     int32_t bucketNum = 0;
175     if (fileId < 0) {
176         LOGE("input fileId %{private}d is invalid", fileId);
177         return -EINVAL;
178     }
179 
180     int32_t start = ASSET_DIR_START_NUM;
181     int32_t divider = ASSET_DIR_START_NUM;
182     while (fileId > start * ASSET_IN_BUCKET_NUM_MAX) {
183         divider = start;
184         start <<= 1;
185     }
186 
187     int32_t fileIdRemainder = fileId % divider;
188     if (fileIdRemainder == 0) {
189         bucketNum = start + fileIdRemainder;
190     } else {
191         bucketNum = (start - divider) + fileIdRemainder;
192     }
193     return bucketNum;
194 }
195 
GetFileIdFromFileName(const std::string & fileName)196 static int32_t GetFileIdFromFileName(const std::string &fileName)
197 {
198     size_t pos = fileName.find_last_of('_');
199     if (pos == std::string::npos || pos == fileName.size() - 1) {
200         return -EINVAL;
201     }
202 
203     std::string idStr = fileName.substr(pos + 1);
204     if (!std::all_of(idStr.begin(), idStr.end(), ::isdigit)) {
205         return -EINVAL;
206     }
207 
208     return std::stoi(idStr);
209 }
210 
GetBucketNum(const std::string & fileName)211 static int32_t GetBucketNum(const std::string &fileName)
212 {
213     int32_t fileId = GetFileIdFromFileName(fileName);
214     if (fileId < 0) {
215         LOGE("GetFileIdFromFileName failed with %{public}s", fileName.c_str());
216         return fileId;
217     }
218     return CalAssetBucket(fileId);
219 }
220 
ParseMediaSandboxPath(const string & sandboxPath,MediaUriInfo & mediaUriInfo)221 static bool ParseMediaSandboxPath(const string &sandboxPath, MediaUriInfo &mediaUriInfo)
222 {
223     string path = sandboxPath;
224     std::replace(path.begin(), path.end(), '/', ' ');
225     stringstream ss;
226     ss << path;
227     ss >> mediaUriInfo.mediaType >> mediaUriInfo.fileId >> mediaUriInfo.realName >> mediaUriInfo.displayName;
228 
229     string buf;
230     ss >> buf;
231     if (!buf.empty()) {
232         LOGE("media sandboxPath is invalid");
233         return false;
234     }
235 
236     return true;
237 }
238 
GetMediaPhysicalPath(const std::string & sandboxPath,const std::string & userId,std::string & physicalPath)239 static int32_t GetMediaPhysicalPath(const std::string &sandboxPath, const std::string &userId,
240                                     std::string &physicalPath)
241 {
242     MediaUriInfo mediaUriInfo;
243     if (!ParseMediaSandboxPath(sandboxPath, mediaUriInfo)) {
244         return -EINVAL;
245     }
246 
247     int32_t bucketNum = GetBucketNum(mediaUriInfo.realName);
248     if (bucketNum < 0) {
249         return -EINVAL;
250     }
251 
252     std::string mediaSuffix;
253     if (GetPathSuffix(sandboxPath, mediaSuffix) != 0) {
254         LOGE("GetPathSuffix failed");
255         return -EINVAL;
256     }
257 
258     physicalPath = SHAER_PATH_HEAD + userId + SHAER_PATH_MID + mediaUriInfo.mediaType +
259                    BACKFLASH + to_string(bucketNum) + BACKFLASH + mediaUriInfo.realName + mediaSuffix;
260     return 0;
261 }
262 
GetNetworkIdFromUri(const std::string & fileUri,string & networkId)263 static void GetNetworkIdFromUri(const std::string &fileUri, string &networkId)
264 {
265     Uri uri(fileUri);
266     std::string networkIdInfo = uri.GetQuery();
267     if (networkIdInfo.empty()) {
268         return;
269     }
270 
271     size_t posIndex = networkIdInfo.find('=');
272     if (posIndex == string::npos || posIndex == (networkIdInfo.size() - 1)) {
273         return;
274     }
275     networkId = networkIdInfo.substr(posIndex + 1);
276 }
277 
GetPhysicalPath(const std::string & fileUri,const std::string & userId,std::string & physicalPath)278 int32_t SandboxHelper::GetPhysicalPath(const std::string &fileUri, const std::string &userId,
279                                        std::string &physicalPath)
280 {
281     Uri uri(fileUri);
282     string bundleName = uri.GetAuthority();
283     if (bundleName == MEDIA) {
284         return GetMediaPhysicalPath(uri.GetPath(), userId, physicalPath);
285     }
286 
287     string sandboxPath = SandboxHelper::Decode(uri.GetPath());
288     if ((sandboxPath.find(FILE_MANAGER_URI_HEAD) == 0 && bundleName != FILE_MANAGER_AUTHORITY) ||
289         (sandboxPath.find(FUSE_URI_HEAD) == 0 && bundleName != DLP_MANAGER_BUNDLE_NAME)) {
290         return -EINVAL;
291     }
292 
293     if (!GetSandboxPathMap()) {
294         LOGE("GetSandboxPathMap failed");
295         return -EINVAL;
296     }
297 
298     string lowerPathTail = "";
299     string lowerPathHead = "";
300     string::size_type curPrefixMatchLen = 0;
301     for (auto it = sandboxPathMap_.begin(); it != sandboxPathMap_.end(); it++) {
302         string sandboxPathPrefix = it->first;
303         string::size_type prefixMatchLen = sandboxPathPrefix.length();
304         if (sandboxPath.length() >= prefixMatchLen) {
305             string sandboxPathTemp = sandboxPath.substr(0, prefixMatchLen);
306             if (sandboxPathTemp == sandboxPathPrefix && curPrefixMatchLen <= prefixMatchLen) {
307                 curPrefixMatchLen = prefixMatchLen;
308                 lowerPathHead = it->second;
309                 lowerPathTail = sandboxPath.substr(prefixMatchLen);
310             }
311         }
312     }
313 
314     if (lowerPathHead == "") {
315         LOGE("lowerPathHead is invalid");
316         return -EINVAL;
317     }
318 
319     string networkId = LOCAL;
320     GetNetworkIdFromUri(fileUri, networkId);
321 
322     physicalPath = GetLowerPath(lowerPathHead, lowerPathTail, userId, bundleName, networkId);
323     return 0;
324 }
325 
IsValidPath(const std::string & path)326 bool SandboxHelper::IsValidPath(const std::string &path)
327 {
328     if (path.find("/./") != std::string::npos ||
329         path.find("/../") != std::string::npos) {
330         return false;
331     }
332     return true;
333 }
334 
CheckValidPath(const std::string & filePath)335 bool SandboxHelper::CheckValidPath(const std::string &filePath)
336 {
337     if (filePath.empty() || filePath.size() >= PATH_MAX) {
338         return false;
339     }
340 
341     char realPath[PATH_MAX]{'\0'};
342     if (realpath(filePath.c_str(), realPath) != nullptr &&
343         strncmp(realPath, filePath.c_str(), filePath.size()) == 0) {
344         return true;
345     } else {
346         return false;
347     }
348 }
349 } // namespace AppFileService
350 } // namespace OHOS
351 
352