Enable socket activation
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 30 May 2019 11:45:45 +0000 (13:45 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 2 Aug 2019 11:42:28 +0000 (13:42 +0200)
Enable oded socket activation. Stop service after ~5s of inactivity. Do
not stop the service if it was started manually and no request has
arrived.

Change-Id: I4d65b278df314b3e16453ab0e1e521b3e80e58e7

16 files changed:
CMakeLists.txt
lib/client.cpp
packaging/ode.spec
server/CMakeLists.txt
server/external-encryption.cpp
server/external-encryption.h
server/internal-encryption.cpp
server/internal-encryption.h
server/key-server.cpp
server/luks.cpp
server/main.cpp
server/secure-erase.cpp
server/server.cpp
server/server.h
server/systemd/ode.service.in
server/systemd/ode.socket.in [new file with mode: 0644]

index 620abf2..cb00110 100755 (executable)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2015-2019 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.
@@ -100,12 +100,17 @@ IF(NOT DEFINED KEY_STORAGE_PLUGIN_DIR)
        SET(KEY_STORAGE_PLUGIN_DIR "${CMAKE_INSTALL_LIBDIR}/ode-key-storage-plugin")
 ENDIF(NOT DEFINED KEY_STORAGE_PLUGIN_DIR)
 
+IF(NOT DEFINED SOCKET_PATH)
+       SET(SOCKET_PATH "${RUN_DIR}/.ode.sock")
+ENDIF(NOT DEFINED SOCKET_PATH)
+
 SET(KEY_STORAGE_PLUGIN "key-storage-plugin")
 
 ADD_DEFINITIONS(-DKEY_STORAGE_PLUGIN_DIR="${KEY_STORAGE_PLUGIN_DIR}")
 ADD_DEFINITIONS(-DKEY_STORAGE_PLUGIN_LIB="${CMAKE_SHARED_LIBRARY_PREFIX}${KEY_STORAGE_PLUGIN}${CMAKE_SHARED_LIBRARY_SUFFIX}")
 
 ADD_DEFINITIONS(-DUG_WAYLAND)
+ADD_DEFINITIONS(-DSOCKET_PATH="${SOCKET_PATH}")
 
 ADD_SUBDIRECTORY(${ODE_LIB})
 ADD_SUBDIRECTORY(${ODE_KEY_STORAGE_PLUGIN})
index 55ed3c9..435f293 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015-2019 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 #include "client.h"
 
-namespace {
-
-const std::string ODE_MANAGER_ADDRESS = "/tmp/.ode.sock";
-
-} // namespace
-
-
 ClientContext::ClientContext() noexcept
 {
 }
@@ -46,7 +39,7 @@ int ClientContext::connect(const std::string& address) noexcept
 
 int ClientContext::connect() noexcept
 {
-       return connect(ODE_MANAGER_ADDRESS);
+       return connect(SOCKET_PATH);
 }
 
 void ClientContext::disconnect() noexcept
index 351bb21..39b5288 100755 (executable)
@@ -27,6 +27,7 @@ Requires: cryptsetup
 %global key_storage_plugin_dir %{_libdir}/ode-key-storage-plugin/
 %global softreset_dir /usr/system/RestoreDir/softreset/
 %define upgrade_script_dir /usr/share/upgrade/scripts/
+%global socket_path %{TZ_SYS_RUN}/.ode.sock
 
 %description
 The ode package provides a daemon which is responsible for encrypting/decryption storages and secure erasing.
@@ -36,7 +37,7 @@ The ode package provides a daemon which is responsible for encrypting/decryption
 %defattr(644,root,root,755)
 %attr(755,root,root) %{_bindir}/oded
 %{_unitdir}/ode.service
-%{_unitdir}/multi-user.target.wants/ode.service
+%{_unitdir}/ode.socket
 %attr(700,root,root) %{TZ_SYS_SBIN}/ode-admin-cli
 %attr(700,root,root) %{softreset_dir}/ode_softreset.sh
 %attr(750,root,system_share) %{TZ_SYS_SBIN}/ode-fota
@@ -65,35 +66,42 @@ The ode package provides a daemon which is responsible for encrypting/decryption
          -DAPP_SHARE_PACKAGES_DIR="%{TZ_SYS_RO_PACKAGES}" \
          -DSOFTRESET_DIR="%{softreset_dir}" \
          -DKEY_STORAGE_PLUGIN_DIR="%{key_storage_plugin_dir}" \
-         -DUPGRADE_SCRIPT_DIR="%{upgrade_script_dir}"
+         -DUPGRADE_SCRIPT_DIR="%{upgrade_script_dir}" \
+         -DSOCKET_PATH="%{socket_path}"
 
 make %{?jobs:-j%jobs}
 
 %install
 %make_install
-%install_service multi-user.target.wants ode.service
 
 %clean
 rm -rf %{buildroot}
 
+%pre
+if [ $1 = 2 ]; then
+    # upgrade
+    systemctl stop ode.service
+fi
+
 %post
-systemctl daemon-reload
+systemctl enable ode.socket
 if [ $1 = 1 ]; then
     # installation
-    systemctl start ode.service
+    systemctl start ode.socket
 elif [ $1 = 2 ]; then
     # update
-    systemctl restart ode.service
+    systemctl daemon-reload
+    systemctl restart ode.socket
 fi
 
 %preun
 if [ $1 = 0 ]; then
-    # unistall
+    # uninstall
+    systemctl disable ode.socket
+    systemctl stop ode.socket
     systemctl stop ode.service
 fi
 
-%postun
-
 ## ODE Client Package ########################################################
 %package -n libode
 Summary: Library for Tizen device encryption and secure erase
index a88ddcb..dd8e68e 100644 (file)
@@ -75,8 +75,9 @@ TARGET_COMPILE_DEFINITIONS(${SERVER_NAME} PRIVATE
 )
 
 CONFIGURE_FILE(systemd/${PROJECT_NAME}.service.in systemd/${PROJECT_NAME}.service)
+CONFIGURE_FILE(systemd/${PROJECT_NAME}.socket.in systemd/${PROJECT_NAME}.socket)
 
 INSTALL(TARGETS ${SERVER_NAME} DESTINATION ${BIN_DIR})
-INSTALL(FILES systemd/${PROJECT_NAME}.service DESTINATION ${SYSTEMD_UNIT_DIR})
+INSTALL(FILES systemd/${PROJECT_NAME}.service systemd/${PROJECT_NAME}.socket DESTINATION ${SYSTEMD_UNIT_DIR})
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/engine/encryption/dummy_password DESTINATION ${PROJECT_DATA_DIR})
 INSTALL(DIRECTORY DESTINATION ${KEY_STORAGE_PLUGIN_DIR})
index 82f9f30..d2f129a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -222,11 +222,15 @@ ExternalEncryptionServer::~ExternalEncryptionServer()
 
 int ExternalEncryptionServer::setMountPassword(const std::string& password)
 {
+       RequestLifetime rl(server);
+
        return keyServer.get(engine->getSource(), password, mountKey);
 }
 
 int ExternalEncryptionServer::mount()
 {
+       RequestLifetime rl(server);
+
        if (mountKey.empty()) {
                ERROR(SINK, "You need to call set_mount_password() first.");
                return error::NoData;
@@ -235,7 +239,7 @@ int ExternalEncryptionServer::mount()
        BinaryData key = mountKey;
        mountKey.clear();
 
-       if (getState() != State::Encrypted) {
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot mount, SD card's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -260,7 +264,9 @@ int ExternalEncryptionServer::mount()
 
 int ExternalEncryptionServer::umount()
 {
-       if (getState() != State::Encrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot umount, SD card's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -286,7 +292,9 @@ int ExternalEncryptionServer::umount()
 
 int ExternalEncryptionServer::encrypt(const std::string &password, unsigned int options)
 {
-       if (getState() != State::Unencrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Unencrypted) {
                INFO(SINK, "Cannot encrypt, SD card's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -296,14 +304,14 @@ int ExternalEncryptionServer::encrypt(const std::string &password, unsigned int
        if (ret != error::None)
                return ret;
 
-       auto encryptWorker = [masterKey, options, this]() {
+       auto encryptWorker = [masterKey, options, this](RequestLifetime&& rl) {
                try {
                        INFO(SINK, "Closing all applications using external storage.");
                        killDependentApplications(EXTERNAL_PATH);
 
                        INFO(SINK, "Encryption started.");
                        engine->encrypt(masterKey, options);
-                       setOptions(options & getSupportedOptions());
+                       setOptions(options & engine->getSupportedOptions());
 
                        INFO(SINK, "Encryption completed.");
                        ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "encrypted");
@@ -317,7 +325,7 @@ int ExternalEncryptionServer::encrypt(const std::string &password, unsigned int
                }
        };
 
-       std::thread asyncWork(encryptWorker);
+       std::thread asyncWork(encryptWorker, std::move(rl));
        asyncWork.detach();
 
        return error::None;
@@ -325,7 +333,9 @@ int ExternalEncryptionServer::encrypt(const std::string &password, unsigned int
 
 int ExternalEncryptionServer::decrypt(const std::string &password)
 {
-       if (getState() != State::Encrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot decrypt, SD card's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -335,7 +345,7 @@ int ExternalEncryptionServer::decrypt(const std::string &password)
        if (ret != error::None)
                return ret;
 
-       auto decryptWorker = [masterKey, this]() {
+       auto decryptWorker = [masterKey, this](RequestLifetime&& rl) {
                try {
                        INFO(SINK, "Closing all applications using external storage.");
                        killDependentApplications(EXTERNAL_PATH);
@@ -364,7 +374,7 @@ int ExternalEncryptionServer::decrypt(const std::string &password)
                }
        };
 
-       std::thread asyncWork(decryptWorker);
+       std::thread asyncWork(decryptWorker, std::move(rl));
        asyncWork.detach();
 
        return error::None;
@@ -372,7 +382,9 @@ int ExternalEncryptionServer::decrypt(const std::string &password)
 
 int ExternalEncryptionServer::recovery()
 {
-       if (getState() == State::Unencrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() == State::Unencrypted) {
                return error::NoSuchDevice;
        }
 
@@ -415,6 +427,27 @@ int ExternalEncryptionServer::verifyPassword(const std::string& password)
 
 int ExternalEncryptionServer::getState()
 {
+       RequestLifetime rl(server);
+
+       return getStateInternal();
+}
+
+unsigned int ExternalEncryptionServer::getSupportedOptions()
+{
+       RequestLifetime rl(server);
+
+       return engine->getSupportedOptions();
+}
+
+std::string ExternalEncryptionServer::getDevicePath() const
+{
+       RequestLifetime rl(server);
+
+       return engine->getSource();
+}
+
+int ExternalEncryptionServer::getStateInternal() const
+{
        char *value = ::vconf_get_str(VCONFKEY_SDE_CRYPTO_STATE);
        if (value == NULL) {
                throw runtime::Exception("Failed to get vconf value.");
@@ -433,14 +466,4 @@ int ExternalEncryptionServer::getState()
        return State::NotSupported;
 }
 
-unsigned int ExternalEncryptionServer::getSupportedOptions()
-{
-       return engine->getSupportedOptions();
-}
-
-std::string ExternalEncryptionServer::getDevicePath() const
-{
-       return engine->getSource();
-}
-
 } // namespace ode
index 6cff993..0046b36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -60,6 +60,8 @@ public:
        std::string getDevicePath() const;
 
 private:
+       int getStateInternal() const;
+
        ServerContext& server;
 
        std::unique_ptr<EXTERNAL_ENGINE> engine;
index ee1c95d..901396a 100644 (file)
@@ -453,7 +453,7 @@ InternalEncryptionServer::InternalEncryptionServer(ServerContext& srv,
 
        std::string source = findDevPath();
 
-       if (getState() == State::Encrypted) {
+       if (getStateInternal() == State::Encrypted) {
                //"error_partially_encrypted"
                if (!FileFooter::exist(source) && !UpgradeSupport::checkUpgradeFlag()) {
                        // Trigger key migration process
@@ -497,6 +497,8 @@ int InternalEncryptionServer::migrateMasterKey(const std::string& dev, const std
 
 int InternalEncryptionServer::setMountPassword(const std::string& password)
 {
+       RequestLifetime rl(server);
+
        const std::string& dev = engine->getSource();
 
        // check if upgrade flag exists
@@ -514,6 +516,8 @@ int InternalEncryptionServer::setMountPassword(const std::string& password)
 
 int InternalEncryptionServer::mount(const std::vector<unsigned char> &mk, unsigned int options)
 {
+       RequestLifetime rl(server);
+
        if (mountKey.empty() && mk.empty()) {
                ERROR(SINK, "You need to set master key first.");
                return error::NoData;
@@ -522,7 +526,7 @@ int InternalEncryptionServer::mount(const std::vector<unsigned char> &mk, unsign
        BinaryData key = mk.empty() ? mountKey : mk;
        mountKey.clear();
 
-       if (getState() != State::Encrypted) {
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot mount, SD partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -550,6 +554,8 @@ int InternalEncryptionServer::mount(const std::vector<unsigned char> &mk, unsign
 
 int InternalEncryptionServer::isMounted()
 {
+       RequestLifetime rl(server);
+
        int ret = 0;
        try {
                ret = engine->isMounted() ? 1 : 0;
@@ -562,7 +568,9 @@ int InternalEncryptionServer::isMounted()
 
 int InternalEncryptionServer::umount()
 {
-       if (getState() != State::Encrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot umount, partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -588,7 +596,9 @@ int InternalEncryptionServer::umount()
 
 int InternalEncryptionServer::prepareEncryption(unsigned int options)
 {
-       if (getState() != State::Unencrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Unencrypted) {
                ERROR(SINK, "Cannot encrypt, partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -601,7 +611,7 @@ int InternalEncryptionServer::prepareEncryption(unsigned int options)
                return error::Unknown;
        }
 
-       setOptions(options & getSupportedOptions());
+       setOptions(options & engine->getSupportedOptions());
 
        ::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "prepared_encryption");
        ::sync();
@@ -612,7 +622,9 @@ int InternalEncryptionServer::prepareEncryption(unsigned int options)
 
 int InternalEncryptionServer::prepareDecryption()
 {
-       if (getState() != State::Encrypted) {
+       RequestLifetime rl(server);
+
+       if (getStateInternal() != State::Encrypted) {
                ERROR(SINK, "Cannot decrypt, partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -634,8 +646,10 @@ int InternalEncryptionServer::prepareDecryption()
 
 int InternalEncryptionServer::encrypt(const std::string& password, unsigned int options)
 {
-       if (getState() != State::Unencrypted
-                       && getState() != State::PreparedEncryption) {
+       RequestLifetime rl(server);
+
+       int state = getStateInternal();
+       if (state != State::Unencrypted && state != State::PreparedEncryption) {
                ERROR(SINK, "Cannot encrypt, partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -645,7 +659,7 @@ int InternalEncryptionServer::encrypt(const std::string& password, unsigned int
        if (ret != error::None)
                return ret;
 
-       auto encryptWorker = [masterKey, options, this]() {
+       auto encryptWorker = [masterKey, options, this](RequestLifetime&& rl) {
                try {
                        if (::device_power_request_lock(POWER_LOCK_DISPLAY, 0) != 0)
                                ERROR(SINK, "Failed to request to lock display");
@@ -654,7 +668,7 @@ int InternalEncryptionServer::encrypt(const std::string& password, unsigned int
                        ::sleep(1);
 
                        runtime::File file("/opt/etc/.odeprogress");
-                       if (getState() == State::Unencrypted) {
+                       if (getStateInternal() == State::Unencrypted) {
                                /* For backward compatibility */
                                file.create(MODE_0640);
                                std::string source = engine->getSource();
@@ -667,7 +681,7 @@ int InternalEncryptionServer::encrypt(const std::string& password, unsigned int
                                        INFO(SINK, "Unmounting internal storage.");
                                        unmountInternalStorage(source);
                                }
-                               setOptions(options & getSupportedOptions());
+                               setOptions(options & engine->getSupportedOptions());
                        }
 
                        INFO(SINK, "Encryption started.");
@@ -698,7 +712,7 @@ int InternalEncryptionServer::encrypt(const std::string& password, unsigned int
                }
        };
 
-       std::thread asyncWork(encryptWorker);
+       std::thread asyncWork(encryptWorker, std::move(rl));
        asyncWork.detach();
 
        return error::None;
@@ -706,8 +720,10 @@ int InternalEncryptionServer::encrypt(const std::string& password, unsigned int
 
 int InternalEncryptionServer::decrypt(const std::string& password)
 {
-       if (getState() != State::Encrypted
-                       && getState() != State::PreparedDecryption) {
+       RequestLifetime rl(server);
+
+       int state = getStateInternal();
+       if (state != State::Encrypted && state != State::PreparedDecryption) {
                ERROR(SINK, "Cannot decrypt, partition's state incorrect.");
                return error::NoSuchDevice;
        }
@@ -726,7 +742,7 @@ int InternalEncryptionServer::decrypt(const std::string& password)
        if (ret != error::None)
                return ret;
 
-       auto decryptWorker = [masterKey, this]() {
+       auto decryptWorker = [masterKey, this](RequestLifetime&& rl) {
                try {
                        if (::device_power_request_lock(POWER_LOCK_DISPLAY, 0) != 0)
                                ERROR(SINK, "Failed to request to lock display");
@@ -735,7 +751,7 @@ int InternalEncryptionServer::decrypt(const std::string& password)
                        ::sleep(1);
 
                        runtime::File file("/opt/etc/.odeprogress");
-                       if (getState() == State::Encrypted) {
+                       if (getStateInternal() == State::Encrypted) {
                                /* For backward compatibility */
                                file.create(MODE_0640);
 
@@ -776,7 +792,7 @@ int InternalEncryptionServer::decrypt(const std::string& password)
                }
        };
 
-       std::thread asyncWork(decryptWorker);
+       std::thread asyncWork(decryptWorker, std::move(rl));
        asyncWork.detach();
 
        return error::None;
@@ -784,7 +800,9 @@ int InternalEncryptionServer::decrypt(const std::string& password)
 
 int InternalEncryptionServer::recovery()
 {
-       int state = getState();
+       RequestLifetime rl(server);
+
+       int state = getStateInternal();
 
        if (state == State::Unencrypted)
                return error::NoSuchDevice;
@@ -844,6 +862,27 @@ int InternalEncryptionServer::verifyPassword(const std::string& password)
 
 int InternalEncryptionServer::getState()
 {
+       RequestLifetime rl(server);
+
+       return getStateInternal();
+}
+
+unsigned int InternalEncryptionServer::getSupportedOptions()
+{
+       RequestLifetime rl(server);
+
+       return engine->getSupportedOptions();
+}
+
+std::string InternalEncryptionServer::getDevicePath() const
+{
+       RequestLifetime rl(server);
+
+       return engine->getSource();
+}
+
+int InternalEncryptionServer::getStateInternal() const
+{
        char *value = ::vconf_get_str(VCONFKEY_ODE_CRYPTO_STATE);
        if (value == NULL) {
                throw runtime::Exception("Failed to get vconf value.");
@@ -866,14 +905,4 @@ int InternalEncryptionServer::getState()
        return State::NotSupported;
 }
 
-unsigned int InternalEncryptionServer::getSupportedOptions()
-{
-       return engine->getSupportedOptions();
-}
-
-std::string InternalEncryptionServer::getDevicePath() const
-{
-       return engine->getSource();
-}
-
 } // namespace ode
index 6507050..8756866 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -62,6 +62,7 @@ public:
 
 private:
        int migrateMasterKey(const std::string& dev, const std::string& password);
+       int getStateInternal() const;
 
 private:
        ServerContext& server;
index 0a07ea5..2e6d55c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -63,6 +63,8 @@ KeyServer::~KeyServer()
 
 int KeyServer::isInitialized(const std::string& dev)
 {
+       RequestLifetime rl(server);
+
        if (dev.empty())
                return error::InvalidParameter;
 
@@ -73,6 +75,8 @@ int KeyServer::init(const std::string& dev,
                                        const std::string& password,
                                        int params)
 {
+       RequestLifetime rl(server);
+
        BinaryData dummy;
        return initAndGet(dev, password, params, dummy);
 }
@@ -97,6 +101,8 @@ int KeyServer::initAndGet(const std::string& dev,
 
 int KeyServer::remove(const std::string& dev, const std::string& password)
 {
+       RequestLifetime rl(server);
+
        if (dev.empty() || password.empty())
                return error::InvalidParameter;
 
@@ -114,6 +120,7 @@ int KeyServer::changePassword(const std::string& dev,
                                                          const std::string& curPassword,
                                                          const std::string& newPassword)
 {
+       RequestLifetime rl(server);
 
        if (dev.empty() || curPassword.empty() || newPassword.empty())
                return error::InvalidParameter;
@@ -158,6 +165,8 @@ int KeyServer::changePassword2(const std::string& dev,
 int KeyServer::verifyPassword(const std::string& dev,
                                                          const std::string& password)
 {
+       RequestLifetime rl(server);
+
        if (dev.empty() || password.empty())
                return error::InvalidParameter;
 
@@ -189,6 +198,8 @@ void KeyServer::removePassword(const std::string& dev)
 int KeyServer::storeMasterKey(const std::string& dev,
                                                          const std::string& password)
 {
+       RequestLifetime rl(server);
+
        if (dev.empty() || password.empty())
                return error::InvalidParameter;
 
@@ -211,6 +222,8 @@ int KeyServer::storeMasterKey(const std::string& dev,
 
 int KeyServer::removeMasterKey(const std::string& dev)
 {
+       RequestLifetime rl(server);
+
        if (dev.empty())
                return error::InvalidParameter;
 
index ffbec87..1ad208e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2017 - 2019 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.
@@ -64,6 +64,8 @@ template <typename F>
 int LuksServer::execute(bool sync, Luks::Operation op, const F& job)
 {
        auto worker = [=]() {
+               RequestLifetime rl(server);
+
                int ret = error::Unknown;
                try {
                        std::lock_guard<std::mutex> guardLock(opGuard);
index 04b9a88..ed140a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -66,7 +66,7 @@ int main(int argc, char *argv[])
        try {
                ODEGMainLoop gmainloop;
                ode::ServerContext server;
-               server.start();
+               server.start(true);
        } catch (std::exception &e) {
                std::cerr << e.what() << std::endl;
                return 1;
index 7cbfab3..94a34f8 100644 (file)
@@ -1,6 +1,5 @@
 /*
- *
- *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2017 - 2019 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.
@@ -68,6 +67,7 @@ SecureEraseServer::~SecureEraseServer()
 int SecureEraseServer::clean(const std::string &name)
 {
        auto cleanWorker = [name, this]() {
+               RequestLifetime rl(server);
                try {
                        std::string target = findDeviceByMountPoint(name);
                        engine->cleanDevice(target);
index 33537cf..521e6f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include <cynara-client.h>
 #include <sys/smack.h>
 
+#include <stdexcept>
+#include <chrono>
+#include <cassert>
+#include <thread>
+
 #include "logger.h"
 #include "file-sink.h"
 #include "secure-erase.h"
@@ -34,12 +39,72 @@ namespace ode {
 
 namespace {
 
-const std::string ODE_MANAGER_ADDRESS = "/tmp/.ode.sock";
 std::unique_ptr<FileLogSink> _sink = nullptr;
 
 } // namespace
 
-ServerContext::ServerContext() : rmi::Service(ODE_MANAGER_ADDRESS)
+/*
+ * Timer thread fuction responsible for detecting a server inactivity period after which it will be
+ * stopped.
+ *
+ * Assumptions & acknowledgements:
+ * - Currently there are only 2 ways of stopping the oded server:
+ *   - Timeout expiration implemented in the function below
+ *   - Terminating with a signal (e.g. SIGTERM from systemd)
+ * - There's a risk of race condition for a request that has just been received (the program is
+ *   somewhere between klay's epoll_wait() and mutex lock in ServerContext::requestStarted) while
+ *   the timerFunc below detects the timeout and stops the server. In such case the newly received
+ *   request will not be processed and client will be disconnected. For now this risk is accepted.
+ *   To reduce it, the klay's socket & thread handling would have to be modified or replaced.
+ * - Request processing callbacks are currently called from one of klay's worker threads.
+ * - For requests that require longer processing additional threads are spawned by the server. The
+ *   server is considered active as long as the request processing thread is running.
+ * - For debugging purpose, a manually started server is not considered inactive until a request
+ *   arrives. In other words, the inactivity time measurement starts after a request is processed.
+ * - Spurious wakeups will not occur in sleep_for().
+ */
+void ServerContext::timerFunc()
+{
+       DEBUG(SINK, "Timer thread started");
+       bool requestArrived = false;
+       for(;;) {
+               std::this_thread::sleep_for(std::chrono::seconds(5));
+
+               std::lock_guard<std::mutex> lock(timerMutex);
+               if (!requestArrived) {
+                       if (!newRequests)
+                               continue;
+
+                       requestArrived = true;
+               }
+               if (!newRequests && currentRequests == 0)
+                       break;
+
+               newRequests = false;
+       }
+       INFO(SINK, "Timeout reached. ODE server stopping.");
+       stop();
+}
+
+// This method may be called from different threads
+void ServerContext::requestStarted()
+{
+       std::lock_guard<std::mutex> lock(timerMutex);
+       currentRequests++;
+       newRequests = true;
+       DEBUG(SINK, "New request received. Current count: " << currentRequests);
+}
+
+// This method may be called from different threads
+void ServerContext::requestFinished()
+{
+       std::lock_guard<std::mutex> lock(timerMutex);
+       assert(currentRequests > 0);
+       currentRequests--;
+       DEBUG(SINK, "Request processed. Current count:" << currentRequests);
+}
+
+ServerContext::ServerContext() : rmi::Service(SOCKET_PATH), currentRequests(0), newRequests(false)
 {
        _sink.reset(new FileLogSink("ode.log"));
        SINK = _sink.get();
@@ -59,6 +124,9 @@ ServerContext::ServerContext() : rmi::Service(ODE_MANAGER_ADDRESS)
        luks.reset(new LuksServer(*this, *keys));
 
        KeyGenerator::init();
+
+       std::thread timerThread(&ServerContext::timerFunc, this);
+       timerThread.detach();
 }
 
 ServerContext::~ServerContext()
@@ -96,6 +164,9 @@ runtime::FileDescriptor ServerContext::registerNotificationSubscriber(const std:
 {
        INFO(SINK, "registerNotificationSubscriber");
        INFO(SINK, name);
+
+       RequestLifetime rl(*this);
+
        int fd = subscribeNotification(name);
 
        /**
@@ -112,6 +183,8 @@ runtime::FileDescriptor ServerContext::registerNotificationSubscriber(const std:
 
 int ServerContext::unregisterNotificationSubscriber(const std::string& name, int id)
 {
+       RequestLifetime rl(*this);
+
        return unsubscribeNotification(name, id);
 }
 
index 9b38f70..9f3ff0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2019 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.
@@ -19,6 +19,7 @@
 
 #include <string>
 #include <memory>
+#include <mutex>
 
 #include <klay/file-descriptor.h>
 #include <klay/rmi/service.h>
@@ -41,12 +42,44 @@ public:
        runtime::FileDescriptor registerNotificationSubscriber(const std::string& name);
        int unregisterNotificationSubscriber(const std::string& name, int id);
 
+       void requestStarted();
+       void requestFinished();
+
 private:
+       void timerFunc();
+
        std::unique_ptr<SecureEraseServer> secureErase;
        std::unique_ptr<InternalEncryptionServer> internalEncryption;
        std::unique_ptr<ExternalEncryptionServer> externalEncryption;
        std::unique_ptr<LuksServer> luks;
        std::unique_ptr<KeyServer> keys;
+
+       std::mutex timerMutex;
+       unsigned currentRequests;
+       bool newRequests;
+};
+
+class RequestLifetime {
+public:
+       explicit RequestLifetime(ServerContext& c) : ctx(&c) {
+               ctx->requestStarted();
+       }
+
+       RequestLifetime(RequestLifetime&& other) {
+               ctx = other.ctx;
+               other.ctx = NULL;
+       }
+
+       ~RequestLifetime() {
+               if (ctx)
+                       ctx->requestFinished();
+       }
+
+       RequestLifetime(const RequestLifetime&) = delete;
+       RequestLifetime& operator=(const RequestLifetime&) = delete;
+
+private:
+       ServerContext* ctx;
 };
 
 } // namespace ode
index 35d3b59..cfc238a 100644 (file)
@@ -1,6 +1,6 @@
 [Unit]
 Description=@PROJECT_NAME@ management daemon
-Before=deviced.service
+Requires=ode.socket
 
 [Service]
 SmackProcessLabel=System::Privileged
@@ -10,6 +10,3 @@ ExecReload=/bin/kill -HUP $MAINPID
 CapabilityBoundingSet=~CAP_MAC_OVERRIDE
 EnvironmentFile=/run/tizen-system-env
 EnvironmentFile=/run/xdg-root-env
-
-[Install]
-WantedBy=multi-user.target
diff --git a/server/systemd/ode.socket.in b/server/systemd/ode.socket.in
new file mode 100644 (file)
index 0000000..ad11fca
--- /dev/null
@@ -0,0 +1,7 @@
+[Socket]
+ListenStream=@SOCKET_PATH@
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+
+[Install]
+WantedBy=sockets.target