|
rpm-build |
0fba15 |
/*
|
|
rpm-build |
0fba15 |
* Copyright (C) 2015 Red Hat, Inc.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* SPDX-License-Identifier: LGPL-2.0+
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is free software; you can redistribute it and/or
|
|
rpm-build |
0fba15 |
* modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License as published by the Free Software Foundation; either
|
|
rpm-build |
0fba15 |
* version 2 of the License, or (at your option) any later version.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
0fba15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
0fba15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
0fba15 |
* Lesser General Public License for more details.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License along with this library; if not, write to the
|
|
rpm-build |
0fba15 |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
rpm-build |
0fba15 |
* Boston, MA 02111-1307, USA.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "config.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "otutil.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "ot-main.h"
|
|
rpm-build |
0fba15 |
#include "ot-remote-builtins.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static char **opt_set;
|
|
rpm-build |
0fba15 |
static gboolean opt_no_gpg_verify;
|
|
rpm-build |
0fba15 |
static gboolean opt_no_sign_verify;
|
|
rpm-build |
0fba15 |
static gboolean opt_if_not_exists;
|
|
rpm-build |
0fba15 |
static gboolean opt_force;
|
|
rpm-build |
0fba15 |
static char *opt_gpg_import;
|
|
rpm-build |
0fba15 |
static char **opt_sign_verify;
|
|
rpm-build |
0fba15 |
static char *opt_contenturl;
|
|
rpm-build |
0fba15 |
static char *opt_collection_id;
|
|
rpm-build |
0fba15 |
static char *opt_sysroot;
|
|
rpm-build |
0fba15 |
static char *opt_repo;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* ATTENTION:
|
|
rpm-build |
0fba15 |
* Please remember to update the bash-completion script (bash/ostree) and
|
|
rpm-build |
0fba15 |
* man page (man/ostree-remote.xml) when changing the option list.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static GOptionEntry option_entries[] = {
|
|
rpm-build |
0fba15 |
{ "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" },
|
|
rpm-build |
0fba15 |
{ "no-gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_gpg_verify, "Disable GPG verification", NULL },
|
|
rpm-build |
0fba15 |
{ "no-sign-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_sign_verify, "Disable signature verification", NULL },
|
|
rpm-build |
0fba15 |
{ "sign-verify", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_sign_verify, "Verify signatures using KEYTYPE=inline:PUBKEY or KEYTYPE=file:/path/to/key", "KEYTYPE=[inline|file]:PUBKEY" },
|
|
rpm-build |
0fba15 |
{ "if-not-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Do nothing if the provided remote exists", NULL },
|
|
rpm-build |
0fba15 |
{ "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Replace the provided remote if it exists", NULL },
|
|
rpm-build |
0fba15 |
{ "gpg-import", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_import, "Import GPG key from FILE", "FILE" },
|
|
rpm-build |
0fba15 |
{ "contenturl", 0, 0, G_OPTION_ARG_STRING, &opt_contenturl, "Use URL when fetching content", "URL" },
|
|
rpm-build |
0fba15 |
{ "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id,
|
|
rpm-build |
0fba15 |
"Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" },
|
|
rpm-build |
0fba15 |
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
|
|
rpm-build |
0fba15 |
{ "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" },
|
|
rpm-build |
0fba15 |
{ NULL }
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static char *
|
|
rpm-build |
0fba15 |
add_verify_opt (GVariantBuilder *builder,
|
|
rpm-build |
0fba15 |
const char *keyspec,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_auto(GStrv) parts = g_strsplit (keyspec, "=", 2);
|
|
rpm-build |
0fba15 |
g_assert (parts && *parts);
|
|
rpm-build |
0fba15 |
const char *keytype = parts[0];
|
|
rpm-build |
0fba15 |
if (!parts[1])
|
|
rpm-build |
0fba15 |
return glnx_null_throw (error, "Failed to parse KEYTYPE=[inline|file]:DATA in %s", keyspec);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_autoptr(OstreeSign) sign = ostree_sign_get_by_name (keytype, error);
|
|
rpm-build |
0fba15 |
if (!sign)
|
|
rpm-build |
0fba15 |
return NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
const char *rest = parts[1];
|
|
rpm-build |
0fba15 |
g_assert (!parts[2]);
|
|
rpm-build |
0fba15 |
g_auto(GStrv) keyparts = g_strsplit (rest, ":", 2);
|
|
rpm-build |
0fba15 |
g_assert (keyparts && *keyparts);
|
|
rpm-build |
0fba15 |
const char *keyref = keyparts[0];
|
|
rpm-build |
0fba15 |
g_assert (keyref);
|
|
rpm-build |
0fba15 |
g_autofree char *optname = NULL;
|
|
rpm-build |
0fba15 |
if (g_str_equal (keyref, "inline"))
|
|
rpm-build |
0fba15 |
optname = g_strdup_printf ("verification-%s-key", keytype);
|
|
rpm-build |
0fba15 |
else if (g_str_equal (keyref, "file"))
|
|
rpm-build |
0fba15 |
optname = g_strdup_printf ("verification-%s-file", keytype);
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
return glnx_null_throw (error, "Invalid key reference %s, expected inline|file", keyref);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_assert (keyparts[1] && !keyparts[2]);
|
|
rpm-build |
0fba15 |
g_variant_builder_add (builder, "{s@v}",
|
|
rpm-build |
0fba15 |
optname,
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_string (keyparts[1])));
|
|
rpm-build |
0fba15 |
return g_strdup (ostree_sign_get_name (sign));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GOptionContext) context = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(OstreeSysroot) sysroot = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(OstreeRepo) repo = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(GString) sign_verify = NULL;
|
|
rpm-build |
0fba15 |
const char *remote_name;
|
|
rpm-build |
0fba15 |
const char *remote_url;
|
|
rpm-build |
0fba15 |
char **iter;
|
|
rpm-build |
0fba15 |
g_autoptr(GVariantBuilder) optbuilder = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(GVariant) options = NULL;
|
|
rpm-build |
0fba15 |
gboolean ret = FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
context = g_option_context_new ("NAME [metalink=|mirrorlist=]URL [BRANCH...]");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
|
|
rpm-build |
0fba15 |
invocation, NULL, cancellable, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo,
|
|
rpm-build |
0fba15 |
&sysroot, &repo,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (argc < 3)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
ot_util_usage_error (context, "NAME and URL must be specified", error);
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (opt_if_not_exists && opt_force)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
ot_util_usage_error (context,
|
|
rpm-build |
0fba15 |
"Can only specify one of --if-not-exists and --force",
|
|
rpm-build |
0fba15 |
error);
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
remote_name = argv[1];
|
|
rpm-build |
0fba15 |
remote_url = argv[2];
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (argc > 3)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GPtrArray) branchesp = g_ptr_array_new ();
|
|
rpm-build |
0fba15 |
int i;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
for (i = 3; i < argc; i++)
|
|
rpm-build |
0fba15 |
g_ptr_array_add (branchesp, argv[i]);
|
|
rpm-build |
0fba15 |
g_ptr_array_add (branchesp, NULL);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
"branches",
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_strv ((const char*const*)branchesp->pdata, -1)));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* We could just make users use --set instead for this since it's a string,
|
|
rpm-build |
0fba15 |
* but e.g. when mirrorlist support is added, it'll be kinda awkward to type:
|
|
rpm-build |
0fba15 |
* --set=contenturl=mirrorlist=... */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (opt_contenturl != NULL)
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
"contenturl", g_variant_new_variant (g_variant_new_string (opt_contenturl)));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
for (iter = opt_set; iter && *iter; iter++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const char *keyvalue = *iter;
|
|
rpm-build |
0fba15 |
g_autofree char *subkey = NULL;
|
|
rpm-build |
0fba15 |
g_autofree char *subvalue = NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ot_parse_keyvalue (keyvalue, &subkey, &subvalue, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
subkey, g_variant_new_variant (g_variant_new_string (subvalue)));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#ifndef OSTREE_DISABLE_GPGME
|
|
rpm-build |
0fba15 |
/* No signature verification implies no verification for GPG signature as well */
|
|
rpm-build |
0fba15 |
if (opt_no_gpg_verify || opt_no_sign_verify)
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
"gpg-verify",
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_boolean (FALSE)));
|
|
rpm-build |
0fba15 |
#endif /* OSTREE_DISABLE_GPGME */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (opt_no_sign_verify)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (opt_sign_verify)
|
|
rpm-build |
0fba15 |
return glnx_throw (error, "Cannot specify both --sign-verify and --no-sign-verify");
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
"sign-verify",
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_boolean (FALSE)));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
for (char **iter = opt_sign_verify; iter && *iter; iter++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const char *keyspec = *iter;
|
|
rpm-build |
0fba15 |
g_autofree char *signname = add_verify_opt (optbuilder, keyspec, error);
|
|
rpm-build |
0fba15 |
if (!signname)
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (!sign_verify)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
sign_verify = g_string_new (signname);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_string_append_c (sign_verify, ',');
|
|
rpm-build |
0fba15 |
g_string_append (sign_verify, signname);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
if (sign_verify != NULL)
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}",
|
|
rpm-build |
0fba15 |
"sign-verify",
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_string (sign_verify->str)));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (opt_collection_id != NULL)
|
|
rpm-build |
0fba15 |
g_variant_builder_add (optbuilder, "{s@v}", "collection-id",
|
|
rpm-build |
0fba15 |
g_variant_new_variant (g_variant_new_take_string (g_steal_pointer (&opt_collection_id))));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
options = g_variant_ref_sink (g_variant_builder_end (optbuilder));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
OstreeRepoRemoteChange changeop;
|
|
rpm-build |
0fba15 |
if (opt_if_not_exists)
|
|
rpm-build |
0fba15 |
changeop = OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS;
|
|
rpm-build |
0fba15 |
else if (opt_force)
|
|
rpm-build |
0fba15 |
changeop = OSTREE_REPO_REMOTE_CHANGE_REPLACE;
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
changeop = OSTREE_REPO_REMOTE_CHANGE_ADD;
|
|
rpm-build |
0fba15 |
if (!ostree_repo_remote_change (repo, NULL, changeop,
|
|
rpm-build |
0fba15 |
remote_name, remote_url,
|
|
rpm-build |
0fba15 |
options,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#ifndef OSTREE_DISABLE_GPGME
|
|
rpm-build |
0fba15 |
/* This is just a convenience option and is not as flexible as the full
|
|
rpm-build |
0fba15 |
* "ostree remote gpg-import" command. It imports all keys from a file,
|
|
rpm-build |
0fba15 |
* which is likely the most common case.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* XXX Not sure this interacts well with if-not-exists since we don't
|
|
rpm-build |
0fba15 |
* know whether the remote already existed. We import regardless. */
|
|
rpm-build |
0fba15 |
if (opt_gpg_import != NULL)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GFile) file = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(GInputStream) input_stream = NULL;
|
|
rpm-build |
0fba15 |
guint imported = 0;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
file = g_file_new_for_path (opt_gpg_import);
|
|
rpm-build |
0fba15 |
input_stream = (GInputStream *) g_file_read (file, cancellable, error);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (input_stream == NULL)
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ostree_repo_remote_gpg_import (repo, remote_name, input_stream,
|
|
rpm-build |
0fba15 |
NULL, &imported, cancellable, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* XXX If we ever add internationalization, use ngettext() here. */
|
|
rpm-build |
0fba15 |
g_print ("Imported %u GPG key%s to remote \"%s\"\n",
|
|
rpm-build |
0fba15 |
imported, (imported == 1) ? "" : "s", remote_name);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
#endif /* OSTREE_DISABLE_GPGME */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
ret = TRUE;
|
|
rpm-build |
0fba15 |
out:
|
|
rpm-build |
0fba15 |
return ret;
|
|
rpm-build |
0fba15 |
}
|