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 #define MLOG_TAG "ReadWritePermissionHandler"
17
18 #include "read_write_permission_handler.h"
19
20 #include <cstdlib>
21
22 #include "media_file_uri.h"
23 #include "media_file_utils.h"
24 #include "medialibrary_bundle_manager.h"
25 #include "medialibrary_rdbstore.h"
26 #include "rdb_utils.h"
27 #include "medialibrary_uripermission_operations.h"
28 #include "permission_utils.h"
29 #include "system_ability_definition.h"
30 #ifdef MEDIALIBRARY_SECURITY_OPEN
31 #include "sec_comp_kit.h"
32 #endif
33 #include "userfilemgr_uri.h"
34 #include "album_operation_uri.h"
35 #include "data_secondary_directory_uri.h"
36 #include "dfx_deprecated_perm_usage.h"
37 #include "mediatool_uri.h"
38
39 using namespace std;
40
41 namespace OHOS::Media {
42 static const set<OperationObject> PHOTO_ACCESS_HELPER_OBJECTS = {
43 OperationObject::PAH_PHOTO,
44 OperationObject::PAH_ALBUM,
45 OperationObject::PAH_MAP,
46 OperationObject::PAH_FORM_MAP,
47 OperationObject::ANALYSIS_PHOTO_ALBUM,
48 OperationObject::ANALYSIS_PHOTO_MAP,
49 OperationObject::VISION_OCR,
50 OperationObject::VISION_AESTHETICS,
51 OperationObject::VISION_VIDEO_AESTHETICS,
52 OperationObject::VISION_LABEL,
53 OperationObject::VISION_VIDEO_LABEL,
54 OperationObject::VISION_IMAGE_FACE,
55 OperationObject::VISION_VIDEO_FACE,
56 OperationObject::VISION_FACE_TAG,
57 OperationObject::VISION_OBJECT,
58 OperationObject::VISION_RECOMMENDATION,
59 OperationObject::VISION_SEGMENTATION,
60 OperationObject::VISION_COMPOSITION,
61 OperationObject::VISION_SALIENCY,
62 OperationObject::VISION_HEAD,
63 OperationObject::VISION_POSE,
64 OperationObject::VISION_TOTAL,
65 OperationObject::VISION_ANALYSIS_ALBUM_TOTAL,
66 OperationObject::GEO_DICTIONARY,
67 OperationObject::GEO_KNOWLEDGE,
68 OperationObject::GEO_PHOTO,
69 OperationObject::PAH_MULTISTAGES_CAPTURE,
70 OperationObject::STORY_ALBUM,
71 OperationObject::STORY_COVER,
72 OperationObject::HIGHLIGHT_DELETE,
73 OperationObject::STORY_PLAY,
74 OperationObject::USER_PHOTOGRAPHY,
75 OperationObject::PAH_BATCH_THUMBNAIL_OPERATE,
76 OperationObject::INDEX_CONSTRUCTION_STATUS,
77 OperationObject::MEDIA_APP_URI_PERMISSION,
78 OperationObject::PAH_CLOUD_ENHANCEMENT_OPERATE,
79 OperationObject::ANALYSIS_ASSET_SD_MAP,
80 OperationObject::ANALYSIS_ALBUM_ASSET_MAP,
81 OperationObject::CLOUD_MEDIA_ASSET_OPERATE,
82 OperationObject::ANALYSIS_ADDRESS,
83 OperationObject::TAB_FACARD_PHOTO,
84 };
85
86 std::string USER_STR = "user";
ContainsFlag(const string & mode,const char flag)87 static inline bool ContainsFlag(const string &mode, const char flag)
88 {
89 return mode.find(flag) != string::npos;
90 }
91
AcrossUserOperationPermCheck(MediaLibraryCommand & cmd)92 static int32_t AcrossUserOperationPermCheck(MediaLibraryCommand &cmd)
93 {
94 std::string user = cmd.GetQuerySetParam(USER_STR);
95 vector<string> perms;
96 if (user == "") {
97 return E_SUCCESS;
98 } else {
99 perms.push_back(PERM_INTERACT_ACROSS_LOCAL_ACCOUNTS);
100 }
101 return PermissionUtils::CheckCallerPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED;
102 }
103
SystemApiCheck(MediaLibraryCommand & cmd)104 static int32_t SystemApiCheck(MediaLibraryCommand &cmd)
105 {
106 static const set<OperationObject> SYSTEM_API_OBJECTS = {
107 OperationObject::UFM_PHOTO,
108 OperationObject::UFM_AUDIO,
109 OperationObject::UFM_ALBUM,
110 OperationObject::UFM_MAP,
111 OperationObject::SMART_ALBUM,
112 OperationObject::CUSTOM_RECORDS_OPERATION,
113
114 OperationObject::ALL_DEVICE,
115 OperationObject::ACTIVE_DEVICE,
116 OperationObject::PAH_FORM_MAP,
117 };
118
119 static const set<string> SYSTEM_API_URIS = {
120 // Deleting asset permanently from system is only allowed for system apps.
121 URI_DELETE_PHOTOS,
122 // Deleting asset to trash album directly without a pop-up box is only allowed for system apps.
123 UFM_DELETE_PHOTOS,
124 PAH_DELETE_PHOTOS,
125 };
126
127 OperationObject obj = cmd.GetOprnObject();
128 string uri = cmd.GetUriStringWithoutSegment();
129 if (SYSTEM_API_OBJECTS.find(obj) != SYSTEM_API_OBJECTS.end() ||
130 (SYSTEM_API_URIS.find(uri) != SYSTEM_API_URIS.end())) {
131 if (!PermissionUtils::IsSystemApp()) {
132 MEDIA_ERR_LOG("Systemapi should only be called by system applications!");
133 return -E_CHECK_SYSTEMAPP_FAIL;
134 }
135 }
136 return E_SUCCESS;
137 }
138
AddHiddenAlbumPermission(MediaLibraryCommand & cmd,vector<string> & outPerms)139 static inline void AddHiddenAlbumPermission(MediaLibraryCommand &cmd, vector<string> &outPerms)
140 {
141 Media::OperationType type = cmd.GetOprnType();
142 if (type == Media::OperationType::QUERY_HIDDEN) {
143 outPerms.push_back(PERM_MANAGE_PRIVATE_PHOTOS);
144 }
145 }
146
HandleSecurityComponentPermission(MediaLibraryCommand & cmd)147 static int32_t HandleSecurityComponentPermission(MediaLibraryCommand &cmd)
148 {
149 if (cmd.GetUri().ToString().find(OPRN_CREATE_COMPONENT) != string::npos ||
150 cmd.GetUri().ToString().find(OPRN_SAVE_CAMERA_PHOTO_COMPONENT) != string::npos) {
151 #ifdef MEDIALIBRARY_SECURITY_OPEN
152 auto tokenId = PermissionUtils::GetTokenId();
153 if (!Security::SecurityComponent::SecCompKit::VerifySavePermission(tokenId)) {
154 MEDIA_ERR_LOG("Failed to verify save permission of security component");
155 return E_NEED_FURTHER_CHECK;
156 }
157 return E_SUCCESS;
158 #else
159 MEDIA_ERR_LOG("Security component is not existed");
160 return E_NEED_FURTHER_CHECK;
161 #endif
162 }
163 return E_NEED_FURTHER_CHECK;
164 }
165
166
UnifyOprnObject(MediaLibraryCommand & cmd)167 static void UnifyOprnObject(MediaLibraryCommand &cmd)
168 {
169 static const unordered_map<OperationObject, OperationObject> UNIFY_OP_OBJECT_MAP = {
170 { OperationObject::UFM_PHOTO, OperationObject::FILESYSTEM_PHOTO },
171 { OperationObject::UFM_AUDIO, OperationObject::FILESYSTEM_AUDIO },
172 { OperationObject::UFM_ALBUM, OperationObject::PHOTO_ALBUM },
173 { OperationObject::UFM_MAP, OperationObject::PHOTO_MAP },
174 { OperationObject::PAH_PHOTO, OperationObject::FILESYSTEM_PHOTO },
175 { OperationObject::PAH_ALBUM, OperationObject::PHOTO_ALBUM },
176 { OperationObject::PAH_MAP, OperationObject::PHOTO_MAP },
177 { OperationObject::TOOL_PHOTO, OperationObject::FILESYSTEM_PHOTO },
178 { OperationObject::TOOL_AUDIO, OperationObject::FILESYSTEM_AUDIO },
179 { OperationObject::TOOL_ALBUM, OperationObject::PHOTO_ALBUM },
180 };
181
182 OperationObject obj = cmd.GetOprnObject();
183 if (UNIFY_OP_OBJECT_MAP.find(obj) != UNIFY_OP_OBJECT_MAP.end()) {
184 cmd.SetOprnObject(UNIFY_OP_OBJECT_MAP.at(obj));
185 }
186 }
187
PhotoAccessHelperPermCheck(MediaLibraryCommand & cmd,const bool isWrite)188 static int32_t PhotoAccessHelperPermCheck(MediaLibraryCommand &cmd, const bool isWrite)
189 {
190 int32_t err = HandleSecurityComponentPermission(cmd);
191 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
192 return err;
193 }
194
195 OperationObject obj = cmd.GetOprnObject();
196 if (PHOTO_ACCESS_HELPER_OBJECTS.find(obj) == PHOTO_ACCESS_HELPER_OBJECTS.end()) {
197 return E_NEED_FURTHER_CHECK;
198 }
199 vector<string> perms;
200 AddHiddenAlbumPermission(cmd, perms);
201 perms.push_back(isWrite ? PERM_WRITE_IMAGEVIDEO : PERM_READ_IMAGEVIDEO);
202 return PermissionUtils::CheckCallerPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED;
203 }
204
UserFileMgrPermissionCheck(MediaLibraryCommand & cmd,const bool isWrite)205 static int32_t UserFileMgrPermissionCheck(MediaLibraryCommand &cmd, const bool isWrite)
206 {
207 static const set<OperationObject> USER_FILE_MGR_OBJECTS = {
208 OperationObject::UFM_PHOTO,
209 OperationObject::UFM_AUDIO,
210 OperationObject::UFM_ALBUM,
211 OperationObject::UFM_MAP,
212 };
213
214 OperationObject obj = cmd.GetOprnObject();
215 if (USER_FILE_MGR_OBJECTS.find(obj) == USER_FILE_MGR_OBJECTS.end()) {
216 return E_NEED_FURTHER_CHECK;
217 }
218
219 int32_t err = HandleSecurityComponentPermission(cmd);
220 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
221 return err;
222 }
223
224 vector<string> perms;
225 if (obj == OperationObject::UFM_AUDIO) {
226 perms.push_back(isWrite ? PERM_WRITE_AUDIO : PERM_READ_AUDIO);
227 } else {
228 perms.push_back(isWrite ? PERM_WRITE_IMAGEVIDEO : PERM_READ_IMAGEVIDEO);
229 }
230 AddHiddenAlbumPermission(cmd, perms);
231 return PermissionUtils::CheckCallerPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED;
232 }
233
HandleBundlePermCheck(const MediaLibraryCommand & cmd)234 static inline int32_t HandleBundlePermCheck(const MediaLibraryCommand &cmd)
235 {
236 bool ret = PermissionUtils::CheckCallerPermission(PERMISSION_NAME_WRITE_MEDIA);
237 if (ret) {
238 DfxDeprecatedPermUsage::Record(
239 static_cast<uint32_t>(cmd.GetOprnObject()), static_cast<uint32_t>(cmd.GetOprnType()));
240 return E_SUCCESS;
241 }
242
243 return PermissionUtils::CheckHasPermission(WRITE_PERMS_V10) ? E_SUCCESS : E_PERMISSION_DENIED;
244 }
245
HandleNoPermCheck(MediaLibraryCommand & cmd)246 static int32_t HandleNoPermCheck(MediaLibraryCommand &cmd)
247 {
248 static const set<string> NO_NEED_PERM_CHECK_URI = {
249 URI_CLOSE_FILE,
250 MEDIALIBRARY_DIRECTORY_URI,
251 };
252
253 static const set<OperationObject> NO_NEED_PERM_CHECK_OBJ = {
254 OperationObject::ALL_DEVICE,
255 OperationObject::ACTIVE_DEVICE,
256 OperationObject::MISCELLANEOUS,
257 OperationObject::TAB_OLD_PHOTO,
258 OperationObject::CONVERT_PHOTO,
259 OperationObject::CUSTOM_RECORDS_OPERATION,
260 };
261
262 string uri = cmd.GetUri().ToString();
263 OperationObject obj = cmd.GetOprnObject();
264 if (NO_NEED_PERM_CHECK_URI.find(uri) != NO_NEED_PERM_CHECK_URI.end() ||
265 NO_NEED_PERM_CHECK_OBJ.find(obj) != NO_NEED_PERM_CHECK_OBJ.end()) {
266 return E_SUCCESS;
267 }
268 return E_NEED_FURTHER_CHECK;
269 }
270
HandleMediaVolumePerm(const MediaLibraryCommand & cmd)271 static inline int32_t HandleMediaVolumePerm(const MediaLibraryCommand &cmd)
272 {
273 bool ret = PermissionUtils::CheckCallerPermission(PERMISSION_NAME_READ_MEDIA);
274 CHECK_AND_EXECUTE(!ret,
275 DfxDeprecatedPermUsage::Record(
276 static_cast<uint32_t>(cmd.GetOprnObject()), static_cast<uint32_t>(cmd.GetOprnType())));
277 return ret ? E_SUCCESS : E_PERMISSION_DENIED;
278 }
279
HandleSpecialObjectPermission(MediaLibraryCommand & cmd,bool isWrite)280 static int32_t HandleSpecialObjectPermission(MediaLibraryCommand &cmd, bool isWrite)
281 {
282 int err = HandleNoPermCheck(cmd);
283 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
284 return err;
285 }
286
287 OperationObject obj = cmd.GetOprnObject();
288 if (obj == OperationObject::MEDIA_VOLUME) {
289 return HandleMediaVolumePerm(cmd);
290 } else if (obj == OperationObject::BUNDLE_PERMISSION) {
291 return HandleBundlePermCheck(cmd);
292 }
293
294 if (MediaFileUtils::IsCalledBySelf() == E_OK) {
295 return E_SUCCESS;
296 }
297
298 return E_NEED_FURTHER_CHECK;
299 }
300
CheckPermFromUri(MediaLibraryCommand & cmd,bool isWrite)301 static int32_t CheckPermFromUri(MediaLibraryCommand &cmd, bool isWrite)
302 {
303 MEDIA_DEBUG_LOG("uri: %{private}s object: %{public}d, opType: %{public}d isWrite: %{public}d",
304 cmd.GetUri().ToString().c_str(), cmd.GetOprnObject(), cmd.GetOprnType(), isWrite);
305
306 int err = AcrossUserOperationPermCheck(cmd);
307 if (err != E_SUCCESS) {
308 return err;
309 }
310
311 err = SystemApiCheck(cmd);
312 if (err != E_SUCCESS) {
313 return err;
314 }
315 err = PhotoAccessHelperPermCheck(cmd, isWrite);
316 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
317 UnifyOprnObject(cmd);
318 return err;
319 }
320 err = UserFileMgrPermissionCheck(cmd, isWrite);
321 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
322 UnifyOprnObject(cmd);
323 return err;
324 }
325 err = HandleSpecialObjectPermission(cmd, isWrite);
326 if (err == E_SUCCESS || (err != E_SUCCESS && err != E_NEED_FURTHER_CHECK)) {
327 UnifyOprnObject(cmd);
328 return err;
329 }
330
331 string perm = isWrite ? PERM_WRITE_IMAGEVIDEO : PERM_READ_IMAGEVIDEO;
332 if (!PermissionUtils::CheckCallerPermission(perm)) {
333 perm = isWrite ? PERMISSION_NAME_WRITE_MEDIA : PERMISSION_NAME_READ_MEDIA;
334 if (!PermissionUtils::CheckCallerPermission(perm)) {
335 return E_PERMISSION_DENIED;
336 }
337 DfxDeprecatedPermUsage::Record(
338 static_cast<uint32_t>(cmd.GetOprnObject()), static_cast<uint32_t>(cmd.GetOprnType()));
339 }
340 UnifyOprnObject(cmd);
341 return E_SUCCESS;
342 }
343
FillV10Perms(const MediaType mediaType,const bool containsRead,const bool containsWrite,vector<string> & perm)344 static void FillV10Perms(const MediaType mediaType, const bool containsRead, const bool containsWrite,
345 vector<string> &perm)
346 {
347 if (containsRead) {
348 if (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO ||
349 mediaType == Media::MEDIA_TYPE_PHOTO || mediaType == Media::MEDIA_TYPE_ALBUM) {
350 perm.push_back(PERM_READ_IMAGEVIDEO);
351 } else if (mediaType == MEDIA_TYPE_AUDIO) {
352 perm.push_back(PERM_READ_AUDIO);
353 } else if (mediaType == MEDIA_TYPE_FILE) {
354 perm.push_back(PERM_READ_IMAGEVIDEO);
355 perm.push_back(PERM_READ_AUDIO);
356 perm.push_back(PERM_READ_DOCUMENT);
357 }
358 }
359 if (containsWrite) {
360 if (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO ||
361 mediaType == Media::MEDIA_TYPE_PHOTO || mediaType == Media::MEDIA_TYPE_ALBUM) {
362 perm.push_back(PERM_WRITE_IMAGEVIDEO);
363 } else if (mediaType == MEDIA_TYPE_AUDIO) {
364 perm.push_back(PERM_WRITE_AUDIO);
365 } else if (mediaType == MEDIA_TYPE_FILE) {
366 perm.push_back(PERM_WRITE_IMAGEVIDEO);
367 perm.push_back(PERM_WRITE_AUDIO);
368 perm.push_back(PERM_WRITE_DOCUMENT);
369 }
370 }
371 }
372
CheckOpenFilePermission(MediaLibraryCommand & cmd,PermParam & permParam)373 static int32_t CheckOpenFilePermission(MediaLibraryCommand &cmd, PermParam &permParam)
374 {
375 MEDIA_DEBUG_LOG("uri: %{private}s mode: %{private}s",
376 cmd.GetUri().ToString().c_str(), permParam.openFileNode.c_str());
377 if (MediaFileUtils::IsCalledBySelf() == E_OK) {
378 return E_SUCCESS;
379 }
380 MediaType mediaType = MediaFileUri::GetMediaTypeFromUri(cmd.GetUri().ToString());
381 const bool containsRead = ContainsFlag(permParam.openFileNode, 'r');
382 const bool containsWrite = ContainsFlag(permParam.openFileNode, 'w');
383 vector<string> perms;
384 FillV10Perms(mediaType, containsRead, containsWrite, perms);
385 if ((cmd.GetOprnObject() == OperationObject::FILESYSTEM_PHOTO) ||
386 (cmd.GetOprnObject() == OperationObject::THUMBNAIL) ||
387 (cmd.GetOprnObject() == OperationObject::THUMBNAIL_ASTC)) {
388 return PermissionUtils::CheckPhotoCallerPermission(perms)? E_SUCCESS : E_PERMISSION_DENIED;
389 }
390 int32_t err = (mediaType == MEDIA_TYPE_FILE) ?
391 (PermissionUtils::CheckHasPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED) :
392 (PermissionUtils::CheckCallerPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED);
393 if (err == E_SUCCESS) {
394 return E_SUCCESS;
395 }
396 perms.clear();
397 if (containsRead) {
398 perms.push_back(PERM_READ_IMAGEVIDEO);
399 }
400 if (containsWrite) {
401 perms.push_back(PERM_WRITE_IMAGEVIDEO);
402 }
403 return PermissionUtils::CheckCallerPermission(perms) ? E_SUCCESS : E_PERMISSION_DENIED;
404 }
405
ExecuteCheckPermission(MediaLibraryCommand & cmd,PermParam & permParam)406 int32_t ReadWritePermissionHandler::ExecuteCheckPermission(MediaLibraryCommand &cmd, PermParam &permParam)
407 {
408 MEDIA_DEBUG_LOG("ReadWritePermissionHandler:isOpenFile=%{public}d", permParam.isOpenFile);
409 if (permParam.isOpenFile) {
410 int err = AcrossUserOperationPermCheck(cmd);
411 if (err != E_SUCCESS) {
412 return err;
413 }
414 permParam.isWrite = ContainsFlag(permParam.openFileNode, 'w');
415 return CheckOpenFilePermission(cmd, permParam);
416 }
417 return CheckPermFromUri(cmd, permParam.isWrite);
418 }
419
420 } // namespace name