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