1 /*
2 * Copyright (c) 2025 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 "dlp_file_operator.h"
16
17 #include <cstdio>
18 #include <dirent.h>
19 #include <memory>
20 #include <openssl/rand.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "nlohmann/json.hpp"
26
27 #include "cert_parcel.h"
28 #include "dlp_crypt.h"
29 #include "dlp_file_manager.h"
30 #include "dlp_permission.h"
31 #include "dlp_permission_kit.h"
32 #include "dlp_permission_log.h"
33 #include "dlp_utils.h"
34 #include "permission_policy.h"
35
36 namespace OHOS {
37 namespace Security {
38 namespace DlpPermission {
39
40 namespace {
41 static const std::string ACCOUNT_INDEX = "account";
42 static const std::string ACCOUNT_TYPE = "accountType";
43 static const std::string EDIT_INDEX = "edit";
44 static const std::string ENC_ACCOUNT_TYPE = "accountType";
45 static const std::string EVERYONE_INDEX = "everyone";
46 static const std::string FC_INDEX = "fullCtrl";
47 static const std::string NEED_ONLINE = "needOnline";
48 static const std::string OWNER_ACCOUNT_NAME = "ownerAccountName";
49 static const std::string OWNER_ACCOUNT = "ownerAccount";
50 static const std::string OWNER_ACCOUNT_ID = "ownerAccountId";
51 static const std::string OWNER_ACCOUNT_TYPE = "ownerAccountType";
52 static const std::string AUTHUSER_LIST = "authUserList";
53 static const std::string CONTACT_ACCOUNT = "contactAccount";
54 static const std::string OFFLINE_ACCESS = "offlineAccess";
55 static const std::string EVERYONE_ACCESS_LIST = "everyoneAccessList";
56 static const std::string PERM_EXPIRY_TIME = "expireTime";
57 static const std::string ACTION_UPON_EXPIRY = "actionUponExpiry";
58 static const std::string POLICY_INDEX = "policy";
59 static const std::string READ_INDEX = "read";
60 static const std::string RIGHT_INDEX = "right";
61 static const std::string CUSTOM_PROPERTY = "customProperty";
62 const std::string PATH_CACHE = "cache";
63
64 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
65 LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "EnterpriseDlpPermissionKit"
66 };
67 using Defer = std::shared_ptr<void>;
68 using json = nlohmann::ordered_json;
69 std::mutex g_dirCleanLock;
70 std::mutex g_missionMutex;
71 std::shared_ptr<std::thread> g_missionThread = nullptr;
72 const std::string APPID = "com.ohos.dlpmanager_BAurHtxID8irkrB1VYVHLCWnMGKeOwaGNcJymGCMdhIpP+"
73 "PyVFlFnmikA0NIVqmvB+TnZpjup0qT4D0nEdTM/soy4Ab/wzCdSyoJYPNjl6IR/lW/IktytZ7Mn6auB9dJ4g==";
74 }
75
EnterpriseSpaceDlpPermissionKit()76 EnterpriseSpaceDlpPermissionKit::EnterpriseSpaceDlpPermissionKit() {}
77
GetInstance()78 EnterpriseSpaceDlpPermissionKit* EnterpriseSpaceDlpPermissionKit::GetInstance()
79 {
80 static EnterpriseSpaceDlpPermissionKit instance;
81 return &instance;
82 }
83
~EnterpriseSpaceDlpPermissionKit()84 EnterpriseSpaceDlpPermissionKit::~EnterpriseSpaceDlpPermissionKit() {}
85
GenerateRandomWorkDir(std::string & workDir)86 static int32_t GenerateRandomWorkDir(std::string &workDir)
87 {
88 DlpBlob dir;
89 int32_t res = DlpOpensslGenerateRandom(sizeof(uint64_t) * BIT_NUM_OF_UINT8, &dir);
90 if (res != DLP_OK) {
91 DLP_LOG_ERROR(LABEL, "Generate dir fail, errno=%{public}d", res);
92 return res;
93 }
94
95 workDir = std::to_string(*reinterpret_cast<uint64_t *>(dir.data));
96 delete[] dir.data;
97 return DLP_OK;
98 }
99
PrepareWorkDir(const std::string & path)100 static int32_t PrepareWorkDir(const std::string& path)
101 {
102 if (mkdir(path.c_str(), S_IRWXU) < 0) {
103 DLP_LOG_ERROR(LABEL, "mkdir work dir failed errno %{public}d", errno);
104 return DLP_PARSE_ERROR_FILE_OPERATE_FAIL;
105 }
106 return DLP_OK;
107 }
108
SerializePermInfo(DLPFileAccess perm,json & rightInfoJson)109 static void SerializePermInfo(DLPFileAccess perm, json& rightInfoJson)
110 {
111 bool read = false;
112 bool edit = false;
113 bool fullCtrl = false;
114
115 switch (perm) {
116 case DLPFileAccess::READ_ONLY: {
117 read = true;
118 break;
119 }
120 case DLPFileAccess::CONTENT_EDIT: {
121 edit = true;
122 break;
123 }
124 case DLPFileAccess::FULL_CONTROL: {
125 read = true;
126 edit = true;
127 fullCtrl = true;
128 break;
129 }
130 default:
131 break;
132 }
133 rightInfoJson[READ_INDEX] = read;
134 rightInfoJson[EDIT_INDEX] = edit;
135 rightInfoJson[FC_INDEX] = fullCtrl;
136 }
137
SerializeAuthUserList(const std::vector<AuthUserInfo> & authUsers,json & authUsersJson)138 static void SerializeAuthUserList(const std::vector<AuthUserInfo>& authUsers, json& authUsersJson)
139 {
140 for (const AuthUserInfo& info : authUsers) {
141 json rightInfoJson;
142 SerializePermInfo(info.authPerm, rightInfoJson);
143 authUsersJson[info.authAccount.c_str()][RIGHT_INDEX] = rightInfoJson;
144 }
145 }
146
SerializeEveryoneInfo(const PermissionPolicy & policy,json & permInfoJson)147 static void SerializeEveryoneInfo(const PermissionPolicy& policy, json& permInfoJson)
148 {
149 if (policy.supportEveryone_) {
150 json rightInfoJson;
151 SerializePermInfo(policy.everyonePerm_, rightInfoJson);
152 permInfoJson[EVERYONE_INDEX][RIGHT_INDEX] = rightInfoJson;
153 return;
154 }
155 }
156
SerializePermissionPolicy(const PermissionPolicy & policy,std::string & policyString)157 static int32_t SerializePermissionPolicy(const PermissionPolicy& policy, std::string& policyString)
158 {
159 json policyJson;
160 json authUsersJson;
161 SerializeAuthUserList(policy.authUsers_, authUsersJson);
162 policyJson[OWNER_ACCOUNT_NAME] = policy.ownerAccount_;
163 policyJson[OWNER_ACCOUNT_ID] = policy.ownerAccountId_;
164 policyJson[ACCOUNT_INDEX] = authUsersJson;
165 policyJson[PERM_EXPIRY_TIME] = policy.expireTime_;
166 policyJson[NEED_ONLINE] = policy.needOnline_;
167 policyJson[CUSTOM_PROPERTY] = policy.customProperty_;
168 SerializeEveryoneInfo(policy, policyJson);
169 policyString = policyJson.dump();
170 return DLP_OK;
171 }
172
SetCustomProperty(DlpProperty & property,const CustomProperty & customProperty)173 static void SetCustomProperty(DlpProperty& property, const CustomProperty& customProperty)
174 {
175 property.customProperty.enterprise = customProperty.enterprise;
176 }
177
EnterpriseSpaceParseDlpFileProperty(std::shared_ptr<DlpFile> & filePtr,PermissionPolicy & policy,bool needCheckCustomProperty)178 int32_t EnterpriseSpaceDlpPermissionKit::EnterpriseSpaceParseDlpFileProperty(std::shared_ptr<DlpFile>& filePtr,
179 PermissionPolicy& policy, bool needCheckCustomProperty)
180 {
181 int32_t result = filePtr->ProcessDlpFile();
182 if (result != DLP_OK) {
183 return result;
184 }
185 struct DlpBlob cert;
186 filePtr->GetEncryptCert(cert);
187 sptr<CertParcel> certParcel = new (std::nothrow) CertParcel();
188 if (certParcel == nullptr) {
189 DLP_LOG_ERROR(LABEL, "Alloc certParcel parcel fail");
190 return DLP_PARSE_ERROR_MEMORY_OPERATE_FAIL;
191 }
192 certParcel->cert = std::vector<uint8_t>(cert.data, cert.data + cert.size);
193 struct DlpBlob offlineCert = { 0 };
194 uint32_t flag = filePtr->GetOfflineAccess();
195 if (flag != 0) {
196 filePtr->GetOfflineCert(offlineCert);
197 certParcel->offlineCert = std::vector<uint8_t>(offlineCert.data, offlineCert.data + offlineCert.size);
198 }
199 filePtr->GetContactAccount(certParcel->contactAccount);
200 certParcel->isNeedAdapter = filePtr->NeedAdapter();
201 certParcel->needCheckCustomProperty = needCheckCustomProperty;
202 result = DlpPermissionKit::ParseDlpCertificate(certParcel, policy, APPID, filePtr->GetOfflineAccess());
203 if (result != DLP_OK) {
204 DLP_LOG_ERROR(LABEL, "Parse cert fail, errno=%{public}d", result);
205 return result;
206 }
207 result = filePtr->SetPolicy(policy);
208 if (result != DLP_OK) {
209 DLP_LOG_ERROR(LABEL, "Set policy fail, errno=%{public}d", result);
210 return result;
211 }
212 return DLP_OK;
213 }
214
EnterpriseSpacePrepareWorkDir(int32_t dlpFileFd,std::shared_ptr<DlpFile> & filePtr,std::string & workDir)215 int32_t EnterpriseSpaceDlpPermissionKit::EnterpriseSpacePrepareWorkDir(int32_t dlpFileFd,
216 std::shared_ptr<DlpFile>& filePtr, std::string& workDir)
217 {
218 int32_t result = DlpUtils::GetFilePathWithFd(dlpFileFd, workDir);
219 if (result != DLP_OK) {
220 DLP_LOG_ERROR(LABEL, "Get file path with fd fail, errno = %{public}d.", result);
221 return result;
222 }
223
224 workDir += PATH_CACHE;
225
226 std::string randomWorkDir;
227 result = GenerateRandomWorkDir(randomWorkDir);
228 if (result != DLP_OK) {
229 DLP_LOG_ERROR(LABEL, "Generate dir fail, errno=%{public}d", result);
230 return result;
231 }
232
233 std::string realWorkDir = workDir + '_' + randomWorkDir;
234 result = PrepareWorkDir(realWorkDir);
235 if (result != DLP_OK) {
236 DLP_LOG_ERROR(LABEL, "Prepare dir fail, errno=%{public}d", result);
237 return result;
238 }
239
240 int64_t timeStamp =
241 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
242 .count();
243 bool isFromUriName = false;
244 std::string realSuffix = DlpUtils::GetRealTypeForEnterpriseWithFd(dlpFileFd, isFromUriName);
245 if (realSuffix == "") {
246 DLP_LOG_ERROR(LABEL, "Get real suffix error.");
247 return DLP_PARSE_ERROR_VALUE_INVALID;
248 }
249 std::string lower = DlpUtils::ToLowerString(realSuffix);
250 std::string realType = "";
251 for (size_t len = MAX_REALY_TYPE_LENGTH; len >= MIN_REALY_TYPE_LENGTH; len--) {
252 if (len > lower.size()) {
253 continue;
254 }
255 std::string newStr = lower.substr(0, len);
256 auto iter = FILE_TYPE_MAP.find(newStr);
257 if (iter != FILE_TYPE_MAP.end()) {
258 realType = newStr;
259 break;
260 }
261 }
262 filePtr = std::make_shared<DlpZipFile>(dlpFileFd, realWorkDir, timeStamp, realType);
263 return DLP_OK;
264 }
265
EnterpriseSpaceParseDlpFileFormat(std::shared_ptr<DlpFile> & filePtr,bool needCheckCustomProperty)266 int32_t EnterpriseSpaceDlpPermissionKit::EnterpriseSpaceParseDlpFileFormat(std::shared_ptr<DlpFile>& filePtr,
267 bool needCheckCustomProperty)
268 {
269 PermissionPolicy policy;
270 int result = EnterpriseSpaceParseDlpFileProperty(filePtr, policy, needCheckCustomProperty);
271 if (result != DLP_OK) {
272 DLP_LOG_ERROR(LABEL, "Enterprise space parse dlp property fail, errno=%{public}d", result);
273 return result;
274 }
275 struct DlpBlob key = {.size = policy.GetAeskeyLen(), .data = policy.GetAeskey()};
276 struct DlpCipherParam param = {.iv = {.size = policy.GetIvLen(), .data = policy.GetIv()}};
277 struct DlpUsageSpec usage = {.mode = DLP_MODE_CTR, .algParam = ¶m};
278 struct DlpBlob hmacKey = {.size = policy.GetHmacKeyLen(), .data = policy.GetHmacKey()};
279 result = filePtr->SetCipher(key, usage, hmacKey);
280 if (result != DLP_OK) {
281 return result;
282 }
283 result = filePtr->HmacCheck();
284 if (result != DLP_OK) {
285 return result;
286 }
287 return result;
288 }
289
EncryptDlpFile(DlpProperty property,CustomProperty customProperty,int32_t plainFileFd,int32_t dlpFileFd)290 int32_t EnterpriseSpaceDlpPermissionKit::EncryptDlpFile(DlpProperty property,
291 CustomProperty customProperty, int32_t plainFileFd, int32_t dlpFileFd)
292 {
293 DLP_LOG_INFO(LABEL, "Start generate dlp file from enterprise space service.");
294 if (plainFileFd < 0 || dlpFileFd < 0) {
295 DLP_LOG_ERROR(LABEL, "Encrypt dlp file fail, plain file fd or dlp file fd invalid");
296 return DLP_PARSE_ERROR_FD_ERROR;
297 }
298 SetCustomProperty(property, customProperty);
299 std::shared_ptr<DlpFile> filePtr = nullptr;
300 std::string workDir;
301 int32_t result = EnterpriseSpacePrepareWorkDir(dlpFileFd, filePtr, workDir);
302 if (result != DLP_OK) {
303 DLP_LOG_ERROR(LABEL, "Enterprise space prepare workDir fail, errno=%{public}d", result);
304 return result;
305 }
306
307 result = DlpFileManager::GetInstance().SetDlpFileParams(filePtr, property);
308 if (result != DLP_OK) {
309 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, set dlp obj params error, errno=%{public}d", result);
310 return result;
311 }
312
313 result = filePtr->GenFile(plainFileFd);
314 if (result != DLP_OK) {
315 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, errno=%{public}d", result);
316 return result;
317 }
318
319 return DLP_OK;
320 }
321
DecryptDlpFile(int32_t plainFileFd,int32_t dlpFileFd)322 int32_t EnterpriseSpaceDlpPermissionKit::DecryptDlpFile(int32_t plainFileFd, int32_t dlpFileFd)
323 {
324 DLP_LOG_INFO(LABEL, "Start decrypt dlp file from enterprise space service.");
325 if (plainFileFd < 0 || dlpFileFd < 0) {
326 DLP_LOG_ERROR(LABEL, "Decrypt dlp file fail, plain file fd or dlp file fd invalid");
327 return DLP_PARSE_ERROR_FD_ERROR;
328 }
329
330 std::shared_ptr<DlpFile> filePtr = nullptr;
331 std::string workDir;
332 int32_t result = EnterpriseSpacePrepareWorkDir(dlpFileFd, filePtr, workDir);
333 if (result != DLP_OK) {
334 DLP_LOG_ERROR(LABEL, "Enterprise space prepare workDir fail, errno=%{public}d", result);
335 return result;
336 }
337
338 result = EnterpriseSpaceParseDlpFileFormat(filePtr, true);
339 if (result != DLP_OK) {
340 DLP_LOG_ERROR(LABEL, "Open dlp file fail, parse dlp file error, errno=%{public}d", result);
341 return result;
342 }
343
344 result = DlpFileManager::GetInstance().RecoverDlpFile(filePtr, plainFileFd);
345 if (result != DLP_OK) {
346 DLP_LOG_ERROR(LABEL, "recover dlp file fail with enterprise space.");
347 }
348 return DLP_OK;
349 }
350
QueryDlpFileProperty(int32_t dlpFileFd,std::string & policyJsonString)351 int32_t EnterpriseSpaceDlpPermissionKit::QueryDlpFileProperty(int32_t dlpFileFd, std::string &policyJsonString)
352 {
353 DLP_LOG_INFO(LABEL, "Start query dlp file property from enterprise space service.");
354 if (dlpFileFd < 0) {
355 DLP_LOG_ERROR(LABEL, "Query dlp property fail, dlp file fd invalid");
356 return DLP_PARSE_ERROR_FD_ERROR;
357 }
358
359 std::shared_ptr<DlpFile> filePtr = nullptr;
360 std::string workDir;
361 int32_t result = EnterpriseSpacePrepareWorkDir(dlpFileFd, filePtr, workDir);
362 if (result != DLP_OK) {
363 DLP_LOG_ERROR(LABEL, "Enterprise space prepare workDir fail, errno=%{public}d", result);
364 return result;
365 }
366 PermissionPolicy policy;
367 result = EnterpriseSpaceParseDlpFileProperty(filePtr, policy, false);
368 if (result != DLP_OK) {
369 DLP_LOG_ERROR(LABEL, "Enterprise space parse dlp property fail, errno=%{public}d", result);
370 return result;
371 }
372 SerializePermissionPolicy(policy, policyJsonString);
373 return DLP_OK;
374 }
375
376 }
377 }
378 }
379