InternalEncryption: make umount logic more error proof
[platform/core/security/ode.git] / server / internal-encryption.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  */
16 #include <set>
17 #include <algorithm>
18
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <unistd.h>
22 #include <sys/mount.h>
23 #include <sys/reboot.h>
24 #include <stdio.h>
25 #include <mntent.h>
26 #include <limits.h>
27 #include <stdlib.h>
28
29 #include <vconf.h>
30 #include <tzplatform_config.h>
31 #include <klay/process.h>
32 #include <klay/file-user.h>
33 #include <klay/filesystem.h>
34 #include <klay/dbus/connection.h>
35
36 #include "vconf.h"
37 #include "logger.h"
38 #include "progress-bar.h"
39 #include "engine/encryption/dmcrypt-engine.h"
40 #include "key-manager/key-manager.h"
41
42 #include "rmi/internal-encryption.h"
43
44 #define INTERNAL_ENGINE DMCryptEngine
45 #define INTERNAL_DEV_PATH       "/dev/disk/by-partlabel"
46 #define INTERNAL_DEV_NAME       "USER"
47 #define INTERNAL_PATH           "/opt/usr"
48 #define INTERNAL_STATE_VCONF_KEY                                        VCONFKEY_ODE_CRYPTO_STATE
49 #define INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY      VCONFKEY_ODE_FAST_ENCRYPTION
50
51 #define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
52
53 const std::string PROG_FACTORY_RESET = "/usr/bin/dbus-send";
54 const std::vector<std::string> wipeCommand = {
55     PROG_FACTORY_RESET,
56     "--system",
57     "--type=signal",
58     "--print-reply",
59     "--dest=com.samsung.factoryreset",
60     "/com/samsung/factoryreset",
61     "com.samsung.factoryreset.start.setting"
62 };
63
64 namespace ode {
65
66 namespace {
67
68 std::string findDevPath()
69 {
70         std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME;
71         try {
72                 runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end;
73
74                 while (iter != end) {
75                         const std::string& path = (*iter).getPath();
76                         std::string name = path.substr(path.rfind('/') + 1);
77                         std::string upper;
78                         upper.reserve(name.size());
79                         for (char c : name) {
80                                 upper += std::toupper(c);
81                         }
82                         if (upper == INTERNAL_DEV_NAME) {
83                                 source = path;
84                                 break;
85                         }
86                         ++iter;
87                 }
88         } catch (runtime::Exception &e) {}
89
90         char *dev = ::realpath(source.c_str(), NULL);
91         if (dev == NULL) {
92                 throw runtime::Exception("Failed to find device path.");
93         }
94
95         std::string devPath(dev);
96         free(dev);
97
98         return devPath;
99 }
100
101 std::string findMntPath(const std::string &devPath)
102 {
103         std::string ret;
104
105         FILE* mtab = ::setmntent("/etc/mtab", "r");
106         struct mntent* entry = NULL;
107         while ((entry = ::getmntent(mtab)) != NULL) {
108                 if (devPath == entry->mnt_fsname) {
109                         ret = entry->mnt_dir;
110                         break;
111                 }
112         }
113         ::endmntent(mtab);
114
115         return ret;
116 }
117
118 std::unique_ptr<INTERNAL_ENGINE> engine;
119 KeyManager::data mountKey;
120
121 void stopKnownSystemdServices() {
122         std::vector<std::string> knownSystemdServices;
123         dbus::Connection& systemDBus = dbus::Connection::getSystem();
124         dbus::VariantIterator iter;
125
126         systemDBus.methodcall("org.freedesktop.systemd1",
127                                                         "/org/freedesktop/systemd1",
128                                                         "org.freedesktop.systemd1.Manager",
129                                                         "ListUnits",
130                                                         -1, "(a(ssssssouso))", "")
131                                                                 .get("(a(ssssssouso))", &iter);
132
133         while (1) {
134                 unsigned int dataUint;
135                 char *dataStr[9];
136                 int ret;
137
138                 ret = iter.get("(ssssssouso)", dataStr, dataStr + 1, dataStr + 2,
139                                                 dataStr + 3, dataStr + 4, dataStr + 5,
140                                                 dataStr + 6, &dataUint, dataStr + 7,
141                                                 dataStr + 8);
142
143                 if (!ret) {
144                         break;
145                 }
146
147                 std::string service(dataStr[0]);
148                 if (service.compare(0, 5, "user@") == 0 ||
149                         service == "tlm.service" ||
150                         service == "resourced.service") {
151                         knownSystemdServices.push_back(service);
152                 }
153         }
154
155         for (const std::string& service : knownSystemdServices) {
156                 INFO(SINK, "Stop service - " + service);
157                 systemDBus.methodcall("org.freedesktop.systemd1",
158                                                                 "/org/freedesktop/systemd1",
159                                                                 "org.freedesktop.systemd1.Manager",
160                                                                 "StopUnit",
161                                                                 -1, "", "(ss)", service.c_str(), "flush");
162         }
163
164         sleep(1);
165 }
166
167 void stopDependedSystemdServices()
168 {
169         dbus::Connection& systemDBus = dbus::Connection::getSystem();
170         std::set<std::string> servicesToStop;
171
172         for (pid_t pid : runtime::FileUser::getList(INTERNAL_PATH, true)) {
173                 try {
174                         char *service;
175                         systemDBus.methodcall("org.freedesktop.systemd1",
176                                                                         "/org/freedesktop/systemd1",
177                                                                         "org.freedesktop.systemd1.Manager",
178                                                                         "GetUnitByPID",
179                                                                         -1, "(o)", "(u)", (unsigned int)pid)
180                                                                                 .get("(o)", &service);
181                         servicesToStop.insert(service);
182                 } catch (runtime::Exception &e) {
183                         INFO(SINK, "Close process - " + std::to_string(pid));
184                         ::kill(pid, SIGKILL);
185                 }
186         }
187
188         for (const std::string& service : servicesToStop) {
189                 INFO(SINK, "Close service - " + service);
190                 systemDBus.methodcall("org.freedesktop.systemd1",
191                                                                 service,
192                                                                 "org.freedesktop.systemd1.Unit",
193                                                                 "Stop",
194                                                                 -1, "", "(s)", "flush");
195         }
196 }
197
198 void showProgressUI(const std::string type) {
199         ::tzplatform_set_user(::tzplatform_getuid(TZ_SYS_DEFAULT_USER));
200         std::string defaultUserHome(::tzplatform_getenv(TZ_USER_HOME));
201         ::tzplatform_reset_user();
202
203         try {
204                 runtime::File shareDirectory("/opt/home/root/share");
205                 if (!shareDirectory.exists()) {
206                         shareDirectory.makeDirectory(true);
207                 }
208
209                 runtime::File elmConfigDir(shareDirectory.getPath() + "/.elementary");
210                 if (!elmConfigDir.exists()) {
211                         runtime::File defaultElmConfigDir(defaultUserHome + "/share/.elementary");
212                         defaultElmConfigDir.copyTo(shareDirectory.getPath());
213                 }
214         } catch (runtime::Exception &e) {
215                 ERROR(SINK, "Failed to set up elm configuration");
216         }
217
218         std::vector<std::string> args = {
219                 "ode", "progress", type, "Internal"
220         };
221
222         runtime::Process proc("/usr/bin/ode", args);
223         proc.execute();
224 }
225
226 unsigned int getOptions()
227 {
228         unsigned int result = 0;
229         int value;
230
231         value = 0;
232         ::vconf_get_bool(INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY, &value);
233         if (value) {
234                 result |= InternalEncryption::Option::IncludeUnusedRegion;
235         }
236
237         return result;
238 }
239
240 void setOptions(unsigned int options)
241 {
242         bool value;
243
244         if (options & InternalEncryption::Option::IncludeUnusedRegion) {
245                 value = true;
246         } else {
247                 value = false;
248         }
249         ::vconf_set_bool(INTERNAL_OPTION_ONLY_USED_REGION_VCONF_KEY, value);
250 }
251
252 }
253
254 InternalEncryption::InternalEncryption(ODEControlContext& ctx) :
255         context(ctx)
256 {
257         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::setMountPassword)(std::string));
258         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::mount)());
259         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::umount)());
260         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::encrypt)(std::string, unsigned int));
261         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::decrypt)(std::string));
262         context.expose(this, "", (int)(InternalEncryption::isPasswordInitialized)());
263         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::initPassword)(std::string));
264         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::cleanPassword)(std::string));
265         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::changePassword)(std::string, std::string));
266         context.expose(this, PRIVILEGE_PLATFORM, (int)(InternalEncryption::verifyPassword)(std::string));
267         context.expose(this, "", (int)(InternalEncryption::getState)());
268         context.expose(this, "", (unsigned int)(InternalEncryption::getSupportedOptions)());
269
270         context.createNotification("InternalEncryption::mount");
271
272         std::string source = findDevPath();
273
274         engine.reset(new INTERNAL_ENGINE(
275                 source, INTERNAL_PATH,
276                 ProgressBar([](int v) {
277                         ::vconf_set_str(VCONFKEY_ODE_ENCRYPT_PROGRESS,
278                                                         std::to_string(v).c_str());
279                 })
280         ));
281 }
282
283 InternalEncryption::~InternalEncryption()
284 {
285 }
286
287 int InternalEncryption::setMountPassword(const std::string& password)
288 {
289         KeyManager::data pwData(password.begin(), password.end());
290         KeyManager keyManager(engine->getKeyMeta());
291         if (!keyManager.verifyPassword(pwData)) {
292                 return -2;
293         }
294
295         ode::mountKey = keyManager.getMasterKey(pwData);
296
297         return 0;
298 }
299
300 int InternalEncryption::mount()
301 {
302         if (getState() != State::Encrypted) {
303                 return -1;
304         }
305
306     if (engine->isMounted()) {
307                 INFO(SINK, "Already mounted");
308                 return 0;
309         }
310
311         try {
312                 INFO(SINK, "Mount internal storage...");
313                 engine->mount(mountKey, getOptions());
314                 mountKey.clear();
315
316                 context.notify("InternalEncryption::mount");
317
318                 runtime::File("/tmp/.lazy_mount").create(O_WRONLY);
319                 runtime::File("/tmp/.unlock_mnt").create(O_WRONLY);
320         } catch (runtime::Exception &e) {
321                 ERROR(SINK, "Mount failed - " + std::string(e.what()));
322                 return -1;
323         }
324
325         return 0;
326 }
327
328 int InternalEncryption::umount()
329 {
330         if (getState() != State::Encrypted) {
331                 return -1;
332         }
333
334         if (!engine->isMounted()) {
335                 INFO(SINK, "Already umounted");
336                 return 0;
337         }
338
339         try {
340                 INFO(SINK, "Close all processes using internal storage...");
341                 stopDependedSystemdServices();
342                 INFO(SINK, "Umount internal storage...");
343                 engine->umount();
344         } catch (runtime::Exception &e) {
345                 ERROR(SINK, "Umount failed - " + std::string(e.what()));
346                 return -1;
347         }
348
349         return 0;
350 }
351
352 int InternalEncryption::encrypt(const std::string& password, unsigned int options)
353 {
354         if (getState() != State::Unencrypted) {
355                 return -1;
356         }
357
358         KeyManager::data pwData(password.begin(), password.end());
359         KeyManager keyManager(engine->getKeyMeta());
360
361         if (!keyManager.verifyPassword(pwData)) {
362                 return -2;
363         }
364
365         KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
366         auto encryptWorker = [MasterKey, options, this]() {
367                 try {
368                         std::string source = engine->getSource();
369                         std::string mntPath = findMntPath(source);
370
371                         if (!mntPath.empty()) {
372                                 INFO(SINK, "Close all known systemd services that might be using internal storage...");
373                                 stopKnownSystemdServices();
374                                 INFO(SINK, "Close all processes using internal storage...");
375                                 stopDependedSystemdServices();
376                         }
377
378                         while (!mntPath.empty()) {
379                                 INFO(SINK, "Umount internal storage...");
380                                 while (::umount(mntPath.c_str()) == -1) {
381                                         if (errno != EBUSY) {
382                                                 throw runtime::Exception("Umount error - " + std::to_string(errno));
383                                         }
384                                         stopDependedSystemdServices();
385                                 }
386                                 mntPath = findMntPath(source);
387                         }
388
389                         showProgressUI("Encrypting");
390
391                         INFO(SINK, "Encryption started...");
392                         engine->encrypt(MasterKey, options);
393                         setOptions(options & getSupportedOptions());
394
395                         INFO(SINK, "Encryption completed");
396                         ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "encrypted");
397                         context.notify("InternalEncryption::mount");
398
399                         INFO(SINK, "Syncing disk and rebooting...");
400                         ::sync();
401                         ::reboot(RB_AUTOBOOT);
402                 } catch (runtime::Exception &e) {
403                         ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
404                         ERROR(SINK, "Encryption failed - " + std::string(e.what()));
405                 }
406         };
407
408         std::thread asyncWork(encryptWorker);
409         asyncWork.detach();
410
411         return 0;
412 }
413
414 int InternalEncryption::decrypt(const std::string& password)
415 {
416         if (getState() != State::Encrypted) {
417                 return -1;
418         }
419
420         KeyManager::data pwData(password.begin(), password.end());
421         KeyManager keyManager(engine->getKeyMeta());
422
423         if (!keyManager.verifyPassword(pwData)) {
424                 return -2;
425         }
426
427         KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
428         auto decryptWorker = [MasterKey, this]() {
429                 try {
430                         if (engine->isMounted()) {
431                                 INFO(SINK, "Close all known systemd services that might be using internal storage...");
432                                 stopKnownSystemdServices();
433                                 INFO(SINK, "Close all processes using internal storage...");
434                                 stopDependedSystemdServices();
435
436                                 INFO(SINK, "Umount internal storage...");
437                                 while (1) {
438                                         try {
439                                                 engine->umount();
440                                                 break;
441                                         } catch (runtime::Exception& e) {
442                                                 stopDependedSystemdServices();
443                                         }
444                                 }
445                         }
446
447                         showProgressUI("Decrypting");
448
449                         INFO(SINK, "Decryption started...");
450                         engine->decrypt(MasterKey, getOptions());
451
452                         INFO(SINK, "Decryption completed");
453                         ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "unencrypted");
454
455                         INFO(SINK, "Syncing disk and rebooting...");
456                         ::sync();
457                         ::reboot(RB_AUTOBOOT);
458                 } catch (runtime::Exception &e) {
459                         ::vconf_set_str(INTERNAL_STATE_VCONF_KEY, "error_partially_encrypted");
460                         ERROR(SINK, "Decryption failed - " + std::string(e.what()));
461                 }
462         };
463
464         std::thread asyncWork(decryptWorker);
465         asyncWork.detach();
466
467         return 0;
468 }
469
470 int InternalEncryption::recovery()
471 {
472         if (getState() != State::Unencrypted) {
473                 return -1;
474         }
475
476         //TODO
477         runtime::Process proc(PROG_FACTORY_RESET, wipeCommand);
478         if (proc.execute() == -1) {
479                 ERROR(SINK, "Failed to launch factory-reset");
480                 return -2;
481         }
482
483         return 0;
484 }
485
486 int InternalEncryption::isPasswordInitialized()
487 {
488         if (engine->isKeyMetaSet()) {
489                 return 1;
490         }
491         return 0;
492 }
493
494 int InternalEncryption::initPassword(const std::string& password)
495 {
496         KeyManager::data pwData(password.begin(), password.end());
497         KeyManager keyManager;
498
499         keyManager.initPassword(pwData);
500         engine->setKeyMeta(keyManager.serialize());
501         return 0;
502 }
503
504 int InternalEncryption::cleanPassword(const std::string& password)
505 {
506         KeyManager::data pwData(password.begin(), password.end());
507         KeyManager keyManager(engine->getKeyMeta());
508
509         if (!keyManager.verifyPassword(pwData)) {
510                 return -2;
511         }
512
513         engine->clearKeyMeta();
514         return 0;
515 }
516
517 int InternalEncryption::changePassword(const std::string& oldPassword,
518                                                                                 const std::string& newPassword)
519 {
520         KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
521         KeyManager::data newPwData(newPassword.begin(), newPassword.end());
522         KeyManager keyManager(engine->getKeyMeta());
523
524         if (!keyManager.verifyPassword(oldPwData)) {
525                 return -2;
526         }
527
528         keyManager.changePassword(oldPwData, newPwData);
529         engine->setKeyMeta(keyManager.serialize());
530
531         return 0;
532 }
533
534 int InternalEncryption::verifyPassword(const std::string& password)
535 {
536         KeyManager::data pwData(password.begin(), password.end());
537         KeyManager keyManager(engine->getKeyMeta());
538
539         if (keyManager.verifyPassword(pwData)) {
540                 return 1;
541         }
542         return 0;
543 }
544
545 int InternalEncryption::getState()
546 {
547         char *value = ::vconf_get_str(INTERNAL_STATE_VCONF_KEY);
548         if (value == NULL) {
549                 throw runtime::Exception("Failed to get vconf value");
550         }
551
552         std::string valueStr(value);
553         free(value);
554
555         if (valueStr == "encrypted") {
556                 return State::Encrypted;
557         } else if (valueStr == "unencrypted") {
558                 return State::Unencrypted;
559         } else {
560                 return State::Corrupted;
561         }
562
563         return 0;
564 }
565
566 unsigned int InternalEncryption::getSupportedOptions()
567 {
568         return engine->getSupportedOptions();
569 }
570
571 } // namespace ode