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 #define LOG_TAG "RdConnection"
16 #include "rd_connection.h"
17 
18 #include <securec.h>
19 #include <string>
20 
21 #include "logger.h"
22 #include "grd_api_manager.h"
23 #include "rd_statement.h"
24 #include "rdb_errno.h"
25 #include "rdb_security_manager.h"
26 #include "sqlite_global_config.h"
27 #include "sqlite_utils.h"
28 
29 namespace OHOS {
30 namespace NativeRdb {
31 using namespace OHOS::Rdb;
32 __attribute__((used))
33 const int32_t RdConnection::regCreator_ = Connection::RegisterCreator(DB_VECTOR, RdConnection::Create);
34 __attribute__((used))
35 const int32_t RdConnection::regRepairer_ = Connection::RegisterRepairer(DB_VECTOR, RdConnection::Repair);
36 __attribute__((used))
37 const int32_t RdConnection::regDeleter_ = Connection::RegisterDeleter(DB_VECTOR, RdConnection::Delete);
38 
Create(const RdbStoreConfig& config, bool isWrite)39 std::pair<int32_t, std::shared_ptr<Connection>> RdConnection::Create(const RdbStoreConfig& config, bool isWrite)
40 {
41     std::pair<int32_t, std::shared_ptr<Connection>> result = { E_ERROR, nullptr };
42     if (!IsUsingArkData() || config.GetStorageMode() == StorageMode::MODE_MEMORY) {
43         result.first = E_NOT_SUPPORT;
44         return result;
45     }
46     auto& [errCode, conn] = result;
47     for (size_t i = 0; i < ITERS_COUNT; i++) {
48         std::shared_ptr<RdConnection> connection = std::make_shared<RdConnection>(config, isWrite);
49         if (connection == nullptr) {
50             LOG_ERROR("SqliteConnection::Open new failed, connection is nullptr.");
51             return result;
52         }
53         errCode = connection->InnerOpen(config);
54         if (errCode == E_OK) {
55             conn = connection;
56             break;
57         }
58     }
59     return result;
60 }
61 
Repair(const RdbStoreConfig& config)62 int32_t RdConnection::Repair(const RdbStoreConfig& config)
63 {
64     std::string dbPath = "";
65     auto errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
66     if (errCode != E_OK) {
67         LOG_ERROR("Can not get db path.");
68         return errCode;
69     }
70     std::vector<uint8_t> key = config.GetEncryptKey();
71     errCode = RdUtils::RdDbRepair(dbPath.c_str(), GetConfigStr(key, config.IsEncrypt()).c_str());
72     key.assign(key.size(), 0);
73     if (errCode != E_OK) {
74         LOG_ERROR("Fail to repair db.");
75     }
76     return errCode;
77 }
78 
79 static constexpr const char *RD_POST_FIXES[] = {
80     "",
81     ".redo",
82     ".undo",
83     ".ctrl",
84     ".ctrl.dwr",
85     ".safe",
86     ".map",
87     ".corruptedflg",
88 };
89 
Delete(const RdbStoreConfig &config)90 int32_t RdConnection::Delete(const RdbStoreConfig &config)
91 {
92     auto path = config.GetPath();
93     for (auto postFix : RD_POST_FIXES) {
94         std::string shmFilePath = path + postFix;
95         if (access(shmFilePath.c_str(), F_OK) == 0) {
96             remove(shmFilePath.c_str());
97         }
98     }
99     return E_OK;
100 }
101 
RdConnection(const RdbStoreConfig &config, bool isWriter)102 RdConnection::RdConnection(const RdbStoreConfig &config, bool isWriter) : isWriter_(isWriter), config_(config)
103 {
104 }
105 
~RdConnection()106 RdConnection::~RdConnection()
107 {
108     if (dbHandle_ != nullptr) {
109         int errCode = RdUtils::RdDbClose(dbHandle_, 0);
110         if (errCode != E_OK) {
111             LOG_ERROR("~RdConnection ~RdConnection: could not close database err = %{public}d", errCode);
112         }
113         dbHandle_ = nullptr;
114     }
115 }
116 
GetConfigStr(const std::vector<uint8_t> &keys, bool isEncrypt)117 std::string RdConnection::GetConfigStr(const std::vector<uint8_t> &keys, bool isEncrypt)
118 {
119     std::string config = "{";
120     if (isEncrypt) {
121         const size_t keyBuffSize = keys.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0'
122         char keyBuff[keyBuffSize];
123         config += "\"isEncrypted\":1,";
124         config += "\"hexPassword\":\"";
125         config += RdUtils::GetEncryptKey(keys, keyBuff, keyBuffSize);
126         config += "\",";
127         (void)memset_s(keyBuff, keyBuffSize, 0, keyBuffSize);
128     }
129     config += RdConnection::GRD_OPEN_CONFIG_STR;
130     config += "}";
131     return config;
132 }
133 
134 
InnerOpen(const RdbStoreConfig &config)135 int RdConnection::InnerOpen(const RdbStoreConfig &config)
136 {
137     std::string dbPath = "";
138     auto errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
139     if (errCode != E_OK) {
140         LOG_ERROR("Can not get db path.");
141         return errCode;
142     }
143     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
144     if (!newKey.empty()) {
145         newKey.assign(newKey.size(), 0);
146         errCode = ReSetKey(config);
147         if (errCode != E_OK) {
148             LOG_ERROR("Can not reset key %{public}d.", errCode);
149             return errCode;
150         }
151     }
152 
153     std::vector<uint8_t> key = config.GetEncryptKey();
154     std::string configStr = GetConfigStr(key, config.IsEncrypt());
155     errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
156     if (errCode == E_CHANGE_UNENCRYPTED_TO_ENCRYPTED) {
157         errCode = RdUtils::RdDbRekey(dbPath.c_str(), GetConfigStr({}, false).c_str(), key);
158         if (errCode != E_OK) {
159             key.assign(key.size(), 0);
160             RdUtils::ClearAndZeroString(configStr);
161             LOG_ERROR("Can not rekey caylay db %{public}d.", errCode);
162             return errCode;
163         }
164         errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
165     }
166     key.assign(key.size(), 0);
167     RdUtils::ClearAndZeroString(configStr);
168     if (errCode != E_OK) {
169         LOG_ERROR("Can not open rd db %{public}d.", errCode);
170         return errCode;
171     }
172     return errCode;
173 }
174 
OnInitialize()175 int32_t RdConnection::OnInitialize()
176 {
177     return E_NOT_SUPPORT;
178 }
179 
CreateStatement(const std::string& sql, Connection::SConn conn)180 std::pair<int32_t, RdConnection::Stmt> RdConnection::CreateStatement(const std::string& sql, Connection::SConn conn)
181 {
182     auto stmt = std::make_shared<RdStatement>();
183     stmt->conn_ = conn;
184     stmt->config_ = &config_;
185     stmt->setPragmas_["user_version"] = ([this](const int &value) -> int32_t {
186         return RdUtils::RdDbSetVersion(dbHandle_, GRD_CONFIG_USER_VERSION, value);
187     });
188     stmt->getPragmas_["user_version"] = ([this](int &version) -> int32_t {
189         return RdUtils::RdDbGetVersion(dbHandle_, GRD_CONFIG_USER_VERSION, version);
190     });
191     int32_t ret = stmt->Prepare(dbHandle_, sql);
192     if (ret != E_OK) {
193         return { ret, nullptr };
194     }
195     return { ret, stmt };
196 }
197 
GetDBType() const198 int32_t RdConnection::GetDBType() const
199 {
200     return DB_VECTOR;
201 }
202 
IsWriter() const203 bool RdConnection::IsWriter() const
204 {
205     return isWriter_;
206 }
207 
ReSetKey(const RdbStoreConfig& config)208 int32_t RdConnection::ReSetKey(const RdbStoreConfig& config)
209 {
210     if (!IsWriter()) {
211         return E_OK;
212     }
213     std::string dbPath = "";
214     int errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
215     if (errCode != E_OK) {
216         LOG_ERROR("Can not get db path.");
217         return errCode;
218     }
219     std::vector<uint8_t> key = config.GetEncryptKey();
220     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
221     std::string configStr = GetConfigStr(key, config.IsEncrypt());
222     errCode = RdUtils::RdDbRekey(dbPath.c_str(), configStr.c_str(), newKey);
223     RdUtils::ClearAndZeroString(configStr);
224     key.assign(key.size(), 0);
225     newKey.assign(newKey.size(), 0);
226     if (errCode != E_OK) {
227         LOG_ERROR("ReKey failed, err = %{public}d, errno = %{public}d", errCode, errno);
228         RdbSecurityManager::GetInstance().DelKeyFile(
229             config.GetPath(), RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY);
230         return E_OK;
231     }
232     config.ChangeEncryptKey();
233     return E_OK;
234 }
235 
TryCheckPoint(bool timeout)236 int32_t RdConnection::TryCheckPoint(bool timeout)
237 {
238     return E_NOT_SUPPORT;
239 }
240 
LimitWalSize()241 int32_t RdConnection::LimitWalSize()
242 {
243     return E_NOT_SUPPORT;
244 }
245 
ConfigLocale(const std::string& localeStr)246 int32_t RdConnection::ConfigLocale(const std::string& localeStr)
247 {
248     return E_NOT_SUPPORT;
249 }
250 
CleanDirtyData(const std::string& table, uint64_t cursor)251 int32_t RdConnection::CleanDirtyData(const std::string& table, uint64_t cursor)
252 {
253     return E_NOT_SUPPORT;
254 }
255 
SubscribeTableChanges(const Connection::Notifier& notifier)256 int32_t RdConnection::SubscribeTableChanges(const Connection::Notifier& notifier)
257 {
258     return E_NOT_SUPPORT;
259 }
260 
GetMaxVariable() const261 int32_t RdConnection::GetMaxVariable() const
262 {
263     return MAX_VARIABLE_NUM;
264 }
265 
GetJournalMode()266 int32_t RdConnection::GetJournalMode()
267 {
268     return E_NOT_SUPPORT;
269 }
270 
ClearCache()271 int32_t RdConnection::ClearCache()
272 {
273     return E_NOT_SUPPORT;
274 }
275 
Subscribe(const std::string& event, const std::shared_ptr<DistributedRdb::RdbStoreObserver>& observer)276 int32_t RdConnection::Subscribe(const std::string& event,
277     const std::shared_ptr<DistributedRdb::RdbStoreObserver>& observer)
278 {
279     return E_NOT_SUPPORT;
280 }
281 
Unsubscribe(const std::string& event, const std::shared_ptr<DistributedRdb::RdbStoreObserver>& observer)282 int32_t RdConnection::Unsubscribe(const std::string& event,
283     const std::shared_ptr<DistributedRdb::RdbStoreObserver>& observer)
284 {
285     return E_NOT_SUPPORT;
286 }
287 
Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey, bool isAsync, SlaveStatus &slaveStatus)288 int32_t RdConnection::Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
289     bool isAsync, SlaveStatus &slaveStatus)
290 {
291     if (!destEncryptKey.empty() && !config_.IsEncrypt()) {
292         return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), destEncryptKey);
293     }
294     if (config_.IsEncrypt()) {
295         std::vector<uint8_t> key = config_.GetEncryptKey();
296         int32_t ret = RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), key);
297         key.assign(key.size(), 0);
298         return ret;
299     }
300     return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), {});
301 }
302 
Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey, SlaveStatus &slaveStatus)303 int32_t RdConnection::Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
304     SlaveStatus &slaveStatus)
305 {
306     if (destEncryptKey.empty()) {
307         std::vector<uint8_t> key = config_.GetEncryptKey();
308         int32_t ret = RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), key);
309         key.assign(key.size(), 0);
310         return ret;
311     }
312     return RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), destEncryptKey);
313 }
314 
GenerateExchangeStrategy(const SlaveStatus &status)315 ExchangeStrategy RdConnection::GenerateExchangeStrategy(const SlaveStatus &status)
316 {
317     return ExchangeStrategy::NOT_HANDLE;
318 }
319 } // namespace NativeRdb
320 } // namespace OHOS