diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2010-11-05 11:39:24 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2010-11-05 11:39:24 +0000 |
commit | a232e62dcf508517a32b9a8d7e4529e827be721b (patch) | |
tree | 8fccb1e49fd75aacbc7190eb55685525b6df0f88 /fish | |
parent | 446db62e113594fef84d2f533ef3a1330153f0bb (diff) | |
download | libguestfs-a232e62dcf508517a32b9a8d7e4529e827be721b.tar.gz libguestfs-a232e62dcf508517a32b9a8d7e4529e827be721b.tar.xz libguestfs-a232e62dcf508517a32b9a8d7e4529e827be721b.zip |
fish: '-i' option automatically handles whole-disk encryption.
This feature is also available in guestmount because of the
shared option parsing code.
You don't need to do anything to enable it, just using -i
will attempt decryption of encrypted partitions.
Only works for simple Fedora whole-disk encryption. It's a
work-in-progress to make it work for other types of encryption.
Diffstat (limited to 'fish')
-rw-r--r-- | fish/Makefile.am | 1 | ||||
-rw-r--r-- | fish/fish.c | 64 | ||||
-rw-r--r-- | fish/fish.h | 1 | ||||
-rw-r--r-- | fish/inspect.c | 76 | ||||
-rw-r--r-- | fish/keys.c | 91 | ||||
-rw-r--r-- | fish/options.h | 5 |
6 files changed, 173 insertions, 65 deletions
diff --git a/fish/Makefile.am b/fish/Makefile.am index 61b6346e..dadda91e 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -46,6 +46,7 @@ EXTRA_DIST = \ # other guestfish files. SHARED_SOURCE_FILES = \ inspect.c \ + keys.c \ options.h \ options.c \ virt.c diff --git a/fish/fish.c b/fish/fish.c index 54fd2707..d9a92dda 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -30,7 +30,6 @@ #include <sys/wait.h> #include <locale.h> #include <langinfo.h> -#include <termios.h> #ifdef HAVE_LIBREADLINE #include <readline/readline.h> @@ -1480,66 +1479,3 @@ file_out (const char *arg) } return ret; } - -/* Read a passphrase ('Key') from /dev/tty with echo off. - * The caller (cmds.c) will call free on the string afterwards. - * Based on the code in cryptsetup file lib/utils.c. - */ -char * -read_key (const char *param) -{ - FILE *infp, *outfp; - struct termios orig, temp; - char *ret = NULL; - - /* Read and write to /dev/tty if available. */ - if (keys_from_stdin || - (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) { - infp = stdin; - outfp = stdout; - } - - /* Print the prompt and set no echo. */ - int tty = isatty (fileno (infp)); - int tcset = 0; - if (tty) { - fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param); - - if (!echo_keys) { - if (tcgetattr (fileno (infp), &orig) == -1) { - perror ("tcgetattr"); - goto error; - } - memcpy (&temp, &orig, sizeof temp); - temp.c_lflag &= ~ECHO; - - tcsetattr (fileno (infp), TCSAFLUSH, &temp); - tcset = 1; - } - } - - size_t n = 0; - ssize_t len; - len = getline (&ret, &n, infp); - if (len == -1) { - perror ("getline"); - ret = NULL; - goto error; - } - - /* Remove the terminating \n if there is one. */ - if (len > 0 && ret[len-1] == '\n') - ret[len-1] = '\0'; - - error: - /* Restore echo, close file descriptor. */ - if (tty && tcset) { - printf ("\n"); - tcsetattr (fileno (infp), TCSAFLUSH, &orig); - } - - if (infp != stdin) - fclose (infp); /* outfp == infp, so this is closed also */ - - return ret; -} diff --git a/fish/fish.h b/fish/fish.h index a3f7caf1..8fedf5dc 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -78,7 +78,6 @@ extern char *file_in (const char *arg); extern void free_file_in (char *s); extern char *file_out (const char *arg); extern void extended_help_message (void); -extern char *read_key (const char *param); /* in cmds.c (auto-generated) */ extern void list_commands (void); diff --git a/fish/inspect.c b/fish/inspect.c index 8e56553d..cc3916b1 100644 --- a/fish/inspect.c +++ b/fish/inspect.c @@ -22,10 +22,14 @@ #include <stdlib.h> #include <string.h> +#include "c-ctype.h" + #include "guestfs.h" #include "options.h" +static void do_decrypt (void); + /* Global that saves the root device between inspect_mount and * print_inspect_prompt. */ @@ -71,6 +75,8 @@ compare_keys (const void *p1, const void *p2) void inspect_mount (void) { + do_decrypt (); + char **roots = guestfs_inspect_os (g); if (roots == NULL) exit (EXIT_FAILURE); @@ -139,3 +145,73 @@ print_inspect_prompt (void) free_strings (mountpoints); } + +/* Make a LUKS map name from the partition name, + * eg "/dev/vda2" => "luksvda2" + */ +static void +make_mapname (const char *device, char *mapname, size_t len) +{ + size_t i = 0; + + if (len < 5) + abort (); + strcpy (mapname, "luks"); + mapname += 4; + len -= 4; + + if (STRPREFIX (device, "/dev/")) + i = 5; + + for (; device[i] != '\0' && len >= 1; ++i) { + if (c_isalnum (device[i])) { + *mapname++ = device[i]; + len--; + } + } + + *mapname = '\0'; +} + +/* Simple implementation of decryption: look for any crypto_LUKS + * partitions and decrypt them, then rescan for VGs. This only works + * for Fedora whole-disk encryption. WIP to make this work for other + * encryption schemes. + */ +static void +do_decrypt (void) +{ + char **partitions = guestfs_list_partitions (g); + if (partitions == NULL) + exit (EXIT_FAILURE); + + int need_rescan = 0; + size_t i; + for (i = 0; partitions[i] != NULL; ++i) { + char *type = guestfs_vfs_type (g, partitions[i]); + if (type && STREQ (type, "crypto_LUKS")) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + char *key = read_key (partitions[i]); + /* XXX Should we call guestfs_luks_open_ro if readonly flag + * is set? This might break 'mount_ro'. + */ + if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) + exit (EXIT_FAILURE); + + free (key); + + need_rescan = 1; + } + } + + free_strings (partitions); + + if (need_rescan) { + if (guestfs_vgscan (g) == -1) + exit (EXIT_FAILURE); + if (guestfs_vg_activate_all (g, 1) == -1) + exit (EXIT_FAILURE); + } +} diff --git a/fish/keys.c b/fish/keys.c new file mode 100644 index 00000000..deb627f8 --- /dev/null +++ b/fish/keys.c @@ -0,0 +1,91 @@ +/* libguestfs - guestfish and guestmount shared option parsing + * 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 <unistd.h> +#include <termios.h> + +#include "guestfs.h" + +#include "options.h" + +/* Read a passphrase ('Key') from /dev/tty with echo off. + * The caller (cmds.c) will call free on the string afterwards. + * Based on the code in cryptsetup file lib/utils.c. + */ +char * +read_key (const char *param) +{ + FILE *infp, *outfp; + struct termios orig, temp; + char *ret = NULL; + + /* Read and write to /dev/tty if available. */ + if (keys_from_stdin || + (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) { + infp = stdin; + outfp = stdout; + } + + /* Print the prompt and set no echo. */ + int tty = isatty (fileno (infp)); + int tcset = 0; + if (tty) { + fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param); + + if (!echo_keys) { + if (tcgetattr (fileno (infp), &orig) == -1) { + perror ("tcgetattr"); + goto error; + } + memcpy (&temp, &orig, sizeof temp); + temp.c_lflag &= ~ECHO; + + tcsetattr (fileno (infp), TCSAFLUSH, &temp); + tcset = 1; + } + } + + size_t n = 0; + ssize_t len; + len = getline (&ret, &n, infp); + if (len == -1) { + perror ("getline"); + ret = NULL; + goto error; + } + + /* Remove the terminating \n if there is one. */ + if (len > 0 && ret[len-1] == '\n') + ret[len-1] = '\0'; + + error: + /* Restore echo, close file descriptor. */ + if (tty && tcset) { + printf ("\n"); + tcsetattr (fileno (infp), TCSAFLUSH, &orig); + } + + if (infp != stdin) + fclose (infp); /* outfp == infp, so this is closed also */ + + return ret; +} diff --git a/fish/options.h b/fish/options.h index b0bbdeb2..e36c57a0 100644 --- a/fish/options.h +++ b/fish/options.h @@ -69,6 +69,8 @@ extern guestfs_h *g; extern int read_only; extern int verbose; extern int inspector; +extern int keys_from_stdin; +extern int echo_keys; extern const char *libvirt_uri; extern const char *program_name; @@ -103,6 +105,9 @@ struct mp { extern void inspect_mount (void); extern void print_inspect_prompt (void); +/* in key.c */ +extern char *read_key (const char *param); + /* in options.c */ extern char add_drives (struct drv *drv, char next_drive); extern void mount_mps (struct mp *mp); |