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