Replace libcryptsetup usage with /usr/sbin/cryptsetup calls 21/142621/5 submit/tizen/20170822.052357
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Mon, 7 Aug 2017 17:01:34 +0000 (19:01 +0200)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Wed, 16 Aug 2017 15:29:04 +0000 (17:29 +0200)
Change-Id: Ieedae7a30a6db706cdac674a55abf8ca3baf631c

CMakeLists.txt
packaging/ode.spec
server/CMakeLists.txt
server/engine/encryption/cryptsetup-engine.cpp
server/engine/encryption/dummy_password [new file with mode: 0644]

index 6cad5c9..f0e4e94 100755 (executable)
@@ -73,6 +73,10 @@ IF(NOT DEFINED HOME_DIR)
        SET(HOME_DIR "/home")
 ENDIF(NOT DEFINED HOME_DIR)
 
+IF(NOT DEFINED DATA_DIR)
+       SET(DATA_DIR "${SHARE_INSTALL_PREFIX}")
+ENDIF(NOT DEFINED DATA_DIR)
+
 IF(NOT DEFINED PAMD_DIR)
        SET(PAMD_DIR "${SYSCONF_INSTALL_DIR}/pam.d")
 ENDIF(NOT DEFINED PAMD_DIR)
index b1d1595..b8b6423 100755 (executable)
@@ -19,7 +19,7 @@ BuildRequires: pkgconfig(key-manager)
 BuildRequires: pkgconfig(cynara-client)
 BuildRequires: pkgconfig(cynara-session)
 BuildRequires: pkgconfig(openssl)
-BuildRequires: pkgconfig(libcryptsetup)
+Requires: cryptsetup
 
 %description
 The ode package provides a daemon which is responsible for encrypting/decryption storages and secure erasing.
@@ -35,6 +35,7 @@ The ode package provides a daemon which is responsible for encrypting/decryption
 %{_unitdir}/ode-mount-external.service
 %{_unitdir}/multi-user.target.wants/ode-mount-external.path
 %attr(700,root,root) %{_sbindir}/ode-admin-cli
+%{_datadir}/%{name}
 
 %prep
 %setup -q
index e72b8ca..1ef12b9 100644 (file)
@@ -46,7 +46,6 @@ SET(DEPENDENCY        klay
                                cynara-client
                                cynara-session
                                openssl
-                               libcryptsetup
 )
 
 SET(SERVER_NAME ${PROJECT_NAME}d)
@@ -74,3 +73,4 @@ INSTALL(TARGETS ${SERVER_NAME} DESTINATION ${BIN_DIR})
 INSTALL(FILES systemd/${PROJECT_NAME}.service DESTINATION ${SYSTEMD_UNIT_DIR})
 INSTALL(FILES systemd/${PROJECT_NAME}-mount-external.path DESTINATION ${SYSTEMD_UNIT_DIR})
 INSTALL(FILES systemd/${PROJECT_NAME}-mount-external.service DESTINATION ${SYSTEMD_UNIT_DIR})
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/engine/encryption/dummy_password DESTINATION ${DATA_DIR}/${PROJECT_NAME}/)
index 9c35f48..5ad0f39 100644 (file)
 #include "../../file-footer.h"
 #include "../../logger.h"
 
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+
 #include <cctype>
 #include <algorithm>
 
-#include <libcryptsetup.h>
-
 #include <klay/exception.h>
 
 namespace ode {
 
 namespace {
 
-const char* DEFAULT_LUKS_CIPHER_NAME = "aes";
-const char* DEFAULT_LUKS_CIPHER_MODE = "xts-plain64";
-const char* DEFAULT_LUKS_HASH = "sha1";
-const size_t DEFAULT_LUKS_ALIGNMENT = 0;
+std::string mappingPath(const std::string& name)
+{
+       static std::string mappings_dir = "/dev/mapper/";
+       return mappings_dir + name;
+}
 
-#ifndef NDEBUG
-// log callback
-void log(int level, const char *msg, void*)
+void forkAndWrite(const char *const* argv, const CryptsetupEngine::data *d)
 {
-       std::string msgStr("[NULL]");
-       if (msg) {
-               msgStr = msg;
-
-               // trim it
-               auto it = find_if_not(msgStr.rbegin(),
-                                                         msgStr.rend(),
-                                                         [](char c){ return isspace(c); }).base();
-               msgStr.erase(it, msgStr.end());
+       // pipe
+       int pipefd[2];
+       if (d != NULL) {
+               if (0 != pipe(pipefd))
+                       throw runtime::Exception("pipe() failed:" + std::to_string(errno));
        }
 
-       switch (level)
-       {
-       case CRYPT_LOG_ERROR:
-               ERROR(SINK, "[libcryptsetup] " + msgStr);
-               break;
-       case CRYPT_LOG_VERBOSE:
-               INFO(SINK, "[libcryptsetup] " + msgStr);
-               break;
-       case CRYPT_LOG_DEBUG:
-       case CRYPT_LOG_NORMAL:
-               DEBUG(SINK, "[libcryptsetup] " + msgStr);
-               break;
-       default:
-               ERROR(SINK, "[libcryptsetup] Unsupported log level. Msg: " + msgStr);
-       }
-}
-#endif
+       pid_t pid = ::fork();
+       if (pid == -1)
+               throw runtime::Exception("fork() failed: " + std::to_string(errno));
 
-class Device
-{
-public:
-       enum class InitMethod
-       {
-               BY_DEV_PATH, // requires device path as first ctor argument
-               BY_MAP_NAME, // requires mapping name as first ctor argument
-       };
+       if (pid == 0) {
+               if (d != NULL) {
+                       ::close(pipefd[1]);
 
-       explicit Device(const std::string &str, InitMethod method = InitMethod::BY_DEV_PATH)
-       {
-               int ret;
-               if (str.empty())
-                       throw runtime::Exception("Empty argument");
-
-               switch (method) {
-               case InitMethod::BY_DEV_PATH:
-                       ret = crypt_init(&device, str.c_str());
-                       if (ret != 0)
-                               throw runtime::Exception("crypt_init() failed for " + str + ": "
-                                                                                + std::to_string(ret));
-                       break;
-               case InitMethod::BY_MAP_NAME:
-                       ret = crypt_init_by_name(&device, str.c_str());
-                       if (ret != 0)
-                               throw runtime::Exception("crypt_init_by_name() failed for " +
-                                                                                str + ": " + std::to_string(ret));
-                       break;
-               default:
-                       throw runtime::Exception("Unsupported init method " +
-                                                                        std::to_string(static_cast<int>(method)));
+                       int fd = TEMP_FAILURE_RETRY(dup2(pipefd[0], STDIN_FILENO));
+                       if (fd == -1)
+                               exit(EXIT_FAILURE);
+
+                       ::close(pipefd[0]);
                }
 
-#ifndef NDEBUG
-               /*
-                * This option causes debug logs to be printed to STDOUT. TODO execute it
-                * once for all engines?
-                */
-               crypt_set_debug_level(CRYPT_DEBUG_ALL);
-               crypt_set_log_callback(device, &log, NULL);
-#endif
-
-               // Needs root
-               if (1 != crypt_memory_lock(device, 1))
-                       throw runtime::Exception("Failed to lock memory");
+               ::execv(argv[0], const_cast<char *const*>(argv));
+               ::exit(EXIT_FAILURE);
        }
 
-       Device(const Device&) = delete;
-       Device& operator=(const Device&) = delete;
+       if (d != NULL) {
+               ::close(pipefd[0]);
 
-       ~Device()
-       {
-               if (0 != crypt_memory_lock(device, 0))
-               ERROR(SINK, "Failed to unlock memory");
+               // write the pipefd[1]
+               ssize_t ret = TEMP_FAILURE_RETRY(write(pipefd[1], d->data(), d->size()));
+               if (ret < 0 || (size_t)ret != d->size())
+                       throw runtime::Exception("write() failed");
 
-               crypt_free(device);
+               ::close(pipefd[1]);
        }
 
-       crypt_device* get() noexcept { return device; }
-
-private:
-       crypt_device *device;
-};
-
-std::string mappingPath(const std::string& name)
-{
-       static std::string mappings_dir = std::string(crypt_get_dir()) + '/';
-       return mappings_dir + name;
+       int status;
+       while (::waitpid(pid, &status, 0) == -1) {
+               if (errno != EINTR) {
+                       throw runtime::Exception("waitpid() failed: " + std::to_string(errno));
+               }
+       }
 }
 
 } // anonymous namespace
@@ -153,28 +102,33 @@ void CryptsetupEngine::format(DeviceType type, const data &key)
 {
        switch (type) {
        case DeviceType::LUKS:
-               {
-                       Device d(devPath);
-
-                       // TODO support other formats? support other ciphers?
-                       crypt_params_luks1 params = {
-                                       .hash = DEFAULT_LUKS_HASH,
-                                       .data_alignment = DEFAULT_LUKS_ALIGNMENT,
-                                       .data_device = NULL,
-                       };
-
-                       int ret = crypt_format(d.get(),
-                                                                  CRYPT_LUKS1,
-                                                                  DEFAULT_LUKS_CIPHER_NAME,
-                                                                  DEFAULT_LUKS_CIPHER_MODE,
-                                                                  NULL,        // NULL uid
-                                                                  reinterpret_cast<const char*>(key.data()),
-                                                                  key.size(),
-                                                                  &params);
-                       if (ret != 0)
-                               throw runtime::Exception("crypt_format() failed: " + std::to_string(ret));
-                       break;
-               }
+       {
+               // format
+               const char *const argv1[] = {
+                       "/usr/sbin/cryptsetup",
+                       "-q",
+                       "luksFormat",
+                       devPath.c_str(),
+                       "--key-size=512",
+                       "--master-key-file=/dev/stdin",
+                       "--key-file=/usr/share/dummy_password",
+                       NULL
+               };
+
+               forkAndWrite(argv1, &key);
+
+               // remove the key slot
+               const char *const argv2[] = {
+                       "/usr/sbin/cryptsetup",
+                       "-q",
+                       "erase",
+                       NULL
+               };
+
+               forkAndWrite(argv2, NULL);
+
+               break;
+       }
        case DeviceType::PLAIN:
                // TODO
        default:
@@ -189,20 +143,17 @@ std::string CryptsetupEngine::open(DeviceType type, const std::string &name, con
        switch (type) {
        case DeviceType::LUKS:
        {
-               Device d(devPath);
-               int ret = crypt_load(d.get(), CRYPT_LUKS1, NULL);
-               if (ret != 0)
-                       throw runtime::Exception("crypt_load() failed: " + std::to_string(ret));
-
-               // TODO possible support for activation flags
-               ret = crypt_activate_by_volume_key(d.get(),
-                                                                                  name.c_str(),
-                                                                                  reinterpret_cast<const char*>(key.data()),
-                                                                                  key.size(),
-                                                                                  0);
-               if (ret != 0)
-                       throw runtime::Exception("crypt_activate_by_volume_key() failed: " +
-                                                                        std::to_string(ret));
+               const char *const argv[] = {
+                       "/usr/sbin/cryptsetup",
+                       "open",
+                       devPath.c_str(),
+                       name.c_str(),
+                       "--master-key-file=/dev/stdin",
+                       NULL
+               };
+
+               forkAndWrite(argv, &key);
+
                break;
        }
 
@@ -217,12 +168,14 @@ std::string CryptsetupEngine::open(DeviceType type, const std::string &name, con
 
 void CryptsetupEngine::close(const std::string &name)
 {
-       Device d(name, Device::InitMethod::BY_MAP_NAME);
+       const char *const argv[] = {
+               "/usr/sbin/cryptsetup",
+               "close",
+               name.c_str(),
+               NULL
+       };
 
-       int ret = crypt_deactivate(d.get(), name.c_str());
-       if (ret != 0)
-               throw runtime::Exception("crypt_deactivate() failed for " + name +
-                                                                ": " + std::to_string(ret));
+       forkAndWrite(argv, NULL);
 }
 
 bool CryptsetupEngine::isKeyMetaSet()
diff --git a/server/engine/encryption/dummy_password b/server/engine/encryption/dummy_password
new file mode 100644 (file)
index 0000000..2fcf419
--- /dev/null
@@ -0,0 +1 @@
+dummy_password
\ No newline at end of file