Switch to sqlcipher library 99/227099/27
authorKonrad Lipinski <k.lipinski2@samsung.com>
Thu, 21 Nov 2019 15:51:31 +0000 (16:51 +0100)
committerDariusz Michaluk <d.michaluk@samsung.com>
Mon, 30 Mar 2020 13:15:29 +0000 (13:15 +0000)
Prior to this change, a modified sqlcipher 1.1.9 amalgamation bundled
with key-manager was being used. A push to externalize sqlcipher has
emerged as a result of wise men running SAM (a metrics tool) on the
entire key-manager repo to find that a 130k loc file scores badly.

Problem is, the bundled 1.1.9 sqlcipher had meta-tables renamed as
a result of an oversight, ex. sqlite_master was renamed to
sqlcipher_master. Result: binary incompatibility with upstream.
Running upstream sqlcipher on our legacy db files was found to corrupt
the files after running a single query.

Backward compatibility with existing db files is achieved by:
* bundling sqlcipher 4.3.0 amalgamation with key-manager
* renaming meta tables in the bundled sqlcipher so it's capable of
  opening legacy db files
* adding a textual sql db dump functionality to the bundled sqlcipher,
  based on an upstream extension; it would not work correctly with
  1.1.9, thus the bump to upstream version 4.3.0
* correcting meta table names on the fly when dumping, for instance
  printing sqlite_sequence instead of sqlcipher_sequence
* keeping legacy db filenames as db-$uid
* introducing upstream db filenames as db0-$uid
* converting legacy db files to upstream by using sql dumps of legacy
  files to seed freshly created upstream files
* removing respective legacy files after successful conversion

The bundled amalgamation is factored out into a separate .so library
exporting only one function: dumpLegacyDb. The library is huge and never
needed once the initial conversion is done, thus dlopen/dlsym/dlclose
are employed to mitigate the overhead.

Room for improvement:
* sqlcipher_master meta table contains arbitrary sql that is output
  verbatim when dumping; I have not been able able to prove that those
  statements are free of misnamed meta table references; key-manager
  database dumps appear to be clean
* the entire thing seems fragile; author of the upstream sql dump code
  very nearly disclaims responsibility for its correctness so I believe
  I should too; no sqlcipher tests were imported, just the amalgamation;
  however, a few migration tests were added to ckm-tests-internal
* as before, no additional preprocessor definitions were specified when
  compiling bundled amalgamation; it may be possible to make the
  resulting binary leaner by judicious use of optimization options;
  regardless, that falls out of scope of this change, i.e. doing the
  bare minimum to make things work
* the current solution is unlikely to satisfy the SAM crowd - the
  amalgamation is still here and it's grown to 230k loc

Change-Id: Ia6b25e29151f7957598b68657d083c064cc44ac9

21 files changed:
CMakeLists.txt
packaging/key-manager.spec
src/CMakeLists.txt
src/manager/CMakeLists.txt
src/manager/dpl/db/include/dpl/db/sql_connection.h
src/manager/dpl/db/src/sql_connection.cpp
src/manager/service/ckm-logic.cpp
src/manager/service/db-crypto.cpp
src/manager/service/db-crypto.h
src/manager/service/file-system.cpp
src/manager/service/file-system.h
src/manager/sqlcipher/CMakeLists.txt [new file with mode: 0644]
src/manager/sqlcipher/sqlcipher.c
tests/CMakeLists.txt
tests/DBFixture.cpp
tests/DBFixture.h
tests/encryption-scheme/scheme-test.cpp
tests/resources/testme0_ver4.db [new file with mode: 0644]
tests/test_db_crypto.cpp
tools/ckm_db_tool/CMakeLists.txt
tools/ckm_db_tool/db-wrapper.cpp

index 9787428..20309dd 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2011-2020 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.
@@ -49,7 +49,9 @@ ADD_DEFINITIONS("-Wextra")                      # Generate even more extra warni
 STRING(REGEX MATCH "([^.]*)" API_VERSION "${VERSION}")
 ADD_DEFINITIONS("-DAPI_VERSION=\"$(API_VERSION)\"")
 ADD_DEFINITIONS("-DSMACK_ENABLED")
-ADD_DEFINITIONS("-DSQLCIPHER_HAS_CODEC")
+ADD_DEFINITIONS("-DSQLITE_HAS_CODEC")
+ADD_DEFINITIONS("-DDUMP_LEGACY_DB_LIBNAME=\"${DUMP_LEGACY_DB_LIBNAME}\"")
+ADD_DEFINITIONS("-DLIB_INSTALL_DIR=\"${LIB_INSTALL_DIR}\"")
 ADD_DEFINITIONS("-DRUN_DIR=\"${RUN_DIR}\"")
 ADD_DEFINITIONS("-DSERVICE_NAME=\"${SERVICE_NAME}\"")
 ADD_DEFINITIONS("-DUSER_NAME=\"${USER_NAME}\"")
index 8010dd7..867ef71 100644 (file)
@@ -31,6 +31,7 @@ BuildRequires: pkgconfig(libtzplatform-config)
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(pkgmgr)
 BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(sqlcipher)
 %if 0%{?watchdog_enabled}
 BuildRequires: pkgconfig(argos_watchdog)
 %endif
@@ -63,6 +64,7 @@ Requires: libkey-manager-common = %{version}-%{release}
 %global initial_values_dir_ro %{ro_data_dir}/initial_values
 %global initial_values_dir_rw %{rw_data_dir}/initial_values
 %global ca_certs_dir %{?TZ_SYS_CA_CERTS:%TZ_SYS_CA_CERTS}%{!?TZ_SYS_CA_CERTS:%ro_etc_dir/ssl/certs}
+%global dump_legacy_db_libname key-manager-dump-legacy-database
 
 %description
 Central Key Manager daemon could be used as secure storage
@@ -146,14 +148,9 @@ Includes ckm_initial_values tool for initial values XML generation
 %if 0%{?sec_build_binary_debug_enable}
     export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
     export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
-    export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
 %endif
 
-# needed to surpress sqlcipher errors while its still embedded
-export CFLAGS="$CFLAGS -Wno-cast-function-type -Wno-implicit-fallthrough"
-export CXXFLAGS="$CXXFLAGS -Wno-cast-function-type -Wno-implicit-fallthrough"
-
-export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions "
+export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions"
 
 %cmake . -DVERSION=%{version} \
         -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:RELEASE} \
@@ -185,7 +182,8 @@ export LDFLAGS+="-Wl,--rpath=%{_libdir},-Bsymbolic-functions "
 %else
         -DTZ_BACKEND_ENABLED=OFF \
 %endif
-        -DTEST_DIR=%{test_dir}
+        -DTEST_DIR=%{test_dir} \
+        -DDUMP_LEGACY_DB_LIBNAME=%{dump_legacy_db_libname}
 
 make %{?jobs:-j%jobs}
 
@@ -273,6 +271,7 @@ fi
 %license LICENSE
 %license LICENSE.BSD-3-Clause
 %{bin_dir}/key-manager
+%{_libdir}/lib%{dump_legacy_db_libname}.so
 %{_unitdir}/multi-user.target.wants/central-key-manager.service
 %{_unitdir}/central-key-manager.service
 %{_unitdir}/sockets.target.wants/central-key-manager-api-control.socket
index f69ab36..7369a67 100644 (file)
@@ -26,6 +26,7 @@ PKG_CHECK_MODULES(KEY_MANAGER_DEP
     cynara-creds-socket
     pkgmgr
     vconf
+    sqlcipher
     ${EXTRA_KM_DEPS}
     )
 FIND_PACKAGE(Threads REQUIRED)
@@ -75,7 +76,6 @@ SET(KEY_MANAGER_SOURCES
     ${KEY_MANAGER_PATH}/initial-values/initial-value-loader.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/obj.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp
@@ -111,7 +111,6 @@ INCLUDE_DIRECTORIES(
     ${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
index ee0ce5e..742d905 100644 (file)
@@ -49,7 +49,6 @@ INCLUDE_DIRECTORIES(
     ${COMMON_PATH}/dpl/core/include
     ${COMMON_PATH}/dpl/log/include
     ${COMMON_PATH}/dpl/db/include
-    ${COMMON_PATH}/sqlcipher
     ${COMMON_PATH}/service
     )
 
@@ -73,3 +72,5 @@ TARGET_LINK_LIBRARIES(${TARGET_KEY_MANAGER_COMMON}
 
 
 INSTALL(TARGETS ${TARGET_KEY_MANAGER_COMMON} DESTINATION ${LIB_INSTALL_DIR})
+
+ADD_SUBDIRECTORY(sqlcipher)
index 35db946..063e05b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2020 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.
 #ifndef CKM_SQL_CONNECTION_H
 #define CKM_SQL_CONNECTION_H
 
-#include <dpl/exception.h>
-#include <dpl/availability.h>
 #include <memory>
+#include <stdint.h>
+
 #include <boost/optional.hpp>
+#include <sqlite3.h>
+
+#include <dpl/availability.h>
+#include <dpl/exception.h>
 #include <dpl/log/log.h>
-#include <stdint.h>
 #include <dpl/raw-buffer.h>
 #include <noncopyable.h>
 
@@ -84,7 +87,7 @@ public:
        class DataCommand {
        private:
                SqlConnection *m_masterConnection;
-               sqlcipher3_stmt *m_stmt;
+               sqlite3_stmt *m_stmt;
 
                void CheckBindResult(int result);
                void CheckColumnIndex(SqlConnection::ColumnIndex column);
@@ -396,14 +399,14 @@ public:
        class Flag {
        public:
                enum Option {
-                       RO = SQLCIPHER_OPEN_NOMUTEX | SQLCIPHER_OPEN_READONLY,
-                       RW = SQLCIPHER_OPEN_NOMUTEX | SQLCIPHER_OPEN_READWRITE,
-                       CRW = RW | SQLCIPHER_OPEN_CREATE
+                       RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY,
+                       RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE,
+                       CRW = RW | SQLITE_OPEN_CREATE
                };
        };
 
        // RowID
-       typedef sqlcipher3_int64 RowID;
+       typedef sqlite3_int64 RowID;
 
        /**
         * Synchronization object used to synchronize SQL connection
@@ -425,7 +428,7 @@ public:
        };
 
 protected:
-       sqlcipher3 *m_connection;
+       sqlite3 *m_connection;
 
        // Options
 
@@ -449,9 +452,9 @@ public:
        /**
         * Open SQL connection
         *
-        * Synchronization is archieved by using provided asynchronization object.
+        * Synchronization is achieved by using a provided synchronization object.
         * If synchronizationObject is set to NULL, so synchronization is performed.
-        * Ownership of the synchronization object is transfered to sql connection
+        * Ownership of the synchronization object is transferred to sql connection
         * object.
         *
         * @param address Database file name
@@ -561,6 +564,7 @@ public:
 private:
        void ExecCommandHelper(Output *out, const char *format, va_list args);
 };
+RawBuffer createHexPass(const RawBuffer &rawPass);
 } // namespace DB
 } // namespace CKM
 
index a9ee1b5..3aa5b72 100644 (file)
@@ -76,17 +76,17 @@ SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
        ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
 
        for (int i = 0; i < MAX_RETRY; i++) {
-               int ret = sqlcipher3_prepare_v2(connection->m_connection,
+               int ret = sqlite3_prepare_v2(connection->m_connection,
                                                                                buffer, strlen(buffer),
                                                                                &m_stmt, NULL);
 
-               if (ret == SQLCIPHER_OK) {
+               if (ret == SQLITE_OK) {
                        LogPedantic("Prepared data command: " << buffer);
 
                        // Increment stored data command count
                        ++m_masterConnection->m_dataCommandsCount;
                        return;
-               } else if (ret == SQLCIPHER_BUSY) {
+               } else if (ret == SQLITE_BUSY) {
                        LogPedantic("Collision occurred while preparing SQL command");
 
                        // Synchronize if synchronization object is available
@@ -100,7 +100,7 @@ SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
                }
 
                // Fatal error
-               const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+               const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
 
                LogError("SQL prepare data command failed");
                LogError("    Statement: " << buffer);
@@ -117,7 +117,7 @@ SqlConnection::DataCommand::~DataCommand()
 {
        LogPedantic("SQL data command finalizing");
 
-       if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
+       if (sqlite3_finalize(m_stmt) != SQLITE_OK)
                LogError("Failed to finalize data command");
 
        // Decrement stored data command count
@@ -126,8 +126,8 @@ SqlConnection::DataCommand::~DataCommand()
 
 void SqlConnection::DataCommand::CheckBindResult(int result)
 {
-       if (result != SQLCIPHER_OK) {
-               const char *error = sqlcipher3_errmsg(
+       if (result != SQLITE_OK) {
+               const char *error = sqlite3_errmsg(
                                                                m_masterConnection->m_connection);
 
                LogError("Failed to bind SQL statement parameter");
@@ -141,7 +141,7 @@ void SqlConnection::DataCommand::CheckBindResult(int result)
 void SqlConnection::DataCommand::BindNull(
        SqlConnection::ArgumentIndex position)
 {
-       CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
+       CheckBindResult(sqlite3_bind_null(m_stmt, position));
        LogPedantic("SQL data command bind null: ["
                                << position << "]");
 }
@@ -151,7 +151,7 @@ void SqlConnection::DataCommand::BindInteger(
        SqlConnection::ArgumentIndex position,
        int value)
 {
-       CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
+       CheckBindResult(sqlite3_bind_int(m_stmt, position, value));
        LogPedantic("SQL data command bind integer: ["
                                << position << "] -> " << value);
 }
@@ -161,7 +161,7 @@ void SqlConnection::DataCommand::BindInt8(
        SqlConnection::ArgumentIndex position,
        int8_t value)
 {
-       CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+       CheckBindResult(sqlite3_bind_int(m_stmt, position,
                                                                                static_cast<int>(value)));
        LogPedantic("SQL data command bind int8: ["
                                << position << "] -> " << value);
@@ -171,7 +171,7 @@ void SqlConnection::DataCommand::BindInt16(
        SqlConnection::ArgumentIndex position,
        int16_t value)
 {
-       CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+       CheckBindResult(sqlite3_bind_int(m_stmt, position,
                                                                                static_cast<int>(value)));
        LogPedantic("SQL data command bind int16: ["
                                << position << "] -> " << value);
@@ -181,7 +181,7 @@ void SqlConnection::DataCommand::BindInt32(
        SqlConnection::ArgumentIndex position,
        int32_t value)
 {
-       CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
+       CheckBindResult(sqlite3_bind_int(m_stmt, position,
                                                                                static_cast<int>(value)));
        LogPedantic("SQL data command bind int32: ["
                                << position << "] -> " << value);
@@ -191,8 +191,8 @@ void SqlConnection::DataCommand::BindInt64(
        SqlConnection::ArgumentIndex position,
        int64_t value)
 {
-       CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
-                                                                                 static_cast<sqlcipher3_int64>(value)));
+       CheckBindResult(sqlite3_bind_int64(m_stmt, position,
+                                                                                 static_cast<sqlite3_int64>(value)));
        LogPedantic("SQL data command bind int64: ["
                                << position << "] -> " << value);
 }
@@ -201,7 +201,7 @@ void SqlConnection::DataCommand::BindFloat(
        SqlConnection::ArgumentIndex position,
        float value)
 {
-       CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
+       CheckBindResult(sqlite3_bind_double(m_stmt, position,
                                                                                   static_cast<double>(value)));
        LogPedantic("SQL data command bind float: ["
                                << position << "] -> " << value);
@@ -211,7 +211,7 @@ void SqlConnection::DataCommand::BindDouble(
        SqlConnection::ArgumentIndex position,
        double value)
 {
-       CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
+       CheckBindResult(sqlite3_bind_double(m_stmt, position, value));
        LogPedantic("SQL data command bind double: ["
                                << position << "] -> " << value);
 }
@@ -227,9 +227,9 @@ void SqlConnection::DataCommand::BindString(
        }
 
        // Assume that text may disappear
-       CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
+       CheckBindResult(sqlite3_bind_text(m_stmt, position,
                                                                                 value, strlen(value),
-                                                                                SQLCIPHER_TRANSIENT));
+                                                                                SQLITE_TRANSIENT));
 
        LogPedantic("SQL data command bind string: ["
                                << position << "] -> " << value);
@@ -245,9 +245,9 @@ void SqlConnection::DataCommand::BindBlob(
        }
 
        // Assume that blob may dissappear
-       CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
+       CheckBindResult(sqlite3_bind_blob(m_stmt, position,
                                                                                 raw.data(), raw.size(),
-                                                                                SQLCIPHER_TRANSIENT));
+                                                                                SQLITE_TRANSIENT));
        LogPedantic("SQL data command bind blob of size: ["
                                << position << "] -> " << raw.size());
 }
@@ -341,15 +341,15 @@ bool SqlConnection::DataCommand::Step()
                m_masterConnection->m_synchronizationObject.get());
 
        for (int i = 0; i < MAX_RETRY; i++) {
-               int ret = sqlcipher3_step(m_stmt);
+               int ret = sqlite3_step(m_stmt);
 
-               if (ret == SQLCIPHER_ROW) {
+               if (ret == SQLITE_ROW) {
                        LogPedantic("SQL data command step ROW");
                        return true;
-               } else if (ret == SQLCIPHER_DONE) {
+               } else if (ret == SQLITE_DONE) {
                        LogPedantic("SQL data command step DONE");
                        return false;
-               } else if (ret == SQLCIPHER_BUSY) {
+               } else if (ret == SQLITE_BUSY) {
                        LogPedantic("Collision occurred while executing SQL command");
 
                        // Synchronize if synchronization object is available
@@ -366,7 +366,7 @@ bool SqlConnection::DataCommand::Step()
                }
 
                // Fatal error
-               const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
+               const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
 
                LogError("SQL step data command failed");
                LogError("    Error: " << error);
@@ -384,11 +384,11 @@ void SqlConnection::DataCommand::Reset()
         * According to:
         * http://www.sqllite.org/c3ref/stmt.html
         *
-        * if last sqlcipher3_step command on this stmt returned an error,
-        * then sqlcipher3_reset will return that error, althought it is not an error.
-        * So sqlcipher3_reset allways succedes.
+        * if last sqlite3_step command on this stmt returned an error,
+        * then sqlite3_reset will return that error, althought it is not an error.
+        * So sqlite3_reset allways succedes.
         */
-       sqlcipher3_reset(m_stmt);
+       sqlite3_reset(m_stmt);
 
        LogPedantic("SQL data command reset");
 }
@@ -396,7 +396,7 @@ void SqlConnection::DataCommand::Reset()
 void SqlConnection::DataCommand::CheckColumnIndex(
        SqlConnection::ColumnIndex column)
 {
-       if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
+       if (column < 0 || column >= sqlite3_column_count(m_stmt))
                ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
 }
 
@@ -406,7 +406,7 @@ bool SqlConnection::DataCommand::IsColumnNull(
 {
        LogPedantic("SQL data command get column type: [" << column << "]");
        CheckColumnIndex(column);
-       return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
+       return sqlite3_column_type(m_stmt, column) == SQLITE_NULL;
 }
 //LCOV_EXCL_STOP
 
@@ -415,7 +415,7 @@ int SqlConnection::DataCommand::GetColumnInteger(
 {
        LogPedantic("SQL data command get column integer: [" << column << "]");
        CheckColumnIndex(column);
-       int value = sqlcipher3_column_int(m_stmt, column);
+       int value = sqlite3_column_int(m_stmt, column);
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -426,7 +426,7 @@ int8_t SqlConnection::DataCommand::GetColumnInt8(
 {
        LogPedantic("SQL data command get column int8: [" << column << "]");
        CheckColumnIndex(column);
-       int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
+       int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -436,7 +436,7 @@ int16_t SqlConnection::DataCommand::GetColumnInt16(
 {
        LogPedantic("SQL data command get column int16: [" << column << "]");
        CheckColumnIndex(column);
-       int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
+       int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -446,7 +446,7 @@ int32_t SqlConnection::DataCommand::GetColumnInt32(
 {
        LogPedantic("SQL data command get column int32: [" << column << "]");
        CheckColumnIndex(column);
-       int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
+       int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -456,7 +456,7 @@ int64_t SqlConnection::DataCommand::GetColumnInt64(
 {
        LogPedantic("SQL data command get column int64: [" << column << "]");
        CheckColumnIndex(column);
-       int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
+       int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -466,7 +466,7 @@ float SqlConnection::DataCommand::GetColumnFloat(
 {
        LogPedantic("SQL data command get column float: [" << column << "]");
        CheckColumnIndex(column);
-       float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
+       float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -476,7 +476,7 @@ double SqlConnection::DataCommand::GetColumnDouble(
 {
        LogPedantic("SQL data command get column double: [" << column << "]");
        CheckColumnIndex(column);
-       double value = sqlcipher3_column_double(m_stmt, column);
+       double value = sqlite3_column_double(m_stmt, column);
        LogPedantic("    Value: " << value);
        return value;
 }
@@ -489,7 +489,7 @@ std::string SqlConnection::DataCommand::GetColumnString(
        CheckColumnIndex(column);
 
        const char *value = reinterpret_cast<const char *>(
-                                                       sqlcipher3_column_text(m_stmt, column));
+                                                       sqlite3_column_text(m_stmt, column));
 
        LogPedantic("Value: " << (value ? value : "NULL"));
 
@@ -506,12 +506,12 @@ RawBuffer SqlConnection::DataCommand::GetColumnBlob(
        CheckColumnIndex(column);
 
        const unsigned char *value = reinterpret_cast<const unsigned char *>(
-                                                                        sqlcipher3_column_blob(m_stmt, column));
+                                                                        sqlite3_column_blob(m_stmt, column));
 
        if (value == NULL)
                return RawBuffer();
 
-       int length = sqlcipher3_column_bytes(m_stmt, column);
+       int length = sqlite3_column_bytes(m_stmt, column);
        LogPedantic("Got blob of length: " << length);
 
        return RawBuffer(value, value + length);
@@ -525,10 +525,10 @@ boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<int>();
 
-       int value = sqlcipher3_column_int(m_stmt, column);
+       int value = sqlite3_column_int(m_stmt, column);
        LogPedantic("    Value: " << value);
        return boost::optional<int>(value);
 }
@@ -540,10 +540,10 @@ boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<int8_t>();
 
-       int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
+       int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return boost::optional<int8_t>(value);
 }
@@ -555,10 +555,10 @@ boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<int16_t>();
 
-       int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
+       int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return boost::optional<int16_t>(value);
 }
@@ -570,10 +570,10 @@ boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<int32_t>();
 
-       int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
+       int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
        LogPedantic("    Value: " << value);
        return boost::optional<int32_t>(value);
 }
@@ -585,10 +585,10 @@ boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<int64_t>();
 
-       int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
+       int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
        LogPedantic("    Value: " << value);
        return boost::optional<int64_t>(value);
 }
@@ -600,10 +600,10 @@ boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<float>();
 
-       float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
+       float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
        LogPedantic("    Value: " << value);
        return boost::optional<float>(value);
 }
@@ -615,10 +615,10 @@ boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
                                << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<double>();
 
-       double value = sqlcipher3_column_double(m_stmt, column);
+       double value = sqlite3_column_double(m_stmt, column);
        LogPedantic("    Value: " << value);
        return boost::optional<double>(value);
 }
@@ -629,13 +629,13 @@ boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
        LogPedantic("SQL data command get column blog: [" << column << "]");
        CheckColumnIndex(column);
 
-       if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
+       if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL)
                return boost::optional<RawBuffer>();
 
        const unsigned char *value = reinterpret_cast<const unsigned char *>(
-                                                                        sqlcipher3_column_blob(m_stmt, column));
+                                                                        sqlite3_column_blob(m_stmt, column));
 
-       int length = sqlcipher3_column_bytes(m_stmt, column);
+       int length = sqlite3_column_bytes(m_stmt, column);
        LogPedantic("Got blob of length: " << length);
 
        RawBuffer temp(value, value + length);
@@ -655,13 +655,13 @@ void SqlConnection::Connect(const std::string &address,
 
        // Connect to database
        int result;
-       result = sqlcipher3_open_v2(
+       result = sqlite3_open_v2(
                                 address.c_str(),
                                 &m_connection,
                                 flag,
                                 NULL);
 
-       if (result == SQLCIPHER_OK) {
+       if (result == SQLITE_OK) {
                LogPedantic("Connected to DB");
        } else {
                LogError("Failed to connect to DB!");
@@ -672,9 +672,9 @@ void SqlConnection::Connect(const std::string &address,
        TurnOnForeignKeys();
 }
 
-const std::string SQLCIPHER_RAW_PREFIX = "x'";
-const std::string SQLCIPHER_RAW_SUFIX = "'";
-const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
+const std::string SQLITE_RAW_PREFIX = "x'";
+const std::string SQLITE_RAW_SUFIX = "'";
+const std::size_t SQLITE_RAW_DATA_SIZE = 32;
 
 RawBuffer rawToHexString(const RawBuffer &raw)
 {
@@ -686,7 +686,7 @@ RawBuffer createHexPass(const RawBuffer &rawPass)
        // We are required to pass 64byte long hex password made out of 32byte raw
        // binary data
        RawBuffer output;
-       std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
+       std::copy(SQLITE_RAW_PREFIX.begin(), SQLITE_RAW_PREFIX.end(),
                          std::back_inserter(output));
 
        RawBuffer password = rawToHexString(rawPass);
@@ -694,7 +694,7 @@ RawBuffer createHexPass(const RawBuffer &rawPass)
        std::copy(password.begin(), password.end(),
                          std::back_inserter(output));
 
-       std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
+       std::copy(SQLITE_RAW_SUFIX.begin(), SQLITE_RAW_SUFIX.end(),
                          std::back_inserter(output));
 
        return output;
@@ -707,17 +707,17 @@ void SqlConnection::SetKey(const RawBuffer &rawPass)
                return;
        }
 
-       if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
+       if (rawPass.size() != SQLITE_RAW_DATA_SIZE)
                ThrowMsg(Exception::InvalidArguments,
                                 "Binary data for raw password should be 32 bytes long.");
 
        RawBuffer pass = createHexPass(rawPass);
-       int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
+       int result = sqlite3_key(m_connection, pass.data(), pass.size());
 
-       if (result == SQLCIPHER_OK) {
+       if (result == SQLITE_OK) {
                LogPedantic("Set key on DB");
        } else {
-               //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
+               //sqlite3_key fails only when m_connection == NULL || key == NULL ||
                //                            key length == 0
                LogError("Failed to set key on DB");
                ThrowMsg(Exception::InvalidArguments, result);
@@ -736,21 +736,20 @@ void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
        }
 
        // Binary data for raw password should be 32 bytes long.
-       assert(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
-              rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE);
+       assert(rawPassOld.size() == SQLITE_RAW_DATA_SIZE &&
+              rawPassNew.size() == SQLITE_RAW_DATA_SIZE);
 
-
-       // sqlcipher3_rekey requires for key to be already set
+       // sqlite3_rekey requires for key to be already set
        if (!m_isKeySet)
                SetKey(rawPassOld);
 
        RawBuffer pass = createHexPass(rawPassNew);
-       int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
+       int result = sqlite3_rekey(m_connection, pass.data(), pass.size());
 
-       if (result == SQLCIPHER_OK) {
+       if (result == SQLITE_OK) {
                LogPedantic("Reset key on DB");
        } else {
-               //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
+               //sqlite3_rekey fails only when m_connection == NULL || key == NULL ||
                //                              key length == 0
                LogError("Failed to reset key on DB");
                ThrowMsg(Exception::InvalidArguments, result);
@@ -772,10 +771,10 @@ void SqlConnection::Disconnect()
 
        int result;
 
-       result = sqlcipher3_close(m_connection);
+       result = sqlite3_close(m_connection);
 
-       if (result != SQLCIPHER_OK) {
-               const char *error = sqlcipher3_errmsg(m_connection);
+       if (result != SQLITE_OK) {
+               const char *error = sqlite3_errmsg(m_connection);
                LogError("SQL close failed");
                LogError("    Error: " << error);
                Throw(Exception::InternalError);
@@ -794,7 +793,7 @@ bool SqlConnection::CheckTableExist(const char *tableName)
        }
 
        DataCommandUniquePtr command =
-               PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
+               PrepareDataCommand("select tbl_name from sqlite_master where name=?;");
 
        command->BindString(1, tableName);
 
@@ -890,7 +889,7 @@ void SqlConnection::ExecCommandHelper(Output *out, const char *format,
 
        for (int i = 0; i < MAX_RETRY; i++) {
                char *errorBuffer;
-               int ret = sqlcipher3_exec(m_connection,
+               int ret = sqlite3_exec(m_connection,
                                                                  queryPtr.get(),
                                                                  out ? &Output::Callback : NULL,
                                                                  out,
@@ -901,13 +900,13 @@ void SqlConnection::ExecCommandHelper(Output *out, const char *format,
                // Take allocated error buffer
                if (errorBuffer != NULL) {
                        errorMsg = errorBuffer;
-                       sqlcipher3_free(errorBuffer);
+                       sqlite3_free(errorBuffer);
                }
 
-               if (ret == SQLCIPHER_OK)
+               if (ret == SQLITE_OK)
                        return;
 
-               if (ret == SQLCIPHER_BUSY) {
+               if (ret == SQLITE_BUSY) {
                        LogPedantic("Collision occurred while executing SQL command");
 
                        // Synchronize if synchronization object is available
@@ -991,7 +990,7 @@ SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
 //LCOV_EXCL_START
 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
 {
-       return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
+       return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection));
 }
 //LCOV_EXCL_STOP
 
index 18e9e69..c26dc6a 100644 (file)
@@ -148,7 +148,7 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
 
                RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-               handle.database = DB::Crypto(fs.getDBPath(), key);
+               handle.database = DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key);
                handle.crypto = CryptoLogic();
 
                if (!m_accessControl.isSystemService(user)) {
index 1121d66..ce85bcf 100644 (file)
  * @brief       Implementation of encrypted db access layer
  */
 
+#include <dlfcn.h>
+#include <fcntl.h>
 #include <fstream>
+#include <libgen.h>
+#include <sys/stat.h>
 #include <db-crypto.h>
 #include <dpl/db/sql_connection.h>
+#include <dpl/errno_string.h>
 #include <dpl/log/log.h>
+#include <dpl/scoped_ptr.h>
 #include <ckm/ckm-error.h>
 #include <exception.h>
 
@@ -149,12 +155,73 @@ const char *DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION =
 
 namespace CKM {
 namespace DB {
-Crypto::Crypto(const std::string &path, const RawBuffer &rawPass) :
+
+namespace {
+auto openSqlConnection(const std::string &path, const RawBuffer &rawPass)
+{
+       auto conn = std::make_unique<SqlConnection>(path, SqlConnection::Flag::Option::CRW);
+       conn->SetKey(rawPass);
+       return conn;
+}
+
+void convertLegacyDatabase(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass)
+{
+       {
+               struct stat st;
+               if (lstat(legacyPath.c_str(), &st)) {
+                       const auto err = errno;
+                       if (ENOENT != err)
+                               ThrowErr(Exc::DatabaseFailed, "lstat failed: " << GetErrnoString(err));
+                       LogDebug("legacy db does not exist, proceeding");
+                       return;
+               }
+               if (!S_ISREG(st.st_mode))
+                       ThrowErr(Exc::DatabaseFailed, "legacy db not a regular file");
+       }
+       if (unlink(path.c_str()) && ENOENT != errno)
+               ThrowErr(Exc::DatabaseFailed, "unlink failed: " << GetErrnoString());
+
+       // in no way to I condone the use of unique_ptr in this context; see: review
+       struct Dlclose { void operator()(void *p) { dlclose(p); } };
+       const auto handle = std::unique_ptr<void, Dlclose>(
+                       dlopen(LIB_INSTALL_DIR "/lib" DUMP_LEGACY_DB_LIBNAME ".so", RTLD_LAZY)
+                               ?: ThrowErr(Exc::DatabaseFailed, "dlopen failed: " << dlerror()));
+       const auto dumpLegacyDb = (char *(*)(const char *, const unsigned char *, size_t))
+               dlsym(handle.get(), "dumpLegacyDb")
+                       ?: ThrowErr(Exc::DatabaseFailed, "dlsym failed: " << dlerror());
+
+       {
+               const RawBuffer pass = createHexPass(rawPass);
+               const CharUniquePtr sqlDump(dumpLegacyDb(legacyPath.c_str(), pass.data(), pass.size())
+                               ?: ThrowErr(Exc::DatabaseFailed, "dump failed"));
+
+               // close to ensure full sync regardless of pragma synchronous value
+               // EXTRA is needed to sync the dir after transaction but isn't used in ckm
+               openSqlConnection(path, rawPass)->ExecCommand(sqlDump.get());
+               LogDebug("legacy db converted, removing");
+       }
+
+       if (unlink(legacyPath.c_str()))
+               ThrowErr(Exc::DatabaseFailed, "unlink legacy db failed: " << GetErrnoString());
+       std::string legacyPathCopy(legacyPath);
+       const auto legacyDirPath = dirname(&legacyPathCopy[0]);
+       const int legacyDirFd = TEMP_FAILURE_RETRY(open(legacyDirPath, O_RDONLY));
+       if (legacyDirFd < 0)
+               ThrowErr(Exc::DatabaseFailed, "open failed: " << GetErrnoString());
+       const auto fsyncRes = fsync(legacyDirFd);
+       const auto fsyncErrno = errno;
+       close(legacyDirFd);
+       if (fsyncRes)
+               ThrowErr(Exc::DatabaseFailed, "fsync failed: " << GetErrnoString(fsyncErrno));
+}
+} // namespace
+
+Crypto::Crypto(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass) :
        m_inUserTransaction(false)
 {
        try {
-               m_connection.reset(new SqlConnection(path, SqlConnection::Flag::Option::CRW));
-               m_connection->SetKey(rawPass);
+               convertLegacyDatabase(legacyPath, path, rawPass);
+               m_connection = openSqlConnection(path, rawPass);
                initDatabase();
                m_connection->ExecCommand("VACUUM;");
        } catch (const SqlConnection::Exception::ConnectionBroken &e) {
@@ -250,12 +317,11 @@ 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
+       if (!getDBVersion(schemaVersion) || schemaVersion > DB_VERSION_CURRENT) {
                LogDebug("no database or database corrupted, initializing the DB");
-               resetDB();
-       } else {
+               goto fail;
+       }
+       if (schemaVersion < DB_VERSION_CURRENT) {
                // migration needed
                LogDebug("DB migration from version " << schemaVersion << " to version " <<
                                 DB_VERSION_CURRENT << " started.");
@@ -267,12 +333,11 @@ void Crypto::initDatabase()
                        if (!script) {
                                LogError("Error, script to migrate database from version: " << vi <<
                                                 " to version: " << vi + 1 << " not available, resetting the DB");
-                               resetDB();
-                               break;
+                               goto fail;
                        }
 
                        LogInfo("migrating from version " << vi << " to version " << vi + 1);
-                       m_connection->ExecCommand((*script).c_str());
+                       m_connection->ExecCommand(script->c_str());
                }
 
                // update DB version info
@@ -280,6 +345,10 @@ void Crypto::initDatabase()
                SchemaInfo.setVersionInfo();
                transaction.commit();
        }
+       return;
+
+fail:
+       resetDB();
 }
 
 Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
index a915307..6372320 100644 (file)
@@ -46,7 +46,8 @@ public:
        Crypto() : m_inUserTransaction(false) {}
 
        // user name instead of path?
-       Crypto(const std::string &path, const RawBuffer &rawPass);
+       // in no way to I condone the use of std::string for legacyPath; see: review
+       Crypto(const std::string &legacyPath, const std::string &path, const RawBuffer &rawPass);
        Crypto(const Crypto &other) = delete;
        Crypto(Crypto &&other);
 
index 0b50d37..e1ef844 100644 (file)
 #include <for-each-file.h>
 #include <file-system.h>
 
+namespace CKM {
+
 namespace {
 
 const std::string CKM_KEY_PREFIX = "key-";
 const std::string CKM_DB_KEY_PREFIX = "db-key-";
-const std::string CKM_DB_PREFIX = "db-";
+const std::string CKM_LEGACY_DB_PREFIX = "db-";
+const std::string CKM_DB_PREFIX = "db0-";
 const std::string CKM_REMOVED_APP_PREFIX = "removed-app-";
 const std::string CKM_LOCK_FILE = RUN_DIR "/" SERVICE_NAME "/key-manager.pid";
 
-} // namespace anonymous
+wur std::string getPath(const std::string &prefix, uid_t uid)
+{
+       std::stringstream ss;
+       ss << RW_DATA_DIR << "/" << prefix << uid;
+       return ss.str();
+}
 
-namespace CKM {
+} // namespace anonymous
 
 FileSystem::FileSystem(uid_t uid)
        : m_uid(uid)
 {
 }
 
+std::string FileSystem::getLegacyDBPath() const
+{
+       return getPath(CKM_LEGACY_DB_PREFIX, m_uid);
+}
+
 std::string FileSystem::getDBPath() const
 {
-       std::stringstream ss;
-       ss << RW_DATA_DIR << "/" << CKM_DB_PREFIX << m_uid;
-       return ss.str();
+       return getPath(CKM_DB_PREFIX, m_uid);
 }
 
 std::string FileSystem::getDKEKPath() const
 {
-       std::stringstream ss;
-       ss << RW_DATA_DIR << "/" << CKM_KEY_PREFIX << m_uid;
-       return ss.str();
+       return getPath(CKM_KEY_PREFIX, m_uid);
 }
 
 std::string FileSystem::getDBDEKPath() const
 {
-       std::stringstream ss;
-       ss << RW_DATA_DIR << "/" << CKM_DB_KEY_PREFIX << m_uid;
-       return ss.str();
+       return getPath(CKM_DB_KEY_PREFIX, m_uid);
 }
 
 std::string FileSystem::getRemovedAppsPath() const
 {
-       std::stringstream ss;
-       ss << RW_DATA_DIR << "/" << CKM_REMOVED_APP_PREFIX << m_uid;
-       return ss.str();
+       return getPath(CKM_REMOVED_APP_PREFIX, m_uid);
 }
 
 RawBuffer FileSystem::loadFile(const std::string &path) const
@@ -245,6 +250,7 @@ int FileSystem::removeUserData() const
        };
 
        return unlinkUserPath(getDBPath(), " database")
+               | unlinkUserPath(getLegacyDBPath(), " legacy database")
                | unlinkUserPath(getDKEKPath(), " DKEK")
                | unlinkUserPath(getDBDEKPath(), " DBDEK")
                | unlinkUserPath(getRemovedAppsPath(), "'s Removed Apps File");
index 31f57ed..efe5999 100644 (file)
@@ -36,6 +36,7 @@ class FileSystem final {
 public:
        explicit FileSystem(uid_t uid);
 
+       wur std::string getLegacyDBPath() const;
        wur std::string getDBPath() const;
 
        // Domain Key Encryption Key
diff --git a/src/manager/sqlcipher/CMakeLists.txt b/src/manager/sqlcipher/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dd7c654
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2020 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.
+
+ADD_LIBRARY(
+    ${DUMP_LEGACY_DB_LIBNAME}
+    SHARED
+    sqlcipher.c
+)
+
+SET_TARGET_PROPERTIES(
+    ${DUMP_LEGACY_DB_LIBNAME}
+    PROPERTIES
+        COMPILE_FLAGS "-fvisibility=hidden -Wl,--no-undefined"
+)
+
+INSTALL(
+    TARGETS
+    ${DUMP_LEGACY_DB_LIBNAME}
+    DESTINATION
+    ${LIB_INSTALL_DIR}
+)
index edb3165..5f345df 100644 (file)
 ** language. The code for the "sqlite3" command-line shell is also in a
 ** separate file. This file contains only code for the core SQLite library.
 */
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 #define SQLITE_CORE 1
 #define SQLITE_AMALGAMATION 1
 #ifndef SQLITE_PRIVATE
@@ -14241,8 +14247,8 @@ struct BusyHandler {
 ** is a special table that holds the names and attributes of all
 ** user tables and indices.
 */
-#define MASTER_NAME       "sqlite_master"
-#define TEMP_MASTER_NAME  "sqlite_temp_master"
+#define MASTER_NAME       "sqlcipher_master"
+#define TEMP_MASTER_NAME  "sqlcipher_temp_master"
 
 /*
 ** The root-page of the master database table.
@@ -22027,7 +22033,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
   */
   zSql = sqlite3_mprintf(
     "SELECT sql "
-    "  FROM %s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+    "  FROM %s.sqlcipher_master WHERE type='table' AND name!='sqlcipher_sequence'"
     "   AND rootpage>0"
   , sourceDb);
   rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
@@ -22036,7 +22042,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
 
   zSql = sqlite3_mprintf(
     "SELECT sql "
-    "  FROM %s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
+    "  FROM %s.sqlcipher_master WHERE sql LIKE 'CREATE INDEX %%' "
   , sourceDb);
   rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
   if( rc!=SQLITE_OK ) goto end_of_export;
@@ -22044,7 +22050,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
 
   zSql = sqlite3_mprintf(
     "SELECT sql "
-    "  FROM %s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
+    "  FROM %s.sqlcipher_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
   , sourceDb);
   rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
   if( rc!=SQLITE_OK ) goto end_of_export;
@@ -22057,8 +22063,8 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
   zSql = sqlite3_mprintf(
     "SELECT 'INSERT INTO %s.' || quote(name) "
     "|| ' SELECT * FROM %s.' || quote(name) || ';'"
-    "FROM %s.sqlite_master "
-    "WHERE type = 'table' AND name!='sqlite_sequence' "
+    "FROM %s.sqlcipher_master "
+    "WHERE type = 'table' AND name!='sqlcipher_sequence' "
     "  AND rootpage>0"
   , targetDb, sourceDb, sourceDb);
   rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
@@ -22070,7 +22076,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
   zSql = sqlite3_mprintf(
     "SELECT 'INSERT INTO %s.' || quote(name) "
     "|| ' SELECT * FROM %s.' || quote(name) || ';' "
-    "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
+    "FROM %s.sqlcipher_master WHERE name=='sqlcipher_sequence';"
   , targetDb, sourceDb, targetDb);
   rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
   if( rc!=SQLITE_OK ) goto end_of_export;
@@ -22082,9 +22088,9 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
   ** from the SQLITE_MASTER table.
   */
   zSql = sqlite3_mprintf(
-    "INSERT INTO %s.sqlite_master "
+    "INSERT INTO %s.sqlcipher_master "
     "  SELECT type, name, tbl_name, rootpage, sql"
-    "    FROM %s.sqlite_master"
+    "    FROM %s.sqlcipher_master"
     "   WHERE type='view' OR type='trigger'"
     "      OR (type='table' AND rootpage=0)"
   , targetDb, sourceDb);
@@ -24467,7 +24473,6 @@ static int sqlcipher_openssl_deactivate(void *ctx) {
   openssl_init_count--;
 
   if(openssl_init_count == 0) {
-    sqlite3_mutex *temp_mutex;
     if(openssl_external_init == 0) {
     /* if OpenSSL hasn't be initialized externally, and the counter reaches zero
        after it's decremented, release EVP memory
@@ -63015,13 +63020,6 @@ SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
   CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
   return aData;
 }
-
-/*
-** Return the current pager state
-*/
-SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
-  return pPager->eState;
-}
 #endif /* SQLITE_HAS_CODEC */
 
 #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -107862,7 +107860,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
             "WHEN type='table' THEN %Q "
             "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' "
             "     AND type='index' THEN "
-             "'sqlite_autoindex_' || %Q || substr(name,%d+18) "
+             "'sqlcipher_autoindex_' || %Q || substr(name,%d+18) "
             "ELSE name END "
       "WHERE tbl_name=%Q COLLATE nocase AND "
           "(type='table' OR type='index' OR type='trigger');",
@@ -107875,9 +107873,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   /* If the sqlite_sequence table exists in this database, then update
   ** it with the new table name.
   */
-  if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
+  if( sqlite3FindTable(db, "sqlcipher_sequence", zDb) ){
     sqlite3NestedParse(pParse,
-        "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
+        "UPDATE \"%w\".sqlcipher_sequence set name = %Q WHERE name = %Q",
         zDb, zName, pTab->zName);
   }
 #endif
@@ -107887,7 +107885,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   ** as required.  */
   if( iDb!=1 ){
     sqlite3NestedParse(pParse,
-        "UPDATE sqlite_temp_master SET "
+        "UPDATE sqlcipher_temp_master SET "
             "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
             "tbl_name = "
               "CASE WHEN tbl_name=%Q COLLATE nocase AND "
@@ -109509,13 +109507,13 @@ static void openStatTable(
     const char *zName;
     const char *zCols;
   } aTable[] = {
-    { "sqlite_stat1", "tbl,idx,stat" },
+    { "sqlcipher_stat1", "tbl,idx,stat" },
 #if defined(SQLITE_ENABLE_STAT4)
-    { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
+    { "sqlcipher_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
 #else
-    { "sqlite_stat4", 0 },
+    { "sqlcipher_stat4", 0 },
 #endif
-    { "sqlite_stat3", 0 },
+    { "sqlcipher_stat3", 0 },
   };
   int i;
   sqlite3 *db = pParse->db;
@@ -110330,7 +110328,7 @@ static void analyzeOneTable(
     pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
     if( pStat1==0 ) return;
     pStat1->zName = (char*)&pStat1[1];
-    memcpy(pStat1->zName, "sqlite_stat1", 13);
+    memcpy(pStat1->zName, "sqlcipher_stat1", 16);
     pStat1->nCol = 3;
     pStat1->iPKey = -1;
     sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
@@ -111109,10 +111107,10 @@ static int loadStat4(sqlite3 *db, const char *zDb){
   int rc = SQLITE_OK;             /* Result codes from subroutines */
 
   assert( db->lookaside.bDisable );
-  if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
+  if( sqlite3FindTable(db, "sqlcipher_stat4", zDb) ){
     rc = loadStatTbl(db,
-      "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
-      "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
+      "SELECT idx,count(*) FROM %Q.sqlcipher_stat4 GROUP BY idx",
+      "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlcipher_stat4",
       zDb
     );
   }
@@ -111168,9 +111166,9 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
   /* Load new statistics out of the sqlite_stat1 table */
   sInfo.db = db;
   sInfo.zDatabase = db->aDb[iDb].zDbSName;
-  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
+  if( sqlite3FindTable(db, "sqlcipher_stat1", sInfo.zDatabase)!=0 ){
     zSql = sqlite3MPrintf(db,
-        "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+        "SELECT tbl,idx,stat FROM %Q.sqlcipher_stat1", sInfo.zDatabase);
     if( zSql==0 ){
       rc = SQLITE_NOMEM_BKPT;
     }else{
@@ -113157,7 +113155,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
   ** so that INSERT can find the table easily.
   */
 #ifndef SQLITE_OMIT_AUTOINCREMENT
-  if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
+  if( !pParse->nested && strcmp(zName, "sqlcipher_sequence")==0 ){
     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
     pTable->pSchema->pSeqTab = pTable;
   }
@@ -114388,7 +114386,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
       assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
       if( pDb->pSchema->pSeqTab==0 ){
         sqlite3NestedParse(pParse,
-          "CREATE TABLE %Q.sqlite_sequence(name,seq)",
+          "CREATE TABLE %Q.sqlcipher_sequence(name,seq)",
           pDb->zDbSName
         );
       }
@@ -114802,7 +114800,7 @@ static void sqlite3ClearStatTables(
   const char *zDbName = pParse->db->aDb[iDb].zDbSName;
   for(i=1; i<=4; i++){
     char zTab[24];
-    sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
+    sqlite3_snprintf(sizeof(zTab),zTab,"sqlcipher_stat%d",i);
     if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
       sqlite3NestedParse(pParse,
         "DELETE FROM %Q.%s WHERE %s=%Q",
@@ -114851,7 +114849,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
   */
   if( pTab->tabFlags & TF_Autoincrement ){
     sqlite3NestedParse(pParse,
-      "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
+      "DELETE FROM %Q.sqlcipher_sequence WHERE name=%Q",
       pDb->zDbSName, pTab->zName
     );
   }
@@ -115488,7 +115486,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
     int n;
     Index *pLoop;
     for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
-    zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n);
+    zName = sqlite3MPrintf(db, "sqlcipher_autoindex_%s_%d", pTab->zName, n);
     if( zName==0 ){
       goto exit_create_index;
     }
@@ -118236,7 +118234,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
     u8 p5 = 0;
     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
     sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
-    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
+    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlcipher_stat1") ){
       sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
     }
     if( eMode!=ONEPASS_OFF ){
@@ -128819,7 +128817,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       if( pPragma->iArg==2 || pPragma->iArg==3 ){
         u8 iByte;
         int i;
-        for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){
+        for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){
           iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
           if( (i&1)!=0 ) zBuf[i/2] = iByte;
         }
@@ -139792,14 +139790,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
   */
   db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
   rc = execSqlF(db, pzErrMsg,
-      "SELECT sql FROM \"%w\".sqlite_master"
-      " WHERE type='table'AND name<>'sqlite_sequence'"
+      "SELECT sql FROM \"%w\".sqlcipher_master"
+      " WHERE type='table'AND name<>'sqlcipher_sequence'"
       " AND coalesce(rootpage,1)>0",
       zDbMain
   );
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
   rc = execSqlF(db, pzErrMsg,
-      "SELECT sql FROM \"%w\".sqlite_master"
+      "SELECT sql FROM \"%w\".sqlcipher_master"
       " WHERE type='index'",
       zDbMain
   );
@@ -139813,7 +139811,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
   rc = execSqlF(db, pzErrMsg,
       "SELECT'INSERT INTO vacuum_db.'||quote(name)"
       "||' SELECT*FROM\"%w\".'||quote(name)"
-      "FROM vacuum_db.sqlite_master "
+      "FROM vacuum_db.sqlcipher_master "
       "WHERE type='table'AND coalesce(rootpage,1)>0",
       zDbMain
   );
@@ -139827,8 +139825,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
   ** from the SQLITE_MASTER table.
   */
   rc = execSqlF(db, pzErrMsg,
-      "INSERT INTO vacuum_db.sqlite_master"
-      " SELECT*FROM \"%w\".sqlite_master"
+      "INSERT INTO vacuum_db.sqlcipher_master"
+      " SELECT*FROM \"%w\".sqlcipher_master"
       " WHERE type IN('view','trigger')"
       " OR(type='table'AND rootpage=0)",
       zDbMain
@@ -147602,7 +147600,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
     const char *zName;
     if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
-      if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
+      if( strncmp(zName, "sqlcipher_autoindex_", 20)==0 ){
         int i = sqlite3Strlen30(zName) - 1;
         while( zName[i]!='_' ) i--;
         zName += i;
@@ -163704,7 +163702,7 @@ SQLITE_PRIVATE int sqlite3CodecQueryParameters(
     u8 iByte;
     int i;
     char zDecoded[40];
-    for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
+    for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){
       iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
       if( (i&1)!=0 ) zDecoded[i/2] = iByte;
     }
@@ -190741,14 +190739,14 @@ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
 ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
 */
 static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
-  const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
+  const char *zFmt = "SELECT stat FROM %Q.sqlcipher_stat1 WHERE tbl = '%q_rowid'";
   char *zSql;
   sqlite3_stmt *p;
   int rc;
   i64 nRow = 0;
 
   rc = sqlite3_table_column_metadata(
-      db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
+      db, pRtree->zDb, "sqlcipher_stat1",0,0,0,0,0,0
   );
   if( rc!=SQLITE_OK ){
     pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
@@ -196094,7 +196092,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
   rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
     sqlite3_mprintf(
       "SELECT rbu_target_name(name, type='view') AS target, name "
-      "FROM sqlite_master "
+      "FROM sqlcipher_master "
       "WHERE type IN ('table', 'view') AND target IS NOT NULL "
       " %s "
       "ORDER BY name"
@@ -196103,7 +196101,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
   if( rc==SQLITE_OK ){
     rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
         "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
-        "  FROM main.sqlite_master "
+        "  FROM main.sqlcipher_master "
         "  WHERE type='index' AND tbl_name = ?"
     );
   }
@@ -196314,7 +196312,7 @@ static void rbuTableType(
   p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
     sqlite3_mprintf(
           "SELECT (sql LIKE 'create virtual%%'), rootpage"
-          "  FROM sqlite_master"
+          "  FROM sqlcipher_master"
           " WHERE name=%Q", zTab
   ));
   if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
@@ -196337,7 +196335,7 @@ static void rbuTableType(
     if( zOrig && zIdx && zOrig[0]=='p' ){
       p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
           sqlite3_mprintf(
-            "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+            "SELECT rootpage FROM sqlcipher_master WHERE name = %Q", zIdx
       ));
       if( p->rc==SQLITE_OK ){
         if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
@@ -197157,7 +197155,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
     ** This is needed for the argument to "PRAGMA index_xinfo". Set
     ** zIdx to point to a nul-terminated string containing this name. */
     p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
-        "SELECT name FROM sqlite_master WHERE rootpage = ?"
+        "SELECT name FROM sqlcipher_master WHERE rootpage = ?"
     );
     if( p->rc==SQLITE_OK ){
       sqlite3_bind_int(pQuery, 1, tnum);
@@ -197330,7 +197328,7 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
 
   if( rc==SQLITE_OK ){
     rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
-        "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
+        "SELECT trim(sql) FROM sqlcipher_master WHERE type='index' AND name=?"
     );
   }
   if( rc==SQLITE_OK ){
@@ -197912,7 +197910,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
       int bOk = 0;
       sqlite3_stmt *pCnt = 0;
       p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
-          "SELECT count(*) FROM stat.sqlite_master"
+          "SELECT count(*) FROM stat.sqlcipher_master"
       );
       if( p->rc==SQLITE_OK
        && sqlite3_step(pCnt)==SQLITE_ROW
@@ -198016,7 +198014,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
   if( p->rc==SQLITE_OK ){
     p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
   }
-  rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+  rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlcipher_master");
 
   /* Mark the database file just opened as an RBU target database. If
   ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
@@ -198109,7 +198107,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
   if( pState==0 ){
     p->eStage = 0;
     if( p->rc==SQLITE_OK ){
-      p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+      p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlcipher_master", 0, 0, 0);
     }
   }
 
@@ -198700,8 +198698,8 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
   p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
   if( p->rc==SQLITE_OK ){
     p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
-      "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
-      " AND name!='sqlite_sequence' "
+      "SELECT sql FROM sqlcipher_master WHERE sql!='' AND rootpage!=0"
+      " AND name!='sqlcipher_sequence' "
       " ORDER BY type DESC"
     );
   }
@@ -198715,13 +198713,13 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
 
   if( p->rc==SQLITE_OK ){
     p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
-        "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+        "SELECT * FROM sqlcipher_master WHERE rootpage=0 OR rootpage IS NULL"
     );
   }
 
   if( p->rc==SQLITE_OK ){
     p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
-        "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+        "INSERT INTO sqlcipher_master VALUES(?,?,?,?,?)"
     );
   }
 
@@ -198984,7 +198982,7 @@ static void rbuIndexCntFunc(
   assert( nVal==1 );
 
   rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
-      sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+      sqlite3_mprintf("SELECT count(*) FROM sqlcipher_master "
         "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
   );
   if( rc!=SQLITE_OK ){
@@ -199035,7 +199033,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
     ** occurs, nPhaseOneStep will be left set to -1. */
     if( p->rc==SQLITE_OK ){
       p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
-          "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+          "SELECT 1 FROM sqlcipher_master WHERE tbl_name = 'rbu_count'"
       );
     }
     if( p->rc==SQLITE_OK ){
@@ -201075,10 +201073,10 @@ static int statFilter(
   sqlite3_finalize(pCsr->pStmt);
   pCsr->pStmt = 0;
   zSql = sqlite3_mprintf(
-      "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+      "SELECT 'sqlcipher_master' AS name, 1 AS rootpage, 'table' AS type"
       "  UNION ALL  "
       "SELECT name, rootpage, type"
-      "  FROM \"%w\".sqlite_master WHERE rootpage!=0"
+      "  FROM \"%w\".sqlcipher_master WHERE rootpage!=0"
       "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName);
   if( zSql==0 ){
     return SQLITE_NOMEM_BKPT;
@@ -202585,7 +202583,7 @@ static int sessionTableInfo(
   assert( pazCol && pabPK );
 
   nThis = sqlite3Strlen30(zThis);
-  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
+  if( nThis==12 && 0==sqlite3_stricmp("sqlcipher_stat1", zThis) ){
     rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
     if( rc==SQLITE_OK ){
       /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
@@ -202693,7 +202691,7 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
           break;
         }
       }
-      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
+      if( 0==sqlite3_stricmp("sqlcipher_stat1", pTab->zName) ){
         pTab->bStat1 = 1;
       }
     }
@@ -203825,7 +203823,7 @@ static int sessionSelectStmt(
 
   if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
     zSql = sqlite3_mprintf(
-        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
+        "SELECT tbl, ?2, stat FROM %Q.sqlcipher_stat1 WHERE tbl IS ?1 AND "
         "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
     );
     if( zSql==0 ) rc = SQLITE_NOMEM;
@@ -205327,17 +205325,17 @@ static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
 ** other tables.
 */
 static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
-  int rc = sessionSelectRow(db, "sqlite_stat1", p);
+  int rc = sessionSelectRow(db, "sqlcipher_stat1", p);
   if( rc==SQLITE_OK ){
     rc = sessionPrepare(db, &p->pInsert,
-        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
+        "INSERT INTO main.sqlcipher_stat1 VALUES(?1, "
         "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
         "?3)"
     );
   }
   if( rc==SQLITE_OK ){
     rc = sessionPrepare(db, &p->pUpdate,
-        "UPDATE main.sqlite_stat1 SET "
+        "UPDATE main.sqlcipher_stat1 SET "
         "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
         "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
         "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
@@ -205348,7 +205346,7 @@ static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
   }
   if( rc==SQLITE_OK ){
     rc = sessionPrepare(db, &p->pDelete,
-        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
+        "DELETE FROM main.sqlcipher_stat1 WHERE tbl=?1 AND idx IS "
         "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
         "AND (?4 OR stat IS ?3)"
     );
@@ -206009,7 +206007,7 @@ static int sessionChangesetApply(
         }
         else{
           sApply.nCol = nCol;
-          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
+          if( 0==sqlite3_stricmp(zTab, "sqlcipher_stat1") ){
             if( (rc = sessionStat1Sql(db, &sApply) ) ){
               break;
             }
@@ -229578,6 +229576,7 @@ SQLITE_API int sqlite3_stmt_init(
 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
 /************************** End of sqlite3.c ******************************/
 
+#pragma GCC diagnostic pop
 /************** Begin file dbdump.c ********************************************/
 /*
 ** 2016-03-13
@@ -229625,9 +229624,6 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
 ** of the database file, the schema, and optionally the table, forming the
 ** first three arguments of a single call to the library routine.
 */
-#include "sqlite3.h"
-#include <stdarg.h>
-#include <string.h>
 #include <ctype.h>
 
 /*
@@ -229973,11 +229969,11 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
   zType = azArg[1];
   zSql = azArg[2];
 
-  if( strcmp(zTable, "sqlite_sequence")==0 ){
+  if( strcmp(zTable, "sqlcipher_sequence")==0 ){
     p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg);
-  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
+  }else if( sqlite3_strglob("sqlcipher_stat?", zTable)==0 ){
     p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
-  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+  }else if( strncmp(zTable, "sqlcipher_", 10)==0 ){
     return 0;
   }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
     if( !p->writableSchema ){
@@ -230014,7 +230010,12 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
 
     /* Always quote the table name, even if it appears to be pure ascii,
     ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
-    appendText(&sTable, zTable, quoteChar(zTable));
+    if (strncmp(zTable, "sqlcipher_", sizeof "sqlcipher"))
+      appendText(&sTable, zTable, quoteChar(zTable));
+    else {
+      appendText(&sTable, "sqlite_", 0);
+      appendText(&sTable, zTable + sizeof "sqlcipher", 0);
+    }
 
     /* If preserving the rowid, add a column list after the table name.
     ** In other words:  "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
@@ -230212,8 +230213,6 @@ static void run_schema_dump_query(
 */
 int sqlite3_db_dump(
   sqlite3 *db,               /* The database connection */
-  const char *zSchema,       /* Which schema to dump.  Usually "main". */
-  const char *zTable,        /* Which table to dump.  NULL means everything. */
   int (*xCallback)(const char*,void*),   /* Output sent to this callback */
   void *pArg                             /* Second argument of the callback */
 ){
@@ -230225,40 +230224,68 @@ int sqlite3_db_dump(
   x.xCallback = xCallback;
   x.pArg = pArg;
   xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg);
-  if( zTable==0 ){
-    run_schema_dump_query(&x,
-      "SELECT name, type, sql FROM \"%w\".sqlite_master "
-      "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
-      zSchema
-    );
-    run_schema_dump_query(&x,
-      "SELECT name, type, sql FROM \"%w\".sqlite_master "
-      "WHERE name=='sqlite_sequence'", zSchema
-    );
-    output_sql_from_query(&x,
-      "SELECT sql FROM sqlite_master "
-      "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
-    );
-  }else{
-    run_schema_dump_query(&x,
-      "SELECT name, type, sql FROM \"%w\".sqlite_master "
-      "WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
-      "  AND sql NOT NULL",
-      zSchema, zTable
-    );
-    output_sql_from_query(&x,
-      "SELECT sql FROM \"%w\".sqlite_master "
-      "WHERE sql NOT NULL"
-      "  AND type IN ('index','trigger','view')"
-      "  AND tbl_name=%Q COLLATE nocase",
-      zSchema, zTable
-    );
-  }
+  run_schema_dump_query(&x,
+    "SELECT name, type, sql FROM sqlcipher_master "
+    "WHERE sql NOT NULL AND type=='table' AND name!='sqlcipher_sequence'"
+  );
+  run_schema_dump_query(&x,
+    "SELECT name, type, sql FROM sqlcipher_master "
+    "WHERE name=='sqlcipher_sequence'"
+  );
+  output_sql_from_query(&x,
+    "SELECT sql FROM sqlcipher_master "
+    "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
+  );
   if( x.writableSchema ){
     xCallback("PRAGMA writable_schema=OFF;\n", pArg);
   }
   xCallback(x.nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n", pArg);
   sqlite3_exec(db, "COMMIT", 0, 0, 0);
-  return x.rc;
+  return x.rc ?: x.nErr ? SQLITE_ERROR : SQLITE_OK;
 }
 /************** End of dbdump.c ************************************************/
+
+struct Out {
+  size_t reserved, empty;
+  char *p;
+};
+
+static int ssout(const char *s, void *p) {
+  struct Out *out = (struct Out *)p;
+  const size_t len = strlen(s);
+  if (len >= out->empty) {
+    const size_t expandby = out->reserved + len;
+    out->empty += expandby;
+    out->reserved += expandby;
+    char *p = (char *)realloc(out->p, out->reserved);
+    if (!p)
+      return EOF;
+    out->p = p;
+  }
+  memcpy(out->p + (out->reserved - out->empty), s, len);
+  out->empty -= len;
+  return 0;
+}
+
+__attribute__((visibility("default"))) char *dumpLegacyDb(const char *dbPath, const unsigned char *pass, size_t passSize) {
+  struct Out out;
+  out.reserved = out.empty = 1 << 12;
+  out.p = (char *)malloc(out.reserved);
+  if (!out.p)
+    return NULL;
+
+
+  sqlite3 *db;
+  int rc = sqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, 0);
+
+  if (!rc && !(rc = sqlite3_key(db, pass, passSize)) && !(rc = sqlite3_exec(db, "PRAGMA cipher_compatibility=2", 0, 0, 0)))
+    rc = sqlite3_db_dump(db, ssout, (void*)&out);
+  sqlite3_close(db);
+
+  if (rc) {
+    free(out.p);
+    return NULL;
+  }
+  out.p[out.reserved - out.empty] = '\0';
+  return out.p;
+}
index 40cd751..27078e4 100644 (file)
@@ -20,7 +20,8 @@ SET(KEY_MANAGER_PATH ${PROJECT_SOURCE_DIR}/src/manager)
 PKG_CHECK_MODULES(ENCRYPTION_SCHEME_DEP
     REQUIRED
     openssl1.1
-    libsmack)
+    libsmack
+    sqlcipher)
 
 SET(ENCRYPTION_SCHEME_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/encryption-scheme/smack-access.cpp
@@ -33,7 +34,6 @@ SET(ENCRYPTION_SCHEME_SOURCES
     ${KEY_MANAGER_PATH}/service/file-system.cpp
     ${KEY_MANAGER_PATH}/service/for-each-file.cpp
     ${KEY_MANAGER_PATH}/service/key-provider.cpp
-    ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
 )
 
 INCLUDE_DIRECTORIES(SYSTEM ${ENCRYPTION_SCHEME_DEP_INCLUDE_DIRS})
@@ -44,7 +44,6 @@ INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_PATH}/dpl/core/include
     ${KEY_MANAGER_PATH}/dpl/log/include
     ${KEY_MANAGER_PATH}/dpl/db/include
-    ${KEY_MANAGER_PATH}/sqlcipher
     ${KEY_MANAGER_PATH}/service
     ${KEY_MANAGER_PATH}/crypto
 )
@@ -84,7 +83,6 @@ INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_PATH}/dpl/db/include
     ${KEY_MANAGER_PATH}/dpl/core/include
     ${KEY_MANAGER_PATH}/dpl/log/include
-    ${KEY_MANAGER_PATH}/sqlcipher
     ${KEY_MANAGER_PATH}/service
     ${KEY_MANAGER_PATH}/initial-values
     ${KEY_MANAGER_PATH}/main
@@ -203,6 +201,7 @@ INSTALL(
         resources/testme_ver1.db
         resources/testme_ver2.db
         resources/testme_ver3.db
+        resources/testme0_ver4.db
     DESTINATION ${DB_TEST_DIR}
     )
 
index 67241c5..da73dfe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
  *
  *  Contact: Kyungwook Tak <k.tak@samsung.com>
  *
 using namespace CKM;
 using namespace std::chrono;
 
+static void copyFile(const char *src, const char *dst)
+{
+       std::ifstream f1(src, std::fstream::binary);
+       std::ofstream f2(dst, std::fstream::trunc | std::fstream::binary);
+       f2 << f1.rdbuf();
+       f2.close();
+       f1.close();
+       BOOST_REQUIRE(f1);
+       BOOST_REQUIRE(f2);
+}
+
+void DBFixture::unlinkDb()
+{
+       for (const auto f : {m_crypto_legacy_db_fname, m_crypto_db_fname})
+               BOOST_REQUIRE_MESSAGE(!unlink(f) || errno == ENOENT, "unlink " << f);
+}
 
-DBFixture::DBFixture()
+DBFixture::DBFixture(DBCryptoThrows dbCryptoThrows)
 {
-       BOOST_CHECK(unlink(m_crypto_db_fname) == 0 || errno == ENOENT);
-       init();
+       unlinkDb();
+       init(dbCryptoThrows);
 }
-DBFixture::DBFixture(const char *db_fname)
+DBFixture::DBFixture(const char *legacy_db_fname, const char *db_fname, DBCryptoThrows dbCryptoThrows)
 {
-       BOOST_CHECK(unlink(m_crypto_db_fname) == 0 || errno == ENOENT);
+       BOOST_REQUIRE(legacy_db_fname || db_fname);
+       unlinkDb();
 
-       // copy file
-       std::ifstream f1(db_fname, std::fstream::binary);
-       std::ofstream f2(m_crypto_db_fname, std::fstream::trunc | std::fstream::binary);
-       f2 << f1.rdbuf();
-       f2.close();
-       f1.close();
+       if (legacy_db_fname)
+               copyFile(legacy_db_fname, m_crypto_legacy_db_fname);
+       if (db_fname)
+               copyFile(db_fname, m_crypto_db_fname);
 
-       init();
+       init(dbCryptoThrows);
 }
 
-void DBFixture::init()
+void DBFixture::init(DBCryptoThrows dbCryptoThrows)
 {
        high_resolution_clock::time_point srand_feed = high_resolution_clock::now();
        srand(srand_feed.time_since_epoch().count());
 
-       BOOST_REQUIRE_NO_THROW(m_db = DB::Crypto(m_crypto_db_fname, defaultPass));
+       switch (dbCryptoThrows) {
+               case DBCryptoThrows::yes:
+                       BOOST_REQUIRE_THROW(m_db = DB::Crypto(m_crypto_legacy_db_fname, m_crypto_db_fname, defaultPass), Exc::DatabaseFailed);
+                       break;
+               case DBCryptoThrows::no:
+                       BOOST_REQUIRE_NO_THROW(m_db = DB::Crypto(m_crypto_legacy_db_fname, m_crypto_db_fname, defaultPass));
+                       BOOST_REQUIRE(access(m_crypto_legacy_db_fname, F_OK) && ENOENT == errno);
+       }
 }
 
 double DBFixture::performance_get_time_elapsed_ms()
index 9efb330..fd2381c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016-2019 Samsung Electronics Co., Ltd. All rights reserved
+ *  Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
  *
  *  Contact: Kyungwook Tak <k.tak@samsung.com>
  *
 
 class DBFixture {
 public:
-       DBFixture();
-       explicit DBFixture(const char *db_fname);
+       enum class DBCryptoThrows : bool { no, yes };
+       DBFixture(DBCryptoThrows dbCryptoThrows = DBCryptoThrows::no);
+       explicit DBFixture(const char *legacy_db_fname, const char *db_fname,
+                                          DBCryptoThrows dbCryptoThrows = DBCryptoThrows::no);
 
        constexpr static const char *m_default_name = "name";
        constexpr static const char *m_default_owner = "label";
@@ -65,10 +67,12 @@ public:
        CKM::DB::Crypto    m_db;
 
 private:
-       void    init();
+       void    init(DBCryptoThrows dbCryptoThrows);
        double  performance_get_time_elapsed_ms();
+       static void unlinkDb();
 
-       constexpr static const char *m_crypto_db_fname = "/tmp/testme.db";
+       constexpr static const char *m_crypto_legacy_db_fname = "/tmp/testme.db";
+       constexpr static const char *m_crypto_db_fname = "/tmp/testme0.db";
        std::string m_operation;
        std::chrono::high_resolution_clock::time_point m_start_time, m_end_time;
 };
index 04319a2..bfaaef9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015-2020 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.
@@ -818,10 +818,10 @@ size_t SchemeTest::CountObjects()
 
 void SchemeTest::RestoreDb()
 {
+       m_db.reset();
        restoreFile("key-7654");
        restoreFile("db-key-7654");
        restoreFile("db-7654");
-       m_db.reset();
        m_directAccessEnabled = false;
 }
 
@@ -863,8 +863,15 @@ void SchemeTest::EnableDirectDbAccess()
        auto wrappedDatabaseDEK = fs.getDBDEK();
        RawBuffer key = keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-       m_db.reset(new DB::Crypto(fs.getDBPath(), key));
+       m_db.reset(new DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key));
        m_directAccessEnabled = true;
+
+       // Legacy db files of the form db-$uid are incompatible with upstream sqlcipher.
+       // DB::Crypto(...) converts them to db0-$uid upstream-compatible, then deletes them.
+       // This function runs DB::Crypto(...) as root so db0-$uid are root-owned.
+       // However, database files need to be accessible to USER_NAME/GROUP_NAME (ex. ReadAll()).
+       // Thus the need to fix up ownership, much like restoreFile() does.
+       BOOST_REQUIRE(!chown(RW_DATA_DIR "/db0-7654", getUid(USER_NAME), getGid(GROUP_NAME)));
 }
 
 void SchemeTest::SignVerifyItem(const Item &itemPrv, const Item &itemPub)
diff --git a/tests/resources/testme0_ver4.db b/tests/resources/testme0_ver4.db
new file mode 100644 (file)
index 0000000..b409035
Binary files /dev/null and b/tests/resources/testme0_ver4.db differ
index 68b01b4..5ed8d5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
  *
  *  Contact: Kyungwook Tak <k.tak@samsung.com>
  *
@@ -305,35 +305,54 @@ void verifyDBisValid(DBFixture &fixture)
        }
 }
 
-struct DBVer1Migration : public DBFixture {
-       DBVer1Migration() : DBFixture(DB_TEST_DIR "/testme_ver1.db") {}
-};
-
-struct DBVer2Migration : public DBFixture {
-       DBVer2Migration() : DBFixture(DB_TEST_DIR "/testme_ver2.db") {}
-};
-
-struct DBVer3Migration : public DBFixture {
-       DBVer3Migration() : DBFixture(DB_TEST_DIR "/testme_ver3.db") {}
-};
+void verifyDBisValid(const char *legacyDb, const char *db)
+{
+       DBFixture DB(legacyDb, db);
+       verifyDBisValid(DB);
+}
 }
 
 POSITIVE_TEST_CASE(DBMigrationDBVer1)
 {
-       DBVer1Migration DBver1;
-       verifyDBisValid(DBver1);
+       verifyDBisValid(DB_TEST_DIR "/testme_ver1.db", nullptr);
 }
 
 POSITIVE_TEST_CASE(DBMigrationDBVer2)
 {
-       DBVer2Migration DBver2;
-       verifyDBisValid(DBver2);
+       verifyDBisValid(DB_TEST_DIR "/testme_ver2.db", nullptr);
 }
 
 POSITIVE_TEST_CASE(DBMigrationDBVer3)
 {
-       DBVer3Migration DBver3;
-       verifyDBisValid(DBver3);
+       verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", nullptr);
+}
+
+POSITIVE_TEST_CASE(DBMigrationDBVer3UncleanBoot)
+{
+       verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", DB_TEST_DIR "/testme_ver3.db");
+}
+
+POSITIVE_TEST_CASE(DB0MigrationDBVer4)
+{
+       verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver4.db");
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalid)
+{
+       DBFixture(DB_TEST_DIR "/testme0_ver4.db", nullptr,
+                       DBFixture::DBCryptoThrows::yes);
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalidUncleanBoot)
+{
+       DBFixture(DB_TEST_DIR "/testme0_ver4.db", DB_TEST_DIR "/testme_ver3.db",
+                       DBFixture::DBCryptoThrows::yes);
+}
+
+NEGATIVE_TEST_CASE(DBMigrationInvalid0)
+{
+       DBFixture(nullptr, DB_TEST_DIR "/testme_ver3.db",
+                       DBFixture::DBCryptoThrows::yes);
 }
 
 POSITIVE_TEST_CASE(DBMigrationDBCurrent)
index 7833c67..e282e79 100644 (file)
@@ -18,6 +18,7 @@ PKG_CHECK_MODULES(CKM_DB_TOOL_DEP
     cynara-client-async
     cynara-creds-socket
     security-manager
+    sqlcipher
     ${CKM_DB_TOOL_EXTRA_DEP}
     )
 
@@ -30,7 +31,6 @@ INCLUDE_DIRECTORIES(
     ${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
@@ -77,7 +77,6 @@ SET(CKM_DB_TOOLS_SOURCES
     ${KEY_MANAGER_PATH}/service/ss-migrate.cpp
     ${KEY_MANAGER_PATH}/service/ss-crypto.cpp
     ${KEY_MANAGER_PATH}/service/permission.cpp
-    ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
     )
 
 IF(TZ_BACKEND_ENABLED)
index 00a4756..66f3188 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000-2020 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,17 +33,17 @@ 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_%' "
+const char *const SQL_TABLES = "SELECT name FROM sqlite_master "
+                                                          "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
                                                           "UNION ALL "
-                                                          "SELECT name FROM sqlcipher_temp_master "
+                                                          "SELECT name FROM sqlite_temp_master "
                                                           "WHERE type IN ('table','view') "
                                                           "ORDER BY 1";
 
 const char *const SQL_SCHEMA = "SELECT sql FROM "
-                                                          "(SELECT * FROM sqlcipher_master "
+                                                          "(SELECT * FROM sqlite_master "
                                                           "UNION ALL "
-                                                          "SELECT * FROM sqlcipher_temp_master) "
+                                                          "SELECT * FROM sqlite_temp_master) "
                                                           "WHERE type!='meta' AND sql!='NULL'"
                                                           "ORDER BY tbl_name, type DESC, name";
 } // anonymous namespace