/* * 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} };