Add functions required during db debug.
[platform/core/security/key-manager.git] / src / manager / service / db-crypto.cpp
index c0998e9..ce9d750 100644 (file)
@@ -20,6 +20,8 @@
  * @brief       Implementation of encrypted db access layer
  */
 
+#include <fstream>
+#include <sstream>
 #include <db-crypto.h>
 #include <dpl/db/sql_connection.h>
 #include <dpl/log/log.h>
 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
 
 namespace {
-    const char *main_table = "CKM_TABLE";
-    const char *key_table = "KEY_TABLE";
-
-// CKM_TABLE (alias TEXT, label TEXT, restricted INT, exportable INT, dataType INT,
-//            algorithmType INT, encryptionScheme INT, iv BLOB, dataSize INT, data BLOB)
-
-    const char *db_create_main_cmd =
-            "CREATE TABLE CKM_TABLE("
-            "   alias TEXT NOT NULL,"
-            "   label TEXT NOT NULL,"
-            "   exportable INTEGER NOT NULL,"
-            "   dataType INTEGER NOT NULL,"
-            "   algorithmType INTEGER NOT NULL,"
-            "   encryptionScheme INTEGER NOT NULL,"
-            "   iv BLOB NOT NULL,"
-            "   dataSize INTEGER NOT NULL,"
-            "   data BLOB NOT NULL,"
-            "   tag BLOB NOT NULL,"
-            "   PRIMARY KEY(alias, label),"
-            "   UNIQUE(alias)"
-            ");";
-
-
-    const char *insert_main_cmd =
-            "INSERT INTO CKM_TABLE("
-            //      1   2       3
-            "   alias, label, exportable,"
-            //      4           5           6
-            "   dataType, algorithmType, encryptionScheme,"
-            //  7       8       9    10
-            "   iv, dataSize, data, tag) "
-            "VALUES("
-            "   ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
-
-    const char *select_alias_cmd =
-            //                                   1              2        3
-            "SELECT * FROM CKM_TABLE WHERE alias=? AND dataType=? AND label=?; ";
-
-    const char *select_check_alias_cmd =
-            //                                          1           2
-            "SELECT dataType FROM CKM_TABLE WHERE alias=? AND label=?; ";
-
-    const char *select_check_global_alias_cmd =
-            //                                       1
-            "SELECT label FROM CKM_TABLE WHERE alias=? ;";
-
-    const char *select_count_rows_cmd =
-            //                                   1           2
-            "SELECT COUNT(alias) FROM CKM_TABLE WHERE alias=? AND label=?;";
-
-    const char *select_key_alias_cmd =
-            //                                   1
-            "SELECT * FROM CKM_TABLE WHERE alias=?"
-            //                     2     3
-            " AND dataType BETWEEN ? AND ? "
-            //          4
-            " AND label=? ;";
-
-    const char *select_key_type_cmd =
-            "SELECT alias FROM CKM_TABLE WHERE "
-            //                1
-                " dataType >= ? AND "
-            //                2
-                " dataType <= ? AND "
-            //        3
-                " label=?;";
-
-    const char *select_type_cmd =
-            //                                     1            2
-            "SELECT alias FROM CKM_TABLE WHERE dataType=? AND label=?;";
-
-    const char *delete_alias_cmd =
-            //                                 1           2
-            "DELETE FROM CKM_TABLE WHERE alias=? AND label=?;";
-
-    const char *delete_data_with_key_cmd =
-            //                                 1
-            "DELETE FROM CKM_TABLE WHERE label=?;";
-
-// KEY_TABLE (label TEXT, key BLOB)
-
-    const char *db_create_key_cmd =
-            "CREATE TABLE KEY_TABLE("
-            "   label TEXT PRIMARY KEY,"
-            "   key BLOB NOT NULL"
-            ");";
-
-    const char *insert_key_cmd =
-            "INSERT INTO KEY_TABLE(label, key) VALUES (?, ?);";
-    const char *select_key_cmd =
-            "SELECT key FROM KEY_TABLE WHERE label=?;";
-    const char *delete_key_cmd =
-            "DELETE FROM KEY_TABLE WHERE label=?";
+    const CKM::PermissionMask DEFAULT_PERMISSIONS =
+                        static_cast<CKM::PermissionMask>(CKM::Permission::READ | CKM::Permission::REMOVE);
+
+    const char *SCRIPTS_PATH = "/usr/share/ckm/scripts/";
+
+    enum DBVersion : int {
+        DB_VERSION_1                   = 1,
+        DB_VERSION_2                   = 2,
+        /* ... since version 3, there is no need to manually
+         * recognize database version.
+         * Remember only that if doing changes to the database,
+         * increment and update DB_VERSION_CURRENT,
+         * then provide migration mechanism!
+         */
+        DB_VERSION_CURRENT             = 4
+    };
+
+    const char *SCRIPT_CREATE_SCHEMA                = "create_schema";
+    const char *SCRIPT_DROP_ALL_ITEMS               = "drop_all";
+    const char *SCRIPT_MIGRATE                      = "migrate_";
+
+    // common substitutions:
+    // 100 - idx
+    // 101 - name
+    // 102 - label
+    // 103 - value
+    // 104 - permissionLabel
+    // 105 - permissionMask
+    const char *DB_CMD_SCHEMA_SET =
+            "REPLACE INTO SCHEMA_INFO(name, value) "
+            "   VALUES(?101, ?103);";
+
+    const char *DB_CMD_SCHEMA_GET =
+            "SELECT * FROM SCHEMA_INFO WHERE name=?101;";
+
+    const char *DB_SCHEMA_VERSION_FIELD = "schema_version";
+
+
+    const char *DB_CMD_NAME_INSERT =
+            "INSERT INTO NAMES("
+            "   name, label) "
+            "   VALUES(?101, ?102);";
+
+    const char *DB_CMD_NAME_COUNT_ROWS =
+            "SELECT COUNT(idx) FROM NAMES WHERE name=?101 AND label=?102;";
+
+    const char *DB_CMD_NAME_DELETE =
+            "DELETE FROM NAMES WHERE name=?101 AND label=?102;";
+
+    const char *DB_CMD_NAME_DELETE_BY_LABEL =
+            "DELETE FROM NAMES WHERE label=?102;";
+
+
+    const char *DB_CMD_OBJECT_INSERT =
+            "INSERT INTO OBJECTS("
+            "   exportable, dataType,"
+            "   algorithmType, encryptionScheme,"
+            "   iv, dataSize, data, tag, idx, backendId) "
+            "   VALUES(?001, ?002, ?003, ?004, ?005, "
+            "          ?006, ?007, ?008,"
+            "          (SELECT idx FROM NAMES WHERE name=?101 and label=?102),"
+            "          ?009"
+            "         );";
+
+    const char *DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL =
+            "SELECT * FROM [join_name_object_tables] "
+            " WHERE (dataType BETWEEN ?001 AND ?002) "
+            " AND name=?101 and label=?102;";
+
+
+    const char *DB_CMD_KEY_INSERT =
+            "INSERT INTO KEYS(label, key) VALUES (?, ?);";
+    const char *DB_CMD_KEY_SELECT =
+            "SELECT key FROM KEYS WHERE label=?;";
+    const char *DB_CMD_KEY_DELETE =
+            "DELETE FROM KEYS WHERE label=?";
+
+
+    const char *DB_CMD_PERMISSION_SET = // SQLite does not support updating views
+            "REPLACE INTO PERMISSIONS(permissionLabel, permissionMask, idx) "
+            " VALUES (?104, ?105, (SELECT idx FROM NAMES WHERE name=?101 and label=?102));";
+
+    const char *DB_CMD_PERMISSION_SELECT =
+            "SELECT permissionMask FROM [join_name_permission_tables] "
+            " WHERE permissionLabel=?104 "
+            " AND name=?101 and label=?102;";
+
+    const char *DB_CMD_PERMISSION_DELETE = // SQLite does not support updating views
+            "DELETE FROM PERMISSIONS WHERE permissionLabel=?104 AND "
+            " idx=(SELECT idx FROM NAMES WHERE name=?101 and label=?102);";
+
+
+    /*
+     * GROUP BY is necessary because of the following case:
+     * -There are several permissions to L1, N1 (label, name) from other accessors. When listing
+     *  objects accessible by L1 the query will produce one result (L1, N1) for each allowed
+     *  accessor but GROUP BY will reduce them to one so L1 will have (L1, N1) on its list only once
+     */
+    const char *DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION =
+            "SELECT label, name FROM [join_all_tables] "
+            " WHERE dataType>=?001 AND dataType<=?002 "
+            " AND permissionLabel=?104 AND permissionMask&?004!=0 GROUP BY idx;";
 }
 
 namespace CKM {
-using namespace DB;
-    DBCrypto::DBCrypto(const std::string& path,
-                         const RawBuffer &rawPass) {
+namespace DB {
+    Crypto::Crypto(const std::string& path, const RawBuffer &rawPass)
+    {
         m_connection = NULL;
         m_inUserTransaction = false;
         Try {
             m_connection = new SqlConnection(path, SqlConnection::Flag::Option::CRW);
             m_connection->SetKey(rawPass);
-            m_connection->ExecCommand("VACUUM;");
             initDatabase();
+            m_connection->ExecCommand("VACUUM;");
         } Catch(SqlConnection::Exception::ConnectionBroken) {
             LogError("Couldn't connect to database: " << path);
-            ReThrow(DBCrypto::Exception::InternalError);
+            ReThrow(Crypto::Exception::InternalError);
         } Catch(SqlConnection::Exception::InvalidArguments) {
             LogError("Couldn't set the key for database");
-            ReThrow(DBCrypto::Exception::InternalError);
+            ReThrow(Crypto::Exception::InternalError);
         } Catch(SqlConnection::Exception::SyntaxError) {
             LogError("Couldn't initiate the database");
-            ReThrow(DBCrypto::Exception::InternalError);
+            ReThrow(Crypto::Exception::InternalError);
         } Catch(SqlConnection::Exception::InternalError) {
             LogError("Couldn't create the database");
-            ReThrow(DBCrypto::Exception::InternalError);
+            ReThrow(Crypto::Exception::InternalError);
         }
     }
 
-    DBCrypto::DBCrypto(DBCrypto &&other) :
+    Crypto::Crypto(Crypto &&other) :
             m_connection(other.m_connection),
-            m_inUserTransaction(other.m_inUserTransaction){
+            m_inUserTransaction(other.m_inUserTransaction)
+    {
         other.m_connection = NULL;
         other.m_inUserTransaction = false;
     }
 
-    DBCrypto::~DBCrypto() {
+    Crypto::~Crypto() {
         delete m_connection;
     }
 
-    DBCrypto& DBCrypto::operator=(DBCrypto&& other) {
+    Crypto& Crypto::operator=(Crypto&& other) {
         if (this == &other)
             return *this;
         delete m_connection;
@@ -175,7 +187,7 @@ using namespace DB;
         return *this;
     }
 
-    void DBCrypto::createTable(
+    void Crypto::createTable(
             const char* create_cmd,
             const char *table_name)
     {
@@ -190,116 +202,240 @@ using namespace DB;
         }
     }
 
-    void DBCrypto::initDatabase() {
-        Transaction transaction(this);
-        if(!m_connection->CheckTableExist(main_table)) {
-            createTable(db_create_main_cmd, main_table);
-        }
-        if(!m_connection->CheckTableExist(key_table)) {
-            createTable(db_create_key_cmd, key_table);
+    void Crypto::createView(
+            const char* create_cmd)
+    {
+        Try {
+            m_connection->ExecCommand(create_cmd);
+        } Catch(SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't create view!");
+            throw;
+        } Catch(SqlConnection::Exception::InternalError) {
+            LogError("Sqlite got into infinite busy state");
+            throw;
         }
-        transaction.commit();
     }
 
-    bool DBCrypto::checkGlobalAliasExist(const std::string& alias) {
-        SqlConnection::DataCommandUniquePtr checkCmd =
-                m_connection->PrepareDataCommand(select_check_global_alias_cmd);
-        checkCmd->BindString(1, alias.c_str());
-        if(checkCmd->Step()) {
-            LogDebug("Global alias '" << alias  << "' exists already for label "
-                    << checkCmd->GetColumnString(0));
+    bool Crypto::getDBVersion(int & schemaVersion)
+    {
+        SchemaInfo SchemaInfo(this);
+        if(SchemaInfo.getVersionInfo(schemaVersion)) {
+            LogDebug("Current DB version: " << schemaVersion);
             return true;
-        } else
-            return false;
-    }
+        }
+        else
+        {
+            LogDebug("No DB version known or DB not present");
+
+            // special case: old CKM_TABLE exists
+            if(m_connection->CheckTableExist("CKM_TABLE")) {
+                schemaVersion = DB_VERSION_1;
+                return true;
+            }
 
-    bool DBCrypto::checkAliasExist(
-            const std::string& alias,
-            const std::string& label) {
-        SqlConnection::DataCommandUniquePtr checkCmd =
-                m_connection->PrepareDataCommand(select_check_alias_cmd);
-        checkCmd->BindString(1, alias.c_str());
-        checkCmd->BindString(2, label.c_str());
-        if(checkCmd->Step()) {
-            LogDebug("Private alias '" << alias  << "' exists already for type "
-                    << checkCmd->GetColumnInteger(0));
-            return true;
-        } else
-            return false;
+            // special case: new scheme exists, but no SCHEMA_INFO table present
+            else if(m_connection->CheckTableExist("NAME_TABLE")) {
+                schemaVersion = DB_VERSION_2;
+                return true;
+            }
+        }
+        // not recognized - proceed with an empty DBs
+        return false;
     }
 
-    void DBCrypto::saveDBRow(const DBRow &row){
-        Try {
-
-            //Sqlite does not support partial index in our version,
-            //so we do it by hand
+    void Crypto::initDatabase()
+    {
+        // run migration if old database is present
+        int schemaVersion;
+        if( getDBVersion(schemaVersion)==false ||       // DB empty or corrupted
+            schemaVersion > DB_VERSION_CURRENT)         // or too new scheme
+        {
+            LogDebug("no database or database corrupted, initializing the DB");
+            resetDB();
+        }
+        else
+        {
+            // migration needed
+            LogDebug("DB migration from version " << schemaVersion << " to version " << DB_VERSION_CURRENT << " started.");
             Transaction transaction(this);
-            if(checkAliasExist(row.alias, row.smackLabel)) {
-                ThrowMsg(DBCrypto::Exception::AliasExists,
-                        "Alias exists for alias: " << row.alias
-                        << ", label: " << row.smackLabel);
+            for(int vi=schemaVersion; vi<DB_VERSION_CURRENT; vi++)
+            {
+                ScriptOptional script = getMigrationScript(vi);
+                if(!script)
+                {
+                    LogError("Error, script to migrate database from version: " << vi <<
+                             " to version: " << vi+1 << " not available, resetting the DB");
+                    resetDB();
+                    break;
+                }
+
+                LogInfo("migrating from version " << vi << " to version " << vi+1);
+                m_connection->ExecCommand((*script).c_str());
             }
+            // update DB version info
+            SchemaInfo SchemaInfo(this);
+            SchemaInfo.setVersionInfo();
+            transaction.commit();
+        }
+    }
 
-            SqlConnection::DataCommandUniquePtr insertCommand =
-                    m_connection->PrepareDataCommand(insert_main_cmd);
-            insertCommand->BindString(1, row.alias.c_str());
-            insertCommand->BindString(2, row.smackLabel.c_str());
-            insertCommand->BindInteger(3, row.exportable);
-            insertCommand->BindInteger(4, static_cast<int>(row.dataType));
-            insertCommand->BindInteger(5, static_cast<int>(row.algorithmType));
-            insertCommand->BindInteger(6, row.encryptionScheme);
-            insertCommand->BindBlob(7, row.iv);
-            insertCommand->BindInteger(8, row.dataSize);
-            insertCommand->BindBlob(9, row.data);
-            insertCommand->BindBlob(10, row.tag);
+    Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
+    {
+        std::string scriptPath = SCRIPTS_PATH + scriptName + std::string(".sql");
+        std::ifstream is(scriptPath);
+        if(is.fail()) {
+            LogError("Script " << scriptPath << " not found!");
+            return ScriptOptional();
+        }
 
-            insertCommand->Step();
-            transaction.commit();
+        std::istreambuf_iterator<char> begin(is),end;
+        return ScriptOptional(std::string(begin, end));
+    }
+
+    Crypto::ScriptOptional Crypto::getMigrationScript(int db_version) const
+    {
+        std::string scriptPath = std::string(SCRIPT_MIGRATE) + std::to_string(db_version);
+        return getScript(scriptPath);
+    }
+
+    void Crypto::createDBSchema() {
+        Transaction transaction(this);
+
+        ScriptOptional script = getScript(SCRIPT_CREATE_SCHEMA);
+        if(!script)
+        {
+            std::string errmsg = "Can not create the database schema: no initialization script";
+            LogError(errmsg);
+            ThrowMsg(Exception::InternalError, errmsg);
+        }
+
+        m_connection->ExecCommand((*script).c_str());
+        SchemaInfo SchemaInfo(this);
+        SchemaInfo.setVersionInfo();
+        transaction.commit();
+    }
+
+    void Crypto::resetDB() {
+        Transaction transaction(this);
+        ScriptOptional script = getScript(SCRIPT_DROP_ALL_ITEMS);
+        if(!script)
+        {
+            std::string errmsg = "Can not clear the database: no clearing script";
+            LogError(errmsg);
+            ThrowMsg(Exception::InternalError, errmsg);
+        }
+
+        m_connection->ExecCommand((*script).c_str());
+        createDBSchema();
+        transaction.commit();
+    }
+
+    bool Crypto::isNameLabelPresent(const Name &name, const Label &owner) const {
+        Try {
+            NameTable nameTable(this->m_connection);
+            return nameTable.isPresent(name, owner);
+        } Catch(SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare insert statement");
+        } Catch(SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute insert statement");
+        }
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't check if name and label pair is present");
+    }
+
+    void Crypto::saveRows(const Name &name, const Label &owner, const RowVector &rows)
+    {
+        Try {
+            // transaction is present in the layer above
+            NameTable nameTable(this->m_connection);
+            ObjectTable objectTable(this->m_connection);
+            PermissionTable permissionTable(this->m_connection);
+            nameTable.addRow(name, owner);
+            for (const auto &i: rows)
+                objectTable.addRow(i);
+            permissionTable.setPermission(name,
+                                          owner,
+                                          owner,
+                                          static_cast<int>(DEFAULT_PERMISSIONS));
             return;
+        } Catch(SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare insert statement");
+        } Catch(SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute insert statement: " << _rethrown_exception.GetMessage());
+        }
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't save Row");
+    }
 
+    void Crypto::saveRow(const Row &row) {
+        Try {
+            // transaction is present in the layer above
+            NameTable nameTable(this->m_connection);
+            ObjectTable objectTable(this->m_connection);
+            PermissionTable permissionTable(this->m_connection);
+            nameTable.addRow(row.name, row.ownerLabel);
+            objectTable.addRow(row);
+            permissionTable.setPermission(row.name,
+                                          row.ownerLabel,
+                                          row.ownerLabel,
+                                          static_cast<int>(DEFAULT_PERMISSIONS));
+            return;
         } Catch(SqlConnection::Exception::SyntaxError) {
             LogError("Couldn't prepare insert statement");
         } Catch(SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute insert statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't save DBRow");
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't save Row");
+    }
+
+    bool Crypto::deleteRow(
+            const Name &name,
+            const Label &ownerLabel)
+    {
+        Try {
+            // transaction is present in the layer above
+            NameTable nameTable(this->m_connection);
+            if(nameTable.isPresent(name, ownerLabel))
+            {
+                nameTable.deleteRow(name, ownerLabel);
+                return true;
+            }
+            return false;
+        } Catch (SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare delete statement");
+        } Catch (SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute delete statement");
+        }
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't delete Row for name " << name << " using ownerLabel " << ownerLabel);
     }
 
-    DBRow DBCrypto::getRow(const SqlConnection::DataCommandUniquePtr &selectCommand) {
-        DBRow row;
-        row.alias = selectCommand->GetColumnString(0);
-        row.smackLabel = selectCommand->GetColumnString(1);
+    Row Crypto::getRow(
+            const SqlConnection::DataCommandUniquePtr &selectCommand) const {
+        Row row;
+        row.name = selectCommand->GetColumnString(0);
+        row.ownerLabel = selectCommand->GetColumnString(1);
         row.exportable = selectCommand->GetColumnInteger(2);
-        row.dataType = static_cast<DBDataType>(selectCommand->GetColumnInteger(3));
+        row.dataType = DataType(selectCommand->GetColumnInteger(3));
         row.algorithmType = static_cast<DBCMAlgType>(selectCommand->GetColumnInteger(4));
         row.encryptionScheme = selectCommand->GetColumnInteger(5);
         row.iv = selectCommand->GetColumnBlob(6);
         row.dataSize = selectCommand->GetColumnInteger(7);
         row.data = selectCommand->GetColumnBlob(8);
         row.tag = selectCommand->GetColumnBlob(9);
+        row.backendId = static_cast<CryptoBackend>(selectCommand->GetColumnInteger(11));
         return row;
     }
 
-    DBCrypto::DBRowOptional DBCrypto::getDBRow(
-        const Alias &alias,
-        const std::string &label,
-        DBDataType type)
+    PermissionMaskOptional Crypto::getPermissionRow(
+        const Name &name,
+        const Label &ownerLabel,
+        const Label &accessorLabel) const
     {
         Try {
-            Transaction transaction(this);
-            SqlConnection::DataCommandUniquePtr selectCommand =
-                    m_connection->PrepareDataCommand(select_alias_cmd);
-            selectCommand->BindString(1, alias.c_str());
-            selectCommand->BindInteger(2, static_cast<int>(type));
-            selectCommand->BindString(3, label.c_str());
-
-            if(selectCommand->Step()) {
-                transaction.commit();
-                return DBRowOptional(getRow(selectCommand));
-            } else {
-                return DBRowOptional();
-            }
+            PermissionTable permissionTable(this->m_connection);
+            return permissionTable.getPermissionRow(name, ownerLabel, accessorLabel);
         } Catch (SqlConnection::Exception::InvalidColumn) {
             LogError("Select statement invalid column error");
         } Catch (SqlConnection::Exception::SyntaxError) {
@@ -307,29 +443,42 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute select statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't get row for type " << static_cast<int>(type) <<
-                " alias " << alias << " and label " << label);
+        return PermissionMaskOptional();
     }
 
-    DBCrypto::DBRowOptional DBCrypto::getKeyDBRow(
-        const Alias &alias,
-        const std::string &label)
+    Crypto::RowOptional Crypto::getRow(
+        const Name &name,
+        const Label &ownerLabel,
+        DataType type)
     {
-        Try{
-            Transaction transaction(this);
+        return getRow(name, ownerLabel, type, type);
+    }
+
+    Crypto::RowOptional Crypto::getRow(
+        const Name &name,
+        const Label &ownerLabel,
+        DataType typeRangeStart,
+        DataType typeRangeStop)
+    {
+        Try {
             SqlConnection::DataCommandUniquePtr selectCommand =
-                    m_connection->PrepareDataCommand(select_key_alias_cmd);
-            selectCommand->BindString(1, alias.c_str());
-            selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_FIRST));
-            selectCommand->BindInteger(3, static_cast<int>(DBDataType::DB_KEY_LAST));
-            selectCommand->BindString(4, label.c_str());
+                    m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
+            selectCommand->BindInteger(1, typeRangeStart);
+            selectCommand->BindInteger(2, typeRangeStop);
 
-            if(selectCommand->Step()) {
-                transaction.commit();
-                return DBRowOptional(getRow(selectCommand));
+            // name table reference
+            selectCommand->BindString (101, name.c_str());
+            selectCommand->BindString (102, ownerLabel.c_str());
+
+            if(selectCommand->Step())
+            {
+                // extract data
+                Row current_row = getRow(selectCommand);
+
+                // all okay, proceed
+                return RowOptional(current_row);
             } else {
-                return DBRowOptional();
+                return RowOptional();
             }
         } Catch (SqlConnection::Exception::InvalidColumn) {
             LogError("Select statement invalid column error");
@@ -338,26 +487,43 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute select statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't get Key for alias " << alias
-                << " and label " << label);
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't get row of type <" <<
+                static_cast<int>(typeRangeStart) << "," <<
+                static_cast<int>(typeRangeStop)  << ">" <<
+                " name " << name << " with owner label " << ownerLabel);
     }
 
-    void DBCrypto::getSingleType(
-            DBDataType type,
-            const std::string& label,
-            AliasVector& aliases)
+    void Crypto::getRows(
+        const Name &name,
+        const Label &ownerLabel,
+        DataType type,
+        RowVector &output)
     {
-        Try{
-            SqlConnection::DataCommandUniquePtr selectCommand =
-                            m_connection->PrepareDataCommand(select_type_cmd);
-            selectCommand->BindInteger(1, static_cast<int>(type));
-            selectCommand->BindString(2, label.c_str());
+        getRows(name, ownerLabel, type, type, output);
+    }
 
-            while(selectCommand->Step()) {
-                Alias alias;
-                alias = selectCommand->GetColumnString(0);
-                aliases.push_back(alias);
+    void Crypto::getRows(
+        const Name &name,
+        const Label &ownerLabel,
+        DataType typeRangeStart,
+        DataType typeRangeStop,
+        RowVector &output)
+    {
+        Try {
+            SqlConnection::DataCommandUniquePtr selectCommand =
+                    m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
+            selectCommand->BindInteger(1, typeRangeStart);
+            selectCommand->BindInteger(2, typeRangeStop);
+
+            // name table reference
+            selectCommand->BindString (101, name.c_str());
+            selectCommand->BindString (102, ownerLabel.c_str());
+
+            while(selectCommand->Step())
+            {
+                // extract data
+                output.push_back(getRow(selectCommand));
             }
             return;
         } Catch (SqlConnection::Exception::InvalidColumn) {
@@ -367,38 +533,41 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute select statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't get type " << static_cast<int>(type)
-                << " for label " << label);
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't get row of type <" <<
+                static_cast<int>(typeRangeStart) << "," <<
+                static_cast<int>(typeRangeStop)  << ">" <<
+                " name " << name << " with owner label " << ownerLabel);
     }
 
-    void DBCrypto::getAliases(
-        DBDataType type,
-        const std::string& label,
-        AliasVector& aliases)
+    void Crypto::listNames(
+        const Label &smackLabel,
+        LabelNameVector& labelNameVector,
+        DataType type)
     {
-        getSingleType(type, label, aliases);
+        listNames(smackLabel, labelNameVector, type, type);
     }
 
-
-    void DBCrypto::getKeyAliases(
-        const std::string &label,
-        AliasVector &aliases)
+    void Crypto::listNames(
+        const Label &smackLabel,
+        LabelNameVector& labelNameVector,
+        DataType typeRangeStart,
+        DataType typeRangeStop)
     {
         Try{
             Transaction transaction(this);
             SqlConnection::DataCommandUniquePtr selectCommand =
-                            m_connection->PrepareDataCommand(select_key_type_cmd);
-            selectCommand->BindInteger(1, static_cast<int>(DBDataType::DB_KEY_FIRST));
-            selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_LAST));
-            selectCommand->BindString(3, label.c_str());
+                            m_connection->PrepareDataCommand(DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION);
+            selectCommand->BindInteger(1, static_cast<int>(typeRangeStart));
+            selectCommand->BindInteger(2, static_cast<int>(typeRangeStop));
+            selectCommand->BindString(104, smackLabel.c_str());
+            selectCommand->BindInteger(4, static_cast<int>(Permission::READ | Permission::REMOVE));
 
             while(selectCommand->Step()) {
-                Alias alias;
-                alias = selectCommand->GetColumnString(0);
-                aliases.push_back(alias);
+                Label ownerLabel = selectCommand->GetColumnString(0);
+                Name name = selectCommand->GetColumnString(1);
+                labelNameVector.push_back(std::make_pair(ownerLabel, name));
             }
-            transaction.commit();
             return;
         } Catch (SqlConnection::Exception::InvalidColumn) {
             LogError("Select statement invalid column error");
@@ -407,85 +576,46 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute select statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't get key aliases for label " << label);
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't list names of type <" <<
+                static_cast<int>(typeRangeStart) << "," <<
+                static_cast<int>(typeRangeStop)  << ">" <<
+                " accessible to client label " << smackLabel);
     }
 
-    int DBCrypto::countRows(const Alias &alias, const std::string &label) {
-        SqlConnection::DataCommandUniquePtr checkCmd =
-                    m_connection->PrepareDataCommand(select_count_rows_cmd);
-        checkCmd->BindString(1, alias.c_str());
-        checkCmd->BindString(2, label.c_str());
-        if(checkCmd->Step()) {
-            return checkCmd->GetColumnInteger(0);
-        } else {
-            LogDebug("Row does not exist for alias=" << alias << "and label=" << label);
-            return 0;
-        }
-    }
-    int DBCrypto::deleteDBRow(
-            const Alias &alias,
-            const std::string &label)
-    {
-        Try {
-            Transaction transaction(this);
-            unsigned int count;
-            if((count = countRows(alias, label)) > 0) {
-                SqlConnection::DataCommandUniquePtr deleteCommand =
-                        m_connection->PrepareDataCommand(delete_alias_cmd);
-                deleteCommand->BindString(1, alias.c_str());
-                deleteCommand->BindString(2, label.c_str());
-                deleteCommand->Step();
-                transaction.commit();
-            }
-            return count;
-        } Catch (SqlConnection::Exception::SyntaxError) {
-            LogError("Couldn't prepare delete statement");
-        } Catch (SqlConnection::Exception::InternalError) {
-            LogError("Couldn't execute delete statement");
-        }
-        ThrowMsg(DBCrypto::Exception::InternalError,
-                "Couldn't delete DBRow for alias " << alias
-                << " and label " << label);
-    }
 
-    void DBCrypto::saveKey(
-            const std::string& label,
+
+    void Crypto::saveKey(
+            const Label& label,
             const RawBuffer &key)
     {
         Try {
-            Transaction transaction(this);
             SqlConnection::DataCommandUniquePtr insertCommand =
-                    m_connection->PrepareDataCommand(insert_key_cmd);
+                    m_connection->PrepareDataCommand(DB_CMD_KEY_INSERT);
             insertCommand->BindString(1, label.c_str());
             insertCommand->BindBlob(2, key);
             insertCommand->Step();
-            transaction.commit();
             return;
         } Catch (SqlConnection::Exception::SyntaxError) {
             LogError("Couldn't prepare insert key statement");
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute insert statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
+        ThrowMsg(Crypto::Exception::InternalError,
                 "Couldn't save key for label " << label);
     }
 
-    DBCrypto::RawBufferOptional DBCrypto::getKey(
-            const std::string& label)
+    Crypto::RawBufferOptional Crypto::getKey(const Label& label)
     {
         Try {
-            Transaction transaction(this);
             SqlConnection::DataCommandUniquePtr selectCommand =
-                    m_connection->PrepareDataCommand(select_key_cmd);
+                    m_connection->PrepareDataCommand(DB_CMD_KEY_SELECT);
             selectCommand->BindString(1, label.c_str());
 
             if (selectCommand->Step()) {
-                transaction.commit();
                 return RawBufferOptional(
                         selectCommand->GetColumnBlob(0));
             } else {
-                transaction.commit();
                 return RawBufferOptional();
             }
 
@@ -496,23 +626,21 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute insert statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
+        ThrowMsg(Crypto::Exception::InternalError,
                 "Couldn't get key for label " << label);
     }
 
-    void DBCrypto::deleteKey(const std::string& label) {
+    void Crypto::deleteKey(const Label& label) {
         Try {
             Transaction transaction(this);
 
             SqlConnection::DataCommandUniquePtr deleteCommand =
-                    m_connection->PrepareDataCommand(delete_key_cmd);
+                    m_connection->PrepareDataCommand(DB_CMD_KEY_DELETE);
             deleteCommand->BindString(1, label.c_str());
             deleteCommand->Step();
 
-            SqlConnection::DataCommandUniquePtr deleteData =
-                m_connection->PrepareDataCommand(delete_data_with_key_cmd);
-            deleteData->BindString(1, label.c_str());
-            deleteData->Step();
+            NameTable nameTable(this->m_connection);
+            nameTable.deleteAllRows(label);
 
             transaction.commit();
             return;
@@ -521,10 +649,253 @@ using namespace DB;
         } Catch (SqlConnection::Exception::InternalError) {
             LogError("Couldn't execute insert statement");
         }
-        ThrowMsg(DBCrypto::Exception::InternalError,
+        ThrowMsg(Crypto::Exception::InternalError,
                 "Couldn't delete key for label " << label);
     }
 
-} // CKM
+    void Crypto::setPermission(
+            const Name &name,
+            const Label& ownerLabel,
+            const Label& accessorLabel,
+            const PermissionMask permissionMask)
+    {
+        Try {
+            PermissionTable permissionTable(this->m_connection);
+            permissionTable.setPermission(name, ownerLabel, accessorLabel, permissionMask);
+            return;
+        } Catch (SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare set statement");
+        } Catch (SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute set statement");
+        }
+        ThrowMsg(Crypto::Exception::InternalError,
+                "Couldn't set permissions for name " << name );
+    }
+
+
+    void Crypto::SchemaInfo::setVersionInfo() {
+        SqlConnection::DataCommandUniquePtr insertContextCommand =
+                m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET);
+        insertContextCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
+        insertContextCommand->BindString(103, std::to_string(DB_VERSION_CURRENT).c_str());
+        insertContextCommand->Step();
+    }
+
+    bool Crypto::SchemaInfo::getVersionInfo(int & version) const
+    {
+        // Try..Catch mandatory here - we don't need to escalate the error
+        // if it happens - we just won't return the version, allowing CKM to work
+        Try {
+            SqlConnection::DataCommandUniquePtr selectCommand =
+                    m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET);
+            selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
+
+            if(selectCommand->Step()) {
+                version = static_cast<int>(atoi(selectCommand->GetColumnString(1).c_str()));
+                return true;
+            }
+        } Catch (SqlConnection::Exception::InvalidColumn) {
+            LogError("Select statement invalid column error");
+        } Catch (SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare select statement");
+        } Catch (SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute select statement");
+        }
+        return false;
+    }
+
+    void Crypto::PermissionTable::setPermission(
+            const Name &name,
+            const Label& ownerLabel,
+            const Label& accessorLabel,
+            const PermissionMask permissionMask)
+    {
+        if(permissionMask == Permission::NONE)
+        {
+            // clear permissions
+            SqlConnection::DataCommandUniquePtr deletePermissionCommand =
+                m_connection->PrepareDataCommand(DB_CMD_PERMISSION_DELETE);
+            deletePermissionCommand->BindString(104, accessorLabel.c_str());
+            deletePermissionCommand->BindString(101, name.c_str());
+            deletePermissionCommand->BindString(102, ownerLabel.c_str());
+            deletePermissionCommand->Step();
+        }
+        else
+        {
+            // add new permissions
+            SqlConnection::DataCommandUniquePtr setPermissionCommand =
+                m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SET);
+            setPermissionCommand->BindString(104, accessorLabel.c_str());
+            setPermissionCommand->BindInteger(105, static_cast<int>(permissionMask));
+            setPermissionCommand->BindString(101, name.c_str());
+            setPermissionCommand->BindString(102, ownerLabel.c_str());
+            setPermissionCommand->Step();
+        }
+    }
+
+    PermissionMaskOptional Crypto::PermissionTable::getPermissionRow(
+            const Name &name,
+            const Label &ownerLabel,
+            const Label &accessorLabel) const
+    {
+        SqlConnection::DataCommandUniquePtr selectCommand =
+                m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SELECT);
+        selectCommand->BindString(104, accessorLabel.c_str());
+
+        // name table reference
+        selectCommand->BindString(101, name.c_str());
+        selectCommand->BindString(102, ownerLabel.c_str());
+
+        if(selectCommand->Step())
+        {
+            // there is entry for the <name, ownerLabel> pair
+            return PermissionMaskOptional(PermissionMask(selectCommand->GetColumnInteger(0)));
+        }
+        return PermissionMaskOptional();
+    }
+
+    void Crypto::NameTable::addRow(
+            const Name &name,
+            const Label &ownerLabel)
+    {
+        // insert NAMES item
+        SqlConnection::DataCommandUniquePtr insertNameCommand =
+                m_connection->PrepareDataCommand(DB_CMD_NAME_INSERT);
+        insertNameCommand->BindString (101, name.c_str());
+        insertNameCommand->BindString (102, ownerLabel.c_str());
+        insertNameCommand->Step();
+    }
+
+    void Crypto::NameTable::deleteRow(
+            const Name &name,
+            const Label &ownerLabel)
+    {
+        SqlConnection::DataCommandUniquePtr deleteCommand =
+                m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE);
+        deleteCommand->BindString(101, name.c_str());
+        deleteCommand->BindString(102, ownerLabel.c_str());
+
+        // Step() result code does not provide information whether
+        // anything was removed.
+        deleteCommand->Step();
+    }
+
+    void Crypto::NameTable::deleteAllRows(const Label &ownerLabel)
+    {
+        SqlConnection::DataCommandUniquePtr deleteData =
+                m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE_BY_LABEL);
+        deleteData->BindString(102, ownerLabel.c_str());
+
+        // Step() result code does not provide information whether
+        // anything was removed.
+        deleteData->Step();
+    }
+
+    bool Crypto::NameTable::isPresent(const Name &name, const Label &ownerLabel) const
+    {
+        SqlConnection::DataCommandUniquePtr checkCmd =
+                m_connection->PrepareDataCommand(DB_CMD_NAME_COUNT_ROWS);
+        checkCmd->BindString(101, name.c_str());
+        checkCmd->BindString(102, ownerLabel.c_str());
+        if(checkCmd->Step()) {
+            int element_count = checkCmd->GetColumnInteger(0);
+            LogDebug("Item name: " << name  << " ownerLabel: " << ownerLabel <<
+                     " hit count: " << element_count);
+            if(element_count > 0)
+                return true;
+        }
+        return false;
+    }
+
+    void Crypto::ObjectTable::addRow(const Row &row)
+    {
+        SqlConnection::DataCommandUniquePtr insertObjectCommand =
+                m_connection->PrepareDataCommand(DB_CMD_OBJECT_INSERT);
+        insertObjectCommand->BindInteger(1, row.exportable);
+        insertObjectCommand->BindInteger(2, static_cast<int>(row.dataType));
+        insertObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
+        insertObjectCommand->BindInteger(4, row.encryptionScheme);
+        insertObjectCommand->BindBlob   (5, row.iv);
+        insertObjectCommand->BindInteger(6, row.dataSize);
+        insertObjectCommand->BindBlob   (7, row.data);
+        insertObjectCommand->BindBlob   (8, row.tag);
+        insertObjectCommand->BindInteger(9, static_cast<int>(row.backendId));
+
+        // name table reference
+        insertObjectCommand->BindString (101, row.name.c_str());
+        insertObjectCommand->BindString (102, row.ownerLabel.c_str());
+
+        insertObjectCommand->Step();
+    }
+
+    std::string Crypto::getSchema() {
+        SqlConnection::DataCommandUniquePtr schema =
+                m_connection->PrepareDataCommand("SELECT sql FROM "
+                        "(SELECT * FROM sqlcipher_master UNION ALL "
+                        "SELECT * FROM sqlcipher_temp_master) "
+                        "WHERE type!='meta' "
+                        "ORDER BY tbl_name, type DESC, name;");
+
+        std::stringstream ss;
+        while(schema->Step()) {
+            ss << schema->GetColumnString(0) << std::endl;
+        }
+        return ss.str();
+    }
+
+    std::string Crypto::getContent() {
+        SqlConnection::DataCommandUniquePtr tableSelect =
+                m_connection->PrepareDataCommand(
+                        "SELECT name FROM sqlcipher_master "
+                        "WHERE type IN ('table','view') AND name NOT LIKE 'sqlcipher_%' "
+                        "UNION ALL "
+                        "SELECT name FROM sqlcipher_temp_master "
+                        "WHERE type IN ('table','view') "
+                        "ORDER BY 1; ");
+
+        std::vector<std::string> tables;
+        while(tableSelect->Step()) {
+            tables.push_back(tableSelect->GetColumnString(0));
+        }
+
+        std::stringstream ss;
+
+        for (auto &e : tables) {
+            ss << "Table " << e << std::endl;
+            std::string query = "select * from " + e + ";";
+            SqlConnection::DataCommandUniquePtr result =
+                m_connection->PrepareDataCommand(query.c_str());
+            while(result->Step()) {
+                int maxColumn = result->GetColumnCount();
+                for (int i = 0; i < maxColumn; ++i) {
+                    switch(result->GetColumnType(i)) {
+                        case 1: // int64
+                            ss << result->GetColumnInteger(i) << " | ";
+                            break;
+                        case 2: // float
+                            ss << result->GetColumnFloat(i) << " | ";
+                            break;
+                        case 3: // string
+                            ss << result->GetColumnString(i) << " | ";
+                            break;
+                        case 4: // Blob
+                            {
+                            auto buffer = result->GetColumnBlob(i);
+                            ss << "BLOB (Size: " << buffer.size() << ") | ";
+                            break;
+                            }
+                        case 5: // NULL
+                            ss << "NULL | ";
+                            break;
+                    }
+                }
+                ss << std::endl;
+            }
+        }
+
+        return ss.str();
+    }
+} // namespace DB
+} // namespace CKM
 
 #pragma GCC diagnostic pop