2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
22 #include <sys/mount.h>
23 #include <sys/reboot.h>
31 #include <tzplatform_config.h>
32 #include <klay/process.h>
33 #include <klay/file-user.h>
34 #include <klay/filesystem.h>
35 #include <klay/dbus/connection.h>
39 #include "progress-bar.h"
40 #include "engine/encryption/dmcrypt-engine.h"
41 #include "key-manager/key-manager.h"
43 #include "rmi/internal-encryption.h"
45 #define INTERNAL_ENGINE DMCryptEngine
46 #define INTERNAL_DEV_PATH "/dev/disk/by-partlabel"
47 #define INTERNAL_DEV_NAME "USER"
48 #define INTERNAL_PATH "/opt/usr"
49 #define INTERNAL_STATE_VCONF_KEY VCONFKEY_ODE_CRYPTO_STATE
50 #define INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY VCONFKEY_ODE_FAST_ENCRYPTION
52 #define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
54 const std::string PROG_FACTORY_RESET = "/usr/bin/dbus-send";
55 const std::vector<std::string> wipeCommand = {
60 "--dest=com.samsung.factoryreset",
61 "/com/samsung/factoryreset",
62 "com.samsung.factoryreset.start.setting"
69 std::string findDevPath()
71 std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME;
73 runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end;
76 const std::string& path = (*iter).getPath();
77 std::string name = path.substr(path.rfind('/') + 1);
79 upper.reserve(name.size());
81 upper += std::toupper(c);
83 if (upper.compare(0, strlen(INTERNAL_DEV_NAME), INTERNAL_DEV_NAME) == 0) {
89 } catch (runtime::Exception &e) {}
91 char *dev = ::realpath(source.c_str(), NULL);
93 throw runtime::Exception("Failed to find device path.");
96 std::string devPath(dev);
102 std::string findMntPath(const std::string &devPath)
106 FILE* mtab = ::setmntent("/etc/mtab", "r");
107 struct mntent* entry = NULL;
108 while ((entry = ::getmntent(mtab)) != NULL) {
109 if (devPath == entry->mnt_fsname) {
110 ret = entry->mnt_dir;
119 std::unique_ptr<INTERNAL_ENGINE> engine;
120 KeyManager::data mountKey;
122 void stopKnownSystemdServices() {
123 std::vector<std::string> knownSystemdServices;
124 dbus::Connection& systemDBus = dbus::Connection::getSystem();
125 dbus::VariantIterator iter;
127 systemDBus.methodcall("org.freedesktop.systemd1",
128 "/org/freedesktop/systemd1",
129 "org.freedesktop.systemd1.Manager",
131 -1, "(a(ssssssouso))", "")
132 .get("(a(ssssssouso))", &iter);
135 unsigned int dataUint;
139 ret = iter.get("(ssssssouso)", dataStr, dataStr + 1, dataStr + 2,
140 dataStr + 3, dataStr + 4, dataStr + 5,
141 dataStr + 6, &dataUint, dataStr + 7,
148 std::string service(dataStr[0]);
149 if (service.compare(0, 5, "user@") == 0 ||
150 service == "tlm.service" ||
151 service == "resourced.service") {
152 knownSystemdServices.push_back(service);
156 for (const std::string& service : knownSystemdServices) {
157 INFO(SINK, "Stop service - " + service);
158 systemDBus.methodcall("org.freedesktop.systemd1",
159 "/org/freedesktop/systemd1",
160 "org.freedesktop.systemd1.Manager",
162 -1, "", "(ss)", service.c_str(), "flush");
168 void stopDependedSystemdServices()
170 dbus::Connection& systemDBus = dbus::Connection::getSystem();
171 std::set<std::string> servicesToStop;
173 for (pid_t pid : runtime::FileUser::getList(INTERNAL_PATH, true)) {
176 systemDBus.methodcall("org.freedesktop.systemd1",
177 "/org/freedesktop/systemd1",
178 "org.freedesktop.systemd1.Manager",
180 -1, "(o)", "(u)", (unsigned int)pid)
181 .get("(o)", &service);
182 servicesToStop.insert(service);
183 } catch (runtime::Exception &e) {
184 INFO(SINK, "Close process - " + std::to_string(pid));
185 ::kill(pid, SIGKILL);
189 for (const std::string& service : servicesToStop) {
190 INFO(SINK, "Close service - " + service);
191 systemDBus.methodcall("org.freedesktop.systemd1",
193 "org.freedesktop.systemd1.Unit",
195 -1, "", "(s)", "flush");
199 void showProgressUI(const std::string type) {
200 ::tzplatform_set_user(::tzplatform_getuid(TZ_SYS_DEFAULT_USER));
201 std::string defaultUserHome(::tzplatform_getenv(TZ_USER_HOME));
202 ::tzplatform_reset_user();
205 runtime::File shareDirectory("/opt/home/root/share");
206 if (!shareDirectory.exists()) {
207 shareDirectory.makeDirectory(true);
210 runtime::File elmConfigDir(shareDirectory.getPath() + "/.elementary");
211 if (!elmConfigDir.exists()) {
212 runtime::File defaultElmConfigDir(defaultUserHome + "/share/.elementary");
213 defaultElmConfigDir.copyTo(shareDirectory.getPath());
215 } catch (runtime::Exception &e) {
216 ERROR(SINK, "Failed to set up elm configuration");
219 std::vector<std::string> args = {
220 "ode", "progress", type, "Internal"
223 runtime::Process proc("/usr/bin/ode", args);
227 unsigned int getOptions()
229 unsigned int result = 0;
233 ::vconf_get_bool(INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY, &value);
235 result |= InternalEncryption::Option::IncludeUnusedRegion;
241 void setOptions(unsigned int options)
245 if (options & InternalEncryption::Option::IncludeUnusedRegion) {
250 ::vconf_set_bool(INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY, value);
255 InternalEncryption::InternalEncryption(ODEControlContext& ctx) :
258 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::setMountPassword)(std::string));
259 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::mount)());
260 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::umount)());
261 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::encrypt)(std::string, unsigned int));
262 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::decrypt)(std::string));
263 context.expose(this, "", (int)(InternalEncryption::isPasswordInitialized)());
264 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::initPassword)(std::string));
265 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::cleanPassword)(std::string));
266 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::changePassword)(std::string, std::string));
267 context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::verifyPassword)(std::string));
268 context.expose(this, "", (int)(InternalEncryption::getState)());
269 context.expose(this, "", (unsigned int)(InternalEncryption::getSupportedOptions)());
271 context.createNotification("InternalEncryption::mount");
273 std::string source = findDevPath();
275 engine.reset(new INTERNAL_ENGINE(
276 source, INTERNAL_PATH,
277 ProgressBar([](int v) {
278 ::vconf_set_str(VCONFKEY_ODE_ENCRYPT_PROGRESS,
279 std::to_string(v).c_str());
284 InternalEncryption::~InternalEncryption()
288 int InternalEncryption::setMountPassword(const std::string& password)
290 KeyManager::data pwData(password.begin(), password.end());
291 KeyManager keyManager(engine->getKeyMeta());
292 if (!keyManager.verifyPassword(pwData)) {
296 ode::mountKey = keyManager.getMasterKey(pwData);
301 int InternalEncryption::mount()
303 if (getState() != State::Encrypted) {
307 if (engine->isMounted()) {
308 INFO(SINK, "Already mounted");
313 INFO(SINK, "Mount internal storage...");
314 engine->mount(mountKey, getOptions());
317 context.notify("InternalEncryption::mount");
319 runtime::File("/tmp/.lazy_mount").create(O_WRONLY);
320 runtime::File("/tmp/.unlock_mnt").create(O_WRONLY);
321 } catch (runtime::Exception &e) {
322 ERROR(SINK, "Mount failed - " + std::string(e.what()));
329 int InternalEncryption::umount()
331 if (getState() != State::Encrypted) {
335 if (!engine->isMounted()) {
336 INFO(SINK, "Already umounted");
341 INFO(SINK, "Close all processes using internal storage...");
342 stopDependedSystemdServices();
343 INFO(SINK, "Umount internal storage...");
345 } catch (runtime::Exception &e) {
346 ERROR(SINK, "Umount failed - " + std::string(e.what()));
353 int InternalEncryption::encrypt(const std::string& password, unsigned int options)
355 if (getState() != State::Unencrypted) {
359 KeyManager::data pwData(password.begin(), password.end());
360 KeyManager keyManager(engine->getKeyMeta());
362 if (!keyManager.verifyPassword(pwData)) {
366 KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
367 auto encryptWorker = [MasterKey, options, this]() {
369 std::string source = engine->getSource();
370 std::string mntPath = findMntPath(source);
372 if (!mntPath.empty()) {
373 INFO(SINK, "Close all known systemd services that might be using internal storage...");
374 stopKnownSystemdServices();
375 INFO(SINK, "Close all processes using internal storage...");
376 stopDependedSystemdServices();
379 while (!mntPath.empty()) {
380 INFO(SINK, "Umount internal storage...");
381 while (::umount(mntPath.c_str()) == -1) {
382 if (errno != EBUSY) {
383 throw runtime::Exception("Umount error - " + std::to_string(errno));
385 stopDependedSystemdServices();
387 mntPath = findMntPath(source);
390 showProgressUI("Encrypting");
392 INFO(SINK, "Encryption started...");
393 engine->encrypt(MasterKey, options);
394 setOptions(options & getSupportedOptions());
396 INFO(SINK, "Encryption completed");
397 ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "encrypted");
398 context.notify("InternalEncryption::mount");
400 INFO(SINK, "Syncing disk and rebooting...");
402 ::reboot(RB_AUTOBOOT);
403 } catch (runtime::Exception &e) {
404 ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
405 ERROR(SINK, "Encryption failed - " + std::string(e.what()));
409 std::thread asyncWork(encryptWorker);
415 int InternalEncryption::decrypt(const std::string& password)
417 if (getState() != State::Encrypted) {
421 KeyManager::data pwData(password.begin(), password.end());
422 KeyManager keyManager(engine->getKeyMeta());
424 if (!keyManager.verifyPassword(pwData)) {
428 KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
429 auto decryptWorker = [MasterKey, this]() {
431 if (engine->isMounted()) {
432 INFO(SINK, "Close all known systemd services that might be using internal storage...");
433 stopKnownSystemdServices();
434 INFO(SINK, "Close all processes using internal storage...");
435 stopDependedSystemdServices();
437 INFO(SINK, "Umount internal storage...");
442 } catch (runtime::Exception& e) {
443 stopDependedSystemdServices();
448 showProgressUI("Decrypting");
450 INFO(SINK, "Decryption started...");
451 engine->decrypt(MasterKey, getOptions());
453 INFO(SINK, "Decryption completed");
454 ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "unencrypted");
456 INFO(SINK, "Syncing disk and rebooting...");
458 ::reboot(RB_AUTOBOOT);
459 } catch (runtime::Exception &e) {
460 ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
461 ERROR(SINK, "Decryption failed - " + std::string(e.what()));
465 std::thread asyncWork(decryptWorker);
471 int InternalEncryption::recovery()
473 if (getState() != State::Unencrypted) {
478 runtime::Process proc(PROG_FACTORY_RESET, wipeCommand);
479 if (proc.execute() == -1) {
480 ERROR(SINK, "Failed to launch factory-reset");
487 int InternalEncryption::isPasswordInitialized()
489 if (engine->isKeyMetaSet()) {
495 int InternalEncryption::initPassword(const std::string& password)
497 KeyManager::data pwData(password.begin(), password.end());
498 KeyManager keyManager;
500 keyManager.initPassword(pwData);
501 engine->setKeyMeta(keyManager.serialize());
505 int InternalEncryption::cleanPassword(const std::string& password)
507 KeyManager::data pwData(password.begin(), password.end());
508 KeyManager keyManager(engine->getKeyMeta());
510 if (!keyManager.verifyPassword(pwData)) {
514 engine->clearKeyMeta();
518 int InternalEncryption::changePassword(const std::string& oldPassword,
519 const std::string& newPassword)
521 KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
522 KeyManager::data newPwData(newPassword.begin(), newPassword.end());
523 KeyManager keyManager(engine->getKeyMeta());
525 if (!keyManager.verifyPassword(oldPwData)) {
529 keyManager.changePassword(oldPwData, newPwData);
530 engine->setKeyMeta(keyManager.serialize());
535 int InternalEncryption::verifyPassword(const std::string& password)
537 KeyManager::data pwData(password.begin(), password.end());
538 KeyManager keyManager(engine->getKeyMeta());
540 if (keyManager.verifyPassword(pwData)) {
546 int InternalEncryption::getState()
548 char *value = ::vconf_get_str(INTERNAL_STATE_VCONF_KEY);
550 throw runtime::Exception("Failed to get vconf value");
553 std::string valueStr(value);
556 if (valueStr == "encrypted") {
557 return State::Encrypted;
558 } else if (valueStr == "unencrypted") {
559 return State::Unencrypted;
561 return State::Corrupted;
567 unsigned int InternalEncryption::getSupportedOptions()
569 return engine->getSupportedOptions();