diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml index a46f96a9b..700488c51 100644 --- a/data/org.freedesktop.UDisks2.xml +++ b/data/org.freedesktop.UDisks2.xml @@ -2360,6 +2360,19 @@ + + + + + + diff --git a/src/tests/dbus-tests/test_50_block.py b/src/tests/dbus-tests/test_50_block.py index 82d8a84c8..f210142e5 100644 --- a/src/tests/dbus-tests/test_50_block.py +++ b/src/tests/dbus-tests/test_50_block.py @@ -357,6 +357,35 @@ def test_rescan(self): disk.Rescan(self.no_options, dbus_interface=self.iface_prefix + '.Block') + def test_encrypt(self): + disk = self.vdevs[0] + device = self.get_device(disk) + self.assertIsNotNone(device) + + d = dbus.Dictionary(signature='sv') + d['passphrase'] = "shouldnotseeme" + d['key-size'] = dbus.UInt32(256) + d['cipher'] = "aes" + d['cipher-mode'] = "cbc-essiv:sha256" + d['resilience'] = "datashift" # required, otherwise won't work + d['hash'] = "sha256" + d['max-hotzone-size'] = dbus.UInt64(0) + d['sector-size'] = dbus.UInt32(512) + d['new-volume_key'] = True + + device.Encrypt(self.LUKS_PASSPHRASE, d, dbus_interface=self.iface_prefix + '.Block') + + # verify that device now has the .Encrypted interface + device = self.get_device(disk) + self.assertHasIface(device, "org.freedesktop.UDisks2.Encrypted") + + # verify that the newly encrypted device can be unlocked + luks_obj = device.Unlock("shouldnotseeme", self.no_options, + dbus_interface=self.iface_prefix + '.Encrypted') + self.assertIsNotNone(luks_obj) + ret, _ = self.run_command("ls /dev/mapper/luks*") + self.assertEqual(ret, 0) + class UdisksBlockRemovableTest(udiskstestcase.UdisksTestCase): '''Extra block device tests over a scsi_debug removable device''' diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c index 5b5588b2c..708e855a1 100644 --- a/src/udiskslinuxblock.c +++ b/src/udiskslinuxblock.c @@ -4308,6 +4308,129 @@ handle_restore_encrypted_header (UDisksBlock *encrypted, /* ---------------------------------------------------------------------------------------------------- */ +/* runs in thread dedicated to handling method call */ +static gboolean +handle_encrypt (UDisksBlock *block, + GDBusMethodInvocation *invocation, + const gchar *passphrase, + GVariant *options) +{ + UDisksObject *object = NULL; + UDisksDaemon *daemon; + UDisksState *state = NULL; + uid_t caller_uid; + GError *error = NULL; + UDisksBaseJob *job = NULL; + + const gchar *device; + BDCryptoKeyslotContext *context = NULL; + guint32 key_size; + gchar *cipher; + gchar *cipher_mode; + gchar *resilience; + gchar *hash; + guint64 max_hotzone_size; + guint32 sector_size; + gboolean new_volume_key; + gboolean offline = TRUE; +// gchar *pbkdf_type; +// BDCryptoLUKSPBKDF *pbkdf = NULL; + BDCryptoLUKSReencryptParams *params = NULL; + + object = udisks_daemon_util_dup_object (block, &error); + if (object == NULL) + { + g_dbus_method_invocation_return_gerror (invocation, error); + goto out; + } + + daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object)); + state = udisks_daemon_get_state (daemon); + + udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object)); + udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object))); + + if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL /* GCancellable */, &caller_uid, &error)) + { + g_dbus_method_invocation_return_gerror (invocation, error); + goto out; + } + + job = udisks_daemon_launch_simple_job (daemon, + UDISKS_OBJECT (object), + "block-encrypt", + caller_uid, + NULL); + if (job == NULL) + { + g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED, + "Failed to create a job object"); + goto out; + } + + udisks_linux_block_encrypted_lock (block); + // do stuff here + device = udisks_block_get_device (block); + + context = bd_crypto_keyslot_context_new_passphrase ((const guint8 *) passphrase, + strlen(passphrase), + &error); + if (!context) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Error encrypting block device %s (ctx): %s", + device, + error->message); + udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message); + udisks_linux_block_encrypted_unlock (block); + goto out; + } + + g_variant_lookup (options, "key-size", "u", &key_size); + g_variant_lookup (options, "cipher", "&s", &cipher); + g_variant_lookup (options, "cipher-mode", "&s", &cipher_mode); + g_variant_lookup (options, "resilience", "&s", &resilience); + g_variant_lookup (options, "hash", "&s", &hash); + g_variant_lookup (options, "max-hotzone-size", "u", &max_hotzone_size); + g_variant_lookup (options, "sector-size", "u", §or_size); + g_variant_lookup (options, "new-volume_key", "b", &new_volume_key); + // `offline` is already determined + + params = bd_crypto_luks_reencrypt_params_new (key_size, cipher, cipher_mode, resilience, hash, max_hotzone_size, sector_size, new_volume_key, offline, NULL); + + if (! bd_crypto_luks_encrypt (device, params, context, NULL /* prog_func -- TODO */, &error)) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Error encrypting block device %s (enc): %s", + device, + error->message); + udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message); + udisks_linux_block_encrypted_unlock (block); + goto out; + } + + // + udisks_linux_block_encrypted_unlock (block); + + udisks_block_complete_encrypt (block, invocation); + udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), TRUE, NULL); + + out: + if (object != NULL) + udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object)); + if (state != NULL) + udisks_state_check (state); + g_clear_object (&object); + g_clear_error (&error); + return TRUE; /* returning TRUE means that we handled the method invocation */ +} + +/* ---------------------------------------------------------------------------------------------------- */ + static void block_iface_init (UDisksBlockIface *iface) { @@ -4322,4 +4445,5 @@ block_iface_init (UDisksBlockIface *iface) iface->handle_open_device = handle_open_device; iface->handle_rescan = handle_rescan; iface->handle_restore_encrypted_header = handle_restore_encrypted_header; + iface->handle_encrypt = handle_encrypt; } diff --git a/udisks/udisksclient.c b/udisks/udisksclient.c index 56ca6ca57..38c1ccaf8 100644 --- a/udisks/udisksclient.c +++ b/udisks/udisksclient.c @@ -2738,6 +2738,7 @@ udisks_client_get_job_description_from_operation (const gchar *operation) g_hash_table_insert (hash, (gpointer) "encrypted-header-backup", (gpointer) C_("job", "Backing Up Header of an Encrypted Device")); g_hash_table_insert (hash, (gpointer) "encrypted-reencrypt", (gpointer) C_("job", "Reencrypting an Encrypted Device")); g_hash_table_insert (hash, (gpointer) "block-restore-encrypted-header", (gpointer) C_("job", "Restoring Header of an Encrypted Device")); + g_hash_table_insert (hash, (gpointer) "block-encrypt", (gpointer) C_("job", "Encrypting a Block Device")); g_hash_table_insert (hash, (gpointer) "swapspace-start", (gpointer) C_("job", "Starting Swap Device")); g_hash_table_insert (hash, (gpointer) "swapspace-stop", (gpointer) C_("job", "Stopping Swap Device")); g_hash_table_insert (hash, (gpointer) "swapspace-modify", (gpointer) C_("job", "Modifying Swap Device"));