Aktualizr
C++ SOTA Client
invstorage.cc
1 #include "invstorage.h"
2 
3 #include <unistd.h>
4 
5 #include "fsstorage_read.h"
6 #include "logging/logging.h"
7 #include "sqlstorage.h"
8 #include "utilities/utils.h"
9 
10 std::ostream& operator<<(std::ostream& os, const StorageType stype) {
11  std::string stype_str;
12  switch (stype) {
13  case StorageType::kFileSystem:
14  stype_str = "filesystem";
15  break;
16  case StorageType::kSqlite:
17  stype_str = "sqlite";
18  break;
19  default:
20  stype_str = "unknown";
21  break;
22  }
23  os << '"' << stype_str << '"';
24  return os;
25 }
26 
27 void StorageConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
28  CopyFromConfig(type, "type", pt);
29  CopyFromConfig(path, "path", pt);
30  CopyFromConfig(sqldb_path, "sqldb_path", pt);
31  CopyFromConfig(uptane_metadata_path, "uptane_metadata_path", pt);
32  CopyFromConfig(uptane_private_key_path, "uptane_private_key_path", pt);
33  CopyFromConfig(uptane_public_key_path, "uptane_public_key_path", pt);
34  CopyFromConfig(tls_cacert_path, "tls_cacert_path", pt);
35  CopyFromConfig(tls_pkey_path, "tls_pkey_path", pt);
36  CopyFromConfig(tls_clientcert_path, "tls_clientcert_path", pt);
37 }
38 
39 void StorageConfig::writeToStream(std::ostream& out_stream) const {
40  writeOption(out_stream, type, "type");
41  writeOption(out_stream, path, "path");
42  writeOption(out_stream, sqldb_path.get(""), "sqldb_path");
43  writeOption(out_stream, uptane_metadata_path.get(""), "uptane_metadata_path");
44  writeOption(out_stream, uptane_private_key_path.get(""), "uptane_private_key_path");
45  writeOption(out_stream, uptane_public_key_path.get(""), "uptane_public_key_path");
46  writeOption(out_stream, tls_cacert_path.get(""), "tls_cacert_path");
47  writeOption(out_stream, tls_pkey_path.get(""), "tls_pkey_path");
48  writeOption(out_stream, tls_clientcert_path.get(""), "tls_clientcert_path");
49 }
50 
51 void ImportConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
52  CopyFromConfig(base_path, "base_path", pt);
53  CopyFromConfig(uptane_private_key_path, "uptane_private_key_path", pt);
54  CopyFromConfig(uptane_public_key_path, "uptane_public_key_path", pt);
55  CopyFromConfig(tls_cacert_path, "tls_cacert_path", pt);
56  CopyFromConfig(tls_pkey_path, "tls_pkey_path", pt);
57  CopyFromConfig(tls_clientcert_path, "tls_clientcert_path", pt);
58 }
59 
60 void ImportConfig::writeToStream(std::ostream& out_stream) const {
61  writeOption(out_stream, base_path, "base_path");
62  writeOption(out_stream, uptane_private_key_path.get(""), "uptane_private_key_path");
63  writeOption(out_stream, uptane_public_key_path.get(""), "uptane_public_key_path");
64  writeOption(out_stream, tls_cacert_path.get(""), "tls_cacert_path");
65  writeOption(out_stream, tls_pkey_path.get(""), "tls_pkey_path");
66  writeOption(out_stream, tls_clientcert_path.get(""), "tls_clientcert_path");
67 }
68 
69 void INvStorage::importSimple(const boost::filesystem::path& base_path, store_data_t store_func, load_data_t load_func,
70  const BasedPath& imported_data_path) {
71  if (!(this->*load_func)(nullptr) && !imported_data_path.empty()) {
72  boost::filesystem::path abs_path = imported_data_path.get(base_path);
73  if (!boost::filesystem::exists(abs_path)) {
74  LOG_ERROR << "Couldn't import data: " << abs_path << " doesn't exist.";
75  return;
76  }
77  std::string content = Utils::readFile(abs_path.string());
78  (this->*store_func)(content);
79  }
80 }
81 
82 void INvStorage::importUpdateSimple(const boost::filesystem::path& base_path, store_data_t store_func,
83  load_data_t load_func, const BasedPath& imported_data_path) {
84  std::string prev_content;
85  std::string content;
86  bool update = false;
87  if (!(this->*load_func)(&prev_content)) {
88  update = true;
89  } else if (!imported_data_path.empty()) {
90  content = Utils::readFile(imported_data_path.get(base_path).string());
91  if (Crypto::sha256digest(content) != Crypto::sha256digest(prev_content)) {
92  update = true;
93  }
94  }
95 
96  if (update && !imported_data_path.empty()) {
97  boost::filesystem::path abs_path = imported_data_path.get(base_path);
98  if (!boost::filesystem::exists(abs_path)) {
99  LOG_ERROR << "Couldn't import data: " << abs_path << " doesn't exist.";
100  return;
101  }
102  if (content.empty()) {
103  content = Utils::readFile(abs_path.string());
104  }
105  (this->*store_func)(content);
106  }
107 }
108 
109 void INvStorage::importPrimaryKeys(const boost::filesystem::path& base_path, const BasedPath& import_pubkey_path,
110  const BasedPath& import_privkey_path) {
111  if (loadPrimaryKeys(nullptr, nullptr) || import_pubkey_path.empty() || import_privkey_path.empty()) {
112  return;
113  }
114  boost::filesystem::path pubkey_abs_path = import_pubkey_path.get(base_path);
115  boost::filesystem::path privkey_abs_path = import_privkey_path.get(base_path);
116  if (!boost::filesystem::exists(pubkey_abs_path)) {
117  LOG_ERROR << "Couldn't import data: " << pubkey_abs_path << " doesn't exist.";
118  return;
119  }
120  if (!boost::filesystem::exists(privkey_abs_path)) {
121  LOG_ERROR << "Couldn't import data: " << privkey_abs_path << " doesn't exist.";
122  return;
123  }
124  std::string pub_content = Utils::readFile(pubkey_abs_path.string());
125  std::string priv_content = Utils::readFile(privkey_abs_path.string());
126  storePrimaryKeys(pub_content, priv_content);
127 }
128 
129 void INvStorage::importData(const ImportConfig& import_config) {
130  importPrimaryKeys(import_config.base_path, import_config.uptane_public_key_path,
131  import_config.uptane_private_key_path);
132  // root CA certificate can be updated
133  importUpdateSimple(import_config.base_path, &INvStorage::storeTlsCa, &INvStorage::loadTlsCa,
134  import_config.tls_cacert_path);
135  importSimple(import_config.base_path, &INvStorage::storeTlsCert, &INvStorage::loadTlsCert,
136  import_config.tls_clientcert_path);
137  importSimple(import_config.base_path, &INvStorage::storeTlsPkey, &INvStorage::loadTlsPkey,
138  import_config.tls_pkey_path);
139 }
140 
141 std::shared_ptr<INvStorage> INvStorage::newStorage(const StorageConfig& config, bool readonly) {
142  switch (config.type) {
143  case StorageType::kSqlite: {
144  boost::filesystem::path db_path = config.sqldb_path.get(config.path);
145  if (!boost::filesystem::exists(db_path) && boost::filesystem::exists(config.path)) {
146  if (readonly) {
147  throw StorageException("Migration from FS is not possible, because of readonly database");
148  }
149 
150  LOG_INFO << "Starting FS to SQL storage migration";
151  if (access(config.path.c_str(), R_OK | W_OK | X_OK) != 0) {
152  throw StorageException(std::string("Cannot read prior filesystem configuration from ") +
153  config.path.string() + " due to insufficient permissions.");
154  }
155  StorageConfig old_config = config;
156  old_config.type = StorageType::kFileSystem;
157  old_config.path = config.path;
158 
159  auto sql_storage = std::make_shared<SQLStorage>(config, readonly);
160  FSStorageRead fs_storage(old_config);
161  INvStorage::FSSToSQLS(fs_storage, *sql_storage);
162  return sql_storage;
163  }
164  if (!boost::filesystem::exists(db_path)) {
165  LOG_INFO << "Bootstrap empty SQL storage";
166  } else {
167  LOG_INFO << "Use existing SQL storage: " << db_path;
168  }
169  return std::make_shared<SQLStorage>(config, readonly);
170  }
171  case StorageType::kFileSystem:
172  default:
173  throw std::runtime_error("FSStorage has been removed in recent versions of aktualizr, please use SQLStorage");
174  }
175 }
176 
177 void INvStorage::FSSToSQLS(FSStorageRead& fs_storage, SQLStorage& sql_storage) {
178  std::string public_key;
179  std::string private_key;
180  if (fs_storage.loadPrimaryKeys(&public_key, &private_key)) {
181  sql_storage.storePrimaryKeys(public_key, private_key);
182  }
183 
184  std::string ca;
185  if (fs_storage.loadTlsCa(&ca)) {
186  sql_storage.storeTlsCa(ca);
187  }
188 
189  std::string cert;
190  if (fs_storage.loadTlsCert(&cert)) {
191  sql_storage.storeTlsCert(cert);
192  }
193 
194  std::string pkey;
195  if (fs_storage.loadTlsPkey(&pkey)) {
196  sql_storage.storeTlsPkey(pkey);
197  }
198 
199  std::string device_id;
200  if (fs_storage.loadDeviceId(&device_id)) {
201  sql_storage.storeDeviceId(device_id);
202  }
203 
204  EcuSerials serials;
205  if (fs_storage.loadEcuSerials(&serials)) {
206  sql_storage.storeEcuSerials(serials);
207  }
208 
209  if (fs_storage.loadEcuRegistered()) {
210  sql_storage.storeEcuRegistered();
211  }
212 
213  std::vector<MisconfiguredEcu> ecus;
214  if (fs_storage.loadMisconfiguredEcus(&ecus)) {
215  sql_storage.storeMisconfiguredEcus(ecus);
216  }
217 
219  if (fs_storage.loadInstallationResult(&res)) {
220  sql_storage.storeInstallationResult(res);
221  }
222 
223  std::vector<Uptane::Target> installed_versions;
224  std::string current_hash = fs_storage.loadInstalledVersions(&installed_versions);
225  if (installed_versions.size() != 0u) {
226  sql_storage.storeInstalledVersions(installed_versions, current_hash);
227  }
228 
229  // migrate latest versions of all metadata
230  for (auto role : Uptane::Role::Roles()) {
231  if (role == Uptane::Role::Root()) {
232  continue;
233  }
234 
235  std::string meta;
236  for (auto repo : {Uptane::RepositoryType::Director, Uptane::RepositoryType::Images}) {
237  if (fs_storage.loadNonRoot(&meta, repo, role)) {
238  sql_storage.storeNonRoot(meta, repo, role);
239  }
240  }
241  }
242  // additionally migrate the whole root metadata chain
243  std::string latest_root;
244  for (auto repo : {Uptane::RepositoryType::Director, Uptane::RepositoryType::Images}) {
245  if (fs_storage.loadLatestRoot(&latest_root, Uptane::RepositoryType::Director)) {
246  int latest_version = Uptane::extractVersionUntrusted(latest_root);
247  for (int version = 0; version <= latest_version; ++version) {
248  std::string root;
249  if (fs_storage.loadRoot(&root, repo, Uptane::Version(version))) {
250  sql_storage.storeRoot(root, repo, Uptane::Version(version));
251  }
252  }
253  }
254  }
255 
256  // if everything is ok, remove old files.
257  fs_storage.cleanUpAll();
258 }
259 
260 void INvStorage::saveInstalledVersion(const Uptane::Target& target) {
261  std::vector<Uptane::Target> versions;
262  std::string new_current_hash;
263  loadInstalledVersions(&versions);
264  if (std::find(versions.begin(), versions.end(), target) == versions.end()) {
265  versions.push_back(target);
266  }
267  storeInstalledVersions(versions, target.sha256Hash());
268 }
Metadata version numbers.
Definition: tuf.h:57