mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
New APIs: cryptsetup-open and cryptsetup-close.
This commit deprecates luks-open/luks-open-ro/luks-close for the more generic sounding names cryptsetup-open/cryptsetup-close, which also correspond directly to the cryptsetup commands. The optional cryptsetup-open readonly flag is used to replace the functionality of luks-open-ro. The optional cryptsetup-open crypttype parameter can be used to select the type (corresponding to cryptsetup open --type), which allows us to open BitLocker-encrypted disks with no extra effort. As a convenience the crypttype parameter may be omitted, and libguestfs will use a heuristic (based on vfs-type output) to try to determine the correct type to use. The deprecated functions and the new functions are all (re-)written in OCaml. There is no new test here, unfortunately. It would be nice to test Windows BitLocker support in this new API, however the Linux tools do not support creating BitLocker disks, and while it is possible to create one under Windows, the smallest compressed disk I could create is 37M because of a mixture of the minimum support size for BitLocker disks and the fact that encrypted parts of NTFS cannot be compressed. Also synchronise with common module.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -147,6 +147,7 @@ Makefile.in
|
||||
/daemon/btrfs.mli
|
||||
/daemon/callbacks.ml
|
||||
/daemon/caml-stubs.c
|
||||
/daemon/cryptsetup.mli
|
||||
/daemon/daemon_config.ml
|
||||
/daemon/daemon_utils_tests
|
||||
/daemon/devsparts.mli
|
||||
|
||||
2
common
2
common
Submodule common updated: 858060bfa4...132c355d3b
@@ -39,6 +39,7 @@ generator_built = \
|
||||
blkid.mli \
|
||||
btrfs.mli \
|
||||
callbacks.ml \
|
||||
cryptsetup.mli \
|
||||
devsparts.mli \
|
||||
file.mli \
|
||||
filearch.mli \
|
||||
@@ -269,6 +270,7 @@ SOURCES_MLI = \
|
||||
btrfs.mli \
|
||||
callbacks.mli \
|
||||
chroot.mli \
|
||||
cryptsetup.mli \
|
||||
daemon.mli \
|
||||
daemon_config.mli \
|
||||
devsparts.mli \
|
||||
@@ -310,6 +312,7 @@ SOURCES_ML = \
|
||||
chroot.ml \
|
||||
blkid.ml \
|
||||
btrfs.ml \
|
||||
cryptsetup.ml \
|
||||
devsparts.ml \
|
||||
file.ml \
|
||||
filearch.ml \
|
||||
|
||||
78
daemon/cryptsetup.ml
Normal file
78
daemon/cryptsetup.ml
Normal file
@@ -0,0 +1,78 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2020 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*)
|
||||
|
||||
open Printf
|
||||
open Unix
|
||||
|
||||
open Std_utils
|
||||
|
||||
open Utils
|
||||
|
||||
let cryptsetup_open ?(readonly = false) ?crypttype device key mapname =
|
||||
(* 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".
|
||||
*)
|
||||
let devmapper = sprintf "/dev/mapper/%s" mapname in
|
||||
if is_block_device devmapper then
|
||||
failwithf "%s: device already exists" devmapper;
|
||||
|
||||
(* Heuristically determine the encryption type. *)
|
||||
let crypttype =
|
||||
match crypttype with
|
||||
| Some s -> s
|
||||
| None ->
|
||||
let t = Blkid.vfs_type (Mountable.of_device device) in
|
||||
match t with
|
||||
| "crypto_LUKS" -> "luks"
|
||||
| "BitLocker" -> "bitlk"
|
||||
| _ ->
|
||||
failwithf "%s: unknown encrypted device type" t in
|
||||
|
||||
(* Write the key to a temporary file. *)
|
||||
let keyfile, chan = Filename.open_temp_file "crypt" ".key" in
|
||||
output_string chan key;
|
||||
close_out chan;
|
||||
|
||||
let args = ref [] in
|
||||
List.push_back_list args ["-d"; keyfile];
|
||||
if readonly then List.push_back args "--readonly";
|
||||
List.push_back_list args ["open"; device; mapname; "--type"; crypttype];
|
||||
|
||||
(* Make sure we always remove the temporary file. *)
|
||||
protect ~f:(fun () -> ignore (command "cryptsetup" !args))
|
||||
~finally:(fun () -> unlink keyfile);
|
||||
|
||||
udev_settle ()
|
||||
|
||||
let cryptsetup_close device =
|
||||
(* Must be /dev/mapper/... *)
|
||||
if not (String.is_prefix device "/dev/mapper/") then
|
||||
failwithf "%s: you must call this on the /dev/mapper device created by cryptsetup-open" device;
|
||||
|
||||
let mapname = String.sub device 12 (String.length device - 12) in
|
||||
ignore (command "cryptsetup" ["close"; mapname]);
|
||||
|
||||
udev_settle ()
|
||||
|
||||
(* Deprecated APIs for backwards compatibility. *)
|
||||
let luks_open device key mapname =
|
||||
cryptsetup_open ~crypttype:"luks" device key mapname
|
||||
let luks_open_ro device key mapname =
|
||||
cryptsetup_open ~crypttype:"luks" ~readonly:true device key mapname
|
||||
let luks_close = cryptsetup_close
|
||||
@@ -81,89 +81,6 @@ remove_temp (char *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".
|
||||
*/
|
||||
CLEANUP_FREE char *devmapper = NULL;
|
||||
if (asprintf (&devmapper, "/dev/mapper/%s", mapname) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
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[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "cryptsetup");
|
||||
ADD_ARG (argv, i, "-d");
|
||||
ADD_ARG (argv, i, tempfile);
|
||||
if (readonly) ADD_ARG (argv, i, "--readonly");
|
||||
ADD_ARG (argv, i, "luksOpen");
|
||||
ADD_ARG (argv, i, device);
|
||||
ADD_ARG (argv, i, mapname);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (NULL, &err, "cryptsetup", "luksClose", mapname, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
luks_format (const char *device, const char *key, int keyslot,
|
||||
const char *cipher)
|
||||
|
||||
@@ -5664,52 +5664,6 @@ will be able to see every block device.
|
||||
This command also clears the LVM cache and performs a volume
|
||||
group scan." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_open"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); String (PlainString, "mapname")], [];
|
||||
optional = Some "luks";
|
||||
shortdesc = "open a LUKS-encrypted block device";
|
||||
longdesc = "\
|
||||
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 F</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_lvm_scan> with the C<activate>
|
||||
parameter C<true> will make them visible.
|
||||
|
||||
Use C<guestfs_list_dm_devices> to list all device mapper
|
||||
devices." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_open_ro"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); String (PlainString, "mapname")], [];
|
||||
optional = Some "luks";
|
||||
shortdesc = "open a LUKS-encrypted block device read-only";
|
||||
longdesc = "\
|
||||
This is the same as C<guestfs_luks_open> except that a read-only
|
||||
mapping is created." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_close"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device")], [];
|
||||
optional = Some "luks";
|
||||
shortdesc = "close a LUKS device";
|
||||
longdesc = "\
|
||||
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. F</dev/mapper/mapname>) and I<not> the name
|
||||
of the underlying block device." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_format"; added = (1, 5, 2);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); Int "keyslot"], [];
|
||||
@@ -9753,4 +9707,67 @@ is used)." };
|
||||
longdesc = "\
|
||||
This returns the UUID of the LUKS device C<device>." };
|
||||
|
||||
{ defaults with
|
||||
name = "cryptsetup_open"; added = (1, 43, 2);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); String (PlainString, "mapname")], [OBool "readonly"; OString "crypttype"];
|
||||
impl = OCaml "Cryptsetup.cryptsetup_open";
|
||||
optional = Some "luks";
|
||||
test_excuse = "no way to format BitLocker, and smallest device is huge";
|
||||
shortdesc = "open an encrypted block device";
|
||||
longdesc = "\
|
||||
This command opens a block device which has been encrypted
|
||||
according to the Linux Unified Key Setup (LUKS) standard,
|
||||
Windows BitLocker, or some other types.
|
||||
|
||||
C<device> is the encrypted block device or partition.
|
||||
|
||||
The caller must supply one of the keys associated with the
|
||||
encrypted block device, in the C<key> parameter.
|
||||
|
||||
This creates a new block device called F</dev/mapper/mapname>.
|
||||
Reads and writes to this block device are decrypted from and
|
||||
encrypted to the underlying C<device> respectively.
|
||||
|
||||
C<mapname> cannot be C<\"control\"> because that name is reserved
|
||||
by device-mapper.
|
||||
|
||||
If the optional C<crypttype> parameter is not present then
|
||||
libguestfs tries to guess the correct type (for example
|
||||
LUKS or BitLocker). However you can override this by
|
||||
specifying one of the following types:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<luks>
|
||||
|
||||
A Linux LUKS device.
|
||||
|
||||
=item C<bitlk>
|
||||
|
||||
A Windows BitLocker device.
|
||||
|
||||
=back
|
||||
|
||||
The optional C<readonly> flag, if set to true, creates a
|
||||
read-only mapping.
|
||||
|
||||
If this block device contains LVM volume groups, then
|
||||
calling C<guestfs_lvm_scan> with the C<activate>
|
||||
parameter C<true> will make them visible.
|
||||
|
||||
Use C<guestfs_list_dm_devices> to list all device mapper
|
||||
devices." };
|
||||
|
||||
{ defaults with
|
||||
name = "cryptsetup_close"; added = (1, 43, 2);
|
||||
style = RErr, [String (Device, "device")], [];
|
||||
impl = OCaml "Cryptsetup.cryptsetup_close";
|
||||
optional = Some "luks";
|
||||
shortdesc = "close an encrypted device";
|
||||
longdesc = "\
|
||||
This closes an encrypted device that was created earlier by
|
||||
C<guestfs_cryptsetup_open>. The C<device> parameter must be
|
||||
the name of the mapping device (ie. F</dev/mapper/mapname>)
|
||||
and I<not> the name of the underlying block device." };
|
||||
|
||||
]
|
||||
|
||||
@@ -847,4 +847,56 @@ allows you to specify the new size (in bytes) explicitly." };
|
||||
This rescans all block devices and rebuilds the list of LVM
|
||||
physical volumes, volume groups and logical volumes." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_open"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); String (PlainString, "mapname")], [];
|
||||
impl = OCaml "Cryptsetup.luks_open";
|
||||
optional = Some "luks";
|
||||
deprecated_by = Replaced_by "cryptsetup_open";
|
||||
shortdesc = "open a LUKS-encrypted block device";
|
||||
longdesc = "\
|
||||
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 F</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_lvm_scan> with the C<activate>
|
||||
parameter C<true> will make them visible.
|
||||
|
||||
Use C<guestfs_list_dm_devices> to list all device mapper
|
||||
devices." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_open_ro"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device"); String (Key, "key"); String (PlainString, "mapname")], [];
|
||||
impl = OCaml "Cryptsetup.luks_open_ro";
|
||||
optional = Some "luks";
|
||||
deprecated_by = Replaced_by "cryptsetup_open";
|
||||
shortdesc = "open a LUKS-encrypted block device read-only";
|
||||
longdesc = "\
|
||||
This is the same as C<guestfs_luks_open> except that a read-only
|
||||
mapping is created." };
|
||||
|
||||
{ defaults with
|
||||
name = "luks_close"; added = (1, 5, 1);
|
||||
style = RErr, [String (Device, "device")], [];
|
||||
impl = OCaml "Cryptsetup.luks_close";
|
||||
optional = Some "luks";
|
||||
deprecated_by = Replaced_by "cryptsetup_close";
|
||||
shortdesc = "close a LUKS device";
|
||||
longdesc = "\
|
||||
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. F</dev/mapper/mapname>) and I<not> the name
|
||||
of the underlying block device." };
|
||||
|
||||
]
|
||||
|
||||
@@ -776,7 +776,8 @@ let generate_daemon_caml_stubs () =
|
||||
pr "Val_bool (%s)" n;
|
||||
| OInt _ -> assert false
|
||||
| OInt64 _ -> assert false
|
||||
| OString _ -> assert false
|
||||
| OString _ ->
|
||||
pr "caml_copy_string (%s)" n
|
||||
| OStringList _ -> assert false
|
||||
);
|
||||
pr ";\n";
|
||||
@@ -792,7 +793,7 @@ let generate_daemon_caml_stubs () =
|
||||
| Bool n -> pr "Val_bool (%s)" n
|
||||
| Int n -> pr "Val_int (%s)" n
|
||||
| Int64 n -> pr "caml_copy_int64 (%s)" n
|
||||
| String ((PlainString|Device|Pathname|Dev_or_Path), n) ->
|
||||
| String ((PlainString|Device|Pathname|Dev_or_Path|Key), n) ->
|
||||
pr "caml_copy_string (%s)" n
|
||||
| String ((Mountable|Mountable_or_Path), n) ->
|
||||
pr "guestfs_int_daemon_copy_mountable (%s)" n
|
||||
|
||||
@@ -514,6 +514,8 @@ let proc_nr = [
|
||||
505, "f2fs_expand";
|
||||
506, "lvm_scan";
|
||||
507, "luks_uuid";
|
||||
508, "cryptsetup_open";
|
||||
509, "cryptsetup_close";
|
||||
]
|
||||
|
||||
(* End of list. If adding a new entry, add it at the end of the list
|
||||
|
||||
@@ -69,6 +69,7 @@ guestfs_gobject_headers= \
|
||||
include/guestfs-gobject/optargs-copy_file_to_device.h \
|
||||
include/guestfs-gobject/optargs-copy_file_to_file.h \
|
||||
include/guestfs-gobject/optargs-cpio_out.h \
|
||||
include/guestfs-gobject/optargs-cryptsetup_open.h \
|
||||
include/guestfs-gobject/optargs-disk_create.h \
|
||||
include/guestfs-gobject/optargs-download_blocks.h \
|
||||
include/guestfs-gobject/optargs-e2fsck.h \
|
||||
@@ -162,6 +163,7 @@ guestfs_gobject_sources= \
|
||||
src/optargs-copy_file_to_device.c \
|
||||
src/optargs-copy_file_to_file.c \
|
||||
src/optargs-cpio_out.c \
|
||||
src/optargs-cryptsetup_open.c \
|
||||
src/optargs-disk_create.c \
|
||||
src/optargs-download_blocks.c \
|
||||
src/optargs-e2fsck.c \
|
||||
|
||||
@@ -1 +1 @@
|
||||
507
|
||||
509
|
||||
|
||||
@@ -585,17 +585,18 @@ 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.
|
||||
Linux guests. Windows BitLocker is also supported.
|
||||
|
||||
Use L</guestfs_vfs_type> to identify LUKS-encrypted block
|
||||
devices (it returns the string C<crypto_LUKS>).
|
||||
Use L</guestfs_vfs_type> to identify encrypted block
|
||||
devices. For LUKS it returns the string C<crypto_LUKS>.
|
||||
For Windows BitLocker it returns C<BitLocker>.
|
||||
|
||||
Then open these devices by calling L</guestfs_luks_open>.
|
||||
Then open these devices by calling L</guestfs_cryptsetup_open>.
|
||||
Obviously you will require the passphrase!
|
||||
|
||||
Opening a LUKS device creates a new device mapper device
|
||||
Opening an encrypted device creates a new device mapper device
|
||||
called F</dev/mapper/mapname> (where C<mapname> is the
|
||||
string you supply to L</guestfs_luks_open>).
|
||||
string you supply to L</guestfs_cryptsetup_open>).
|
||||
Reads and writes to this mapper device are decrypted from and
|
||||
encrypted to the underlying block device respectively.
|
||||
|
||||
@@ -603,11 +604,11 @@ 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
|
||||
Use the reverse process to close an encrypted device. Unmount
|
||||
any logical volumes on it, deactivate the volume groups
|
||||
by calling C<guestfs_vg_activate (g, 0, ["/dev/VG"])>.
|
||||
Then close the mapper device by calling
|
||||
L</guestfs_luks_close> on the F</dev/mapper/mapname>
|
||||
L</guestfs_cryptsetup_close> on the F</dev/mapper/mapname>
|
||||
device (I<not> the underlying encrypted block device).
|
||||
|
||||
=head2 MOUNT LOCAL
|
||||
|
||||
Reference in New Issue
Block a user