The new virsh commands are:
get-user-sshkeys
set-user-sshkeys
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
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