[Libguestfs] [libguestfs-common PATCH v2 04/12] options: replace NULL-termination with number-of-elements in get_keys()

Laszlo Ersek lersek at redhat.com
Thu Jun 30 12:20:20 UTC 2022


Currently, get_keys() returns a NULL-terminated array of (char*) elements.
In a later patch in this series, we'll want to change the element type to
a structure type, at which point the NULL-termination would become
awkward. Replace the NULL-termination scheme with the number-of-elements
scheme. No behavioral changes.

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
Reviewed-by: Richard W.M. Jones <rjones at redhat.com>
---

Notes:
    v2:
    - pick up Rich's R-b

 options/options.h |  4 +++-
 options/decrypt.c | 17 +++++++-------
 options/keys.c    | 24 ++++++++++++++------
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/options/options.h b/options/options.h
index 80df91a85f98..d7a3aeff6f41 100644
--- a/options/options.h
+++ b/options/options.h
@@ -149,11 +149,13 @@ extern void inspect_mount_root (guestfs_h *g, const char *root);
 #define inspect_mount() inspect_mount_handle (g, ks)
 extern void print_inspect_prompt (void);
 
 /* in key.c */
 extern char *read_key (const char *param);
-extern char **get_keys (struct key_store *ks, const char *device, const char *uuid);
+extern char **get_keys (struct key_store *ks, const char *device, const char *uuid,
+                        size_t *nr_matches);
+extern void free_keys (char **keys, size_t nr_matches);
 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);
 
 /* in options.c */
diff --git a/options/decrypt.c b/options/decrypt.c
index 1cd7b627e264..c25b5888d8b4 100644
--- a/options/decrypt.c
+++ b/options/decrypt.c
@@ -122,14 +122,14 @@ decrypt_mountables (guestfs_h *g, const char * const *mountables,
   const char *mountable;
 
   while ((mountable = *mnt_scan++) != NULL) {
     CLEANUP_FREE char *type = NULL;
     CLEANUP_FREE char *uuid = NULL;
-    CLEANUP_FREE_STRING_LIST char **keys = NULL;
+    char **keys;
+    size_t nr_matches;
     CLEANUP_FREE char *mapname = NULL;
-    const char * const *key_scan;
-    const char *key;
+    size_t scan;
 
     type = guestfs_vfs_type (g, mountable);
     if (type == NULL)
       continue;
 
@@ -142,37 +142,38 @@ decrypt_mountables (guestfs_h *g, const char * const *mountables,
       continue;
 
     /* Grab the keys that we should try with this device, based on device name,
      * or UUID (if any).
      */
-    keys = get_keys (ks, mountable, uuid);
-    assert (keys[0] != NULL);
+    keys = get_keys (ks, mountable, uuid, &nr_matches);
+    assert (nr_matches > 0);
 
     /* Generate a node name for the plaintext (decrypted) device node. */
     if (uuid == NULL || asprintf (&mapname, "luks-%s", uuid) == -1)
       mapname = make_mapname (mountable);
 
     /* Try each key in turn. */
-    key_scan = (const char * const *)keys;
-    while ((key = *key_scan++) != NULL) {
+    for (scan = 0; scan < nr_matches; ++scan) {
+      const char *key = keys[scan];
       int r;
 
       guestfs_push_error_handler (g, NULL, NULL);
       r = guestfs_cryptsetup_open (g, mountable, key, mapname, -1);
       guestfs_pop_error_handler (g);
 
       if (r == 0)
         break;
     }
 
-    if (key == NULL)
+    if (scan == nr_matches)
       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)"),
              mountable, guestfs_last_error (g), guestfs_last_errno (g));
 
+    free_keys (keys, nr_matches);
     decrypted_some = true;
   }
 
   return decrypted_some;
 }
diff --git a/options/keys.c b/options/keys.c
index 8713372a305e..1d97d980a460 100644
--- a/options/keys.c
+++ b/options/keys.c
@@ -124,11 +124,12 @@ read_first_line_from_file (const char *filename)
 /* 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, const char *uuid)
+get_keys (struct key_store *ks, const char *device, const char *uuid,
+          size_t *nr_matches)
 {
   size_t i, j, nmemb;
   char **r;
   char *s;
 
@@ -137,18 +138,16 @@ get_keys (struct key_store *ks, const char *device, const char *uuid)
    */
   nmemb = 1;
   if (ks && ks->nr_keys > nmemb)
     nmemb = ks->nr_keys;
 
-  /* make room for the terminating NULL */
-  if (nmemb == (size_t)-1)
+  if (nmemb > (size_t)-1 / sizeof *r)
     error (EXIT_FAILURE, 0, _("size_t overflow"));
-  nmemb++;
 
-  r = calloc (nmemb, sizeof (char *));
+  r = malloc (nmemb * sizeof *r);
   if (r == NULL)
-    error (EXIT_FAILURE, errno, "calloc");
+    error (EXIT_FAILURE, errno, "malloc");
 
   j = 0;
 
   if (ks) {
     for (i = 0; i < ks->nr_keys; ++i) {
@@ -175,16 +174,27 @@ get_keys (struct key_store *ks, const char *device, const char *uuid)
   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;
+    r[j++] = s;
   }
 
+  *nr_matches = j;
   return r;
 }
 
+void
+free_keys (char **keys, size_t nr_matches)
+{
+  size_t i;
+
+  for (i = 0; i < nr_matches; ++i)
+    free (keys[i]);
+  free (keys);
+}
+
 struct key_store *
 key_store_add_from_selector (struct key_store *ks, const char *selector)
 {
   CLEANUP_FREE_STRING_LIST char **fields =
     guestfs_int_split_string (':', selector);
-- 
2.19.1.3.g30247aa5d201




More information about the Libguestfs mailing list