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 "GdbConn"
16 #include "graph_connection.h"
17
18 #include <unistd.h>
19
20 #include <string>
21 #include <utility>
22
23 #include "gdb_errors.h"
24 #include "gdb_utils.h"
25 #include "graph_statement.h"
26 #include "logger.h"
27 #include "rdb_security_manager.h"
28 #include "securec.h"
29
30 namespace OHOS::DistributedDataAip {
31 __attribute__((used))
32 const int32_t GraphConnection::regCreator_ = Connection::RegisterCreator(DBType::DB_GRAPH, GraphConnection::Create);
33
Create(const StoreConfig & config,bool isWriter)34 std::pair<int32_t, std::shared_ptr<Connection>> GraphConnection::Create(const StoreConfig &config, bool isWriter)
35 {
36 LOG_DEBUG("GraphConnection::Create start, name=%{public}s, isWriter=%{public}d",
37 GdbUtils::Anonymous(config.GetName()).c_str(), isWriter);
38 std::pair<int32_t, std::shared_ptr<Connection>> result = { E_INNER_ERROR, nullptr };
39 auto &[errCode, conn] = result;
40 for (size_t i = 0; i < ITERS_COUNT; i++) {
41 std::shared_ptr<GraphConnection> connection = std::make_shared<GraphConnection>(config, isWriter);
42 if (connection == nullptr) {
43 LOG_ERROR("Open new failed, connection is nullptr. name=%{public}s",
44 GdbUtils::Anonymous(config.GetName()).c_str());
45 return result;
46 }
47 errCode = connection->InnerOpen(config);
48 if (errCode == E_OK) {
49 conn = connection;
50 break;
51 }
52 if (errCode == E_GRD_INVALID_ARGS && connection->IsEncryptInvalidChanged(config)) {
53 errCode = E_CONFIG_INVALID_CHANGE;
54 break;
55 }
56 }
57 return result;
58 }
59
GraphConnection(const StoreConfig & config,bool isWriter)60 GraphConnection::GraphConnection(const StoreConfig &config, bool isWriter) : config_(config), isWriter_(isWriter)
61 {
62 }
63
~GraphConnection()64 GraphConnection::~GraphConnection()
65 {
66 LOG_DEBUG("enter");
67 if (dbHandle_ != nullptr) {
68 int errCode = GrdAdapter::Close(dbHandle_, 0);
69 if (errCode != E_OK) {
70 LOG_ERROR("could not close database, err=%{public}d", errCode);
71 }
72 dbHandle_ = nullptr;
73 }
74 }
75
InnerOpen(const StoreConfig & config)76 int GraphConnection::InnerOpen(const StoreConfig &config)
77 {
78 std::string dbPath = config.GetFullPath();
79 std::vector<uint8_t> newKey = config.GetNewEncryptKey();
80 if (!newKey.empty()) {
81 // NewKey exists, oldKey has expired, ResetKey is required
82 newKey.assign(newKey.size(), 0);
83 auto errCode = ResetKey(config);
84 if (errCode != E_OK) {
85 LOG_ERROR("Can not reset key %{public}d.", errCode);
86 return errCode;
87 }
88 }
89 std::vector<uint8_t> key = config.GetEncryptKey();
90 std::string configJson = GdbUtils::GetConfigStr(key, config.IsEncrypt());
91 LOG_DEBUG(
92 "GraphConnection::InnerOpen: dbPath=%{public}s, configJson=%{public}s",
93 GdbUtils::Anonymous(dbPath).c_str(), configJson.c_str());
94 int32_t errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
95 if (errCode == E_GRD_PASSWORD_NEED_REKEY) {
96 // Upgrading from non encrypted to encrypted, requires Rekey first and then Open
97 errCode = GrdAdapter::Rekey(dbPath.c_str(), GdbUtils::GetConfigStr({}, false).c_str(), key);
98 if (errCode != E_OK) {
99 key.assign(key.size(), 0);
100 GdbUtils::ClearAndZeroString(configJson);
101 LOG_ERROR("Can not rekey graph db %{public}d.", errCode);
102 return errCode;
103 }
104 errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
105 }
106 key.assign(key.size(), 0);
107 GdbUtils::ClearAndZeroString(configJson);
108 if (errCode != E_OK) {
109 LOG_ERROR("Can not open graph db, name=%{public}s, errCode=%{public}d.",
110 GdbUtils::Anonymous(config.GetName()).c_str(), errCode);
111 return errCode;
112 }
113 return errCode;
114 }
115
CreateStatement(const std::string & gql,std::shared_ptr<Connection> connection)116 std::pair<int32_t, GraphConnection::Stmt> GraphConnection::CreateStatement(
117 const std::string &gql, std::shared_ptr<Connection> connection)
118 {
119 int32_t ret;
120 auto stmt = std::make_shared<GraphStatement>(dbHandle_, gql, connection, ret);
121 if (ret != E_OK) {
122 return { ret, nullptr };
123 }
124 return { ret, stmt };
125 }
126
GetDBType() const127 DBType GraphConnection::GetDBType() const
128 {
129 return DBType::DB_GRAPH;
130 }
131
IsWriter() const132 bool GraphConnection::IsWriter() const
133 {
134 return isWriter_;
135 }
136
ResetKey(const StoreConfig & config)137 int32_t GraphConnection::ResetKey(const StoreConfig &config)
138 {
139 if (!IsWriter()) {
140 return E_OK;
141 }
142 std::string dbPath = config.GetFullPath();
143 std::vector<uint8_t> key = config.GetEncryptKey();
144 std::vector<uint8_t> newKey = config.GetNewEncryptKey();
145 std::string configStr = GdbUtils::GetConfigStr(key, config.IsEncrypt());
146 auto errCode = GrdAdapter::Rekey(dbPath.c_str(), configStr.c_str(), newKey);
147 GdbUtils::ClearAndZeroString(configStr);
148 key.assign(key.size(), 0);
149 newKey.assign(newKey.size(), 0);
150 if (errCode != E_OK) {
151 LOG_ERROR("Rekey failed, err = %{public}d, errno = %{public}d", errCode, errno);
152 NativeRdb::RdbSecurityManager::GetInstance().DelKeyFile(
153 config.GetFullPath(), NativeRdb::RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY);
154 return errCode;
155 }
156 config.ChangeEncryptKey();
157 return E_OK;
158 }
159
IsEncryptInvalidChanged(const StoreConfig & config)160 bool GraphConnection::IsEncryptInvalidChanged(const StoreConfig &config)
161 {
162 if (config.GetFullPath().empty() || config.IsEncrypt()) {
163 LOG_WARN("Config has no path or config is encrypted, path: %{public}s, isEncrypt: %{public}d",
164 GdbUtils::Anonymous(config.GetFullPath()).c_str(), config.IsEncrypt());
165 return false;
166 }
167 return NativeRdb::RdbSecurityManager::GetInstance().IsKeyFileExists(config.GetFullPath(),
168 NativeRdb::RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
169 }
170 } // namespace OHOS::DistributedDataAip
171