mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
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:
13
TODO
13
TODO
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
138
daemon/luks.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
256
|
||||
259
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user