1 /*
2  * Copyright (c) 2020 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 "bundle_daemon_handler.h"
17 
18 #include <climits>
19 #include <cstring>
20 #include <dirent.h>
21 
22 #include "bundle_daemon_log.h"
23 #include "bundle_file_utils.h"
24 #include "extractor_util.h"
25 #include "ohos_errno.h"
26 
27 namespace OHOS {
28 namespace {
29 const char *PERMISSIONS_PATH = "/storage/app/etc/permissions/";
30 constexpr pid_t PMS_UID = 7;
31 constexpr pid_t PMS_GID = 7;
32 const std::string JSON_PATH = "/app/etc/";
33 const std::string HAP_CODE_PATH = "/app/run/";
34 const std::string HAP_DATA_PATH = "/app/data/";
35 const std::string SYSTEM_HAP_PATH = "/system/internal";
36 const std::string THIRD_HAP_PATH = "/system/external";
37 const std::string SDCARD = "/sdcard";
38 const std::string STORAGE = "/storage";
39 }
40 
ExtractHap(const char * hapPath,const char * codePath)41 int32_t BundleDaemonHandler::ExtractHap(const char *hapPath, const char *codePath)
42 {
43     char realHapPath[PATH_MAX + 1] = { '\0' };
44     if (hapPath == nullptr || realpath(hapPath, realHapPath) == nullptr) {
45         PRINTE("BundleDaemonHandler", "realPath fail!");
46         return EC_INVALID;
47     }
48     ExtractorUtil extractorUtil(realHapPath);
49     if (!extractorUtil.Init()) {
50         PRINTE("BundleDaemonHandler", "init fail!");
51         return EC_NOINIT;
52     }
53 
54     // check and mkdir code path
55     if (!IsValideCodePath(codePath)) {
56         return EC_INVALID;
57     }
58     if (!BundleFileUtils::RemoveFile(codePath)) {
59         PRINTE("BundleDaemonHandler", "remove codePath fail!");
60         return EC_NODIR;
61     }
62     std::string codeDir = std::string(codePath);
63     if (codeDir.back() != PATH_SEPARATOR) {
64         codeDir += PATH_SEPARATOR;
65     }
66 
67     if (!BundleFileUtils::MkRecursiveDir(codeDir.c_str(), true)) {
68         PRINTE("BundleDaemonHandler", "create codePath fail!");
69         return EC_NODIR;
70     }
71 
72     // unzip one by one
73     const std::vector<std::string> &fileNames = extractorUtil.GetZipFileNames();
74     for (const auto &fileName : fileNames) {
75         if (fileName.find("..") != std::string::npos) {
76             PRINTE("BundleDaemonHandler", "zip file is invalid!");
77             return EC_NODIR;
78         }
79         if (fileName.back() == PATH_SEPARATOR) {
80             continue;
81         }
82         const std::string dir = BundleFileUtils::GetPathDir(fileName);
83         if (!dir.empty()) {
84             std::string fileDir = codeDir + dir;
85             if (!BundleFileUtils::MkRecursiveDir(fileDir.c_str(), false)) {
86                 PRINTE("BundleDaemonHandler", "create other dir fail!");
87                 return EC_NODIR;
88             }
89         }
90         std::string filePath = codeDir + fileName;
91         if (!extractorUtil.ExtractFileToPath(filePath, fileName)) {
92             PRINTE("BundleDaemonHandler", "ExtractFileToPath fail!");
93             return EC_NODIR;
94         }
95     }
96     return EC_SUCCESS;
97 }
98 
RenameFile(const char * oldFile,const char * newFile)99 int32_t BundleDaemonHandler::RenameFile(const char *oldFile, const char *newFile)
100 {
101     char realOldPath[PATH_MAX + 1] = { '\0' };
102     if (oldFile == nullptr || realpath(oldFile, realOldPath) == nullptr) {
103         PRINTE("BundleDaemonHandler", "realPath fail!");
104         return EC_INVALID;
105     }
106     if (!(IsValideCodePath(realOldPath) && IsValideCodePath(newFile)) &&
107         !(IsValideJsonPath(realOldPath) && IsValideJsonPath(newFile))) {
108         PRINTE("BundleDaemonHandler", "file path is invalid");
109         return EC_INVALID;
110     }
111     if (!BundleFileUtils::RenameFile(realOldPath, newFile)) {
112         PRINTE("BundleDaemonHandler", "rename dir fail");
113         return EC_NODIR;
114     }
115     return EC_SUCCESS;
116 }
117 
CreatePermissionDir()118 int32_t BundleDaemonHandler::CreatePermissionDir()
119 {
120     if (!BundleFileUtils::MkRecursiveDir(PERMISSIONS_PATH, false)) {
121         PRINTE("BundleDaemonHandler", "mk dir fail");
122         return EC_NODIR;
123     }
124     if (!BundleFileUtils::ChownFile(PERMISSIONS_PATH, PMS_UID, PMS_GID)) {
125         PRINTE("BundleDaemonHandler", "chown permission path fail");
126         return EC_PERMISSION;
127     }
128     return EC_SUCCESS;
129 }
130 
CreateDataDirectory(const char * dataPath,int32_t uid,int32_t gid,bool isChown)131 int32_t BundleDaemonHandler::CreateDataDirectory(const char *dataPath, int32_t uid, int32_t gid, bool isChown)
132 {
133     if (!IsValideDataPath(dataPath)) {
134         PRINTE("BundleDaemonHandler", "bundleName is nullptr");
135         return EC_INVALID;
136     }
137     std::string dataDir = std::string(dataPath);
138     if (dataDir.back() != PATH_SEPARATOR) {
139         dataDir += PATH_SEPARATOR;
140     }
141 
142     if (!BundleFileUtils::IsExistDir(dataDir.c_str())) {
143         if (!BundleFileUtils::MkOwnerDir(dataDir.c_str())) {
144             PRINTE("BundleDaemonHandler", "create dataPath fail");
145             return EC_NODIR;
146         }
147     }
148     PRINTI("BundleDaemonClient", "uid is %{public}d, isChown is %{public}d", uid, isChown);
149     if (isChown && !BundleFileUtils::ChownFile(dataDir.c_str(), uid, gid)) {
150         PRINTE("BundleDaemonHandler", "chown file fail");
151         return EC_NOFILE;
152     }
153     return EC_SUCCESS;
154 }
155 
RemoveInstallDirectory(const char * codePath,const char * dataPath,bool keepData)156 int32_t BundleDaemonHandler::RemoveInstallDirectory(const char *codePath, const char *dataPath, bool keepData)
157 {
158     bool result = IsValideCodePath(codePath) && BundleFileUtils::RemoveFile(codePath);
159     if (!keepData) {
160         result = IsValideDataPath(dataPath) && BundleFileUtils::RemoveFile(dataPath) && result;
161     }
162     return result ? EC_SUCCESS : EC_NODIR;
163 }
164 
StoreContentToFile(const char * filePath,const void * buffer,uint32_t size)165 int32_t BundleDaemonHandler::StoreContentToFile(const char *filePath, const void *buffer, uint32_t size)
166 {
167     if (!IsValideJsonPath(filePath)) {
168         PRINTE("BundleDaemonHandler", "store content file path invalid");
169         return EC_NOFILE;
170     }
171     // mkdir root dir
172     const std::string dir = BundleFileUtils::GetPathDir(filePath);
173     if (dir.empty()) {
174         PRINTE("BundleDaemonHandler", "store content file dir invalid");
175         return EC_NODIR;
176     }
177     if (!BundleFileUtils::IsExistDir(dir.c_str())) {
178         if (!BundleFileUtils::MkRecursiveDir(dir.c_str(), true)) {
179             PRINTE("BundleDaemonHandler", "mkdir content json path fail");
180             return EC_NODIR;
181         }
182     }
183 
184     if (!BundleFileUtils::WriteFile(filePath, buffer, size)) {
185         PRINTE("BundleDaemonHandler", "save content to file fail");
186         BundleFileUtils::RemoveFile(filePath);
187         return EC_NODIR;
188     }
189     return EC_SUCCESS;
190 }
191 
MoveFile(const char * oldFile,const char * newFile)192 int32_t BundleDaemonHandler::MoveFile(const char *oldFile, const char *newFile)
193 {
194     char realOldPath[PATH_MAX + 1] = { '\0' };
195     if (oldFile == nullptr || realpath(oldFile, static_cast<char *>(realOldPath)) == nullptr) {
196         PRINTE("BundleDaemonHandler", "realPath oldFile fail!");
197         return EC_INVALID;
198     }
199 
200     if (BundleFileUtils::IsExistFile(static_cast<char *>(realOldPath))) {
201         if (!BundleFileUtils::RenameFile(static_cast<char *>(realOldPath), newFile)) {
202             PRINTE("BundleDaemonHandler", "RenameFile fail!");
203             return EC_FAILURE;
204         }
205         return EC_SUCCESS;
206     }
207     if (BundleFileUtils::IsExistFile(newFile)) {
208         PRINTE("BundleDaemonHandler", "target file exist!");
209         return EC_INVALID;
210     }
211     if (!BundleFileUtils::IsExistDir(newFile)) {
212         BundleFileUtils::MkRecursiveDir(newFile, true);
213     }
214 
215     DIR *dir = opendir(static_cast<char *>(realOldPath));
216     if (dir == nullptr) {
217         return EC_FAILURE;
218     }
219 
220     dirent *ent;
221     while ((ent = readdir(dir)) != nullptr) {
222         if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..")) == 0) {
223             continue;
224         }
225         std::string oldFileName = std::string(realOldPath) + PATH_SEPARATOR + ent->d_name;
226         if (BundleFileUtils::IsExistDir(oldFileName.c_str())) {
227             continue;
228         }
229         std::string newFileName = std::string(newFile) + PATH_SEPARATOR + ent->d_name;
230         if (!BundleFileUtils::RenameFile(oldFileName.c_str(), newFileName.c_str())) {
231             PRINTW("BundleDaemonHandler", "RenameFile fail!");
232         }
233     }
234     closedir(dir);
235     BundleFileUtils::RemoveFile(static_cast<char *>(realOldPath));
236 
237     return EC_SUCCESS;
238 }
239 
RemoveFile(const char * filePath)240 int32_t BundleDaemonHandler::RemoveFile(const char *filePath)
241 {
242     char realFilePath[PATH_MAX + 1] = { '\0' };
243     if (filePath == nullptr || realpath(filePath, realFilePath) == nullptr) {
244         PRINTE("BundleDaemonHandler", "realPath fail!");
245         return EC_INVALID;
246     }
247     if (!IsValideJsonPath(realFilePath) && !IsValideSystemPath(realFilePath) &&
248         !IsValideCodePath(realFilePath)) {
249         PRINTE("BundleDaemonHandler", "file path is invalid");
250         return EC_INVALID;
251     }
252     if (!BundleFileUtils::RemoveFile(realFilePath)) {
253         PRINTE("BundleDaemonHandler", "clear content to file fail");
254         return EC_NODIR;
255     }
256     return EC_SUCCESS;
257 }
258 
IsValideCodePath(const char * codePath)259 bool BundleDaemonHandler::IsValideCodePath(const char *codePath)
260 {
261     if (codePath == nullptr) {
262         return false;
263     }
264     return BundleFileUtils::IsValidPath(STORAGE + HAP_CODE_PATH, codePath) ||
265         BundleFileUtils::IsValidPath(SDCARD + HAP_CODE_PATH, codePath);
266 }
267 
IsValideDataPath(const char * dataPath)268 bool BundleDaemonHandler::IsValideDataPath(const char *dataPath)
269 {
270     if (dataPath == nullptr) {
271         return false;
272     }
273     return BundleFileUtils::IsValidPath(STORAGE + HAP_DATA_PATH, dataPath) ||
274         BundleFileUtils::IsValidPath(SDCARD + HAP_DATA_PATH, dataPath);
275 }
276 
IsValideJsonPath(const char * jsonPath)277 bool BundleDaemonHandler::IsValideJsonPath(const char *jsonPath)
278 {
279     if (jsonPath == nullptr) {
280         return false;
281     }
282     return BundleFileUtils::IsValidPath(STORAGE + JSON_PATH, jsonPath);
283 }
284 
IsValideSystemPath(const char * path)285 bool BundleDaemonHandler::IsValideSystemPath(const char *path)
286 {
287     if (path == nullptr) {
288         return false;
289     }
290     return BundleFileUtils::IsValidPath(SYSTEM_HAP_PATH, path) ||
291         BundleFileUtils::IsValidPath(THIRD_HAP_PATH, path);
292 }
293 } // OHOS
294