Provide missing passphrase when creating a volume.

If the <encryption format='qcow'> element does not specify a secret
during volume creation, generate a suitable secret and add it to the
<encryption> tag.  The caller can view the updated <encryption> tag
using virStorageVolGetXMLDesc().

Similarly, when <encryption format='default'/> is specified while
creating a qcow or qcow2-formatted volume, change the format to "qcow"
and generate a secret as described above.

* src/storage_encryption_conf.h (VIR_STORAGE_QCOW_PASSPHRASE_SIZE,
  virStorageGenerateQcowPasphrase),
  src/storage_encryption_conf.c (virStorageGenerateQcowPasphrase),
  src/libvirt_private.syms: Add virStorageGenerateQcowPasphrase().
* src/storage_backend.c (virStoragegenerateQcowEncryption,
  virStorageBackendCreateQemuImg): Generate a passphrase and
  <encryption> when creating a qcow-formatted encrypted volume and the
  user did not supply the information.
This commit is contained in:
Miloslav Trmač 2009-08-14 20:06:59 +02:00 committed by Daniel P. Berrange
parent 2db2c5a186
commit cd6a9334b6
4 changed files with 155 additions and 3 deletions

View File

@ -371,6 +371,7 @@ virStorageEncryptionFree;
virStorageEncryptionDropSecrets;
virStorageEncryptionParseNode;
virStorageEncryptionFormat;
virStorageGenerateQcowPassphrase;
# threads.h

View File

@ -43,11 +43,13 @@
#include <selinux/selinux.h>
#endif
#include "datatypes.h"
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
#include "node_device.h"
#include "internal.h"
#include "secret_conf.h"
#include "storage_backend.h"
@ -335,6 +337,103 @@ cleanup:
return ret;
}
static int
virStorageGenerateQcowEncryption(virConnectPtr conn,
virStorageVolDefPtr vol)
{
virSecretDefPtr def = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virStorageEncryptionPtr enc;
virStorageEncryptionSecretPtr enc_secret = NULL;
virSecretPtr secret = NULL;
char *uuid = NULL, *xml;
unsigned char value[VIR_STORAGE_QCOW_PASSPHRASE_SIZE];
int ret = -1;
if (conn->secretDriver == NULL || conn->secretDriver->defineXML == NULL ||
conn->secretDriver->setValue == NULL) {
virStorageReportError(conn, VIR_ERR_NO_SUPPORT, "%s",
_("secret storage not supported"));
goto cleanup;
}
enc = vol->target.encryption;
if (enc->nsecrets != 0) {
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
_("secrets already defined"));
goto cleanup;
}
if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0 ||
VIR_ALLOC(def) < 0) {
virReportOOMError(conn);
goto cleanup;
}
def->ephemeral = 0;
def->private = 0;
def->id = NULL; /* Chosen by the secret driver */
if (virAsprintf(&def->description, "qcow passphrase for %s",
vol->target.path) == -1) {
virReportOOMError(conn);
goto cleanup;
}
def->usage_type = VIR_SECRET_USAGE_TYPE_VOLUME;
def->usage.volume = strdup(vol->target.path);
if (def->usage.volume == NULL) {
virReportOOMError(conn);
goto cleanup;
}
xml = virSecretDefFormat(conn, def);
virSecretDefFree(def);
def = NULL;
if (xml == NULL)
goto cleanup;
secret = conn->secretDriver->defineXML(conn, xml, 0);
if (secret == NULL) {
VIR_FREE(xml);
goto cleanup;
}
VIR_FREE(xml);
uuid = strdup(secret->uuid);
if (uuid == NULL) {
virReportOOMError(conn);
goto cleanup;
}
if (virStorageGenerateQcowPassphrase(conn, value) < 0)
goto cleanup;
if (conn->secretDriver->setValue(secret, value, sizeof(value), 0) < 0)
goto cleanup;
secret = NULL;
enc_secret->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
enc_secret->uuid = uuid;
uuid = NULL;
enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
enc->secrets[0] = enc_secret; /* Space for secrets[0] allocated above */
enc_secret = NULL;
enc->nsecrets = 1;
ret = 0;
cleanup:
VIR_FREE(uuid);
if (secret != NULL) {
if (conn->secretDriver->undefine != NULL)
conn->secretDriver->undefine(secret);
virSecretFree(secret);
}
xml = virBufferContentAndReset(&buf);
VIR_FREE(xml);
virSecretDefFree(def);
VIR_FREE(enc_secret);
return ret;
}
static int
virStorageBackendCreateQemuImg(virConnectPtr conn,
virStorageVolDefPtr vol,
@ -433,6 +532,8 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
}
if (vol->target.encryption != NULL) {
virStorageEncryptionPtr enc;
if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW &&
vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
@ -440,18 +541,24 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
"volume format %s"), type);
return -1;
}
if (vol->target.encryption->format !=
VIR_STORAGE_ENCRYPTION_FORMAT_QCOW) {
enc = vol->target.encryption;
if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) {
virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
_("unsupported volume encryption format %d"),
vol->target.encryption->format);
return -1;
}
if (vol->target.encryption->nsecrets > 1) {
if (enc->nsecrets > 1) {
virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
_("too many secrets for qcow encryption"));
return -1;
}
if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT ||
enc->nsecrets == 0) {
if (virStorageGenerateQcowEncryption(conn, vol) < 0)
return -1;
}
}
if ((create_tool = virFindFileInPath("kvm-img")) != NULL)

View File

@ -22,6 +22,9 @@
#include <config.h>
#include <fcntl.h>
#include <unistd.h>
#include "internal.h"
#include "buf.h"
@ -242,3 +245,37 @@ virStorageEncryptionFormat(virConnectPtr conn,
return 0;
}
int
virStorageGenerateQcowPassphrase(virConnectPtr conn, unsigned char *dest)
{
int fd;
size_t i;
/* A qcow passphrase is up to 16 bytes, with any data following a NUL
ignored. Prohibit control and non-ASCII characters to avoid possible
unpleasant surprises with the qemu monitor input mechanism. */
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot open /dev/urandom"));
return -1;
}
i = 0;
while (i < VIR_STORAGE_QCOW_PASSPHRASE_SIZE) {
ssize_t r;
while ((r = read(fd, dest + i, 1)) == -1 && errno == EINTR)
;
if (r <= 0) {
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot read from /dev/urandom"));
close(fd);
return -1;
}
if (dest[i] >= 0x20 && dest[i] <= 0x7E)
i++; /* Got an acceptable character */
}
close(fd);
return 0;
}

View File

@ -69,4 +69,11 @@ virStorageEncryptionPtr virStorageEncryptionParseNode(virConnectPtr conn,
int virStorageEncryptionFormat(virConnectPtr conn, virBufferPtr buf,
virStorageEncryptionPtr enc);
/* A helper for VIR_STORAGE_ENCRYPTION_FORMAT_QCOW */
enum {
VIR_STORAGE_QCOW_PASSPHRASE_SIZE = 16
};
int virStorageGenerateQcowPassphrase(virConnectPtr conn, unsigned char *dest);
#endif /* __VIR_STORAGE_ENCRYPTION_H__ */