1 /*
2 * Copyright (c) 2023-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 "dlp_file_kits.h"
17 #include <cstdlib>
18 #include <fcntl.h>
19 #include <string>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <unordered_map>
24 #include "dlp_file.h"
25 #include "dlp_permission_log.h"
26 #include "dlp_zip.h"
27 #include "file_uri.h"
28 #include "securec.h"
29 #include "dlp_utils.h"
30 #include "dlp_permission.h"
31
32 namespace OHOS {
33 namespace Security {
34 namespace DlpPermission {
35 namespace {
36 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpFileKits"};
37 static const std::string FILE_SCHEME_PREFIX = "file://";
38 static const std::string DEFAULT_STRINGS = "";
39 static const uint32_t BYTE_TO_HEX_OPER_LENGTH = 2;
40 static const uint32_t CURRENT_VERSION = 3;
41 static const uint32_t FILE_HEAD = 8;
42 static const uint32_t HMAC_SIZE = 32;
43 } // namespace
44 using Want = OHOS::AAFwk::Want;
45 using WantParams = OHOS::AAFwk::WantParams;
46
47 static const std::unordered_map<std::string, std::string> SUFFIX_MIMETYPE_MAP = {
48 {"txt", "text/plain"},
49 {"doc", "application/msword"},
50 {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
51 {"pdf", "application/pdf"},
52 {"ppt", "application/vnd.ms-powerpoint"},
53 {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
54 {"xls", "application/vnd.ms-excel"},
55 {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
56 {"bmp", "image/bmp"},
57 {"bm", "image/bmp"},
58 {"dng", "image/x-adobe-dng"},
59 {"gif", "image/gif"},
60 {"heic", "image/heic"},
61 {"heics", "image/heic"},
62 {"heif", "image/heif"},
63 {"heifs", "image/heif"},
64 {"hif", "image/heif"},
65 {"jpg", "image/jpeg"},
66 {"jpeg", "image/jpeg"},
67 {"jpe", "image/jpeg"},
68 {"png", "image/png"},
69 {"webp", "image/webp"},
70 {"cur", "image/ico"},
71 {"raf", "image/x-fuji-raf"},
72 {"ico", "image/x-icon"},
73 {"nrw", "image/x-nikon-nrw"},
74 {"rw2", "image/x-panasonic-raw"},
75 {"pef", "image/x-pentax-pef"},
76 {"srw", "image/x-samsung-srw"},
77 {"svg", "image/svg+xml"},
78 {"arw", "image/x-sony-arw"},
79 {"3gpp2", "video/3gpp2"},
80 {"3gp2", "video/3gpp2"},
81 {"3g2", "video/3gpp2"},
82 {"3gpp", "video/3gpp"},
83 {"3gp", "video/3gpp"},
84 {"avi", "video/avi"},
85 {"m4v", "video/mp4"},
86 {"f4v", "video/mp4"},
87 {"mp4v", "video/mp4"},
88 {"mpeg4", "video/mp4"},
89 {"mp4", "video/mp4"},
90 {"m2ts", "video/mp2t"},
91 {"mts", "video/mp2t"},
92 {"ts", "video/mp2ts"},
93 {"vt", "video/vnd.youtube.yt"},
94 {"wrf", "video/x-webex"},
95 {"mpeg", "video/mpeg"},
96 {"mpeg2", "video/mpeg"},
97 {"mpv2", "video/mpeg"},
98 {"mp2v", "video/mpeg"},
99 {"m2v", "video/mpeg"},
100 {"m2t", "video/mpeg"},
101 {"mpeg1", "video/mpeg"},
102 {"mpv1", "video/mpeg"},
103 {"mp1v", "video/mpeg"},
104 {"m1v", "video/mpeg"},
105 {"mpg", "video/mpeg"},
106 {"mov", "video/quicktime"},
107 {"mkv", "video/x-matroska"},
108 {"webm", "video/webm"},
109 {"h264", "video/H264"},
110 {"wbmp", "image/vnd.wap.wbmp"},
111 {"nef", "image/x-nikon-nef"},
112 {"cr2", "image/x-canon-cr2"},
113 };
114
IsDlpFileName(const std::string & dlpFileName)115 static bool IsDlpFileName(const std::string& dlpFileName)
116 {
117 uint32_t dlpSuffixLen = DLP_FILE_SUFFIX.size();
118 uint32_t fileNameLen = dlpFileName.size();
119 if (fileNameLen < dlpSuffixLen) {
120 return false;
121 }
122
123 std::string fileSuffix = dlpFileName.substr(fileNameLen - dlpSuffixLen, dlpSuffixLen);
124 if (DlpUtils::ToLowerString(fileSuffix) != DLP_FILE_SUFFIX) {
125 return false;
126 }
127 return true;
128 }
129
GetMimeTypeBySuffix(const std::string & suffix)130 static std::string GetMimeTypeBySuffix(const std::string& suffix)
131 {
132 std::string lower = DlpUtils::ToLowerString(suffix);
133 for (size_t len = MAX_REALY_TYPE_LENGTH; len >= MIN_REALY_TYPE_LENGTH; len--) {
134 if (len > lower.size()) {
135 continue;
136 }
137 std::string newStr = lower.substr(0, len);
138 auto iter = SUFFIX_MIMETYPE_MAP.find(newStr);
139 if (iter != SUFFIX_MIMETYPE_MAP.end()) {
140 return iter->second;
141 }
142 }
143 return DEFAULT_STRING;
144 }
145
IsValidDlpHeader(const struct DlpHeader & head)146 static bool IsValidDlpHeader(const struct DlpHeader& head)
147 {
148 if (head.magic != DLP_FILE_MAGIC || head.certSize == 0 || head.certSize > DLP_MAX_CERT_SIZE ||
149 head.contactAccountSize == 0 || head.contactAccountSize > DLP_MAX_CERT_SIZE ||
150 head.contactAccountOffset != sizeof(struct DlpHeader) + FILE_HEAD ||
151 head.txtOffset != head.contactAccountOffset + head.contactAccountSize ||
152 head.txtSize > DLP_MAX_CONTENT_SIZE || head.hmacOffset != head.txtOffset + head.txtSize ||
153 head.hmacSize != HMAC_SIZE * BYTE_TO_HEX_OPER_LENGTH || head.offlineCertSize > DLP_MAX_CERT_SIZE ||
154 !(head.certOffset == head.txtOffset || head.certOffset == head.hmacOffset + head.hmacSize)) {
155 DLP_LOG_ERROR(LABEL, "Parse dlp file header error.");
156 return false;
157 }
158 return true;
159 }
160
IsDlpFile(int32_t dlpFd)161 bool DlpFileKits::IsDlpFile(int32_t dlpFd)
162 {
163 if (dlpFd < 0) {
164 DLP_LOG_ERROR(LABEL, "dlp file fd is invalid");
165 return false;
166 }
167
168 if (IsZipFile(dlpFd)) {
169 return CheckUnzipFileInfo(dlpFd);
170 }
171
172 off_t curPos = lseek(dlpFd, 0, SEEK_CUR);
173 if (curPos < 0) {
174 DLP_LOG_ERROR(LABEL, "seek dlp file current failed, %{public}s", strerror(errno));
175 return false;
176 }
177
178 if (lseek(dlpFd, 0, SEEK_SET) == static_cast<off_t>(-1)) {
179 DLP_LOG_ERROR(LABEL, "seek dlp file start failed, %{public}s", strerror(errno));
180 return false;
181 }
182
183 uint32_t version = 0;
184 if (read(dlpFd, &version, sizeof(uint32_t)) != sizeof(uint32_t)) {
185 DLP_LOG_ERROR(LABEL, "can not read version, %{public}s", strerror(errno));
186 return false;
187 }
188
189 uint32_t dlpHeaderSize = 0;
190 if (read(dlpFd, &dlpHeaderSize, sizeof(uint32_t)) != sizeof(uint32_t)) {
191 DLP_LOG_ERROR(LABEL, "can not read dlpHeaderSize, %{public}s", strerror(errno));
192 return false;
193 }
194 if (version != CURRENT_VERSION || dlpHeaderSize != sizeof(struct DlpHeader)) {
195 DLP_LOG_ERROR(LABEL, "version or dlpHeaderSize is error");
196 return false;
197 }
198
199 struct DlpHeader head;
200 if (read(dlpFd, &head, sizeof(struct DlpHeader)) != sizeof(struct DlpHeader)) {
201 DLP_LOG_ERROR(LABEL, "can not read dlp file head, %{public}s", strerror(errno));
202 return false;
203 }
204
205 if (lseek(dlpFd, curPos, SEEK_SET) < 0) {
206 DLP_LOG_ERROR(LABEL, "seek dlp file back failed, %{public}s", strerror(errno));
207 return false;
208 }
209
210 return IsValidDlpHeader(head);
211 }
212
GetSandboxFlag(Want & want)213 bool DlpFileKits::GetSandboxFlag(Want& want)
214 {
215 std::string action = want.GetAction();
216 if (!action.empty() && action != TAG_ACTION_VIEW && action != TAG_ACTION_EDIT) {
217 DLP_LOG_DEBUG(LABEL, "Action %{public}s is not dlp scene", action.c_str());
218 return false;
219 }
220
221 std::string uri = want.GetUriString();
222 if (uri.find(FILE_SCHEME_PREFIX) != 0) {
223 DLP_LOG_DEBUG(LABEL, "uri is missing file://");
224 return false;
225 }
226 AppFileService::ModuleFileUri::FileUri fileUri(uri);
227 std::string fileName = fileUri.GetName();
228 if (fileName.empty() || !IsDlpFileName(fileName)) {
229 DLP_LOG_DEBUG(LABEL, "File name is not exist or not dlp, name=%{private}s", fileName.c_str());
230 return false;
231 }
232 std::string path = fileUri.GetRealPath();
233 int fd = open(path.c_str(), O_RDONLY);
234 if (fd == -1) {
235 DLP_LOG_ERROR(LABEL, "open file error, error=%{public}d", errno);
236 return false;
237 }
238 if (!IsDlpFile(fd)) {
239 DLP_LOG_WARN(LABEL, "Fd %{public}d is not dlp file", fd);
240 }
241 bool isFromUriName = false;
242 std::string realSuffix = DlpUtils::GetRealTypeWithFd(fd, isFromUriName);
243 if (realSuffix != DEFAULT_STRING) {
244 DLP_LOG_DEBUG(LABEL, "Real suffix is %{public}s", realSuffix.c_str());
245 std::string realType = GetMimeTypeBySuffix(realSuffix);
246 if (realType != DEFAULT_STRING) {
247 want.SetType(realType);
248 } else {
249 DLP_LOG_INFO(LABEL, "Real suffix %{public}s not match known type, using origin type %{public}s",
250 realSuffix.c_str(), want.GetType().c_str());
251 }
252 }
253 close(fd);
254 fd = -1;
255 DLP_LOG_INFO(LABEL, "Sanbox flag is true");
256 return true;
257 }
258
ConvertAbilityInfoWithBundleName(const std::string & abilityName,const std::string & bundleName,std::vector<AppExecFwk::AbilityInfo> & abilityInfos)259 static int32_t ConvertAbilityInfoWithBundleName(const std::string &abilityName, const std::string &bundleName,
260 std::vector<AppExecFwk::AbilityInfo> &abilityInfos)
261 {
262 Want want;
263 AppExecFwk::ElementName name;
264 name.SetAbilityName(abilityName);
265 name.SetBundleName(bundleName);
266 want.SetElement(name);
267
268 int32_t flags = static_cast<int32_t>(AppExecFwk::GetAbilityInfoFlag::GET_ABILITY_INFO_DEFAULT);
269 int32_t userId = 0;
270 int32_t ret = AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(userId);
271 if (ret != ERR_OK) {
272 DLP_LOG_ERROR(LABEL, "Get os account localId error, %{public}d", ret);
273 return DLP_PARSE_ERROR_GET_ACCOUNT_FAIL;
274 }
275
276 auto bundleMgrProxy = DlpUtils::GetBundleMgrProxy();
277 if (bundleMgrProxy == nullptr) {
278 return DLP_SERVICE_ERROR_IPC_REQUEST_FAIL;
279 }
280 ret = bundleMgrProxy->QueryAbilityInfosV9(want, flags, userId, abilityInfos);
281 if (ret != ERR_OK) {
282 DLP_LOG_ERROR(LABEL, "Get ability info error, %{public}d", ret);
283 return DLP_PARSE_ERROR_BMS_ERROR;
284 }
285 return DLP_OK;
286 }
287
IsSupportDlp(const std::vector<std::string> & authPolicy,const std::string & bundleName)288 static bool IsSupportDlp(const std::vector<std::string> &authPolicy, const std::string &bundleName)
289 {
290 auto it = std::find(authPolicy.begin(), authPolicy.end(), bundleName);
291 if (it != authPolicy.end()) {
292 return true;
293 }
294 return false;
295 }
296
GetRealFileType(const AAFwk::Want & want)297 static std::string GetRealFileType(const AAFwk::Want &want)
298 {
299 std::string uri = want.GetUriString();
300 if (uri.find(FILE_SCHEME_PREFIX) != 0) {
301 DLP_LOG_DEBUG(LABEL, "uri is missing file://");
302 return DEFAULT_STRINGS;
303 }
304 AppFileService::ModuleFileUri::FileUri fileUri(uri);
305 std::string fileName = fileUri.GetName();
306 if (fileName.empty() || !IsDlpFileName(fileName)) {
307 DLP_LOG_ERROR(LABEL, "File name is not exist or not dlp, name=%{private}s", fileName.c_str());
308 return DEFAULT_STRINGS;
309 }
310
311 std::string realMimeType = want.GetType();
312 if (realMimeType == DEFAULT_STRING) {
313 DLP_LOG_ERROR(LABEL, "get real mime mype error.");
314 return DEFAULT_STRINGS;
315 }
316
317 std::string realSuffix = DEFAULT_STRING;
318 for (const auto& p : SUFFIX_MIMETYPE_MAP) {
319 if (p.second == realMimeType) {
320 realSuffix = p.first;
321 break;
322 }
323 }
324 std::string fileType = DlpUtils::GetFileTypeBySuffix(realSuffix, false);
325 if (fileType == DEFAULT_STRING) {
326 DLP_LOG_ERROR(LABEL, "%{public}s is not support dlp.", realSuffix.c_str());
327 }
328 return fileType;
329 }
330
ConvertAbilityInfoWithSupportDlp(const AAFwk::Want & want,std::vector<AppExecFwk::AbilityInfo> & abilityInfos)331 void DlpFileKits::ConvertAbilityInfoWithSupportDlp(const AAFwk::Want &want,
332 std::vector<AppExecFwk::AbilityInfo> &abilityInfos)
333 {
334 std::string fileType = GetRealFileType(want);
335 if (fileType == DEFAULT_STRING) {
336 return;
337 }
338
339 std::vector<std::string> authPolicy;
340 if (!DlpUtils::GetAuthPolicyWithType(DLP_AUTH_POLICY, fileType, authPolicy)) {
341 return;
342 }
343
344 for (auto it = abilityInfos.begin(); it != abilityInfos.end();) {
345 if (!IsSupportDlp(authPolicy, it->bundleName)) {
346 abilityInfos.erase(it);
347 } else {
348 ++it;
349 }
350 }
351
352 if (abilityInfos.size() != 0) {
353 return;
354 }
355 std::vector<std::string> defalutAuthPolicy;
356 if (!DlpUtils::GetAuthPolicyWithType(DLP_AUTH_POLICY, DLP_DEFAULT_AUTH_POLICY, defalutAuthPolicy) ||
357 defalutAuthPolicy.size() <= 1) {
358 return;
359 }
360 int32_t ret = ConvertAbilityInfoWithBundleName(defalutAuthPolicy[0], defalutAuthPolicy[1], abilityInfos);
361 if (ret != DLP_OK) {
362 DLP_LOG_ERROR(LABEL, "Query ability info with bundleName error.");
363 }
364 }
365
IsDlpFileBySuffix(const std::string & fileSuffix)366 bool DlpFileKits::IsDlpFileBySuffix(const std::string &fileSuffix)
367 {
368 std::string lowerFileSuffix = DlpUtils::ToLowerString(fileSuffix);
369 if (lowerFileSuffix != DLP_FILE_SUFFIX) {
370 DLP_LOG_DEBUG(LABEL, "%{public}s is not dlp file suffix", lowerFileSuffix.c_str());
371 return false;
372 }
373 return true;
374 }
375 } // namespace DlpPermission
376 } // namespace Security
377 } // namespace OHOS
378