psss / rpms / libguestfs

Forked from rpms/libguestfs 5 years ago
Clone

Blame 0007-New-APIs-Support-for-creating-LUKS-and-managing-keys.patch

0882396
From 088f1c169ed1f685647ab0a71cad54068bebb757 Mon Sep 17 00:00:00 2001
0882396
From: Richard Jones <rjones@redhat.com>
0882396
Date: Thu, 22 Jul 2010 11:00:59 +0100
0882396
Subject: [PATCH] New APIs: Support for creating LUKS and managing keys.
0882396
0882396
This commit adds four APIs for creating new LUKS devices
0882396
and key management.  These are:
0882396
0882396
  luks_format         Format a LUKS device with the default cipher.
0882396
  luks_format_cipher  Format with a chosen cipher.
0882396
  luks_add_key        Add another key to an existing device.
0882396
  luks_kill_slot      Delete a key from an existing device.
0882396
0882396
This enables all the significant functionality of the
0882396
cryptsetup luks* commands.
0882396
0882396
Note that you can obtain the UUID of a LUKS device already
0882396
by using vfs-uuid.
0882396
0882396
This also includes a regression test covering all the LUKS
0882396
functions.
0882396
(cherry picked from commit 945e569db64ab2608b21feba0aa94044c9835ac3)
0882396
---
0882396
 TODO                     |    2 -
0882396
 daemon/luks.c            |  204 +++++++++++++++++++++++++++++++++++++++++-----
0882396
 regressions/Makefile.am  |    1 +
0882396
 regressions/test-luks.sh |   88 ++++++++++++++++++++
0882396
 src/MAX_PROC_NR          |    2 +-
0882396
 src/generator.ml         |   37 ++++++++
0882396
 6 files changed, 311 insertions(+), 23 deletions(-)
0882396
 create mode 100755 regressions/test-luks.sh
0882396
0882396
diff --git a/TODO b/TODO
0882396
index d0196c8..5bce5d9 100644
0882396
--- a/TODO
0882396
+++ b/TODO
0882396
@@ -365,7 +365,5 @@ groups.  If it contains, eg., partitions, you cannot access them.
0882396
 We would like to add:
0882396
 
0882396
   - An easier way to use this from guestfish.
0882396
-  - Ability to create LUKS devices.
0882396
-  - Ability to change LUKS keys on existing devices.
0882396
   - Direct access to the /dev/mapper device (eg. if it contains
0882396
     anything apart from VGs).
0882396
diff --git a/daemon/luks.c b/daemon/luks.c
0882396
index f5a0b9d..07aebdd 100644
0882396
--- a/daemon/luks.c
0882396
+++ b/daemon/luks.c
0882396
@@ -33,43 +33,69 @@ optgroup_luks_available (void)
0882396
   return prog_exists ("cryptsetup");
0882396
 }
0882396
 
0882396
-static int
0882396
-luks_open (const char *device, const char *key, const char *mapname,
0882396
-           int readonly)
0882396
+/* Callers must also call remove_temp (tempfile). */
0882396
+static char *
0882396
+write_key_to_temp (const char *key)
0882396
 {
0882396
-  /* Sanity check: /dev/mapper/mapname must not exist already.  Note
0882396
-   * that the device-mapper control device (/dev/mapper/control) is
0882396
-   * always there, so you can't ever have mapname == "control".
0882396
-   */
0882396
-  size_t len = strlen (mapname);
0882396
-  char devmapper[len+32];
0882396
-  snprintf (devmapper, len+32, "/dev/mapper/%s", mapname);
0882396
-  if (access (devmapper, F_OK) == 0) {
0882396
-    reply_with_error ("%s: device already exists", devmapper);
0882396
-    return -1;
0882396
+  char *tempfile = strdup ("/tmp/luksXXXXXX");
0882396
+  if (!tempfile) {
0882396
+    reply_with_perror ("strdup");
0882396
+    return NULL;
0882396
   }
0882396
 
0882396
-  char tempfile[] = "/tmp/luksXXXXXX";
0882396
   int fd = mkstemp (tempfile);
0882396
   if (fd == -1) {
0882396
     reply_with_perror ("mkstemp");
0882396
-    return -1;
0882396
+    goto error;
0882396
   }
0882396
 
0882396
-  len = strlen (key);
0882396
+  size_t len = strlen (key);
0882396
   if (xwrite (fd, key, len) == -1) {
0882396
     reply_with_perror ("write");
0882396
     close (fd);
0882396
-    unlink (tempfile);
0882396
-    return -1;
0882396
+    goto error;
0882396
   }
0882396
 
0882396
   if (close (fd) == -1) {
0882396
     reply_with_perror ("close");
0882396
-    unlink (tempfile);
0882396
+    goto error;
0882396
+  }
0882396
+
0882396
+  return tempfile;
0882396
+
0882396
+ error:
0882396
+  unlink (tempfile);
0882396
+  free (tempfile);
0882396
+  return NULL;
0882396
+}
0882396
+
0882396
+static void
0882396
+remove_temp (char *tempfile)
0882396
+{
0882396
+  unlink (tempfile);
0882396
+  free (tempfile);
0882396
+}
0882396
+
0882396
+static int
0882396
+luks_open (const char *device, const char *key, const char *mapname,
0882396
+           int readonly)
0882396
+{
0882396
+  /* Sanity check: /dev/mapper/mapname must not exist already.  Note
0882396
+   * that the device-mapper control device (/dev/mapper/control) is
0882396
+   * always there, so you can't ever have mapname == "control".
0882396
+   */
0882396
+  size_t len = strlen (mapname);
0882396
+  char devmapper[len+32];
0882396
+  snprintf (devmapper, len+32, "/dev/mapper/%s", mapname);
0882396
+  if (access (devmapper, F_OK) == 0) {
0882396
+    reply_with_error ("%s: device already exists", devmapper);
0882396
     return -1;
0882396
   }
0882396
 
0882396
+  char *tempfile = write_key_to_temp (key);
0882396
+  if (!tempfile)
0882396
+    return -1;
0882396
+
0882396
   const char *argv[16];
0882396
   size_t i = 0;
0882396
 
0882396
@@ -84,7 +110,7 @@ luks_open (const char *device, const char *key, const char *mapname,
0882396
 
0882396
   char *err;
0882396
   int r = commandv (NULL, &err, (const char * const *) argv);
0882396
-  unlink (tempfile);
0882396
+  remove_temp (tempfile);
0882396
 
0882396
   if (r == -1) {
0882396
     reply_with_error ("%s", err);
0882396
@@ -136,3 +162,141 @@ do_luks_close (const char *device)
0882396
 
0882396
   return 0;
0882396
 }
0882396
+
0882396
+static int
0882396
+luks_format (const char *device, const char *key, int keyslot,
0882396
+             const char *cipher)
0882396
+{
0882396
+  char *tempfile = write_key_to_temp (key);
0882396
+  if (!tempfile)
0882396
+    return -1;
0882396
+
0882396
+  const char *argv[16];
0882396
+  char keyslot_s[16];
0882396
+  size_t i = 0;
0882396
+
0882396
+  argv[i++] = "cryptsetup";
0882396
+  argv[i++] = "-q";
0882396
+  if (cipher) {
0882396
+    argv[i++] = "--cipher";
0882396
+    argv[i++] = cipher;
0882396
+  }
0882396
+  argv[i++] = "--key-slot";
0882396
+  snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
0882396
+  argv[i++] = keyslot_s;
0882396
+  argv[i++] = "luksFormat";
0882396
+  argv[i++] = device;
0882396
+  argv[i++] = tempfile;
0882396
+  argv[i++] = NULL;
0882396
+
0882396
+  char *err;
0882396
+  int r = commandv (NULL, &err, (const char * const *) argv);
0882396
+  remove_temp (tempfile);
0882396
+
0882396
+  if (r == -1) {
0882396
+    reply_with_error ("%s", err);
0882396
+    free (err);
0882396
+    return -1;
0882396
+  }
0882396
+
0882396
+  free (err);
0882396
+
0882396
+  udev_settle ();
0882396
+
0882396
+  return 0;
0882396
+}
0882396
+
0882396
+int
0882396
+do_luks_format (const char *device, const char *key, int keyslot)
0882396
+{
0882396
+  return luks_format (device, key, keyslot, NULL);
0882396
+}
0882396
+
0882396
+int
0882396
+do_luks_format_cipher (const char *device, const char *key, int keyslot,
0882396
+                       const char *cipher)
0882396
+{
0882396
+  return luks_format (device, key, keyslot, cipher);
0882396
+}
0882396
+
0882396
+int
0882396
+do_luks_add_key (const char *device, const char *key, const char *newkey,
0882396
+                 int keyslot)
0882396
+{
0882396
+  char *keyfile = write_key_to_temp (key);
0882396
+  if (!keyfile)
0882396
+    return -1;
0882396
+
0882396
+  char *newkeyfile = write_key_to_temp (newkey);
0882396
+  if (!newkeyfile) {
0882396
+    remove_temp (keyfile);
0882396
+    return -1;
0882396
+  }
0882396
+
0882396
+  const char *argv[16];
0882396
+  char keyslot_s[16];
0882396
+  size_t i = 0;
0882396
+
0882396
+  argv[i++] = "cryptsetup";
0882396
+  argv[i++] = "-q";
0882396
+  argv[i++] = "-d";
0882396
+  argv[i++] = keyfile;
0882396
+  argv[i++] = "--key-slot";
0882396
+  snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
0882396
+  argv[i++] = keyslot_s;
0882396
+  argv[i++] = "luksAddKey";
0882396
+  argv[i++] = device;
0882396
+  argv[i++] = newkeyfile;
0882396
+  argv[i++] = NULL;
0882396
+
0882396
+  char *err;
0882396
+  int r = commandv (NULL, &err, (const char * const *) argv);
0882396
+  remove_temp (keyfile);
0882396
+  remove_temp (newkeyfile);
0882396
+
0882396
+  if (r == -1) {
0882396
+    reply_with_error ("%s", err);
0882396
+    free (err);
0882396
+    return -1;
0882396
+  }
0882396
+
0882396
+  free (err);
0882396
+
0882396
+  return 0;
0882396
+}
0882396
+
0882396
+int
0882396
+do_luks_kill_slot (const char *device, const char *key, int keyslot)
0882396
+{
0882396
+  char *tempfile = write_key_to_temp (key);
0882396
+  if (!tempfile)
0882396
+    return -1;
0882396
+
0882396
+  const char *argv[16];
0882396
+  char keyslot_s[16];
0882396
+  size_t i = 0;
0882396
+
0882396
+  argv[i++] = "cryptsetup";
0882396
+  argv[i++] = "-q";
0882396
+  argv[i++] = "-d";
0882396
+  argv[i++] = tempfile;
0882396
+  argv[i++] = "luksKillSlot";
0882396
+  argv[i++] = device;
0882396
+  snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
0882396
+  argv[i++] = keyslot_s;
0882396
+  argv[i++] = NULL;
0882396
+
0882396
+  char *err;
0882396
+  int r = commandv (NULL, &err, (const char * const *) argv);
0882396
+  remove_temp (tempfile);
0882396
+
0882396
+  if (r == -1) {
0882396
+    reply_with_error ("%s", err);
0882396
+    free (err);
0882396
+    return -1;
0882396
+  }
0882396
+
0882396
+  free (err);
0882396
+
0882396
+  return 0;
0882396
+}
0882396
diff --git a/regressions/Makefile.am b/regressions/Makefile.am
0882396
index 5736aaf..ca4292a 100644
0882396
--- a/regressions/Makefile.am
0882396
+++ b/regressions/Makefile.am
0882396
@@ -35,6 +35,7 @@ TESTS = \
0882396
 	test-cancellation-download-librarycancels.sh \
0882396
 	test-cancellation-upload-daemoncancels.sh \
0882396
 	test-find0.sh \
0882396
+	test-luks.sh \
0882396
 	test-lvm-filtering.sh \
0882396
 	test-lvm-mapping.pl \
0882396
 	test-noexec-stack.pl \
0882396
diff --git a/regressions/test-luks.sh b/regressions/test-luks.sh
0882396
new file mode 100755
0882396
index 0000000..fe42d87
0882396
--- /dev/null
0882396
+++ b/regressions/test-luks.sh
0882396
@@ -0,0 +1,88 @@
0882396
+#!/bin/bash -
0882396
+# libguestfs
0882396
+# Copyright (C) 2010 Red Hat Inc.
0882396
+#
0882396
+# This program is free software; you can redistribute it and/or modify
0882396
+# it under the terms of the GNU General Public License as published by
0882396
+# the Free Software Foundation; either version 2 of the License, or
0882396
+# (at your option) any later version.
0882396
+#
0882396
+# This program is distributed in the hope that it will be useful,
0882396
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
0882396
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0882396
+# GNU General Public License for more details.
0882396
+#
0882396
+# You should have received a copy of the GNU General Public License
0882396
+# along with this program; if not, write to the Free Software
0882396
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0882396
+
0882396
+# Test LUKS device creation, opening, key slots.
0882396
+
0882396
+set -e
0882396
+
0882396
+rm -f test1.img
0882396
+
0882396
+../fish/guestfish --keys-from-stdin <
0882396
+sparse test1.img 1G
0882396
+run
0882396
+part-disk /dev/sda mbr
0882396
+
0882396
+# Create LUKS device with key "key0" in slot 0.
0882396
+luks-format /dev/sda1 0
0882396
+key0
0882396
+
0882396
+# Open the device.
0882396
+luks-open /dev/sda1 lukstest
0882396
+key0
0882396
+
0882396
+# Put some LVM structures on the encrypted device.
0882396
+pvcreate /dev/mapper/lukstest
0882396
+vgcreate VG /dev/mapper/lukstest
0882396
+lvcreate LV1 VG 64
0882396
+lvcreate LV2 VG 64
0882396
+vg-activate-all false
0882396
+
0882396
+# Close the device.
0882396
+luks-close /dev/mapper/lukstest
0882396
+
0882396
+# Add keys in other slots.
0882396
+luks-add-key /dev/sda1 1
0882396
+key0
0882396
+key1
0882396
+luks-add-key /dev/sda1 2
0882396
+key1
0882396
+key2
0882396
+luks-add-key /dev/sda1 3
0882396
+key2
0882396
+key3
0882396
+
0882396
+# Check we can open the device with one of the new keys.
0882396
+luks-open /dev/sda1 lukstest
0882396
+key1
0882396
+luks-close /dev/mapper/lukstest
0882396
+luks-open /dev/sda1 lukstest
0882396
+key3
0882396
+luks-close /dev/mapper/lukstest
0882396
+
0882396
+# Remove a key.
0882396
+luks-kill-slot /dev/sda1 1
0882396
+key0
0882396
+
0882396
+# This is expected to fail.
0882396
+-luks-open /dev/sda1 lukstest
0882396
+key1
0882396
+
0882396
+# Replace a key slot.
0882396
+luks-kill-slot /dev/sda1 3
0882396
+key2
0882396
+luks-add-key /dev/sda1 3
0882396
+key2
0882396
+newkey3
0882396
+
0882396
+luks-open /dev/sda1 lukstest
0882396
+newkey3
0882396
+luks-close /dev/mapper/lukstest
0882396
+
0882396
+EOF
0882396
+
0882396
+rm -f test1.img
0882396
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
0882396
index 98ecf58..175b6c5 100644
0882396
--- a/src/MAX_PROC_NR
0882396
+++ b/src/MAX_PROC_NR
0882396
@@ -1 +1 @@
0882396
-259
0882396
+263
0882396
diff --git a/src/generator.ml b/src/generator.ml
0882396
index 43ca70a..8675828 100755
0882396
--- a/src/generator.ml
0882396
+++ b/src/generator.ml
0882396
@@ -4916,6 +4916,43 @@ C<device> parameter must be the name of the LUKS mapping
0882396
 device (ie. C</dev/mapper/mapname>) and I<not> the name
0882396
 of the underlying block device.");
0882396
 
0882396
+  ("luks_format", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 260, [Optional "luks"; DangerWillRobinson],
0882396
+   [],
0882396
+   "format a block device as a LUKS encrypted device",
0882396
+   "\
0882396
+This command erases existing data on C<device> and formats
0882396
+the device as a LUKS encrypted device.  C<key> is the
0882396
+initial key, which is added to key slot C<slot>.  (LUKS
0882396
+supports 8 key slots, numbered 0-7).");
0882396
+
0882396
+  ("luks_format_cipher", (RErr, [Device "device"; Key "key"; Int "keyslot"; String "cipher"]), 261, [Optional "luks"; DangerWillRobinson],
0882396
+   [],
0882396
+   "format a block device as a LUKS encrypted device",
0882396
+   "\
0882396
+This command is the same as C<guestfs_luks_format> but
0882396
+it also allows you to set the C<cipher> used.");
0882396
+
0882396
+  ("luks_add_key", (RErr, [Device "device"; Key "key"; Key "newkey"; Int "keyslot"]), 262, [Optional "luks"],
0882396
+   [],
0882396
+   "add a key on a LUKS encrypted device",
0882396
+   "\
0882396
+This command adds a new key on LUKS device C<device>.
0882396
+C<key> is any existing key, and is used to access the device.
0882396
+C<newkey> is the new key to add.  C<keyslot> is the key slot
0882396
+that will be replaced.
0882396
+
0882396
+Note that if C<keyslot> already contains a key, then this
0882396
+command will fail.  You have to use C<guestfs_luks_kill_slot>
0882396
+first to remove that key.");
0882396
+
0882396
+  ("luks_kill_slot", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 263, [Optional "luks"],
0882396
+   [],
0882396
+   "remove a key from a LUKS encrypted device",
0882396
+   "\
0882396
+This command deletes the key in key slot C<keyslot> from the
0882396
+encrypted LUKS device C<device>.  C<key> must be one of the
0882396
+I<other> keys.");
0882396
+
0882396
 ]
0882396
 
0882396
 let all_functions = non_daemon_functions @ daemon_functions
0882396
-- 
0882396
1.7.1
0882396