* 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/dbus/variant.h>
-#include <klay/dbus/connection.h>
-
-#include "logger.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 size_t DEFAULT_KEY_SIZE = 64;
-
-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(SINK, "Close process - " + std::to_string(pid));
- ::kill(pid, SIGKILL);
- }
-}
-
-bool findKillAndUmount(const std::string &devPath)
-{
- std::string realMntPath = findMntPath(devPath);
- if (!realMntPath.empty()) {
- INFO(SINK, "Closing all applications using an SD card...");
- killDependedApplications(realMntPath);
-
- int ret = ::umount(realMntPath.c_str());
- if (ret != 0) {
- ERROR(SINK, "The card is still mounted, umount failed with: "
- + std::to_string(ret));
- return false;
- }
- }
-
- return true;
-}
-
-} // namsepace
-
ExtensionEncryption::ExtensionEncryption(ODEControlContext &ctx) :
- context(ctx),
- currentReq(Request::NONE)
+ context(ctx)
{
- 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)
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
- std::unique_lock<std::mutex> stateLock(stateGuard);
-
- if (getStatePriv() != State::Encrypted) {
- ERROR(SINK, "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(SINK, "Wrong password passed.");
- return -2;
- }
-
- if (isMounted()) {
- INFO(SINK, "Already mounted");
- return 0;
- }
-
- KeyManager::data mountKey = keyManager.getMasterKey(pwData);
-
- INFO(SINK, "Mount extension storage...");
-
- if (!isOpened()) {
- // Storaged will mount MAP automatically when it appears, let's prepare
- currentReq = Request::MOUNT;
-
- try {
- INFO(SINK, "Open the MAP of an extension storage...");
- engine->open(CryptsetupEngine::DeviceType::LUKS, EXTENSION_NAME, mountKey);
- } catch (runtime::Exception &e) {
- ERROR(SINK, "Open failed: " + std::string(e.what()));
- return -3;
- }
-
- INFO(SINK, "Wait for the storaged to mount the MAP automatically...");
- if (!storagedCv.wait_for(stateLock, std::chrono::seconds(1), [this] {
- return currentReq == Request::NONE;
- })) {
- ERROR(SINK, "Storaged timed out mounting the MAP.");
- return -3;
- }
- } else {
- INFO(SINK, "Ask storaged to mount extension storage...");
- if (!storagedMount(stateLock)) {
- return -3;
- }
- }
-
- context.notify("ExtensionEncryption::mount");
- return 0;
+ return -1;
}
int ExtensionEncryption::umount()
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
- std::unique_lock<std::mutex> stateLock(stateGuard);
-
- if (getStatePriv() != State::Encrypted) {
- ERROR(SINK, "Cannot umount, card not inserted or corrupted.");
- return -1;
- }
-
- if (!isMounted() && !isOpened()) {
- INFO(SINK, "Already umounted.");
- return 0;
- }
-
- INFO(SINK, "Umount extension storage...");
-
- if (isMounted()) {
- INFO(SINK, "Close all applications using extension storage...");
- killDependedApplications(info[Device::MAP].mntPath);
-
- INFO(SINK, "Ask storaged to umount extension storage...");
- if (!storagedUnmount(stateLock)) {
- return -3;
- }
- }
-
- if (isOpened()) {
- INFO(SINK, "Close the MAP of an extension storage...");
- try {
- CryptsetupEngine::close(EXTENSION_NAME);
- } catch (runtime::Exception &e) {
- ERROR(SINK, "Close failed: " + std::string(e.what()));
- return -3;
- }
- }
-
- return 0;
+ return -1;
}
int ExtensionEncryption::format(const std::string &password)
{
- 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(SINK, "There is no card inserted.");
- status = -1;
- stateLock.unlock();
- workerCv.notify_one();
- return;
- }
-
- if (isMounted() || isOpened()) {
- ERROR(SINK, "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(SINK, "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(SINK, "Creating LUKS...");
- engine->format(CryptsetupEngine::DeviceType::LUKS, masterKey);
-
- INFO(SINK, "Opening LUKS...");
- std::string mappingPath = engine->open(CryptsetupEngine::DeviceType::LUKS,
- EXTENSION_NAME,
- masterKey);
-
- INFO(SINK, "Creating EXT4...");
- Ext4Tool::mkfs(mappingPath);
-
- INFO(SINK, "Closing up the operation...");
- CryptsetupEngine::close(EXTENSION_NAME);
- sync();
-
- INFO(SINK, "Formatting completed");
- } catch (runtime::Exception &e) {
- ERROR(SINK, "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(SINK, "Timed out waiting for format status.");
- return -4;
- }
-
- if (status < 0)
- return status;
-
- return 0;
+ return -1;
}
int ExtensionEncryption::isPasswordInitialized()
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
-
- if (engine->isKeyMetaSet()) {
- return 1;
- }
-
- return 0;
+ return -1;
}
int ExtensionEncryption::initPassword(const std::string& password)
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
-
- KeyManager::data pwData(password.begin(), password.end());
- KeyManager keyManager;
-
- keyManager.initPassword(pwData, DEFAULT_KEY_SIZE);
- engine->setKeyMeta(keyManager.serialize());
- return 0;
+ return -1;
}
int ExtensionEncryption::cleanPassword(const std::string& password)
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
-
- KeyManager::data pwData(password.begin(), password.end());
- KeyManager keyManager(engine->getKeyMeta());
-
- if (!keyManager.verifyPassword(pwData)) {
- ERROR(SINK, "Wrong password passed.");
- return -2;
- }
-
- engine->clearKeyMeta();
- return 0;
+ return -1;
}
int ExtensionEncryption::changePassword(const std::string &oldPassword,
const std::string &newPassword)
{
- 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(SINK, "Wrong password passed.");
- return -2;
- }
-
- keyManager.changePassword(oldPwData, newPwData);
- engine->setKeyMeta(keyManager.serialize());
-
- return 0;
+ return -1;
}
int ExtensionEncryption::verifyPassword(const std::string& password)
{
- 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;
+ return -1;
}
int ExtensionEncryption::getState()
{
- std::lock_guard<std::mutex> guardLock(apiGuard);
- std::unique_lock<std::mutex> stateLock(stateGuard);
-
- return getStatePriv();
-}
-
-void ExtensionEncryption::logStoragedEvent(Operation op, Device d)
-{
- DEBUG(SINK, "Storaged event:");
-
- switch(op) {
- case Operation::ADDED:
- DEBUG(SINK, " Operation: ADDED");
- break;
- case Operation::CHANGED:
- DEBUG(SINK, " Operation: CHANGED");
- break;
- case Operation::REMOVED:
- DEBUG(SINK, " Operation: REMOVED");
- break;
- default:
- break;
- }
-
- switch(d) {
- case Device::MMC:
- DEBUG(SINK, " Device: MMC");
- break;
- case Device::MAP:
- DEBUG(SINK, " Device: MAP");
- break;
- default:
- break;
- }
-
- DEBUG(SINK, " Mnt Path: " + info[d].mntPath);
- DEBUG(SINK, " Fs Type: " + info[d].fsType);
- DEBUG(SINK, " Sys path: " + info[d].sysPath);
- DEBUG(SINK, " Mounted: " + std::to_string(info[d].mounted));
- DEBUG(SINK, " 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(SINK, "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(SINK, "MMC card removed while still mounted, umounting.");
- if (!findKillAndUmount(EXTENSION_MAP_PATH)) {
- return;
- }
- }
-
- if (isOpened()) {
- INFO(SINK, "MMC card removed while LUKS is still opened, closing.");
- try {
- CryptsetupEngine::close(EXTENSION_NAME);
- } catch (runtime::Exception &e) {
- ERROR(SINK, "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(SINK, "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(SINK, "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(SINK, "Failed to call mount in storaged: " + std::string(e.what()));
- currentReq = Request::NONE;
- return false;
- }
-
- if (ret != 0) {
- ERROR(SINK, "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(SINK, "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(SINK, "Failed to call unmount in storaged: " + std::string(e.what()));
- currentReq = Request::NONE;
- return false;
- }
-
- if (ret != 0) {
- ERROR(SINK, "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(SINK, "Storaged timed out unmounting the MAP.");
- currentReq = Request::NONE;
- return false;
- }
-
- return true;
-}
-
-int ExtensionEncryption::getStatePriv() const
-{
- if (!isInserted()) {
- ERROR(SINK, "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;
+ return -1;
}
} // namespace ode