Add showing log only when process termination is failed
[platform/core/security/ode.git] / server / internal-encryption.cpp
index 284e436..ae410c5 100644 (file)
  *  limitations under the License
  */
 #include <set>
+#include <algorithm>
 
+#include <fcntl.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/mount.h>
 #include <sys/reboot.h>
+#include <sys/inotify.h>
 
 #include <vconf.h>
+#include <tzplatform_config.h>
 #include <klay/process.h>
 #include <klay/file-user.h>
 #include <klay/filesystem.h>
 #include <klay/dbus/connection.h>
-#include <klay/audit/logger.h>
 
 #include "vconf.h"
+#include "logger.h"
 #include "progress-bar.h"
-#include "engine/dmcrypt-engine.h"
+#include "engine/encryption/dmcrypt-engine.h"
 #include "key-manager/key-manager.h"
 
 #include "rmi/internal-encryption.h"
 
 #define INTERNAL_ENGINE        DMCryptEngine
-#define INTERNAL_DEV   "/dev/mmcblk0p25"
-#define INTERNAL_PATH  "/opt/usr"
+#define INTERNAL_DEV_PATH      "/dev/disk/by-partlabel"
+#define INTERNAL_DEV_NAME      "USER"
+#define INTERNAL_PATH          "/opt/usr"
 #define INTERNAL_STATE_VCONF_KEY                                       VCONFKEY_ODE_CRYPTO_STATE
 #define INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY     VCONFKEY_ODE_FAST_ENCRYPTION
 
 #define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
 
+const std::string PROG_FACTORY_RESET = "/usr/bin/dbus-send";
+const std::vector<std::string> wipeCommand = {
+    PROG_FACTORY_RESET,
+    "--system",
+    "--type=signal",
+    "--print-reply",
+    "--dest=com.samsung.factoryreset",
+    "/com/samsung/factoryreset",
+    "com.samsung.factoryreset.start.setting"
+};
+
 namespace ode {
 
 namespace {
 
 std::unique_ptr<INTERNAL_ENGINE> engine;
+KeyManager::data mountKey;
 
 void stopDependedSystemdServices()
 {
-       dbus::Connection& systemDBus = dbus::Connection::getSystem();
-       std::set<std::string> servicesToStop;
+       runtime::File fileToTouch("/tmp/.ode-umount-internal");
+       try {
+               fileToTouch.remove();
+       } catch(runtime::Exception &e) {}
+       fileToTouch.create(O_WRONLY);
 
-       for (pid_t pid : runtime::FileUser::getList(INTERNAL_PATH, true)) {
-               try {
-                       char *service;
-                       systemDBus.methodcall("org.freedesktop.systemd1",
-                                                                       "/org/freedesktop/systemd1",
-                                                                       "org.freedesktop.systemd1.Manager",
-                                                                       "GetUnitByPID",
-                                                                       -1, "(o)", "(u)", (unsigned int)pid)
-                                                                               .get("(o)", &service);
-                       servicesToStop.insert(service);
-               } catch (runtime::Exception &e) {
-                       INFO("Close process - " + std::to_string(pid));
-                       ::kill(pid, SIGKILL);
-               }
-       }
+       sleep(1);
+}
 
-       for (const std::string& service : servicesToStop) {
-               INFO("Close service - " + service);
-               systemDBus.methodcall("org.freedesktop.systemd1",
-                                                               service,
-                                                               "org.freedesktop.systemd1.Unit",
-                                                               "Stop",
-                                                               -1, "", "(s)", "flush");
-       }
+void killDependedProcesses()
+{
+       INFO(SINK, "killDependedProcesses");
+    for (pid_t pid : runtime::FileUser::getList(INTERNAL_PATH, true)) {
+        INFO(SINK, "Close process - " + std::to_string(pid));
+               int ret = ::kill(pid, SIGKILL);
+               if (ret != 0) {
+                       ERROR(SINK, "Failed to kill process " + std::to_string(pid));
+               }
+    }
 }
 
 void showProgressUI(const std::string type) {
-       std::vector<std::string> args = {
-               "ode", "progress", type, "Internal"
-       };
-
-       runtime::Process proc("/usr/bin/ode", args);
-       proc.execute();
+       runtime::File fileToTouch("/tmp/.ode-progress-internal@" + type);
+       try {
+               fileToTouch.remove();
+       } catch(runtime::Exception &e) {}
+       fileToTouch.create(O_WRONLY);
 }
 
 unsigned int getOptions()
@@ -119,7 +127,8 @@ void setOptions(unsigned int options)
 InternalEncryption::InternalEncryption(ODEControlContext& ctx) :
        context(ctx)
 {
-       context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::mount)(std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::setMountPassword)(std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::mount)());
        context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::umount)());
        context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::encrypt)(std::string, unsigned int));
        context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::decrypt)(std::string));
@@ -131,8 +140,30 @@ InternalEncryption::InternalEncryption(ODEControlContext& ctx) :
        context.expose(this, "", (int)(InternalEncryption::getState)());
        context.expose(this, "", (unsigned int)(InternalEncryption::getSupportedOptions)());
 
+       context.createNotification("InternalEncryption::mount");
+
+       std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME;
+       try {
+               runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end;
+
+               while (iter != end) {
+                       const std::string& path = (*iter).getPath();
+                       std::string name = path.substr(path.rfind('/') + 1);
+                       std::string upper;
+                       upper.reserve(name.size());
+                       for (char c : name) {
+                               upper += std::toupper(c);
+                       }
+                       if (upper == INTERNAL_DEV_NAME) {
+                               source = path;
+                               break;
+                       }
+                       ++iter;
+               }
+       } catch (runtime::Exception &e) {}
+
        engine.reset(new INTERNAL_ENGINE(
-               INTERNAL_DEV, INTERNAL_PATH,
+               source, INTERNAL_PATH,
                ProgressBar([](int v) {
                        ::vconf_set_str(VCONFKEY_ODE_ENCRYPT_PROGRESS,
                                                        std::to_string(v).c_str());
@@ -144,20 +175,38 @@ InternalEncryption::~InternalEncryption()
 {
 }
 
-int InternalEncryption::mount(const std::string& password)
+int InternalEncryption::setMountPassword(const std::string& password)
 {
-       if (getState() != State::Encrypted) {
-               return -1;
-       }
-
        KeyManager::data pwData(password.begin(), password.end());
        KeyManager keyManager(engine->getKeyMeta());
-
        if (!keyManager.verifyPassword(pwData)) {
                return -2;
        }
 
-       engine->mount(keyManager.getMasterKey(pwData), getOptions());
+       ode::mountKey = keyManager.getMasterKey(pwData);
+
+       return 0;
+}
+
+int InternalEncryption::mount()
+{
+       if (getState() != State::Encrypted) {
+               return -1;
+       }
+
+    if (engine->isMounted()) {
+               INFO(SINK, "Already mounted");
+               return 0;
+       }
+
+       engine->mount(mountKey, getOptions());
+       mountKey.clear();
+
+       context.notify("InternalEncryption::mount");
+
+       runtime::File("/tmp/.lazy_mount").create(O_WRONLY);
+       runtime::File("/tmp/.unlock_mnt").create(O_WRONLY);
+
        return 0;
 }
 
@@ -167,9 +216,15 @@ int InternalEncryption::umount()
                return -1;
        }
 
-       INFO("Close all processes using internal storage...");
+       if (!engine->isMounted()) {
+               INFO(SINK, "Already umounted");
+               return 0;
+       }
+
+       INFO(SINK, "Close all processes that use internal storage...");
        stopDependedSystemdServices();
-       INFO("Umount internal storage...");
+       killDependedProcesses();
+       INFO(SINK, "Umount internal storage...");
        engine->umount();
 
        return 0;
@@ -191,31 +246,33 @@ int InternalEncryption::encrypt(const std::string& password, unsigned int option
        KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
        auto encryptWorker = [MasterKey, options, this]() {
                try {
-                       showProgressUI("Encrypting");
-
-                       INFO("Close all processes using internal storage...");
+                       INFO(SINK, "Close all processes that use internal storage...");
                        stopDependedSystemdServices();
-                       INFO("Umount internal storage...");
+                       killDependedProcesses();
+                       INFO(SINK, "Umount internal storage...");
                        while (::umount(INTERNAL_PATH) == -1) {
                                if (errno != EBUSY) {
                                        throw runtime::Exception("Umount error - " + std::to_string(errno));
                                }
-                               stopDependedSystemdServices();
+                               killDependedProcesses();
                        }
 
-                       INFO("Encryption started...");
-                       ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
+                       showProgressUI("Encrypting");
+
+                       INFO(SINK, "Encryption started...");
                        engine->encrypt(MasterKey, options);
                        setOptions(options & getSupportedOptions());
-                       INFO("Sync disk...");
+                       INFO(SINK, "Sync disk...");
                        sync();
-                       INFO("Encryption completed");
+                       INFO(SINK, "Encryption completed");
 
                        ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "encrypted");
+                       context.notify("InternalEncryption::mount");
+                       ::reboot(RB_AUTOBOOT);
                } catch (runtime::Exception &e) {
-                       ERROR("Encryption failed - " + std::string(e.what()));
+                       ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
+                       ERROR(SINK, "Encryption failed - " + std::string(e.what()));
                }
-               ::reboot(RB_AUTOBOOT);
        };
 
        std::thread asyncWork(encryptWorker);
@@ -240,32 +297,33 @@ int InternalEncryption::decrypt(const std::string& password)
        KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
        auto decryptWorker = [MasterKey, this]() {
                try {
-                       showProgressUI("Decrypting");
-
-                       INFO("Close all processes using internal storage...");
+                       INFO(SINK, "Umount internal storage...");
                        stopDependedSystemdServices();
-                       INFO("Umount internal storage...");
+                       killDependedProcesses();
+                       INFO(SINK, "Umount internal storage...");
                        while (1) {
                                try {
                                        engine->umount();
                                        break;
                                } catch (runtime::Exception& e) {
-                                       stopDependedSystemdServices();
+                                       killDependedProcesses();
                                }
                        }
 
-                       INFO("Decryption started...");
-                       ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
+                       showProgressUI("Decrypting");
+
+                       INFO(SINK, "Decryption started...");
                        engine->decrypt(MasterKey, getOptions());
-                       INFO("Sync disk...");
+                       INFO(SINK, "Sync disk...");
                        sync();
-                       INFO("Decryption completed");
+                       INFO(SINK, "Decryption completed");
 
                        ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "unencrypted");
+                       ::reboot(RB_AUTOBOOT);
                } catch (runtime::Exception &e) {
-                       ERROR("Decryption failed - " + std::string(e.what()));
+                       ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
+                       ERROR(SINK, "Decryption failed - " + std::string(e.what()));
                }
-               ::reboot(RB_AUTOBOOT);
        };
 
        std::thread asyncWork(decryptWorker);
@@ -274,6 +332,22 @@ int InternalEncryption::decrypt(const std::string& password)
        return 0;
 }
 
+int InternalEncryption::recovery()
+{
+       if (getState() != State::Unencrypted) {
+               return -1;
+       }
+
+       //TODO
+       runtime::Process proc(PROG_FACTORY_RESET, wipeCommand);
+       if (proc.execute() == -1) {
+               ERROR(SINK, "Failed to launch factory-reset");
+               return -2;
+       }
+
+       return 0;
+}
+
 int InternalEncryption::isPasswordInitialized()
 {
        if (engine->isKeyMetaSet()) {