1 /*
2  * Copyright (c) 2023 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 #include "dlp_kv_data_storage.h"
17 #include <unistd.h>
18 #include "dlp_permission_log.h"
19 #include "dlp_permission.h"
20 
21 namespace OHOS {
22 namespace Security {
23 namespace DlpPermission {
24 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpKvDataStorage"};
25 static const int32_t MAX_TIMES = 10;
26 static const int32_t SLEEP_INTERVAL = 100 * 1000;
27 static const std::string KV_STORE_EL1_BASE_DIR = "/data/service/el1/public/database/";
28 static const std::string KV_STORE_EL2_BASE_DIR = "/data/service/el2/public/database/";
29 static const std::string DLP_KV_APP_ID = "dlp_permission_service_storage";
30 
DlpKvDataStorage(const std::string & storeId,const KvDataStorageOptions & options)31 DlpKvDataStorage::DlpKvDataStorage(const std::string &storeId,
32     const KvDataStorageOptions &options)
33 {
34     appId_.appId = DLP_KV_APP_ID;
35     storeId_.storeId = storeId;
36     options_ = options;
37     if (options_.area == DistributedKv::EL1) {
38         baseDir_ = KV_STORE_EL1_BASE_DIR + DLP_KV_APP_ID;
39     } else {
40         baseDir_ = KV_STORE_EL2_BASE_DIR + DLP_KV_APP_ID;
41     }
42 }
43 
~DlpKvDataStorage()44 DlpKvDataStorage::~DlpKvDataStorage()
45 {
46     if (kvStorePtr_ != nullptr) {
47         dataManager_.CloseKvStore(appId_, kvStorePtr_);
48     }
49 }
50 
TryTwice(const std::function<DistributedKv::Status ()> & func) const51 void DlpKvDataStorage::TryTwice(const std::function<DistributedKv::Status()> &func) const
52 {
53     OHOS::DistributedKv::Status status = func();
54     if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
55         status = func();
56         DLP_LOG_ERROR(LABEL, "distribute database ipc error and try again, status = %{public}d", status);
57     }
58 }
59 
LoadAllData(std::map<std::string,std::string> & infos)60 int32_t DlpKvDataStorage::LoadAllData(std::map<std::string, std::string> &infos)
61 {
62     bool res = CheckKvStore();
63     if (!res) {
64         DLP_LOG_ERROR(LABEL, "kvStore is nullptr");
65         return DLP_COMMON_CHECK_KVSTORE_ERROR;
66     }
67     OHOS::DistributedKv::Status status = DistributedKv::Status::SUCCESS;
68     std::vector<OHOS::DistributedKv::Entry> allEntries;
69     TryTwice([this, &status, &allEntries] {
70         status = GetEntries("", allEntries);
71         return status;
72     });
73     if (status != OHOS::DistributedKv::Status::SUCCESS) {
74         DLP_LOG_ERROR(LABEL, "get entries error: %{public}d", status);
75         return DLP_QUERY_DISTRIBUTE_DATA_ERROR;
76     }
77     infos.clear();
78     SaveEntries(allEntries, infos);
79     return ERR_OK;
80 }
81 
GetKvStore()82 OHOS::DistributedKv::Status DlpKvDataStorage::GetKvStore()
83 {
84     OHOS::DistributedKv::Options options = {
85         .createIfMissing = true,
86         .encrypt = false,
87         .autoSync = options_.autoSync,
88         .syncable = options_.autoSync,
89         .securityLevel = options_.securityLevel,
90         .area = options_.area,
91         .kvStoreType = OHOS::DistributedKv::KvStoreType::SINGLE_VERSION,
92         .baseDir = baseDir_,
93     };
94     OHOS::DistributedKv::Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
95     bool res = (status != OHOS::DistributedKv::Status::SUCCESS) || (kvStorePtr_ == nullptr);
96     if (res) {
97         DLP_LOG_ERROR(LABEL, "GetSingleKvStore failed! status %{public}d, kvStorePtr_ is nullptr", status);
98     }
99     return status;
100 }
101 
CheckKvStore()102 bool DlpKvDataStorage::CheckKvStore()
103 {
104     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
105     if (kvStorePtr_ != nullptr) {
106         return true;
107     }
108     int32_t tryTimes = MAX_TIMES;
109     OHOS::DistributedKv::Status status = OHOS::DistributedKv::Status::SUCCESS;
110     while (tryTimes > 0) {
111         status = GetKvStore();
112         bool res = (status == OHOS::DistributedKv::Status::SUCCESS) && (kvStorePtr_ != nullptr);
113         if (res) {
114             return true;
115         }
116         usleep(SLEEP_INTERVAL);
117         tryTimes--;
118     }
119     return false;
120 }
121 
AddOrUpdateValue(const std::string & key,const std::string & value)122 int32_t DlpKvDataStorage::AddOrUpdateValue(const std::string &key, const std::string &value)
123 {
124     if (key.empty() || value.empty()) {
125         DLP_LOG_ERROR(LABEL, "param is empty!");
126         return DLP_KV_DATE_INFO_EMPTY_ERROR;
127     }
128     return PutValueToKvStore(key, value);
129 }
130 
RemoveValueFromKvStore(const std::string & keyStr)131 int32_t DlpKvDataStorage::RemoveValueFromKvStore(const std::string &keyStr)
132 {
133     if (!CheckKvStore()) {
134         DLP_LOG_ERROR(LABEL, "kvStore is nullptr");
135         return DLP_COMMON_CHECK_KVSTORE_ERROR;
136     }
137     OHOS::DistributedKv::Key key(keyStr);
138     OHOS::DistributedKv::Status status;
139     OHOS::DistributedKv::Value value;
140     {
141         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
142         // check exist
143         status = kvStorePtr_->Get(key, value);
144         if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
145             DLP_LOG_ERROR(LABEL, "kvstore ipc error and try again, status = %{public}d", status);
146             status = kvStorePtr_->Get(key, value);
147         }
148         if (status != OHOS::DistributedKv::Status::SUCCESS) {
149             DLP_LOG_INFO(LABEL, "key does not exist in kvStore.");
150             return DLP_OK;
151         }
152         // delete
153         status = kvStorePtr_->Delete(key);
154         if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
155             status = kvStorePtr_->Delete(key);
156             DLP_LOG_ERROR(LABEL, "kvstore ipc error and try to call again, status = %{public}d", status);
157         }
158     }
159     if (status != OHOS::DistributedKv::Status::SUCCESS) {
160         DLP_LOG_ERROR(LABEL, "delete key from kvstore failed, status %{public}d.", status);
161         return DLP_COMMON_DELETE_KEY_FROM_KVSTORE_ERROR;
162     }
163     DLP_LOG_DEBUG(LABEL, "delete key from kvStore succeed!");
164     return DLP_OK;
165 }
166 
DeleteKvStore()167 int32_t DlpKvDataStorage::DeleteKvStore()
168 {
169     bool res = CheckKvStore();
170     if (!res) {
171         DLP_LOG_ERROR(LABEL, "kvStore is nullptr");
172         return DLP_QUERY_DISTRIBUTE_DATA_ERROR;
173     }
174     OHOS::DistributedKv::Status status;
175     {
176         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
177         dataManager_.CloseKvStore(this->appId_, this->storeId_);
178         kvStorePtr_ = nullptr;
179         status = dataManager_.DeleteKvStore(this->appId_, this->storeId_, baseDir_);
180     }
181     if (status != OHOS::DistributedKv::Status::SUCCESS) {
182         DLP_LOG_ERROR(LABEL, "error, status = %{public}d", status);
183         return DLP_QUERY_DISTRIBUTE_DATA_ERROR;
184     }
185     return DLP_OK;
186 }
187 
PutValueToKvStore(const std::string & keyStr,const std::string & valueStr)188 int32_t DlpKvDataStorage::PutValueToKvStore(const std::string &keyStr, const std::string &valueStr)
189 {
190     bool res = CheckKvStore();
191     if (!res) {
192         DLP_LOG_ERROR(LABEL, "kvStore is nullptr");
193         return DLP_COMMON_CHECK_KVSTORE_ERROR;
194     }
195     OHOS::DistributedKv::Key key(keyStr);
196     OHOS::DistributedKv::Value value(valueStr);
197     OHOS::DistributedKv::Status status;
198     {
199         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
200         status = kvStorePtr_->Put(key, value);
201         if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
202             status = kvStorePtr_->Put(key, value);
203         }
204     }
205     if (status != OHOS::DistributedKv::Status::SUCCESS) {
206         DLP_LOG_ERROR(LABEL, "put value to kvStore error, status = %{public}d", status);
207         return DLP_QUERY_DISTRIBUTE_DATA_ERROR;
208     }
209     return DLP_OK;
210 }
211 
GetValueFromKvStore(const std::string & keyStr,std::string & valueStr)212 int32_t DlpKvDataStorage::GetValueFromKvStore(const std::string &keyStr, std::string &valueStr)
213 {
214     bool res = CheckKvStore();
215     if (!res) {
216         DLP_LOG_ERROR(LABEL, "kvStore is nullptr");
217         return DLP_COMMON_CHECK_KVSTORE_ERROR;
218     }
219     OHOS::DistributedKv::Key key(keyStr);
220     OHOS::DistributedKv::Value value;
221     OHOS::DistributedKv::Status status;
222     {
223         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
224         status = kvStorePtr_->Get(key, value);
225         if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
226             DLP_LOG_ERROR(LABEL, "kvstore ipc error and try again, status = %{public}d", status);
227             status = kvStorePtr_->Get(key, value);
228         }
229     }
230     if (status != OHOS::DistributedKv::Status::SUCCESS) {
231         DLP_LOG_ERROR(LABEL, "get value from kvstore error, status %{public}d.", status);
232         return DLP_QUERY_DISTRIBUTE_DATA_ERROR;
233     }
234     valueStr = value.ToString();
235     return DLP_OK;
236 }
237 
GetEntries(std::string subId,std::vector<OHOS::DistributedKv::Entry> & allEntries) const238 OHOS::DistributedKv::Status DlpKvDataStorage::GetEntries(
239     std::string subId, std::vector<OHOS::DistributedKv::Entry> &allEntries) const
240 {
241     OHOS::DistributedKv::Key allEntryKeyPrefix(subId);
242     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
243     OHOS::DistributedKv::Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
244     return status;
245 }
246 
IsKeyExists(const std::string & keyStr)247 bool DlpKvDataStorage::IsKeyExists(const std::string &keyStr)
248 {
249     if (keyStr.empty()) {
250         DLP_LOG_ERROR(LABEL, "param is empty!");
251         return false;
252     }
253     std::string valueStr;
254     return GetValueFromKvStore(keyStr, valueStr) == DLP_OK;
255 }
256 }  // namespace DlpPermission
257 }  // namespace Security
258 }  // namespace OHOS
259