2012-07-23 06:18:51 +00:00
|
|
|
/*
|
|
|
|
* virsh-secret.c: Commands to manage secret
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005, 2007-2012 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.1 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, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
|
|
|
* Karel Zak <kzak@redhat.com>
|
|
|
|
* Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-08-20 23:14:37 +00:00
|
|
|
#include <config.h>
|
|
|
|
#include "virsh-secret.h"
|
|
|
|
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
|
|
|
#include <libxml/xpath.h>
|
|
|
|
#include <libxml/xmlsave.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "base64.h"
|
|
|
|
#include "buf.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "xml.h"
|
|
|
|
|
2012-07-23 06:18:51 +00:00
|
|
|
static virSecretPtr
|
|
|
|
vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name)
|
|
|
|
{
|
|
|
|
virSecretPtr secret = NULL;
|
|
|
|
const char *n = NULL;
|
|
|
|
const char *optname = "secret";
|
|
|
|
|
2012-08-20 20:29:27 +00:00
|
|
|
if (!vshCmdHasOption(ctl, cmd, optname))
|
2012-07-23 06:18:51 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptString(cmd, optname, &n) <= 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"%s: found option <%s>: %s\n", cmd->def->name, optname, n);
|
|
|
|
|
|
|
|
if (name != NULL)
|
|
|
|
*name = n;
|
|
|
|
|
|
|
|
secret = virSecretLookupByUUIDString(ctl->conn, n);
|
|
|
|
|
|
|
|
if (secret == NULL)
|
|
|
|
vshError(ctl, _("failed to get secret '%s'"), n);
|
|
|
|
|
|
|
|
return secret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_define[] = {
|
|
|
|
{"help", N_("define or modify a secret from an XML file")},
|
|
|
|
{"desc", N_("Define or modify a secret.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_secret_define[] = {
|
|
|
|
{"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
|
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *from = NULL;
|
|
|
|
char *buffer;
|
|
|
|
virSecretPtr res;
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptString(cmd, "file", &from) <= 0)
|
|
|
|
return false;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
2012-07-23 06:18:51 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
res = virSecretDefineXML(ctl->conn, buffer, 0);
|
|
|
|
VIR_FREE(buffer);
|
|
|
|
|
|
|
|
if (res == NULL) {
|
|
|
|
vshError(ctl, _("Failed to set attributes from %s"), from);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to get UUID of created secret"));
|
|
|
|
virSecretFree(res);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, _("Secret %s created\n"), uuid);
|
|
|
|
virSecretFree(res);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_dumpxml[] = {
|
|
|
|
{"help", N_("secret attributes in XML")},
|
|
|
|
{"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_secret_dumpxml[] = {
|
|
|
|
{"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
|
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virSecretPtr secret;
|
|
|
|
bool ret = false;
|
|
|
|
char *xml;
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
secret = vshCommandOptSecret(ctl, cmd, NULL);
|
|
|
|
if (secret == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
xml = virSecretGetXMLDesc(secret, 0);
|
|
|
|
if (xml == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
vshPrint(ctl, "%s", xml);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virSecretFree(secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-set-value" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_set_value[] = {
|
|
|
|
{"help", N_("set a secret value")},
|
|
|
|
{"desc", N_("Set a secret value.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_secret_set_value[] = {
|
|
|
|
{"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
|
|
|
|
{"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
|
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virSecretPtr secret;
|
|
|
|
size_t value_size;
|
|
|
|
const char *base64 = NULL;
|
|
|
|
char *value;
|
|
|
|
int res;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
secret = vshCommandOptSecret(ctl, cmd, NULL);
|
|
|
|
if (secret == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptString(cmd, "base64", &base64) <= 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
|
|
|
|
vshError(ctl, "%s", _("Invalid base64 data"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (value == NULL) {
|
|
|
|
vshError(ctl, "%s", _("Failed to allocate memory"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
|
|
|
|
memset(value, 0, value_size);
|
|
|
|
VIR_FREE(value);
|
|
|
|
|
|
|
|
if (res != 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to set secret value"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, "%s", _("Secret value set\n"));
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virSecretFree(secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-get-value" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_get_value[] = {
|
|
|
|
{"help", N_("Output a secret value")},
|
|
|
|
{"desc", N_("Output a secret value to stdout.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_secret_get_value[] = {
|
|
|
|
{"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
|
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virSecretPtr secret;
|
|
|
|
char *base64;
|
|
|
|
unsigned char *value;
|
|
|
|
size_t value_size;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
secret = vshCommandOptSecret(ctl, cmd, NULL);
|
|
|
|
if (secret == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
value = virSecretGetValue(secret, &value_size, 0);
|
|
|
|
if (value == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
base64_encode_alloc((char *)value, value_size, &base64);
|
|
|
|
memset(value, 0, value_size);
|
|
|
|
VIR_FREE(value);
|
|
|
|
|
|
|
|
if (base64 == NULL) {
|
|
|
|
vshError(ctl, "%s", _("Failed to allocate memory"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, "%s", base64);
|
|
|
|
memset(base64, 0, strlen(base64));
|
|
|
|
VIR_FREE(base64);
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virSecretFree(secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-undefine" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_undefine[] = {
|
|
|
|
{"help", N_("undefine a secret")},
|
|
|
|
{"desc", N_("Undefine a secret.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_secret_undefine[] = {
|
|
|
|
{"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
|
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virSecretPtr secret;
|
|
|
|
bool ret = false;
|
|
|
|
const char *uuid;
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
secret = vshCommandOptSecret(ctl, cmd, &uuid);
|
|
|
|
if (secret == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virSecretUndefine(secret) < 0) {
|
|
|
|
vshError(ctl, _("Failed to delete secret %s"), uuid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, _("Secret %s deleted\n"), uuid);
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virSecretFree(secret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "secret-list" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_secret_list[] = {
|
|
|
|
{"help", N_("list secrets")},
|
|
|
|
{"desc", N_("Returns a list of secrets")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
int maxuuids = 0, i;
|
|
|
|
char **uuids = NULL;
|
|
|
|
|
|
|
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
maxuuids = virConnectNumOfSecrets(ctl->conn);
|
|
|
|
if (maxuuids < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to list secrets"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
|
|
|
|
|
|
|
|
maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
|
|
|
|
if (maxuuids < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to list secrets"));
|
|
|
|
VIR_FREE(uuids);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
qsort(uuids, maxuuids, sizeof(char *), vshNameSorter);
|
|
|
|
|
|
|
|
vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
|
|
|
|
vshPrintExtra(ctl, "-----------------------------------------------------------\n");
|
|
|
|
|
|
|
|
for (i = 0; i < maxuuids; i++) {
|
|
|
|
virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
|
|
|
|
const char *usageType = NULL;
|
|
|
|
|
|
|
|
if (!sec) {
|
|
|
|
VIR_FREE(uuids[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (virSecretGetUsageType(sec)) {
|
|
|
|
case VIR_SECRET_USAGE_TYPE_VOLUME:
|
|
|
|
usageType = _("Volume");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (usageType) {
|
|
|
|
vshPrint(ctl, "%-36s %s %s\n",
|
|
|
|
uuids[i], usageType,
|
|
|
|
virSecretGetUsageID(sec));
|
|
|
|
} else {
|
|
|
|
vshPrint(ctl, "%-36s %s\n",
|
|
|
|
uuids[i], _("Unused"));
|
|
|
|
}
|
|
|
|
virSecretFree(sec);
|
|
|
|
VIR_FREE(uuids[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(uuids);
|
|
|
|
return true;
|
|
|
|
}
|
2012-07-23 07:19:04 +00:00
|
|
|
|
2012-08-20 23:14:37 +00:00
|
|
|
const vshCmdDef secretCmds[] = {
|
2012-07-23 07:19:04 +00:00
|
|
|
{"secret-define", cmdSecretDefine, opts_secret_define,
|
|
|
|
info_secret_define, 0},
|
|
|
|
{"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml,
|
|
|
|
info_secret_dumpxml, 0},
|
|
|
|
{"secret-get-value", cmdSecretGetValue, opts_secret_get_value,
|
|
|
|
info_secret_get_value, 0},
|
|
|
|
{"secret-list", cmdSecretList, NULL, info_secret_list, 0},
|
|
|
|
{"secret-set-value", cmdSecretSetValue, opts_secret_set_value,
|
|
|
|
info_secret_set_value, 0},
|
|
|
|
{"secret-undefine", cmdSecretUndefine, opts_secret_undefine,
|
|
|
|
info_secret_undefine, 0},
|
|
|
|
{NULL, NULL, NULL, NULL, 0}
|
|
|
|
};
|