%{_datadir}/ckm-db-test/XML_1_wrong.xsd
%{_datadir}/ckm-db-test/XML_2_structure.xml
%{_bindir}/ckm_so_loader
+%{_bindir}/ckm_db_tool
%files -n key-manager-pam-plugin
%defattr(-,root,root,-)
DECLARE_EXCEPTION_TYPE(Base, InvalidArguments)
};
+ /**
+ * Output of SQL command
+ */
+ class Output {
+ public:
+ typedef std::vector<std::string> Row;
+ typedef std::vector<Row> Rows;
+
+ static int Callback(void*,int,char**,char**);
+ const Row& GetNames() const { return m_names; }
+ const Rows& GetValues() const { return m_values; }
+ private:
+ void SetResults(int columns, char** values, char** names);
+
+ Row m_names;
+ Rows m_values;
+ };
+
typedef int ColumnIndex;
typedef int ArgumentIndex;
void ExecCommand(const char *format, ...);
/**
+ * Execute SQL command without result
+ *
+ * @param output The output of SQL command will be stored in this object
+ * if it's no NULL.
+ * @param format
+ * @param ...
+ */
+ //To prevent sql injection do not use this method for direct sql execution
+ void ExecCommand(Output* output, const char *format, ...);
+
+ /**
* Execute BEGIN; command to start new transaction
*
*/
* @return Row ID
*/
RowID GetLastInsertRowID() const;
+
+ private:
+ void ExecCommandHelper(Output* out, const char *format, va_list args);
};
} // namespace DB
} // namespace CKM
namespace {
const int MAX_RETRY = 10;
+
+struct ScopedVaList {
+ ~ScopedVaList() { va_end(args); }
+ va_list args;
+};
+
+#define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param);
}
namespace CKM {
}
}
-void SqlConnection::ExecCommand(const char *format, ...)
+int SqlConnection::Output::Callback(void* param, int columns, char** values, char** names)
+{
+ if(param)
+ static_cast<Output*>(param)->SetResults(columns, values, names);
+ return 0;
+}
+
+void SqlConnection::Output::SetResults(int columns, char** values, char** names)
+{
+ if (m_names.empty()) {
+ for (int i=0;i<columns;i++)
+ m_names.push_back(names[i] ? names[i] : "NULL");
+ }
+ Row row;
+ for (int i=0;i<columns;i++)
+ row.push_back(values[i] ? values[i] : "NULL");
+ m_values.push_back(std::move(row));
+}
+
+void SqlConnection::ExecCommandHelper(Output* out, const char* format, va_list args)
{
if (m_connection == NULL) {
LogError("Cannot execute command. Not connected to DB!");
ThrowMsg(Exception::SyntaxError, "Null statement");
}
- char *rawBuffer;
-
- va_list args;
- va_start(args, format);
-
- if (vasprintf(&rawBuffer, format, args) == -1) {
- rawBuffer = NULL;
- }
-
- va_end(args);
+ char *query;
- CharUniquePtr buffer(rawBuffer);
-
- if (!buffer) {
+ if (vasprintf(&query, format, args) == -1) {
LogError("Failed to allocate statement string");
return;
}
- LogPedantic("Executing SQL command: " << buffer.get());
+ CharUniquePtr queryPtr(query);
+
+ LogPedantic("Executing SQL command: " << queryPtr.get());
// Notify all after potentially synchronized database connection access
ScopedNotifyAll notifyAll(m_synchronizationObject.get());
for (int i = 0; i < MAX_RETRY; i++) {
char *errorBuffer;
-
int ret = sqlcipher3_exec(m_connection,
- buffer.get(),
- NULL,
- NULL,
- &errorBuffer);
+ queryPtr.get(),
+ out ? &Output::Callback : NULL,
+ out,
+ &errorBuffer);
std::string errorMsg;
ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
+void SqlConnection::ExecCommand(Output* out, const char *format, ...)
+{
+ scoped_va_start(svl, format);
+
+ ExecCommandHelper(out, format, svl.args);
+}
+
+void SqlConnection::ExecCommand(const char *format, ...)
+{
+ scoped_va_start(svl, format);
+
+ ExecCommandHelper(NULL, format, svl.args);
+}
+
SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
const char *format,
...)
const Password& pass,
Crypto::GKeyShPtr& key);
+protected:
+ int unlockSystemDB();
+
private:
// select private/system database depending on asking uid and owner label.
UserData & selectDatabase(const Credentials &incoming_cred,
const Label &incoming_label);
- int unlockSystemDB();
int unlockDatabase(uid_t user,
const Password & password);
int loadAppKey(UserData& handle, const Label& appLabel);
- std::map<uid_t, UserData> m_userDataMap;
AccessControl m_accessControl;
Crypto::Decider m_decider;
//FileLock m_lock;
+
+protected:
+ std::map<uid_t, UserData> m_userDataMap;
};
} // namespace CKM
bool m_inTransaction;
};
- private:
+ protected:
SqlConnection* m_connection;
+ private:
bool m_inUserTransaction;
void resetDB();
WORLD_EXECUTE
)
+ADD_SUBDIRECTORY(ckm_db_tool)
\ No newline at end of file
--- /dev/null
+SET(CKM_DB_TOOL "ckm_db_tool")
+SET(KEY_MANAGER_PATH ${PROJECT_SOURCE_DIR}/src/manager)
+
+PKG_CHECK_MODULES(CKM_DB_TOOL_DEP
+ REQUIRED
+ openssl
+ libsmack
+ libcrypto
+ capi-base-common
+ capi-system-info
+ vconf
+ libxml-2.0
+ )
+
+FIND_PACKAGE(Threads REQUIRED)
+
+INCLUDE_DIRECTORIES(
+ ${CKM_DB_TOOL_DEP_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/
+ ${KEY_MANAGER_PATH}/main
+ ${KEY_MANAGER_PATH}/common
+ ${KEY_MANAGER_PATH}/service
+ ${KEY_MANAGER_PATH}/initial-values
+ ${KEY_MANAGER_PATH}/sqlcipher
+ ${KEY_MANAGER_PATH}/dpl/core/include
+ ${KEY_MANAGER_PATH}/dpl/log/include
+ ${KEY_MANAGER_PATH}/dpl/db/include
+ ${KEY_MANAGER_PATH}/crypto
+ )
+
+SET(CKM_DB_TOOL_SOURCES
+ ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm_db_tool.cpp
+ ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/db-crypto-ext.cpp
+ ${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm-logic-ext.cpp
+
+ ${KEY_MANAGER_PATH}/main/generic-socket-manager.cpp
+ ${KEY_MANAGER_PATH}/main/socket-manager.cpp
+ ${KEY_MANAGER_PATH}/main/smack-check.cpp
+ ${KEY_MANAGER_PATH}/main/thread-service.cpp
+ ${KEY_MANAGER_PATH}/main/socket-2-id.cpp
+ ${KEY_MANAGER_PATH}/service/certificate-store.cpp
+ ${KEY_MANAGER_PATH}/service/certificate-config.cpp
+ ${KEY_MANAGER_PATH}/service/digest.cpp
+ ${KEY_MANAGER_PATH}/service/file-lock.cpp
+ ${KEY_MANAGER_PATH}/service/access-control.cpp
+ ${KEY_MANAGER_PATH}/service/ckm-logic.cpp
+ ${KEY_MANAGER_PATH}/service/key-provider.cpp
+ ${KEY_MANAGER_PATH}/service/crypto-logic.cpp
+ ${KEY_MANAGER_PATH}/service/db-crypto.cpp
+ ${KEY_MANAGER_PATH}/service/file-system.cpp
+ ${KEY_MANAGER_PATH}/initial-values/parser.cpp
+ ${KEY_MANAGER_PATH}/initial-values/BufferHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/CertHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/DataHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/KeyHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/PermissionHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/InitialValueHandler.cpp
+ ${KEY_MANAGER_PATH}/initial-values/InitialValuesFile.cpp
+ ${KEY_MANAGER_PATH}/initial-values/xml-utils.cpp
+ ${KEY_MANAGER_PATH}/dpl/core/src/assert.cpp
+ ${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp
+ ${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp
+ ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
+ ${KEY_MANAGER_PATH}/crypto/sw-backend/key.cpp
+ ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp
+ ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp
+ ${KEY_MANAGER_PATH}/crypto/platform/decider.cpp
+ ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp
+ ${KEY_MANAGER_PATH}/main/socket-2-id-mockup.cpp
+ )
+
+ADD_EXECUTABLE( ${CKM_DB_TOOL} ${CKM_DB_TOOL_SOURCES} )
+
+TARGET_LINK_LIBRARIES(${CKM_DB_TOOL}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CKM_DB_TOOL_DEP_LIBRARIES}
+ ${TARGET_KEY_MANAGER_COMMON}
+ -ldl
+ )
+
+#place for output file
+INSTALL(TARGETS ${CKM_DB_TOOL}
+ DESTINATION /usr/bin
+ PERMISSIONS OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ GROUP_READ
+ GROUP_EXECUTE
+ WORLD_READ
+ WORLD_EXECUTE
+ )
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 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-logic-ext.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#include <ckm-logic-ext.h>
+#include <db-crypto-ext.h>
+
+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.
+ * That's why we need a derived class DB::CryptoExt. m_userDataMap must be left unchanged after
+ * this operation but DB::Crypto can't be copied. According to C++ standard static casting
+ * DB::Crypto pointer to DB::CryptoExt pointer is UB. Therefore DB::Crypto is temporarily moved
+ * into DB::CryptoExt and moved back to m_userDataMap after the call to Execute().
+ */
+ DB::CryptoExt db(std::move(m_userDataMap[user].database));
+ try {
+ output = db.Execute(cmd);
+ 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;
+ }
+}
+
+} // namespace CKM
+
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 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-logic-ext.h
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#pragma once
+
+#include <string>
+#include <ckm-logic.h>
+#include <dpl/db/sql_connection.h>
+
+namespace CKM {
+struct CKMLogicExt : public CKMLogic {
+ CKMLogicExt() : m_systemDbUnlocked(false) {}
+
+ DB::SqlConnection::Output Execute(uid_t user, const std::string& cmd);
+
+private:
+ bool m_systemDbUnlocked;
+};
+} // namespace CKM
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 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_tool.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#include <iostream>
+#include <sstream>
+#include <exception>
+
+#include <ckm-logic-ext.h>
+
+#include <ckm/ckm-type.h>
+#include <ckm/ckm-error.h>
+#include <message-buffer.h>
+#include <dpl/db/sql_connection.h>
+#include <exception.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) {
+ cout << e.GetMessage() << endl;
+ } catch (const Exc::Exception &e) {
+ cout << e.message() << endl;
+ } catch (const std::exception &e) {
+ cout << e.what() << endl;
+ } catch (...) {
+ cout << "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 /opt/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;
+}
+
+void internalHelp() {
+ cout << "[sqlite_command] executes sqlite command on database" << endl;
+ cout << ".tables shows a list of table names" << endl;
+ cout << ".schema shows Sqlite3 command used to create tables in the database" << endl;
+ cout << "help shows this help" << endl;
+ cout << "exit (Ctrl-D) quits the program" << endl;
+}
+
+int main(int argc, char* argv[])
+{
+ if(argc < 2 || !argv[1]) {
+ usage();
+ return -1;
+ }
+
+ // read uid
+ stringstream ss(argv[1]);
+ uid_t uid;
+ if(!(ss >> uid)) {
+ usage();
+ return -1;
+ }
+
+ int idx = 2;
+
+ // read password
+ Password pass;
+ if(uid >= 5000) {
+ if(argc > idx) {
+ pass = argv[idx];
+ idx++;
+ }
+ }
+
+ // read sqlite3 command
+ string argcmd;
+ if(argc > idx)
+ argcmd = argv[idx];
+
+ // unlock db
+ DbWrapper dbw(uid, pass);
+ int retCode = dbw.unlock();
+ if (retCode != CKM_API_SUCCESS ) {
+ cout << "Unlocking database failed: " << retCode << endl;
+ return -1;
+ }
+ cout << "Database unlocked" << endl;
+
+ for(;;) {
+ string cmd;
+ if (argcmd.empty()) {
+ cout << "> ";
+ if(!getline(cin, cmd)) {
+ cout << "exit" << endl;
+ break; // EOF
+ }
+ } else {
+ cmd = argcmd;
+ }
+
+ if(cmd == "exit")
+ break;
+ if(cmd == "help") {
+ internalHelp();
+ continue;
+ }
+
+ dbw.process(cmd);
+
+ if(!argcmd.empty())
+ break;
+ }
+ dbw.lock();
+ cout << "Database locked" << endl;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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-crypto-ext.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ * @brief Limited implementation of encrypted db access layer
+ */
+
+#include <db-crypto-ext.h>
+#include <dpl/exception.h>
+
+namespace CKM {
+namespace DB {
+
+SqlConnection::Output CryptoExt::Execute(const std::string& cmd) {
+ SqlConnection::Output out;
+ if(!m_connection) {
+ ThrowMsg(SqlConnection::Exception::ConnectionBroken, "Not connected to database");
+ }
+ m_connection->ExecCommand(&out, "%s", cmd.c_str());
+ return out;
+}
+} // namespace DB
+} // namespace CKM
--- /dev/null
+/*
+ * Copyright (c) 2015 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-crypto-ext.h
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ * @brief Header of encrypted db access layer
+ */
+
+#pragma once
+
+#include <db-crypto.h>
+#include <string>
+#include <utility>
+#include <dpl/db/sql_connection.h>
+
+namespace CKM {
+namespace DB {
+struct CryptoExt : public Crypto {
+ CryptoExt(Crypto orig) : Crypto(std::move(orig)) {}
+
+ SqlConnection::Output Execute(const std::string& cmd);
+};
+
+} // namespace DB
+} // namespace CKM
+