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 image_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 metadata
21  {
22  for (auto repo : {Uptane::RepositoryType::Director(), Uptane::RepositoryType::Image()}) {
23  boost::filesystem::path& meta_dir = repo == (Uptane::RepositoryType::Director()) ? director_path : image_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_image_root = findMaxVersion(image_path, Uptane::Role::Root());
38 }
39 
40 bool FSStorageRead::loadPrimaryKeys(std::string* public_key, std::string* private_key) const {
41  return loadPrimaryPublic(public_key) && loadPrimaryPrivate(private_key);
42 }
43 
44 bool FSStorageRead::loadPrimaryPublic(std::string* public_key) const {
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) const {
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) const {
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 utils::BasedPath& path_in) const {
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) const { return loadTlsCommon(ca, config_.tls_cacert_path); }
103 
104 bool FSStorageRead::loadTlsCert(std::string* cert) const { return loadTlsCommon(cert, config_.tls_clientcert_path); }
105 
106 bool FSStorageRead::loadTlsPkey(std::string* pkey) const { return loadTlsCommon(pkey, config_.tls_pkey_path); }
107 
108 bool FSStorageRead::loadRoot(std::string* data, Uptane::RepositoryType repo, Uptane::Version version) const {
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::Image()):
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, const Uptane::Role& role) const {
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::Image()):
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) const {
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() const {
181  return boost::filesystem::exists(Utils::absolutePath(config_.path, "is_registered").string());
182 }
183 
184 bool FSStorageRead::loadEcuSerials(EcuSerials* serials) const {
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) const {
233  if (!boost::filesystem::exists(Utils::absolutePath(config_.path, "misconfigured_ecus"))) {
234  return false;
235  }
236 
237  try {
238  Json::Value content_json = Utils::parseJSONFile(Utils::absolutePath(config_.path, "misconfigured_ecus").string());
239  for (auto it = content_json.begin(); it != content_json.end(); ++it) {
240  ecus->push_back(MisconfiguredEcu(Uptane::EcuSerial((*it)["serial"].asString()),
241  Uptane::HardwareIdentifier((*it)["hardware_id"].asString()),
242  static_cast<EcuState>((*it)["state"].asInt())));
243  }
244  } catch (const std::exception& ex) {
245  LOG_ERROR << "Unable to parse misconfigured_ecus: " << ex.what();
246  return false;
247  }
248  return true;
249 }
250 
251 bool FSStorageRead::loadInstalledVersions(std::vector<Uptane::Target>* installed_versions,
252  size_t* current_version) const {
253  const boost::filesystem::path path = Utils::absolutePath(config_.path, "installed_versions");
254  return INvStorage::fsReadInstalledVersions(path, installed_versions, current_version);
255 }
256 
257 bool FSStorageRead::splitNameRoleVersion(const std::string& full_name, std::string* role_name, int* version) {
258  size_t dot_pos = full_name.find('.');
259 
260  // doesn't have a dot
261  if (dot_pos == std::string::npos) {
262  return false;
263  }
264  std::string prefix = full_name.substr(0, dot_pos);
265  if (role_name != nullptr) {
266  *role_name = full_name.substr(dot_pos + 1);
267  }
268 
269  try {
270  auto v = boost::lexical_cast<int>(prefix);
271  if (version != nullptr) {
272  *version = v;
273  }
274  } catch (const boost::bad_lexical_cast&) {
275  return false;
276  }
277  return true;
278 }
279 
280 Uptane::Version FSStorageRead::findMaxVersion(const boost::filesystem::path& meta_directory, const Uptane::Role& role) {
281  int version = -1;
282  if (!boost::filesystem::exists(meta_directory)) {
283  return {};
284  }
285 
286  boost::filesystem::directory_iterator it{meta_directory};
287  for (; it != boost::filesystem::directory_iterator(); ++it) {
288  if (!boost::filesystem::is_regular_file(it->path())) {
289  continue;
290  }
291  std::string name = it->path().filename().native();
292  int file_version;
293  std::string file_role;
294  if (splitNameRoleVersion(name, &file_role, &file_version)) {
295  if (file_role == Uptane::Version().RoleFileName(role) && file_version > version) {
296  version = file_version;
297  }
298  }
299  }
300 
301  return Uptane::Version(version);
302 }
303 
304 // clear methods, to clean the storage files after a migration
305 
306 void FSStorageRead::clearPrimaryKeys() {
307  boost::filesystem::remove(config_.uptane_public_key_path.get(config_.path));
308  boost::filesystem::remove(config_.uptane_private_key_path.get(config_.path));
309 }
310 
311 void FSStorageRead::clearTlsCreds() {
312  boost::filesystem::remove(config_.tls_cacert_path.get(config_.path));
313  boost::filesystem::remove(config_.tls_clientcert_path.get(config_.path));
314  boost::filesystem::remove(config_.tls_pkey_path.get(config_.path));
315 }
316 
317 void FSStorageRead::clearNonRootMeta(Uptane::RepositoryType repo) {
318  boost::filesystem::path meta_path;
319  switch (repo) {
320  case Uptane::RepositoryType::Image():
321  meta_path = config_.uptane_metadata_path.get(config_.path) / "repo";
322  break;
323  case Uptane::RepositoryType::Director():
324  meta_path = config_.uptane_metadata_path.get(config_.path) / "director";
325  break;
326  default:
327  return;
328  }
329 
330  boost::filesystem::directory_iterator it{meta_path};
331  for (; it != boost::filesystem::directory_iterator(); ++it) {
332  for (const auto& role : Uptane::Role::Roles()) {
333  if (role == Uptane::Role::Root()) {
334  continue;
335  }
336  std::string role_name;
337  std::string fn = it->path().filename().native();
338  if (fn == Uptane::Version().RoleFileName(role) ||
339  (splitNameRoleVersion(fn, &role_name, nullptr) && (role_name == Uptane::Version().RoleFileName(role)))) {
340  boost::filesystem::remove(it->path());
341  }
342  }
343  }
344 }
345 
346 void FSStorageRead::clearMetadata() {
347  for (const auto& meta_path : {config_.uptane_metadata_path.get(config_.path) / "repo",
348  config_.uptane_metadata_path.get(config_.path) / "director"}) {
349  if (!boost::filesystem::exists(meta_path)) {
350  return;
351  }
352 
353  boost::filesystem::directory_iterator it{meta_path};
354  for (; it != boost::filesystem::directory_iterator(); ++it) {
355  boost::filesystem::remove(it->path());
356  }
357  }
358 }
359 
360 void FSStorageRead::clearDeviceId() { boost::filesystem::remove(Utils::absolutePath(config_.path, "device_id")); }
361 
362 void FSStorageRead::clearEcuRegistered() {
363  boost::filesystem::remove(Utils::absolutePath(config_.path, "is_registered"));
364 }
365 
366 void FSStorageRead::clearEcuSerials() {
367  boost::filesystem::remove(Utils::absolutePath(config_.path, "primary_ecu_serial"));
368  boost::filesystem::remove(Utils::absolutePath(config_.path, "primary_ecu_hardware_id"));
369  boost::filesystem::remove(Utils::absolutePath(config_.path, "secondaries_list"));
370 }
371 
372 void FSStorageRead::clearMisconfiguredEcus() {
373  boost::filesystem::remove(Utils::absolutePath(config_.path, "misconfigured_ecus"));
374 }
375 
376 void FSStorageRead::clearInstalledVersions() {
377  if (boost::filesystem::exists(Utils::absolutePath(config_.path, "installed_versions"))) {
378  boost::filesystem::remove(Utils::absolutePath(config_.path, "installed_versions"));
379  }
380 }
381 
382 void FSStorageRead::clearInstallationResult() {
383  boost::filesystem::remove(Utils::absolutePath(config_.path, "installation_result"));
384 }
385 
386 void FSStorageRead::cleanUpAll() {
387  clearPrimaryKeys();
388  clearTlsCreds();
389  clearDeviceId();
390  clearEcuSerials();
391  clearEcuRegistered();
392  clearMisconfiguredEcus();
393  clearInstalledVersions();
394  clearInstallationResult();
395  clearMetadata();
396 
397  boost::filesystem::remove_all(config_.uptane_metadata_path.get(config_.path));
398  boost::filesystem::remove_all(config_.path / "targets");
399 }
400 
401 bool FSStorageRead::FSStoragePresent(const StorageConfig& config) {
402  return boost::filesystem::exists(Utils::absolutePath(config.path, "is_registered").string());
403 }
Uptane::Version
Metadata version numbers.
Definition: tuf.h:120
StorageConfig
Definition: config.h:111
MisconfiguredEcu
Definition: invstorage.h:29
data
General data structures.
Definition: types.h:217
Uptane::HardwareIdentifier
Definition: types.h:315
utils::BasedPath
The BasedPath class Can represent an absolute or relative path, only readable through the BasePath::g...
Definition: types.h:31
Uptane::RepositoryType
Definition: tuf.h:21
Uptane::EcuSerial
Definition: types.h:346
Uptane::Role
TUF Roles.
Definition: tuf.h:61