Aktualizr
C++ SOTA Client
fsstorage_read.cc
1 #include "fsstorage_read.h"
2 
3 #include <fcntl.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 
7 #include <iostream>
8 #include <utility>
9 
10 #include <boost/lexical_cast.hpp>
11 #include <boost/scoped_array.hpp>
12 #include "json/json.h"
13 
14 #include "logging/logging.h"
15 #include "utilities/utils.h"
16 
17 FSStorageRead::FSStorageRead(const StorageConfig& config) : config_(config) {
18  boost::filesystem::path images_path = config_.uptane_metadata_path.get(config_.path) / "repo";
19  boost::filesystem::path director_path = config_.uptane_metadata_path.get(config_.path) / "director";
20  // migrate from old unversioned Uptane root meta
21  {
22  for (auto repo : {Uptane::RepositoryType::Director, Uptane::RepositoryType::Images}) {
23  boost::filesystem::path& meta_dir = repo == (Uptane::RepositoryType::Director) ? director_path : images_path;
24  boost::filesystem::path meta_path = meta_dir / Uptane::Version().RoleFileName(Uptane::Role::Root());
25  if (boost::filesystem::exists(meta_path)) {
26  std::string data = Utils::readFile(meta_path);
27  Uptane::Version version{Uptane::extractVersionUntrusted(data)};
28  boost::filesystem::remove(meta_path);
29  if (version.version() >= 0) {
30  Utils::writeFile(meta_dir / version.RoleFileName(Uptane::Role::Root()), data);
31  }
32  }
33  }
34  }
35 
36  latest_director_root = findMaxVersion(director_path, Uptane::Role::Root());
37  latest_images_root = findMaxVersion(images_path, Uptane::Role::Root());
38 }
39 
40 bool FSStorageRead::loadPrimaryKeys(std::string* public_key, std::string* private_key) {
41  return loadPrimaryPublic(public_key) && loadPrimaryPrivate(private_key);
42 }
43 
44 bool FSStorageRead::loadPrimaryPublic(std::string* public_key) {
45  boost::filesystem::path public_key_path = config_.uptane_public_key_path.get(config_.path);
46  if (!boost::filesystem::exists(public_key_path)) {
47  return false;
48  }
49 
50  if (public_key != nullptr) {
51  *public_key = Utils::readFile(public_key_path.string());
52  }
53  return true;
54 }
55 
56 bool FSStorageRead::loadPrimaryPrivate(std::string* private_key) {
57  boost::filesystem::path private_key_path = config_.uptane_private_key_path.get(config_.path);
58  if (!boost::filesystem::exists(private_key_path)) {
59  return false;
60  }
61 
62  if (private_key != nullptr) {
63  *private_key = Utils::readFile(private_key_path.string());
64  }
65  return true;
66 }
67 
68 bool FSStorageRead::loadTlsCreds(std::string* ca, std::string* cert, std::string* pkey) {
69  boost::filesystem::path ca_path(config_.tls_cacert_path.get(config_.path));
70  boost::filesystem::path cert_path(config_.tls_clientcert_path.get(config_.path));
71  boost::filesystem::path pkey_path(config_.tls_pkey_path.get(config_.path));
72  if (!boost::filesystem::exists(ca_path) || boost::filesystem::is_directory(ca_path) ||
73  !boost::filesystem::exists(cert_path) || boost::filesystem::is_directory(cert_path) ||
74  !boost::filesystem::exists(pkey_path) || boost::filesystem::is_directory(pkey_path)) {
75  return false;
76  }
77  if (ca != nullptr) {
78  *ca = Utils::readFile(ca_path.string());
79  }
80  if (cert != nullptr) {
81  *cert = Utils::readFile(cert_path.string());
82  }
83  if (pkey != nullptr) {
84  *pkey = Utils::readFile(pkey_path.string());
85  }
86  return true;
87 }
88 
89 bool FSStorageRead::loadTlsCommon(std::string* data, const BasedPath& path_in) {
90  boost::filesystem::path path(path_in.get(config_.path));
91  if (!boost::filesystem::exists(path)) {
92  return false;
93  }
94 
95  if (data != nullptr) {
96  *data = Utils::readFile(path.string());
97  }
98 
99  return true;
100 }
101 
102 bool FSStorageRead::loadTlsCa(std::string* ca) { return loadTlsCommon(ca, config_.tls_cacert_path); }
103 
104 bool FSStorageRead::loadTlsCert(std::string* cert) { return loadTlsCommon(cert, config_.tls_clientcert_path); }
105 
106 bool FSStorageRead::loadTlsPkey(std::string* pkey) { return loadTlsCommon(pkey, config_.tls_pkey_path); }
107 
108 bool FSStorageRead::loadRoot(std::string* data, Uptane::RepositoryType repo, Uptane::Version version) {
109  boost::filesystem::path metafile;
110  switch (repo) {
111  case (Uptane::RepositoryType::Director):
112  if (version.version() < 0) {
113  version = latest_director_root;
114  }
115  metafile =
116  config_.uptane_metadata_path.get(config_.path) / "director" / version.RoleFileName(Uptane::Role::Root());
117  break;
118 
119  case (Uptane::RepositoryType::Images):
120  if (version.version() < 0) {
121  version = latest_director_root;
122  }
123  metafile = config_.uptane_metadata_path.get(config_.path) / "repo" / version.RoleFileName(Uptane::Role::Root());
124  break;
125 
126  default:
127  return false;
128  }
129 
130  if (version.version() < 0) {
131  return false;
132  }
133 
134  if (!boost::filesystem::exists(metafile)) {
135  return false;
136  }
137 
138  if (data != nullptr) {
139  *data = Utils::readFile(metafile);
140  }
141  return true;
142 }
143 
144 bool FSStorageRead::loadNonRoot(std::string* data, Uptane::RepositoryType repo, Uptane::Role role) {
145  boost::filesystem::path metafile;
146  switch (repo) {
147  case (Uptane::RepositoryType::Director):
148  metafile = config_.uptane_metadata_path.get(config_.path) / "director" / Uptane::Version().RoleFileName(role);
149  break;
150 
151  case (Uptane::RepositoryType::Images):
152  metafile = config_.uptane_metadata_path.get(config_.path) / "repo" / Uptane::Version().RoleFileName(role);
153  break;
154 
155  default:
156  return false;
157  }
158 
159  if (!boost::filesystem::exists(metafile)) {
160  return false;
161  }
162 
163  if (data != nullptr) {
164  *data = Utils::readFile(metafile);
165  }
166  return true;
167 }
168 
169 bool FSStorageRead::loadDeviceId(std::string* device_id) {
170  if (!boost::filesystem::exists(Utils::absolutePath(config_.path, "device_id").string())) {
171  return false;
172  }
173 
174  if (device_id != nullptr) {
175  *device_id = Utils::readFile(Utils::absolutePath(config_.path, "device_id").string());
176  }
177  return true;
178 }
179 
180 bool FSStorageRead::loadEcuRegistered() {
181  return boost::filesystem::exists(Utils::absolutePath(config_.path, "is_registered").string());
182 }
183 
184 bool FSStorageRead::loadEcuSerials(EcuSerials* serials) {
185  std::string buf;
186  std::string serial;
187  std::string hw_id;
188 
189  const boost::filesystem::path serial_path = Utils::absolutePath(config_.path, "primary_ecu_serial");
190  if (!boost::filesystem::exists(serial_path)) {
191  return false;
192  }
193  serial = Utils::readFile(serial_path.string());
194  // use default hardware ID for backwards compatibility
195  const boost::filesystem::path hw_id_path = Utils::absolutePath(config_.path, "primary_ecu_hardware_id");
196  if (!boost::filesystem::exists(hw_id_path)) {
197  hw_id = Utils::getHostname();
198  } else {
199  hw_id = Utils::readFile(hw_id_path.string());
200  }
201 
202  if (serials != nullptr) {
203  serials->push_back({Uptane::EcuSerial(serial), Uptane::HardwareIdentifier(hw_id)});
204  }
205 
206  // return true for backwards compatibility
207  const boost::filesystem::path sec_list_path = Utils::absolutePath(config_.path, "secondaries_list");
208  if (!boost::filesystem::exists(sec_list_path)) {
209  return true;
210  }
211  std::ifstream file(sec_list_path.c_str());
212  while (std::getline(file, buf)) {
213  size_t tab = buf.find('\t');
214  serial = buf.substr(0, tab);
215  try {
216  hw_id = buf.substr(tab + 1);
217  } catch (const std::out_of_range& e) {
218  if (serials != nullptr) {
219  serials->clear();
220  }
221  file.close();
222  return false;
223  }
224  if (serials != nullptr) {
225  serials->push_back({Uptane::EcuSerial(serial), Uptane::HardwareIdentifier(hw_id)});
226  }
227  }
228  file.close();
229  return true;
230 }
231 
232 bool FSStorageRead::loadMisconfiguredEcus(std::vector<MisconfiguredEcu>* ecus) {
233  if (!boost::filesystem::exists(Utils::absolutePath(config_.path, "misconfigured_ecus"))) {
234  return false;
235  }
236  Json::Value content_json = Utils::parseJSONFile(Utils::absolutePath(config_.path, "misconfigured_ecus").string());
237 
238  for (Json::ValueIterator it = content_json.begin(); it != content_json.end(); ++it) {
239  ecus->push_back(MisconfiguredEcu(Uptane::EcuSerial((*it)["serial"].asString()),
240  Uptane::HardwareIdentifier((*it)["hardware_id"].asString()),
241  static_cast<EcuState>((*it)["state"].asInt())));
242  }
243  return true;
244 }
245 
246 std::string FSStorageRead::loadInstalledVersions(std::vector<Uptane::Target>* installed_versions) {
247  std::string current_hash;
248  if (!boost::filesystem::exists(Utils::absolutePath(config_.path, "installed_versions"))) {
249  return current_hash;
250  }
251  Json::Value installed_versions_json =
252  Utils::parseJSONFile(Utils::absolutePath(config_.path, "installed_versions").string());
253  std::vector<Uptane::Target> new_versions;
254  for (Json::ValueIterator it = installed_versions_json.begin(); it != installed_versions_json.end(); ++it) {
255  if (!(*it).isObject()) {
256  // We loaded old format, migrate to new one.
257  Json::Value t_json;
258  t_json["hashes"]["sha256"] = it.key();
259  Uptane::Target t((*it).asString(), t_json);
260  new_versions.push_back(t);
261  } else {
262  if ((*it)["is_current"].asBool()) {
263  current_hash = (*it)["hashes"]["sha256"].asString();
264  }
265  Uptane::Target t(it.key().asString(), *it);
266  new_versions.push_back(t);
267  }
268  }
269  *installed_versions = new_versions;
270 
271  return current_hash;
272 }
273 
274 bool FSStorageRead::loadInstallationResult(data::OperationResult* result) {
275  if (!boost::filesystem::exists(Utils::absolutePath(config_.path, "installation_result").string())) {
276  return false;
277  }
278 
279  if (result != nullptr) {
280  *result = data::OperationResult::fromJson(
281  Utils::readFile(Utils::absolutePath(config_.path, "installation_result").string()));
282  }
283  return true;
284 }
285 
286 bool FSStorageRead::splitNameRoleVersion(const std::string& full_name, std::string* role_name, int* version) {
287  size_t dot_pos = full_name.find('.');
288 
289  // doesn't have a dot
290  if (dot_pos == std::string::npos) {
291  return false;
292  }
293  std::string prefix = full_name.substr(0, dot_pos);
294  if (role_name != nullptr) {
295  *role_name = full_name.substr(dot_pos + 1);
296  }
297 
298  try {
299  auto v = boost::lexical_cast<int>(prefix);
300  if (version != nullptr) {
301  *version = v;
302  }
303  } catch (const boost::bad_lexical_cast&) {
304  return false;
305  }
306  return true;
307 }
308 
309 Uptane::Version FSStorageRead::findMaxVersion(const boost::filesystem::path& meta_directory, Uptane::Role role) {
310  int version = -1;
311  if (!boost::filesystem::exists(meta_directory)) {
312  return {};
313  }
314 
315  boost::filesystem::directory_iterator it{meta_directory};
316  for (; it != boost::filesystem::directory_iterator(); ++it) {
317  if (!boost::filesystem::is_regular_file(it->path())) {
318  continue;
319  }
320  std::string name = it->path().filename().native();
321  int file_version;
322  std::string file_role;
323  if (splitNameRoleVersion(name, &file_role, &file_version)) {
324  if (file_role == Uptane::Version().RoleFileName(role) && file_version > version) {
325  version = file_version;
326  }
327  }
328  }
329 
330  return Uptane::Version(version);
331 }
332 
333 // clear methods, to clean the storage files after a migration
334 
335 void FSStorageRead::clearPrimaryKeys() {
336  boost::filesystem::remove(config_.uptane_public_key_path.get(config_.path));
337  boost::filesystem::remove(config_.uptane_private_key_path.get(config_.path));
338 }
339 
340 void FSStorageRead::clearTlsCreds() {
341  boost::filesystem::remove(config_.tls_cacert_path.get(config_.path));
342  boost::filesystem::remove(config_.tls_clientcert_path.get(config_.path));
343  boost::filesystem::remove(config_.tls_pkey_path.get(config_.path));
344 }
345 
346 void FSStorageRead::clearNonRootMeta(Uptane::RepositoryType repo) {
347  boost::filesystem::path meta_path;
348  switch (repo) {
349  case Uptane::RepositoryType::Images:
350  meta_path = config_.uptane_metadata_path.get(config_.path) / "repo";
351  break;
352  case Uptane::RepositoryType::Director:
353  meta_path = config_.uptane_metadata_path.get(config_.path) / "director";
354  break;
355  default:
356  return;
357  }
358 
359  boost::filesystem::directory_iterator it{meta_path};
360  for (; it != boost::filesystem::directory_iterator(); ++it) {
361  for (auto role : Uptane::Role::Roles()) {
362  if (role == Uptane::Role::Root()) {
363  continue;
364  }
365  std::string role_name;
366  std::string fn = it->path().filename().native();
367  if (fn == Uptane::Version().RoleFileName(role) ||
368  (splitNameRoleVersion(fn, &role_name, nullptr) && (role_name == Uptane::Version().RoleFileName(role)))) {
369  boost::filesystem::remove(it->path());
370  }
371  }
372  }
373 }
374 
375 void FSStorageRead::clearMetadata() {
376  for (const auto& meta_path : {config_.uptane_metadata_path.get(config_.path) / "repo",
377  config_.uptane_metadata_path.get(config_.path) / "director"}) {
378  if (!boost::filesystem::exists(meta_path)) {
379  return;
380  }
381 
382  boost::filesystem::directory_iterator it{meta_path};
383  for (; it != boost::filesystem::directory_iterator(); ++it) {
384  boost::filesystem::remove(it->path());
385  }
386  }
387 }
388 
389 void FSStorageRead::clearDeviceId() { boost::filesystem::remove(Utils::absolutePath(config_.path, "device_id")); }
390 
391 void FSStorageRead::clearEcuRegistered() {
392  boost::filesystem::remove(Utils::absolutePath(config_.path, "is_registered"));
393 }
394 
395 void FSStorageRead::clearEcuSerials() {
396  boost::filesystem::remove(Utils::absolutePath(config_.path, "primary_ecu_serial"));
397  boost::filesystem::remove(Utils::absolutePath(config_.path, "primary_ecu_hardware_id"));
398  boost::filesystem::remove(Utils::absolutePath(config_.path, "secondaries_list"));
399 }
400 
401 void FSStorageRead::clearMisconfiguredEcus() {
402  boost::filesystem::remove(Utils::absolutePath(config_.path, "misconfigured_ecus"));
403 }
404 
405 void FSStorageRead::clearInstalledVersions() {
406  if (boost::filesystem::exists(Utils::absolutePath(config_.path, "installed_versions"))) {
407  boost::filesystem::remove(Utils::absolutePath(config_.path, "installed_versions"));
408  }
409 }
410 
411 void FSStorageRead::clearInstallationResult() {
412  boost::filesystem::remove(Utils::absolutePath(config_.path, "installation_result"));
413 }
414 
415 void FSStorageRead::cleanUpAll() {
416  clearPrimaryKeys();
417  clearTlsCreds();
418  clearDeviceId();
419  clearEcuSerials();
420  clearEcuRegistered();
421  clearMisconfiguredEcus();
422  clearInstalledVersions();
423  clearInstallationResult();
424  clearMetadata();
425 
426  boost::filesystem::remove_all(config_.uptane_metadata_path.get(config_.path));
427  boost::filesystem::remove_all(config_.path / "targets");
428 }
General data structures.
Definition: types.cc:6
Metadata version numbers.
Definition: tuf.h:57
TUF Roles.
Definition: tuf.h:25
RepositoryType
This must match the repo_type table in sqlstorage.
Definition: tuf.h:18