From c287a7419cda9b2f5029f81e39da15625baff2e8 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 1 May 2015 09:09:42 -0400 Subject: [PATCH] ostree: Add a "remote gpg-import" command Imports GPG keys into a remote-specific keyring. --- Makefile-ostree.am | 1 + doc/ostree-remote.xml | 37 ++++++ src/ostree/ot-builtin-remote.c | 1 + src/ostree/ot-remote-builtin-gpg-import.c | 142 ++++++++++++++++++++++ src/ostree/ot-remote-builtins.h | 1 + 5 files changed, 182 insertions(+) create mode 100644 src/ostree/ot-remote-builtin-gpg-import.c diff --git a/Makefile-ostree.am b/Makefile-ostree.am index f420e28c..9ae9870a 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -77,6 +77,7 @@ ostree_SOURCES += \ src/ostree/ot-remote-builtins.h \ src/ostree/ot-remote-builtin-add.c \ src/ostree/ot-remote-builtin-delete.c \ + src/ostree/ot-remote-builtin-gpg-import.c \ src/ostree/ot-remote-builtin-list.c \ src/ostree/ot-remote-builtin-show-url.c \ $(NULL) diff --git a/doc/ostree-remote.xml b/doc/ostree-remote.xml index add24322..e5222992 100644 --- a/doc/ostree-remote.xml +++ b/doc/ostree-remote.xml @@ -60,6 +60,9 @@ Boston, MA 02111-1307, USA. ostree remote list OPTIONS NAME + + ostree remote gpg-import OPTIONS NAME KEY-ID + @@ -68,6 +71,12 @@ Boston, MA 02111-1307, USA. Changes remote respository configurations. The NAME refers to the name of the remote. + + The gpg-import subcommand can associate GPG keys to a specific remote respository for use when pulling signed commits from that repository (if GPG verification is enabled). + + + The GPG keys to import may be in binary OpenPGP format or ASCII armored. The optional KEY-ID list can restrict which keys are imported from a keyring file or input stream. All keys are imported if this list is omitted. If neither nor options are given, then keys are imported from the user's personal GPG keyring. + @@ -106,6 +115,34 @@ Boston, MA 02111-1307, USA. + + 'GPG-Import' Options + + + + =FILE + + + Import one or more keys from a file. + + This option may be repeated to import from multiple files, + but may not be used in combination with + . + + + + + + + Import one or more keys from standard input. + + This option may not be used in combination with + . + + + + + Example $ ostree remote show-url local diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c index 608b9ef1..c112063c 100644 --- a/src/ostree/ot-builtin-remote.c +++ b/src/ostree/ot-builtin-remote.c @@ -36,6 +36,7 @@ static OstreeRemoteCommand remote_subcommands[] = { { "delete", ot_remote_builtin_delete }, { "show-url", ot_remote_builtin_show_url }, { "list", ot_remote_builtin_list }, + { "gpg-import", ot_remote_builtin_gpg_import }, { NULL, NULL } }; diff --git a/src/ostree/ot-remote-builtin-gpg-import.c b/src/ostree/ot-remote-builtin-gpg-import.c new file mode 100644 index 00000000..4d2ad505 --- /dev/null +++ b/src/ostree/ot-remote-builtin-gpg-import.c @@ -0,0 +1,142 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +/* XXX This belongs in libotutil. */ +#include "ostree-chain-input-stream.h" + +static gboolean opt_stdin; +static char **opt_keyrings; + +static GOptionEntry option_entries[] = { + { "keyring", 'k', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_keyrings, "Import keys from a keyring file (repeatable)", "FILE" }, + { "stdin", 0, 0, G_OPTION_ARG_NONE, &opt_stdin, "Import keys from standard input", NULL }, + { NULL } +}; + +static gboolean +open_source_stream (GInputStream **out_source_stream, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) source_stream = NULL; + guint n_keyrings = 0; + gboolean ret = FALSE; + + if (opt_keyrings != NULL) + n_keyrings = g_strv_length (opt_keyrings); + + if (opt_stdin) + { + source_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE); + } + else + { + g_autoptr(GPtrArray) streams = NULL; + guint ii; + + streams = g_ptr_array_new_with_free_func (g_object_unref); + + for (ii = 0; ii < n_keyrings; ii++) + { + g_autoptr(GFile) file = NULL; + GFileInputStream *input_stream = NULL; + + file = g_file_new_for_path (opt_keyrings[ii]); + input_stream = g_file_read (file, cancellable, error); + + if (input_stream == NULL) + goto out; + + /* Takes ownership. */ + g_ptr_array_add (streams, input_stream); + } + + /* Chain together all the --keyring options as one long stream. */ + source_stream = (GInputStream *) ostree_chain_input_stream_new (streams); + } + + *out_source_stream = g_steal_pointer (&source_stream); + + ret = TRUE; + +out: + return ret; +} + +gboolean +ot_remote_builtin_gpg_import (int argc, char **argv, GCancellable *cancellable, GError **error) +{ + GOptionContext *context; + glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(GInputStream) source_stream = NULL; + const char *remote_name; + const char * const *key_ids; + guint imported = 0; + gboolean ret = FALSE; + + context = g_option_context_new ("NAME [KEY-ID...] - Import GPG keys"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + goto out; + } + + if (opt_stdin && opt_keyrings != NULL) + { + ot_util_usage_error (context, "--keyring and --stdin are mutually exclusive", error); + goto out; + } + + remote_name = argv[1]; + key_ids = (argc > 2) ? (const char * const *) argv + 2 : NULL; + + if (!open_source_stream (&source_stream, cancellable, error)) + goto out; + + if (!ostree_repo_remote_gpg_import (repo, remote_name, source_stream, + key_ids, &imported, cancellable, error)) + goto out; + + /* XXX If we ever add internationalization, use ngettext() here. */ + g_print ("Imported %u GPG key%s to remote \"%s\"\n", + imported, (imported == 1) ? "" : "s", remote_name); + + ret = TRUE; + + out: + g_option_context_free (context); + + return ret; +} diff --git a/src/ostree/ot-remote-builtins.h b/src/ostree/ot-remote-builtins.h index 833b6149..286ac9a1 100644 --- a/src/ostree/ot-remote-builtins.h +++ b/src/ostree/ot-remote-builtins.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS gboolean ot_remote_builtin_add (int argc, char **argv, GCancellable *cancellable, GError **error); gboolean ot_remote_builtin_delete (int argc, char **argv, GCancellable *cancellable, GError **error); +gboolean ot_remote_builtin_gpg_import (int argc, char **argv, GCancellable *cancellable, GError **error); gboolean ot_remote_builtin_list (int argc, char **argv, GCancellable *cancellable, GError **error); gboolean ot_remote_builtin_show_url (int argc, char **argv, GCancellable *cancellable, GError **error);