return prog_exists ("cryptsetup");
}
-static int
-luks_open (const char *device, const char *key, const char *mapname,
- int readonly)
+/* Callers must also call remove_temp (tempfile). */
+static char *
+write_key_to_temp (const char *key)
{
- /* Sanity check: /dev/mapper/mapname must not exist already. Note
- * that the device-mapper control device (/dev/mapper/control) is
- * always there, so you can't ever have mapname == "control".
- */
- size_t len = strlen (mapname);
- char devmapper[len+32];
- snprintf (devmapper, len+32, "/dev/mapper/%s", mapname);
- if (access (devmapper, F_OK) == 0) {
- reply_with_error ("%s: device already exists", devmapper);
- return -1;
+ char *tempfile = strdup ("/tmp/luksXXXXXX");
+ if (!tempfile) {
+ reply_with_perror ("strdup");
+ return NULL;
}
- char tempfile[] = "/tmp/luksXXXXXX";
int fd = mkstemp (tempfile);
if (fd == -1) {
reply_with_perror ("mkstemp");
- return -1;
+ goto error;
}
- len = strlen (key);
+ size_t len = strlen (key);
if (xwrite (fd, key, len) == -1) {
reply_with_perror ("write");
close (fd);
- unlink (tempfile);
- return -1;
+ goto error;
}
if (close (fd) == -1) {
reply_with_perror ("close");
- unlink (tempfile);
+ goto error;
+ }
+
+ return tempfile;
+
+ error:
+ unlink (tempfile);
+ free (tempfile);
+ return NULL;
+}
+
+static void
+remove_temp (char *tempfile)
+{
+ unlink (tempfile);
+ free (tempfile);
+}
+
+static int
+luks_open (const char *device, const char *key, const char *mapname,
+ int readonly)
+{
+ /* Sanity check: /dev/mapper/mapname must not exist already. Note
+ * that the device-mapper control device (/dev/mapper/control) is
+ * always there, so you can't ever have mapname == "control".
+ */
+ size_t len = strlen (mapname);
+ char devmapper[len+32];
+ snprintf (devmapper, len+32, "/dev/mapper/%s", mapname);
+ if (access (devmapper, F_OK) == 0) {
+ reply_with_error ("%s: device already exists", devmapper);
return -1;
}
+ char *tempfile = write_key_to_temp (key);
+ if (!tempfile)
+ return -1;
+
const char *argv[16];
size_t i = 0;
char *err;
int r = commandv (NULL, &err, (const char * const *) argv);
- unlink (tempfile);
+ remove_temp (tempfile);
if (r == -1) {
reply_with_error ("%s", err);
return 0;
}
+
+static int
+luks_format (const char *device, const char *key, int keyslot,
+ const char *cipher)
+{
+ char *tempfile = write_key_to_temp (key);
+ if (!tempfile)
+ return -1;
+
+ const char *argv[16];
+ char keyslot_s[16];
+ size_t i = 0;
+
+ argv[i++] = "cryptsetup";
+ argv[i++] = "-q";
+ if (cipher) {
+ argv[i++] = "--cipher";
+ argv[i++] = cipher;
+ }
+ argv[i++] = "--key-slot";
+ snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
+ argv[i++] = keyslot_s;
+ argv[i++] = "luksFormat";
+ argv[i++] = device;
+ argv[i++] = tempfile;
+ argv[i++] = NULL;
+
+ char *err;
+ int r = commandv (NULL, &err, (const char * const *) argv);
+ remove_temp (tempfile);
+
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+
+ udev_settle ();
+
+ return 0;
+}
+
+int
+do_luks_format (const char *device, const char *key, int keyslot)
+{
+ return luks_format (device, key, keyslot, NULL);
+}
+
+int
+do_luks_format_cipher (const char *device, const char *key, int keyslot,
+ const char *cipher)
+{
+ return luks_format (device, key, keyslot, cipher);
+}
+
+int
+do_luks_add_key (const char *device, const char *key, const char *newkey,
+ int keyslot)
+{
+ char *keyfile = write_key_to_temp (key);
+ if (!keyfile)
+ return -1;
+
+ char *newkeyfile = write_key_to_temp (newkey);
+ if (!newkeyfile) {
+ remove_temp (keyfile);
+ return -1;
+ }
+
+ const char *argv[16];
+ char keyslot_s[16];
+ size_t i = 0;
+
+ argv[i++] = "cryptsetup";
+ argv[i++] = "-q";
+ argv[i++] = "-d";
+ argv[i++] = keyfile;
+ argv[i++] = "--key-slot";
+ snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
+ argv[i++] = keyslot_s;
+ argv[i++] = "luksAddKey";
+ argv[i++] = device;
+ argv[i++] = newkeyfile;
+ argv[i++] = NULL;
+
+ char *err;
+ int r = commandv (NULL, &err, (const char * const *) argv);
+ remove_temp (keyfile);
+ remove_temp (newkeyfile);
+
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+
+ return 0;
+}
+
+int
+do_luks_kill_slot (const char *device, const char *key, int keyslot)
+{
+ char *tempfile = write_key_to_temp (key);
+ if (!tempfile)
+ return -1;
+
+ const char *argv[16];
+ char keyslot_s[16];
+ size_t i = 0;
+
+ argv[i++] = "cryptsetup";
+ argv[i++] = "-q";
+ argv[i++] = "-d";
+ argv[i++] = tempfile;
+ argv[i++] = "luksKillSlot";
+ argv[i++] = device;
+ snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
+ argv[i++] = keyslot_s;
+ argv[i++] = NULL;
+
+ char *err;
+ int r = commandv (NULL, &err, (const char * const *) argv);
+ remove_temp (tempfile);
+
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+
+ return 0;
+}
--- /dev/null
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2010 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Test LUKS device creation, opening, key slots.
+
+set -e
+
+rm -f test1.img
+
+../fish/guestfish --keys-from-stdin <<EOF
+sparse test1.img 1G
+run
+part-disk /dev/sda mbr
+
+# Create LUKS device with key "key0" in slot 0.
+luks-format /dev/sda1 0
+key0
+
+# Open the device.
+luks-open /dev/sda1 lukstest
+key0
+
+# Put some LVM structures on the encrypted device.
+pvcreate /dev/mapper/lukstest
+vgcreate VG /dev/mapper/lukstest
+lvcreate LV1 VG 64
+lvcreate LV2 VG 64
+vg-activate-all false
+
+# Close the device.
+luks-close /dev/mapper/lukstest
+
+# Add keys in other slots.
+luks-add-key /dev/sda1 1
+key0
+key1
+luks-add-key /dev/sda1 2
+key1
+key2
+luks-add-key /dev/sda1 3
+key2
+key3
+
+# Check we can open the device with one of the new keys.
+luks-open /dev/sda1 lukstest
+key1
+luks-close /dev/mapper/lukstest
+luks-open /dev/sda1 lukstest
+key3
+luks-close /dev/mapper/lukstest
+
+# Remove a key.
+luks-kill-slot /dev/sda1 1
+key0
+
+# This is expected to fail.
+-luks-open /dev/sda1 lukstest
+key1
+
+# Replace a key slot.
+luks-kill-slot /dev/sda1 3
+key2
+luks-add-key /dev/sda1 3
+key2
+newkey3
+
+luks-open /dev/sda1 lukstest
+newkey3
+luks-close /dev/mapper/lukstest
+
+EOF
+
+rm -f test1.img
device (ie. C</dev/mapper/mapname>) and I<not> the name
of the underlying block device.");
+ ("luks_format", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 260, [Optional "luks"; DangerWillRobinson],
+ [],
+ "format a block device as a LUKS encrypted device",
+ "\
+This command erases existing data on C<device> and formats
+the device as a LUKS encrypted device. C<key> is the
+initial key, which is added to key slot C<slot>. (LUKS
+supports 8 key slots, numbered 0-7).");
+
+ ("luks_format_cipher", (RErr, [Device "device"; Key "key"; Int "keyslot"; String "cipher"]), 261, [Optional "luks"; DangerWillRobinson],
+ [],
+ "format a block device as a LUKS encrypted device",
+ "\
+This command is the same as C<guestfs_luks_format> but
+it also allows you to set the C<cipher> used.");
+
+ ("luks_add_key", (RErr, [Device "device"; Key "key"; Key "newkey"; Int "keyslot"]), 262, [Optional "luks"],
+ [],
+ "add a key on a LUKS encrypted device",
+ "\
+This command adds a new key on LUKS device C<device>.
+C<key> is any existing key, and is used to access the device.
+C<newkey> is the new key to add. C<keyslot> is the key slot
+that will be replaced.
+
+Note that if C<keyslot> already contains a key, then this
+command will fail. You have to use C<guestfs_luks_kill_slot>
+first to remove that key.");
+
+ ("luks_kill_slot", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 263, [Optional "luks"],
+ [],
+ "remove a key from a LUKS encrypted device",
+ "\
+This command deletes the key in key slot C<keyslot> from the
+encrypted LUKS device C<device>. C<key> must be one of the
+I<other> keys.");
+
]
let all_functions = non_daemon_functions @ daemon_functions