Aktualizr
C++ SOTA Client
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 << "Failed to 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 << "Failed to 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 << "Failed to 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 << "Failed to 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 << "Uptane public key not found in database";
97  return false;
98  } else if (result != SQLITE_ROW) {
99  LOG_ERROR << "Failed to get Uptane 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 << "Uptane private key not found in database";
123  return false;
124  } else if (result != SQLITE_ROW) {
125  LOG_ERROR << "Failed to get Uptane 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 << "Failed to 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 SQLException(db.errmsg().insert(0, "Failed to 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 SQLException(db.errmsg().insert(0, "Failed to set 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 SQLException(db.errmsg().insert(0, "Failed to 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 SQLException(db.errmsg().insert(0, "Failed to set 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 in database";
225  return false;
226  } else if (statement_state != SQLITE_ROW) {
227  LOG_ERROR << "Failed to 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 << "Failed to 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 << "Failed to 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 << "Failed to set CA certificate: " << 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 << "Failed to 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 << "Failed to set client certificate: " << 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 << "Failed to 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 << "Failed to set client private key: " << 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 credentials not found in database";
392  return false;
393  } else if (result != SQLITE_ROW) {
394  LOG_ERROR << "Failed to get TLS credentials: " << 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 << "Failed to clear TLS credentials: " << 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 certificate not found in database";
439  return false;
440  } else if (result != SQLITE_ROW) {
441  LOG_ERROR << "Failed to get CA certificate: " << 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 certificate not found in database";
465  return false;
466  } else if (result != SQLITE_ROW) {
467  LOG_ERROR << "Failed to get client certificate: " << 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 private key not found in database";
491  return false;
492  } else if (result != SQLITE_ROW) {
493  LOG_ERROR << "Failed to get client private key: " << 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 << "Failed to 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 << "Failed to store Root 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 << "Failed to 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 << "Failed to 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 found in database";
572  return false;
573  } else if (result != SQLITE_ROW) {
574  LOG_ERROR << "Failed to 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 found in database";
589  return false;
590  } else if (result != SQLITE_ROW) {
591  LOG_ERROR << "Failed to 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 << "Failed to 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 found in database";
619  return false;
620  } else if (result != SQLITE_ROW) {
621  LOG_ERROR << "Failed to 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 << "Failed to 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 << "Failed to 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 << "Failed to store 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 found in database";
671  return false;
672  } else if (result != SQLITE_ROW) {
673  LOG_ERROR << "Failed to 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 not found in database";
694  return true;
695  } else if (statement_state != SQLITE_ROW) {
696  LOG_ERROR << "Failed to 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 << "Failed to 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 << "Failed to 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 key not found in database";
752  return false;
753  } else if (result != SQLITE_ROW) {
754  LOG_ERROR << "Failed to 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 << "Failed to 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 SQLException(std::string("Failed to get device_info count: ") + db.errmsg());
788  }
789  if (statement.get_result_col_int(0) != 1) {
790  throw SQLException("Failed to set ECU registered because device info is empty.");
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 << "Failed to set registration flag: " << 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  LOG_TRACE << "Registration flag not found in database";
810  return false;
811  } else if (result != SQLITE_ROW) {
812  LOG_ERROR << "Failed to get registration flag: " << db.errmsg();
813  return false;
814  }
815 
816  return statement.get_result_col_int(0) != 0;
817 }
818 
819 void SQLStorage::clearEcuRegistered() {
820  SQLite3Guard db = dbConnection();
821 
822  // note: if the table is empty, nothing is done but that's fine
823  std::string req = "UPDATE device_info SET is_registered = 0";
824  if (db.exec(req.c_str(), nullptr, nullptr) != SQLITE_OK) {
825  LOG_ERROR << "Failed to clear registration flag: " << db.errmsg();
826  return;
827  }
828 }
829 
830 void SQLStorage::storeNeedReboot() {
831  SQLite3Guard db = dbConnection();
832 
833  auto statement = db.prepareStatement<int>("INSERT OR REPLACE INTO need_reboot(unique_mark,flag) VALUES(0,?);", 1);
834  if (statement.step() != SQLITE_DONE) {
835  LOG_ERROR << "Failed to set reboot flag: " << db.errmsg();
836  return;
837  }
838 }
839 
840 bool SQLStorage::loadNeedReboot(bool* need_reboot) const {
841  SQLite3Guard db = dbConnection();
842 
843  auto statement = db.prepareStatement("SELECT flag FROM need_reboot LIMIT 1;");
844 
845  int result = statement.step();
846  if (result == SQLITE_DONE) {
847  if (need_reboot != nullptr) {
848  *need_reboot = false;
849  }
850  return true;
851  } else if (result != SQLITE_ROW) {
852  LOG_ERROR << "Failed to get reboot flag: " << db.errmsg();
853  return false;
854  }
855 
856  auto flag = static_cast<bool>(statement.get_result_col_int(0));
857  if (need_reboot != nullptr) {
858  *need_reboot = flag;
859  }
860 
861  return true;
862 }
863 
864 void SQLStorage::clearNeedReboot() {
865  SQLite3Guard db = dbConnection();
866 
867  if (db.exec("DELETE FROM need_reboot;", nullptr, nullptr) != SQLITE_OK) {
868  LOG_ERROR << "Failed to clear reboot flag: " << db.errmsg();
869  return;
870  }
871 }
872 
873 void SQLStorage::storeEcuSerials(const EcuSerials& serials) {
874  if (!serials.empty()) {
875  SQLite3Guard db = dbConnection();
876 
877  db.beginTransaction();
878 
879  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
880  LOG_ERROR << "Failed to clear ECU serials: " << db.errmsg();
881  return;
882  }
883 
884  // first is the Primary
885  std::string serial = serials[0].first.ToString();
886  std::string hwid = serials[0].second.ToString();
887  {
888  auto statement = db.prepareStatement<std::string, std::string>(
889  "INSERT INTO ecus(id, serial,hardware_id,is_primary) VALUES (0, ?,?,1);", serial, hwid);
890  if (statement.step() != SQLITE_DONE) {
891  LOG_ERROR << "Failed to store ECU serials: " << db.errmsg();
892  return;
893  }
894 
895  // update lazily stored installed version
896  auto statement_ivupdate = db.prepareStatement<std::string>(
897  "UPDATE installed_versions SET ecu_serial = ? WHERE ecu_serial = '';", serial);
898 
899  if (statement_ivupdate.step() != SQLITE_DONE) {
900  LOG_ERROR << "Failed to store ECU serials: " << db.errmsg();
901  return;
902  }
903  }
904 
905  for (auto it = serials.cbegin() + 1; it != serials.cend(); it++) {
906  auto statement = db.prepareStatement<int64_t, std::string, std::string>(
907  "INSERT INTO ecus(id,serial,hardware_id) VALUES (?,?,?);", it - serials.cbegin(), it->first.ToString(),
908  it->second.ToString());
909 
910  if (statement.step() != SQLITE_DONE) {
911  LOG_ERROR << "Failed to store ECU serials: " << db.errmsg();
912  return;
913  }
914  }
915 
916  db.commitTransaction();
917  }
918 }
919 
920 bool SQLStorage::loadEcuSerials(EcuSerials* serials) const {
921  SQLite3Guard db = dbConnection();
922 
923  // order by auto-incremented Primary key so that the ECU order is kept constant
924  auto statement = db.prepareStatement("SELECT serial, hardware_id FROM ecus ORDER BY id;");
925  int statement_state;
926 
927  EcuSerials new_serials;
928  bool empty = true;
929  while ((statement_state = statement.step()) == SQLITE_ROW) {
930  try {
931  new_serials.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
932  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()));
933  empty = false;
934  } catch (const boost::bad_optional_access&) {
935  return false;
936  }
937  }
938 
939  if (statement_state != SQLITE_DONE) {
940  LOG_ERROR << "Failed to get ECU serials: " << db.errmsg();
941  return false;
942  }
943 
944  if (serials != nullptr) {
945  *serials = std::move(new_serials);
946  }
947 
948  return !empty;
949 }
950 
951 void SQLStorage::clearEcuSerials() {
952  SQLite3Guard db = dbConnection();
953 
954  db.beginTransaction();
955 
956  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
957  LOG_ERROR << "Failed to clear ECU serials: " << db.errmsg();
958  return;
959  }
960 
961  if (db.exec("DELETE FROM secondary_ecus;", nullptr, nullptr) != SQLITE_OK) {
962  LOG_ERROR << "Failed to clear Secondary ECUs: " << db.errmsg();
963  return;
964  }
965 
966  db.commitTransaction();
967 }
968 
969 void SQLStorage::storeCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, const std::string& manifest) {
970  SQLite3Guard db = dbConnection();
971 
972  auto statement = db.prepareStatement<std::string, std::string>(
973  "UPDATE secondary_ecus SET manifest = ? WHERE (serial = ?);", manifest, ecu_serial.ToString());
974  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
975  LOG_ERROR << "Failed to store Secondary manifest: " << db.errmsg();
976  return;
977  }
978 }
979 
980 bool SQLStorage::loadCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, std::string* manifest) const {
981  SQLite3Guard db = dbConnection();
982 
983  std::string stmanifest;
984 
985  bool empty = false;
986 
987  auto statement = db.prepareStatement<std::string>("SELECT manifest FROM secondary_ecus WHERE (serial = ?);",
988  ecu_serial.ToString());
989 
990  if (statement.step() != SQLITE_ROW) {
991  LOG_WARNING << "Could not find manifest for ECU " << ecu_serial;
992  return false;
993  } else {
994  stmanifest = statement.get_result_col_str(0).value_or("");
995 
996  empty = stmanifest.empty();
997  }
998 
999  if (manifest != nullptr) {
1000  *manifest = std::move(stmanifest);
1001  }
1002 
1003  return !empty;
1004 }
1005 
1006 void SQLStorage::saveMisconfiguredEcu(const MisconfiguredEcu& ecu) {
1007  SQLite3Guard db = dbConnection();
1008 
1009  auto statement = db.prepareStatement<std::string, std::string, int>(
1010  "INSERT OR REPLACE INTO misconfigured_ecus VALUES (?,?,?);", ecu.serial.ToString(), ecu.hardware_id.ToString(),
1011  static_cast<int>(ecu.state));
1012  if (statement.step() != SQLITE_DONE) {
1013  throw SQLException(db.errmsg().insert(0, "Failed to set misconfigured ECUs: "));
1014  }
1015 }
1016 
1017 bool SQLStorage::loadMisconfiguredEcus(std::vector<MisconfiguredEcu>* ecus) const {
1018  SQLite3Guard db = dbConnection();
1019 
1020  auto statement = db.prepareStatement("SELECT serial, hardware_id, state FROM misconfigured_ecus;");
1021  int statement_state;
1022 
1023  std::vector<MisconfiguredEcu> new_ecus;
1024  bool empty = true;
1025  while ((statement_state = statement.step()) == SQLITE_ROW) {
1026  try {
1027  new_ecus.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
1028  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()),
1029  static_cast<EcuState>(statement.get_result_col_int(2)));
1030  empty = false;
1031  } catch (const boost::bad_optional_access&) {
1032  return false;
1033  }
1034  }
1035 
1036  if (statement_state != SQLITE_DONE) {
1037  LOG_ERROR << "Failed to get misconfigured ECUs: " << db.errmsg();
1038  return false;
1039  }
1040 
1041  if (ecus != nullptr) {
1042  *ecus = std::move(new_ecus);
1043  }
1044 
1045  return !empty;
1046 }
1047 
1048 void SQLStorage::clearMisconfiguredEcus() {
1049  SQLite3Guard db = dbConnection();
1050 
1051  if (db.exec("DELETE FROM misconfigured_ecus;", nullptr, nullptr) != SQLITE_OK) {
1052  LOG_ERROR << "Failed to clear misconfigured ECUs: " << db.errmsg();
1053  return;
1054  }
1055 }
1056 
1057 void SQLStorage::saveInstalledVersion(const std::string& ecu_serial, const Uptane::Target& target,
1058  InstalledVersionUpdateMode update_mode) {
1059  SQLite3Guard db = dbConnection();
1060 
1061  db.beginTransaction();
1062 
1063  // either adds a new entry or update the last one's status
1064 
1065  // empty serial: use Primary
1066  std::string ecu_serial_real = ecu_serial;
1067  if (ecu_serial_real.empty()) {
1068  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1069  if (statement.step() == SQLITE_ROW) {
1070  ecu_serial_real = statement.get_result_col_str(0).value();
1071  } else {
1072  LOG_WARNING << "Could not find Primary ECU serial, set to lazy init mode";
1073  }
1074  }
1075 
1076  std::string hashes_encoded = Hash::encodeVector(target.hashes());
1077 
1078  // get the last time this version was installed on this ecu
1079  boost::optional<int64_t> old_id;
1080  bool old_was_installed = false;
1081  {
1082  auto statement = db.prepareStatement<std::string>(
1083  "SELECT id, sha256, name, was_installed FROM installed_versions WHERE ecu_serial = ? ORDER BY id DESC "
1084  "LIMIT 1;",
1085  ecu_serial_real);
1086 
1087  if (statement.step() == SQLITE_ROW) {
1088  int64_t rid = statement.get_result_col_int(0);
1089  std::string rsha256 = statement.get_result_col_str(1).value_or("");
1090  std::string rname = statement.get_result_col_str(2).value_or("");
1091  bool rwasi = statement.get_result_col_int(3) == 1;
1092 
1093  if (rsha256 == target.sha256Hash() && rname == target.filename()) {
1094  old_id = rid;
1095  old_was_installed = rwasi;
1096  }
1097  }
1098  }
1099 
1100  if (update_mode == InstalledVersionUpdateMode::kCurrent) {
1101  // unset 'current' and 'pending' on all versions for this ecu
1102  auto statement = db.prepareStatement<std::string>(
1103  "UPDATE installed_versions SET is_current = 0, is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1104  if (statement.step() != SQLITE_DONE) {
1105  LOG_ERROR << "Failed to save installed versions: " << db.errmsg();
1106  return;
1107  }
1108  } else if (update_mode == InstalledVersionUpdateMode::kPending) {
1109  // unset 'pending' on all versions for this ecu
1110  auto statement = db.prepareStatement<std::string>(
1111  "UPDATE installed_versions SET is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1112  if (statement.step() != SQLITE_DONE) {
1113  LOG_ERROR << "Failed to save installed versions: " << db.errmsg();
1114  return;
1115  }
1116  }
1117 
1118  if (!!old_id) {
1119  auto statement = db.prepareStatement<std::string, int, int, int64_t>(
1120  "UPDATE installed_versions SET correlation_id = ?, is_current = ?, is_pending = ?, was_installed = ? WHERE id "
1121  "= ?;",
1122  target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1123  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1124  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent || old_was_installed), old_id.value());
1125 
1126  if (statement.step() != SQLITE_DONE) {
1127  LOG_ERROR << "Failed to save installed versions: " << db.errmsg();
1128  return;
1129  }
1130  } else {
1131  std::string custom = Utils::jsonToCanonicalStr(target.custom_data());
1132  auto statement = db.prepareStatement<std::string, std::string, std::string, std::string, int64_t, std::string,
1133  std::string, int, int>(
1134  "INSERT INTO installed_versions(ecu_serial, sha256, name, hashes, length, custom_meta, correlation_id, "
1135  "is_current, is_pending, was_installed) VALUES (?,?,?,?,?,?,?,?,?,?);",
1136  ecu_serial_real, target.sha256Hash(), target.filename(), hashes_encoded, static_cast<int64_t>(target.length()),
1137  custom, target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1138  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1139  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent));
1140 
1141  if (statement.step() != SQLITE_DONE) {
1142  LOG_ERROR << "Failed to save installed versions: " << db.errmsg();
1143  return;
1144  }
1145  }
1146 
1147  db.commitTransaction();
1148 }
1149 
1150 static void loadEcuMap(SQLite3Guard& db, std::string& ecu_serial, Uptane::EcuMap& ecu_map) {
1151  // The Secondary only knows about itself and in its database it is considered
1152  // a Primary, for better or worse.
1153  if (ecu_serial.empty()) {
1154  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1155  if (statement.step() == SQLITE_ROW) {
1156  ecu_serial = statement.get_result_col_str(0).value();
1157  } else if (statement.step() == SQLITE_DONE) {
1158  LOG_DEBUG << "No serial found in database for this ECU, defaulting to empty serial";
1159  } else {
1160  LOG_ERROR << "Error getting serial for this ECU, defaulting to empty serial: " << db.errmsg();
1161  }
1162  }
1163 
1164  if (!ecu_serial.empty()) {
1165  auto statement = db.prepareStatement<std::string>("SELECT hardware_id FROM ecus WHERE serial = ?;", ecu_serial);
1166  if (statement.step() == SQLITE_ROW) {
1167  ecu_map.insert(
1168  {Uptane::EcuSerial(ecu_serial), Uptane::HardwareIdentifier(statement.get_result_col_str(0).value())});
1169  } else if (statement.step() == SQLITE_DONE) {
1170  LOG_DEBUG << "No hardware ID found in database for ECU serial " << ecu_serial;
1171  } else {
1172  LOG_ERROR << "Error getting hardware ID for ECU serial " << ecu_serial << ": " << db.errmsg();
1173  }
1174  }
1175 }
1176 
1177 bool SQLStorage::loadInstallationLog(const std::string& ecu_serial, std::vector<Uptane::Target>* log,
1178  bool only_installed) const {
1179  SQLite3Guard db = dbConnection();
1180 
1181  std::string ecu_serial_real = ecu_serial;
1182  Uptane::EcuMap ecu_map;
1183  loadEcuMap(db, ecu_serial_real, ecu_map);
1184 
1185  std::string query =
1186  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1187  "ecu_serial = ? ORDER BY id;";
1188  if (only_installed) {
1189  query =
1190  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1191  "ecu_serial = ? AND was_installed = 1 ORDER BY id;";
1192  }
1193 
1194  auto statement = db.prepareStatement<std::string>(query, ecu_serial_real);
1195  int statement_state;
1196 
1197  std::vector<Uptane::Target> new_log;
1198  std::map<int64_t, size_t> ids_map;
1199  size_t k = 0;
1200  while ((statement_state = statement.step()) == SQLITE_ROW) {
1201  try {
1202  auto id = statement.get_result_col_int(0);
1203  auto sha256 = statement.get_result_col_str(1).value();
1204  auto filename = statement.get_result_col_str(2).value();
1205  auto hashes_str = statement.get_result_col_str(3).value();
1206  auto length = statement.get_result_col_int(4);
1207  auto correlation_id = statement.get_result_col_str(5).value();
1208  auto custom_str = statement.get_result_col_str(6).value();
1209 
1210  // note: sha256 should always be present and is used to uniquely identify
1211  // a version. It should normally be part of the hash list as well.
1212  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1213 
1214  auto find_sha256 =
1215  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1216  if (find_sha256 == hashes.cend()) {
1217  LOG_WARNING << "No sha256 in hashes list";
1218  hashes.emplace_back(Hash::Type::kSha256, sha256);
1219  }
1220 
1221  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1222  if (!custom_str.empty()) {
1223  std::istringstream css(custom_str);
1224  std::string errs;
1225  Json::Value custom;
1226  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, nullptr)) {
1227  t.updateCustom(custom);
1228  } else {
1229  LOG_ERROR << "Unable to parse custom data: " << errs;
1230  }
1231  }
1232  new_log.emplace_back(t);
1233 
1234  ids_map[id] = k;
1235  k++;
1236  } catch (const boost::bad_optional_access&) {
1237  LOG_ERROR << "Incomplete installed version list; keeping previous entries.";
1238  return false;
1239  }
1240  }
1241 
1242  if (statement_state != SQLITE_DONE) {
1243  LOG_ERROR << "Failed to get installed versions: " << db.errmsg();
1244  return false;
1245  }
1246 
1247  if (log == nullptr) {
1248  return true;
1249  }
1250 
1251  *log = std::move(new_log);
1252 
1253  return true;
1254 }
1255 
1256 bool SQLStorage::loadInstalledVersions(const std::string& ecu_serial, boost::optional<Uptane::Target>* current_version,
1257  boost::optional<Uptane::Target>* pending_version) const {
1258  SQLite3Guard db = dbConnection();
1259 
1260  std::string ecu_serial_real = ecu_serial;
1261  Uptane::EcuMap ecu_map;
1262  loadEcuMap(db, ecu_serial_real, ecu_map);
1263 
1264  auto read_target = [&ecu_map](SQLiteStatement& statement) -> Uptane::Target {
1265  auto sha256 = statement.get_result_col_str(0).value();
1266  auto filename = statement.get_result_col_str(1).value();
1267  auto hashes_str = statement.get_result_col_str(2).value();
1268  auto length = statement.get_result_col_int(3);
1269  auto correlation_id = statement.get_result_col_str(4).value();
1270  auto custom_str = statement.get_result_col_str(5).value();
1271 
1272  // note: sha256 should always be present and is used to uniquely identify
1273  // a version. It should normally be part of the hash list as well.
1274  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1275 
1276  auto find_sha256 =
1277  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1278  if (find_sha256 == hashes.cend()) {
1279  LOG_WARNING << "No sha256 in hashes list";
1280  hashes.emplace_back(Hash::Type::kSha256, sha256);
1281  }
1282  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1283  if (!custom_str.empty()) {
1284  std::istringstream css(custom_str);
1285  Json::Value custom;
1286  std::string errs;
1287  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, &errs)) {
1288  t.updateCustom(custom);
1289  } else {
1290  LOG_ERROR << "Unable to parse custom data: " << errs;
1291  }
1292  }
1293 
1294  return t;
1295  };
1296 
1297  if (current_version != nullptr) {
1298  auto statement = db.prepareStatement<std::string>(
1299  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1300  "ecu_serial = ? AND is_current = 1 LIMIT 1;",
1301  ecu_serial_real);
1302 
1303  if (statement.step() == SQLITE_ROW) {
1304  try {
1305  *current_version = read_target(statement);
1306  } catch (const boost::bad_optional_access&) {
1307  LOG_ERROR << "Could not read current installed version";
1308  return false;
1309  }
1310  } else {
1311  LOG_TRACE << "Failed to get current installed version: " << db.errmsg();
1312  *current_version = boost::none;
1313  }
1314  }
1315 
1316  if (pending_version != nullptr) {
1317  auto statement = db.prepareStatement<std::string>(
1318  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1319  "ecu_serial = ? AND is_pending = 1 LIMIT 1;",
1320  ecu_serial_real);
1321 
1322  if (statement.step() == SQLITE_ROW) {
1323  try {
1324  *pending_version = read_target(statement);
1325  } catch (const boost::bad_optional_access&) {
1326  LOG_ERROR << "Could not read pending installed version";
1327  return false;
1328  }
1329  } else {
1330  LOG_TRACE << "Failed to get pending installed version: " << db.errmsg();
1331  *pending_version = boost::none;
1332  }
1333  }
1334 
1335  return true;
1336 }
1337 
1338 bool SQLStorage::hasPendingInstall() {
1339  SQLite3Guard db = dbConnection();
1340 
1341  auto statement = db.prepareStatement("SELECT count(*) FROM installed_versions where is_pending = 1");
1342  if (statement.step() != SQLITE_ROW) {
1343  LOG_ERROR << "Failed to get pending installation count: " << db.errmsg();
1344  throw SQLException(std::string("Failed to get pending installation count: ") + db.errmsg());
1345  }
1346 
1347  return statement.get_result_col_int(0) > 0;
1348 }
1349 
1350 void SQLStorage::getPendingEcus(std::vector<std::pair<Uptane::EcuSerial, Hash>>* pendingEcus) {
1351  SQLite3Guard db = dbConnection();
1352 
1353  auto statement = db.prepareStatement("SELECT ecu_serial, sha256 FROM installed_versions where is_pending = 1");
1354  int statement_result = statement.step();
1355  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1356  throw SQLException("Failed to get ECUs with a pending target installation: " + db.errmsg());
1357  }
1358 
1359  std::vector<std::pair<Uptane::EcuSerial, Hash>> ecu_res;
1360 
1361  if (statement_result == SQLITE_DONE) {
1362  // if there are not any records in the DB
1363  return;
1364  }
1365 
1366  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1367  std::string ecu_serial = statement.get_result_col_str(0).value();
1368  std::string hash = statement.get_result_col_str(1).value();
1369  ecu_res.emplace_back(std::make_pair(Uptane::EcuSerial(ecu_serial), Hash(Hash::Type::kSha256, hash)));
1370  }
1371 
1372  if (pendingEcus != nullptr) {
1373  *pendingEcus = std::move(ecu_res);
1374  }
1375 }
1376 
1377 void SQLStorage::clearInstalledVersions() {
1378  SQLite3Guard db = dbConnection();
1379 
1380  if (db.exec("DELETE FROM installed_versions;", nullptr, nullptr) != SQLITE_OK) {
1381  LOG_ERROR << "Failed to clear installed versions: " << db.errmsg();
1382  return;
1383  }
1384 }
1385 
1386 void SQLStorage::saveEcuInstallationResult(const Uptane::EcuSerial& ecu_serial,
1388  SQLite3Guard db = dbConnection();
1389 
1390  auto statement = db.prepareStatement<std::string, int, std::string, std::string>(
1391  "INSERT OR REPLACE INTO ecu_installation_results (ecu_serial, success, result_code, description) VALUES "
1392  "(?,?,?,?);",
1393  ecu_serial.ToString(), static_cast<int>(result.success), result.result_code.toRepr(), result.description);
1394  if (statement.step() != SQLITE_DONE) {
1395  LOG_ERROR << "Failed to set ECU installation result: " << db.errmsg();
1396  return;
1397  }
1398 }
1399 
1400 bool SQLStorage::loadEcuInstallationResults(
1401  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>>* results) const {
1402  SQLite3Guard db = dbConnection();
1403 
1404  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> ecu_res;
1405 
1406  // keep the same order as in ECUs (start with Primary)
1407  auto statement = db.prepareStatement(
1408  "SELECT ecu_serial, success, result_code, description FROM ecu_installation_results INNER JOIN ecus ON "
1409  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1410  int statement_result = statement.step();
1411  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1412  LOG_ERROR << "Failed to get ECU installation results: " << db.errmsg();
1413  return false;
1414  }
1415 
1416  if (statement_result == SQLITE_DONE) {
1417  // if there are not any records in the DB
1418  return false;
1419  }
1420 
1421  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1422  try {
1423  std::string ecu_serial = statement.get_result_col_str(0).value();
1424  auto success = static_cast<bool>(statement.get_result_col_int(1));
1425  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(2).value());
1426  std::string description = statement.get_result_col_str(3).value();
1427 
1428  ecu_res.emplace_back(Uptane::EcuSerial(ecu_serial), data::InstallationResult(success, result_code, description));
1429  } catch (const boost::bad_optional_access&) {
1430  return false;
1431  }
1432  }
1433 
1434  if (results != nullptr) {
1435  *results = std::move(ecu_res);
1436  }
1437 
1438  return true;
1439 }
1440 
1441 void SQLStorage::storeDeviceInstallationResult(const data::InstallationResult& result, const std::string& raw_report,
1442  const std::string& correlation_id) {
1443  SQLite3Guard db = dbConnection();
1444 
1445  auto statement = db.prepareStatement<int, std::string, std::string, std::string, std::string>(
1446  "INSERT OR REPLACE INTO device_installation_result (unique_mark, success, result_code, description, raw_report, "
1447  "correlation_id) "
1448  "VALUES (0,?,?,?,?,?);",
1449  static_cast<int>(result.success), result.result_code.toRepr(), result.description, raw_report, correlation_id);
1450  if (statement.step() != SQLITE_DONE) {
1451  LOG_ERROR << "Failed to store device installation result: " << db.errmsg();
1452  return;
1453  }
1454 }
1455 
1456 bool SQLStorage::storeDeviceInstallationRawReport(const std::string& raw_report) {
1457  SQLite3Guard db = dbConnection();
1458  auto statement = db.prepareStatement<std::string>("UPDATE device_installation_result SET raw_report=?;", raw_report);
1459  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
1460  LOG_ERROR << "Failed to store device installation raw report: " << db.errmsg();
1461  return false;
1462  }
1463  return true;
1464 }
1465 
1466 bool SQLStorage::loadDeviceInstallationResult(data::InstallationResult* result, std::string* raw_report,
1467  std::string* correlation_id) const {
1468  SQLite3Guard db = dbConnection();
1469 
1470  data::InstallationResult dev_res;
1471  std::string raw_report_res;
1472  std::string corrid_res;
1473 
1474  auto statement = db.prepareStatement(
1475  "SELECT success, result_code, description, raw_report, correlation_id FROM device_installation_result;");
1476  int statement_result = statement.step();
1477  if (statement_result == SQLITE_DONE) {
1478  LOG_TRACE << "Device installation result not found in database";
1479  return false;
1480  } else if (statement_result != SQLITE_ROW) {
1481  LOG_ERROR << "Failed to get device installation result: " << db.errmsg();
1482  return false;
1483  }
1484 
1485  try {
1486  auto success = static_cast<bool>(statement.get_result_col_int(0));
1487  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(1).value());
1488  std::string description = statement.get_result_col_str(2).value();
1489  raw_report_res = statement.get_result_col_str(3).value();
1490  corrid_res = statement.get_result_col_str(4).value();
1491 
1492  dev_res = data::InstallationResult(success, result_code, description);
1493  } catch (const boost::bad_optional_access&) {
1494  return false;
1495  }
1496 
1497  if (result != nullptr) {
1498  *result = std::move(dev_res);
1499  }
1500 
1501  if (raw_report != nullptr) {
1502  *raw_report = std::move(raw_report_res);
1503  }
1504 
1505  if (correlation_id != nullptr) {
1506  *correlation_id = std::move(corrid_res);
1507  }
1508 
1509  return true;
1510 }
1511 
1512 void SQLStorage::saveEcuReportCounter(const Uptane::EcuSerial& ecu_serial, const int64_t counter) {
1513  SQLite3Guard db = dbConnection();
1514 
1515  auto statement = db.prepareStatement<std::string, int64_t>(
1516  "INSERT OR REPLACE INTO ecu_report_counter (ecu_serial, counter) VALUES "
1517  "(?,?);",
1518  ecu_serial.ToString(), counter);
1519  if (statement.step() != SQLITE_DONE) {
1520  LOG_ERROR << "Failed to set ECU report counter: " << db.errmsg();
1521  return;
1522  }
1523 }
1524 
1525 bool SQLStorage::loadEcuReportCounter(std::vector<std::pair<Uptane::EcuSerial, int64_t>>* results) const {
1526  SQLite3Guard db = dbConnection();
1527 
1528  std::vector<std::pair<Uptane::EcuSerial, int64_t>> ecu_cnt;
1529 
1530  // keep the same order as in ECUs (start with Primary)
1531  auto statement = db.prepareStatement(
1532  "SELECT ecu_serial, counter FROM ecu_report_counter INNER JOIN ecus ON "
1533  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1534  int statement_result = statement.step();
1535  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1536  LOG_ERROR << "Failed to get ECU report counter: " << db.errmsg();
1537  return false;
1538  }
1539 
1540  if (statement_result == SQLITE_DONE) {
1541  // if there are not any records in the DB
1542  return false;
1543  }
1544 
1545  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1546  try {
1547  std::string ecu_serial = statement.get_result_col_str(0).value();
1548  int64_t counter = statement.get_result_col_int(1);
1549 
1550  ecu_cnt.emplace_back(Uptane::EcuSerial(ecu_serial), counter);
1551  } catch (const boost::bad_optional_access&) {
1552  return false;
1553  }
1554  }
1555 
1556  if (results != nullptr) {
1557  *results = std::move(ecu_cnt);
1558  }
1559 
1560  return true;
1561 }
1562 
1563 void SQLStorage::saveReportEvent(const Json::Value& json_value) {
1564  std::string json_string = Utils::jsonToCanonicalStr(json_value);
1565  SQLite3Guard db = dbConnection();
1566  auto statement = db.prepareStatement<std::string>(
1567  "INSERT INTO report_events SELECT MAX(id) + 1, ? FROM report_events", json_string);
1568  if (statement.step() != SQLITE_DONE) {
1569  LOG_ERROR << "Failed to save report event: " << db.errmsg();
1570  return;
1571  }
1572 }
1573 
1574 bool SQLStorage::loadReportEvents(Json::Value* report_array, int64_t* id_max) const {
1575  SQLite3Guard db = dbConnection();
1576  auto statement = db.prepareStatement("SELECT id, json_string FROM report_events;");
1577  int statement_result = statement.step();
1578  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1579  LOG_ERROR << "Failed to get report events: " << db.errmsg();
1580  return false;
1581  }
1582  if (statement_result == SQLITE_DONE) {
1583  // if there are not any records in the DB
1584  return false;
1585  }
1586  *id_max = 0;
1587  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1588  try {
1589  int64_t id = statement.get_result_col_int(0);
1590  std::string json_string = statement.get_result_col_str(1).value();
1591  std::istringstream jss(json_string);
1592  Json::Value event_json;
1593  std::string errs;
1594  if (Json::parseFromStream(Json::CharReaderBuilder(), jss, &event_json, &errs)) {
1595  report_array->append(event_json);
1596  *id_max = (*id_max) > id ? (*id_max) : id;
1597  } else {
1598  LOG_ERROR << "Unable to parse event data: " << errs;
1599  }
1600  } catch (const boost::bad_optional_access&) {
1601  return false;
1602  }
1603  }
1604 
1605  return true;
1606 }
1607 
1608 void SQLStorage::deleteReportEvents(int64_t id_max) {
1609  SQLite3Guard db = dbConnection();
1610 
1611  auto statement = db.prepareStatement<int64_t>("DELETE FROM report_events WHERE id <= ?;", id_max);
1612  if (statement.step() != SQLITE_DONE) {
1613  LOG_ERROR << "Failed to clear report events: " << db.errmsg();
1614  }
1615 }
1616 
1617 void SQLStorage::clearInstallationResults() {
1618  SQLite3Guard db = dbConnection();
1619 
1620  db.beginTransaction();
1621 
1622  if (db.exec("DELETE FROM device_installation_result;", nullptr, nullptr) != SQLITE_OK) {
1623  LOG_ERROR << "Failed to clear device installation result: " << db.errmsg();
1624  return;
1625  }
1626 
1627  if (db.exec("DELETE FROM ecu_installation_results;", nullptr, nullptr) != SQLITE_OK) {
1628  LOG_ERROR << "Failed to clear ECU installation results: " << db.errmsg();
1629  return;
1630  }
1631 
1632  db.commitTransaction();
1633 }
1634 
1635 void SQLStorage::storeDeviceDataHash(const std::string& data_type, const std::string& hash) {
1636  SQLite3Guard db = dbConnection();
1637 
1638  auto statement = db.prepareStatement<std::string, std::string>(
1639  "INSERT OR REPLACE INTO device_data(data_type,hash) VALUES (?,?);", data_type, hash);
1640  if (statement.step() != SQLITE_DONE) {
1641  LOG_ERROR << "Failed to store " << data_type << " hash: " << db.errmsg();
1642  throw SQLException("Failed to store " + data_type + " hash: " + db.errmsg());
1643  }
1644 }
1645 
1646 bool SQLStorage::loadDeviceDataHash(const std::string& data_type, std::string* hash) const {
1647  SQLite3Guard db = dbConnection();
1648 
1649  auto statement =
1650  db.prepareStatement<std::string>("SELECT hash FROM device_data WHERE data_type = ? LIMIT 1;", data_type);
1651 
1652  int result = statement.step();
1653  if (result == SQLITE_DONE) {
1654  LOG_TRACE << data_type << " hash not found in database";
1655  return false;
1656  } else if (result != SQLITE_ROW) {
1657  LOG_ERROR << "Failed to get " << data_type << " hash: " << db.errmsg();
1658  return false;
1659  }
1660 
1661  if (hash != nullptr) {
1662  *hash = statement.get_result_col_str(0).value();
1663  }
1664 
1665  return true;
1666 }
1667 
1668 void SQLStorage::clearDeviceData() {
1669  SQLite3Guard db = dbConnection();
1670 
1671  if (db.exec("DELETE FROM device_data;", nullptr, nullptr) != SQLITE_OK) {
1672  LOG_ERROR << "Failed to clear device data: " << db.errmsg();
1673  return;
1674  }
1675 }
1676 
1677 void SQLStorage::storeTargetFilename(const std::string& targetname, const std::string& filename) const {
1678  SQLite3Guard db = dbConnection();
1679  auto statement = db.prepareStatement<std::string, std::string>(
1680  "INSERT OR REPLACE INTO target_images (targetname, filename) VALUES (?, ?);", targetname, filename);
1681 
1682  if (statement.step() != SQLITE_DONE) {
1683  LOG_ERROR << "Failed to store Target filename: " << db.errmsg();
1684  throw SQLException(std::string("Failed to store Target filename: ") + db.errmsg());
1685  }
1686 }
1687 
1688 std::string SQLStorage::getTargetFilename(const std::string& targetname) const {
1689  SQLite3Guard db = dbConnection();
1690 
1691  auto statement =
1692  db.prepareStatement<std::string>("SELECT filename FROM target_images WHERE targetname = ?;", targetname);
1693 
1694  switch (statement.step()) {
1695  case SQLITE_ROW:
1696  return statement.get_result_col_str(0).value();
1697  case SQLITE_DONE:
1698  return {};
1699  default:
1700  throw SQLException(db.errmsg().insert(0, "Failed to read Target filename from database: "));
1701  }
1702 }
1703 
1704 std::vector<std::string> SQLStorage::getAllTargetNames() const {
1705  SQLite3Guard db = dbConnection();
1706 
1707  auto statement = db.prepareStatement<>("SELECT targetname FROM target_images;");
1708 
1709  std::vector<std::string> names;
1710 
1711  int result = statement.step();
1712  while (result != SQLITE_DONE) {
1713  if (result != SQLITE_ROW) {
1714  LOG_ERROR << "Failed to get Target filenames: " << db.errmsg();
1715  throw SQLException(std::string("Failed to get Target filenames: ") + db.errmsg());
1716  }
1717  names.push_back(statement.get_result_col_str(0).value());
1718  result = statement.step();
1719  }
1720  return names;
1721 }
1722 
1723 void SQLStorage::deleteTargetInfo(const std::string& targetname) const {
1724  SQLite3Guard db = dbConnection();
1725 
1726  auto statement = db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", targetname);
1727 
1728  if (statement.step() != SQLITE_DONE) {
1729  LOG_ERROR << "Failed to clear Target filenames: " << db.errmsg();
1730  throw SQLException(std::string("Failed to clear Target filenames: ") + db.errmsg());
1731  }
1732 }
1733 
1734 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:219
data::InstallationResult
Definition: types.h:277
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:315
Uptane::RepositoryType
Definition: tuf.h:21
Uptane::EcuSerial
Definition: types.h:346
SecondaryInfo
Definition: types.h:462
PublicKey
Definition: types.h:119
result
Results of libaktualizr API calls.
Definition: results.h:12
SQLite3Guard
Definition: sql_utils.h:131
SQLiteStatement
Definition: sql_utils.h:34
Uptane::Role
TUF Roles.
Definition: tuf.h:61
Uptane::Target
Definition: types.h:379
SQLStorageBase
Definition: sqlstorage_base.h:33
SQLException
Definition: sql_utils.h:22
INvStorage
Definition: invstorage.h:43