[PATCH 3/6] virsh: Expose OpenSSH authorized key file mgmt APIs

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

 



The new virsh commands are:

  get-user-sshkeys
  set-user-sshkeys

Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx>
---
 docs/manpages/virsh.rst |  37 ++++++++++
 tools/virsh-domain.c    | 152 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index bfd26e3120..30b234aeab 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -2636,6 +2636,21 @@ When *--timestamp* is used, a human-readable timestamp will be printed
 before the event.
 
 
+get-user-sshkeys
+----------------
+
+**Syntax:**
+
+::
+
+   get-user-sshkeys domain user
+
+Print SSH authorized keys for given *user* in the guest *domain*. Please note,
+that an entry in the file has internal structure as defined by *sshd(8)* and
+virsh/libvirt does handle keys as opaque strings, i.e. does not interpret
+them.
+
+
 guest-agent-timeout
 -------------------
 
@@ -4004,6 +4019,28 @@ For QEMU/KVM, this requires the guest agent to be configured
 and running.
 
 
+set-user-sshkeys
+----------------
+
+**Syntax:**
+
+::
+
+   set-user-sshkeys domain user [{--append | --remove}] [--keys keys]
+
+Replace the contents of *user*'s SSH authorized file in the guest *domain* with
+*keys*. Please note, that an entry in the file has internal structure as
+defined by *sshd(8)* and virsh/libvirt does handle keys as opaque strings,
+i.e. does not interpret them.
+
+If *--append* is specified, then the file content is not replaced and new keys
+are just appended.
+
+If *--remove* is specified, then instead of adding any new keys these are
+removed from the file. It is not considered an error if the key does not exist
+in the file.
+
+
 setmaxmem
 ---------
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 1ae936c6b2..f51765cb42 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14259,6 +14259,146 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
     return ret;
 }
 
+/*
+ * "get-user-sshkeys" command
+ */
+static const vshCmdInfo info_get_user_sshkeys[] = {
+    {.name = "help",
+     .data = N_("list authorized SSH keys for given user (via agent)")
+    },
+    {.name = "desc",
+     .data = N_("Use the guest agent to query authorized SSH keys for given "
+                "user")
+    },
+    {.name = NULL}
+};
+
+static const vshCmdOptDef opts_get_user_sshkeys[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
+    {.name = "user",
+     .type = VSH_OT_DATA,
+     .flags = VSH_OFLAG_REQ,
+     .help = N_("user to list authorized keys for"),
+    },
+    {.name = NULL}
+};
+
+static bool
+cmdGetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
+{
+    virDomainPtr dom = NULL;
+    const char *user;
+    char **keys = NULL;
+    int nkeys = 0;
+    size_t i;
+    const unsigned int flags = 0;
+    vshTablePtr table = NULL;
+    bool ret = false;
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        return false;
+
+    if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0)
+        goto cleanup;
+
+    nkeys = virDomainAuthorizedSSHKeysGet(dom, user, &keys, flags);
+    if (nkeys < 0)
+        goto cleanup;
+
+    if (!(table = vshTableNew(_("key"), NULL)))
+        goto cleanup;
+
+    for (i = 0; i < nkeys; i++) {
+        if (vshTableRowAppend(table, keys[i], NULL) < 0)
+            goto cleanup;
+    }
+
+    vshTablePrintToStdout(table, ctl);
+
+    ret = true;
+ cleanup:
+    vshTableFree(table);
+    if (nkeys > 0)
+        virStringListFreeCount(keys, nkeys);
+    virshDomainFree(dom);
+    return ret;
+}
+
+
+/*
+ * "set-user-sshkeys" command
+ */
+static const vshCmdInfo info_set_user_sshkeys[] = {
+    {.name = "help",
+     .data = N_("manipulate authorized SSH keys file for given user (via agent)")
+    },
+    {.name = "desc",
+     .data = N_("Append, reset or remove specified key from the authorized "
+                "keys file for given user")
+    },
+    {.name = NULL}
+};
+
+static const vshCmdOptDef opts_set_user_sshkeys[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
+    {.name = "user",
+     .type = VSH_OT_DATA,
+     .flags = VSH_OFLAG_REQ,
+     .help = N_("user to list authorized keys for"),
+    },
+    {.name = "append",
+     .type = VSH_OT_BOOL,
+     .help = N_("append keys to the file"),
+    },
+    {.name = "remove",
+     .type = VSH_OT_BOOL,
+     .help = N_("remove keys from the file"),
+    },
+    {.name = "keys",
+     .type = VSH_OT_ARGV,
+     .help = N_("OpenSSH keys"),
+    },
+    {.name = NULL}
+};
+
+static bool
+cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
+{
+    virDomainPtr dom = NULL;
+    const char *user;
+    const vshCmdOpt *opt = NULL;
+    g_autofree const char **keys = NULL;
+    int nkeys = 0;
+    unsigned int flags = 0;
+    bool ret = false;
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        return false;
+
+    if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0)
+        goto cleanup;
+
+    if (vshCommandOptBool(cmd, "append"))
+        flags |= VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND;
+    if (vshCommandOptBool(cmd, "remove"))
+        flags |= VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE;
+
+    while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
+        keys = g_renew(const char *, keys, nkeys + 1);
+        keys[nkeys] = opt->data;
+        nkeys++;
+    }
+
+    if (virDomainAuthorizedSSHKeysSet(dom, user, keys, nkeys, flags) < 0)
+        goto cleanup;
+
+    ret = true;
+ cleanup:
+    virshDomainFree(dom);
+    return ret;
+}
+
+
 const vshCmdDef domManagementCmds[] = {
     {.name = "attach-device",
      .handler = cmdAttachDevice,
@@ -14526,6 +14666,12 @@ const vshCmdDef domManagementCmds[] = {
      .info = info_event,
      .flags = 0
     },
+    {.name = "get-user-sshkeys",
+     .handler = cmdGetUserSSHKeys,
+     .opts = opts_get_user_sshkeys,
+     .info = info_get_user_sshkeys,
+     .flags = 0
+    },
     {.name = "inject-nmi",
      .handler = cmdInjectNMI,
      .opts = opts_inject_nmi,
@@ -14772,6 +14918,12 @@ const vshCmdDef domManagementCmds[] = {
      .info = info_setLifecycleAction,
      .flags = 0
     },
+    {.name = "set-user-sshkeys",
+     .handler = cmdSetUserSSHKeys,
+     .opts = opts_set_user_sshkeys,
+     .info = info_set_user_sshkeys,
+     .flags = 0
+    },
     {.name = "set-user-password",
      .handler = cmdSetUserPassword,
      .opts = opts_set_user_password,
-- 
2.26.2




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux