Implementation of ExtensionEncryption with CryptsetupEngine 02/129702/15
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Mon, 15 May 2017 15:34:40 +0000 (17:34 +0200)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Wed, 31 May 2017 09:40:54 +0000 (11:40 +0200)
New approach, let storaged do its work

Change-Id: I565bfed56322bbbb65b877b05a4ae4fe332954c8

rmi/extension-encryption.h
server/extension-encryption.cpp
server/external-encryption.cpp
server/server.cpp

index cdcb2ab..7fdac84 100644 (file)
@@ -18,6 +18,9 @@
 #define __EXTENSION_ENCRYPTION_H__
 
 #include <string>
+#include <mutex>
+
+#include <klay/dbus/connection.h>
 
 #include "context.h"
 
@@ -52,7 +55,71 @@ public:
        int getState();
 
 private:
+       enum Operation {
+               ADDED = 0,
+               CHANGED,
+               REMOVED,
+
+               OPERATION_MAX
+       };
+
+       enum Device {
+               MMC = 0,
+               MAP,
+
+               DEVICE_MAX
+       };
+
+       enum Request {
+               NONE = 0,
+               MOUNT,
+               UMOUNT
+       };
+
+       struct DevInfo {
+               std::string mntPath;
+               std::string fsType;
+               std::string sysPath;
+               bool mounted;
+               int storagedId;
+
+               DevInfo() : mounted(false), storagedId(-1) {}
+               ~DevInfo() {}
+
+               void clear() {
+                       mntPath.clear();
+                       fsType.clear();
+                       sysPath.clear();
+                       mounted = false;
+                       storagedId = -1;
+               }
+       };
+
+       void logStoragedEvent(Operation op, Device d);
+       void handleDevice(Operation op,
+                                         const std::vector<int> &intparams,
+                                         const std::vector<char*> &strparams);
+       void parseVariant(Operation op, dbus::Variant parameters);
+       void queryStoraged();
+       void subscribeToStoraged();
+       void unsubscribeFromStoraged();
+
+       bool storagedMount(std::unique_lock<std::mutex> &lock);
+       bool storagedUnmount(std::unique_lock<std::mutex> &lock);
+
+       int getStatePriv() const;
+       bool isInserted() const;
+       bool isOpened() const;
+       bool isMounted() const;
+
        ODEControlContext& context;
+
+       // currently inserted card information, empty if no card:
+       DevInfo info[DEVICE_MAX];
+
+       dbus::Connection::SubscriptionId subId[OPERATION_MAX];
+
+       Request currentReq;
 };
 
 } // namespace ode
index e430d5e..9c7f1a3 100644 (file)
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
+#include <mutex>
+
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <stdio.h>
+#include <mntent.h>
+
+#include <klay/file-user.h>
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+#include <klay/dbus/variant.h>
+#include <klay/dbus/connection.h>
+
+#include "ext4-tool.h"
+#include "engine/encryption/cryptsetup-engine.h"
+#include "key-manager/key-manager.h"
 
 #include "rmi/extension-encryption.h"
 
+#define EXTENSION_ENGINE       CryptsetupEngine
+#define EXTENSION_NAME_DEF     "extension"
+
 namespace ode {
 
+namespace {
+
+const char *EXTENSION_DEV_PATH = "/dev/mmcblk1p1";
+const char *EXTENSION_NAME             = EXTENSION_NAME_DEF;
+const char *EXTENSION_MAP_PATH = "/dev/mapper/" EXTENSION_NAME_DEF;
+const char *EXTENSION_FS_TYPE  = "crypto_LUKS";
+
+const char *PRIVILEGE_PLATFORM = "http://tizen.org/privilege/internal/default/platform";
+
+const char *STORAGED_DBUS_BUSNAME      = "org.tizen.system.storage";
+const char *STORAGED_DBUS_OBJECT       = "/Org/Tizen/System/Storage/Block/Manager";
+const char *STORAGED_DBUS_INTERFACE    = "org.tizen.system.storage.BlockManager";
+
+std::unique_ptr<EXTENSION_ENGINE> engine;
+
+std::mutex apiGuard;
+std::mutex stateGuard;
+std::condition_variable storagedCv;
+
+std::string findMntPath(const std::string &devPath)
+{
+       std::string ret;
+
+       FILE* mtab = setmntent("/etc/mtab", "r");
+       struct mntent* entry = NULL;
+       while ((entry = getmntent(mtab)) != NULL) {
+               if (devPath == entry->mnt_fsname) {
+                       ret = entry->mnt_dir;
+                       break;
+               }
+       }
+       endmntent(mtab);
+
+       return ret;
+}
+
+void killDependedApplications(const std::string &mntPath)
+{
+       for (pid_t pid : runtime::FileUser::getList(mntPath, true)) {
+               INFO("Close process - " + std::to_string(pid));
+               ::kill(pid, SIGKILL);
+       }
+}
+
+bool findKillAndUmount(const std::string &devPath)
+{
+       std::string realMntPath = findMntPath(devPath);
+       if (!realMntPath.empty()) {
+               INFO("Closing all applications using an SD card...");
+               killDependedApplications(realMntPath);
+
+               int ret = ::umount(realMntPath.c_str());
+               if (ret != 0) {
+                       ERROR("The card is still mounted, umount failed with: "
+                                 + std::to_string(ret));
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+} // namsepace
+
 ExtensionEncryption::ExtensionEncryption(ODEControlContext &ctx) :
-       context(ctx)
+       context(ctx),
+       currentReq(Request::NONE)
 {
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::mount)(std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::umount)());
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::format)(std::string));
+       context.expose(this, "", (int)(ExtensionEncryption::isPasswordInitialized)());
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::initPassword)(std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::cleanPassword)(std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::changePassword)(std::string, std::string));
+       context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::verifyPassword)(std::string));
+       context.expose(this, "", (int)(ExtensionEncryption::getState)());
+
+       context.createNotification("ExtensionEncryption::mount");
+
+       // TODO: think about handling more than one card / more than one engine
+       // it would require global API change to select which card is handled atm
+       engine.reset(new EXTENSION_ENGINE(EXTENSION_DEV_PATH));
+
+       queryStoraged();
+       subscribeToStoraged();
 }
 
 ExtensionEncryption::~ExtensionEncryption()
 {
+       unsubscribeFromStoraged();
 }
 
 int ExtensionEncryption::mount(const std::string& password)
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+       std::unique_lock<std::mutex> stateLock(stateGuard);
+
+       if (getStatePriv() != State::Encrypted) {
+               ERROR("Cannot mount, card not inserted or corrupted");
+               return -1;
+       }
+
+       KeyManager::data pwData(password.begin(), password.end());
+       KeyManager keyManager(engine->getKeyMeta());
+
+       if (!keyManager.verifyPassword(pwData)) {
+               ERROR("Wrong password passed.");
+               return -2;
+       }
+
+       if (isMounted()) {
+               INFO("Already mounted");
+               return 0;
+       }
+
+       KeyManager::data mountKey = keyManager.getMasterKey(pwData);
+
+       INFO("Mount extension storage...");
+
+       if (!isOpened()) {
+               // Storaged will mount MAP automatically when it appears, let's prepare
+               currentReq = Request::MOUNT;
+
+               try {
+                       INFO("Open the MAP of an extension storage...");
+                       engine->open(CryptsetupEngine::DeviceType::LUKS, EXTENSION_NAME, mountKey);
+               } catch (runtime::Exception &e) {
+                       ERROR("Open failed: " + std::string(e.what()));
+                       return -3;
+               }
+
+               INFO("Wait for the storaged to mount the MAP automatically...");
+               if (!storagedCv.wait_for(stateLock, std::chrono::seconds(1), [this] {
+                                       return currentReq == Request::NONE;
+                               })) {
+                       ERROR("Storaged timed out mounting the MAP.");
+                       return -3;
+               }
+       } else {
+               INFO("Ask storaged to mount extension storage...");
+               if (!storagedMount(stateLock)) {
+                       return -3;
+               }
+       }
+
+       context.notify("ExtensionEncryption::mount");
+       return 0;
 }
 
 int ExtensionEncryption::umount()
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+       std::unique_lock<std::mutex> stateLock(stateGuard);
+
+       if (getStatePriv() != State::Encrypted) {
+               ERROR("Cannot umount, card not inserted or corrupted.");
+               return -1;
+       }
+
+       if (!isMounted() && !isOpened()) {
+               INFO("Already umounted.");
+               return 0;
+       }
+
+       INFO("Umount extension storage...");
+
+       if (isMounted()) {
+               INFO("Close all applications using extension storage...");
+               killDependedApplications(info[Device::MAP].mntPath);
+
+               INFO("Ask storaged to umount extension storage...");
+               if (!storagedUnmount(stateLock)) {
+                       return -3;
+               }
+       }
+
+       if (isOpened()) {
+               INFO("Close the MAP of an extension storage...");
+               try {
+                       CryptsetupEngine::close(EXTENSION_NAME);
+               } catch (runtime::Exception &e) {
+                       ERROR("Close failed: " + std::string(e.what()));
+                       return -3;
+               }
+       }
+
+       return 0;
 }
 
 int ExtensionEncryption::format(const std::string &password)
 {
-       return -1;
+       int status = 0;
+       std::condition_variable workerCv;
+
+       auto formatWorker = [&, this]() {
+               try {
+                       std::lock_guard<std::mutex> guardLock(apiGuard);
+                       std::unique_lock<std::mutex> stateLock(stateGuard);
+
+                       if (!isInserted()) {
+                               ERROR("There is no card inserted.");
+                               status = -1;
+                               stateLock.unlock();
+                               workerCv.notify_one();
+                               return;
+                       }
+
+                       if (isMounted() || isOpened()) {
+                               ERROR("The card is still mounted and/or opened, umount and close first.");
+                               status = -1;
+                               stateLock.unlock();
+                               workerCv.notify_one();
+                               return;
+                       }
+
+                       KeyManager::data pwData(password.begin(), password.end());
+                       KeyManager keyManager(engine->getKeyMeta());
+
+                       if (!keyManager.verifyPassword(pwData)) {
+                               ERROR("Wrong password passed.");
+                               status = -2;
+                               stateLock.unlock();
+                               workerCv.notify_one();
+                               return;
+                       }
+
+                       // no error, let's notify the main thread it can return
+                       status = 1;
+                       stateLock.unlock();
+                       workerCv.notify_one();
+
+                       KeyManager::data masterKey = keyManager.getMasterKey(pwData);
+
+                       // TODO: this probably needs a rework, some sort of communication
+                       // and/or merge with External. The use case for it might be:
+                       // 1. The mmc is mounted by something else, somewhere else. Do we care?
+                       // 2. We take over the cd card from External.
+                       if (!findKillAndUmount(EXTENSION_DEV_PATH))
+                               return;
+
+                       INFO("Creating LUKS...");
+                       engine->format(CryptsetupEngine::DeviceType::LUKS, masterKey);
+
+                       INFO("Opening LUKS...");
+                       std::string mappingPath = engine->open(CryptsetupEngine::DeviceType::LUKS,
+                                                                                                  EXTENSION_NAME,
+                                                                                                  masterKey);
+
+                       INFO("Creating EXT4...");
+                       Ext4Tool::mkfs(mappingPath);
+
+                       INFO("Closing up the operation...");
+                       CryptsetupEngine::close(EXTENSION_NAME);
+                       sync();
+
+                       INFO("Formatting completed");
+               } catch (runtime::Exception &e) {
+                       ERROR("Formatting thread failed: " + std::string(e.what()));
+               }
+       };
+
+       std::thread asyncWork(formatWorker);
+       asyncWork.detach();
+
+       std::unique_lock<std::mutex> stateLock(stateGuard);
+       if(!workerCv.wait_for(stateLock, std::chrono::seconds(1), [&status] {
+                               return status != 0;
+                       })) {
+               ERROR("Timed out waiting for format status.");
+               return -4;
+       }
+
+       if (status < 0)
+               return status;
+
+       return 0;
 }
 
 int ExtensionEncryption::isPasswordInitialized()
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+
+       if (engine->isKeyMetaSet()) {
+               return 1;
+       }
+
+       return 0;
 }
 
 int ExtensionEncryption::initPassword(const std::string& password)
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+
+       KeyManager::data pwData(password.begin(), password.end());
+       KeyManager keyManager;
+
+       keyManager.initPassword(pwData);
+       engine->setKeyMeta(keyManager.serialize());
+       return 0;
 }
 
 int ExtensionEncryption::cleanPassword(const std::string& password)
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+
+       KeyManager::data pwData(password.begin(), password.end());
+       KeyManager keyManager(engine->getKeyMeta());
+
+       if (!keyManager.verifyPassword(pwData)) {
+               ERROR("Wrong password passed.");
+               return -2;
+       }
+
+       engine->clearKeyMeta();
+       return 0;
 }
 
 int ExtensionEncryption::changePassword(const std::string &oldPassword,
                                                                           const std::string &newPassword)
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+
+       KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
+       KeyManager::data newPwData(newPassword.begin(), newPassword.end());
+       KeyManager keyManager(engine->getKeyMeta());
+
+       if (!keyManager.verifyPassword(oldPwData)) {
+               ERROR("Wrong password passed.");
+               return -2;
+       }
+
+       keyManager.changePassword(oldPwData, newPwData);
+       engine->setKeyMeta(keyManager.serialize());
+
+       return 0;
 }
 
 int ExtensionEncryption::verifyPassword(const std::string& password)
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+
+       KeyManager::data pwData(password.begin(), password.end());
+       KeyManager keyManager(engine->getKeyMeta());
+
+       if (keyManager.verifyPassword(pwData)) {
+               return 1;
+       }
+
+       return 0;
 }
 
 int ExtensionEncryption::getState()
 {
-       return -1;
+       std::lock_guard<std::mutex> guardLock(apiGuard);
+       std::unique_lock<std::mutex> stateLock(stateGuard);
+
+       return getStatePriv();
+}
+
+void ExtensionEncryption::logStoragedEvent(Operation op, Device d)
+{
+       DEBUG("Storaged event:");
+
+       switch(op) {
+       case Operation::ADDED:
+               DEBUG("   Operation: ADDED");
+               break;
+       case Operation::CHANGED:
+               DEBUG("   Operation: CHANGED");
+               break;
+       case Operation::REMOVED:
+               DEBUG("   Operation: REMOVED");
+               break;
+       default:
+               break;
+       }
+
+       switch(d) {
+       case Device::MMC:
+               DEBUG("   Device: MMC");
+               break;
+       case Device::MAP:
+               DEBUG("   Device: MAP");
+               break;
+       default:
+               break;
+       }
+
+       DEBUG("   Mnt Path: " + info[d].mntPath);
+       DEBUG("   Fs Type: " + info[d].fsType);
+       DEBUG("   Sys path: " + info[d].sysPath);
+       DEBUG("   Mounted: " + std::to_string(info[d].mounted));
+       DEBUG("   ID: " + std::to_string(info[d].storagedId));
+}
+
+void ExtensionEncryption::handleDevice(Operation op,
+                                                                          const std::vector<int> &intparams,
+                                                                          const std::vector<char*> &strparams)
+{
+       Device d;
+
+       if (std::string(strparams[0]) == EXTENSION_DEV_PATH && intparams[0] == 1) {
+               d = Device::MMC;
+       } else if (std::string(strparams[0]) == EXTENSION_MAP_PATH && intparams[0] == 2) {
+               d = Device::MAP;
+       } else {
+               DEBUG("Storaged event: neither extension MMC nor extension mapping, ignoring");
+               return;
+       }
+
+       std::unique_lock<std::mutex> stateLock(stateGuard);
+
+       if (op == Operation::REMOVED) {
+               info[d].clear();
+       } else {
+               info[d].mntPath = strparams[6];
+               info[d].fsType = strparams[3];
+               info[d].sysPath = strparams[1];
+               info[d].mounted = intparams[2];
+               info[d].storagedId = intparams[5];
+       }
+
+       logStoragedEvent(op, d);
+
+       // removing/reformatting the SD card does not automatically close the DM crypt mapping
+       if (d == Device::MMC && (op == Operation::REMOVED ||
+                                                        (op == Operation::CHANGED &&
+                                                         info[d].fsType != EXTENSION_FS_TYPE))) {
+               if (isMounted()) {
+                       INFO("MMC card removed while still mounted, umounting.");
+                       if (!findKillAndUmount(EXTENSION_MAP_PATH)) {
+                               return;
+                       }
+               }
+
+               if (isOpened()) {
+                       INFO("MMC card removed while LUKS is still opened, closing.");
+                       try {
+                               CryptsetupEngine::close(EXTENSION_NAME);
+                       } catch (runtime::Exception &e) {
+                               ERROR("Closing failed: " + std::string(e.what()));
+                               return;
+                       }
+               }
+
+               return;
+       }
+
+       if (d == Device::MMC && op == Operation::ADDED &&
+               getStatePriv() == State::Encrypted) {
+               // TODO: when UI gets written it should be triggered here.
+
+               return;
+       }
+
+       if (d == Device::MAP && op == Operation::CHANGED) {
+               if ((currentReq == Request::MOUNT  &&  info[Device::MAP].mounted) ||
+                       (currentReq == Request::UMOUNT && !info[Device::MAP].mounted)) {
+
+                       currentReq = Request::NONE;
+                       stateLock.unlock();
+                       storagedCv.notify_one();
+
+                       return;
+               }
+       }
+}
+
+void ExtensionEncryption::parseVariant(Operation op, dbus::Variant parameters)
+{
+       std::vector<int> intparams(6);
+       std::vector<char*> strparams(7);
+
+       parameters.get("(issssssisibii)",
+                                  &intparams[0], // block type: 0 - scsi, 1 : mmc, 2 : mapper
+                                  &strparams[0], // devnode
+                                  &strparams[1], // syspath
+                                  &strparams[2], // usage
+                                  &strparams[3], // fs type
+                                  &strparams[4], // fs version
+                                  &strparams[5], // fs uuid enc
+                                  &intparams[1], // readonly: 0 - rw, 1 - ro
+                                  &strparams[6], // mount point
+                                  &intparams[2], // state: 0 - unmount, 1 - mount
+                                  &intparams[3], // primary: 0 - false, 1 - true
+                                  &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
+                                  &intparams[5]); // storage id
+
+       handleDevice(op, intparams, strparams);
+}
+
+void ExtensionEncryption::queryStoraged()
+{
+       INFO("Querying the storaged for devices...");
+
+       dbus::VariantIterator vi;
+
+       try {
+               dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
+                                                                                                STORAGED_DBUS_OBJECT,
+                                                                                                STORAGED_DBUS_INTERFACE,
+                                                                                                "GetDeviceList",
+                                                                                                -1,
+                                                                                                "(a(issssssisibii))",
+                                                                                                "(s)",
+                                                                                                "all").get("(a(issssssisibii))", &vi);
+       } catch (runtime::Exception &e) {
+               ERROR("Failed to query storaged: " + std::string(e.what()));
+       }
+
+       std::vector<int> intparams(6);
+       std::vector<char*> strparams(7);
+
+       while(vi.get("(issssssisibii)",
+                                &intparams[0], // block type: 0 - scsi, 1 : mmc, 2 : mapper
+                                &strparams[0], // devnode
+                                &strparams[1], // syspath
+                                &strparams[2], // usage
+                                &strparams[3], // fs type
+                                &strparams[4], // fs version
+                                &strparams[5], // fs uuid enc
+                                &intparams[1], // readonly: 0 - rw, 1 - ro
+                                &strparams[6], // mount point
+                                &intparams[2], // state: 0 - unmount, 1 - mount
+                                &intparams[3], // primary: 0 - false, 1 - true
+                                &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
+                                &intparams[5])) // storage id
+       {
+               handleDevice(Operation::ADDED, intparams, strparams);
+       }
+}
+
+void ExtensionEncryption::subscribeToStoraged()
+{
+       dbus::Connection &systemDBus = dbus::Connection::getSystem();
+
+       auto subscribe = [&systemDBus, this](Operation op, const std::string &method) {
+               dbus::Connection::SignalCallback callback =
+               std::bind(&ExtensionEncryption::parseVariant,
+                                 this,
+                                 op,
+                                 std::placeholders::_1);
+
+               subId[op] = systemDBus.subscribeSignal("",
+                                                                                          STORAGED_DBUS_OBJECT,
+                                                                                          STORAGED_DBUS_INTERFACE,
+                                                                                          method.c_str(),
+                                                                                          callback);
+       };
+
+       subscribe(Operation::ADDED, "DeviceAdded");
+       subscribe(Operation::CHANGED, "DeviceChanged");
+       subscribe(Operation::REMOVED, "DeviceRemoved");
+}
+
+void ExtensionEncryption::unsubscribeFromStoraged()
+{
+       dbus::Connection &systemDBus = dbus::Connection::getSystem();
+
+       systemDBus.unsubscribeSignal(subId[Operation::ADDED]);
+       systemDBus.unsubscribeSignal(subId[Operation::CHANGED]);
+       systemDBus.unsubscribeSignal(subId[Operation::REMOVED]);
+}
+
+bool ExtensionEncryption::storagedMount(std::unique_lock<std::mutex> &lock)
+{
+       currentReq = Request::MOUNT;
+
+       int ret = -1;
+       try {
+               dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
+                                                                                                STORAGED_DBUS_OBJECT,
+                                                                                                STORAGED_DBUS_INTERFACE,
+                                                                                                "Mount",
+                                                                                                -1,
+                                                                                                "(i)",
+                                                                                                "(is)",
+                                                                                                info[Device::MAP].storagedId,
+                                                                                                info[Device::MAP].mntPath.c_str()).get("(i)", &ret);
+       } catch (runtime::Exception &e) {
+               ERROR("Failed to call mount in storaged: " + std::string(e.what()));
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       if (ret != 0) {
+               ERROR("Storaged failed to mount: " + std::to_string(ret));
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       if (!storagedCv.wait_for(lock, std::chrono::seconds(1), [this] {
+                               return currentReq == Request::NONE;
+                       })) {
+               ERROR("Storaged timed out mounting the MAP.");
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       return true;
+}
+
+bool ExtensionEncryption::storagedUnmount(std::unique_lock<std::mutex> &lock)
+{
+       currentReq = Request::UMOUNT;
+
+       int ret = -1;
+       try {
+               dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
+                                                                                                STORAGED_DBUS_OBJECT,
+                                                                                                STORAGED_DBUS_INTERFACE,
+                                                                                                "Unmount",
+                                                                                                -1,
+                                                                                                "(i)",
+                                                                                                "(ii)",
+                                                                                                info[Device::MAP].storagedId,
+                                                                                                0).get("(i)", &ret);
+       } catch (runtime::Exception &e) {
+               ERROR("Failed to call unmount in storaged: " + std::string(e.what()));
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       if (ret != 0) {
+               ERROR("Storaged failed to unmount: " + std::to_string(ret));
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       if (!storagedCv.wait_for(lock, std::chrono::seconds(1), [this] {
+                               return currentReq == Request::NONE;
+                       })) {
+               ERROR("Storaged timed out unmounting the MAP.");
+               currentReq = Request::NONE;
+               return false;
+       }
+
+       return true;
+}
+
+int ExtensionEncryption::getStatePriv() const
+{
+       if (!isInserted()) {
+               ERROR("Cannot check state, card not inserted");
+               return -1;
+       }
+
+       if (info[Device::MMC].fsType == EXTENSION_FS_TYPE)
+               return State::Encrypted;
+
+       return State::Corrupted;
+}
+
+bool ExtensionEncryption::isInserted() const
+{
+       return info[Device::MMC].storagedId >= 0;
+}
+
+bool ExtensionEncryption::isOpened() const
+{
+       return info[Device::MAP].storagedId >= 0;
+}
+
+bool ExtensionEncryption::isMounted() const
+{
+       return info[Device::MAP].mounted;
 }
 
 } // namespace ode
index 350ef2b..70a4aa5 100644 (file)
@@ -67,7 +67,7 @@ void externalCallback(dbus::Variant parameters)
        char* strparams[7];
 
        parameters.get("(issssssisibii)",
-               &intparams[0], // block type: 0 - scsi, 1 : mmc
+               &intparams[0], // block type: 0 - scsi, 1 : mmc, 2 : mapper
                &strparams[0], // devnode
                &strparams[1], // syspath
                &strparams[2], // usage
@@ -81,6 +81,14 @@ void externalCallback(dbus::Variant parameters)
                &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
                &intparams[5]); // strage id
 
+       // TODO: this implementation probably would do better if it was on par with
+       // ExtensionEncryption in terms of how it detects and reacts to card events
+       if (intparams[0] != 1 || (std::string(strparams[3]) != "vfat" &&
+                                                         std::string(strparams[3]) != "ext4")) {
+               DEBUG("Storaged says it's not a regular SD card. Ignoring.");
+               return;
+       }
+
        if(intparams[2] == 0) {
                INFO("Unmounted");
        } else {
index 4dada85..5d6ab6b 100644 (file)
@@ -45,6 +45,8 @@ Server::Server()
        audit::Logger::setBackend(new audit::DlogLogSink());
        audit::Logger::setTag("ODE");
 
+       INFO("ODE server starting.");
+
        service.reset(new rmi::Service(ODE_MANAGER_ADDRESS));
 
        service->setPrivilegeChecker(std::bind(&Server::checkPeerPrivilege, this, _1, _2));