181 lines
5.4 KiB
Diff
181 lines
5.4 KiB
Diff
From 0267ad921c3be8a780342b052264666cef2cc1b1 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Tue, 12 Nov 2019 17:50:17 +0000
|
|
Subject: [PATCH] options: Allow multiple --key parameters.
|
|
|
|
This allows multiple --key parameters on the command line to match a
|
|
single device. For example:
|
|
|
|
tool --key /dev/sda1:key:trykey1 --key /dev/sda1:key:trykey2
|
|
|
|
would try "trykey1" and "trykey2" against /dev/sda1.
|
|
|
|
(cherry picked from commit c10c8baedb88e7c2988a01b70fc5f81fa8e4885c
|
|
in libguestfs-common)
|
|
---
|
|
common/options/decrypt.c | 35 ++++++++++++++++++++++++-------
|
|
common/options/keys.c | 45 +++++++++++++++++++++++++++++++---------
|
|
common/options/options.h | 6 ++++--
|
|
3 files changed, 66 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/common/options/decrypt.c b/common/options/decrypt.c
|
|
index 234163d8c..3511d9fe9 100644
|
|
--- a/common/options/decrypt.c
|
|
+++ b/common/options/decrypt.c
|
|
@@ -26,6 +26,9 @@
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
+#include <libintl.h>
|
|
+#include <error.h>
|
|
+#include <assert.h>
|
|
|
|
#include "c-ctype.h"
|
|
|
|
@@ -74,21 +77,37 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
|
|
if (partitions == NULL)
|
|
exit (EXIT_FAILURE);
|
|
|
|
- int need_rescan = 0;
|
|
- size_t i;
|
|
+ int need_rescan = 0, r;
|
|
+ size_t i, j;
|
|
+
|
|
for (i = 0; partitions[i] != NULL; ++i) {
|
|
CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]);
|
|
if (type && STREQ (type, "crypto_LUKS")) {
|
|
char mapname[32];
|
|
make_mapname (partitions[i], mapname, sizeof mapname);
|
|
|
|
- CLEANUP_FREE char *key = get_key (ks, 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);
|
|
+ CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i]);
|
|
+ assert (guestfs_int_count_strings (keys) > 0);
|
|
|
|
+ /* Try each key in turn. */
|
|
+ for (j = 0; keys[j] != NULL; ++j) {
|
|
+ /* XXX Should we call guestfs_luks_open_ro if readonly flag
|
|
+ * is set? This might break 'mount_ro'.
|
|
+ */
|
|
+ guestfs_push_error_handler (g, NULL, NULL);
|
|
+ r = guestfs_luks_open (g, partitions[i], keys[j], mapname);
|
|
+ guestfs_pop_error_handler (g);
|
|
+ if (r == 0)
|
|
+ goto opened;
|
|
+ }
|
|
+ error (EXIT_FAILURE, 0,
|
|
+ _("could not find key to open LUKS encrypted %s.\n\n"
|
|
+ "Try using --key on the command line.\n\n"
|
|
+ "Original error: %s (%d)"),
|
|
+ partitions[i], guestfs_last_error (g),
|
|
+ guestfs_last_errno (g));
|
|
+
|
|
+ opened:
|
|
need_rescan = 1;
|
|
}
|
|
}
|
|
diff --git a/common/options/keys.c b/common/options/keys.c
|
|
index 74b549731..782bdb67f 100644
|
|
--- a/common/options/keys.c
|
|
+++ b/common/options/keys.c
|
|
@@ -121,15 +121,32 @@ read_first_line_from_file (const char *filename)
|
|
return ret;
|
|
}
|
|
|
|
-char *
|
|
-get_key (struct key_store *ks, const char *device)
|
|
+/* Return the key(s) matching this particular device from the
|
|
+ * keystore. There may be multiple. If none are read from the
|
|
+ * keystore, ask the user.
|
|
+ */
|
|
+char **
|
|
+get_keys (struct key_store *ks, const char *device)
|
|
{
|
|
- size_t i;
|
|
+ size_t i, j, len;
|
|
+ char **r;
|
|
+ char *s;
|
|
+
|
|
+ /* We know the returned list must have at least one element and not
|
|
+ * more than ks->nr_keys.
|
|
+ */
|
|
+ len = 1;
|
|
+ if (ks)
|
|
+ len = MIN (1, ks->nr_keys);
|
|
+ r = calloc (len+1, sizeof (char *));
|
|
+ if (r == NULL)
|
|
+ error (EXIT_FAILURE, errno, "calloc");
|
|
+
|
|
+ j = 0;
|
|
|
|
if (ks) {
|
|
for (i = 0; i < ks->nr_keys; ++i) {
|
|
struct key_store_key *key = &ks->keys[i];
|
|
- char *s;
|
|
|
|
if (STRNEQ (key->device, device))
|
|
continue;
|
|
@@ -139,17 +156,25 @@ get_key (struct key_store *ks, const char *device)
|
|
s = strdup (key->string.s);
|
|
if (!s)
|
|
error (EXIT_FAILURE, errno, "strdup");
|
|
- return s;
|
|
+ r[j++] = s;
|
|
+ break;
|
|
case key_file:
|
|
- return read_first_line_from_file (key->file.name);
|
|
+ s = read_first_line_from_file (key->file.name);
|
|
+ r[j++] = s;
|
|
+ break;
|
|
}
|
|
-
|
|
- /* Key not found in the key store, ask the user for it. */
|
|
- break;
|
|
}
|
|
}
|
|
|
|
- return read_key (device);
|
|
+ if (j == 0) {
|
|
+ /* Key not found in the key store, ask the user for it. */
|
|
+ s = read_key (device);
|
|
+ if (!s)
|
|
+ error (EXIT_FAILURE, 0, _("could not read key from user"));
|
|
+ r[0] = s;
|
|
+ }
|
|
+
|
|
+ return r;
|
|
}
|
|
|
|
struct key_store *
|
|
diff --git a/common/options/options.h b/common/options/options.h
|
|
index 6fadf1e76..510e8a8a9 100644
|
|
--- a/common/options/options.h
|
|
+++ b/common/options/options.h
|
|
@@ -104,7 +104,9 @@ struct mp {
|
|
|
|
/* A key in the key store. */
|
|
struct key_store_key {
|
|
- /* The device this key refers to. */
|
|
+ /* The device this key refers to. There may be multiple matching
|
|
+ * devices in the list.
|
|
+ */
|
|
char *device;
|
|
|
|
enum {
|
|
@@ -146,7 +148,7 @@ extern void print_inspect_prompt (void);
|
|
|
|
/* in key.c */
|
|
extern char *read_key (const char *param);
|
|
-extern char *get_key (struct key_store *ks, const char *device);
|
|
+extern char **get_keys (struct key_store *ks, const char *device);
|
|
extern struct key_store *key_store_add_from_selector (struct key_store *ks, const char *selector);
|
|
extern struct key_store *key_store_import_key (struct key_store *ks, const struct key_store_key *key);
|
|
extern void free_key_store (struct key_store *ks);
|
|
--
|
|
2.18.4
|
|
|