2 * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Zofia Abramowska (z.abramowska@samsung.com)
20 * @brief Implementation of encrypted db access layer
28 #include <db-crypto.h>
29 #include <dpl/db/sql_connection.h>
30 #include <dpl/errno_string.h>
31 #include <dpl/log/log.h>
32 #include <dpl/scoped_ptr.h>
33 #include <ckm/ckm-error.h>
34 #include <exception.h>
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
41 const CKM::PermissionMask DEFAULT_PERMISSIONS =
42 static_cast<CKM::PermissionMask>(CKM::Permission::READ |
43 CKM::Permission::REMOVE);
45 const char *SCRIPTS_PATH = RO_DATA_DIR "/scripts/";
47 enum DBVersion : int {
50 /* ... since version 3, there is no need to manually
51 * recognize database version.
52 * Remember only that if doing changes to the database,
53 * increment and update DB_VERSION_CURRENT,
54 * then provide migration mechanism!
56 DB_VERSION_CURRENT = 5
59 const char *SCRIPT_CREATE_SCHEMA = "create_schema";
60 const char *SCRIPT_DROP_ALL_ITEMS = "drop_all";
61 const char *SCRIPT_MIGRATE = "migrate_";
63 // common substitutions:
68 // 104 - permissionLabel
69 // 105 - permissionMask
70 const char *DB_CMD_SCHEMA_SET =
71 "REPLACE INTO SCHEMA_INFO(name, value) "
72 " VALUES(?101, ?103);";
74 const char *DB_CMD_SCHEMA_GET =
75 "SELECT * FROM SCHEMA_INFO WHERE name=?101;";
77 const char *DB_SCHEMA_VERSION_FIELD = "schema_version";
80 const char *DB_CMD_NAME_INSERT =
83 " VALUES(?101, ?102);";
85 const char *DB_CMD_NAME_COUNT_ROWS =
86 "SELECT COUNT(idx) FROM NAMES WHERE name=?101 AND label=?102;";
88 const char *DB_CMD_NAME_DELETE =
89 "DELETE FROM NAMES WHERE name=?101 AND label=?102;";
91 const char *DB_CMD_NAME_DELETE_BY_OWNER =
92 "DELETE FROM NAMES WHERE label=?102;";
95 const char *DB_CMD_OBJECT_INSERT =
96 "INSERT INTO OBJECTS("
97 " exportable, dataType,"
98 " algorithmType, encryptionScheme,"
99 " iv, dataSize, data, tag, idx, backendId) "
100 " VALUES(?001, ?002, ?003, ?004, ?005, "
102 " (SELECT idx FROM NAMES WHERE name=?101 and label=?102),"
106 const char *DB_CMD_OBJECT_UPDATE =
107 "UPDATE OR FAIL OBJECTS SET"
108 " algorithmType = ?003,"
109 " encryptionScheme = ?004,"
114 " WHERE idx IN (SELECT idx FROM NAMES WHERE name=?101 and label=?102)"
115 " AND dataType = ?002;";
117 const char *DB_CMD_OBJECT_SELECT_BY_NAME_AND_OWNER =
118 "SELECT * FROM [join_name_object_tables] "
119 " WHERE (dataType BETWEEN ?001 AND ?002) "
120 " AND name=?101 and label=?102;";
123 const char *DB_CMD_KEY_INSERT =
124 "INSERT INTO KEYS(label, key) VALUES (?, ?);";
125 const char *DB_CMD_KEY_SELECT =
126 "SELECT key FROM KEYS WHERE label=?;";
127 const char *DB_CMD_KEY_DELETE =
128 "DELETE FROM KEYS WHERE label=?";
131 const char *DB_CMD_PERMISSION_SET = // SQLite does not support updating views
132 "REPLACE INTO PERMISSIONS(permissionLabel, permissionMask, idx) "
133 " VALUES (?104, ?105, (SELECT idx FROM NAMES WHERE name=?101 and label=?102));";
135 const char *DB_CMD_PERMISSION_SELECT =
136 "SELECT permissionMask FROM [join_name_permission_tables] "
137 " WHERE permissionLabel=?104 "
138 " AND name=?101 and label=?102;";
140 const char *DB_CMD_PERMISSION_DELETE = // SQLite does not support updating views
141 "DELETE FROM PERMISSIONS WHERE permissionLabel=?104 AND "
142 " idx=(SELECT idx FROM NAMES WHERE name=?101 and label=?102);";
146 * GROUP BY is necessary because of the following case:
147 * -There are several permissions to L1, N1 (label, name) from other accessors. When listing
148 * objects accessible by L1 the query will produce one result (L1, N1) for each allowed
149 * accessor but GROUP BY will reduce them to one so L1 will have (L1, N1) on its list only once
151 const char *DB_CMD_INFO_SELECT_BY_TYPE_AND_PERMISSION =
152 "SELECT label, name, dataType, backendId FROM [join_all_tables] "
153 " WHERE dataType>=?001 AND dataType<=?002 "
154 " AND permissionLabel=?104 AND permissionMask&?004!=0 GROUP BY idx;";
161 auto openSqlConnection(const std::string &path, const RawBuffer &rawPass)
163 auto conn = std::make_unique<SqlConnection>(path, SqlConnection::Flag::Option::CRW);
164 conn->SetKey(rawPass);
168 void convertLegacyDatabase(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass)
172 if (lstat(legacyPath.c_str(), &st)) {
173 const auto err = errno;
175 ThrowErr(Exc::DatabaseFailed, "lstat failed: " << GetErrnoString(err));
176 LogDebug("legacy db does not exist, proceeding");
179 if (!S_ISREG(st.st_mode))
180 ThrowErr(Exc::DatabaseFailed, "legacy db not a regular file");
182 if (unlink(path.c_str()) && ENOENT != errno)
183 ThrowErr(Exc::DatabaseFailed, "unlink failed: " << GetErrnoString());
185 // in no way to I condone the use of unique_ptr in this context; see: review
186 const auto handle = uptr<dlclose>(
187 dlopen(LIB_INSTALL_DIR "/lib" DUMP_LEGACY_DB_LIBNAME ".so", RTLD_LAZY)
188 ?: ThrowErr(Exc::DatabaseFailed, "dlopen failed: " << dlerror()));
189 const auto dumpLegacyDb = (char *(*)(const char *, const unsigned char *, size_t))
190 dlsym(handle.get(), "dumpLegacyDb")
191 ?: ThrowErr(Exc::DatabaseFailed, "dlsym failed: " << dlerror());
194 const RawBuffer pass = createHexPass(rawPass);
195 const CharUniquePtr sqlDump(dumpLegacyDb(legacyPath.c_str(), pass.data(), pass.size())
196 ?: ThrowErr(Exc::DatabaseFailed, "dump failed"));
198 // close to ensure full sync regardless of pragma synchronous value
199 // EXTRA is needed to sync the dir after transaction but isn't used in ckm
200 openSqlConnection(path, rawPass)->ExecCommand(sqlDump.get());
201 LogDebug("legacy db converted, removing");
204 if (unlink(legacyPath.c_str()))
205 ThrowErr(Exc::DatabaseFailed, "unlink legacy db failed: " << GetErrnoString());
206 std::string legacyPathCopy(legacyPath);
207 const auto legacyDirPath = dirname(&legacyPathCopy[0]);
208 const int legacyDirFd = TEMP_FAILURE_RETRY(open(legacyDirPath, O_RDONLY));
210 ThrowErr(Exc::DatabaseFailed, "open failed: " << GetErrnoString());
211 const auto fsyncRes = fsync(legacyDirFd);
212 const auto fsyncErrno = errno;
215 ThrowErr(Exc::DatabaseFailed, "fsync failed: " << GetErrnoString(fsyncErrno));
219 Crypto::Crypto(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass) :
220 m_inUserTransaction(false)
223 convertLegacyDatabase(legacyPath, path, rawPass);
224 m_connection = openSqlConnection(path, rawPass);
226 m_connection->ExecCommand("VACUUM;");
227 } catch (const SqlConnection::Exception::ConnectionBroken &e) {
228 ThrowErr(Exc::DatabaseFailed, "Couldn't connect to database: ", path,
230 } catch (const SqlConnection::Exception::InvalidArguments &e) {
231 ThrowErr(Exc::DatabaseFailed, "Couldn't set the key for database. ",
233 } catch (const SqlConnection::Exception::SyntaxError &e) {
234 ThrowErr(Exc::DatabaseFailed, "Couldn't initiate the database. ",
236 } catch (const SqlConnection::Exception::InternalError &e) {
237 ThrowErr(Exc::DatabaseFailed, "Couldn't create the database. ",
242 Crypto::Crypto(Crypto &&other) :
243 m_connection(std::move(other.m_connection)),
244 m_inUserTransaction(other.m_inUserTransaction)
246 other.m_inUserTransaction = false;
249 Crypto &Crypto::operator=(Crypto &&other)
254 m_connection = std::move(other.m_connection);
256 m_inUserTransaction = other.m_inUserTransaction;
257 other.m_inUserTransaction = false;
262 bool Crypto::getDBVersion(int &schemaVersion)
264 Transaction transaction(this);
266 if (m_connection->CheckTableExist("SCHEMA_INFO")) {
267 SchemaInfo info(m_connection.get());
268 if (info.getVersionInfo(schemaVersion)) {
269 LogDebug("Current DB version: " << schemaVersion);
274 LogDebug("No DB version known or DB not present");
276 if (m_connection->CheckTableExist("CKM_TABLE")) {
277 // special case: old CKM_TABLE exists
278 schemaVersion = DB_VERSION_1;
280 } else if (m_connection->CheckTableExist("NAME_TABLE")) {
281 // special case: new scheme exists, but no SCHEMA_INFO table present
282 schemaVersion = DB_VERSION_2;
286 // not recognized - proceed with an empty DBs
290 void Crypto::initDatabase()
292 // run migration if old database is present
294 if (!getDBVersion(schemaVersion) || schemaVersion > DB_VERSION_CURRENT) {
295 LogDebug("no database or database corrupted, initializing the DB");
298 if (schemaVersion < DB_VERSION_CURRENT) {
300 LogDebug("DB migration from version " << schemaVersion << " to version " <<
301 DB_VERSION_CURRENT << " started.");
302 Transaction transaction(this);
304 for (int vi = schemaVersion; vi < DB_VERSION_CURRENT; vi++) {
305 ScriptOptional script = getMigrationScript(vi);
308 LogError("Error, script to migrate database from version: " << vi <<
309 " to version: " << vi + 1 << " not available, resetting the DB");
313 LogInfo("migrating from version " << vi << " to version " << vi + 1);
314 m_connection->ExecCommand(script->c_str());
317 // update DB version info
318 SchemaInfo info(m_connection.get());
319 info.setVersionInfo();
320 transaction.commit();
328 Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
330 std::string scriptPath = SCRIPTS_PATH + scriptName + std::string(".sql");
331 std::ifstream is(scriptPath);
334 LogError("Script " << scriptPath << " not found!");
335 return ScriptOptional();
338 std::istreambuf_iterator<char> begin(is), end;
339 return ScriptOptional(std::string(begin, end));
342 Crypto::ScriptOptional Crypto::getMigrationScript(int db_version) const
344 std::string scriptPath = std::string(SCRIPT_MIGRATE) + std::to_string(
346 return getScript(scriptPath);
349 void Crypto::createDBSchema()
351 Transaction transaction(this);
353 ScriptOptional script = getScript(SCRIPT_CREATE_SCHEMA);
356 ThrowErr(Exc::DatabaseFailed,
357 "Can not create the database schema: no initialization script");
359 m_connection->ExecCommand((*script).c_str());
360 SchemaInfo info(m_connection.get());
361 info.setVersionInfo();
362 transaction.commit();
365 void Crypto::resetDB()
367 Transaction transaction(this);
368 ScriptOptional script = getScript(SCRIPT_DROP_ALL_ITEMS);
371 ThrowErr(Exc::DatabaseFailed, "Can not clear the database: no clearing script");
373 m_connection->ExecCommand((*script).c_str());
375 transaction.commit();
378 bool Crypto::isNameOwnerPresent(const Name &name, const ClientId &owner) const
381 NameTable nameTable(m_connection.get());
382 return nameTable.isPresent(name, owner);
383 } catch (const SqlConnection::Exception::SyntaxError &) {
384 LogError("Couldn't prepare insert statement");
385 } catch (const SqlConnection::Exception::InternalError &) {
386 LogError("Couldn't execute insert statement");
389 ThrowErr(Exc::DatabaseFailed,
390 "Couldn't check if name and owner pair is present");
393 void Crypto::saveRows(const Name &name, const ClientId &owner,
394 const RowVector &rows)
400 // transaction is present in the layer above
401 NameTable nameTable(m_connection.get());
402 ObjectTable objectTable(m_connection.get());
403 PermissionTable permissionTable(m_connection.get());
404 nameTable.addRow(name, owner);
406 for (const auto &i : rows)
407 objectTable.addRow(i);
409 permissionTable.setPermission(name,
412 static_cast<int>(DEFAULT_PERMISSIONS));
414 } catch (const SqlConnection::Exception::SyntaxError &e) {
415 LogError("Couldn't prepare insert statement: " <<
417 } catch (const SqlConnection::Exception::InternalError &e) {
418 LogError("Couldn't execute insert statement: " <<
422 ThrowErr(Exc::DatabaseFailed, "Couldn't save Row");
425 void Crypto::saveRow(const Row &row)
428 // transaction is present in the layer above
429 NameTable nameTable(m_connection.get());
430 ObjectTable objectTable(m_connection.get());
431 PermissionTable permissionTable(m_connection.get());
432 nameTable.addRow(row.name, row.owner);
433 objectTable.addRow(row);
434 permissionTable.setPermission(row.name,
437 static_cast<int>(DEFAULT_PERMISSIONS));
439 } catch (const SqlConnection::Exception::SyntaxError &) {
440 LogError("Couldn't prepare insert statement");
441 } catch (const SqlConnection::Exception::InternalError &) {
442 LogError("Couldn't execute insert statement");
445 ThrowErr(Exc::DatabaseFailed, "Couldn't save Row");
448 void Crypto::updateRow(const Row &row)
451 // transaction is present in the layer above
452 ObjectTable objectTable(m_connection.get());
453 objectTable.updateRow(row);
455 } catch (const SqlConnection::Exception::SyntaxError &) {
456 LogError("Couldn't prepare update statement");
457 } catch (const SqlConnection::Exception::InternalError &) {
458 LogError("Couldn't execute update statement");
461 ThrowErr(Exc::DatabaseFailed, "Couldn't update Row");
464 bool Crypto::deleteRow(
466 const ClientId &owner)
469 // transaction is present in the layer above
470 NameTable nameTable(m_connection.get());
472 if (nameTable.isPresent(name, owner)) {
473 nameTable.deleteRow(name, owner);
478 } catch (const SqlConnection::Exception::SyntaxError &) {
479 LogError("Couldn't prepare delete statement");
480 } catch (const SqlConnection::Exception::InternalError &) {
481 LogError("Couldn't execute delete statement");
484 ThrowErr(Exc::DatabaseFailed,
485 "Couldn't delete Row for name ", name, " using owner id ", owner);
489 const SqlConnection::DataCommandUniquePtr &selectCommand) const
492 row.name = selectCommand->GetColumnString(0);
493 row.owner = selectCommand->GetColumnString(1);
494 row.exportable = selectCommand->GetColumnInteger(2);
495 row.dataType = static_cast<DataType::Type>(selectCommand->GetColumnInteger(3));
497 static_cast<DBCMAlgType>(selectCommand->GetColumnInteger(4));
498 row.encryptionScheme = selectCommand->GetColumnInteger(5);
499 row.iv = selectCommand->GetColumnBlob(6);
500 row.dataSize = selectCommand->GetColumnInteger(7);
501 row.data = selectCommand->GetColumnBlob(8);
502 row.tag = selectCommand->GetColumnBlob(9);
503 row.backendId = static_cast<CryptoBackend>(selectCommand->GetColumnInteger(11));
507 PermissionMaskOptional Crypto::getPermissionRow(
509 const ClientId &owner,
510 const ClientId &accessor) const
513 PermissionTable permissionTable(m_connection.get());
514 return permissionTable.getPermissionRow(name, owner, accessor);
515 } catch (const SqlConnection::Exception::InvalidColumn &) {
516 LogError("Select statement invalid column error");
517 } catch (const SqlConnection::Exception::SyntaxError &) {
518 LogError("Couldn't prepare select statement");
519 } catch (const SqlConnection::Exception::InternalError &) {
520 LogError("Couldn't execute select statement");
523 return PermissionMaskOptional();
526 Crypto::RowOptional Crypto::getRow(
528 const ClientId &owner,
531 return getRow(name, owner, type, type);
534 Crypto::RowOptional Crypto::getRow(
536 const ClientId &owner,
537 DataType typeRangeStart,
538 DataType typeRangeStop)
541 SqlConnection::DataCommandUniquePtr selectCommand =
542 m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_OWNER);
543 selectCommand->BindInteger(1, typeRangeStart);
544 selectCommand->BindInteger(2, typeRangeStop);
546 // name table reference
547 selectCommand->BindString(101, name.c_str());
548 selectCommand->BindString(102, owner.c_str());
550 if (selectCommand->Step()) {
552 Row current_row = getRow(selectCommand);
555 return RowOptional(current_row);
557 return RowOptional();
559 } catch (const SqlConnection::Exception::InvalidColumn &) {
560 LogError("Select statement invalid column error");
561 } catch (const SqlConnection::Exception::SyntaxError &) {
562 LogError("Couldn't prepare select statement");
563 } catch (const SqlConnection::Exception::InternalError &) {
564 LogError("Couldn't execute select statement");
567 ThrowErr(Exc::DatabaseFailed,
568 "Couldn't get row of type <",
569 static_cast<int>(typeRangeStart), ",",
570 static_cast<int>(typeRangeStop), ">",
571 " name ", name, " with owner ", owner);
574 void Crypto::getRows(
576 const ClientId &owner,
580 getRows(name, owner, type, type, output);
583 void Crypto::getRows(
585 const ClientId &owner,
586 DataType typeRangeStart,
587 DataType typeRangeStop,
591 SqlConnection::DataCommandUniquePtr selectCommand =
592 m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_OWNER);
593 selectCommand->BindInteger(1, typeRangeStart);
594 selectCommand->BindInteger(2, typeRangeStop);
596 // name table reference
597 selectCommand->BindString(101, name.c_str());
598 selectCommand->BindString(102, owner.c_str());
600 while (selectCommand->Step()) {
602 output.push_back(getRow(selectCommand));
606 } catch (const SqlConnection::Exception::InvalidColumn &) {
607 LogError("Select statement invalid column error");
608 } catch (const SqlConnection::Exception::SyntaxError &) {
609 LogError("Couldn't prepare select statement");
610 } catch (const SqlConnection::Exception::InternalError &) {
611 LogError("Couldn't execute select statement");
614 ThrowErr(Exc::DatabaseFailed,
615 "Couldn't get row of type <",
616 static_cast<int>(typeRangeStart), ",",
617 static_cast<int>(typeRangeStop), ">",
618 " name ", name, " with owner label ", owner);
621 void Crypto::listInfos(const ClientId &accessor,
622 AliasInfoVector &aliasInfoVector,
625 listInfos(accessor, aliasInfoVector, type, type);
628 void Crypto::listInfos(const ClientId &accessor,
629 AliasInfoVector &aliasInfoVector,
630 DataType typeRangeStart,
631 DataType typeRangeStop)
634 Transaction transaction(this);
635 SqlConnection::DataCommandUniquePtr selectCommand =
636 m_connection->PrepareDataCommand(DB_CMD_INFO_SELECT_BY_TYPE_AND_PERMISSION);
637 selectCommand->BindInteger(1, typeRangeStart);
638 selectCommand->BindInteger(2, typeRangeStop);
639 selectCommand->BindString(104, accessor.c_str());
640 selectCommand->BindInteger(4, static_cast<int>(Permission::READ | Permission::REMOVE));
642 while (selectCommand->Step()) {
643 ClientId owner = selectCommand->GetColumnString(0);
644 Name name = selectCommand->GetColumnString(1);
645 int type = selectCommand->GetColumnInteger(2);
646 auto cryptoBackend = static_cast<CryptoBackend>(selectCommand->GetColumnInteger(3));
648 switch (cryptoBackend) {
649 case CryptoBackend::OpenSSL:
650 backendId = BackendId::SW;
652 case CryptoBackend::TrustZone:
653 backendId = BackendId::TZ;
656 ThrowErr(Exc::DatabaseFailed,
657 "Unexpected backend: ",
658 static_cast<unsigned>(cryptoBackend));
660 aliasInfoVector.emplace_back(AliasSupport::merge(owner, name), type, backendId);
664 } catch (const SqlConnection::Exception::InvalidColumn &) {
665 LogError("Select statement invalid column error");
666 } catch (const SqlConnection::Exception::SyntaxError &) {
667 LogError("Couldn't prepare select statement");
668 } catch (const SqlConnection::Exception::InternalError &) {
669 LogError("Couldn't execute select statement");
672 ThrowErr(Exc::DatabaseFailed,
673 "Couldn't list names of type <",
676 " accessible to client ", accessor);
679 void Crypto::saveKey(
680 const ClientId &owner,
681 const RawBuffer &key)
684 SqlConnection::DataCommandUniquePtr insertCommand =
685 m_connection->PrepareDataCommand(DB_CMD_KEY_INSERT);
686 insertCommand->BindString(1, owner.c_str());
687 insertCommand->BindBlob(2, key);
688 insertCommand->Step();
690 } catch (const SqlConnection::Exception::SyntaxError &) {
691 LogError("Couldn't prepare insert key statement");
692 } catch (const SqlConnection::Exception::InternalError &) {
693 LogError("Couldn't execute insert statement");
696 ThrowErr(Exc::DatabaseFailed, "Couldn't save key for owner ", owner);
699 Crypto::RawBufferOptional Crypto::getKey(const ClientId &owner)
702 SqlConnection::DataCommandUniquePtr selectCommand =
703 m_connection->PrepareDataCommand(DB_CMD_KEY_SELECT);
704 selectCommand->BindString(1, owner.c_str());
706 if (selectCommand->Step())
707 return RawBufferOptional(selectCommand->GetColumnBlob(0));
709 return RawBufferOptional();
710 } catch (const SqlConnection::Exception::InvalidColumn &) {
711 LogError("Select statement invalid column error");
712 } catch (const SqlConnection::Exception::SyntaxError &) {
713 LogError("Couldn't prepare insert key statement");
714 } catch (const SqlConnection::Exception::InternalError &) {
715 LogError("Couldn't execute insert statement");
718 ThrowErr(Exc::DatabaseFailed, "Couldn't get key for owner ", owner);
721 void Crypto::deleteKey(const ClientId &owner)
724 Transaction transaction(this);
726 SqlConnection::DataCommandUniquePtr deleteCommand =
727 m_connection->PrepareDataCommand(DB_CMD_KEY_DELETE);
728 deleteCommand->BindString(1, owner.c_str());
729 deleteCommand->Step();
731 NameTable nameTable(m_connection.get());
732 nameTable.deleteAllRows(owner);
734 transaction.commit();
736 } catch (const SqlConnection::Exception::SyntaxError &) {
737 LogError("Couldn't prepare insert key statement");
738 } catch (const SqlConnection::Exception::InternalError &) {
739 LogError("Couldn't execute insert statement");
742 ThrowErr(Exc::DatabaseFailed, "Couldn't delete key for owner ", owner);
745 void Crypto::setPermission(
747 const ClientId &owner,
748 const ClientId &accessor,
749 const PermissionMask permissionMask)
752 PermissionTable permissionTable(m_connection.get());
753 permissionTable.setPermission(name, owner, accessor, permissionMask);
755 } catch (const SqlConnection::Exception::SyntaxError &) {
756 LogError("Couldn't prepare set statement");
757 } catch (const SqlConnection::Exception::InternalError &) {
758 LogError("Couldn't execute set statement");
761 ThrowErr(Exc::DatabaseFailed, "Couldn't set permissions for name ", name);
764 void Crypto::SchemaInfo::setVersionInfo()
766 SqlConnection::DataCommandUniquePtr insertContextCommand =
767 m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET);
768 insertContextCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
769 insertContextCommand->BindString(103,
770 std::to_string(DB_VERSION_CURRENT).c_str());
771 insertContextCommand->Step();
774 bool Crypto::SchemaInfo::getVersionInfo(int &version)
776 SqlConnection::DataCommandUniquePtr selectCommand =
777 m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET);
778 selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
780 if (selectCommand->Step()) {
781 version = static_cast<int>(atoi(selectCommand->GetColumnString(1).c_str()));
787 void Crypto::PermissionTable::setPermission(
789 const ClientId &owner,
790 const ClientId &accessor,
791 const PermissionMask permissionMask)
793 if (permissionMask == Permission::NONE) {
795 SqlConnection::DataCommandUniquePtr deletePermissionCommand =
796 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_DELETE);
797 deletePermissionCommand->BindString(104, accessor.c_str());
798 deletePermissionCommand->BindString(101, name.c_str());
799 deletePermissionCommand->BindString(102, owner.c_str());
800 deletePermissionCommand->Step();
802 // add new permissions
803 SqlConnection::DataCommandUniquePtr setPermissionCommand =
804 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SET);
805 setPermissionCommand->BindString(104, accessor.c_str());
806 setPermissionCommand->BindInteger(105, static_cast<int>(permissionMask));
807 setPermissionCommand->BindString(101, name.c_str());
808 setPermissionCommand->BindString(102, owner.c_str());
809 setPermissionCommand->Step();
813 PermissionMaskOptional Crypto::PermissionTable::getPermissionRow(
815 const ClientId &owner,
816 const ClientId &accessor) const
818 SqlConnection::DataCommandUniquePtr selectCommand =
819 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SELECT);
820 selectCommand->BindString(104, accessor.c_str());
822 // name table reference
823 selectCommand->BindString(101, name.c_str());
824 selectCommand->BindString(102, owner.c_str());
826 if (selectCommand->Step()) {
827 // there is entry for the <name, owner> pair
828 return PermissionMaskOptional(PermissionMask(selectCommand->GetColumnInteger(
832 return PermissionMaskOptional();
835 void Crypto::NameTable::addRow(
837 const ClientId &owner)
840 SqlConnection::DataCommandUniquePtr insertNameCommand =
841 m_connection->PrepareDataCommand(DB_CMD_NAME_INSERT);
842 insertNameCommand->BindString(101, name.c_str());
843 insertNameCommand->BindString(102, owner.c_str());
844 insertNameCommand->Step();
847 void Crypto::NameTable::deleteRow(
849 const ClientId &ownerOwner)
851 SqlConnection::DataCommandUniquePtr deleteCommand =
852 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE);
853 deleteCommand->BindString(101, name.c_str());
854 deleteCommand->BindString(102, ownerOwner.c_str());
856 // Step() result code does not provide information whether
857 // anything was removed.
858 deleteCommand->Step();
861 void Crypto::NameTable::deleteAllRows(const ClientId &owner)
863 SqlConnection::DataCommandUniquePtr deleteData =
864 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE_BY_OWNER);
865 deleteData->BindString(102, owner.c_str());
867 // Step() result code does not provide information whether
868 // anything was removed.
872 bool Crypto::NameTable::isPresent(const Name &name,
873 const ClientId &owner) const
875 SqlConnection::DataCommandUniquePtr checkCmd =
876 m_connection->PrepareDataCommand(DB_CMD_NAME_COUNT_ROWS);
877 checkCmd->BindString(101, name.c_str());
878 checkCmd->BindString(102, owner.c_str());
880 if (checkCmd->Step()) {
881 int element_count = checkCmd->GetColumnInteger(0);
882 LogDebug("Item name: " << name << " owner: " << owner <<
883 " hit count: " << element_count);
885 if (element_count > 0)
892 void Crypto::ObjectTable::addRow(const Row &row)
894 SqlConnection::DataCommandUniquePtr insertObjectCommand =
895 m_connection->PrepareDataCommand(DB_CMD_OBJECT_INSERT);
896 insertObjectCommand->BindInteger(1, row.exportable);
897 insertObjectCommand->BindInteger(2, row.dataType);
898 insertObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
899 insertObjectCommand->BindInteger(4, row.encryptionScheme);
900 insertObjectCommand->BindBlob(5, row.iv);
901 insertObjectCommand->BindInteger(6, row.dataSize);
902 insertObjectCommand->BindBlob(7, row.data);
903 insertObjectCommand->BindBlob(8, row.tag);
904 insertObjectCommand->BindInteger(9, static_cast<int>(row.backendId));
906 // name table reference
907 insertObjectCommand->BindString(101, row.name.c_str());
908 insertObjectCommand->BindString(102, row.owner.c_str());
910 insertObjectCommand->Step();
913 void Crypto::ObjectTable::updateRow(const Row &row)
915 SqlConnection::DataCommandUniquePtr updateObjectCommand =
916 m_connection->PrepareDataCommand(DB_CMD_OBJECT_UPDATE);
917 updateObjectCommand->BindInteger(2, row.dataType);
918 updateObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
919 updateObjectCommand->BindInteger(4, row.encryptionScheme);
920 updateObjectCommand->BindBlob(5, row.iv);
921 updateObjectCommand->BindInteger(6, row.dataSize);
922 updateObjectCommand->BindBlob(7, row.data);
923 updateObjectCommand->BindBlob(8, row.tag);
925 // name table reference
926 updateObjectCommand->BindString(101, row.name.c_str());
927 updateObjectCommand->BindString(102, row.owner.c_str());
929 updateObjectCommand->Step();
934 #pragma GCC diagnostic pop