summaryrefslogtreecommitdiffstats
path: root/fish
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2010-11-05 11:39:24 +0000
committerRichard W.M. Jones <rjones@redhat.com>2010-11-05 11:39:24 +0000
commita232e62dcf508517a32b9a8d7e4529e827be721b (patch)
tree8fccb1e49fd75aacbc7190eb55685525b6df0f88 /fish
parent446db62e113594fef84d2f533ef3a1330153f0bb (diff)
downloadlibguestfs-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.am1
-rw-r--r--fish/fish.c64
-rw-r--r--fish/fish.h1
-rw-r--r--fish/inspect.c76
-rw-r--r--fish/keys.c91
-rw-r--r--fish/options.h5
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);