[ostree] libotutil: Add ot_gpgme_ctx_tmp_home_dir()



commit 97379ec38c7de6144089372c16a875e209eb4c2c
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Apr 26 21:25:35 2015 -0400

    libotutil: Add ot_gpgme_ctx_tmp_home_dir()
    
    Currently used for signature verification, will also be used for
    importing GPG keys.

 Makefile-tests.am                   |    2 +-
 src/libostree/ostree-gpg-verifier.c |  167 +++++++++--------------------------
 src/libotutil/ot-gpg-utils.c        |   83 +++++++++++++++++
 src/libotutil/ot-gpg-utils.h        |    7 ++
 4 files changed, 133 insertions(+), 126 deletions(-)
---
diff --git a/Makefile-tests.am b/Makefile-tests.am
index 46bf499..c697333 100644
--- a/Makefile-tests.am
+++ b/Makefile-tests.am
@@ -116,7 +116,7 @@ check_PROGRAMS =  $(TESTS)
 TESTS_ENVIRONMENT = \
        G_TEST_SRCDIR=$(abs_srcdir)/tests \
        G_TEST_BUILDDIR=$(abs_builddir)/tests
-TESTS_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS)
+TESTS_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx
 TESTS_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS)
 
 tests_test_rollsum_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum.c
diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c
index 17282a9..96ca7c6 100644
--- a/src/libostree/ostree-gpg-verifier.c
+++ b/src/libostree/ostree-gpg-verifier.c
@@ -104,120 +104,17 @@ _ostree_gpg_verifier_initable_iface_init (GInitableIface *iface)
   iface->init = ostree_gpg_verifier_initable_init;
 }
 
-static gboolean
-concatenate_keyrings (OstreeGpgVerifier *self,
-                      GFile *destination,
-                      GCancellable *cancellable,
-                      GError **error)
-{
-  gs_unref_object GOutputStream *target_stream = NULL;
-  GList *link;
-  gboolean ret = FALSE;
-
-  target_stream = (GOutputStream *) g_file_replace (destination,
-                                                    NULL,   /* no etag */
-                                                    FALSE,  /* no backup */
-                                                    G_FILE_CREATE_NONE,
-                                                    cancellable, error);
-  if (target_stream == NULL)
-    goto out;
-
-  for (link = self->keyrings; link != NULL; link = link->next)
-    {
-      gs_unref_object GInputStream *source_stream = NULL;
-      GFile *keyring_file = link->data;
-      gssize bytes_written;
-      GError *local_error = NULL;
-
-      source_stream = (GInputStream *) g_file_read (keyring_file, cancellable, &local_error);
-
-      /* Disregard non-existent keyrings. */
-      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-        {
-          g_clear_error (&local_error);
-          continue;
-        }
-      else if (local_error != NULL)
-        {
-          g_propagate_error (error, local_error);
-          goto out;
-        }
-
-      bytes_written = g_output_stream_splice (target_stream,
-                                              source_stream,
-                                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
-                                              cancellable, error);
-      if (bytes_written == -1)
-        goto out;
-    }
-
-  if (!g_output_stream_close (target_stream, cancellable, error))
-    goto out;
-
-  ret = TRUE;
-
-out:
-  return ret;
-}
-
-static gboolean
-override_gpgme_home_dir (gpgme_ctx_t gpg_ctx,
-                         const char *home_dir,
-                         GError **error)
-{
-  gpgme_engine_info_t gpg_engine_info;
-  gboolean ret = FALSE;
-
-  /* Override the OpenPGP engine's configuration directory without
-   * affecting other parameters.  This requires finding the current
-   * parameters since the engine API takes all parameters at once. */
-
-  for (gpg_engine_info = gpgme_ctx_get_engine_info (gpg_ctx);
-       gpg_engine_info != NULL;
-       gpg_engine_info = gpg_engine_info->next)
-    {
-      if (gpg_engine_info->protocol == GPGME_PROTOCOL_OpenPGP)
-        {
-          gpgme_error_t gpg_error;
-
-          gpg_error = gpgme_ctx_set_engine_info (gpg_ctx,
-                                                 gpg_engine_info->protocol,
-                                                 gpg_engine_info->file_name,
-                                                 home_dir);
-          if (gpg_error != GPG_ERR_NO_ERROR)
-            {
-              ot_gpgme_error_to_gio_error (gpg_error, error);
-              goto out;
-            }
-
-          break;
-        }
-    }
-
-  if (gpg_engine_info == NULL)
-    {
-      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "GPGME: No OpenPGP engine available");
-      goto out;
-    }
-
-  ret = TRUE;
-
-out:
-  return ret;
-}
-
 static void
 verify_result_finalized_cb (gpointer data,
                             GObject *finalized_verify_result)
 {
-  g_autofree gchar *temp_dir = data;  /* assume ownership */
+  g_autofree gchar *tmp_dir = data;  /* assume ownership */
 
   /* XXX OstreeGpgVerifyResult could do this cleanup in its own
    *     finalize() method, but I didn't want this keyring hack
    *     bleeding into multiple classes. */
 
-  (void) glnx_shutil_rm_rf_at (AT_FDCWD, temp_dir, NULL, NULL);
+  (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL);
 }
 
 OstreeGpgVerifyResult *
@@ -231,11 +128,11 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier  *self,
   gpgme_error_t gpg_error = NULL;
   gpgme_data_t data_buffer = NULL;
   gpgme_data_t signature_buffer = NULL;
-  gs_unref_object GFile *pubring_file = NULL;
-  gs_free char *pubring_path = NULL;
-  gs_free char *temp_dir = NULL;
+  g_autofree char *tmp_dir = NULL;
+  glnx_unref_object GOutputStream *target_stream = NULL;
   OstreeGpgVerifyResult *result = NULL;
   gboolean success = FALSE;
+  GList *link;
 
   /* GPGME has no API for using multiple keyrings (aka, gpg --keyring),
    * so we concatenate all the keyring files into one pubring.gpg in a
@@ -245,26 +142,46 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier  *self,
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     goto out;
 
-  temp_dir = g_build_filename (g_get_tmp_dir (), "ostree-gpg-XXXXXX", NULL);
+  result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT,
+                           cancellable, error, NULL);
+  if (result == NULL)
+    goto out;
+
+  if (!ot_gpgme_ctx_tmp_home_dir (result->context, NULL,
+                                  &tmp_dir, &target_stream,
+                                  cancellable, error))
+    goto out;
 
-  if (mkdtemp (temp_dir) == NULL)
+  for (link = self->keyrings; link != NULL; link = link->next)
     {
-      gs_set_error_from_errno (error, errno);
-      goto out;
-    }
+      glnx_unref_object GFileInputStream *source_stream = NULL;
+      GFile *keyring_file = link->data;
+      gssize bytes_written;
+      GError *local_error = NULL;
 
-  pubring_path = g_build_filename (temp_dir, "pubring.gpg", NULL);
+      source_stream = g_file_read (keyring_file, cancellable, &local_error);
 
-  pubring_file = g_file_new_for_path (pubring_path);
-  if (!concatenate_keyrings (self, pubring_file, cancellable, error))
-    goto out;
+      /* Disregard non-existent keyrings. */
+      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+        {
+          g_clear_error (&local_error);
+          continue;
+        }
+      else if (local_error != NULL)
+        {
+          g_propagate_error (error, local_error);
+          goto out;
+        }
 
-  result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT,
-                           cancellable, error, NULL);
-  if (result == NULL)
-    goto out;
+      bytes_written = g_output_stream_splice (target_stream,
+                                              G_INPUT_STREAM (source_stream),
+                                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+                                              cancellable, error);
+      if (bytes_written < 0)
+        goto out;
+    }
 
-  if (!override_gpgme_home_dir (result->context, temp_dir, error))
+  if (!g_output_stream_close (target_stream, cancellable, error))
     goto out;
 
   /* Both the signed data and signature GBytes instances will outlive the
@@ -325,7 +242,7 @@ out:
        * the fabricated pubring.gpg keyring. */
       g_object_weak_ref (G_OBJECT (result),
                          verify_result_finalized_cb,
-                         g_strdup (temp_dir));
+                         g_strdup (tmp_dir));
     }
   else
     {
@@ -333,8 +250,8 @@ out:
       g_clear_object (&result);
 
       /* Try to clean up the temporary directory. */
-      if (temp_dir != NULL)
-        (void) glnx_shutil_rm_rf_at (AT_FDCWD, temp_dir, NULL, NULL);
+      if (tmp_dir != NULL)
+        (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL);
     }
 
   g_prefix_error (error, "GPG: ");
diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c
index d1e2a9f..959f0f4 100644
--- a/src/libotutil/ot-gpg-utils.c
+++ b/src/libotutil/ot-gpg-utils.c
@@ -22,6 +22,10 @@
 
 #include "ot-gpg-utils.h"
 
+#include <stdlib.h>
+
+#include "libglnx.h"
+
 void
 ot_gpgme_error_to_gio_error (gpgme_error_t   gpg_error,
                              GError        **error)
@@ -55,3 +59,82 @@ ot_gpgme_error_to_gio_error (gpgme_error_t   gpg_error,
                gpgme_strsource (gpg_error),
                gpgme_strerror (gpg_error));
 }
+
+gboolean
+ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t     gpgme_ctx,
+                           const char     *tmp_dir,
+                           char          **out_tmp_home_dir,
+                           GOutputStream **out_pubring_stream,
+                           GCancellable   *cancellable,
+                           GError        **error)
+{
+  g_autoptr(GFile) pubring_file = NULL;
+  g_autoptr(GOutputStream) target_stream = NULL;
+  g_autofree char *pubring_path = NULL;
+  g_autofree char *tmp_home_dir = NULL;
+  gpgme_error_t gpg_error;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (gpgme_ctx != NULL, FALSE);
+
+  /* GPGME has no API for using multiple keyrings (aka, gpg --keyring),
+   * so we create a temporary directory and tell GPGME to use it as the
+   * home directory.  Then (optionally) create a pubring.gpg file there
+   * and hand the caller an open output stream to concatenate necessary
+   * keyring files. */
+
+  if (tmp_dir == NULL)
+    tmp_dir = g_get_tmp_dir ();
+
+  tmp_home_dir = g_build_filename (tmp_dir, "ostree-gpg-XXXXXX", NULL);
+
+  if (mkdtemp (tmp_home_dir) == NULL)
+    {
+      glnx_set_error_from_errno (error);
+      goto out;
+    }
+
+  /* Not documented, but gpgme_ctx_set_engine_info() accepts NULL for
+   * the executable file name, which leaves the old setting unchanged. */
+  gpg_error = gpgme_ctx_set_engine_info (gpgme_ctx,
+                                         GPGME_PROTOCOL_OpenPGP,
+                                         NULL, tmp_home_dir);
+  if (gpg_error != GPG_ERR_NO_ERROR)
+    {
+      ot_gpgme_error_to_gio_error (gpg_error, error);
+      goto out;
+    }
+
+  if (out_pubring_stream != NULL)
+    {
+      GFileOutputStream *pubring_stream;
+      glnx_unref_object GFile *pubring_file = NULL;
+      g_autofree char *pubring_path = NULL;
+
+      pubring_path = g_build_filename (tmp_home_dir, "pubring.gpg", NULL);
+      pubring_file = g_file_new_for_path (pubring_path);
+
+      pubring_stream = g_file_create (pubring_file,
+                                      G_FILE_CREATE_NONE,
+                                      cancellable, error);
+      if (pubring_stream == NULL)
+        goto out;
+
+      /* Sneaky cast from GFileOutputStream to GOutputStream. */
+      *out_pubring_stream = g_steal_pointer (&pubring_stream);
+    }
+
+  if (out_tmp_home_dir != NULL)
+    *out_tmp_home_dir = g_steal_pointer (&tmp_home_dir);
+
+  ret = TRUE;
+
+out:
+  if (!ret)
+    {
+      /* Clean up our mess on error. */
+      (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_home_dir, NULL, NULL);
+    }
+
+  return ret;
+}
diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h
index 1ec9e9e..0a67070 100644
--- a/src/libotutil/ot-gpg-utils.h
+++ b/src/libotutil/ot-gpg-utils.h
@@ -27,4 +27,11 @@ G_BEGIN_DECLS
 
 void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error);
 
+gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t     gpgme_ctx,
+                                    const char     *tmp_dir,
+                                    char          **out_tmp_home_dir,
+                                    GOutputStream **out_pubring_stream,
+                                    GCancellable   *cancellable,
+                                    GError        **error);
+
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]