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