Blame SOURCES/0037-options-Allow-multiple-key-parameters.patch

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