f23698f5fc23eddf77731fa93f4e544e255bb92a
[platform/core/security/ode.git] / server / extension-encryption.cpp
1 /*
2  *  Copyright (c) 2017 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 <mutex>
17
18 #include <signal.h>
19 #include <unistd.h>
20 #include <sys/mount.h>
21 #include <stdio.h>
22 #include <mntent.h>
23
24 #include <klay/file-user.h>
25 #include <klay/filesystem.h>
26 #include <klay/dbus/variant.h>
27 #include <klay/dbus/connection.h>
28
29 #include "logger.h"
30 #include "ext4-tool.h"
31 #include "engine/encryption/cryptsetup-engine.h"
32 #include "key-manager/key-manager.h"
33
34 #include "rmi/extension-encryption.h"
35
36 #define EXTENSION_ENGINE        CryptsetupEngine
37 #define EXTENSION_NAME_DEF      "extension"
38
39 namespace ode {
40
41 namespace {
42
43 const size_t DEFAULT_KEY_SIZE = 64;
44
45 const char *EXTENSION_DEV_PATH  = "/dev/mmcblk1p1";
46 const char *EXTENSION_NAME              = EXTENSION_NAME_DEF;
47 const char *EXTENSION_MAP_PATH  = "/dev/mapper/" EXTENSION_NAME_DEF;
48 const char *EXTENSION_FS_TYPE   = "crypto_LUKS";
49
50 const char *PRIVILEGE_PLATFORM  = "http://tizen.org/privilege/internal/default/platform";
51
52 const char *STORAGED_DBUS_BUSNAME       = "org.tizen.system.storage";
53 const char *STORAGED_DBUS_OBJECT        = "/Org/Tizen/System/Storage/Block/Manager";
54 const char *STORAGED_DBUS_INTERFACE     = "org.tizen.system.storage.BlockManager";
55
56 std::unique_ptr<EXTENSION_ENGINE> engine;
57
58 std::mutex apiGuard;
59 std::mutex stateGuard;
60 std::condition_variable storagedCv;
61
62 std::string findMntPath(const std::string &devPath)
63 {
64         std::string ret;
65
66         FILE* mtab = setmntent("/etc/mtab", "r");
67         struct mntent* entry = NULL;
68         while ((entry = getmntent(mtab)) != NULL) {
69                 if (devPath == entry->mnt_fsname) {
70                         ret = entry->mnt_dir;
71                         break;
72                 }
73         }
74         endmntent(mtab);
75
76         return ret;
77 }
78
79 void killDependedApplications(const std::string &mntPath)
80 {
81         for (pid_t pid : runtime::FileUser::getList(mntPath, true)) {
82                 INFO(SINK, "Close process - " + std::to_string(pid));
83                 ::kill(pid, SIGKILL);
84         }
85 }
86
87 bool findKillAndUmount(const std::string &devPath)
88 {
89         std::string realMntPath = findMntPath(devPath);
90         if (!realMntPath.empty()) {
91                 INFO(SINK, "Closing all applications using an SD card...");
92                 killDependedApplications(realMntPath);
93
94                 int ret = ::umount(realMntPath.c_str());
95                 if (ret != 0) {
96                         ERROR(SINK, "The card is still mounted, umount failed with: "
97                                   + std::to_string(ret));
98                         return false;
99                 }
100         }
101
102         return true;
103 }
104
105 } // namsepace
106
107 ExtensionEncryption::ExtensionEncryption(ODEControlContext &ctx) :
108         context(ctx),
109         currentReq(Request::NONE)
110 {
111         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::mount)(std::string));
112         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::umount)());
113         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::format)(std::string));
114         context.expose(this, "", (int)(ExtensionEncryption::isPasswordInitialized)());
115         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::initPassword)(std::string));
116         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::cleanPassword)(std::string));
117         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::changePassword)(std::string, std::string));
118         context.expose(this, PRIVILEGE_PLATFORM, (int)(ExtensionEncryption::verifyPassword)(std::string));
119         context.expose(this, "", (int)(ExtensionEncryption::getState)());
120
121         context.createNotification("ExtensionEncryption::mount");
122
123         // TODO: think about handling more than one card / more than one engine
124         // it would require global API change to select which card is handled atm
125         engine.reset(new EXTENSION_ENGINE(EXTENSION_DEV_PATH));
126
127         queryStoraged();
128         subscribeToStoraged();
129 }
130
131 ExtensionEncryption::~ExtensionEncryption()
132 {
133         unsubscribeFromStoraged();
134 }
135
136 int ExtensionEncryption::mount(const std::string& password)
137 {
138         std::lock_guard<std::mutex> guardLock(apiGuard);
139         std::unique_lock<std::mutex> stateLock(stateGuard);
140
141         if (getStatePriv() != State::Encrypted) {
142                 ERROR(SINK, "Cannot mount, card not inserted or corrupted");
143                 return -1;
144         }
145
146         KeyManager::data pwData(password.begin(), password.end());
147         KeyManager keyManager(engine->getKeyMeta());
148
149         if (!keyManager.verifyPassword(pwData)) {
150                 ERROR(SINK, "Wrong password passed.");
151                 return -2;
152         }
153
154         if (isMounted()) {
155                 INFO(SINK, "Already mounted");
156                 return 0;
157         }
158
159         KeyManager::data mountKey = keyManager.getMasterKey(pwData);
160
161         INFO(SINK, "Mount extension storage...");
162
163         if (!isOpened()) {
164                 // Storaged will mount MAP automatically when it appears, let's prepare
165                 currentReq = Request::MOUNT;
166
167                 try {
168                         INFO(SINK, "Open the MAP of an extension storage...");
169                         engine->open(CryptsetupEngine::DeviceType::LUKS, EXTENSION_NAME, mountKey);
170                 } catch (runtime::Exception &e) {
171                         ERROR(SINK, "Open failed: " + std::string(e.what()));
172                         return -3;
173                 }
174
175                 INFO(SINK, "Wait for the storaged to mount the MAP automatically...");
176                 if (!storagedCv.wait_for(stateLock, std::chrono::seconds(1), [this] {
177                                         return currentReq == Request::NONE;
178                                 })) {
179                         ERROR(SINK, "Storaged timed out mounting the MAP.");
180                         return -3;
181                 }
182         } else {
183                 INFO(SINK, "Ask storaged to mount extension storage...");
184                 if (!storagedMount(stateLock)) {
185                         return -3;
186                 }
187         }
188
189         context.notify("ExtensionEncryption::mount");
190         return 0;
191 }
192
193 int ExtensionEncryption::umount()
194 {
195         std::lock_guard<std::mutex> guardLock(apiGuard);
196         std::unique_lock<std::mutex> stateLock(stateGuard);
197
198         if (getStatePriv() != State::Encrypted) {
199                 ERROR(SINK, "Cannot umount, card not inserted or corrupted.");
200                 return -1;
201         }
202
203         if (!isMounted() && !isOpened()) {
204                 INFO(SINK, "Already umounted.");
205                 return 0;
206         }
207
208         INFO(SINK, "Umount extension storage...");
209
210         if (isMounted()) {
211                 INFO(SINK, "Close all applications using extension storage...");
212                 killDependedApplications(info[Device::MAP].mntPath);
213
214                 INFO(SINK, "Ask storaged to umount extension storage...");
215                 if (!storagedUnmount(stateLock)) {
216                         return -3;
217                 }
218         }
219
220         if (isOpened()) {
221                 INFO(SINK, "Close the MAP of an extension storage...");
222                 try {
223                         CryptsetupEngine::close(EXTENSION_NAME);
224                 } catch (runtime::Exception &e) {
225                         ERROR(SINK, "Close failed: " + std::string(e.what()));
226                         return -3;
227                 }
228         }
229
230         return 0;
231 }
232
233 int ExtensionEncryption::format(const std::string &password)
234 {
235         int status = 0;
236         std::condition_variable workerCv;
237
238         auto formatWorker = [&, this]() {
239                 try {
240                         std::lock_guard<std::mutex> guardLock(apiGuard);
241                         std::unique_lock<std::mutex> stateLock(stateGuard);
242
243                         if (!isInserted()) {
244                                 ERROR(SINK, "There is no card inserted.");
245                                 status = -1;
246                                 stateLock.unlock();
247                                 workerCv.notify_one();
248                                 return;
249                         }
250
251                         if (isMounted() || isOpened()) {
252                                 ERROR(SINK, "The card is still mounted and/or opened, umount and close first.");
253                                 status = -1;
254                                 stateLock.unlock();
255                                 workerCv.notify_one();
256                                 return;
257                         }
258
259                         KeyManager::data pwData(password.begin(), password.end());
260                         KeyManager keyManager(engine->getKeyMeta());
261
262                         if (!keyManager.verifyPassword(pwData)) {
263                                 ERROR(SINK, "Wrong password passed.");
264                                 status = -2;
265                                 stateLock.unlock();
266                                 workerCv.notify_one();
267                                 return;
268                         }
269
270                         // no error, let's notify the main thread it can return
271                         status = 1;
272                         stateLock.unlock();
273                         workerCv.notify_one();
274
275                         KeyManager::data masterKey = keyManager.getMasterKey(pwData);
276
277                         // TODO: this probably needs a rework, some sort of communication
278                         // and/or merge with External. The use case for it might be:
279                         // 1. The mmc is mounted by something else, somewhere else. Do we care?
280                         // 2. We take over the cd card from External.
281                         if (!findKillAndUmount(EXTENSION_DEV_PATH))
282                                 return;
283
284                         INFO(SINK, "Creating LUKS...");
285                         engine->format(CryptsetupEngine::DeviceType::LUKS, masterKey);
286
287                         INFO(SINK, "Opening LUKS...");
288                         std::string mappingPath = engine->open(CryptsetupEngine::DeviceType::LUKS,
289                                                                                                    EXTENSION_NAME,
290                                                                                                    masterKey);
291
292                         INFO(SINK, "Creating EXT4...");
293                         Ext4Tool::mkfs(mappingPath);
294
295                         INFO(SINK, "Closing up the operation...");
296                         CryptsetupEngine::close(EXTENSION_NAME);
297                         sync();
298
299                         INFO(SINK, "Formatting completed");
300                 } catch (runtime::Exception &e) {
301                         ERROR(SINK, "Formatting thread failed: " + std::string(e.what()));
302                 }
303         };
304
305         std::thread asyncWork(formatWorker);
306         asyncWork.detach();
307
308         std::unique_lock<std::mutex> stateLock(stateGuard);
309         if(!workerCv.wait_for(stateLock, std::chrono::seconds(1), [&status] {
310                                 return status != 0;
311                         })) {
312                 ERROR(SINK, "Timed out waiting for format status.");
313                 return -4;
314         }
315
316         if (status < 0)
317                 return status;
318
319         return 0;
320 }
321
322 int ExtensionEncryption::isPasswordInitialized()
323 {
324         std::lock_guard<std::mutex> guardLock(apiGuard);
325
326         if (engine->isKeyMetaSet()) {
327                 return 1;
328         }
329
330         return 0;
331 }
332
333 int ExtensionEncryption::initPassword(const std::string& password)
334 {
335         std::lock_guard<std::mutex> guardLock(apiGuard);
336
337         KeyManager::data pwData(password.begin(), password.end());
338         KeyManager keyManager;
339
340         keyManager.initPassword(pwData, DEFAULT_KEY_SIZE);
341         engine->setKeyMeta(keyManager.serialize());
342         return 0;
343 }
344
345 int ExtensionEncryption::cleanPassword(const std::string& password)
346 {
347         std::lock_guard<std::mutex> guardLock(apiGuard);
348
349         KeyManager::data pwData(password.begin(), password.end());
350         KeyManager keyManager(engine->getKeyMeta());
351
352         if (!keyManager.verifyPassword(pwData)) {
353                 ERROR(SINK, "Wrong password passed.");
354                 return -2;
355         }
356
357         engine->clearKeyMeta();
358         return 0;
359 }
360
361 int ExtensionEncryption::changePassword(const std::string &oldPassword,
362                                                                            const std::string &newPassword)
363 {
364         std::lock_guard<std::mutex> guardLock(apiGuard);
365
366         KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
367         KeyManager::data newPwData(newPassword.begin(), newPassword.end());
368         KeyManager keyManager(engine->getKeyMeta());
369
370         if (!keyManager.verifyPassword(oldPwData)) {
371                 ERROR(SINK, "Wrong password passed.");
372                 return -2;
373         }
374
375         keyManager.changePassword(oldPwData, newPwData);
376         engine->setKeyMeta(keyManager.serialize());
377
378         return 0;
379 }
380
381 int ExtensionEncryption::verifyPassword(const std::string& password)
382 {
383         std::lock_guard<std::mutex> guardLock(apiGuard);
384
385         KeyManager::data pwData(password.begin(), password.end());
386         KeyManager keyManager(engine->getKeyMeta());
387
388         if (keyManager.verifyPassword(pwData)) {
389                 return 1;
390         }
391
392         return 0;
393 }
394
395 int ExtensionEncryption::getState()
396 {
397         std::lock_guard<std::mutex> guardLock(apiGuard);
398         std::unique_lock<std::mutex> stateLock(stateGuard);
399
400         return getStatePriv();
401 }
402
403 void ExtensionEncryption::logStoragedEvent(Operation op, Device d)
404 {
405         DEBUG(SINK, "Storaged event:");
406
407         switch(op) {
408         case Operation::ADDED:
409                 DEBUG(SINK, "   Operation: ADDED");
410                 break;
411         case Operation::CHANGED:
412                 DEBUG(SINK, "   Operation: CHANGED");
413                 break;
414         case Operation::REMOVED:
415                 DEBUG(SINK, "   Operation: REMOVED");
416                 break;
417         default:
418                 break;
419         }
420
421         switch(d) {
422         case Device::MMC:
423                 DEBUG(SINK, "   Device: MMC");
424                 break;
425         case Device::MAP:
426                 DEBUG(SINK, "   Device: MAP");
427                 break;
428         default:
429                 break;
430         }
431
432         DEBUG(SINK, "   Mnt Path: " + info[d].mntPath);
433         DEBUG(SINK, "   Fs Type: " + info[d].fsType);
434         DEBUG(SINK, "   Sys path: " + info[d].sysPath);
435         DEBUG(SINK, "   Mounted: " + std::to_string(info[d].mounted));
436         DEBUG(SINK, "   ID: " + std::to_string(info[d].storagedId));
437 }
438
439 void ExtensionEncryption::handleDevice(Operation op,
440                                                                            const std::vector<int> &intparams,
441                                                                            const std::vector<char*> &strparams)
442 {
443         Device d;
444
445         if (std::string(strparams[0]) == EXTENSION_DEV_PATH && intparams[0] == 1) {
446                 d = Device::MMC;
447         } else if (std::string(strparams[0]) == EXTENSION_MAP_PATH && intparams[0] == 2) {
448                 d = Device::MAP;
449         } else {
450                 DEBUG(SINK, "Storaged event: neither extension MMC nor extension mapping, ignoring");
451                 return;
452         }
453
454         std::unique_lock<std::mutex> stateLock(stateGuard);
455
456         if (op == Operation::REMOVED) {
457                 info[d].clear();
458         } else {
459                 info[d].mntPath = strparams[6];
460                 info[d].fsType = strparams[3];
461                 info[d].sysPath = strparams[1];
462                 info[d].mounted = intparams[2];
463                 info[d].storagedId = intparams[5];
464         }
465
466         logStoragedEvent(op, d);
467
468         // removing/reformatting the SD card does not automatically close the DM crypt mapping
469         if (d == Device::MMC && (op == Operation::REMOVED ||
470                                                          (op == Operation::CHANGED &&
471                                                           info[d].fsType != EXTENSION_FS_TYPE))) {
472                 if (isMounted()) {
473                         INFO(SINK, "MMC card removed while still mounted, umounting.");
474                         if (!findKillAndUmount(EXTENSION_MAP_PATH)) {
475                                 return;
476                         }
477                 }
478
479                 if (isOpened()) {
480                         INFO(SINK, "MMC card removed while LUKS is still opened, closing.");
481                         try {
482                                 CryptsetupEngine::close(EXTENSION_NAME);
483                         } catch (runtime::Exception &e) {
484                                 ERROR(SINK, "Closing failed: " + std::string(e.what()));
485                                 return;
486                         }
487                 }
488
489                 return;
490         }
491
492         if (d == Device::MMC && op == Operation::ADDED &&
493                 getStatePriv() == State::Encrypted) {
494                 // TODO: when UI gets written it should be triggered here.
495
496                 return;
497         }
498
499         if (d == Device::MAP && op == Operation::CHANGED) {
500                 if ((currentReq == Request::MOUNT  &&  info[Device::MAP].mounted) ||
501                         (currentReq == Request::UMOUNT && !info[Device::MAP].mounted)) {
502
503                         currentReq = Request::NONE;
504                         stateLock.unlock();
505                         storagedCv.notify_one();
506
507                         return;
508                 }
509         }
510 }
511
512 void ExtensionEncryption::parseVariant(Operation op, dbus::Variant parameters)
513 {
514         std::vector<int> intparams(6);
515         std::vector<char*> strparams(7);
516
517         parameters.get("(issssssisibii)",
518                                    &intparams[0], // block type: 0 - scsi, 1 : mmc, 2 : mapper
519                                    &strparams[0], // devnode
520                                    &strparams[1], // syspath
521                                    &strparams[2], // usage
522                                    &strparams[3], // fs type
523                                    &strparams[4], // fs version
524                                    &strparams[5], // fs uuid enc
525                                    &intparams[1], // readonly: 0 - rw, 1 - ro
526                                    &strparams[6], // mount point
527                                    &intparams[2], // state: 0 - unmount, 1 - mount
528                                    &intparams[3], // primary: 0 - false, 1 - true
529                                    &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
530                                    &intparams[5]); // storage id
531
532         handleDevice(op, intparams, strparams);
533 }
534
535 void ExtensionEncryption::queryStoraged()
536 {
537         INFO(SINK, "Querying the storaged for devices...");
538
539         dbus::VariantIterator vi;
540
541         try {
542                 dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
543                                                                                                  STORAGED_DBUS_OBJECT,
544                                                                                                  STORAGED_DBUS_INTERFACE,
545                                                                                                  "GetDeviceList",
546                                                                                                  -1,
547                                                                                                  "(a(issssssisibii))",
548                                                                                                  "(s)",
549                                                                                                  "all").get("(a(issssssisibii))", &vi);
550         } catch (runtime::Exception &e) {
551                 ERROR(SINK, "Failed to query storaged: " + std::string(e.what()));
552         }
553
554         std::vector<int> intparams(6);
555         std::vector<char*> strparams(7);
556
557         while(vi.get("(issssssisibii)",
558                                  &intparams[0], // block type: 0 - scsi, 1 : mmc, 2 : mapper
559                                  &strparams[0], // devnode
560                                  &strparams[1], // syspath
561                                  &strparams[2], // usage
562                                  &strparams[3], // fs type
563                                  &strparams[4], // fs version
564                                  &strparams[5], // fs uuid enc
565                                  &intparams[1], // readonly: 0 - rw, 1 - ro
566                                  &strparams[6], // mount point
567                                  &intparams[2], // state: 0 - unmount, 1 - mount
568                                  &intparams[3], // primary: 0 - false, 1 - true
569                                  &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
570                                  &intparams[5])) // storage id
571         {
572                 handleDevice(Operation::ADDED, intparams, strparams);
573         }
574 }
575
576 void ExtensionEncryption::subscribeToStoraged()
577 {
578         dbus::Connection &systemDBus = dbus::Connection::getSystem();
579
580         auto subscribe = [&systemDBus, this](Operation op, const std::string &method) {
581                 dbus::Connection::SignalCallback callback =
582                 std::bind(&ExtensionEncryption::parseVariant,
583                                   this,
584                                   op,
585                                   std::placeholders::_1);
586
587                 subId[op] = systemDBus.subscribeSignal("",
588                                                                                            STORAGED_DBUS_OBJECT,
589                                                                                            STORAGED_DBUS_INTERFACE,
590                                                                                            method.c_str(),
591                                                                                            callback);
592         };
593
594         subscribe(Operation::ADDED, "DeviceAdded");
595         subscribe(Operation::CHANGED, "DeviceChanged");
596         subscribe(Operation::REMOVED, "DeviceRemoved");
597 }
598
599 void ExtensionEncryption::unsubscribeFromStoraged()
600 {
601         dbus::Connection &systemDBus = dbus::Connection::getSystem();
602
603         systemDBus.unsubscribeSignal(subId[Operation::ADDED]);
604         systemDBus.unsubscribeSignal(subId[Operation::CHANGED]);
605         systemDBus.unsubscribeSignal(subId[Operation::REMOVED]);
606 }
607
608 bool ExtensionEncryption::storagedMount(std::unique_lock<std::mutex> &lock)
609 {
610         currentReq = Request::MOUNT;
611
612         int ret = -1;
613         try {
614                 dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
615                                                                                                  STORAGED_DBUS_OBJECT,
616                                                                                                  STORAGED_DBUS_INTERFACE,
617                                                                                                  "Mount",
618                                                                                                  -1,
619                                                                                                  "(i)",
620                                                                                                  "(is)",
621                                                                                                  info[Device::MAP].storagedId,
622                                                                                                  info[Device::MAP].mntPath.c_str()).get("(i)", &ret);
623         } catch (runtime::Exception &e) {
624                 ERROR(SINK, "Failed to call mount in storaged: " + std::string(e.what()));
625                 currentReq = Request::NONE;
626                 return false;
627         }
628
629         if (ret != 0) {
630                 ERROR(SINK, "Storaged failed to mount: " + std::to_string(ret));
631                 currentReq = Request::NONE;
632                 return false;
633         }
634
635         if (!storagedCv.wait_for(lock, std::chrono::seconds(1), [this] {
636                                 return currentReq == Request::NONE;
637                         })) {
638                 ERROR(SINK, "Storaged timed out mounting the MAP.");
639                 currentReq = Request::NONE;
640                 return false;
641         }
642
643         return true;
644 }
645
646 bool ExtensionEncryption::storagedUnmount(std::unique_lock<std::mutex> &lock)
647 {
648         currentReq = Request::UMOUNT;
649
650         int ret = -1;
651         try {
652                 dbus::Connection::getSystem().methodcall(STORAGED_DBUS_BUSNAME,
653                                                                                                  STORAGED_DBUS_OBJECT,
654                                                                                                  STORAGED_DBUS_INTERFACE,
655                                                                                                  "Unmount",
656                                                                                                  -1,
657                                                                                                  "(i)",
658                                                                                                  "(ii)",
659                                                                                                  info[Device::MAP].storagedId,
660                                                                                                  0).get("(i)", &ret);
661         } catch (runtime::Exception &e) {
662                 ERROR(SINK, "Failed to call unmount in storaged: " + std::string(e.what()));
663                 currentReq = Request::NONE;
664                 return false;
665         }
666
667         if (ret != 0) {
668                 ERROR(SINK, "Storaged failed to unmount: " + std::to_string(ret));
669                 currentReq = Request::NONE;
670                 return false;
671         }
672
673         if (!storagedCv.wait_for(lock, std::chrono::seconds(1), [this] {
674                                 return currentReq == Request::NONE;
675                         })) {
676                 ERROR(SINK, "Storaged timed out unmounting the MAP.");
677                 currentReq = Request::NONE;
678                 return false;
679         }
680
681         return true;
682 }
683
684 int ExtensionEncryption::getStatePriv() const
685 {
686         if (!isInserted()) {
687                 ERROR(SINK, "Cannot check state, card not inserted");
688                 return -1;
689         }
690
691         if (info[Device::MMC].fsType == EXTENSION_FS_TYPE)
692                 return State::Encrypted;
693
694         return State::Corrupted;
695 }
696
697 bool ExtensionEncryption::isInserted() const
698 {
699         return info[Device::MMC].storagedId >= 0;
700 }
701
702 bool ExtensionEncryption::isOpened() const
703 {
704         return info[Device::MAP].storagedId >= 0;
705 }
706
707 bool ExtensionEncryption::isMounted() const
708 {
709         return info[Device::MAP].mounted;
710 }
711
712 } // namespace ode