/*
* 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
* .
*
* Daniel Veillard
* Karel Zak
* Daniel P. Berrange
*
*/
#include
#include "virsh-secret.h"
#include
#include
#include
#include
#include "internal.h"
#include "base64.h"
#include "buf.h"
#include "memory.h"
#include "util.h"
#include "xml.h"
static virSecretPtr
vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name)
{
virSecretPtr secret = NULL;
const char *n = NULL;
const char *optname = "secret";
if (!vshCmdHasOption(ctl, cmd, optname))
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 (vshCommandOptString(cmd, "file", &from) <= 0)
return false;
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
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;
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;
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;
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;
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;
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;
}
const vshCmdDef secretCmds[] = {
{"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}
};