1 /*
2  * Copyright (c) 2024 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 "distributed_sched_utils.h"
17 
18 #include <algorithm>
19 #include <cstdlib>
20 #include <filesystem>
21 #include <fstream>
22 #include <iostream>
23 #include <vector>
24 
25 #include "ability_manager_client.h"
26 #include "config_policy_utils.h"
27 #include "securec.h"
28 
29 #include "dtbschedmgr_log.h"
30 
31 namespace OHOS {
32 namespace DistributedSchedule {
33 const std::string TAG = "DistributedSchedUtils";
34 const std::string CONTINUE_CONFIG_RELATIVE_PATH = "etc/distributedhardware/dms/continue_config.json";
35 const std::string ALLOW_APP_LIST_KEY = "allow_applist";
36 constexpr int32_t MAX_CONFIG_PATH_LEN = 1024;
37 constexpr size_t INT32_SHORT_ID_LEN = 20;
38 constexpr size_t INT32_MIN_ID_LEN = 6;
39 constexpr size_t INT32_PLAINTEXT_LEN = 4;
40 
41 constexpr uint32_t OFFSET2 = 2;
42 constexpr uint32_t OFFSET4 = 4;
43 constexpr uint32_t OFFSET6 = 6;
44 constexpr uint8_t PARAM_FC = 0xfc;
45 constexpr uint8_t PARAM_03 = 0x03;
46 constexpr uint8_t PARAM_F0 = 0xf0;
47 constexpr uint8_t PARAM_0F = 0x0f;
48 constexpr uint8_t PARAM_C0 = 0xc0;
49 constexpr uint8_t PARAM_3F = 0x3f;
50 constexpr uint32_t INDEX_FIRST = 0;
51 constexpr uint32_t INDEX_SECOND = 1;
52 constexpr uint32_t INDEX_THIRD = 2;
53 constexpr uint32_t INDEX_FORTH = 3;
54 
55 static std::atomic<bool> g_isMissContinueCfg = false;
56 static std::string g_continueCfgFullPath = "";
57 static std::vector<std::string> g_allowAppList;
58 std::mutex g_allowAppListMtx;
59 
IsValidPath(const std::string & inFilePath,std::string & realFilePath)60 bool IsValidPath(const std::string &inFilePath, std::string &realFilePath)
61 {
62     char path[PATH_MAX + 1] = { 0 };
63     if (inFilePath.empty() || inFilePath.length() > PATH_MAX || inFilePath.length() + 1 > MAX_CONFIG_PATH_LEN ||
64         realpath(inFilePath.c_str(), path) == nullptr) {
65         HILOGE("Get continue config file real path fail, inFilePath %{public}s.", GetAnonymStr(inFilePath).c_str());
66         return false;
67     }
68 
69     realFilePath = std::string(path);
70     if (realFilePath.empty()) {
71         HILOGE("Real file path is empty.");
72         return false;
73     }
74     if (!std::filesystem::exists(realFilePath)) {
75         HILOGE("The real file path %{public}s does not exist in the file system.", GetAnonymStr(realFilePath).c_str());
76         realFilePath = "";
77         return false;
78     }
79     HILOGI("The real file path %{public}s exist in the file system.", GetAnonymStr(realFilePath).c_str());
80     return true;
81 }
82 
UpdateAllowAppList(const std::string & cfgJsonStr)83 bool UpdateAllowAppList(const std::string &cfgJsonStr)
84 {
85     cJSON *inJson = nullptr;
86     cJSON *allowList = nullptr;
87     bool isSuccess = false;
88     do {
89         inJson = cJSON_Parse(cfgJsonStr.c_str());
90         if (inJson == nullptr) {
91             HILOGE("parse continue config json file stream to json fail.");
92             break;
93         }
94 
95         allowList = cJSON_GetObjectItem(inJson, ALLOW_APP_LIST_KEY.c_str());
96         if (allowList == nullptr || !cJSON_IsArray(allowList)) {
97             HILOGE("allow app list array is not in continue config json file.");
98             break;
99         }
100 
101         std::lock_guard<std::mutex> lock(g_allowAppListMtx);
102         for (int32_t i = 0; i < cJSON_GetArraySize(allowList); i++) {
103             cJSON *iAllowAppJson = cJSON_GetArrayItem(allowList, i);
104             if (!cJSON_IsString(iAllowAppJson)) {
105                 HILOGE("allow app list [%{public}d] is not string.", i);
106                 continue;
107             }
108 
109             std::string iAllowAppStr = std::string(cJSON_GetStringValue(iAllowAppJson));
110             HILOGI("allow app list show [%{public}d] : [%{public}s].", i, iAllowAppStr.c_str());
111             g_allowAppList.push_back(iAllowAppStr);
112         }
113         isSuccess = true;
114     } while (false);
115 
116     if (inJson != nullptr) {
117         cJSON_Delete(inJson);
118         inJson = nullptr;
119     }
120     return isSuccess;
121 }
122 
LoadContinueConfig()123 int32_t LoadContinueConfig()
124 {
125     HILOGI("Load continue config, isMissContinueCfg %{public}d, ContinueCfgFullPath %{public}s.",
126         g_isMissContinueCfg.load(), GetAnonymStr(g_continueCfgFullPath).c_str());
127     std::string tempPath = g_continueCfgFullPath;
128     if (!g_isMissContinueCfg.load() &&
129         (g_continueCfgFullPath.empty() || !IsValidPath(tempPath, g_continueCfgFullPath))) {
130         char cfgPathBuf[MAX_CONFIG_PATH_LEN] = { 0 };
131         char *filePath  = GetOneCfgFile(CONTINUE_CONFIG_RELATIVE_PATH.c_str(), cfgPathBuf, MAX_CONFIG_PATH_LEN);
132         if (filePath == nullptr || filePath != cfgPathBuf) {
133             HILOGI("Not find continue config file, relative path %{public}s.",
134                 GetAnonymStr(CONTINUE_CONFIG_RELATIVE_PATH).c_str());
135             g_isMissContinueCfg.store(true);
136             g_continueCfgFullPath = "";
137             return ERR_OK;
138         }
139         g_isMissContinueCfg.store(false);
140         g_continueCfgFullPath = std::string(filePath);
141         HILOGI("Get Continue config file full path success, cfgFullPath %{public}s.",
142             GetAnonymStr(g_continueCfgFullPath).c_str());
143     }
144     if (g_isMissContinueCfg.load()) {
145         HILOGI("Current device does not carry continue config file.");
146         return ERR_OK;
147     }
148     tempPath = g_continueCfgFullPath;
149     std::string anonymPath = GetAnonymStr(g_continueCfgFullPath);
150     if (!IsValidPath(tempPath, g_continueCfgFullPath)) {
151         HILOGE("Continue config full path is invalid, cfgFullPath %{public}s.", anonymPath.c_str());
152         return DMS_PERMISSION_DENIED;
153     }
154     std::ifstream in;
155     in.open(g_continueCfgFullPath.c_str(), std::ios::binary | std::ios::in);
156     if (!in.is_open()) {
157         HILOGE("Open continue config json file fail, cfgFullPath %{public}s.", anonymPath.c_str());
158         return DMS_PERMISSION_DENIED;
159     }
160 
161     std::string cfgFileContent;
162     in.seekg(0, std::ios::end);
163     cfgFileContent.resize(in.tellg());
164     in.seekg(0, std::ios::beg);
165     in.rdbuf()->sgetn(&cfgFileContent[0], cfgFileContent.size());
166     in.close();
167 
168     if (!UpdateAllowAppList(cfgFileContent)) {
169         HILOGE("Update allow app list fail, cfgFullPath %{public}s.", anonymPath.c_str());
170         return DMS_PERMISSION_DENIED;
171     }
172     HILOGI("Load continue config success, isMissContinueCfg %{public}d, cfgFullPath %{public}s.",
173         g_isMissContinueCfg.load(), anonymPath.c_str());
174     return ERR_OK;
175 }
176 
CheckBundleContinueConfig(const std::string & bundleName)177 bool CheckBundleContinueConfig(const std::string &bundleName)
178 {
179     if (g_isMissContinueCfg.load()) {
180         HILOGI("Current device does not carry continue config file.");
181         return true;
182     }
183 
184     std::lock_guard<std::mutex> lock(g_allowAppListMtx);
185     auto it = std::find(g_allowAppList.begin(), g_allowAppList.end(), bundleName);
186     if (it == g_allowAppList.end()) {
187         HILOGE("Current app is not allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
188             bundleName.c_str(), GetAnonymStr(g_continueCfgFullPath).c_str());
189         return false;
190     }
191 
192     HILOGI("Current app is allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
193         bundleName.c_str(), GetAnonymStr(g_continueCfgFullPath).c_str());
194     return true;
195 }
196 
GetCurrentMissionId()197 int32_t GetCurrentMissionId()
198 {
199     HILOGI("GetCurrentMission begin");
200     sptr<IRemoteObject> token;
201     int ret = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility(token);
202     if (ret != ERR_OK || token == nullptr) {
203         HILOGE("GetTopAbility failed, ret: %{public}d", ret);
204         return INVALID_MISSION_ID;
205     }
206     int32_t missionId = INVALID_MISSION_ID;
207     if (AAFwk::AbilityManagerClient::GetInstance()->GetMissionIdByToken(token, missionId) != ERR_OK) {
208         HILOGE("GetMissionIdByToken failed");
209         return INVALID_MISSION_ID;
210     }
211     return missionId;
212 }
213 
ParcelToBase64Str(const Parcel & parcel)214 std::string ParcelToBase64Str(const Parcel& parcel)
215 {
216     auto parcelSize = parcel.GetDataSize();
217     return Base64Encode(reinterpret_cast<const unsigned char *>(parcel.GetData()), parcelSize);
218 }
219 
Base64StrToParcel(const std::string & rawStr,Parcel & parcel)220 int32_t Base64StrToParcel(const std::string& rawStr, Parcel& parcel)
221 {
222     std::string str = Base64Decode(rawStr);
223     auto parcelSize = str.size();
224     if (!parcel.SetDataCapacity(parcelSize)) {
225         HILOGE("Base64 string parcel set data capacity %{public}zu fail.", parcelSize);
226         return INVALID_PARAMETERS_ERR;
227     }
228     auto ret = memcpy_s((void *)parcel.GetData(), parcel.GetMaxCapacity(), &str[0], parcelSize);
229     if (ret != ERR_OK || !parcel.SetDataSize(parcelSize)) {
230         HILOGE("Base64 string parcel memcpy raw string data fail.");
231         return INVALID_PARAMETERS_ERR;
232     }
233     return ERR_OK;
234 }
235 
Base64Encode(const unsigned char * toEncode,unsigned int len)236 std::string Base64Encode(const unsigned char *toEncode, unsigned int len)
237 {
238     std::string ret = "";
239     if (len == 0 || toEncode == nullptr) {
240         HILOGE("toEncode is null or len is zero.");
241         return ret;
242     }
243     uint32_t length = len;
244     uint32_t i = 0;
245     unsigned char charArray3[3];
246     unsigned char charArray4[4];
247 
248     while (length--) {
249         charArray3[i++] = *(toEncode++);
250         if (i == sizeof(charArray3)) {
251             charArray4[INDEX_FIRST] = (charArray3[INDEX_FIRST] & PARAM_FC) >> OFFSET2;
252             charArray4[INDEX_SECOND] = ((charArray3[INDEX_FIRST] & PARAM_03) << OFFSET4) +
253                 ((charArray3[INDEX_SECOND] & PARAM_F0) >> OFFSET4);
254             charArray4[INDEX_THIRD] = ((charArray3[INDEX_SECOND] & PARAM_0F) << OFFSET2) +
255                 ((charArray3[INDEX_THIRD] & PARAM_C0) >> OFFSET6);
256             charArray4[INDEX_FORTH] = charArray3[INDEX_THIRD] & PARAM_3F;
257             for (i = 0; i < sizeof(charArray4); i++) {
258                 ret += BASE_64_CHARS[charArray4[i]];
259             }
260             i = 0;
261         }
262     }
263 
264     if (i > 0) {
265         uint32_t j = 0;
266         for (j = i; j < sizeof(charArray3); j++) {
267             charArray3[j] = '\0';
268         }
269         charArray4[INDEX_FIRST] = (charArray3[INDEX_FIRST] & PARAM_FC) >> OFFSET2;
270         charArray4[INDEX_SECOND] = ((charArray3[INDEX_FIRST] & PARAM_03) << OFFSET4) +
271             ((charArray3[INDEX_SECOND] & PARAM_F0) >> OFFSET4);
272         charArray4[INDEX_THIRD] = ((charArray3[INDEX_SECOND] & PARAM_0F) << OFFSET2) +
273             ((charArray3[INDEX_THIRD] & PARAM_C0) >> OFFSET6);
274         charArray4[INDEX_FORTH] = charArray3[INDEX_THIRD] & PARAM_3F;
275         for (j = 0; j < i + 1; j++) {
276             ret += BASE_64_CHARS[charArray4[j]];
277         }
278         while (i++ < sizeof(charArray3)) {
279             ret += '=';
280         }
281     }
282     return ret;
283 }
284 
Base64Decode(const std::string & basicString)285 std::string Base64Decode(const std::string& basicString)
286 {
287     std::string ret = "";
288     if (basicString.empty()) {
289         HILOGE("basicString is empty.");
290         return ret;
291     }
292     uint32_t i = 0;
293     int index = 0;
294     int len = static_cast<int>(basicString.size());
295     unsigned char charArray3[3];
296     unsigned char charArray4[4];
297 
298     while (len-- && (basicString[index] != '=') && IsBase64(basicString[index])) {
299         charArray4[i++] = basicString[index];
300         index++;
301         if (i == sizeof(charArray4)) {
302             for (i = 0; i < sizeof(charArray4); i++) {
303                 charArray4[i] = BASE_64_CHARS.find(charArray4[i]);
304             }
305             charArray3[INDEX_FIRST] = (charArray4[INDEX_FIRST] << OFFSET2) +
306                 ((charArray4[INDEX_SECOND] & 0x30) >> OFFSET4);
307             charArray3[INDEX_SECOND] = ((charArray4[INDEX_SECOND] & 0xf) << OFFSET4) +
308                 ((charArray4[INDEX_THIRD] & 0x3c) >> OFFSET2);
309             charArray3[INDEX_THIRD] = ((charArray4[INDEX_THIRD] & 0x3) << OFFSET6) + charArray4[INDEX_FORTH];
310             for (i = 0; i < sizeof(charArray3); i++) {
311                 ret += charArray3[i];
312             }
313             i = 0;
314         }
315     }
316 
317     if (i > 0) {
318         uint32_t j = 0;
319         for (j = i; j < sizeof(charArray4); j++) {
320             charArray4[j] = 0;
321         }
322         for (j = 0; j < sizeof(charArray4); j++) {
323             charArray4[j] = BASE_64_CHARS.find(charArray4[j]);
324         }
325         charArray3[INDEX_FIRST] = (charArray4[INDEX_FIRST] << OFFSET2) +
326             ((charArray4[INDEX_SECOND] & 0x30) >> OFFSET4);
327         charArray3[INDEX_SECOND] = ((charArray4[INDEX_SECOND] & 0xf) << OFFSET4) +
328             ((charArray4[INDEX_THIRD] & 0x3c) >> OFFSET2);
329         charArray3[INDEX_THIRD] = ((charArray4[INDEX_THIRD] & 0x3) << OFFSET6) + charArray4[INDEX_FORTH];
330         for (j = 0; j < i - 1; j++) {
331             ret += charArray3[j];
332         }
333     }
334     return ret;
335 }
336 
IsBase64(unsigned char c)337 bool IsBase64(unsigned char c)
338 {
339     return (isalnum(c) || (c == '+') || (c == '/'));
340 }
341 
GetAnonymStr(const std::string & value)342 std::string GetAnonymStr(const std::string &value)
343 {
344     std::string res;
345     std::string tmpStr("******");
346     size_t strLen = value.length();
347     if (strLen < INT32_MIN_ID_LEN) {
348         return tmpStr;
349     }
350 
351     if (strLen <= INT32_SHORT_ID_LEN) {
352         res += value[0];
353         res += tmpStr;
354         res += value[strLen - 1];
355     } else {
356         res.append(value, 0, INT32_PLAINTEXT_LEN);
357         res += tmpStr;
358         res.append(value, strLen - INT32_PLAINTEXT_LEN, INT32_PLAINTEXT_LEN);
359     }
360 
361     return res;
362 }
363 
GetAnonymInt32(const int32_t value)364 std::string GetAnonymInt32(const int32_t value)
365 {
366     std::string tmpStr = std::to_string(value);
367     return GetAnonymStr(tmpStr);
368 }
369 
370 } // namespace DistributedSchedule
371 } // namespace OHOS
372