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