SET(SYSTEMD_UNIT_DIR "${CMAKE_INSTALL_PREFIX}/lib/systemd/system")
ENDIF(NOT DEFINED SYSTEMD_UNIT_DIR)
+IF(NOT DEFINED SOFTRESET_DIR)
+ SET(SOFTRESET_DIR "/usr/system/RestoreDir/softreset")
+ENDIF(NOT DEFINED SOFTRESET_DIR)
+
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)
--- /dev/null
+#!/bin/bash
+# RW Update Script for 3.0 -> 4.0 and 4.0 -> 4.0
+# Update ode status whenever doing FOTA
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+source /usr/share/upgrade/rw-update-macro.inc
+get_version_info
+
+ODE_STATE=`vconftool get -t string db/ode/crypto_state`
+ODE_STATE=${ODE_STATE#*=}
+ODE_STATE=${ODE_STATE%(*}
+
+if [ $ODE_STATE = "notsupported" ]; then
+vconftool set -f -t string db/ode/crypto_state "unencrypted"
+elif [ $ODE_STATE = "mounted" ]; then
+vconftool set -f -t string db/ode/crypto_state "encrypted"
+fi
+
+if [ -e /opt/etc/ode_footer ]; then
+ touch /opt/etc/.ode_upgrade_started
+ rm -f /opt/etc/ode_footer
+fi
SET(PROJECT_NAME "ode-fota")
-PKG_CHECK_MODULES(FOTA_DEPS REQUIRED klay)
+PKG_CHECK_MODULES(FOTA_DEPS REQUIRED klay-static blkid)
SET(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/fota.cpp
${ODE_SERVER}/upgrade-support.cpp
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIE")
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-pie")
-INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${SBIN_DIR})
\ No newline at end of file
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${SBIN_DIR})
+INSTALL(FILES ode_softreset.sh DESTINATION ${SOFTRESET_DIR})
+INSTALL(FILES 500.ode_upgrade.sh DESTINATION ${UPGRADE_SCRIPT_DIR})
* See the License for the specific language governing permissions and
* limitations under the License
*/
-
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include <stdlib.h>
+#include <strings.h>
+#include <blkid.h>
#include <string>
#include <iostream>
namespace ode {
+struct AbstractDevice {
+ AbstractDevice() {}
+ virtual ~AbstractDevice() {}
+ virtual std::string findNode(const std::string &name) = 0;
+};
+
+struct MmcDevice : public AbstractDevice {
+public:
+ MmcDevice(int id) : device("/dev/mmcblk" + std::to_string(id)), deviceHandle(-1)
+ {
+ deviceHandle = ::open(device.c_str(), O_RDONLY);
+ if (deviceHandle == -1)
+ throw std::runtime_error("Invalid device: " + device);
+ }
+
+ virtual ~MmcDevice()
+ {
+ if (deviceHandle != -1)
+ ::close(deviceHandle);
+ }
+
+ virtual std::string findNode(const std::string &name)
+ {
+ blkid_partlist partlist;
+ blkid_probe probe;
+ int partno = 0;
+
+ probe = ::blkid_new_probe();
+ if (!probe) {
+ throw std::runtime_error("Failed to call blkid_new_probe");
+ }
+
+ if (::blkid_probe_set_device(probe, deviceHandle, 0, 0) < 0) {
+ ::blkid_free_probe(probe);
+ throw std::runtime_error("Failed to set prove device: " + device);
+ }
+
+ partlist = ::blkid_probe_get_partitions(probe);
+ if (!partlist) {
+ ::blkid_free_probe(probe);
+ throw std::runtime_error("Failed to get partition list in device: " + device);
+ }
+
+ int num = ::blkid_partlist_numof_partitions(partlist);
+ for (int i = 1; i <= num; i++) {
+ blkid_partition par = ::blkid_partlist_get_partition(partlist, i);
+
+ const char *n = ::blkid_partition_get_name(par);
+ if (!n)
+ break;
+
+ if (::strcasecmp(n, name.c_str()) == 0) {
+ partno = ::blkid_partition_get_partno(par);
+ break;
+ }
+ }
+
+ ::blkid_free_probe(probe);
+
+ if (partno <= 0) {
+ throw std::runtime_error("Failed to get partition number with " + name);
+ }
+
+ return device + "p" + std::to_string(partno);
+ }
+
+private:
+ std::string device;
+ int deviceHandle;
+};
+
// dummy implementation
ProgressBar::ProgressBar(UpdateFunc const&) : updateValue(0) {}
ProgressBar::~ProgressBar() {}
namespace {
const std::string MOUNT = "mount";
+const std::string UMOUNT = "umount";
const std::string REMOVE = "remove";
-const std::string DEV_PATH = ode::findDevPath();
-
void usage()
{
std::cout <<
"Usage: ode-fota [Operation]" << std::endl <<
std::endl <<
"Operations :" << std::endl <<
- " mount Mount internal memory using stored master key" << std::endl <<
- " remove Remove stored internal memory master key" << std::endl;
+ " mount [path] Mount internal memory using stored master key" << std::endl <<
+ " umount [path] Unmount internal memory" << std::endl <<
+ " remove Remove stored internal memory master key" << std::endl;
}
} // anonymous namespace
try {
using namespace ode;
- if (argc < 2) {
+ if (argc < 2 || argc > 3) {
usage();
return EXIT_FAILURE;
}
+ MmcDevice dev(0);
+ std::string devpath = dev.findNode("user");
+
if (MOUNT == argv[1]) {
- auto masterKey = UpgradeSupport::loadMasterKey(DEV_PATH);
+ auto masterKey = UpgradeSupport::loadMasterKey(devpath);
+ std::string path = INTERNAL_PATH;
+ if (argc == 3)
+ path = argv[2];
- DMCryptEngine dmcrypt(DEV_PATH, INTERNAL_PATH, ProgressBar([](unsigned){}));
+ DMCryptEngine dmcrypt(devpath, path, ProgressBar([](unsigned){}));
// mount options are ignored by mount()
dmcrypt.mount(masterKey, 0);
+ UpgradeSupport::createUpgradeFlag();
+ } else if (UMOUNT == argv[1]) {
+ std::string path = INTERNAL_PATH;
+ if (argc == 3)
+ path = argv[2];
+
+ DMCryptEngine dmcrypt(devpath, path, ProgressBar([](int){}));
+ dmcrypt.umount();
} else if (REMOVE == argv[1]) {
- UpgradeSupport::removeMasterKey(DEV_PATH);
+ UpgradeSupport::removeMasterKey(devpath);
} else {
usage();
return EXIT_FAILURE;
--- /dev/null
+#!/bin/bash
+
+# ode footer and key tokens
+METAFILE=`ls /opt/etc/.ode_*`
+
+# vconf keys required by ode
+VCONFKEYS="db/ode/crypto_blkdev db/ode/crypto_state db/ode/crypto_type db/ode/encrypt_progress db/ode/fast_encryption"
+
+for file in $METAFILE; do
+/usr/bin/pkg -k $file
+done
+
+for key in $VCONFKEYS; do
+/usr/bin/pkg -v $key
+done
}
}
-int InternalEncryptionClient::mount()
+int InternalEncryptionClient::mount(const std::vector<unsigned char> &mk, unsigned int options)
{
try {
- return context->methodCall<int>("InternalEncryptionServer::mount");
+ return context->methodCall<int>("InternalEncryptionServer::mount", mk, options);
+ } catch (runtime::Exception& e) {
+ return error::Unknown;
+ }
+}
+
+int InternalEncryptionClient::isMounted()
+{
+ try {
+ return context->methodCall<int>("InternalEncryptionServer::isMounted");
} catch (runtime::Exception& e) {
return error::Unknown;
}
#define __INTERNAL_ENCRYPTION_CLIENT_H__
#include <string>
+#include <vector>
#include "rmi/internal-encryption.h"
#include "client.h"
int setMountPassword(const std::string& password);
- int mount();
+ int mount(const std::vector<unsigned char> &mk, unsigned int options);
int umount();
+ int isMounted();
int encrypt(const std::string& password, unsigned int options);
int decrypt(const std::string& password);
* @since_tizen 4.0
*/
typedef enum {
- ODE_STATE_UNENCRYPTED = 0x00, /**< Device is not encrypted */
- ODE_STATE_ENCRYPTED = 0x01, /**< Device is encrypted */
- ODE_STATE_CORRUPTED = 0x02, /**< Device is corrupted because of encryption error */
+ ODE_STATE_NOT_SUPPORTED = -1,
+ ODE_STATE_UNENCRYPTED = 0, /**< Device is not encrypted */
+ ODE_STATE_ENCRYPTED = 1, /**< Device is encrypted */
+ ODE_STATE_CORRUPTED = 2, /**< Device is corrupted because of encryption error */
} ode_state_e;
/**
RET_ON_FAILURE(client.connect() == 0, ODE_ERROR_CONNECTION_REFUSED);
InternalEncryptionClient internal = client.createInterface<InternalEncryptionClient>();
- return toApiError(internal.mount());
+ return toApiError(internal.mount(std::vector<unsigned char>(), 0));
+}
+
+int ode_internal_encryption_mount_ex(const unsigned char *mk, unsigned int options)
+{
+ size_t key_len = options == 0 ? 32 : 64;
+ std::vector<unsigned char> key(mk, mk + key_len);
+ ClientContext client;
+ RET_ON_FAILURE(client.connect() == 0, ODE_ERROR_CONNECTION_REFUSED);
+ InternalEncryptionClient internal = client.createInterface<InternalEncryptionClient>();
+
+ return toApiError(internal.mount(key, options));
+}
+
+int ode_internal_encryption_is_mounted(bool *result)
+{
+ ClientContext client;
+ RET_ON_FAILURE(client.connect() == 0, ODE_ERROR_CONNECTION_REFUSED);
+ InternalEncryptionClient internal = client.createInterface<InternalEncryptionClient>();
+ int ret = internal.isMounted();
+ if (ret < 0)
+ return toApiError(ret);
+
+ *result = ret == 1 ? true : false;
+
+ return ODE_ERROR_NONE;
}
int ode_internal_encryption_umount()
ODE_API int ode_internal_encryption_mount();
/**
+ * @brief Mount internal storage with encryption
+ * @details Administrator can use this API to mount encrypted internal
+ * storage.
+ * @since_tizen 4.0
+ * @param[in] mk Master key used to mount internal storage
+ * @param[in] options Mount options
+ * @return #ODE_ERROR_NONE on success, otherwise a negative value
+ * @retval #ODE_ERROR_NONE Successful
+ * @retval #ODE_ERROR_NO_SUCH_DEVICE Internal storage is not encrypted
+ * @retval #ODE_ERROR_NO_DATA Password isn't set
+ * @retval #ODE_ERROR_PERMISSION_DENIED The application does not have
+ * the privilege to call this API
+ * @retval #ODE_ERROR_CONNECTION_REFUSED Connection to the server failed
+ * @retval #ODE_ERROR_UNKNOWN Unknown error
+ * @see ode_internal_encryption_umount()
+ */
+
+ODE_API int ode_internal_encryption_mount_ex(const unsigned char *mk, unsigned int option);
+
+/**
+ * @brief Check whether the encrypted internal storage is mounted
+ * @details Administrator can use this API to get the current mount state
+ * of encrypted internal storage.
+ * @since_tizen 4.0
+ * @param[out] result Whether the encrypted internal storage is mounted
+ * @return #ODE_ERROR_NONE on success, otherwise a negative value
+ * @retval #ODE_ERROR_NONE Successful
+ * @retval #ODE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ODE_ERROR_CONNECTION_REFUSED Connection to the server failed
+ * @retval #ODE_ERROR_UNKNOWN Unknown error
+ * @see ode_internal_encryption_mount()
+ */
+ODE_API int ode_internal_encryption_is_mounted(bool *result);
+
+/**
* @brief Umount internal storage
* @details Administrator can use this API to unmount internal storage.
* @since_tizen 4.0
* @retval #ODE_ERROR_UNKNOWN Unknown error
*/
ODE_API int ode_internal_encryption_get_device_path(char** device);
-
/*
* @}
*/
BuildRequires: cmake
BuildRequires: gettext-tools
BuildRequires: pkgconfig(klay)
+BuildRequires: pkgconfig(vconf)
BuildRequires: pkgconfig(glib-2.0)
-BuildRequires: pkgconfig(aul)
-BuildRequires: pkgconfig(bundle)
BuildRequires: pkgconfig(libtzplatform-config)
BuildRequires: pkgconfig(cynara-client)
BuildRequires: pkgconfig(libcrypto)
BuildRequires: pkgconfig(libsmack)
+BuildRequires: pkgconfig(blkid)
+BuildRequires: pkgconfig(capi-system-device)
+BuildRequires: pkgconfig(libsystemd)
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/
%description
The ode package provides a daemon which is responsible for encrypting/decryption storages and secure erasing.
%{_unitdir}/ode.service
%{_unitdir}/multi-user.target.wants/ode.service
%attr(700,root,root) %{TZ_SYS_SBIN}/ode-admin-cli
-%attr(700,root,root) %{TZ_SYS_SBIN}/ode-fota
+%attr(700,root,root) %{softreset_dir}/ode_softreset.sh
+%attr(750,root,system_share) %{TZ_SYS_SBIN}/ode-fota
%{_datadir}/%{name}
%dir %{key_storage_plugin_dir}
+%attr(755,root,root) %{upgrade_script_dir}/500.ode_upgrade.sh
%prep
%setup -q
-DSYSTEMD_UNIT_DIR=%{_unitdir} \
-DAPP_INSTALL_PREFIX="%{TZ_SYS_RO_APP}" \
-DAPP_SHARE_PACKAGES_DIR="%{TZ_SYS_RO_PACKAGES}" \
- -DKEY_STORAGE_PLUGIN_DIR="%{key_storage_plugin_dir}"
+ -DSOFTRESET_DIR="%{softreset_dir}" \
+ -DKEY_STORAGE_PLUGIN_DIR="%{key_storage_plugin_dir}" \
+ -DUPGRADE_SCRIPT_DIR="%{upgrade_script_dir}"
make %{?jobs:-j%jobs}
virtual int verifyPassword(const std::string& password) = 0;
enum State {
- Unencrypted = 0x00,
- Encrypted = 0x01,
- Corrupted = 0x02,
- Invalid = 0x03,
+ NotSupported = -1,
+ Unencrypted = 0,
+ Encrypted = 1,
+ Corrupted = 2,
};
virtual int getState() = 0;
#define __INTERNAL_ENCRYPTION_H__
#include <string>
+#include <vector>
namespace ode {
virtual int setMountPassword(const std::string& password) = 0;
- virtual int mount() = 0;
+ virtual int mount(const std::vector<unsigned char>& mk, unsigned int options) = 0;
virtual int umount() = 0;
+ virtual int isMounted() = 0;
virtual int encrypt(const std::string& password, unsigned int options) = 0;
virtual int decrypt(const std::string& password) = 0;
virtual int verifyPassword(const std::string& password) = 0;
enum State {
- Unencrypted = 0x00,
- Encrypted = 0x01,
- Corrupted = 0x02,
- Invalid = 0x03,
+ NotSupported = -1,
+ Unencrypted = 0,
+ Encrypted = 1,
+ Corrupted = 2,
};
virtual int getState() = 0;
#
-# 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.
#
SET(SERVER_SRCS main.cpp
server.cpp
- launchpad.cpp
misc.cpp
ext4-tool.cpp
- app-bundle.cpp
file-footer.cpp
+ file-sink.cpp
secure-erase.cpp
progress-bar.cpp
kernel-keyring.cpp
)
SET(DEPENDENCY klay
+ vconf
glib-2.0
gio-2.0
- aul
- bundle
libtzplatform-config
cynara-client
libcrypto
libsmack
+ capi-system-device
+ libsystemd
)
SET(SERVER_NAME ${PROJECT_NAME}d)
+++ /dev/null
-/*
- * Copyright (c) 2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-#include <memory>
-
-#include <klay/exception.h>
-
-#include "app-bundle.h"
-
-AppBundle::AppBundle() :
- handle(nullptr)
-{
- handle = ::bundle_create();
- if (handle == nullptr) {
- throw runtime::Exception("Failed to create bundle");
- }
-}
-
-AppBundle::~AppBundle()
-{
- ::bundle_free(handle);
-}
-
-void AppBundle::addInternal(const std::string& key, const std::string& value)
-{
- ::bundle_add_str(handle, key.c_str(), value.c_str());
-}
-
-void AppBundle::addArrayInternal(const std::string& key, const std::vector<std::string>& array)
-{
- std::unique_ptr<const char*[]> arrayptr(new const char*[array.size()]);
-
- int index = 0;
- for (const std::string& data : array) {
- arrayptr.get()[index++] = data.c_str();
- }
-
- ::bundle_add_str_array(handle, key.c_str(), arrayptr.get(), array.size());
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifndef __DPM_APP_BUNDLE_H__
-#define __DPM_APP_BUNDLE_H__
-
-#include <string>
-#include <vector>
-
-#include <bundle.h>
-
-class AppBundle {
-public:
- AppBundle();
- ~AppBundle();
-
- template<typename T>
- void add(const std::string& key, const std::vector<T>& value)
- {
- addArrayInternal(key, value);
- }
-
- template<typename T>
- void add(const std::string& key, const T& value)
- {
- addInternal(key, value);
- }
-
- bundle* get() const
- {
- return handle;
- }
-
-private:
- void addInternal(const std::string& key, const std::string& value);
- void addArrayInternal(const std::string& key, const std::vector<std::string>& array);
-
-private:
- bundle* handle;
-};
-
-#endif //__DPM_APP_BUNDLE_H__
// Create Device (mount_name)
initDMIoctl(dmBuf, DM_MAX_BUFFER_SIZE, mountName, 0);
- if (ioctl(fd, DM_DEV_CREATE, dmBuf)) {
+ if (ioctl(fd, DM_DEV_CREATE, dmBuf) && errno != EBUSY) {
throw runtime::Exception("Cannot create dm-crypt device");
}
} // namepsace
DMCryptEngine::DMCryptEngine(const std::string &src, const std::string &dest, const ProgressBar &prgsBar) :
- source(src), destination(dest), progress(prgsBar)
+ source(src), destination(dest), progress(prgsBar), start(false)
{
}
void DMCryptEngine::umount()
{
- if (::umount(destination.c_str()) && errno != EINVAL)
+ if (::umount(destination.c_str()) && errno != EINVAL && errno != ENOENT)
throw runtime::Exception(runtime::GetSystemErrorMessage());
destroyCryptoBlkDev(DM_DEFAULT_LABEL_NAME);
// create crypto type device mapping layer to mount the plain partition
// should be encrypted here.
auto cryptoBlkDev = createCryptoBlkDev(source, DM_DEFAULT_LABEL_NAME, sanitizeKey(key), DM_DEFAULT_CRYPTO_NAME);
+ start = true;
// We always do In-place encryption
copyInPlace(source, cryptoBlkDev, options, progress);
// Force filesystem check via fcsf might be able to avoid fail situation during decryption.
Ext4Tool ext4CryptoBlkDev(cryptoBlkDev);
+ start = true;
+
for (int retry = 0; retry < 32; retry++) {
try {
ext4CryptoBlkDev.forceCleanUp();
return destination;
}
+ bool isStarted()
+ {
+ return start;
+ }
+
void mount(const BinaryData &key, unsigned int options);
void umount();
bool isMounted();
private:
std::string source, destination;
ProgressBar progress;
+ bool start;
};
} // namespace ode
#include "misc.h"
#include "logger.h"
-#include "launchpad.h"
-#include "app-bundle.h"
#include "progress-bar.h"
#include "rmi/common.h"
#include "file-footer.h"
{
INFO(SINK, "Launching SD card password popup.");
try {
- AppBundle bundle;
- bundle.add("viewtype", "SD_CARD_PASSWORD");
-
- Launchpad launchpad(::tzplatform_getuid(TZ_SYS_DEFAULT_USER));
- launchpad.launch("org.tizen.ode", bundle);
+ dbus::Connection &systemDBus = dbus::Connection::getSystem();
+ std::string unit("ode-password@external.service");
+
+ systemDBus.methodcall("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartUnit",
+ -1, "", "(ss)", unit.c_str(), "replace");
} catch (runtime::Exception &e) {
ERROR(SINK, "Failed to launch SD card password popup: " + std::string(e.what()));
}
externalCallback);
systemDBus.subscribeSignal("",
- "/Org/Tizen/System/Pass/Core",
- "org.tizen.system.pass.core",
+ "/Org/Tizen/System/DeviceD/Core",
+ "org.tizen.system.deviced.core",
"BootingDone",
bootCompletionCallback);
}
else if (valueStr == "error_partially_encrypted" || valueStr == "error_partially_decrypted")
return State::Corrupted;
- return State::Invalid;
+ return State::NotSupported;
}
unsigned int ExternalEncryptionServer::getSupportedOptions()
runtime::File file(fileName);
- file.create(S_IRUSR | S_IWUSR);
+ if (!file.exists()) {
+ file.create(S_IRUSR | S_IWUSR);
+ } else {
+ file.open(O_RDWR);
+ }
+
file.write(value.data(), value.size());
}
--- /dev/null
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <chrono>
+#include <errno.h>
+
+#include "file-sink.h"
+
+namespace ode {
+
+#define MAX_LOG_LEN 16
+
+namespace {
+std::string getFileName(const std::string &path)
+{
+ std::string name;
+ auto pos = path.rfind('/');
+ pos = (pos == std::string::npos) ? 0 : pos + 1;
+ name = path.substr(pos, path.size());
+ return name;
+}
+} //namespace
+
+FileLogSink::FileLogSink(const std::string& name)
+ : path("/opt/var/log/"), fd(-1)
+{
+ path.append(getFileName(name));
+ fd = ::open(path.c_str(), O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0664);
+}
+
+FileLogSink::~FileLogSink()
+{
+ ::close(fd);
+}
+
+void FileLogSink::resize()
+{
+ std::lock_guard<std::recursive_mutex> lock(mtx);
+ struct stat st;
+ int ret = 0;
+ int blkcnt = MAX_LOG_LEN;
+ size_t blksize = 0;
+
+ if (::lstat(path.c_str(), &st) < 0) {
+ std::cerr << "Invalid log file" << std::endl;
+ return;
+ }
+
+ blksize = st.st_blksize;
+ if (blksize > 0)
+ blkcnt = (st.st_size / blksize) + 1;
+
+ if (blkcnt <= MAX_LOG_LEN)
+ return;
+
+ ret = ::fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, blksize*(blkcnt-MAX_LOG_LEN));
+ if (ret < 0)
+ std::cerr << "Failed to collapse the log file : " << errno << std::endl;
+}
+
+void FileLogSink::write(const std::string &message)
+{
+ std::lock_guard<std::recursive_mutex> lock(mtx);
+ resize();
+
+ auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ std::tm tm = {
+ .tm_sec = 0,
+ .tm_min = 0,
+ .tm_hour = 0,
+ .tm_mday = 1,
+ .tm_mon = 1,
+ .tm_year = 0,
+ .tm_wday = 0,
+ .tm_yday = 0,
+ .tm_isdst = 1,
+ };
+
+ if (::localtime_r(&now, &tm) == nullptr)
+ std::cerr << "Failed to get local time" << std::endl;
+
+ std::string log("[" + std::to_string(tm.tm_hour)
+ + ":"
+ + std::to_string(tm.tm_min)
+ + ":"
+ + std::to_string(tm.tm_sec) + "] ");
+
+ log.append(message);
+
+ size_t written = 0, size = log.size();
+ const char *data = log.c_str();
+
+ while (written < size) {
+ int bytes = ::write(fd, data + written, size-written);
+ if (bytes >= 0) {
+ written += bytes;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ continue;
+ } else {
+ std::cerr << "Failed to write log" << std::endl;
+ break;
+ }
+ }
+ ::sync();
+}
+
+void FileLogSink::sink(const std::string &message)
+{
+ auto level = message.substr(0, message.find('<'));
+ auto subMsg = message.substr(message.find(':') + 1);
+ std::string log;
+
+ switch (audit::StringToLogLevel(level)) {
+ case audit::LogLevel::Error:
+ log.append("[ERROR] : " + subMsg);
+ break;
+ case audit::LogLevel::Warning:
+ log.append("[WARN] : " + subMsg);
+ break;
+ case audit::LogLevel::Debug:
+ log.append("[DEBUG] : " + subMsg);
+ break;
+ case audit::LogLevel::Info:
+ log.append("[INFO] : " + subMsg);
+ break;
+ case audit::LogLevel::Trace:
+ log.append("[TRACE] : " + subMsg);
+ break;
+ default:
+ log.append("[SILENT] : " + subMsg);
+ break;
+ }
+
+ write(log);
+}
+
+} //namespace ode
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2018 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.
* limitations under the License
*/
-#ifndef __DPM_LAUNCHPAD_H__
-#define __DPM_LAUNCHPAD_H__
+#ifndef __ODE_FILE_LOGSINK_H__
+#define __ODE_FILE_LOGSINK_H__
#include <string>
+#include <memory>
+#include <mutex>
-#include "app-bundle.h"
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
-class Launchpad {
+namespace ode {
+
+class FileLogSink : public audit::LogSink {
public:
- Launchpad(const uid_t uid = 0);
- Launchpad(const Launchpad&) = delete;
- Launchpad(Launchpad&&) = delete;
+ explicit FileLogSink(const std::string& tag);
+ ~FileLogSink();
+ void sink(const std::string& message) override;
- void launch(const std::string& appid);
- void launch(const std::string& appid, const AppBundle& bundle);
- void resume(const std::string& appid);
- bool isRunning(const std::string& appid);
- void terminate(const std::string& appid);
+private:
+ void resize();
+ void write(const std::string &message);
private:
- uid_t user;
+ std::string path;
+ int fd;
+ std::recursive_mutex mtx;
};
-#endif //__DPM_LAUNCHPAD_H__
+} //namespace ode
+
+#endif //__ODE_FILE_LOGSINK_H__
/*
- * 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 <unistd.h>
#include <sys/mount.h>
#include <sys/reboot.h>
+#include <sys/wait.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <vconf.h>
#include <tzplatform_config.h>
+#include <device/power.h>
#include <klay/process.h>
#include <klay/file-user.h>
#include <klay/filesystem.h>
#include <klay/dbus/connection.h>
+#include <klay/dbus/signal.h>
#include <klay/error.h>
+#include <systemd/sd-bus.h>
#include "misc.h"
#include "logger.h"
#include "ext4-tool.h"
#include "internal-encryption.h"
#include "internal-encryption-common.h"
+#include "upgrade-support.h"
+#include "file-footer.h"
namespace ode {
const char *PRIVILEGE_PLATFORM = "http://tizen.org/privilege/internal/default/platform";
const mode_t MODE_0640 = S_IRUSR | S_IWUSR | S_IRGRP;
+const std::string ODE_OBJECT_PATH = "/Org/Tizen/OnDeviceEncryption";
+const std::string ODE_INTERFACE_EVENT = "org.tizen.OnDeviceEncryption.Event";
+const std::string ODE_SIGNAL_NAME = "unmount";
+const std::string manifest =
+ "<node>"
+ " <interface name='" + ODE_INTERFACE_EVENT + "'>"
+ " <signal name='" + ODE_SIGNAL_NAME + "'>"
+ " </signal>"
+ " </interface>"
+ "</node>";
// watches systemd jobs
class JobWatch {
bool JobWatch::waitForJob(const std::string& job) {
while(true) {
std::unique_lock<std::mutex> lock(jobsMutex);
- jobsCv.wait(lock, [this]{ return !removedJobs.empty(); });
+ bool timeout = true;
+ auto sec = std::chrono::seconds(1);
+ jobsCv.wait_for(lock, 5*sec, [this, &timeout]{
+ if (!removedJobs.empty()) {
+ timeout = false;
+ return true;
+ }
+ return false;});
+
+ if (timeout) {
+ ERROR(SINK, "job: " + job + ", result: time out");
+ return false;
+ }
while(!removedJobs.empty()) {
bool match = (removedJobs.front().job == job);
const char* unit;
const char* result;
parameters.get("(uoss)", &id, &job, &unit, &result);
- INFO(SINK, "id:" + std::to_string(id) + " job:" + job + " unit:" + unit + " result:" + result);
+ WARN(SINK, "id:" + std::to_string(id) + " job:" + job + " unit:" + unit + " result:" + result);
{
std::lock_guard<std::mutex> guard(jobsMutex);
jobsCv.notify_one();
}
-void stopKnownSystemdUnits()
+void stopSystemdUnits()
{
- std::vector<std::string> knownSystemdUnits;
dbus::Connection& systemDBus = dbus::Connection::getSystem();
dbus::VariantIterator iter;
+ std::vector<std::string> preprocessUnits;
+ std::set<std::string> unitsToStop;
- systemDBus.methodcall("org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits",
- -1, "(a(ssssssouso))", "")
- .get("(a(ssssssouso))", &iter);
+ try {
+ systemDBus.emitSignal("",
+ ODE_OBJECT_PATH,
+ ODE_INTERFACE_EVENT,
+ ODE_SIGNAL_NAME, "()", nullptr);
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, "Failed to emit signal : " + std::string(e.what()));
+ }
+
+ auto stopUnit = [&systemDBus](const std::string &unit) {
+ JobWatch watch(systemDBus);
+ WARN(SINK, "Stopping unit: " + unit);
+ const char* job = NULL;
+ try {
+ systemDBus.methodcall("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StopUnit",
+ -1, "(o)", "(ss)", unit.c_str(), "flush").get("(o)", &job);
+ WARN(SINK, "Waiting for job: " + std::string(job));
+ if (!watch.waitForJob(job))
+ ERROR(SINK, "Stopping unit: " + unit + " failed");
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, std::string(e.what()));
+ }
+ };
+
+ try {
+ systemDBus.methodcall("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnits",
+ -1, "(a(ssssssouso))", "").get("(a(ssssssouso))", &iter);
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, "Get list of systemd unit : " + std::string(e.what()));
+ }
while (1) {
- unsigned int dataUint;
+ unsigned int dataUnit;
char *dataStr[9];
int ret;
-
ret = iter.get("(ssssssouso)", dataStr, dataStr + 1, dataStr + 2,
dataStr + 3, dataStr + 4, dataStr + 5,
- dataStr + 6, &dataUint, dataStr + 7,
- dataStr + 8);
-
- if (!ret) {
+ dataStr + 6, &dataUnit, dataStr + 7, dataStr + 8);
+ if (!ret)
break;
- }
- std::string unit(dataStr[0]);
- if (unit == "security-manager.socket") {
- knownSystemdUnits.insert(knownSystemdUnits.begin(), unit);
- } else if (unit.compare(0, 5, "user@") == 0 ||
- unit == "tlm.service" ||
- unit == "resourced.service" ||
- unit == "security-manager.service") {
- knownSystemdUnits.push_back(unit);
+ std::string unitName(dataStr[0]);
+ if (unitName == "security-manager.socket" ||
+ unitName == "connman.socket" ||
+ unitName == "msg-server.socket") {
+ preprocessUnits.insert(preprocessUnits.begin(), unitName);
+ } else if (unitName.compare(0, 5, "user@") == 0 ||
+ unitName == "tlm.service" ||
+ unitName == "resourced.service" ||
+ unitName == "security-manager.service") {
+ preprocessUnits.push_back(unitName);
}
}
- JobWatch watch(systemDBus);
-
- for (const std::string& unit : knownSystemdUnits) {
- INFO(SINK, "Stopping unit: " + unit);
- const char* job = NULL;
- systemDBus.methodcall("org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StopUnit",
- -1, "(o)", "(ss)", unit.c_str(), "flush").get("(o)", &job);
- INFO(SINK, "Waiting for job: " + std::string(job));
- if (!watch.waitForJob(job))
- throw runtime::Exception("Stopping unit: " + unit + " failed");
+ for (auto unit : preprocessUnits) {
+ stopUnit(unit);
}
-}
-
-void stopDependedSystemdUnits()
-{
- dbus::Connection& systemDBus = dbus::Connection::getSystem();
- std::set<std::string> unitsToStop;
for (pid_t pid : runtime::FileUser::getList(INTERNAL_PATH, true)) {
+ auto pgid = ::getpgid(pid);
+ if (pgid > 0 && pid != pgid) {
+ WARN(SINK, "PGID doesn't match - pgid : " + std::to_string(pgid) + ", pid : " + std::to_string(pid));
+ continue;
+ }
+
try {
- char *unit;
+ char *unit = nullptr;
systemDBus.methodcall("org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"GetUnitByPID",
-1, "(o)", "(u)", (unsigned int)pid)
.get("(o)", &unit);
- unitsToStop.insert(unit);
+
+ char* tmp = NULL;
+ int err = sd_bus_path_decode(unit, "/org/freedesktop/systemd1/unit", &tmp);
+ if (err <= 0 || tmp == NULL) {
+ ERROR(SINK, "Failed to decode unit name: " + std::string(unit) + " error: " +
+ std::to_string(err));
+ continue;
+ }
+ std::string unescapedName(tmp);
+ free(tmp);
+
+ unitsToStop.insert(unescapedName);
} catch (runtime::Exception &e) {
- INFO(SINK, "Killing process: " + std::to_string(pid));
+ ERROR(SINK, "Killing process: " + std::to_string(pid));
::kill(pid, SIGKILL);
}
}
- JobWatch watch(systemDBus);
-
- for (const std::string& unit : unitsToStop) {
- INFO(SINK, "Stopping unit: " + unit);
- const char* job = NULL;
- systemDBus.methodcall("org.freedesktop.systemd1",
- unit,
- "org.freedesktop.systemd1.Unit",
- "Stop",
- -1, "(o)", "(s)", "flush").get("(o)", &job);
- INFO(SINK, "Waiting for job: " + std::string(job));
- if (!watch.waitForJob(job))
- throw runtime::Exception("Stopping unit: " + unit + " failed");
+ for (auto unit : unitsToStop) {
+ stopUnit(unit);
}
}
INFO(SINK, "Waiting for job: " + std::string(job));
if (!watch.waitForJob(job))
- throw runtime::Exception("Starting unit: " + unit + " failed");
+ ERROR(SINK, "Starting unit: " + unit + " failed");
}
unsigned int getOptions()
::vconf_set_bool(VCONFKEY_ODE_FAST_ENCRYPTION, value);
}
-void unmountInternalStorage(const std::string& source)
+void killProcesses(std::vector<const char*> &args)
{
- while(true) {
- auto mntPaths = findMountPointsByDevice(source);
- if(mntPaths.empty())
- break;
+ int pipeFd[2] = {0, };
+ pid_t pid = 0;
- bool unmounted = true;
- for(const auto& path : mntPaths) {
- INFO(SINK, "Unmounting " + path);
- if (::umount(path.c_str()) == -1) {
- // If it's busy or was already unmounted ignore the error
- if (errno != EBUSY && errno != EINVAL) {
- throw runtime::Exception("umount() error: " + runtime::GetSystemErrorMessage());
- }
- unmounted = false;
- }
+ if (::pipe(pipeFd) < 0)
+ throw runtime::Exception("Failed to create pipe");
+
+ pid = ::fork();
+ if (pid < 0) {
+ ::close(pipeFd[0]);
+ ::close(pipeFd[1]);
+ throw runtime::Exception("Failed to fork");
+ }
+
+ if (pid == 0) {
+ ::close(pipeFd[0]);
+ if (::dup2(pipeFd[1], STDOUT_FILENO) < 0)
+ ERROR(SINK, "Failed to copy STDOUT_FILENO");
+
+ if (::dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
+ ERROR(SINK, "Failed to copy STDERR_FILENO");
+
+ ::close(pipeFd[1]);
+
+ if (::execv(args[0], const_cast<char* const*>(args.data())) < 0)
+ ERROR(SINK, "Failed to execute : " + std::to_string(errno));
+
+ std::quick_exit(EXIT_FAILURE);
+ }
+
+ ::close(pipeFd[1]);
+
+ for (int status = 0; ::waitpid(pid, &status, 0) == -1;) {
+ if (errno != EINTR) {
+ ::close(pipeFd[0]);
+ throw runtime::Exception("Failed to wait child process");
+ }
+ }
+
+ auto closeFile = [](FILE *fp) { ::fclose(fp); };
+ std::unique_ptr<FILE, decltype(closeFile)> fp(::fdopen(pipeFd[0], "r"), closeFile);
+ if (fp == nullptr) {
+ ::close(pipeFd[0]);
+ throw runtime::Exception("Failed to open pipe descriptor");
+ }
+
+ char *line = nullptr;
+ size_t len = 0;
+ try {
+ while ((::getline(&line, &len, fp.get())) != -1) {
+ std::string log(line);
+ log.erase(std::find_if(log.rbegin(), log.rend(),
+ std::ptr_fun<int, int>(std::isgraph)).base(), log.end());
+ WARN(SINK, log);
}
- if (!unmounted)
- stopDependedSystemdUnits();
+ } catch (std::exception &e) {
+ ERROR(SINK, e.what());
}
+ ::free(line);
+ ::close(pipeFd[0]);
}
+bool isPartitionTerminated(const std::string &partition)
+{
+ bool ret = true;
+ const std::string cmd("fuser -m " + partition + " | grep -o '[0-9]*'");
+ char *line = nullptr;
+ size_t len = 0;
+
+ FILE *fp = ::popen(cmd.c_str(), "r");
+ if (fp == nullptr) {
+ ERROR(SINK, "Failed to get processes on partition");
+ return false;
+ }
+
+ if (::getline(&line, &len, fp) != -1)
+ ret = false;
+
+ ::free(line);
+ ::pclose(fp);
+
+ return ret;
}
-InternalEncryptionServer::InternalEncryptionServer(ServerContext& srv, KeyServer& key) :
+void unmountInternalStorage(const std::string& source)
+{
+ if (::umount2("/opt/usr", MNT_DETACH) == -1) {
+ if (errno != EBUSY && errno != EINVAL) {
+ throw runtime::Exception("umount() error : " + runtime::GetSystemErrorMessage());
+ }
+ }
+
+ do {
+ ::sync();
+ std::vector<const char*> args = {
+ "/usr/bin/fuser", "-m", "-k", "-v", "-SIGTERM", source.c_str(), nullptr
+ };
+ try {
+ killProcesses(args);
+ ::usleep((useconds_t)((unsigned int)(500)*1000));
+
+ args[4] = "-SIGKILL";
+ killProcesses(args);
+ ::usleep((useconds_t)((unsigned int)(200)*1000));
+ } catch (runtime::Exception &e) {
+ ERROR(e.what());
+ }
+ } while (!isPartitionTerminated(source));
+}
+
+}
+
+InternalEncryptionServer::InternalEncryptionServer(ServerContext& srv,
+ KeyServer& key) :
server(srv),
keyServer(key)
{
server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::setMountPassword)(std::string));
- server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::mount)());
+ server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::mount)(std::vector<unsigned char>, unsigned int));
server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::umount)());
+ server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::isMounted)());
server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::encrypt)(std::string, unsigned int));
server.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryptionServer::decrypt)(std::string));
server.expose(this, "", (int)(InternalEncryptionServer::isPasswordInitialized)());
std::string source = findDevPath();
+ if (getState() == State::Encrypted) {
+ //"error_partially_encrypted"
+ if (!FileFooter::exist(source) && !UpgradeSupport::checkUpgradeFlag()) {
+ // Trigger key migration process
+ UpgradeSupport::createUpgradeFlag();
+ }
+ }
+
engine.reset(new INTERNAL_ENGINE(
source, INTERNAL_PATH,
ProgressBar([](unsigned v) {
std::to_string(v).c_str());
})
));
+
+ try {
+ dbus::Connection &systemDBus = dbus::Connection::getSystem();
+ systemDBus.registerObject(ODE_OBJECT_PATH, manifest, nullptr, nullptr);
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, e.what());
+ }
}
InternalEncryptionServer::~InternalEncryptionServer()
{
}
+int InternalEncryptionServer::migrateMasterKey(const std::string& dev, const std::string& password)
+{
+ try {
+ BinaryData masterKey = UpgradeSupport::loadMasterKey(dev);
+
+ // encrypt the master key with given password
+ return keyServer.changePassword2(dev, masterKey, password);
+ } catch (const runtime::Exception&) {
+ ERROR(SINK, "Failed to load the master key stored during upgrade.");
+ }
+
+ return error::Unknown;
+}
+
int InternalEncryptionServer::setMountPassword(const std::string& password)
{
- return keyServer.get(engine->getSource(), password, mountKey);
+ const std::string& dev = engine->getSource();
+
+ // check if upgrade flag exists
+ if (UpgradeSupport::checkUpgradeFlag()) {
+ INFO(SINK, "Upgrade flag detected.");
+
+ int rc = migrateMasterKey(dev, password);
+ if (rc != error::None)
+ return rc;
+ UpgradeSupport::removeUpgradeFlag();
+ }
+
+ return keyServer.get(dev, password, mountKey);
}
-int InternalEncryptionServer::mount()
+int InternalEncryptionServer::mount(const std::vector<unsigned char> &mk, unsigned int options)
{
- if (mountKey.empty()) {
- ERROR(SINK, "You need to call set_mount_password() first.");
+ if (mountKey.empty() && mk.empty()) {
+ ERROR(SINK, "You need to set master key first.");
return error::NoData;
}
- BinaryData key = mountKey;
+ BinaryData key = mk.empty() ? mountKey : mk;
mountKey.clear();
if (getState() != State::Encrypted) {
- INFO(SINK, "Cannot mount, SD partition's state incorrect.");
+ ERROR(SINK, "Cannot mount, SD partition's state incorrect.");
return error::NoSuchDevice;
}
if (engine->isMounted()) {
- INFO(SINK, "Partition already mounted.");
+ ERROR(SINK, "Partition already mounted.");
return error::None;
}
engine->mount(key, getOptions());
server.notify("InternalEncryptionServer::mount");
+
+ runtime::File("/tmp/.lazy_mount").create(O_WRONLY);
+ runtime::File("/tmp/.unlock_mnt").create(O_WRONLY);
} catch (runtime::Exception &e) {
ERROR(SINK, "Mount failed: " + std::string(e.what()));
return error::Unknown;
return error::None;
}
+int InternalEncryptionServer::isMounted()
+{
+ int ret = 0;
+ try {
+ ret = engine->isMounted() ? 1 : 0;
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, "Failed to access the mount flag");
+ return error::Unknown;
+ }
+ return ret;
+}
+
int InternalEncryptionServer::umount()
{
if (getState() != State::Encrypted) {
}
if (!engine->isMounted()) {
- INFO(SINK, "Partition already umounted.");
+ ERROR(SINK, "Partition already umounted.");
return error::None;
}
INFO(SINK, "Closing all processes using internal storage.");
try {
- stopDependedSystemdUnits();
+ stopSystemdUnits();
INFO(SINK, "Umounting internal storage.");
+ unmountInternalStorage("/dev/mapper/userdata");
engine->umount();
} catch (runtime::Exception &e) {
ERROR(SINK, "Umount failed: " + std::string(e.what()));
auto encryptWorker = [masterKey, options, this]() {
try {
+ if (::device_power_request_lock(POWER_LOCK_DISPLAY, 0) != 0)
+ ERROR(SINK, "Failed to request to lock display");
+
showProgressUI("encrypt");
::sleep(1);
runtime::File file("/opt/etc/.odeprogress");
file.create(MODE_0640);
- INFO(SINK, "Closing all known systemd services that might be using internal storage.");
- stopKnownSystemdUnits();
-
std::string source = engine->getSource();
auto mntPaths = findMountPointsByDevice(source);
if (!mntPaths.empty()) {
INFO(SINK, "Closing all processes using internal storage.");
- stopDependedSystemdUnits();
+ stopSystemdUnits();
INFO(SINK, "Unmounting internal storage.");
unmountInternalStorage(source);
INFO(SINK, "Encryption started.");
::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "error_partially_encrypted");
- engine->encrypt(masterKey, options);
+ try {
+ engine->encrypt(masterKey, options);
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, e.what());
+ if (!engine->isStarted()) {
+ ::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "unencrypted");
+ file.remove();
+ }
+ ::sync();
+ ::reboot(RB_AUTOBOOT);
+ }
setOptions(options & getSupportedOptions());
INFO(SINK, "Encryption completed.");
return error::NoSuchDevice;
}
+ // check if key migration is needed
+ if (UpgradeSupport::checkUpgradeFlag()) {
+ INFO(SINK, "Upgrade flag detected.");
+ const std::string& dev = engine->getSource();
+ int rc = migrateMasterKey(dev, password);
+ if (rc == error::None)
+ UpgradeSupport::removeUpgradeFlag();
+ }
+
BinaryData masterKey;
int ret = keyServer.get(engine->getSource(), password, masterKey);
if (ret != error::None)
auto decryptWorker = [masterKey, this]() {
try {
+ if (::device_power_request_lock(POWER_LOCK_DISPLAY, 0) != 0)
+ ERROR(SINK, "Failed to request to lock display");
+
showProgressUI("decrypt");
::sleep(1);
file.create(MODE_0640);
if (engine->isMounted()) {
- INFO(SINK, "Closing all known systemd services that might be using internal storage.");
- stopKnownSystemdUnits();
INFO(SINK, "Closing all processes using internal storage.");
- stopDependedSystemdUnits();
+ stopSystemdUnits();
INFO(SINK, "Umounting internal storage.");
- while (1) {
- try {
- engine->umount();
- break;
- } catch (runtime::Exception& e) {
- stopDependedSystemdUnits();
- }
- }
+ unmountInternalStorage("/dev/mapper/userdata");
+ engine->umount();
}
INFO(SINK, "Decryption started.");
::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "error_partially_decrypted");
- engine->decrypt(masterKey, getOptions());
+ try {
+ engine->decrypt(masterKey, getOptions());
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, e.what());
+ if (!engine->isStarted()) {
+ ::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "encrypted");
+ file.remove();
+ }
+ ::sync();
+ ::reboot(RB_AUTOBOOT);
+ }
INFO(SINK, "Decryption complete.");
::vconf_set_str(VCONFKEY_ODE_CRYPTO_STATE, "unencrypted");
if (state == State::Unencrypted)
return error::NoSuchDevice;
- if (state == State::Corrupted)
- Ext4Tool::mkfs(engine->getSource());
-
runtime::File file("/opt/.factoryreset");
file.create(MODE_0640);
else if (valueStr == "error_partially_encrypted" || valueStr == "error_partially_decrypted")
return State::Corrupted;
- return State::Invalid;
+ return State::NotSupported;
}
unsigned int InternalEncryptionServer::getSupportedOptions()
int setMountPassword(const std::string& password);
- int mount();
+ int mount(const std::vector<unsigned char> &mk, unsigned int options);
int umount();
+ int isMounted();
int encrypt(const std::string& password, unsigned int options);
int decrypt(const std::string& password);
std::string getDevicePath() const;
private:
+ int migrateMasterKey(const std::string& dev, const std::string& password);
+
+private:
ServerContext& server;
std::unique_ptr<INTERNAL_ENGINE> engine;
const BinaryData& iv)
{
BinaryData ret(in.size(), 0);
- EVP_CIPHER_CTX* ctx;
+ EVP_CIPHER_CTX* ctx = nullptr;
int outLen, len;
ctx = ::EVP_CIPHER_CTX_new();
+ if (ctx == nullptr)
+ throw runtime::Exception("Failed to allocate memory for chipher context");
::EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv.data());
const BinaryData& iv)
{
BinaryData ret(in.size(), 0);
- EVP_CIPHER_CTX* ctx;
+ EVP_CIPHER_CTX* ctx = nullptr;
int len, len1;
ctx = ::EVP_CIPHER_CTX_new();
+ if (ctx == nullptr)
+ throw runtime::Exception("Failed to allocate memory for chipher context");
::EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv.data());
::EVP_CIPHER_CTX_set_padding(ctx, 0);
const std::string& curPassword,
const std::string& newPassword)
{
+
if (dev.empty() || curPassword.empty() || newPassword.empty())
return error::InvalidParameter;
ek.encrypt(key, newPassword);
FileFooter::write(dev, ek.serialize());
+
+ UpgradeSupport::removeUpgradeFlag();
+
+ return error::None;
+}
+
+int KeyServer::changePassword2(const std::string& dev,
+ const BinaryData& masterKey,
+ const std::string& newPassword)
+{
+ if (dev.empty() || masterKey.empty() || newPassword.empty())
+ return error::InvalidParameter;
+
+ std::lock_guard<std::mutex> lock(footerLock);
+ EncryptedKey ek(masterKey, newPassword);
+
+ FileFooter::write(dev, ek.serialize());
return error::None;
}
return error::NoSuchFile;
}
+ UpgradeSupport::removeUpgradeFlag();
+
EncryptedKey ek(FileFooter::read(dev));
key = ek.decrypt(password);
int changePassword(const std::string& dev,
const std::string& curPW,
const std::string& newPW);
+ int changePassword2(const std::string& dev,
+ const BinaryData& masterKey,
+ const std::string& newPW);
int verifyPassword(const std::string& dev, const std::string& password);
int get(const std::string& dev,
const std::string& password,
+++ /dev/null
-/*
- * Copyright (c) 2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-#include <unistd.h>
-#include <signal.h>
-#include <sys/types.h>
-
-#include <aul.h>
-#include <klay/exception.h>
-
-#include "logger.h"
-#include "launchpad.h"
-
-Launchpad::Launchpad(const uid_t uid) :
- user(uid)
-{
- if (user == 0) {
- throw runtime::Exception("No logined user for launching app");
- }
-}
-
-bool Launchpad::isRunning(const std::string& appid)
-{
- return ::aul_app_is_running_for_uid(appid.c_str(), user);
-}
-
-void Launchpad::launch(const std::string& appid)
-{
- launch(appid, AppBundle());
-}
-
-void Launchpad::launch(const std::string& appid, const AppBundle& bundle)
-{
- if (::aul_launch_app_for_uid(appid.c_str(), bundle.get(), user) < 0) {
- throw runtime::Exception("Failed to launch app " + appid);
- }
-}
-
-void Launchpad::resume(const std::string& appid)
-{
- if (::aul_resume_app_for_uid(appid.c_str(), user) < 0) {
- throw runtime::Exception("Failed to resume app " + appid);
- }
-}
-
-void Launchpad::terminate(const std::string& appid)
-{
- int pid = ::aul_app_get_pid_for_uid(appid.c_str(), user);
- if (pid > 0) {
- if (::aul_terminate_pid_for_uid(pid, user) < 0) {
- WARN(SINK, "Failed to terminate app PID=" + std::to_string(pid));
- ::kill(pid, SIGKILL);
- }
- }
-}
#include <cynara-client.h>
#include <sys/smack.h>
-#include <klay/audit/dlog-sink.h>
-
#include "logger.h"
+#include "file-sink.h"
#include "secure-erase.h"
#include "internal-encryption.h"
#include "external-encryption.h"
namespace {
const std::string ODE_MANAGER_ADDRESS = "/tmp/.ode.sock";
-std::unique_ptr<audit::DlogLogSink> _sink = nullptr;
+std::unique_ptr<FileLogSink> _sink = nullptr;
} // namespace
ServerContext::ServerContext() : rmi::Service(ODE_MANAGER_ADDRESS)
{
- _sink.reset(new audit::DlogLogSink("ODE"));
+ _sink.reset(new FileLogSink("ode.log"));
SINK = _sink.get();
INFO(SINK, "ODE server starting.");
[Service]
Type=simple
+Group=system_share
SmackProcessLabel=System::Privileged
ExecStart=@BIN_DIR@/@PROJECT_NAME@d
Restart=on-failure
typedef int(*KeyStoragePluginRemoveFn)(const unsigned char*, size_t);
}
+const std::string UPGRADE_FLAG_PATH = "/opt/etc/.ode_upgrade_started";
+
std::mutex opGuard;
// not thread-safe because of static member
{
size_t tokenSize(token.size());
- file.create(S_IRUSR | S_IWUSR);
+ file.create(S_IRUSR | S_IWUSR | S_IRGRP);
file.write(&tokenSize, sizeof(tokenSize));
file.write(token.data(), token.size());
runtime::File file(getTokenFileName(device));
readToken(file, token);
- if (token.empty())
- throw runtime::Exception("Token opening failed");
-
auto& up = KeyStoragePlugin::Instance();
return up.load(token);
}
runtime::File file(getTokenFileName(device));
readToken(file, token);
- // already removed
- if (token.empty()) {
- INFO(SINK, "Token for " + device + " does not exist. Ignoring.");
- return;
- }
-
auto& up = KeyStoragePlugin::Instance();
up.remove(token);
- file.remove();
+ try {
+ file.remove();
+ } catch (runtime::Exception &e) {
+ ERROR(SINK, "Failed to remove token: " + std::string(e.what()));
+ }
+}
+
+void createUpgradeFlag()
+{
+ runtime::File file(UPGRADE_FLAG_PATH);
+ file.create(S_IRUSR | S_IWUSR); // 0600
+}
+
+void removeUpgradeFlag()
+{
+ runtime::File file(UPGRADE_FLAG_PATH);
+ bool exists = file.exists();
+ if (exists)
+ file.remove();
+}
+
+bool checkUpgradeFlag()
+{
+ runtime::File file(UPGRADE_FLAG_PATH);
+ return file.exists();
}
} // namespace UpgradeSupport
void storeMasterKey(const std::string &device, const BinaryData& key);
BinaryData loadMasterKey(const std::string &device);
void removeMasterKey(const std::string &device);
+void createUpgradeFlag();
+void removeUpgradeFlag();
+bool checkUpgradeFlag();
} // namespace UpgradeSupport