Test version of ckm_db_merge 21/142121/10
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Wed, 2 Aug 2017 12:21:44 +0000 (14:21 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 6 Aug 2018 08:33:28 +0000 (08:33 +0000)
ckm_db_merge allows to read database and copy it's contents
to other one. ckm_db_merge supports db since versions 0.1.14.

Please note: both databases will be automatically migrated to
the newest schema.

Change-Id: I5cec9dfdc2ab75a2ccd5156b0bb05cb46d134480

packaging/key-manager.spec
src/manager/service/db-crypto.h
tools/ckm_db_tool/CMakeLists.txt
tools/ckm_db_tool/ckm-logic-ext.cpp
tools/ckm_db_tool/ckm-logic-ext.h
tools/ckm_db_tool/ckm_db_merge.cpp [new file with mode: 0644]
tools/ckm_db_tool/ckm_db_tool.cpp
tools/ckm_db_tool/db-crypto-ext.cpp
tools/ckm_db_tool/db-crypto-ext.h
tools/ckm_db_tool/db-wrapper.cpp [new file with mode: 0644]
tools/ckm_db_tool/db-wrapper.h [new file with mode: 0644]

index fe470a7..aead73a 100644 (file)
@@ -322,5 +322,6 @@ fi
 %{bin_dir}/ckm-tests-internal
 %{bin_dir}/ckm_so_loader
 %{bin_dir}/ckm_db_tool
+%{bin_dir}/ckm_db_merge
 %{bin_dir}/ckm_generate_db
 %test_dir
index 3fbacf6..f4021c3 100644 (file)
@@ -200,6 +200,9 @@ public:
 protected:
        SqlConnection *m_connection;
 
+       Row getRow(
+               const SqlConnection::DataCommandUniquePtr &selectCommand) const;
+
 private:
        bool m_inUserTransaction;
 
@@ -219,9 +222,6 @@ private:
        ScriptOptional getScript(const std::string &scriptName) const;
        ScriptOptional getMigrationScript(int db_version) const;
 
-       Row getRow(
-               const SqlConnection::DataCommandUniquePtr &selectCommand) const;
-
        void createTable(
                const char *create_cmd,
                const char *table_name);
index 7b78c1a..4a47a1d 100644 (file)
@@ -1,4 +1,5 @@
 SET(CKM_DB_TOOL "ckm_db_tool")
+SET(CKM_DB_MERGE "ckm_db_merge")
 SET(KEY_MANAGER_PATH ${PROJECT_SOURCE_DIR}/src/manager)
 
 IF (TZ_BACKEND_ENABLED)
@@ -36,10 +37,10 @@ INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_PATH}/crypto
     )
 
-SET(CKM_DB_TOOL_SOURCES
-    ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm_db_tool.cpp
+SET(CKM_DB_TOOLS_SOURCES
     ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/db-crypto-ext.cpp
     ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm-logic-ext.cpp
+    ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/db-wrapper.cpp
     ${KEY_MANAGER_PATH}/crypto/platform/decider.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/obj.cpp
@@ -80,8 +81,8 @@ SET(CKM_DB_TOOL_SOURCES
     )
 
 IF(TZ_BACKEND_ENABLED)
-SET(CKM_DB_TOOL_SOURCES
-    ${CKM_DB_TOOL_SOURCES}
+SET(CKM_DB_TOOLS_SOURCES
+    ${CKM_DB_TOOLS_SOURCES}
     ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp
     ${KEY_MANAGER_PATH}/crypto/tz-backend/obj.cpp
     ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp
@@ -92,7 +93,7 @@ ENDIF()
 
 LINK_DIRECTORIES(${CKM_DB_TOOL_DEP_LIBRARY_DIRS})
 
-ADD_EXECUTABLE( ${CKM_DB_TOOL} ${CKM_DB_TOOL_SOURCES} )
+ADD_EXECUTABLE(${CKM_DB_TOOL} ${CKM_DB_TOOLS_SOURCES} ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm_db_tool.cpp)
 
 IF(TZ_BACKEND_ENABLED)
 SET(CKM_DB_TOOL_LINK_EXTRA_DEPS
@@ -110,8 +111,18 @@ TARGET_LINK_LIBRARIES(${CKM_DB_TOOL}
     -ldl
     )
 
+ADD_EXECUTABLE(${CKM_DB_MERGE} ${CKM_DB_TOOLS_SOURCES} ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm_db_merge.cpp)
+
+TARGET_LINK_LIBRARIES(${CKM_DB_MERGE}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${CKM_DB_TOOL_DEP_LIBRARIES}
+    ${TARGET_KEY_MANAGER_COMMON}
+    ${CKM_DB_TOOL_LINK_EXTRA_DEPS}
+    -ldl
+    )
+
 #place for output file
-INSTALL(TARGETS ${CKM_DB_TOOL}
+INSTALL(TARGETS ${CKM_DB_TOOL} ${CKM_DB_MERGE}
     DESTINATION ${BIN_DIR}
     PERMISSIONS OWNER_READ
                 OWNER_WRITE
index a82b5db..6d64fc4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,15 +27,6 @@ namespace CKM {
 DB::SqlConnection::Output CKMLogicExt::Execute(uid_t user,
                const std::string &cmd)
 {
-       if (user < 5000 && !m_systemDbUnlocked) {
-               if (CKM_API_SUCCESS != unlockSystemDB())
-                       ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
-
-               m_systemDbUnlocked = true;
-       }
-
-       DB::SqlConnection::Output output;
-
        /*
         * We need to access to DB::Crypto::m_connection to call Execute() on it. We don't want to mess
         * with DB::Crypto too much so adding a friend and extending public interface was not an option.
@@ -47,7 +38,7 @@ DB::SqlConnection::Output CKMLogicExt::Execute(uid_t user,
        DB::CryptoExt db(std::move(m_userDataMap[user].database));
 
        try {
-               output = db.Execute(cmd);
+               DB::SqlConnection::Output output = db.Execute(cmd);
                m_userDataMap[user].database = std::move(*static_cast<DB::Crypto *>(&db));
                return output;
        } catch (const DB::SqlConnection::Exception::Base &e) {
@@ -56,6 +47,25 @@ DB::SqlConnection::Output CKMLogicExt::Execute(uid_t user,
        }
 }
 
+DB::RowVector CKMLogicExt::getRows(uid_t user)
+{
+       DB::CryptoExt db(std::move(m_userDataMap[user].database));
+
+       try {
+               DB::RowVector output = db.getRows();
+               m_userDataMap[user].database = std::move(*static_cast<DB::Crypto *>(&db));
+               return output;
+       } catch (const DB::SqlConnection::Exception::Base &e) {
+               m_userDataMap[user].database = std::move(*static_cast<DB::Crypto *>(&db));
+               throw;
+       }
+}
+
+void CKMLogicExt::saveRow(uid_t user, const DB::Row &row)
+{
+       m_userDataMap[user].database.saveRow(row);
+}
+
 } // namespace CKM
 
 
index ca6916f..c988179 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -30,6 +30,8 @@ struct CKMLogicExt : public CKMLogic {
        CKMLogicExt() : m_systemDbUnlocked(false) {}
 
        DB::SqlConnection::Output Execute(uid_t user, const std::string &cmd);
+       DB::RowVector getRows(uid_t user);
+       void saveRow(uid_t user, const DB::Row &row);
 
 private:
        bool m_systemDbUnlocked;
diff --git a/tools/ckm_db_tool/ckm_db_merge.cpp b/tools/ckm_db_tool/ckm_db_merge.cpp
new file mode 100644 (file)
index 0000000..17e308c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file       ckm_db_merge.cpp
+ * @author     Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version    1.0
+ */
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <exception>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include <db-wrapper.h>
+
+using namespace std;
+using namespace CKM;
+
+typedef function<bool(DB::Row &row)> RowFilter;
+typedef vector<RowFilter> RowFilterVector;
+
+bool printRow(const DB::Row &row) {
+       string iv(10, ' '), data(10, ' ');
+       for (std::size_t i=0; i < iv.size(); ++i) {
+               if (row.iv.size() > i) iv[i] = row.iv[i];
+               if (row.data.size() > i) data[i] = row.data[i];
+       }
+       cout << "Read row:";
+       cout << "\n   Name:                  " << row.name;
+       cout << "\n   Owner:                 " << row.ownerLabel;
+       cout << "\n   Exportable:            " << row.exportable;
+       cout << "\n   Alg type:              " << static_cast<int>(row.algorithmType);
+       cout << "\n   Enc schema:            " << row.encryptionScheme;
+       cout << "\n   Data size:             " << row.dataSize;
+       cout << "\n   BackendId:             " << static_cast<int>(row.backendId);
+       cout << "\n   Data(first 10 chars):  " << data;
+       cout << "\n   IV(first 10 chars):    " << iv;
+       cout << "\n";
+       return true;
+}
+
+void printUsage()
+{
+       cout << "Usage: ckm_db_merge [OPTION]\n";
+       cout << "Copy data from one key-manager database into other one.\n";
+       cout << "Options:\n";
+       cout << "  -v, --verbose         print additional data on screen\n";
+       cout << "  -s, --source UID      database UID from were data will be readed - default value 0\n";
+       cout << "  -t, --target UID      database UID to were data will be writen - default value 0\n";
+       cout << "  -p, --spass PASSWORD  password for source database - default empty string\n";
+       cout << "  -r, --tpass PASSWORD  password for target database - default emtpy string\n";
+       cout << "  -o, --owner OWNER     change the owner of information in database to OWNER\n";
+       cout << "  -h, --help            print this help on screen\n";
+       cout << "Example: Copy data from db-5001 to db-0 (system database) and change object owner to /System\n";
+       cout << "  ckm_db_merge -s 5001 -t 0 -p !@#SDFCV -o \"/System\"\n";
+       cout << "Please note: This tool automatically updates databases to newest scheme!" << endl;
+}
+
+int mergeDatabase(
+       uid_t uid1,
+       const Password &pass1,
+       uid_t uid2,
+       const Password &pass2,
+       const RowFilterVector &filters)
+{
+       DbWrapper source(uid1, pass1);
+       DbWrapper target(uid2, pass2);
+
+       int ret;
+
+       if (CKM_API_SUCCESS != (ret = source.unlock())) {  // this should migrate database to newest version
+               cerr << "Unlocking source database failed: " << ret << endl;
+               return 1;
+       }
+       if (CKM_API_SUCCESS != (ret = target.unlock())) {  // this should migrate database to newest version
+               cerr << "Unlocking target database failed: " << ret << endl;
+               return 1;
+       }
+
+       DB::RowVector data = source.getRows();
+
+       // apply all filters to each row
+       for (auto &e : data) {
+               bool migrate = true;
+               for (auto &f : filters) {
+                       migrate &= f(e);
+               }
+               if (migrate) {
+                       try {
+                               target.saveRow(e);
+                       } catch (const CKM::DB::SqlConnection::Exception::Base &e) {
+                               cerr << "Sql exception. Migration failed or object already exist in database: " << e.DumpToString() << endl;
+                       }
+               }
+       }
+
+       source.lock();
+       target.lock();
+       return 0;
+}
+
+int main(int argc, char *argv[]) {
+       Password password1, password2;
+       uid_t uid1 = 0, uid2 = 0;
+       string owner;
+       RowFilterVector filters;
+       try {
+               while (1) {
+                       int option_index = 0;
+
+                       static struct option long_options[] = {
+                               {"verbose", no_argument,       0, 'v'},
+                               {"source",  required_argument, 0, 's'},
+                               {"target",  required_argument, 0, 't'},
+                               {"spass",   required_argument, 0, 'p'},
+                               {"tpass",   required_argument, 0, 'r'},
+                               {"owner",   required_argument, 0, 'o'},
+                               {"help",    no_argument,       0, 'h'},
+                               {0,         0,                 0, 0  }
+                       };
+                       int c = getopt_long(argc, argv, "vs:t:p:r:o:h", long_options, &option_index);
+
+                       if (-1 == c)
+                               break;
+
+                       switch (c) {
+                       case 'v':
+                               filters.push_back(printRow);
+                               break;
+                       case 's':
+                               uid1 = stoi(optarg);
+                               break;
+                       case 't':
+                               uid2 = stoi(optarg);
+                               break;
+                       case 'p':
+                               password1 = optarg;
+                               break;
+                       case 'r':
+                               password2 = optarg;
+                               break;
+                       case 'o':
+                               owner = optarg; // I cannot pass optarg to lambda because it's pointer
+                               filters.push_back([=](DB::Row &row) {row.ownerLabel = owner; return true;});
+                               break;
+                       case 'h':
+                               printUsage();
+                               return 0;
+                       case '?':
+                       case ':':
+                       default:
+                               printUsage();
+                               return 1;
+                       }
+               }
+
+               if (uid1 == uid2) {
+                       cerr << "Source database and target database must be different!" << endl;
+                       return 1;
+               }
+
+               return mergeDatabase(uid1, password1, uid2, password2, filters);
+       } catch (const CKM::DB::SqlConnection::Exception::InvalidColumn &e) {
+               cerr << "Invalid Column exception was catched. Probably migration failed. " << e.DumpToString() << endl;
+       } catch (const invalid_argument &e) {
+               cerr << "Argument could not be converted" << endl;
+       } catch (const out_of_range &e) {
+               cerr << "Out of range" << endl;
+       } catch (const exception &e) {
+               cerr << "Unexpected error: " << e.what() << endl;
+       } catch (...) {
+               cerr << "Unknown exception" << endl;
+       }
+
+       return 1;
+}
index 672cd86..2435ee3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include <sstream>
 #include <exception>
 
-#include <ckm-logic-ext.h>
+#include <getopt.h>
+#include <unistd.h>
 
-#include <ckm/ckm-type.h>
-#include <ckm/ckm-error.h>
-#include <message-buffer.h>
-#include <dpl/db/sql_connection.h>
-#include <exception.h>
+#include <db-wrapper.h>
 
 using namespace std;
 using namespace CKM;
 
-namespace {
-const size_t MAX_LEN = 32;
-const char ELLIPSIS[] = "...";
-const size_t ELLIPSIS_LEN = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]);
-
-const char *const SQL_TABLES = "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";
-
-const char *const SQL_SCHEMA = "SELECT sql FROM "
-                                                          "(SELECT * FROM sqlcipher_master "
-                                                          "UNION ALL "
-                                                          "SELECT * FROM sqlcipher_temp_master) "
-                                                          "WHERE type!='meta' AND sql!='NULL'"
-                                                          "ORDER BY tbl_name, type DESC, name";
-} // namespace anonymous
-
-class DbWrapper {
-public:
-       DbWrapper(uid_t uid, Password pw) : m_uid(uid), m_pw(pw) {}
-
-       int unlock();
-       void lock();
-       void process(const string &cmd);
-
-private:
-       void displayRow(const DB::SqlConnection::Output::Row &row, bool trim);
-
-       uid_t m_uid;
-       Password m_pw;
-       CKMLogicExt m_logic;
-};
-
-int DbWrapper::unlock()
-{
-       // no unlock for system db
-       if (m_uid < 5000)
-               return CKM_API_SUCCESS;
-
-       int retCode;
-       RawBuffer ret = m_logic.unlockUserKey(m_uid, m_pw);
-       MessageBuffer buff;
-       buff.Push(ret);
-       buff.Deserialize(retCode);
-       return retCode;
-}
-
-void DbWrapper::lock()
-{
-       // no lock for system db
-       if (m_uid < 5000)
-               return;
-
-       m_logic.lockUserKey(m_uid);
-}
-
-void DbWrapper::process(const string &acmd)
-{
-       try {
-               string cmd = acmd;
-               bool trim = true;
-
-               if (acmd == ".tables") {
-                       cmd = SQL_TABLES;
-                       trim = false;
-               } else if (acmd == ".schema") {
-                       cmd = SQL_SCHEMA;
-                       trim = false;
-               }
-
-               DB::SqlConnection::Output output = m_logic.Execute(m_uid, cmd);
-
-               if (output.GetNames().empty())
-                       return;
-
-               displayRow(output.GetNames(), trim);
-               cout << "--------------------------" << endl;
-
-               for (const auto &row : output.GetValues()) {
-                       displayRow(row, trim);
-               }
-       } catch (const DB::SqlConnection::Exception::Base &e) {
-               cerr << e.GetMessage() << endl;
-       } catch (const Exc::Exception &e) {
-               cerr << e.message() << endl;
-       } catch (const std::exception &e) {
-               cerr << e.what() << endl;
-       } catch (...) {
-               cerr << "Unexpected exception occurred" << endl;
-       }
-}
-
-void DbWrapper::displayRow(const DB::SqlConnection::Output::Row &row, bool trim)
-{
-       for (auto it = row.begin(); it != row.end(); it++) {
-               std::string col = *it;
-
-               if (trim && col.size() > MAX_LEN) {
-                       col.resize(MAX_LEN);
-                       col.replace(MAX_LEN - ELLIPSIS_LEN, ELLIPSIS_LEN, ELLIPSIS);
-               }
-
-               cout << col;
-
-               if (it + 1 != row.end())
-                       cout << "|";
-       }
-
-       cout << endl;
-}
-
 void usage()
 {
-       cout << "ckm_db_tool - the command line tool for accessing key-manager encrypted databases."
-                << endl;
-       cout << endl;
-       cout << "Usage: ckm_db_tool uid [password] [sql_command]" << endl;
-       cout << endl;
-       cout << "uid (mandatory)         User id as in <TZ_SYS_DATA>/ckm/db-<uid>" <<
-                endl;
-       cout << "password (optional)     Password used for database encryption. For system database (uid < 5000) no password should be used."
-                << endl;
-       cout << "sql_command (optional)  Sqlite3 command to execute on database. If empty the tool will enter interactive mode."
-                << endl;
-       cout << endl;
-       cout << "Example:" << endl;
-       cout << "cmd_db_tool 5000 user-pass \"select * from names\"" << endl;
+       cout << "Usage: ckm_db_tool [OPTION]\n";
+       cout << "The command line tool for accessing key-manager encrypted databases.\n";
+       cout << "Options:\n";
+       cout << "  -u, --uid UID         User id as in <TZ_SYS_DATA>/ckm/db-<uid> - default value 0\n";
+       cout << "  -p, --pass PASSWORD   Password used for database encryption. For system database (uid < 5000) no password should be used.\n";
+       cout << "  -c, --cmd SQLCOMMAND  Sqlite3 command to execute on database. If command not provided tool will enter interactive mode.\n";
+       cout << "  -h, --help            Shows this help.\n";
+       cout << "Example: Open database for user 5000 and select all data from table names\n";
+       cout << "  cmd_db_tool -u 5000 -p P45W0RD \"select * from names\"\n";
+       cout << "Example: Open database for user 5001 in interactive mode\n";
+       cout << "  cmd_db_tool -uid 5001 -p user-strong-password\n";
+       cout << "Example: Open database for user 0 in interactive mode\n";
+       cout << "  cmd_db_tool" << endl;
 }
 
 void internalHelp()
@@ -179,43 +61,49 @@ void internalHelp()
 int main(int argc, char *argv[])
 {
        try {
-               if (argc < 2 || !argv[1]) {
-                       usage();
-                       return -1;
-               }
-
-               // read uid
-               stringstream ss(argv[1]);
-               uid_t uid;
+               uid_t uid = 0;
+               Password pass;
+               std::string argcmd;
+               while(1) {
+                       int option_index = 0;
 
-               if (!(ss >> uid)) {
-                       usage();
-                       return -1;
-               }
+                       static struct option long_options[] = {
+                               {"uid",  required_argument, 0, 'u'},
+                               {"cmd",  required_argument, 0, 'c'},
+                               {"pass", required_argument, 0, 'p'},
+                               {"help", no_argument,       0, 'h'},
+                               {0,      0,                 0, 0  }
+                       };
 
-               int idx = 2;
+                       int c = getopt_long(argc, argv, "u:c:p:h", long_options, &option_index);
 
-               // read password
-               Password pass;
+                       if (-1 == c)
+                               break;
 
-               if (uid >= 5000) {
-                       if (argc > idx) {
-                               pass = argv[idx];
-                               idx++;
+                       switch (c) {
+                               default:
+                               case ':':
+                               case '?':
+                               case 'h':
+                                       usage();
+                                       return 0;
+                               case 'u':
+                                       uid = std::stoi(optarg);
+                                       break;
+                               case 'c':
+                                       argcmd = optarg;
+                                       break;
+                               case 'p':
+                                       pass = optarg;
+                                       break;
                        }
                }
 
-               // read sqlite3 command
-               string argcmd;
-
-               if (argc > idx)
-                       argcmd = argv[idx];
-
                // unlock db
                DbWrapper dbw(uid, pass);
-               int retCode = dbw.unlock();
+               int retCode;
 
-               if (retCode != CKM_API_SUCCESS) {
+               if (CKM_API_SUCCESS != (retCode = dbw.unlock())) {
                        cerr << "Unlocking database failed: " << retCode << endl;
                        return -1;
                }
@@ -254,8 +142,15 @@ int main(int argc, char *argv[])
                cout << "Database locked" << endl;
 
                return 0;
+       } catch (const std::invalid_argument &e) {
+               cerr << "Argument could not be converted" << endl;
+       } catch (const std::out_of_range &e) {
+               cerr << "Out of range" << endl;
+       } catch (const std::exception &e) {
+               cerr << "Exception: " << e.what() << endl;
        } catch (...) {
                cerr << "Unexpected exception occurred" << endl;
-               return -1;
        }
+       return -1;
 }
+
index 2667145..90d5a4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -26,6 +26,9 @@
 namespace CKM {
 namespace DB {
 
+const char *DB_CMD_OBJECT_SELECT =
+       "SELECT * FROM [join_name_object_tables];";
+
 SqlConnection::Output CryptoExt::Execute(const std::string &cmd)
 {
        SqlConnection::Output out;
@@ -38,5 +41,30 @@ SqlConnection::Output CryptoExt::Execute(const std::string &cmd)
        m_connection->ExecCommand(&out, "%s", cmd.c_str());
        return out;
 }
+
+RowVector CryptoExt::getRows()
+{
+       try {
+               RowVector output;
+               SqlConnection::DataCommandUniquePtr selectCommand =
+                       m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT);
+
+               while (selectCommand->Step()) {
+                       // extract data
+                       output.push_back(getRow(selectCommand));
+               }
+
+               return output;
+       } catch (const SqlConnection::Exception::InvalidColumn &) {
+               LogError("Select statement invalid column error");
+       } catch (const SqlConnection::Exception::SyntaxError &) {
+               LogError("Couldn't prepare select statement");
+       } catch (const SqlConnection::Exception::InternalError &) {
+               LogError("Couldn't execute select statement");
+       }
+
+       ThrowErr(Exc::DatabaseFailed, "Couldn't get row from database");
+}
+
 } // namespace DB
 } // namespace CKM
index 5991af1..bb1eb35 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ struct CryptoExt : public Crypto {
        CryptoExt(Crypto orig) : Crypto(std::move(orig)) {}
 
        SqlConnection::Output Execute(const std::string &cmd);
+       RowVector getRows();
 };
 
 } // namespace DB
diff --git a/tools/ckm_db_tool/db-wrapper.cpp b/tools/ckm_db_tool/db-wrapper.cpp
new file mode 100644 (file)
index 0000000..e7027db
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file       db-wrapper.cpp
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @author     Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version    1.0
+ */
+#include <string>
+
+#include <db-wrapper.h>
+
+namespace {
+
+const size_t MAX_LEN = 32;
+const char ELLIPSIS[] = "...";
+const size_t ELLIPSIS_LEN = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]);
+
+
+const char *const SQL_TABLES = "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";
+
+const char *const SQL_SCHEMA = "SELECT sql FROM "
+                                                          "(SELECT * FROM sqlcipher_master "
+                                                          "UNION ALL "
+                                                          "SELECT * FROM sqlcipher_temp_master) "
+                                                          "WHERE type!='meta' AND sql!='NULL'"
+                                                          "ORDER BY tbl_name, type DESC, name";
+} // anonymous namespace
+
+namespace CKM {
+
+int DbWrapper::unlock()
+{
+       // no unlock for system db
+       if (m_uid == 0 && m_pw.empty())
+               return m_logic.unlockSystemDB();
+
+       int retCode;
+       RawBuffer ret = m_logic.unlockUserKey(m_uid, m_pw);
+       MessageBuffer buff;
+       buff.Push(ret);
+       buff.Deserialize(retCode);
+       return retCode;
+}
+
+void DbWrapper::lock()
+{
+       // no lock for system db
+       if (m_uid < 5000)
+               return;
+
+       m_logic.lockUserKey(m_uid);
+}
+
+void DbWrapper::process(const std::string &acmd)
+{
+       try {
+               std::string cmd = acmd;
+               bool trim = true;
+
+               if (acmd == ".tables") {
+                       cmd = SQL_TABLES;
+                       trim = false;
+               } else if (acmd == ".schema") {
+                       cmd = SQL_SCHEMA;
+                       trim = false;
+               }
+
+               DB::SqlConnection::Output output = m_logic.Execute(m_uid, cmd);
+
+               if (output.GetNames().empty())
+                       return;
+
+               displayRow(output.GetNames(), trim);
+               std::cout << "--------------------------" << std::endl;
+
+               for (const auto &row : output.GetValues()) {
+                       displayRow(row, trim);
+               }
+       } catch (const DB::SqlConnection::Exception::Base &e) {
+               std::cerr << e.GetMessage() << std::endl;
+       } catch (const Exc::Exception &e) {
+               std::cerr << e.message() << std::endl;
+       } catch (const std::exception &e) {
+               std::cerr << e.what() << std::endl;
+       } catch (...) {
+               std::cerr << "Unexpected exception occurred" << std::endl;
+       }
+}
+
+void DbWrapper::displayRow(const DB::SqlConnection::Output::Row &row, bool trim)
+{
+       for (auto it = row.begin(); it != row.end(); it++) {
+               std::string col = *it;
+
+               if (trim && col.size() > MAX_LEN) {
+                       col.resize(MAX_LEN);
+                       col.replace(MAX_LEN - ELLIPSIS_LEN, ELLIPSIS_LEN, ELLIPSIS);
+               }
+
+               std::cout << col;
+
+               if (it + 1 != row.end())
+                       std::cout << "|";
+       }
+
+       std::cout << std::endl;
+}
+
+DB::RowVector DbWrapper::getRows()
+{
+       return m_logic.getRows(m_uid);
+}
+
+void DbWrapper::saveRow(const DB::Row &row)
+{
+       return m_logic.saveRow(m_uid, row);
+}
+
+} // namespace CKM
diff --git a/tools/ckm_db_tool/db-wrapper.h b/tools/ckm_db_tool/db-wrapper.h
new file mode 100644 (file)
index 0000000..2fa6653
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file       db-wrapper.h
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @author     Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version    1.0
+ */
+#pragma once
+
+#include <string>
+
+#include <ckm/ckm-type.h>
+#include <ckm/ckm-error.h>
+#include <message-buffer.h>
+#include <dpl/db/sql_connection.h>
+#include <ckm-logic-ext.h>
+
+#include <exception.h>
+
+namespace CKM {
+
+class DbWrapper {
+public:
+       DbWrapper(uid_t uid, Password pw) : m_uid(uid), m_pw(pw) {}
+
+       int unlock();
+       void lock();
+       void process(const std::string &cmd);
+       DB::RowVector getRows();
+       void saveRow(const DB::Row &row);
+
+private:
+       void displayRow(const DB::SqlConnection::Output::Row &row, bool trim);
+
+       uid_t m_uid;
+       Password m_pw;
+       CKMLogicExt m_logic;
+};
+
+} // namespace CKM
+