New APIs: Support for opening LUKS-encrypted disks.

This adds support for opening LUKS-encrypted disks, via
three new APIs:

  luks_open:    Create a mapping for an encrypted disk.
  luks_open_ro: Same, but read-only mapping.
  luks_close:   Close a mapping.

A typical guestfish session using this functionality looks
like this:

  $ guestfish --ro -a encrypted.img
  ><fs> run
  ><fs> list-devices
  /dev/vda
  ><fs> list-partitions
  /dev/vda1
  /dev/vda2
  ><fs> vfs-type /dev/vda2
  crypto_LUKS
  ><fs> luks-open /dev/vda2 luksdev
  Enter key or passphrase ("key"):
  ><fs> vgscan
  ><fs> vg-activate-all true
  ><fs> pvs
  /dev/dm-0
  ><fs> vgs
  vg_f13x64encrypted
  ><fs> lvs
  /dev/vg_f13x64encrypted/lv_root
  /dev/vg_f13x64encrypted/lv_swap
  ><fs> mount /dev/vg_f13x64encrypted/lv_root /
  ><fs> ll /
  total 132
  dr-xr-xr-x.  24 root root  4096 Jul 21 12:01 .
  dr-xr-xr-x   20 root root     0 Jul 21 20:06 ..
  drwx------.   3 root root  4096 Jul 21 11:59 .dbus
  drwx------.   2 root root  4096 Jul 21 12:00 .pulse
  -rw-------.   1 root root   256 Jul 21 12:00 .pulse-cookie
  dr-xr-xr-x.   2 root root  4096 May 13 03:03 bin

NOT included in this patch:

 - An easier way to use this from guestfish.
 - Ability to create LUKS devices.
 - Ability to change LUKS keys on existing devices.
 - Direct access to the /dev/mapper device (eg. if it contains
   anything apart from VGs).
This commit is contained in:
Richard Jones
2010-07-21 19:50:06 +01:00
parent 581a7965fa
commit 637f8df837
10 changed files with 272 additions and 1 deletions

13
TODO
View File

@@ -356,3 +356,16 @@ Progress of long-running operations
For example, copying in virt-resize. How can we display the progress
of these operations? This is a basic usability requirement, and
frequently requested.
Better support for encrypted devices
------------------------------------
Currently LUKS support only works if the device contains volume
groups. If it contains, eg., partitions, you cannot access them.
We would like to add:
- An easier way to use this from guestfish.
- Ability to create LUKS devices.
- Ability to change LUKS keys on existing devices.
- Direct access to the /dev/mapper device (eg. if it contains
anything apart from VGs).

View File

@@ -69,3 +69,18 @@ loop.ko
gfs2.ko
dlm.ko
configfs.ko
# Used by dm-crypt. Probably many more crypto modules
# should be added here.
aes*.ko
blkcipher.ko
cbc.ko
cryptd.ko
crypto_blkcipher.ko
gf128mul.ko
padlock-aes.ko
sha256*.ko
sha512*.ko
xor.ko
xts.ko
zlib.ko

View File

@@ -11,6 +11,7 @@
#if REDHAT == 1
augeas-libs
btrfs-progs
cryptsetup-luks
diffutils
e2fsprogs
/* e4fsprogs only exists on RHEL 5, will be ignored everywhere else. */
@@ -34,6 +35,7 @@
#elif DEBIAN == 1
bsdmainutils
btrfs-tools
cryptsetup
/* Dependency problem prevents installation of these two:
gfs-tools
gfs2-tools

View File

@@ -98,6 +98,7 @@ guestfsd_SOURCES = \
inotify.c \
link.c \
ls.c \
luks.c \
lvm.c \
lvm-filter.c \
mkfs.c \

138
daemon/luks.c Normal file
View File

@@ -0,0 +1,138 @@
/* libguestfs - the guestfsd daemon
* 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.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "daemon.h"
#include "c-ctype.h"
#include "actions.h"
#include "optgroups.h"
int
optgroup_luks_available (void)
{
return prog_exists ("cryptsetup");
}
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[] = "/tmp/luksXXXXXX";
int fd = mkstemp (tempfile);
if (fd == -1) {
reply_with_perror ("mkstemp");
return -1;
}
len = strlen (key);
if (xwrite (fd, key, len) == -1) {
reply_with_perror ("write");
close (fd);
unlink (tempfile);
return -1;
}
if (close (fd) == -1) {
reply_with_perror ("close");
unlink (tempfile);
return -1;
}
const char *argv[16];
size_t i = 0;
argv[i++] = "cryptsetup";
argv[i++] = "-d";
argv[i++] = tempfile;
if (readonly) argv[i++] = "--readonly";
argv[i++] = "luksOpen";
argv[i++] = device;
argv[i++] = mapname;
argv[i++] = NULL;
char *err;
int r = commandv (NULL, &err, (const char * const *) argv);
unlink (tempfile);
if (r == -1) {
reply_with_error ("%s", err);
free (err);
return -1;
}
free (err);
udev_settle ();
return 0;
}
int
do_luks_open (const char *device, const char *key, const char *mapname)
{
return luks_open (device, key, mapname, 0);
}
int
do_luks_open_ro (const char *device, const char *key, const char *mapname)
{
return luks_open (device, key, mapname, 1);
}
int
do_luks_close (const char *device)
{
/* Must be /dev/mapper/... */
if (! STRPREFIX (device, "/dev/mapper/")) {
reply_with_error ("luks_close: you must call this on the /dev/mapper device created by luks_open");
return -1;
}
const char *mapname = &device[12];
char *err;
int r = command (NULL, &err, "cryptsetup", "luksClose", mapname, NULL);
if (r == -1) {
reply_with_error ("%s", err);
free (err);
return -1;
}
free (err);
udev_settle ();
return 0;
}

View File

@@ -530,6 +530,39 @@ it, eg:
echo "~"
=head1 ENCRYPTED DISKS
Libguestfs has some support for Linux guests encrypted according to
the Linux Unified Key Setup (LUKS) standard, which includes nearly all
whole disk encryption systems used by modern Linux guests. Currently
only LVM-on-LUKS is supported.
Identify encrypted block devices and partitions using L</vfs-type>:
><fs> vfs-type /dev/sda2
crypto_LUKS
Then open those devices using L</luks-open>. This creates a
device-mapper device called C</dev/mapper/luksdev>.
><fs> luks-open /dev/sda2 luksdev
Enter key or passphrase ("key"): <enter the passphrase>
Finally you have to tell LVM to scan for volume groups on
the newly created mapper device:
><fs> vgscan
><fs> vg-activate-all true
The logical volume(s) can now be mounted in the usual way.
Before closing a LUKS device you must unmount any logical volumes on
it and deactivate the volume groups by calling C<vg-activate false VG>
on each one. Then you can close the mapper device:
><fs> vg-activate false /dev/VG
><fs> luks-close /dev/mapper/luksdev
=head1 WINDOWS PATHS
If a path is prefixed with C<win:> then you can use Windows-style

View File

@@ -33,6 +33,7 @@ daemon/initrd.c
daemon/inotify.c
daemon/link.c
daemon/ls.c
daemon/luks.c
daemon/lvm-filter.c
daemon/lvm.c
daemon/mkfs.c

View File

@@ -1 +1 @@
256
259

View File

@@ -4881,6 +4881,43 @@ will be able to see every block device.
This command also clears the LVM cache and performs a volume
group scan.");
("luks_open", (RErr, [Device "device"; Key "key"; String "mapname"]), 257, [Optional "luks"],
[],
"open a LUKS-encrypted block device",
"\
This command opens a block device which has been encrypted
according to the Linux Unified Key Setup (LUKS) standard.
C<device> is the encrypted block device or partition.
The caller must supply one of the keys associated with the
LUKS block device, in the C<key> parameter.
This creates a new block device called C</dev/mapper/mapname>.
Reads and writes to this block device are decrypted from and
encrypted to the underlying C<device> respectively.
If this block device contains LVM volume groups, then
calling C<guestfs_vgscan> followed by C<guestfs_vg_activate_all>
will make them visible.");
("luks_open_ro", (RErr, [Device "device"; Key "key"; String "mapname"]), 258, [Optional "luks"],
[],
"open a LUKS-encrypted block device read-only",
"\
This is the same as C<guestfs_luks_open> except that a read-only
mapping is created.");
("luks_close", (RErr, [Device "device"]), 259, [Optional "luks"],
[],
"close a LUKS device",
"\
This closes a LUKS device that was created earlier by
C<guestfs_luks_open> or C<guestfs_luks_open_ro>. The
C<device> parameter must be the name of the LUKS mapping
device (ie. C</dev/mapper/mapname>) and I<not> the name
of the underlying block device.");
]
let all_functions = non_daemon_functions @ daemon_functions

View File

@@ -450,6 +450,37 @@ L</guestfs_chmod> after creating each file or directory.
For more information about umask, see L<umask(2)>.
=head2 ENCRYPTED DISKS
Libguestfs allows you to access Linux guests which have been
encrypted using whole disk encryption that conforms to the
Linux Unified Key Setup (LUKS) standard. This includes
nearly all whole disk encryption systems used by modern
Linux guests.
Use L</guestfs_vfs_type> to identify LUKS-encrypted block
devices (it returns the string C<crypto_LUKS>).
Then open these devices by calling L</guestfs_luks_open>.
Obviously you will require the passphrase!
Opening a LUKS device creates a new device mapper device
called C</dev/mapper/mapname> (where C<mapname> is the
string you supply to L</guestfs_luks_open>).
Reads and writes to this mapper device are decrypted from and
encrypted to the underlying block device respectively.
LVM volume groups on the device can be made visible by calling
L</guestfs_vgscan> followed by L</guestfs_vg_activate_all>.
The logical volume(s) can now be mounted in the usual way.
Use the reverse process to close a LUKS device. Unmount
any logical volumes on it, deactivate the volume groups
by caling C<guestfs_vg_activate (g, 0, ["/dev/VG"])>.
Then close the mapper device by calling
L</guestfs_luks_close> on the C</dev/mapper/mapname>
device (I<not> the underlying encrypted block device).
=head2 SPECIAL CONSIDERATIONS FOR WINDOWS GUESTS
Libguestfs can mount NTFS partitions. It does this using the