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 "DbPermissionHandler"
17
18 #include "db_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 "medialibrary_type_const.h"
30 #include "medialibrary_data_manager.h"
31 #include "media_column.h"
32
33 using namespace std;
34 using namespace OHOS::RdbDataShareAdapter;
35
36 namespace OHOS::Media {
37 static set<int> readPermSet{0, 1, 3, 4};
38
39 static set<int> writePermSet{2, 3, 4};
40 static const string UFM_PHOTO_PREFIX = "datashare:///media/userfilemgr_photo_operation";
41 static const string UFM_AUDIO_PREFIX = "datashare:///media/userfilemgr_audio_operation";
42 static const string PATH_PHOTO_PREFIX = "datashare:///media/phaccess_photo_operation";
43
ParseFileIdFromPredicates(const DataShare::DataSharePredicates & predicates,string & fileId)44 static bool ParseFileIdFromPredicates(const DataShare::DataSharePredicates &predicates, string &fileId)
45 {
46 // parse fileId from operationList
47 constexpr int32_t FIELD_IDX = 0;
48 constexpr int32_t VALUE_IDX = 1;
49 constexpr int32_t OPERATION_SIZE = 2;
50 auto operationItems = predicates.GetOperationList();
51 for (DataShare::OperationItem item : operationItems) {
52 if (item.singleParams.size() < OPERATION_SIZE) {
53 continue;
54 }
55 if (!MediaLibraryDataManagerUtils::IsNumber(static_cast<string>(item.GetSingle(VALUE_IDX)))) {
56 continue;
57 }
58 if (static_cast<string>(item.GetSingle(FIELD_IDX)) == MediaColumn::MEDIA_ID) {
59 fileId = static_cast<string>(item.GetSingle(VALUE_IDX));
60 return true;
61 }
62 }
63
64 // parse fileId from whereClause
65 const string &clause = predicates.GetWhereClause();
66 const vector<string> &values = predicates.GetWhereArgs();
67 size_t pos = clause.find(MediaColumn::MEDIA_ID);
68 if (pos == string::npos) {
69 MEDIA_ERR_LOG("whereClause not include fileId");
70 return false;
71 }
72 size_t argIndex = 0;
73 constexpr char placeholder = '?';
74 for (size_t i = 0; i < pos; ++i) {
75 if (clause[i] == placeholder) {
76 ++argIndex;
77 }
78 }
79 if (argIndex >= values.size()) {
80 MEDIA_ERR_LOG("argIndex should less than values size");
81 return false;
82 }
83 fileId = values[argIndex];
84 if (!MediaLibraryDataManagerUtils::IsNumber(fileId)) {
85 MEDIA_ERR_LOG("whereArgs fileId=%{public}s is not num", fileId.c_str());
86 return false;
87 }
88 return true;
89 }
90
ParseInfoFromCmd(MediaLibraryCommand & cmd,string & fileId,int32_t & uriType)91 static bool ParseInfoFromCmd(MediaLibraryCommand &cmd, string &fileId, int32_t &uriType)
92 {
93 string cmdUri = cmd.GetUri().ToString();
94 if (MediaFileUtils::StartsWith(cmdUri, PhotoColumn::PHOTO_URI_PREFIX)) {
95 uriType = static_cast<int32_t>(TableType::TYPE_PHOTOS);
96 fileId = MediaFileUtils::GetIdFromUri(cmdUri);
97 return true;
98 }
99 if (MediaFileUtils::StartsWith(cmdUri, AudioColumn::AUDIO_URI_PREFIX)) {
100 uriType = static_cast<int32_t>(TableType::TYPE_AUDIOS);
101 fileId = MediaFileUtils::GetIdFromUri(cmdUri);
102 return true;
103 }
104
105 if (cmd.IsDataSharePredNull()) {
106 MEDIA_DEBUG_LOG("DataSharePred is nullptr");
107 return false;
108 }
109 bool isPhotoType = MediaFileUtils::StartsWith(cmdUri, UFM_PHOTO_PREFIX)
110 || MediaFileUtils::StartsWith(cmdUri, PATH_PHOTO_PREFIX);
111 if (isPhotoType) {
112 uriType = static_cast<int32_t>(TableType::TYPE_PHOTOS);
113 return ParseFileIdFromPredicates(cmd.GetDataSharePred(), fileId);
114 }
115 if (MediaFileUtils::StartsWith(cmdUri, UFM_AUDIO_PREFIX)) {
116 uriType = static_cast<int32_t>(TableType::TYPE_AUDIOS);
117 return ParseFileIdFromPredicates(cmd.GetDataSharePred(), fileId);
118 }
119 MEDIA_ERR_LOG("parse fileId and uriType from cmd fail");
120 return false;
121 }
122
ExecuteCheckPermission(MediaLibraryCommand & cmd,PermParam & permParam)123 int32_t DbPermissionHandler::ExecuteCheckPermission(MediaLibraryCommand &cmd, PermParam &permParam)
124 {
125 MEDIA_DEBUG_LOG("DbPermissionHandler enter");
126 bool isWrite = permParam.isWrite;
127 string appId = GetClientAppId();
128 string fileId = "";
129 int32_t uriType = 0;
130 if (!ParseInfoFromCmd(cmd, fileId, uriType)) {
131 return E_INVALID_URI;
132 }
133 MEDIA_DEBUG_LOG("isWrite=%{public}d,appId=%{public}s,fileId=%{public}s,uriType=%{public}d",
134 isWrite, appId.c_str(), fileId.c_str(), uriType);
135 if (appId.empty() || fileId.empty()) {
136 MEDIA_ERR_LOG("invalid input");
137 return E_INVALID_FILEID;
138 }
139 DataShare::DataSharePredicates predicates;
140 predicates.SetWhereClause("file_id = ? and appid = ? and uri_type = ?");
141 predicates.SetWhereArgs({fileId, appId, to_string(uriType)});
142 vector<string> columns;
143 auto queryResultSet =
144 MediaLibraryRdbStore::QueryWithFilter(RdbUtils::ToPredicates(predicates, TABLE_PERMISSION), columns);
145 CHECK_AND_RETURN_RET_LOG(queryResultSet != nullptr, E_PERMISSION_DENIED, "queryResultSet is nullptr");
146 int count = 0;
147 auto ret = queryResultSet->GetRowCount(count);
148 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK && count > 0, E_PERMISSION_DENIED, "db is no permission record");
149 ret = queryResultSet->GoToFirstRow();
150 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, E_PERMISSION_DENIED, "GoToFirstRow fail");
151 int index = -1;
152 ret = queryResultSet->GetColumnIndex(FIELD_PERMISSION_TYPE, index);
153 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, E_PERMISSION_DENIED, "GetColumnIndex fail");
154 int32_t permissionType = 0;
155 ret = queryResultSet->GetInt(index, permissionType);
156 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, E_PERMISSION_DENIED, "GetInt fail");
157 if (!isWrite) {
158 return ConvertPermResult(readPermSet.count(permissionType));
159 }
160 return ConvertPermResult(writePermSet.count(permissionType));
161 }
162
163 } // namespace name