1 #include "invstorage.h"
5 #include "fsstorage_read.h"
6 #include "logging/logging.h"
7 #include "sqlstorage.h"
8 #include "utilities/utils.h"
10 void INvStorage::importSimple(
const boost::filesystem::path& base_path, store_data_t store_func, load_data_t load_func,
12 if (!(this->*load_func)(
nullptr) && !imported_data_path.empty()) {
13 boost::filesystem::path abs_path = imported_data_path.get(base_path);
14 if (!boost::filesystem::exists(abs_path)) {
15 LOG_ERROR <<
"Couldn't import " << data_name <<
": " << abs_path <<
" doesn't exist.";
18 std::string content = Utils::readFile(abs_path.string());
19 (this->*store_func)(content);
20 LOG_DEBUG <<
"Successfully imported " << data_name <<
" from " << abs_path;
24 void INvStorage::importUpdateSimple(
const boost::filesystem::path& base_path, store_data_t store_func,
26 const std::string& data_name) {
27 std::string prev_content;
30 if (!(this->*load_func)(&prev_content)) {
32 }
else if (!imported_data_path.empty()) {
33 content = Utils::readFile(imported_data_path.get(base_path).string());
34 if (Crypto::sha256digest(content) != Crypto::sha256digest(prev_content)) {
39 if (update && !imported_data_path.empty()) {
40 boost::filesystem::path abs_path = imported_data_path.get(base_path);
41 if (!boost::filesystem::exists(abs_path)) {
42 LOG_ERROR <<
"Couldn't import " << data_name <<
": " << abs_path <<
" doesn't exist.";
45 if (content.empty()) {
46 content = Utils::readFile(abs_path.string());
48 (this->*store_func)(content);
49 LOG_DEBUG <<
"Successfully imported " << data_name <<
" from " << abs_path;
53 void INvStorage::importUpdateCertificate(
const boost::filesystem::path& base_path,
55 std::string prev_content;
58 if (!loadTlsCert(&prev_content)) {
60 }
else if (!imported_data_path.empty()) {
61 content = Utils::readFile(imported_data_path.get(base_path).string());
62 if (Crypto::sha256digest(content) != Crypto::sha256digest(prev_content)) {
67 if (update && !imported_data_path.empty()) {
68 boost::filesystem::path abs_path = imported_data_path.get(base_path);
69 if (!boost::filesystem::exists(abs_path)) {
70 LOG_ERROR <<
"Couldn't import client certificate: " << abs_path <<
" doesn't exist.";
73 if (content.empty()) {
74 content = Utils::readFile(abs_path.string());
78 const std::string new_device_id = Crypto::extractSubjectCN(content);
79 std::string old_device_id;
80 if (!loadDeviceId(&old_device_id)) {
81 LOG_DEBUG <<
"Unable to load previous device ID.";
82 }
else if (new_device_id != old_device_id) {
83 throw std::runtime_error(std::string(
"Certificate at ") + abs_path.string() +
" has a device ID of " +
84 new_device_id +
" but the device currently is identified as " + old_device_id +
85 ". Changing device ID is not supported!");
88 storeTlsCert(content);
89 LOG_DEBUG <<
"Successfully imported client certificate from " << abs_path;
93 void INvStorage::importPrimaryKeys(
const boost::filesystem::path& base_path,
const utils::BasedPath& import_pubkey_path,
95 if (loadPrimaryKeys(
nullptr,
nullptr) || import_pubkey_path.empty() || import_privkey_path.empty()) {
98 const boost::filesystem::path pubkey_abs_path = import_pubkey_path.get(base_path);
99 const boost::filesystem::path privkey_abs_path = import_privkey_path.get(base_path);
100 if (!boost::filesystem::exists(pubkey_abs_path)) {
101 LOG_ERROR <<
"Couldn't import data: " << pubkey_abs_path <<
" doesn't exist.";
104 if (!boost::filesystem::exists(privkey_abs_path)) {
105 LOG_ERROR <<
"Couldn't import data: " << privkey_abs_path <<
" doesn't exist.";
108 const std::string pub_content = Utils::readFile(pubkey_abs_path.string());
109 const std::string priv_content = Utils::readFile(privkey_abs_path.string());
110 storePrimaryKeys(pub_content, priv_content);
111 LOG_DEBUG <<
"Successfully imported Uptane keys from " << pubkey_abs_path <<
" and " << privkey_abs_path;
114 void INvStorage::importInstalledVersions(
const boost::filesystem::path& base_path) {
115 std::vector<Uptane::Target> installed_versions;
116 const boost::filesystem::path file_path =
utils::BasedPath(
"installed_versions").get(base_path);
117 loadPrimaryInstallationLog(&installed_versions,
false);
118 if (!installed_versions.empty()) {
121 size_t current_index = SIZE_MAX;
122 fsReadInstalledVersions(file_path, &installed_versions, ¤t_index);
123 if (current_index < installed_versions.size()) {
125 savePrimaryInstalledVersion(installed_versions[current_index], InstalledVersionUpdateMode::kCurrent);
126 boost::filesystem::remove(file_path);
127 LOG_DEBUG <<
"Successfully imported installed versions from " << file_path;
131 void INvStorage::importData(
const ImportConfig& import_config) {
132 importPrimaryKeys(import_config.base_path, import_config.uptane_public_key_path,
133 import_config.uptane_private_key_path);
134 importUpdateCertificate(import_config.base_path, import_config.tls_clientcert_path);
135 importUpdateSimple(import_config.base_path, &INvStorage::storeTlsCa, &INvStorage::loadTlsCa,
136 import_config.tls_cacert_path,
"server CA certificate");
137 importUpdateSimple(import_config.base_path, &INvStorage::storeTlsPkey, &INvStorage::loadTlsPkey,
138 import_config.tls_pkey_path,
"client TLS key");
139 importInstalledVersions(import_config.base_path);
142 std::shared_ptr<INvStorage> INvStorage::newStorage(
const StorageConfig& config,
const bool readonly) {
143 switch (config.type) {
144 case StorageType::kSqlite: {
145 boost::filesystem::path db_path = config.sqldb_path.get(config.path);
146 if (!boost::filesystem::exists(db_path) && FSStorageRead::FSStoragePresent(config)) {
149 "Migration from FS is not possible because the SQL database is configured to be readonly");
152 LOG_INFO <<
"Starting FS to SQL storage migration";
153 if (access(config.path.c_str(), R_OK | W_OK | X_OK) != 0) {
154 throw StorageException(std::string(
"Cannot read prior filesystem configuration from ") +
155 config.path.string() +
" due to insufficient permissions.");
158 old_config.type = StorageType::kFileSystem;
159 old_config.path = config.path;
161 auto sql_storage = std::make_shared<SQLStorage>(config, readonly);
163 INvStorage::FSSToSQLS(fs_storage, *sql_storage);
166 if (!boost::filesystem::exists(db_path)) {
167 LOG_INFO <<
"Bootstrap empty SQL storage";
169 LOG_INFO <<
"Use existing SQL storage: " << db_path;
171 return std::make_shared<SQLStorage>(config, readonly);
173 case StorageType::kFileSystem:
175 throw std::runtime_error(
"FSStorage has been removed in recent versions of aktualizr, please use SQLStorage");
180 std::string public_key;
181 std::string private_key;
182 if (fs_storage.loadPrimaryKeys(&public_key, &private_key)) {
183 sql_storage.storePrimaryKeys(public_key, private_key);
187 if (fs_storage.loadTlsCa(&ca)) {
188 sql_storage.storeTlsCa(ca);
192 if (fs_storage.loadTlsCert(&cert)) {
193 sql_storage.storeTlsCert(cert);
197 if (fs_storage.loadTlsPkey(&pkey)) {
198 sql_storage.storeTlsPkey(pkey);
201 std::string device_id;
202 if (fs_storage.loadDeviceId(&device_id)) {
203 sql_storage.storeDeviceId(device_id);
207 if (fs_storage.loadEcuSerials(&serials)) {
208 sql_storage.storeEcuSerials(serials);
211 if (fs_storage.loadEcuRegistered()) {
212 sql_storage.storeEcuRegistered();
215 std::vector<MisconfiguredEcu> ecus;
216 if (fs_storage.loadMisconfiguredEcus(&ecus)) {
217 for (
auto& ecu : ecus) {
218 sql_storage.saveMisconfiguredEcu(ecu);
222 std::vector<Uptane::Target> installed_versions;
223 size_t current_index = SIZE_MAX;
225 fs_storage.loadInstalledVersions(&installed_versions, ¤t_index);
226 for (
auto it = installed_versions.cbegin(); it != installed_versions.cend(); it++, k++) {
227 auto mode = k == current_index ? InstalledVersionUpdateMode::kCurrent : InstalledVersionUpdateMode::kNone;
228 sql_storage.savePrimaryInstalledVersion(*it, mode);
232 for (
const auto& role : Uptane::Role::Roles()) {
233 if (role == Uptane::Role::Root()) {
238 for (
auto repo : {Uptane::RepositoryType::Director(), Uptane::RepositoryType::Image()}) {
239 if (fs_storage.loadNonRoot(&meta, repo, role)) {
240 sql_storage.storeNonRoot(meta, repo, role);
245 std::string latest_root;
246 for (
auto repo : {Uptane::RepositoryType::Director(), Uptane::RepositoryType::Image()}) {
247 if (fs_storage.loadLatestRoot(&latest_root, Uptane::RepositoryType::Director())) {
248 int latest_version = Uptane::extractVersionUntrusted(latest_root);
249 for (
int version = 0; version <= latest_version; ++version) {
259 fs_storage.cleanUpAll();
262 bool INvStorage::fsReadInstalledVersions(
const boost::filesystem::path& filename,
263 std::vector<Uptane::Target>* installed_versions,
size_t* current_version) {
264 if (access(filename.c_str(), R_OK) != 0) {
268 const Json::Value installed_versions_json = Utils::parseJSONFile(filename.string());
269 std::vector<Uptane::Target> new_versions;
271 for (
auto it = installed_versions_json.begin(); it != installed_versions_json.end(); ++it, ++k) {
272 if (!(*it).isObject()) {
275 t_json[
"hashes"][
"sha256"] = it.key();
277 new_versions.push_back(t);
278 if (current_version !=
nullptr) {
279 *current_version = k;
282 if (current_version !=
nullptr && (*it)[
"is_current"].asBool()) {
283 *current_version = k;
286 new_versions.push_back(t);
289 *installed_versions = new_versions;
290 }
catch (
const std::exception& ex) {
291 LOG_ERROR <<
"Unable to parse installed_versions: " << ex.what();