+/*
+ * 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 <vconf.h>
+#include <thread>
+#include <vector>
+
+#include <dd-deviced.h>
+#include <dd-control.h>
+
+#include <klay/process.h>
+#include <klay/exception.h>
+#include <klay/filesystem.h>
+#include <klay/dbus/variant.h>
+#include <klay/dbus/connection.h>
+
+#include <dpm/pil/policy-context.h>
+#include <dpm/pil/policy-model.h>
+#include <dpm/pil/policy-storage.h>
+#include <dpm/pil/launchpad.h>
+
+namespace {
+
+const std::string APPID_DEVICE_ENCRYPTION = "org.tizen.ode";
+const std::string APPID_LOCKSCREEN = "org.tizen.lockscreen";
+
+const std::string PROG_FACTORY_RESET = "/usr/bin/dbus-send";
+const std::vector<std::string> wipeCommand = {
+ "/usr/bin/dbus-send",
+ "--system",
+ "--type=signal",
+ "--print-reply",
+ "--dest=com.samsung.factoryreset",
+ "/com/samsung/factoryreset",
+ "com.samsung.factoryreset.start.setting"
+};
+
+bool checkEncryptionState(const char* key, bool encrypt)
+{
+ char *value = ::vconf_get_str(key);
+ if (value == NULL) {
+ ERROR("Failed to read internal storage encryption state");
+ return false;
+ }
+
+ std::string state(value);
+ ::free(value);
+ if (encrypt) {
+ if (state != "unencrypted") {
+ ERROR("Storage might be already encrypted or it has error");
+ return false;
+ }
+ } else {
+ if (state != "encrypted") {
+ ERROR("Storage might be already decrypted or it has error");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool getEncryptionState(const char* key)
+{
+ char *state = ::vconf_get_str(key);
+ if (state == NULL) {
+ throw runtime::Exception("Failed to read internal storage encryption state");
+ }
+
+ std::string expected("encrypted");
+ if (expected == state) {
+ ::free(state);
+ return true;
+ }
+
+ ::free(state);
+ return false;
+}
+
+int launchApplication(const std::string& name, const Bundle& bundle)
+{
+ try {
+ Launchpad launchpad(rmi::Service::getPeerUid());
+ if (launchpad.isRunning(name)) {
+ launchpad.resume(name);
+ return 0;
+ }
+
+ launchpad.launch(name, bundle);
+ } catch (runtime::Exception& e) {
+ ERROR("Failed to start application: " << name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+std::vector<std::string> getStorageDeviceList(const std::string& type)
+{
+ int intparams[6];
+ char* strparams[7];
+ std::vector<std::string> storages;
+
+ dbus::Connection &systemDBus = dbus::Connection::getSystem();
+ const dbus::Variant &var = systemDBus.methodcall("org.tizen.system.storage",
+ "/Org/Tizen/System/Storage/Block/Manager",
+ "org.tizen.system.storage.BlockManager",
+ "GetDeviceList",
+ -1,
+ "(a(issssssisibii))",
+ "(s)",
+ type.c_str());
+ dbus::VariantIterator it;
+ var.get("(a(issssssisibii))", &it);
+ while (it.get("(issssssisibii)",
+ &intparams[0], // block type: 0 - scsi, 1 : mmc
+ &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 - flase, 1 - true
+ &intparams[4], // flags: 1 - unmounted
+ // 2 - broken filesystem
+ // 4 - no filesystem
+ // 8 - not supported
+ // 16 - readonly
+ &intparams[5])) { // strage id
+ storages.push_back(strrchr(strparams[0], '/') + 1);
+ for (int i = 0; i < 7; i++) {
+ if (strparams[i]) {
+ ::free(strparams[i]);
+ }
+ }
+ }
+
+ return storages;
+}
+
+void requestDeviceFormat(const std::string& devnode, int option)
+{
+ int ret;
+ dbus::Connection &systemDBus = dbus::Connection::getSystem();
+ systemDBus.methodcall("org.tizen.system.storage",
+ "/Org/Tizen/System/Storage/Block/Devices/" + devnode,
+ "org.tizen.system.storage.Block",
+ "Format",
+ G_MAXINT,
+ "(i)",
+ "(i)",
+ option).get("(i)", &ret);
+ if (ret != 0) {
+ throw runtime::Exception("Failed to format " + devnode);
+ }
+}
+
+} // namespace
+
+class Security : public AbstractPolicyProvider {
+public:
+ enum {
+ WIPE_INTERNAL_STORAGE = (1 << 0), /**< Wipe internal memory */
+ WIPE_EXTERNAL_STORAGE = (1 << 1), /**< Wipe external memory */
+ };
+
+ Security();
+ ~Security();
+
+ int lockoutScreen();
+
+ int wipeData(int id);
+
+ int setInternalStorageEncryption(bool encrypt);
+ bool isInternalStorageEncrypted();
+ int setExternalStorageEncryption(bool encrypt);
+ bool isExternalStorageEncrypted();
+};
+
+Security::Security()
+{
+}
+
+Security::~Security()
+{
+}
+
+int Security::lockoutScreen()
+{
+ return launchApplication(APPID_LOCKSCREEN, Bundle());
+}
+
+int Security::setInternalStorageEncryption(bool encrypt)
+{
+ if (!checkEncryptionState(VCONFKEY_ODE_CRYPTO_STATE, encrypt)) {
+ return -1;
+ }
+
+ Bundle bundle;
+ bundle.add("viewtype", encrypt ? "ENCRYPT_DEVICE" : "DECRYPT_DEVICE");
+ return launchApplication(APPID_DEVICE_ENCRYPTION, bundle);
+}
+
+bool Security::isInternalStorageEncrypted()
+{
+ return getEncryptionState(VCONFKEY_ODE_CRYPTO_STATE);
+}
+
+int Security::setExternalStorageEncryption(bool encrypt)
+{
+ if (!checkEncryptionState(VCONFKEY_SDE_CRYPTO_STATE, encrypt)) {
+ return -1;
+ }
+
+ Bundle bundle;
+ bundle.add("viewtype", encrypt ? "ENCRYPT_SD_CARD" : "DECRYPT_SD_CARD");
+ return launchApplication(APPID_DEVICE_ENCRYPTION, bundle);
+}
+
+bool Security::isExternalStorageEncrypted()
+{
+ return getEncryptionState(VCONFKEY_SDE_CRYPTO_STATE);
+}
+
+int Security::wipeData(int id)
+{
+ auto worker = [id, this]() {
+ if (id & WIPE_EXTERNAL_STORAGE) {
+ try {
+ std::vector<std::string> devices = getStorageDeviceList("mmc");
+ for (const std::string& devnode : devices) {
+ std::cout << "Erase device: " << devnode << std::endl;
+ requestDeviceFormat(devnode, 1);
+ std::cout << "Erase device: " << devnode << " completed" << std::endl;
+ }
+ } catch(runtime::Exception& e) {
+ ERROR("Failed to enforce external storage policy");
+ return -1;
+ }
+ }
+
+ if (id & WIPE_INTERNAL_STORAGE) {
+ runtime::Process proc(PROG_FACTORY_RESET, wipeCommand);
+ if (proc.execute() == -1) {
+ ERROR("Failed to launch factory-reset");
+ return -1;
+ }
+ }
+
+ return 0;
+ };
+
+ std::thread deviceWiper(worker);
+ deviceWiper.detach();
+
+ return 0;
+}
+
+extern "C" {
+
+#define PRIVILEGE_SECURITY "http://tizen.org/privilege/dpm.security"
+#define PRIVILEGE_WIPE "http://tizen.org/privilege/dpm.wipe"
+#define PRIVILEGE_LOCK "http://tizen.org/privilege/dpm.lock"
+
+AbstractPolicyProvider *PolicyFactory(PolicyControlContext& context)
+{
+ Security *policy = new Security();
+
+ context.expose(policy, PRIVILEGE_SECURITY, (int)(Security::setInternalStorageEncryption)(bool));
+ context.expose(policy, PRIVILEGE_SECURITY, (int)(Security::setExternalStorageEncryption)(bool));
+ context.expose(policy, PRIVILEGE_WIPE, (int)(Security::wipeData)(int));
+ context.expose(policy, PRIVILEGE_LOCK, (int)(Security::lockoutScreen)());
+
+ context.expose(policy, "", (bool)(Security::isInternalStorageEncrypted)());
+ context.expose(policy, "", (bool)(Security::isExternalStorageEncrypted)());
+
+ return policy;
+}
+
+} // extern "C"
+
+