Blame src/ostree/ot-remote-builtin-add.c

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
}