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