Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
sqlstorage.cc
1 #include "sqlstorage.h"
2 
3 #include <sys/stat.h>
4 #include <sys/statvfs.h>
5 #include <iostream>
6 #include <map>
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "logging/logging.h"
12 #include "sql_utils.h"
13 #include "utilities/utils.h"
14 
15 // find metadata with version set to -1 (e.g. after migration) and assign proper version to it
16 void SQLStorage::cleanMetaVersion(Uptane::RepositoryType repo, const Uptane::Role& role) {
17  SQLite3Guard db = dbConnection();
18 
19  db.beginTransaction();
20 
21  auto statement = db.prepareStatement<int, int, int>(
22  "SELECT meta FROM meta WHERE (repo=? AND meta_type=? AND version=?);", static_cast<int>(repo), role.ToInt(), -1);
23 
24  int result = statement.step();
25 
26  if (result == SQLITE_DONE) {
27  LOG_TRACE << "meta with role " << role.ToString() << " in repo " << repo.toString() << " not present in db";
28  return;
29  } else if (result != SQLITE_ROW) {
30  LOG_ERROR << "Can't get meta: " << db.errmsg();
31  return;
32  }
33  std::string meta = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
34 
35  int version = Uptane::extractVersionUntrusted(meta);
36  if (version < 0) {
37  LOG_ERROR << "Corrupted metadata";
38  return;
39  }
40 
41  // in there is already metadata with such version delete it
42  statement = db.prepareStatement<int, int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
43  static_cast<int>(repo), role.ToInt(), version);
44 
45  if (statement.step() != SQLITE_DONE) {
46  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
47  return;
48  }
49 
50  statement = db.prepareStatement<int, int, int, int>(
51  "UPDATE meta SET version = ? WHERE (repo=? AND meta_type=? AND version=?);", version, static_cast<int>(repo),
52  role.ToInt(), -1);
53 
54  if (statement.step() != SQLITE_DONE) {
55  LOG_ERROR << "Can't update metadata: " << db.errmsg();
56  return;
57  }
58 
59  db.commitTransaction();
60 }
61 
62 SQLStorage::SQLStorage(const StorageConfig& config, bool readonly)
63  : SQLStorageBase(config.sqldb_path.get(config.path), readonly, libaktualizr_schema_migrations,
64  libaktualizr_schema_rollback_migrations, libaktualizr_current_schema,
65  libaktualizr_current_schema_version),
66  INvStorage(config) {
67  try {
68  cleanMetaVersion(Uptane::RepositoryType::Director(), Uptane::Role::Root());
69  cleanMetaVersion(Uptane::RepositoryType::Image(), Uptane::Role::Root());
70  } catch (...) {
71  LOG_ERROR << "SQLite database metadata version migration failed";
72  }
73 }
74 
75 void SQLStorage::storePrimaryKeys(const std::string& public_key, const std::string& private_key) {
76  SQLite3Guard db = dbConnection();
77 
78  auto statement = db.prepareStatement<std::string>(
79  "INSERT OR REPLACE INTO primary_keys(unique_mark,public,private) VALUES (0,?,?);", public_key, private_key);
80  if (statement.step() != SQLITE_DONE) {
81  LOG_ERROR << "Can't set Primary keys: " << db.errmsg();
82  return;
83  }
84 }
85 
86 bool SQLStorage::loadPrimaryKeys(std::string* public_key, std::string* private_key) const {
87  return loadPrimaryPublic(public_key) && loadPrimaryPrivate(private_key);
88 }
89 
90 bool SQLStorage::loadPrimaryPublic(std::string* public_key) const {
91  SQLite3Guard db = dbConnection();
92 
93  auto statement = db.prepareStatement("SELECT public FROM primary_keys LIMIT 1;");
94 
95  int result = statement.step();
96  if (result == SQLITE_DONE) {
97  LOG_TRACE << "No public key in db";
98  return false;
99  } else if (result != SQLITE_ROW) {
100  LOG_ERROR << "Can't get public key: " << db.errmsg();
101  return false;
102  }
103 
104  auto pub = statement.get_result_col_str(0);
105  if (pub == boost::none) {
106  return false;
107  }
108 
109  if (public_key != nullptr) {
110  *public_key = std::move(pub.value());
111  }
112 
113  return true;
114 }
115 
116 bool SQLStorage::loadPrimaryPrivate(std::string* private_key) const {
117  SQLite3Guard db = dbConnection();
118 
119  auto statement = db.prepareStatement("SELECT private FROM primary_keys LIMIT 1;");
120 
121  int result = statement.step();
122  if (result == SQLITE_DONE) {
123  LOG_TRACE << "No private key in db";
124  return false;
125  } else if (result != SQLITE_ROW) {
126  LOG_ERROR << "Can't get private key: " << db.errmsg();
127  return false;
128  }
129 
130  auto priv = statement.get_result_col_str(0);
131  if (priv == boost::none) {
132  return false;
133  }
134 
135  if (private_key != nullptr) {
136  *private_key = std::move(priv.value());
137  }
138 
139  return true;
140 }
141 
142 void SQLStorage::clearPrimaryKeys() {
143  SQLite3Guard db = dbConnection();
144 
145  if (db.exec("DELETE FROM primary_keys;", nullptr, nullptr) != SQLITE_OK) {
146  LOG_ERROR << "Can't clear Primary keys: " << db.errmsg();
147  return;
148  }
149 }
150 
151 void SQLStorage::saveSecondaryInfo(const Uptane::EcuSerial& ecu_serial, const std::string& sec_type,
152  const PublicKey& public_key) {
153  SQLite3Guard db = dbConnection();
154 
155  std::stringstream key_type_ss;
156  key_type_ss << public_key.Type();
157  std::string key_type_str;
158  key_type_str = key_type_ss.str();
159  key_type_str.erase(std::remove(key_type_str.begin(), key_type_str.end(), '"'), key_type_str.end());
160 
161  db.beginTransaction();
162 
163  auto statement =
164  db.prepareStatement<std::string>("SELECT count(*) FROM secondary_ecus WHERE serial = ?;", ecu_serial.ToString());
165  if (statement.step() != SQLITE_ROW) {
166  throw std::runtime_error(db.errmsg().insert(0, "Can't get count of secondary_ecus table: "));
167  }
168 
169  const char* req;
170  if (statement.get_result_col_int(0) != 0) {
171  req = "UPDATE secondary_ecus SET sec_type = ?, public_key_type = ?, public_key = ? WHERE serial = ?;";
172  } else {
173  req =
174  "INSERT INTO secondary_ecus (serial, sec_type, public_key_type, public_key) SELECT "
175  "serial,?,?,? FROM ecus WHERE (serial = ? AND is_primary = 0);";
176  }
177 
178  statement = db.prepareStatement<std::string, std::string, std::string, std::string>(
179  req, sec_type, key_type_str, public_key.Value(), ecu_serial.ToString());
180  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
181  throw std::runtime_error(db.errmsg().insert(0, "Can't save Secondary key: "));
182  }
183 
184  db.commitTransaction();
185 }
186 
187 void SQLStorage::saveSecondaryData(const Uptane::EcuSerial& ecu_serial, const std::string& data) {
188  SQLite3Guard db = dbConnection();
189 
190  db.beginTransaction();
191 
192  auto statement =
193  db.prepareStatement<std::string>("SELECT count(*) FROM secondary_ecus WHERE serial = ?;", ecu_serial.ToString());
194  if (statement.step() != SQLITE_ROW) {
195  throw std::runtime_error(db.errmsg().insert(0, "Can't get count of secondary_ecus table: "));
196  }
197 
198  const char* req;
199  if (statement.get_result_col_int(0) != 0) {
200  req = "UPDATE secondary_ecus SET extra = ? WHERE serial = ?;";
201  } else {
202  req = "INSERT INTO secondary_ecus (extra, serial) VALUES (?,?);";
203  }
204 
205  statement = db.prepareStatement<std::string, std::string>(req, data, ecu_serial.ToString());
206  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
207  throw std::runtime_error(db.errmsg().insert(0, "Can't save Secondary data: "));
208  }
209 
210  db.commitTransaction();
211 }
212 
213 bool SQLStorage::loadSecondaryInfo(const Uptane::EcuSerial& ecu_serial, SecondaryInfo* secondary) const {
214  SQLite3Guard db = dbConnection();
215 
216  SecondaryInfo new_sec{};
217 
218  auto statement = db.prepareStatement<std::string>(
219  "SELECT serial, hardware_id, sec_type, public_key_type, public_key, extra FROM ecus LEFT JOIN secondary_ecus "
220  "USING "
221  "(serial) WHERE (serial = ? AND is_primary = 0);",
222  ecu_serial.ToString());
223  int statement_state = statement.step();
224  if (statement_state == SQLITE_DONE) {
225  LOG_TRACE << "Secondary ECU " << ecu_serial << " not found";
226  return false;
227  } else if (statement_state != SQLITE_ROW) {
228  LOG_ERROR << "Cannot load Secondary info: " << db.errmsg();
229  return false;
230  }
231 
232  try {
233  Uptane::EcuSerial serial = Uptane::EcuSerial(statement.get_result_col_str(0).value());
234  Uptane::HardwareIdentifier hw_id = Uptane::HardwareIdentifier(statement.get_result_col_str(1).value());
235  std::string sec_type = statement.get_result_col_str(2).value_or("");
236  std::string kt_str = statement.get_result_col_str(3).value_or("");
237  PublicKey key;
238  if (kt_str != "") {
239  KeyType key_type;
240  std::stringstream(kt_str) >> key_type;
241  key = PublicKey(statement.get_result_col_str(4).value_or(""), key_type);
242  }
243  std::string extra = statement.get_result_col_str(5).value_or("");
244  new_sec = SecondaryInfo{serial, hw_id, sec_type, key, extra};
245  } catch (const boost::bad_optional_access&) {
246  return false;
247  }
248 
249  if (secondary != nullptr) {
250  *secondary = std::move(new_sec);
251  }
252 
253  return true;
254 }
255 
256 bool SQLStorage::loadSecondariesInfo(std::vector<SecondaryInfo>* secondaries) const {
257  SQLite3Guard db = dbConnection();
258 
259  std::vector<SecondaryInfo> new_secs;
260 
261  bool empty = true;
262 
263  int statement_state;
264  auto statement = db.prepareStatement(
265  "SELECT serial, hardware_id, sec_type, public_key_type, public_key, extra FROM ecus LEFT JOIN secondary_ecus "
266  "USING "
267  "(serial) WHERE is_primary = 0 ORDER BY ecus.id;");
268  while ((statement_state = statement.step()) == SQLITE_ROW) {
269  try {
270  Uptane::EcuSerial serial = Uptane::EcuSerial(statement.get_result_col_str(0).value());
271  Uptane::HardwareIdentifier hw_id = Uptane::HardwareIdentifier(statement.get_result_col_str(1).value());
272  std::string sec_type = statement.get_result_col_str(2).value_or("");
273  std::string kt_str = statement.get_result_col_str(3).value_or("");
274  PublicKey key;
275  if (kt_str != "") {
276  KeyType key_type;
277  std::stringstream(kt_str) >> key_type;
278  key = PublicKey(statement.get_result_col_str(4).value_or(""), key_type);
279  }
280  std::string extra = statement.get_result_col_str(5).value_or("");
281  new_secs.emplace_back(SecondaryInfo{serial, hw_id, sec_type, key, extra});
282  empty = false;
283  } catch (const boost::bad_optional_access&) {
284  continue;
285  }
286  }
287  if (statement_state != SQLITE_DONE) {
288  LOG_ERROR << "Can't load Secondary info" << db.errmsg();
289  }
290 
291  if (secondaries != nullptr) {
292  *secondaries = std::move(new_secs);
293  }
294 
295  return !empty;
296 }
297 
298 void SQLStorage::storeTlsCreds(const std::string& ca, const std::string& cert, const std::string& pkey) {
299  storeTlsCa(ca);
300  storeTlsCert(cert);
301  storeTlsPkey(pkey);
302 }
303 
304 void SQLStorage::storeTlsCa(const std::string& ca) {
305  SQLite3Guard db = dbConnection();
306 
307  db.beginTransaction();
308 
309  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
310  if (statement.step() != SQLITE_ROW) {
311  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
312  return;
313  }
314 
315  const char* req;
316  if (statement.get_result_col_int(0) != 0) {
317  req = "UPDATE OR REPLACE tls_creds SET ca_cert = ?;";
318  } else {
319  req = "INSERT INTO tls_creds(ca_cert) VALUES (?);";
320  }
321 
322  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(ca));
323  if (statement.step() != SQLITE_DONE) {
324  LOG_ERROR << "Can't set ca_cert: " << db.errmsg();
325  return;
326  }
327 
328  db.commitTransaction();
329 }
330 
331 void SQLStorage::storeTlsCert(const std::string& cert) {
332  SQLite3Guard db = dbConnection();
333 
334  db.beginTransaction();
335 
336  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
337  if (statement.step() != SQLITE_ROW) {
338  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
339  return;
340  }
341 
342  const char* req;
343  if (statement.get_result_col_int(0) != 0) {
344  req = "UPDATE OR REPLACE tls_creds SET client_cert = ?;";
345  } else {
346  req = "INSERT INTO tls_creds(client_cert) VALUES (?);";
347  }
348 
349  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(cert));
350  if (statement.step() != SQLITE_DONE) {
351  LOG_ERROR << "Can't set client_cert: " << db.errmsg();
352  return;
353  }
354 
355  db.commitTransaction();
356 }
357 
358 void SQLStorage::storeTlsPkey(const std::string& pkey) {
359  SQLite3Guard db = dbConnection();
360 
361  db.beginTransaction();
362 
363  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
364  if (statement.step() != SQLITE_ROW) {
365  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
366  return;
367  }
368 
369  const char* req;
370  if (statement.get_result_col_int(0) != 0) {
371  req = "UPDATE OR REPLACE tls_creds SET client_pkey = ?;";
372  } else {
373  req = "INSERT INTO tls_creds(client_pkey) VALUES (?);";
374  }
375 
376  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(pkey));
377  if (statement.step() != SQLITE_DONE) {
378  LOG_ERROR << "Can't set client_pkey: " << db.errmsg();
379  return;
380  }
381 
382  db.commitTransaction();
383 }
384 
385 bool SQLStorage::loadTlsCreds(std::string* ca, std::string* cert, std::string* pkey) const {
386  SQLite3Guard db = dbConnection();
387 
388  db.beginTransaction();
389 
390  auto statement = db.prepareStatement("SELECT ca_cert, client_cert, client_pkey FROM tls_creds LIMIT 1;");
391 
392  int result = statement.step();
393  if (result == SQLITE_DONE) {
394  LOG_TRACE << "Tls creds not present";
395  return false;
396  } else if (result != SQLITE_ROW) {
397  LOG_ERROR << "Can't get tls_creds: " << db.errmsg();
398  return false;
399  }
400 
401  std::string ca_v;
402  std::string cert_v;
403  std::string pkey_v;
404  try {
405  ca_v = statement.get_result_col_str(0).value();
406  cert_v = statement.get_result_col_str(1).value();
407  pkey_v = statement.get_result_col_str(2).value();
408  } catch (const boost::bad_optional_access&) {
409  return false;
410  }
411 
412  if (ca != nullptr) {
413  *ca = std::move(ca_v);
414  }
415  if (cert != nullptr) {
416  *cert = std::move(cert_v);
417  }
418  if (pkey != nullptr) {
419  *pkey = std::move(pkey_v);
420  }
421 
422  db.commitTransaction();
423 
424  return true;
425 }
426 
427 void SQLStorage::clearTlsCreds() {
428  SQLite3Guard db = dbConnection();
429 
430  if (db.exec("DELETE FROM tls_creds;", nullptr, nullptr) != SQLITE_OK) {
431  LOG_ERROR << "Can't clear tls_creds: " << db.errmsg();
432  return;
433  }
434 }
435 
436 bool SQLStorage::loadTlsCa(std::string* ca) const {
437  SQLite3Guard db = dbConnection();
438 
439  auto statement = db.prepareStatement("SELECT ca_cert FROM tls_creds LIMIT 1;");
440 
441  int result = statement.step();
442  if (result == SQLITE_DONE) {
443  LOG_TRACE << "ca_cert not present";
444  return false;
445  } else if (result != SQLITE_ROW) {
446  LOG_ERROR << "Can't get ca_cert: " << db.errmsg();
447  return false;
448  }
449 
450  auto ca_r = statement.get_result_col_str(0);
451  if (ca_r == boost::none) {
452  return false;
453  }
454 
455  if (ca != nullptr) {
456  *ca = std::move(ca_r.value());
457  }
458 
459  return true;
460 }
461 
462 bool SQLStorage::loadTlsCert(std::string* cert) const {
463  SQLite3Guard db = dbConnection();
464 
465  auto statement = db.prepareStatement("SELECT client_cert FROM tls_creds LIMIT 1;");
466 
467  int result = statement.step();
468  if (result == SQLITE_DONE) {
469  LOG_TRACE << "client_cert not present in db";
470  return false;
471  } else if (result != SQLITE_ROW) {
472  LOG_ERROR << "Can't get client_cert: " << db.errmsg();
473  return false;
474  }
475 
476  auto cert_r = statement.get_result_col_str(0);
477  if (cert_r == boost::none) {
478  return false;
479  }
480 
481  if (cert != nullptr) {
482  *cert = std::move(cert_r.value());
483  }
484 
485  return true;
486 }
487 
488 bool SQLStorage::loadTlsPkey(std::string* pkey) const {
489  SQLite3Guard db = dbConnection();
490 
491  auto statement = db.prepareStatement("SELECT client_pkey FROM tls_creds LIMIT 1;");
492 
493  int result = statement.step();
494  if (result == SQLITE_DONE) {
495  LOG_TRACE << "client_pkey not present in db";
496  return false;
497  } else if (result != SQLITE_ROW) {
498  LOG_ERROR << "Can't get client_pkey: " << db.errmsg();
499  return false;
500  }
501 
502  auto pkey_r = statement.get_result_col_str(0);
503  if (pkey_r == boost::none) {
504  return false;
505  }
506 
507  if (pkey != nullptr) {
508  *pkey = std::move(pkey_r.value());
509  }
510 
511  return true;
512 }
513 
514 void SQLStorage::storeRoot(const std::string& data, Uptane::RepositoryType repo, Uptane::Version version) {
515  SQLite3Guard db = dbConnection();
516 
517  db.beginTransaction();
518 
519  auto del_statement =
520  db.prepareStatement<int, int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
521  static_cast<int>(repo), Uptane::Role::Root().ToInt(), version.version());
522 
523  if (del_statement.step() != SQLITE_DONE) {
524  LOG_ERROR << "Can't clear Root metadata: " << db.errmsg();
525  return;
526  }
527 
528  auto ins_statement = db.prepareStatement<SQLBlob, int, int, int>("INSERT INTO meta VALUES (?, ?, ?, ?);",
529  SQLBlob(data), static_cast<int>(repo),
530  Uptane::Role::Root().ToInt(), version.version());
531 
532  if (ins_statement.step() != SQLITE_DONE) {
533  LOG_ERROR << "Can't add metadata: " << db.errmsg();
534  return;
535  }
536 
537  db.commitTransaction();
538 }
539 
540 void SQLStorage::storeNonRoot(const std::string& data, Uptane::RepositoryType repo, const Uptane::Role role) {
541  SQLite3Guard db = dbConnection();
542 
543  db.beginTransaction();
544 
545  auto del_statement = db.prepareStatement<int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=?);",
546  static_cast<int>(repo), role.ToInt());
547 
548  if (del_statement.step() != SQLITE_DONE) {
549  LOG_ERROR << "Can't clear " << role.ToString() << " metadata: " << db.errmsg();
550  return;
551  }
552 
553  auto ins_statement =
554  db.prepareStatement<SQLBlob, int, int, int>("INSERT INTO meta VALUES (?, ?, ?, ?);", SQLBlob(data),
555  static_cast<int>(repo), role.ToInt(), Uptane::Version().version());
556 
557  if (ins_statement.step() != SQLITE_DONE) {
558  LOG_ERROR << "Can't add " << role.ToString() << "metadata: " << db.errmsg();
559  return;
560  }
561 
562  db.commitTransaction();
563 }
564 
565 bool SQLStorage::loadRoot(std::string* data, Uptane::RepositoryType repo, Uptane::Version version) const {
566  SQLite3Guard db = dbConnection();
567 
568  // version < 0 => latest metadata requested
569  if (version.version() < 0) {
570  auto statement = db.prepareStatement<int, int>(
571  "SELECT meta FROM meta WHERE (repo=? AND meta_type=?) ORDER BY version DESC LIMIT 1;", static_cast<int>(repo),
572  Uptane::Role::Root().ToInt());
573  int result = statement.step();
574 
575  if (result == SQLITE_DONE) {
576  LOG_TRACE << "Root metadata not present";
577  return false;
578  } else if (result != SQLITE_ROW) {
579  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
580  return false;
581  }
582  if (data != nullptr) {
583  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
584  }
585  } else {
586  auto statement =
587  db.prepareStatement<int, int, int>("SELECT meta FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
588  static_cast<int>(repo), Uptane::Role::Root().ToInt(), version.version());
589 
590  int result = statement.step();
591 
592  if (result == SQLITE_DONE) {
593  LOG_TRACE << "Root metadata not present";
594  return false;
595  } else if (result != SQLITE_ROW) {
596  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
597  return false;
598  }
599 
600  const auto blob = reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0));
601  if (blob == nullptr) {
602  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
603  return false;
604  }
605 
606  if (data != nullptr) {
607  *data = std::string(blob);
608  }
609  }
610 
611  return true;
612 }
613 
614 bool SQLStorage::loadNonRoot(std::string* data, Uptane::RepositoryType repo, const Uptane::Role role) const {
615  SQLite3Guard db = dbConnection();
616 
617  auto statement = db.prepareStatement<int, int>(
618  "SELECT meta FROM meta WHERE (repo=? AND meta_type=?) ORDER BY version DESC LIMIT 1;", static_cast<int>(repo),
619  role.ToInt());
620  int result = statement.step();
621 
622  if (result == SQLITE_DONE) {
623  LOG_TRACE << role.ToString() << " metadata not present";
624  return false;
625  } else if (result != SQLITE_ROW) {
626  LOG_ERROR << "Can't get " << role.ToString() << " metadata: " << db.errmsg();
627  return false;
628  }
629  if (data != nullptr) {
630  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
631  }
632 
633  return true;
634 }
635 
636 void SQLStorage::clearNonRootMeta(Uptane::RepositoryType repo) {
637  SQLite3Guard db = dbConnection();
638 
639  auto del_statement =
640  db.prepareStatement<int>("DELETE FROM meta WHERE (repo=? AND meta_type != 0);", static_cast<int>(repo));
641 
642  if (del_statement.step() != SQLITE_DONE) {
643  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
644  }
645 }
646 
647 void SQLStorage::clearMetadata() {
648  SQLite3Guard db = dbConnection();
649 
650  if (db.exec("DELETE FROM meta;", nullptr, nullptr) != SQLITE_OK) {
651  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
652  return;
653  }
654 }
655 
656 void SQLStorage::storeDelegation(const std::string& data, const Uptane::Role role) {
657  SQLite3Guard db = dbConnection();
658 
659  db.beginTransaction();
660 
661  auto statement = db.prepareStatement<SQLBlob, std::string>("INSERT OR REPLACE INTO delegations VALUES (?, ?);",
662  SQLBlob(data), role.ToString());
663 
664  if (statement.step() != SQLITE_DONE) {
665  LOG_ERROR << "Can't add delegation metadata: " << db.errmsg();
666  return;
667  }
668 
669  db.commitTransaction();
670 }
671 
672 bool SQLStorage::loadDelegation(std::string* data, const Uptane::Role role) const {
673  SQLite3Guard db = dbConnection();
674 
675  auto statement =
676  db.prepareStatement<std::string>("SELECT meta FROM delegations WHERE role_name=? LIMIT 1;", role.ToString());
677  int result = statement.step();
678 
679  if (result == SQLITE_DONE) {
680  LOG_TRACE << "Delegations metadata not present";
681  return false;
682  } else if (result != SQLITE_ROW) {
683  LOG_ERROR << "Can't get delegations metadata: " << db.errmsg();
684  return false;
685  }
686  if (data != nullptr) {
687  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
688  }
689 
690  return true;
691 }
692 
693 bool SQLStorage::loadAllDelegations(std::vector<std::pair<Uptane::Role, std::string>>& data) const {
694  bool result = false;
695 
696  try {
697  SQLite3Guard db = dbConnection();
698 
699  auto statement = db.prepareStatement("SELECT meta, role_name FROM delegations;");
700  auto statement_state = statement.step();
701 
702  if (statement_state == SQLITE_DONE) {
703  LOG_TRACE << "Delegations metadata are not present";
704  return true;
705  } else if (statement_state != SQLITE_ROW) {
706  LOG_ERROR << "Can't get delegations metadata: " << db.errmsg();
707  return false;
708  }
709 
710  do {
711  data.emplace_back(Uptane::Role::Delegation(statement.get_result_col_str(1).value()),
712  statement.get_result_col_blob(0).value());
713  } while ((statement_state = statement.step()) == SQLITE_ROW);
714 
715  result = true;
716  } catch (const std::exception& exc) {
717  LOG_ERROR << "Failed to fetch records from `delegations` table: " << exc.what();
718  }
719 
720  return result;
721 }
722 
723 void SQLStorage::deleteDelegation(const Uptane::Role role) {
724  SQLite3Guard db = dbConnection();
725 
726  auto statement = db.prepareStatement<std::string>("DELETE FROM delegations WHERE role_name=?;", role.ToString());
727  statement.step();
728 }
729 
730 void SQLStorage::clearDelegations() {
731  SQLite3Guard db = dbConnection();
732 
733  if (db.exec("DELETE FROM delegations;", nullptr, nullptr) != SQLITE_OK) {
734  LOG_ERROR << "Can't clear delegations metadata: " << db.errmsg();
735  }
736 }
737 
738 void SQLStorage::storeDeviceId(const std::string& device_id) {
739  SQLite3Guard db = dbConnection();
740 
741  auto statement = db.prepareStatement<std::string>(
742  "INSERT OR REPLACE INTO device_info(unique_mark,device_id,is_registered) VALUES(0,?,0);", device_id);
743  if (statement.step() != SQLITE_DONE) {
744  LOG_ERROR << "Can't set device ID: " << db.errmsg();
745  return;
746  }
747 }
748 
749 bool SQLStorage::loadDeviceId(std::string* device_id) const {
750  SQLite3Guard db = dbConnection();
751 
752  auto statement = db.prepareStatement("SELECT device_id FROM device_info LIMIT 1;");
753 
754  int result = statement.step();
755  if (result == SQLITE_DONE) {
756  LOG_TRACE << "device_id not present in db";
757  return false;
758  } else if (result != SQLITE_ROW) {
759  LOG_ERROR << "Can't get device ID: " << db.errmsg();
760  return false;
761  }
762 
763  auto did = statement.get_result_col_str(0);
764  if (did == boost::none) {
765  LOG_ERROR << "Empty device ID" << db.errmsg();
766  return false;
767  }
768 
769  if (device_id != nullptr) {
770  *device_id = std::move(did.value());
771  }
772 
773  return true;
774 }
775 
776 void SQLStorage::clearDeviceId() {
777  SQLite3Guard db = dbConnection();
778 
779  if (db.exec("DELETE FROM device_info;", nullptr, nullptr) != SQLITE_OK) {
780  LOG_ERROR << "Can't clear device ID: " << db.errmsg();
781  return;
782  }
783 }
784 
785 void SQLStorage::storeEcuRegistered() {
786  SQLite3Guard db = dbConnection();
787 
788  db.beginTransaction();
789 
790  auto statement = db.prepareStatement("SELECT count(*) FROM device_info;");
791  if (statement.step() != SQLITE_ROW) {
792  throw std::runtime_error("Could not get device_info count");
793  }
794  if (statement.get_result_col_int(0) != 1) {
795  throw std::runtime_error("Cannot set ECU registered if no device_info set");
796  }
797 
798  std::string req = "UPDATE device_info SET is_registered = 1";
799  if (db.exec(req.c_str(), nullptr, nullptr) != SQLITE_OK) {
800  LOG_ERROR << "Can't set is_registered: " << db.errmsg();
801  return;
802  }
803 
804  db.commitTransaction();
805 }
806 
807 bool SQLStorage::loadEcuRegistered() const {
808  SQLite3Guard db = dbConnection();
809 
810  auto statement = db.prepareStatement("SELECT is_registered FROM device_info LIMIT 1;");
811 
812  int result = statement.step();
813  if (result == SQLITE_DONE) {
814  return false;
815  } else if (result != SQLITE_ROW) {
816  LOG_ERROR << "Can't get is_registered in device_info " << db.errmsg();
817  return false;
818  }
819 
820  return statement.get_result_col_int(0) != 0;
821 }
822 
823 void SQLStorage::clearEcuRegistered() {
824  SQLite3Guard db = dbConnection();
825 
826  // note: if the table is empty, nothing is done but that's fine
827  std::string req = "UPDATE device_info SET is_registered = 0";
828  if (db.exec(req.c_str(), nullptr, nullptr) != SQLITE_OK) {
829  LOG_ERROR << "Can't set is_registered: " << db.errmsg();
830  return;
831  }
832 }
833 
834 void SQLStorage::storeNeedReboot() {
835  SQLite3Guard db = dbConnection();
836 
837  auto statement = db.prepareStatement<int>("INSERT OR REPLACE INTO need_reboot(unique_mark,flag) VALUES(0,?);", 1);
838  if (statement.step() != SQLITE_DONE) {
839  LOG_ERROR << "Can't set need_reboot: " << db.errmsg();
840  return;
841  }
842 }
843 
844 bool SQLStorage::loadNeedReboot(bool* need_reboot) const {
845  SQLite3Guard db = dbConnection();
846 
847  auto statement = db.prepareStatement("SELECT flag FROM need_reboot LIMIT 1;");
848 
849  int result = statement.step();
850  if (result == SQLITE_DONE) {
851  if (need_reboot != nullptr) {
852  *need_reboot = false;
853  }
854  return true;
855  } else if (result != SQLITE_ROW) {
856  LOG_ERROR << "Can't get need_reboot: " << db.errmsg();
857  return false;
858  }
859 
860  auto flag = static_cast<bool>(statement.get_result_col_int(0));
861  if (need_reboot != nullptr) {
862  *need_reboot = flag;
863  }
864 
865  return true;
866 }
867 
868 void SQLStorage::clearNeedReboot() {
869  SQLite3Guard db = dbConnection();
870 
871  if (db.exec("DELETE FROM need_reboot;", nullptr, nullptr) != SQLITE_OK) {
872  LOG_ERROR << "Can't clear need_reboot: " << db.errmsg();
873  return;
874  }
875 }
876 
877 void SQLStorage::storeEcuSerials(const EcuSerials& serials) {
878  if (serials.size() >= 1) {
879  SQLite3Guard db = dbConnection();
880 
881  db.beginTransaction();
882 
883  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
884  LOG_ERROR << "Can't clear ecus: " << db.errmsg();
885  return;
886  }
887 
888  // first is the Primary
889  std::string serial = serials[0].first.ToString();
890  std::string hwid = serials[0].second.ToString();
891  {
892  auto statement = db.prepareStatement<std::string, std::string>(
893  "INSERT INTO ecus(id, serial,hardware_id,is_primary) VALUES (0, ?,?,1);", serial, hwid);
894  if (statement.step() != SQLITE_DONE) {
895  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
896  return;
897  }
898 
899  // update lazily stored installed version
900  auto statement_ivupdate = db.prepareStatement<std::string>(
901  "UPDATE installed_versions SET ecu_serial = ? WHERE ecu_serial = '';", serial);
902 
903  if (statement_ivupdate.step() != SQLITE_DONE) {
904  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
905  return;
906  }
907  }
908 
909  for (auto it = serials.cbegin() + 1; it != serials.cend(); it++) {
910  auto statement = db.prepareStatement<int64_t, std::string, std::string>(
911  "INSERT INTO ecus(id,serial,hardware_id) VALUES (?,?,?);", it - serials.cbegin(), it->first.ToString(),
912  it->second.ToString());
913 
914  if (statement.step() != SQLITE_DONE) {
915  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
916  return;
917  }
918  }
919 
920  db.commitTransaction();
921  }
922 }
923 
924 bool SQLStorage::loadEcuSerials(EcuSerials* serials) const {
925  SQLite3Guard db = dbConnection();
926 
927  // order by auto-incremented Primary key so that the ECU order is kept constant
928  auto statement = db.prepareStatement("SELECT serial, hardware_id FROM ecus ORDER BY id;");
929  int statement_state;
930 
931  EcuSerials new_serials;
932  bool empty = true;
933  while ((statement_state = statement.step()) == SQLITE_ROW) {
934  try {
935  new_serials.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
936  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()));
937  empty = false;
938  } catch (const boost::bad_optional_access&) {
939  return false;
940  }
941  }
942 
943  if (statement_state != SQLITE_DONE) {
944  LOG_ERROR << "Can't get ECU serials: " << db.errmsg();
945  return false;
946  }
947 
948  if (serials != nullptr) {
949  *serials = std::move(new_serials);
950  }
951 
952  return !empty;
953 }
954 
955 void SQLStorage::clearEcuSerials() {
956  SQLite3Guard db = dbConnection();
957 
958  db.beginTransaction();
959 
960  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
961  LOG_ERROR << "Can't clear ECUs: " << db.errmsg();
962  return;
963  }
964 
965  if (db.exec("DELETE FROM secondary_ecus;", nullptr, nullptr) != SQLITE_OK) {
966  LOG_ERROR << "Can't clear Secondary ECUs: " << db.errmsg();
967  return;
968  }
969 
970  db.commitTransaction();
971 }
972 
973 void SQLStorage::storeCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, const std::string& manifest) {
974  SQLite3Guard db = dbConnection();
975 
976  auto statement = db.prepareStatement<std::string, std::string>(
977  "UPDATE secondary_ecus SET manifest = ? WHERE (serial = ?);", manifest, ecu_serial.ToString());
978  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
979  LOG_ERROR << "Can't save Secondary manifest " << db.errmsg();
980  return;
981  }
982 }
983 
984 bool SQLStorage::loadCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, std::string* manifest) const {
985  SQLite3Guard db = dbConnection();
986 
987  std::string stmanifest;
988 
989  bool empty = false;
990 
991  auto statement = db.prepareStatement<std::string>("SELECT manifest FROM secondary_ecus WHERE (serial = ?);",
992  ecu_serial.ToString());
993 
994  if (statement.step() != SQLITE_ROW) {
995  LOG_WARNING << "Could not find manifest for ECU " << ecu_serial;
996  return false;
997  } else {
998  stmanifest = statement.get_result_col_str(0).value_or("");
999 
1000  empty = stmanifest == "";
1001  }
1002 
1003  if (manifest != nullptr) {
1004  *manifest = std::move(stmanifest);
1005  }
1006 
1007  return !empty;
1008 }
1009 
1010 void SQLStorage::storeMisconfiguredEcus(const std::vector<MisconfiguredEcu>& ecus) {
1011  if (ecus.size() >= 1) {
1012  SQLite3Guard db = dbConnection();
1013 
1014  db.beginTransaction();
1015 
1016  if (db.exec("DELETE FROM misconfigured_ecus;", nullptr, nullptr) != SQLITE_OK) {
1017  LOG_ERROR << "Can't clear misconfigured_ecus: " << db.errmsg();
1018  return;
1019  }
1020 
1021  std::vector<MisconfiguredEcu>::const_iterator it;
1022  for (it = ecus.begin(); it != ecus.end(); it++) {
1023  auto statement = db.prepareStatement<std::string, std::string, int>(
1024  "INSERT INTO misconfigured_ecus VALUES (?,?,?);", it->serial.ToString(), it->hardware_id.ToString(),
1025  static_cast<int>(it->state));
1026 
1027  if (statement.step() != SQLITE_DONE) {
1028  LOG_ERROR << "Can't set misconfigured_ecus: " << db.errmsg();
1029  return;
1030  }
1031  }
1032 
1033  db.commitTransaction();
1034  }
1035 }
1036 
1037 bool SQLStorage::loadMisconfiguredEcus(std::vector<MisconfiguredEcu>* ecus) const {
1038  SQLite3Guard db = dbConnection();
1039 
1040  auto statement = db.prepareStatement("SELECT serial, hardware_id, state FROM misconfigured_ecus;");
1041  int statement_state;
1042 
1043  std::vector<MisconfiguredEcu> new_ecus;
1044  bool empty = true;
1045  while ((statement_state = statement.step()) == SQLITE_ROW) {
1046  try {
1047  new_ecus.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
1048  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()),
1049  static_cast<EcuState>(statement.get_result_col_int(2)));
1050  empty = false;
1051  } catch (const boost::bad_optional_access&) {
1052  return false;
1053  }
1054  }
1055 
1056  if (statement_state != SQLITE_DONE) {
1057  LOG_ERROR << "Can't get misconfigured_ecus: " << db.errmsg();
1058  return false;
1059  }
1060 
1061  if (ecus != nullptr) {
1062  *ecus = std::move(new_ecus);
1063  }
1064 
1065  return !empty;
1066 }
1067 
1068 void SQLStorage::clearMisconfiguredEcus() {
1069  SQLite3Guard db = dbConnection();
1070 
1071  if (db.exec("DELETE FROM misconfigured_ecus;", nullptr, nullptr) != SQLITE_OK) {
1072  LOG_ERROR << "Can't clear misconfigured_ecus: " << db.errmsg();
1073  return;
1074  }
1075 }
1076 
1077 void SQLStorage::saveInstalledVersion(const std::string& ecu_serial, const Uptane::Target& target,
1078  InstalledVersionUpdateMode update_mode) {
1079  SQLite3Guard db = dbConnection();
1080 
1081  db.beginTransaction();
1082 
1083  // either adds a new entry or update the last one's status
1084 
1085  // empty serial: use Primary
1086  std::string ecu_serial_real = ecu_serial;
1087  if (ecu_serial_real.empty()) {
1088  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1089  if (statement.step() == SQLITE_ROW) {
1090  ecu_serial_real = statement.get_result_col_str(0).value();
1091  } else {
1092  LOG_WARNING << "Could not find Primary ECU serial, set to lazy init mode";
1093  }
1094  }
1095 
1096  std::string hashes_encoded = Hash::encodeVector(target.hashes());
1097 
1098  // get the last time this version was installed on this ecu
1099  boost::optional<int64_t> old_id;
1100  bool old_was_installed = false;
1101  {
1102  auto statement = db.prepareStatement<std::string>(
1103  "SELECT id, sha256, name, was_installed FROM installed_versions WHERE ecu_serial = ? ORDER BY id DESC "
1104  "LIMIT 1;",
1105  ecu_serial_real);
1106 
1107  if (statement.step() == SQLITE_ROW) {
1108  int64_t rid = statement.get_result_col_int(0);
1109  std::string rsha256 = statement.get_result_col_str(1).value_or("");
1110  std::string rname = statement.get_result_col_str(2).value_or("");
1111  bool rwasi = statement.get_result_col_int(3) == 1;
1112 
1113  if (rsha256 == target.sha256Hash() && rname == target.filename()) {
1114  old_id = rid;
1115  old_was_installed = rwasi;
1116  }
1117  }
1118  }
1119 
1120  if (update_mode == InstalledVersionUpdateMode::kCurrent) {
1121  // unset 'current' and 'pending' on all versions for this ecu
1122  auto statement = db.prepareStatement<std::string>(
1123  "UPDATE installed_versions SET is_current = 0, is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1124  if (statement.step() != SQLITE_DONE) {
1125  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1126  return;
1127  }
1128  } else if (update_mode == InstalledVersionUpdateMode::kPending) {
1129  // unset 'pending' on all versions for this ecu
1130  auto statement = db.prepareStatement<std::string>(
1131  "UPDATE installed_versions SET is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1132  if (statement.step() != SQLITE_DONE) {
1133  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1134  return;
1135  }
1136  }
1137 
1138  if (!!old_id) {
1139  auto statement = db.prepareStatement<std::string, int, int, int64_t>(
1140  "UPDATE installed_versions SET correlation_id = ?, is_current = ?, is_pending = ?, was_installed = ? WHERE id "
1141  "= ?;",
1142  target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1143  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1144  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent || old_was_installed), old_id.value());
1145 
1146  if (statement.step() != SQLITE_DONE) {
1147  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1148  return;
1149  }
1150  } else {
1151  std::string custom = Utils::jsonToCanonicalStr(target.custom_data());
1152  auto statement = db.prepareStatement<std::string, std::string, std::string, std::string, int64_t, std::string,
1153  std::string, int, int>(
1154  "INSERT INTO installed_versions(ecu_serial, sha256, name, hashes, length, custom_meta, correlation_id, "
1155  "is_current, is_pending, was_installed) VALUES (?,?,?,?,?,?,?,?,?,?);",
1156  ecu_serial_real, target.sha256Hash(), target.filename(), hashes_encoded, static_cast<int64_t>(target.length()),
1157  custom, target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1158  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1159  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent));
1160 
1161  if (statement.step() != SQLITE_DONE) {
1162  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1163  return;
1164  }
1165  }
1166 
1167  db.commitTransaction();
1168 }
1169 
1170 static void loadEcuMap(SQLite3Guard& db, std::string& ecu_serial, Uptane::EcuMap& ecu_map) {
1171  // The Secondary only knows about itself and in its database it is considered
1172  // a Primary, for better or worse.
1173  if (ecu_serial.empty()) {
1174  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1175  if (statement.step() == SQLITE_ROW) {
1176  ecu_serial = statement.get_result_col_str(0).value();
1177  } else if (statement.step() == SQLITE_DONE) {
1178  LOG_DEBUG << "No serial found in database for this ECU, defaulting to empty serial";
1179  } else {
1180  LOG_ERROR << "Error getting serial for this ECU, defaulting to empty serial: " << db.errmsg();
1181  }
1182  }
1183 
1184  if (!ecu_serial.empty()) {
1185  auto statement = db.prepareStatement<std::string>("SELECT hardware_id FROM ecus WHERE serial = ?;", ecu_serial);
1186  if (statement.step() == SQLITE_ROW) {
1187  ecu_map.insert(
1188  {Uptane::EcuSerial(ecu_serial), Uptane::HardwareIdentifier(statement.get_result_col_str(0).value())});
1189  } else if (statement.step() == SQLITE_DONE) {
1190  LOG_DEBUG << "No hardware ID found in database for ECU serial " << ecu_serial;
1191  } else {
1192  LOG_ERROR << "Error getting hardware ID for ECU serial " << ecu_serial << ": " << db.errmsg();
1193  }
1194  }
1195 }
1196 
1197 bool SQLStorage::loadInstallationLog(const std::string& ecu_serial, std::vector<Uptane::Target>* log,
1198  bool only_installed) const {
1199  SQLite3Guard db = dbConnection();
1200 
1201  std::string ecu_serial_real = ecu_serial;
1202  Uptane::EcuMap ecu_map;
1203  loadEcuMap(db, ecu_serial_real, ecu_map);
1204 
1205  std::string query =
1206  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1207  "ecu_serial = ? ORDER BY id;";
1208  if (only_installed) {
1209  query =
1210  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1211  "ecu_serial = ? AND was_installed = 1 ORDER BY id;";
1212  }
1213 
1214  auto statement = db.prepareStatement<std::string>(query, ecu_serial_real);
1215  int statement_state;
1216 
1217  std::vector<Uptane::Target> new_log;
1218  std::map<int64_t, size_t> ids_map;
1219  size_t k = 0;
1220  while ((statement_state = statement.step()) == SQLITE_ROW) {
1221  try {
1222  auto id = statement.get_result_col_int(0);
1223  auto sha256 = statement.get_result_col_str(1).value();
1224  auto filename = statement.get_result_col_str(2).value();
1225  auto hashes_str = statement.get_result_col_str(3).value();
1226  auto length = statement.get_result_col_int(4);
1227  auto correlation_id = statement.get_result_col_str(5).value();
1228  auto custom_str = statement.get_result_col_str(6).value();
1229 
1230  // note: sha256 should always be present and is used to uniquely identify
1231  // a version. It should normally be part of the hash list as well.
1232  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1233 
1234  auto find_sha256 =
1235  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1236  if (find_sha256 == hashes.cend()) {
1237  LOG_WARNING << "No sha256 in hashes list";
1238  hashes.emplace_back(Hash::Type::kSha256, sha256);
1239  }
1240 
1241  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1242  if (!custom_str.empty()) {
1243  std::istringstream css(custom_str);
1244  std::string errs;
1245  Json::Value custom;
1246  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, nullptr)) {
1247  t.updateCustom(custom);
1248  } else {
1249  LOG_ERROR << "Unable to parse custom data: " << errs;
1250  }
1251  }
1252  new_log.emplace_back(t);
1253 
1254  ids_map[id] = k;
1255  k++;
1256  } catch (const boost::bad_optional_access&) {
1257  LOG_ERROR << "Incompleted installed version, keeping old one";
1258  return false;
1259  }
1260  }
1261 
1262  if (statement_state != SQLITE_DONE) {
1263  LOG_ERROR << "Can't get installed_versions: " << db.errmsg();
1264  return false;
1265  }
1266 
1267  if (log == nullptr) {
1268  return true;
1269  }
1270 
1271  *log = std::move(new_log);
1272 
1273  return true;
1274 }
1275 
1276 bool SQLStorage::loadInstalledVersions(const std::string& ecu_serial, boost::optional<Uptane::Target>* current_version,
1277  boost::optional<Uptane::Target>* pending_version) const {
1278  SQLite3Guard db = dbConnection();
1279 
1280  std::string ecu_serial_real = ecu_serial;
1281  Uptane::EcuMap ecu_map;
1282  loadEcuMap(db, ecu_serial_real, ecu_map);
1283 
1284  auto read_target = [&ecu_map](SQLiteStatement& statement) -> Uptane::Target {
1285  auto sha256 = statement.get_result_col_str(0).value();
1286  auto filename = statement.get_result_col_str(1).value();
1287  auto hashes_str = statement.get_result_col_str(2).value();
1288  auto length = statement.get_result_col_int(3);
1289  auto correlation_id = statement.get_result_col_str(4).value();
1290  auto custom_str = statement.get_result_col_str(5).value();
1291 
1292  // note: sha256 should always be present and is used to uniquely identify
1293  // a version. It should normally be part of the hash list as well.
1294  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1295 
1296  auto find_sha256 =
1297  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1298  if (find_sha256 == hashes.cend()) {
1299  LOG_WARNING << "No sha256 in hashes list";
1300  hashes.emplace_back(Hash::Type::kSha256, sha256);
1301  }
1302  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1303  if (!custom_str.empty()) {
1304  std::istringstream css(custom_str);
1305  Json::Value custom;
1306  std::string errs;
1307  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, &errs)) {
1308  t.updateCustom(custom);
1309  } else {
1310  LOG_ERROR << "Unable to parse custom data: " << errs;
1311  }
1312  }
1313 
1314  return t;
1315  };
1316 
1317  if (current_version != nullptr) {
1318  auto statement = db.prepareStatement<std::string>(
1319  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1320  "ecu_serial = ? AND is_current = 1 LIMIT 1;",
1321  ecu_serial_real);
1322 
1323  if (statement.step() == SQLITE_ROW) {
1324  try {
1325  *current_version = read_target(statement);
1326  } catch (const boost::bad_optional_access&) {
1327  LOG_ERROR << "Could not read current installed version";
1328  return false;
1329  }
1330  } else {
1331  LOG_TRACE << "Cannot get current installed version: " << db.errmsg();
1332  *current_version = boost::none;
1333  }
1334  }
1335 
1336  if (pending_version != nullptr) {
1337  auto statement = db.prepareStatement<std::string>(
1338  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1339  "ecu_serial = ? AND is_pending = 1 LIMIT 1;",
1340  ecu_serial_real);
1341 
1342  if (statement.step() == SQLITE_ROW) {
1343  try {
1344  *pending_version = read_target(statement);
1345  } catch (const boost::bad_optional_access&) {
1346  LOG_ERROR << "Could not read pending installed version";
1347  return false;
1348  }
1349  } else {
1350  LOG_TRACE << "Cannot get pending installed version: " << db.errmsg();
1351  *pending_version = boost::none;
1352  }
1353  }
1354 
1355  return true;
1356 }
1357 
1358 bool SQLStorage::hasPendingInstall() {
1359  SQLite3Guard db = dbConnection();
1360 
1361  auto statement = db.prepareStatement("SELECT count(*) FROM installed_versions where is_pending = 1");
1362  if (statement.step() != SQLITE_ROW) {
1363  LOG_ERROR << "Can't get tables count: " << db.errmsg();
1364  throw std::runtime_error("Could not count pending installations");
1365  }
1366 
1367  return statement.get_result_col_int(0) > 0;
1368 }
1369 
1370 void SQLStorage::getPendingEcus(std::vector<std::pair<Uptane::EcuSerial, Hash>>* pendingEcus) {
1371  SQLite3Guard db = dbConnection();
1372 
1373  auto statement = db.prepareStatement("SELECT ecu_serial, sha256 FROM installed_versions where is_pending = 1");
1374  int statement_result = statement.step();
1375  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1376  throw std::runtime_error("Failed to get ECUs with a pending target installation: " + db.errmsg());
1377  }
1378 
1379  std::vector<std::pair<Uptane::EcuSerial, Hash>> ecu_res;
1380 
1381  if (statement_result == SQLITE_DONE) {
1382  // if there are no any record in the DB
1383  return;
1384  }
1385 
1386  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1387  std::string ecu_serial = statement.get_result_col_str(0).value();
1388  std::string hash = statement.get_result_col_str(1).value();
1389  ecu_res.emplace_back(std::make_pair(Uptane::EcuSerial(ecu_serial), Hash(Hash::Type::kSha256, hash)));
1390  }
1391 
1392  if (pendingEcus != nullptr) {
1393  *pendingEcus = std::move(ecu_res);
1394  }
1395 }
1396 
1397 void SQLStorage::clearInstalledVersions() {
1398  SQLite3Guard db = dbConnection();
1399 
1400  if (db.exec("DELETE FROM installed_versions;", nullptr, nullptr) != SQLITE_OK) {
1401  LOG_ERROR << "Can't clear installed_versions: " << db.errmsg();
1402  return;
1403  }
1404 }
1405 
1406 void SQLStorage::saveEcuInstallationResult(const Uptane::EcuSerial& ecu_serial,
1407  const data::InstallationResult& result) {
1408  SQLite3Guard db = dbConnection();
1409 
1410  auto statement = db.prepareStatement<std::string, int, std::string, std::string>(
1411  "INSERT OR REPLACE INTO ecu_installation_results (ecu_serial, success, result_code, description) VALUES "
1412  "(?,?,?,?);",
1413  ecu_serial.ToString(), static_cast<int>(result.success), result.result_code.toRepr(), result.description);
1414  if (statement.step() != SQLITE_DONE) {
1415  LOG_ERROR << "Can't set ECU installation result: " << db.errmsg();
1416  return;
1417  }
1418 }
1419 
1420 bool SQLStorage::loadEcuInstallationResults(
1421  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>>* results) const {
1422  SQLite3Guard db = dbConnection();
1423 
1424  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> ecu_res;
1425 
1426  // keep the same order as in ECUs (start with Primary)
1427  auto statement = db.prepareStatement(
1428  "SELECT ecu_serial, success, result_code, description FROM ecu_installation_results INNER JOIN ecus ON "
1429  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1430  int statement_result = statement.step();
1431  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1432  LOG_ERROR << "Can't get ecu_installation_results: " << db.errmsg();
1433  return false;
1434  }
1435 
1436  if (statement_result == SQLITE_DONE) {
1437  // if there are no any record in the DB
1438  return false;
1439  }
1440 
1441  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1442  try {
1443  std::string ecu_serial = statement.get_result_col_str(0).value();
1444  auto success = static_cast<bool>(statement.get_result_col_int(1));
1445  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(2).value());
1446  std::string description = statement.get_result_col_str(3).value();
1447 
1448  ecu_res.emplace_back(Uptane::EcuSerial(ecu_serial), data::InstallationResult(success, result_code, description));
1449  } catch (const boost::bad_optional_access&) {
1450  return false;
1451  }
1452  }
1453 
1454  if (results != nullptr) {
1455  *results = std::move(ecu_res);
1456  }
1457 
1458  return true;
1459 }
1460 
1461 void SQLStorage::storeDeviceInstallationResult(const data::InstallationResult& result, const std::string& raw_report,
1462  const std::string& correlation_id) {
1463  SQLite3Guard db = dbConnection();
1464 
1465  auto statement = db.prepareStatement<int, std::string, std::string, std::string, std::string>(
1466  "INSERT OR REPLACE INTO device_installation_result (unique_mark, success, result_code, description, raw_report, "
1467  "correlation_id) "
1468  "VALUES (0,?,?,?,?,?);",
1469  static_cast<int>(result.success), result.result_code.toRepr(), result.description, raw_report, correlation_id);
1470  if (statement.step() != SQLITE_DONE) {
1471  LOG_ERROR << "Can't set device installation result: " << db.errmsg();
1472  return;
1473  }
1474 }
1475 
1476 bool SQLStorage::loadDeviceInstallationResult(data::InstallationResult* result, std::string* raw_report,
1477  std::string* correlation_id) const {
1478  SQLite3Guard db = dbConnection();
1479 
1480  data::InstallationResult dev_res;
1481  std::string raw_report_res;
1482  std::string corrid_res;
1483 
1484  auto statement = db.prepareStatement(
1485  "SELECT success, result_code, description, raw_report, correlation_id FROM device_installation_result;");
1486  int statement_result = statement.step();
1487  if (statement_result == SQLITE_DONE) {
1488  LOG_TRACE << "No device installation result in db";
1489  return false;
1490  } else if (statement_result != SQLITE_ROW) {
1491  LOG_ERROR << "Can't get device_installation_result: " << db.errmsg();
1492  return false;
1493  }
1494 
1495  try {
1496  auto success = static_cast<bool>(statement.get_result_col_int(0));
1497  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(1).value());
1498  std::string description = statement.get_result_col_str(2).value();
1499  raw_report_res = statement.get_result_col_str(3).value();
1500  corrid_res = statement.get_result_col_str(4).value();
1501 
1502  dev_res = data::InstallationResult(success, result_code, description);
1503  } catch (const boost::bad_optional_access&) {
1504  return false;
1505  }
1506 
1507  if (result != nullptr) {
1508  *result = std::move(dev_res);
1509  }
1510 
1511  if (raw_report != nullptr) {
1512  *raw_report = std::move(raw_report_res);
1513  }
1514 
1515  if (correlation_id != nullptr) {
1516  *correlation_id = std::move(corrid_res);
1517  }
1518 
1519  return true;
1520 }
1521 
1522 void SQLStorage::saveEcuReportCounter(const Uptane::EcuSerial& ecu_serial, const int64_t counter) {
1523  SQLite3Guard db = dbConnection();
1524 
1525  auto statement = db.prepareStatement<std::string, int64_t>(
1526  "INSERT OR REPLACE INTO ecu_report_counter (ecu_serial, counter) VALUES "
1527  "(?,?);",
1528  ecu_serial.ToString(), counter);
1529  if (statement.step() != SQLITE_DONE) {
1530  LOG_ERROR << "Can't set ECU counter: " << db.errmsg();
1531  return;
1532  }
1533 }
1534 
1535 bool SQLStorage::loadEcuReportCounter(std::vector<std::pair<Uptane::EcuSerial, int64_t>>* results) const {
1536  SQLite3Guard db = dbConnection();
1537 
1538  std::vector<std::pair<Uptane::EcuSerial, int64_t>> ecu_cnt;
1539 
1540  // keep the same order as in ECUs (start with Primary)
1541  auto statement = db.prepareStatement(
1542  "SELECT ecu_serial, counter FROM ecu_report_counter INNER JOIN ecus ON "
1543  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1544  int statement_result = statement.step();
1545  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1546  LOG_ERROR << "Can't get ecu_report_counter: " << db.errmsg();
1547  return false;
1548  }
1549 
1550  if (statement_result == SQLITE_DONE) {
1551  // if there are no any record in the DB
1552  return false;
1553  }
1554 
1555  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1556  try {
1557  std::string ecu_serial = statement.get_result_col_str(0).value();
1558  int64_t counter = statement.get_result_col_int(1);
1559 
1560  ecu_cnt.emplace_back(Uptane::EcuSerial(ecu_serial), counter);
1561  } catch (const boost::bad_optional_access&) {
1562  return false;
1563  }
1564  }
1565 
1566  if (results != nullptr) {
1567  *results = std::move(ecu_cnt);
1568  }
1569 
1570  return true;
1571 }
1572 
1573 void SQLStorage::saveReportEvent(const Json::Value& json_value) {
1574  std::string json_string = Utils::jsonToCanonicalStr(json_value);
1575  SQLite3Guard db = dbConnection();
1576  auto statement = db.prepareStatement<std::string>(
1577  "INSERT INTO report_events SELECT MAX(id) + 1, ? FROM report_events", json_string);
1578  if (statement.step() != SQLITE_DONE) {
1579  LOG_ERROR << "Can't save report event: " << db.errmsg();
1580  return;
1581  }
1582 }
1583 
1584 bool SQLStorage::loadReportEvents(Json::Value* report_array, int64_t* id_max) const {
1585  SQLite3Guard db = dbConnection();
1586  auto statement = db.prepareStatement("SELECT id, json_string FROM report_events;");
1587  int statement_result = statement.step();
1588  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1589  LOG_ERROR << "Can't get report_events: " << db.errmsg();
1590  return false;
1591  }
1592  if (statement_result == SQLITE_DONE) {
1593  // if there are no any record in the DB
1594  return false;
1595  }
1596  *id_max = 0;
1597  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1598  try {
1599  int64_t id = statement.get_result_col_int(0);
1600  std::string json_string = statement.get_result_col_str(1).value();
1601  std::istringstream jss(json_string);
1602  Json::Value event_json;
1603  std::string errs;
1604  if (Json::parseFromStream(Json::CharReaderBuilder(), jss, &event_json, &errs)) {
1605  report_array->append(event_json);
1606  *id_max = (*id_max) > id ? (*id_max) : id;
1607  } else {
1608  LOG_ERROR << "Unable to parse event data: " << errs;
1609  }
1610  } catch (const boost::bad_optional_access&) {
1611  return false;
1612  }
1613  }
1614 
1615  return true;
1616 }
1617 
1618 void SQLStorage::deleteReportEvents(int64_t id_max) {
1619  SQLite3Guard db = dbConnection();
1620 
1621  db.beginTransaction();
1622 
1623  auto statement = db.prepareStatement<int64_t>("DELETE FROM report_events WHERE id <= ?;", id_max);
1624  if (statement.step() != SQLITE_DONE) {
1625  LOG_ERROR << "Can't delete report_events";
1626  }
1627 
1628  db.commitTransaction();
1629 }
1630 
1631 void SQLStorage::clearInstallationResults() {
1632  SQLite3Guard db = dbConnection();
1633 
1634  db.beginTransaction();
1635 
1636  if (db.exec("DELETE FROM device_installation_result;", nullptr, nullptr) != SQLITE_OK) {
1637  LOG_ERROR << "Can't clear device_installation_result: " << db.errmsg();
1638  return;
1639  }
1640 
1641  if (db.exec("DELETE FROM ecu_installation_results;", nullptr, nullptr) != SQLITE_OK) {
1642  LOG_ERROR << "Can't clear ecu_installation_results: " << db.errmsg();
1643  return;
1644  }
1645 
1646  db.commitTransaction();
1647 }
1648 
1649 void SQLStorage::storeDeviceDataHash(const std::string& data_type, const std::string& hash) {
1650  SQLite3Guard db = dbConnection();
1651 
1652  auto statement = db.prepareStatement<std::string, std::string>(
1653  "INSERT OR REPLACE INTO device_data(data_type,hash) VALUES (?,?);", data_type, hash);
1654  if (statement.step() != SQLITE_DONE) {
1655  LOG_ERROR << "Can't set " << data_type << " hash: " << db.errmsg();
1656  throw std::runtime_error("Can't set " + data_type + " hash: " + db.errmsg());
1657  }
1658 }
1659 
1660 bool SQLStorage::loadDeviceDataHash(const std::string& data_type, std::string* hash) const {
1661  SQLite3Guard db = dbConnection();
1662 
1663  auto statement =
1664  db.prepareStatement<std::string>("SELECT hash FROM device_data WHERE data_type = ? LIMIT 1;", data_type);
1665 
1666  int result = statement.step();
1667  if (result == SQLITE_DONE) {
1668  LOG_TRACE << data_type << " hash not present in db";
1669  return false;
1670  } else if (result != SQLITE_ROW) {
1671  LOG_ERROR << "Can't get " << data_type << " hash: " << db.errmsg();
1672  return false;
1673  }
1674 
1675  if (hash != nullptr) {
1676  *hash = statement.get_result_col_str(0).value();
1677  }
1678 
1679  return true;
1680 }
1681 
1682 void SQLStorage::clearDeviceData() {
1683  SQLite3Guard db = dbConnection();
1684 
1685  if (db.exec("DELETE FROM device_data;", nullptr, nullptr) != SQLITE_OK) {
1686  LOG_ERROR << "Can't clear device_data: " << db.errmsg();
1687  return;
1688  }
1689 }
1690 
1691 bool SQLStorage::checkAvailableDiskSpace(const uint64_t required_bytes) const {
1692  struct statvfs stvfsbuf {};
1693  const int stat_res = statvfs(dbPath().c_str(), &stvfsbuf);
1694  if (stat_res < 0) {
1695  LOG_WARNING << "Unable to read filesystem statistics: error code " << stat_res;
1696  return true;
1697  }
1698  const uint64_t available_bytes = (static_cast<uint64_t>(stvfsbuf.f_bsize) * stvfsbuf.f_bavail);
1699  const uint64_t reserved_bytes = 1 << 20;
1700 
1701  if (required_bytes + reserved_bytes < available_bytes) {
1702  return true;
1703  } else {
1704  LOG_ERROR << "Insufficient disk space available to download target! Required: " << required_bytes
1705  << ", available: " << available_bytes << ", reserved: " << reserved_bytes;
1706  return false;
1707  }
1708 }
1709 
1710 boost::optional<std::pair<uintmax_t, std::string>> SQLStorage::checkTargetFile(const Uptane::Target& target) const {
1711  SQLite3Guard db = dbConnection();
1712 
1713  auto statement = db.prepareStatement<std::string>(
1714  "SELECT sha256, sha512, filename FROM target_images WHERE targetname = ?;", target.filename());
1715 
1716  int statement_state;
1717  while ((statement_state = statement.step()) == SQLITE_ROW) {
1718  auto sha256 = statement.get_result_col_str(0);
1719  auto sha512 = statement.get_result_col_str(1);
1720  auto filename = statement.get_result_col_str(2);
1721  if ((*sha256).empty() && (*sha512).empty()) {
1722  // Old aktualizr didn't save checksums, this could require to redownload old images.
1723  LOG_WARNING << "Image without checksum: " << target.filename();
1724  continue;
1725  }
1726  bool sha256_match = false;
1727  bool sha512_match = false;
1728  if (!(*sha256).empty()) {
1729  if (target.MatchHash(Hash(Hash::Type::kSha256, *sha256))) {
1730  sha256_match = true;
1731  }
1732  }
1733 
1734  if (!(*sha512).empty()) {
1735  if (target.MatchHash(Hash(Hash::Type::kSha512, *sha512))) {
1736  sha512_match = true;
1737  }
1738  }
1739  if (((*sha256).empty() || sha256_match) && ((*sha512).empty() || sha512_match)) {
1740  if (boost::filesystem::exists(images_path_ / *filename)) {
1741  return {{boost::filesystem::file_size(images_path_ / *filename), *filename}};
1742  } else {
1743  return boost::none;
1744  }
1745  }
1746  }
1747 
1748  if (statement_state == SQLITE_DONE) {
1749  return boost::none;
1750  }
1751  assert(statement_state != SQLITE_ROW); // from the previous loop precondition
1752  LOG_ERROR << "Statement step failure: " << db.errmsg();
1753 
1754  return boost::none;
1755 }
1756 
1758  public:
1759  SQLTargetWHandle(const SQLStorage& storage, Uptane::Target target)
1760  : db_path_(storage.dbPath()), target_(std::move(target)), storage_(&storage) {
1761  StorageTargetWHandle::WriteError exc("could not save file " + target_.filename() + " to the filesystem");
1762 
1763  std::string sha256Hash;
1764  std::string sha512Hash;
1765  for (const auto& hash : target_.hashes()) {
1766  if (hash.type() == Hash::Type::kSha256) {
1767  sha256Hash = hash.HashString();
1768  } else if (hash.type() == Hash::Type::kSha512) {
1769  sha512Hash = hash.HashString();
1770  }
1771  }
1772  std::string filename = (storage.images_path_ / target_.hashes()[0].HashString()).string();
1773  SQLite3Guard db = storage_->dbConnection();
1774  auto statement = db.prepareStatement<std::string, std::string, std::string>(
1775  "INSERT OR REPLACE INTO target_images (targetname, sha256, sha512, filename) VALUES ( ?, ?, ?, ?);",
1776  target_.filename(), sha256Hash, sha512Hash, target_.hashes()[0].HashString());
1777 
1778  if (statement.step() != SQLITE_DONE) {
1779  LOG_ERROR << "Statement step failure: " << db.errmsg();
1780  throw exc;
1781  }
1782  boost::filesystem::create_directories(storage.images_path_);
1783  stream_.open(filename);
1784  if (!stream_.good()) {
1785  LOG_ERROR << "Could not open image for write: " << storage.images_path_ / target_.filename();
1786  throw exc;
1787  }
1788  }
1789 
1790  ~SQLTargetWHandle() override {
1791  try {
1792  SQLTargetWHandle::wcommit();
1793  } catch (std::exception& ex) {
1794  LOG_ERROR << "Failed to commit to database: " << ex.what();
1795  } catch (...) {
1796  LOG_ERROR << "Failed to commit to database: unknown error";
1797  }
1798  }
1799 
1800  size_t wfeed(const uint8_t* buf, size_t size) override {
1801  stream_.write(reinterpret_cast<const char*>(buf), static_cast<std::streamsize>(size));
1802  written_size_ += size;
1803 
1804  return size;
1805  }
1806 
1807  void wcommit() override {
1808  if (stream_) {
1809  stream_.close();
1810  }
1811  }
1812 
1813  void wabort() noexcept override {
1814  if (stream_) {
1815  stream_.close();
1816  }
1817 
1818  if (storage_ != nullptr) {
1819  SQLite3Guard db = storage_->dbConnection();
1820  auto statement =
1821  db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_.filename());
1822  if (statement.step() != SQLITE_DONE) {
1823  LOG_ERROR << "could not delete " << target_.filename() << " from sql storage";
1824  }
1825  }
1826  }
1827 
1828  friend class SQLTargetRHandle;
1829 
1830  private:
1831  SQLTargetWHandle(const boost::filesystem::path& db_path, Uptane::Target target,
1832  const boost::filesystem::path& image_path, const uintmax_t& start_from = 0)
1833  : db_path_(db_path), target_(std::move(target)) {
1834  stream_.open(image_path.string(), std::ofstream::out | std::ofstream::app);
1835  if (!stream_.good()) {
1836  LOG_ERROR << "Could not open image for write: " << image_path;
1837  throw StorageTargetWHandle::WriteError("could not open file for write: " + image_path.string());
1838  }
1839 
1840  written_size_ = start_from;
1841  }
1842  boost::filesystem::path db_path_;
1843  Uptane::Target target_;
1844  std::ofstream stream_;
1845  const SQLStorage* storage_ = nullptr;
1846 };
1847 
1848 std::unique_ptr<StorageTargetWHandle> SQLStorage::allocateTargetFile(const Uptane::Target& target) {
1849  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(*this, target));
1850 }
1851 
1853  public:
1854  SQLTargetRHandle(const SQLStorage& storage, Uptane::Target target)
1855  : db_path_(storage.dbPath()), target_(std::move(target)), size_(0) {
1856  StorageTargetRHandle::ReadError exc("could not read file " + target_.filename() + " from sql storage");
1857 
1858  auto exists = storage.checkTargetFile(target_);
1859  if (!exists) {
1860  LOG_ERROR << "File " << target_.filename() << " with expected hash not found in the database!";
1861  throw exc;
1862  }
1863 
1864  size_ = exists->first;
1865  partial_ = size_ < target_.length();
1866  image_path_ = storage.images_path_ / exists->second;
1867  stream_.open(image_path_.string());
1868  if (!stream_.good()) {
1869  LOG_ERROR << "Could not open image: " << storage.images_path_ / target_.filename();
1870  throw exc;
1871  }
1872  }
1873 
1874  ~SQLTargetRHandle() override { SQLTargetRHandle::rclose(); }
1875 
1876  uintmax_t rsize() const override { return size_; }
1877 
1878  size_t rread(uint8_t* buf, size_t size) override {
1879  stream_.read(reinterpret_cast<char*>(buf), static_cast<std::streamsize>(size));
1880  return static_cast<size_t>(stream_.gcount());
1881  }
1882 
1883  void rclose() noexcept override {
1884  if (stream_.is_open()) {
1885  stream_.close();
1886  }
1887  }
1888 
1889  bool isPartial() const noexcept override { return partial_; }
1890  std::unique_ptr<StorageTargetWHandle> toWriteHandle() override {
1891  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(db_path_, target_, image_path_, size_));
1892  }
1893 
1894  private:
1895  boost::filesystem::path db_path_;
1896  Uptane::Target target_;
1897  uintmax_t size_;
1898  bool partial_{false};
1899  boost::filesystem::path image_path_;
1900  std::ifstream stream_;
1901 };
1902 
1903 std::unique_ptr<StorageTargetRHandle> SQLStorage::openTargetFile(const Uptane::Target& target) const {
1904  return std_::make_unique<SQLTargetRHandle>(*this, target);
1905 }
1906 
1907 std::vector<Uptane::Target> SQLStorage::getTargetFiles() {
1908  SQLite3Guard db = dbConnection();
1909 
1910  auto statement = db.prepareStatement<>("SELECT targetname, filename, sha256, sha512 FROM target_images;");
1911 
1912  std::vector<Uptane::Target> v;
1913 
1914  int result = statement.step();
1915  while (result != SQLITE_DONE) {
1916  if (result != SQLITE_ROW) {
1917  LOG_ERROR << "Statement step failure: " << db.errmsg();
1918  throw std::runtime_error("Error getting target files");
1919  }
1920 
1921  auto tname = statement.get_result_col_str(0).value();
1922  auto fname = statement.get_result_col_str(1).value();
1923  auto tsize = boost::filesystem::file_size(images_path_ / fname);
1924  auto sha256 = statement.get_result_col_str(2).value();
1925  auto sha512 = statement.get_result_col_str(3).value();
1926 
1927  std::vector<Hash> hashes;
1928  if (!sha256.empty()) {
1929  hashes.emplace_back(Hash::Type::kSha256, sha256);
1930  }
1931  if (!sha512.empty()) {
1932  hashes.emplace_back(Hash::Type::kSha512, sha512);
1933  }
1934  v.emplace_back(tname, Uptane::EcuMap{}, hashes, tsize);
1935 
1936  result = statement.step();
1937  }
1938 
1939  return v;
1940 }
1941 
1942 void SQLStorage::removeTargetFile(const std::string& target_name) {
1943  SQLite3Guard db = dbConnection();
1944 
1945  db.beginTransaction();
1946 
1947  auto statement =
1948  db.prepareStatement<std::string>("SELECT filename FROM target_images WHERE targetname = ?;", target_name);
1949 
1950  if (statement.step() != SQLITE_ROW) {
1951  LOG_ERROR << "Statement step failure: " << db.errmsg();
1952  throw std::runtime_error("Could not find target file");
1953  }
1954 
1955  std::string filename = statement.get_result_col_str(0).value();
1956 
1957  statement = db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_name);
1958 
1959  if (statement.step() != SQLITE_DONE) {
1960  LOG_ERROR << "Statement step failure: " << db.errmsg();
1961  throw std::runtime_error("Could not remove target file");
1962  }
1963  try {
1964  boost::filesystem::remove(images_path_ / filename);
1965  } catch (std::exception& e) {
1966  LOG_ERROR << "Could not remove target file";
1967  throw;
1968  }
1969 
1970  db.commitTransaction();
1971 }
1972 
1973 void SQLStorage::cleanUp() { boost::filesystem::remove_all(dbPath()); }
General data structures.
Definition: types.cc:55
Metadata version numbers.
Definition: tuf.h:119
TUF Roles.
Definition: tuf.h:60
The hash of a file or Uptane metadata.
Definition: crypto.h:65
Results of libaktualizr API calls.
Definition: results.h:13