From 0267ad921c3be8a780342b052264666cef2cc1b1 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" 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 #include #include +#include +#include +#include #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