2 * Copyright (c) 2015 - 2019 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
21 #include <sys/mount.h>
24 #include <tzplatform_config.h>
25 #include <klay/file-user.h>
26 #include <klay/filesystem.h>
27 #include <klay/dbus/variant.h>
28 #include <klay/dbus/connection.h>
32 #include "progress-bar.h"
33 #include "rmi/common.h"
34 #include "file-footer.h"
36 #include "external-encryption.h"
43 bool isBootCompleted = false;
45 constexpr const char *DEFAULT_EXTERNAL_PATH = "/media/SDCardA1";
46 const char *PRIVILEGE_PLATFORM = "http://tizen.org/privilege/internal/default/platform";
50 INFO(SINK, "Launching SD card password popup.");
52 dbus::Connection &systemDBus = dbus::Connection::getSystem();
54 systemDBus.methodcall("org.freedesktop.systemd1",
55 "/org/freedesktop/systemd1",
56 "org.freedesktop.systemd1.Manager",
58 -1, "", "(ss)", "ode-external-lock.service", "replace");
59 } catch (runtime::Exception &e) {
60 ERROR(SINK, "Failed to launch SD card password popup: " + std::string(e.what()));
67 char *cryptoState = ::vconf_get_str(VCONFKEY_SDE_CRYPTO_STATE);
68 if (cryptoState == NULL)
71 bool encrypted = (strcmp(cryptoState, "encrypted") == 0);
76 void externalCallback(dbus::Variant parameters)
81 parameters.get("(issssssisibii)",
82 &intparams[0], // block type: 0 - scsi, 1 : mmc
83 &strparams[0], // devnode
84 &strparams[1], // syspath
85 &strparams[2], // usage
86 &strparams[3], // fs type
87 &strparams[4], // fs version
88 &strparams[5], // fs uuid enc
89 &intparams[1], // readonly: 0 - rw, 1 - ro
90 &strparams[6], // mount point
91 &intparams[2], // state: 0 - unmount, 1 - mount
92 &intparams[3], // primary: 0 - flase, 1 - true
93 &intparams[4], // flags: 1 - unmounted 2 - broken filesystem 4 - no filesystem 8 - not supported 16 - readonly
94 &intparams[5]); // storage id
96 if (intparams[0] != 1 || (std::string(strparams[3]) != "vfat" &&
97 std::string(strparams[3]) != "ext4")) {
98 DEBUG(SINK, "Storaged says it's not a regular SD card. Ignoring.");
102 if(intparams[2] == 0) {
103 INFO(SINK, "SD card not mounted, ignoring.");
104 int ret = ::vconf_unset(VCONFKEY_SDE_MOUNT_POINT);
106 ERROR(SINK, "vconf_unset() failed with " << ret);
108 INFO(SINK, "SD card mounted.");
110 ret = ::vconf_set_str(VCONFKEY_SDE_MOUNT_POINT, DEFAULT_EXTERNAL_PATH);
112 ERROR(SINK, "vconf_set() failed with " << ret);
116 if (isEncrypted() && isBootCompleted)
121 void bootCompletionCallback(dbus::Variant parameters)
123 auto waitForHomescreen = []() {
124 //For a delay until homescreen is totally loaded
127 INFO(SINK, "Boot completed.");
128 int ret = ::vconf_set_str(VCONFKEY_SDE_MOUNT_POINT, DEFAULT_EXTERNAL_PATH);
130 ERROR(SINK, "vconf_set() failed with " << ret);
131 } else if (isEncrypted()) {
134 isBootCompleted = true;
137 std::thread asyncWork(waitForHomescreen);
141 void externalAddEventReceiver()
143 dbus::Connection &systemDBus = dbus::Connection::getSystem();
145 systemDBus.subscribeSignal("",
146 "/Org/Tizen/System/Storage/Block/Manager",
147 "org.tizen.system.storage.BlockManager",
151 systemDBus.subscribeSignal("",
152 "/Org/Tizen/System/DeviceD/Core",
153 "org.tizen.system.deviced.core",
155 bootCompletionCallback);
159 * Introspection data for the exported object
162 * dbus-send --system --type=method_call --print-reply --dest=org.tizen.ode
163 * /org/tizen/ode/ExternalEncryption org.freedesktop.DBus.Introspectable.Introspect
165 const gchar introspectionXml[] =
167 " <interface name='org.tizen.ode.ExternalEncryption'>"
168 " <method name='UpdateCardStatus'>"
169 " <arg type='s' name='mountpoint' direction='in'/>"
170 " <arg type='i' name='status' direction='in'/>"
175 void dbusMethodCall(GDBusConnection *,
178 const gchar *interface,
181 GDBusMethodInvocation *invocation,
184 DEBUG(SINK, "dbusMethodCall sender: " << sender << ", object: " << object << ", interface: " <<
185 interface << ", method: " << method);
187 static_cast<ExternalEncryptionServer*>(user_data)->dbusMethodCall(method, params, invocation);
190 unsigned int getOptions()
192 unsigned int result = 0;
196 ::vconf_get_bool(VCONFKEY_SDE_EXCLUDE_MEDIAFILE, &value);
198 result |= ExternalEncryption::Option::OnlyNewFile;
202 ::vconf_get_bool(VCONFKEY_SDE_ENCRYPT_NEWFILE, &value);
204 result |= ExternalEncryption::Option::ExceptForMediaFile;
210 void setOptions(unsigned int options)
214 if (options & ExternalEncryption::Option::OnlyNewFile) {
219 ::vconf_set_bool(VCONFKEY_SDE_EXCLUDE_MEDIAFILE, value);
221 if (options & ExternalEncryption::Option::ExceptForMediaFile) {
226 ::vconf_set_bool(VCONFKEY_SDE_ENCRYPT_NEWFILE, value);
231 ExternalEncryptionServer::ExternalEncryptionServer(ServerContext &srv,
236 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::setMountPassword)(std::string));
237 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::mount)());
238 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::umount)());
239 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::encrypt)(std::string, unsigned int));
240 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::decrypt)(std::string));
241 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::recovery)());
242 server.expose(this, "", (int)(ExternalEncryptionServer::isPasswordInitialized)());
243 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::initPassword)(std::string));
244 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::cleanPassword)(std::string));
245 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::changePassword)(std::string, std::string));
246 server.expose(this, PRIVILEGE_PLATFORM, (int)(ExternalEncryptionServer::verifyPassword)(std::string));
247 server.expose(this, "", (int)(ExternalEncryptionServer::getState)());
248 server.expose(this, "", (unsigned int)(ExternalEncryptionServer::getSupportedOptions)());
249 server.expose(this, "", (std::string)(ExternalEncryptionServer::getDevicePath)());
251 server.createNotification("ExternalEncryptionServer::mount");
253 externalAddEventReceiver();
256 ExternalEncryptionServer::~ExternalEncryptionServer()
260 int ExternalEncryptionServer::setMountPassword(const std::string& password)
262 RequestLifetime rl(server);
264 return keyServer.get(getEngine().getSource(), password, mountKey);
267 int ExternalEncryptionServer::mount()
269 RequestLifetime rl(server);
271 if (mountKey.empty()) {
272 ERROR(SINK, "You need to call set_mount_password() first.");
273 return error::NoData;
276 BinaryData key = mountKey;
279 if (getStateInternal() != State::Encrypted) {
280 ERROR(SINK, "Cannot mount, SD card's state incorrect.");
281 return error::NoSuchDevice;
284 auto& engine = getEngine();
285 if (engine.isMounted()) {
286 INFO(SINK, "SD card already mounted.");
290 INFO(SINK, "Mounting external storage.");
292 engine.mount(key, getOptions());
293 } catch (runtime::Exception &e) {
294 ERROR(SINK, "Failed to mount: " + std::string(e.what()));
295 return error::Unknown;
298 server.notify("ExternalEncryptionServer::mount");
303 int ExternalEncryptionServer::umount()
305 RequestLifetime rl(server);
307 if (getStateInternal() != State::Encrypted) {
308 ERROR(SINK, "Cannot umount, SD card's state incorrect.");
309 return error::NoSuchDevice;
312 auto& engine = getEngine();
313 if (!engine.isMounted()) {
314 INFO(SINK, "SD card already umounted.");
318 INFO(SINK, "Closing all applications using external storage.");
319 killDependentApplications(engine.getDestination());
321 INFO(SINK, "Umounting external storage.");
324 } catch (runtime::Exception &e) {
325 ERROR(SINK, "Failed to umount: " + std::string(e.what()));
326 return error::Unknown;
332 int ExternalEncryptionServer::encrypt(const std::string &password, unsigned int options)
334 RequestLifetime rl(server);
336 if (getStateInternal() != State::Unencrypted) {
337 INFO(SINK, "Cannot encrypt, SD card's state incorrect.");
338 return error::NoSuchDevice;
341 BinaryData masterKey;
342 int ret = keyServer.get(getEngine().getSource(), password, masterKey);
343 if (ret != error::None)
346 auto encryptWorker = [masterKey, options, this](RequestLifetime&& rl) {
348 auto& engine = getEngine();
350 INFO(SINK, "Closing all applications using external storage.");
351 killDependentApplications(engine.getDestination());
353 INFO(SINK, "Encryption started.");
354 engine.encrypt(masterKey, options);
355 setOptions(options & engine.getSupportedOptions());
357 INFO(SINK, "Encryption completed.");
358 ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "encrypted");
359 server.notify("ExternalEncryptionServer::mount");
361 INFO(SINK, "Syncing disk.");
363 } catch (runtime::Exception &e) {
364 ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "error_partially_encrypted");
365 ERROR(SINK, "Encryption failed: " + std::string(e.what()));
369 std::thread asyncWork(encryptWorker, std::move(rl));
375 int ExternalEncryptionServer::decrypt(const std::string &password)
377 RequestLifetime rl(server);
379 if (getStateInternal() != State::Encrypted) {
380 ERROR(SINK, "Cannot decrypt, SD card's state incorrect.");
381 return error::NoSuchDevice;
384 BinaryData masterKey;
385 int ret = keyServer.get(getEngine().getSource(), password, masterKey);
386 if (ret != error::None)
389 auto decryptWorker = [masterKey, this](RequestLifetime&& rl) {
391 auto& engine = getEngine();
393 INFO(SINK, "Closing all applications using external storage.");
394 killDependentApplications(engine.getDestination());
396 INFO(SINK, "Umounting external storage.");
401 } catch (runtime::Exception &e) {
402 killDependentApplications(engine.getDestination());
406 INFO(SINK, "Decryption started.");
407 ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "error_partially_decrypted");
408 engine.decrypt(masterKey, getOptions());
410 INFO(SINK, "Decryption completed.");
411 ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "unencrypted");
413 INFO(SINK, "Syncing disk.");
415 } catch (runtime::Exception &e) {
416 ERROR(SINK, "Decryption failed: " + std::string(e.what()));
420 std::thread asyncWork(decryptWorker, std::move(rl));
426 int ExternalEncryptionServer::recovery()
428 RequestLifetime rl(server);
430 if (getStateInternal() == State::Unencrypted) {
431 return error::NoSuchDevice;
434 auto& engine = getEngine();
435 for (runtime::DirectoryIterator iter(engine.getSource()), end;
436 iter != end; ++iter) {
440 keyServer.removePassword(engine.getSource());
441 ::vconf_set_str(VCONFKEY_SDE_CRYPTO_STATE, "unencrypted");
446 int ExternalEncryptionServer::isPasswordInitialized()
448 return keyServer.isInitialized(getEngine().getSource());
451 int ExternalEncryptionServer::initPassword(const std::string& password)
453 return keyServer.init(getEngine().getSource(), password, Key::DEFAULT_256BIT);
456 int ExternalEncryptionServer::cleanPassword(const std::string& password)
458 return keyServer.remove(getEngine().getSource(), password);
461 int ExternalEncryptionServer::changePassword(const std::string &oldPassword,
462 const std::string &newPassword)
464 return keyServer.changePassword(getEngine().getSource(), oldPassword, newPassword);
467 int ExternalEncryptionServer::verifyPassword(const std::string& password)
469 return keyServer.verifyPassword(getEngine().getSource(), password);
472 int ExternalEncryptionServer::getState()
474 RequestLifetime rl(server);
476 return getStateInternal();
479 unsigned int ExternalEncryptionServer::getSupportedOptions()
481 RequestLifetime rl(server);
483 return getEngine().getSupportedOptions();
486 std::string ExternalEncryptionServer::getDevicePath() const
488 RequestLifetime rl(server);
490 return getEngine().getSource();
493 void ExternalEncryptionServer::dbusRegisterObject(GDBusConnection *connection)
496 GDBusNodeInfo *dbusIntrospectionData = g_dbus_node_info_new_for_xml(introspectionXml, &err);
497 if (dbusIntrospectionData == NULL) {
498 ERROR(SINK, "Dbus introspection data creation failed: " << err->message);
502 const GDBusInterfaceVTable interfaceVtable =
511 * dbus-send --system --type=method_call --print-reply --dest=org.tizen.ode
512 * /org/tizen/ode/ExternalEncryption org.tizen.ode.ExternalEncryption.UpdateCardStatus
513 * string:"/media/SDCardA1" int32:1
515 guint registrationId = g_dbus_connection_register_object(connection,
516 "/org/tizen/ode/ExternalEncryption",
517 dbusIntrospectionData->interfaces[0],
522 if (registrationId == 0)
523 ERROR(SINK, "Dbus object registration failed: " << err->message);
525 g_dbus_node_info_unref(dbusIntrospectionData);
528 void ExternalEncryptionServer::dbusMethodCall(const gchar *,
530 GDBusMethodInvocation *invocation)
532 RequestLifetime rl(server);
534 const gchar *mountPoint;
537 g_variant_get(params, "(&si)", &mountPoint, &cardStatus);
539 switch (cardStatus) {
541 DEBUG(SINK, "Card unmounted " << mountPoint);
543 int ret = ::vconf_unset(VCONFKEY_SDE_MOUNT_POINT);
545 ERROR(SINK, "vconf_set_str() failed with " << ret);
551 DEBUG(SINK, "Card mounted " << mountPoint);
553 int ret = ::vconf_set_str(VCONFKEY_SDE_MOUNT_POINT, mountPoint);
555 ERROR(SINK, "vconf_set_str() failed with " << ret);
556 else if (isEncrypted())
561 ERROR(SINK, "Unsupported card status: " << cardStatus);
562 g_dbus_method_invocation_return_error(invocation,
564 G_DBUS_ERROR_INVALID_ARGS,
565 "Unsupported card status");
568 g_dbus_method_invocation_return_value(invocation, NULL);
571 int ExternalEncryptionServer::getStateInternal() const
573 char *value = ::vconf_get_str(VCONFKEY_SDE_CRYPTO_STATE);
575 throw runtime::Exception("Failed to get vconf value.");
578 std::string valueStr(value);
581 if (valueStr == "encrypted")
582 return State::Encrypted;
583 else if (valueStr == "unencrypted")
584 return State::Unencrypted;
585 else if (valueStr == "error_partially_encrypted" || valueStr == "error_partially_decrypted")
586 return State::Corrupted;
588 return State::NotSupported;
591 EXTERNAL_ENGINE& ExternalEncryptionServer::getEngine() const
594 char *tmp = ::vconf_get_str(VCONFKEY_SDE_MOUNT_POINT);
596 static_assert(DEFAULT_EXTERNAL_PATH);
598 std::string mountPoint(tmp ? tmp : DEFAULT_EXTERNAL_PATH);
601 runtime::File f(mountPoint);
602 mountPoint = f.readlink();
604 engine.reset(new EXTERNAL_ENGINE(mountPoint,
606 ProgressBar(VCONFKEY_SDE_ENCRYPT_PROGRESS)));