Add the data structure and infrastructure to support an initialization
vector (IV) secret. The IV secret generation will need to have access
to the domain private master key, so let's make sure the prepare disk
and hostdev functions can accept that now.
Anywhere that needs to make a decision over which secret type to use
in order to fill in or use the IV secret has a switch added. In particular,
when building the command line for the network URI, create a couple of
helper functions which make the decision to add the secret info.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/qemu/qemu_command.c | 106 ++++++++++++++++++++++++++++++++++++++----------
src/qemu/qemu_domain.c | 34 ++++++++++++++--
src/qemu/qemu_domain.h | 22 ++++++++--
src/qemu/qemu_hotplug.c | 6 +--
4 files changed, 138 insertions(+), 30 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8629c15..a8cacb3 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -606,6 +606,85 @@ qemuNetworkDriveGetPort(int protocol,
return -1;
}
+
+/* qemuBuildGeneralSecinfoURI:
+ * @uri: Pointer to the URI structure to add to
+ * @secinfo: Pointer to the secret info data (if present)
+ *
+ * If we have a secinfo, then build the command line options for
+ * the secret info for the "general" case (somewhat a misnomer since
+ * an iscsi disk is the only one with a secinfo).
+ *
+ * Returns 0 on success or if no secinfo,
+ * -1 and error message if fail to add secret information
+ */
+static int
+qemuBuildGeneralSecinfoURI(virURIPtr uri,
+ qemuDomainSecretInfoPtr secinfo)
+{
+ if (!secinfo)
+ return 0;
+
+ switch ((qemuDomainSecretInfoType) secinfo->type) {
+ case VIR_DOMAIN_SECRET_INFO_PLAIN:
+ if (secinfo->s.plain.secret) {
+ if (virAsprintf(&uri->user, "%s:%s",
+ secinfo->s.plain.username,
+ secinfo->s.plain.secret) < 0)
+ return -1;
+ } else {
+ if (VIR_STRDUP(uri->user, secinfo->s.plain.username) < 0)
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_SECRET_INFO_IV:
+ case VIR_DOMAIN_SECRET_INFO_LAST:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* qemuBuildRBDSecinfoURI:
+ * @uri: Pointer to the URI structure to add to
+ * @secinfo: Pointer to the secret info data (if present)
+ *
+ * If we have a secinfo, then build the command line options for
+ * the secret info for the RBD network storage. Assumption for this
+ * is both username and secret exist for plaintext
+ *
+ * Returns 0 on success or if no secinfo,
+ * -1 and error message if fail to add secret information
+ */
+static int
+qemuBuildRBDSecinfoURI(virBufferPtr buf,
+ qemuDomainSecretInfoPtr secinfo)
+{
+ if (!secinfo) {
+ virBufferAddLit(buf, ":auth_supported=none");
+ return 0;
+ }
+
+ switch ((qemuDomainSecretInfoType) secinfo->type) {
+ case VIR_DOMAIN_SECRET_INFO_PLAIN:
+ virBufferEscape(buf, '\\', ":", ":id=%s",
+ secinfo->s.plain.username);
+ virBufferEscape(buf, '\\', ":",
+ ":key=%s:auth_supported=cephx\\;none",
+ secinfo->s.plain.secret);
+ break;
+
+ case VIR_DOMAIN_SECRET_INFO_IV:
+ case VIR_DOMAIN_SECRET_INFO_LAST:
+ return -1;
+ }
+
+ return 0;
+}
+
+
#define QEMU_DEFAULT_NBD_PORT "10809"
static char *
@@ -701,7 +780,8 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
goto cleanup;
}
- if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
+ if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
+ src->hosts->port)) < 0)
goto cleanup;
if (src->path) {
@@ -721,17 +801,8 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
goto cleanup;
- if (secinfo) {
- if (secinfo->s.plain.secret) {
- if (virAsprintf(&uri->user, "%s:%s",
- secinfo->s.plain.username,
- secinfo->s.plain.secret) < 0)
- goto cleanup;
- } else {
- if (VIR_STRDUP(uri->user, secinfo->s.plain.username) < 0)
- goto cleanup;
- }
- }
+ if (qemuBuildGeneralSecinfoURI(uri, secinfo) < 0)
+ goto cleanup;
if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
goto cleanup;
@@ -777,15 +848,8 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
if (src->snapshot)
virBufferEscape(&buf, '\\', ":", "@%s",
src->snapshot);
- if (secinfo) {
- virBufferEscape(&buf, '\\', ":",
":id=%s",
- secinfo->s.plain.username);
- virBufferEscape(&buf, '\\', ":",
- ":key=%s:auth_supported=cephx\\;none",
- secinfo->s.plain.secret);
- } else {
- virBufferAddLit(&buf, ":auth_supported=none");
- }
+ if (qemuBuildRBDSecinfoURI(&buf, secinfo) < 0)
+ goto cleanup;
if (src->nhosts > 0) {
virBufferAddLit(&buf, ":mon_host=");
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 03fdab1..17577ef 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -740,12 +740,34 @@ qemuDomainSecretPlainFree(qemuDomainSecretPlain secret)
static void
+qemuDomainSecretIVFree(qemuDomainSecretIV secret)
+{
+ VIR_FREE(secret.username);
+ VIR_FREE(secret.alias);
+ VIR_FREE(secret.iv);
+ VIR_FREE(secret.ciphertext);
+}
+
+
+static void
qemuDomainSecretInfoFree(qemuDomainSecretInfoPtr *secinfo)
{
if (!*secinfo)
return;
- qemuDomainSecretPlainFree((*secinfo)->s.plain);
+ switch ((qemuDomainSecretInfoType) (*secinfo)->type) {
+ case VIR_DOMAIN_SECRET_INFO_PLAIN:
+ qemuDomainSecretPlainFree((*secinfo)->s.plain);
+ break;
+
+ case VIR_DOMAIN_SECRET_INFO_IV:
+ qemuDomainSecretIVFree((*secinfo)->s.iv);
+ break;
+
+ case VIR_DOMAIN_SECRET_INFO_LAST:
+ break;
+ }
+
VIR_FREE(*secinfo);
}
@@ -893,6 +915,7 @@ qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk)
/* qemuDomainSecretDiskPrepare:
* @conn: Pointer to connection
+ * @priv: pointer to domain private object
* @disk: Pointer to a disk definition
*
* For the right disk, generate the qemuDomainSecretInfo structure.
@@ -901,6 +924,7 @@ qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk)
*/
int
qemuDomainSecretDiskPrepare(virConnectPtr conn,
+ qemuDomainObjPrivatePtr priv ATTRIBUTE_UNUSED,
virDomainDiskDefPtr disk)
{
virStorageSourcePtr src = disk->src;
@@ -952,6 +976,7 @@ qemuDomainSecretHostdevDestroy(virDomainHostdevDefPtr hostdev)
/* qemuDomainSecretHostdevPrepare:
* @conn: Pointer to connection
+ * @priv: pointer to domain private object
* @hostdev: Pointer to a hostdev definition
*
* For the right host device, generate the qemuDomainSecretInfo structure.
@@ -960,6 +985,7 @@ qemuDomainSecretHostdevDestroy(virDomainHostdevDefPtr hostdev)
*/
int
qemuDomainSecretHostdevPrepare(virConnectPtr conn,
+ qemuDomainObjPrivatePtr priv ATTRIBUTE_UNUSED,
virDomainHostdevDefPtr hostdev)
{
virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
@@ -1032,15 +1058,17 @@ int
qemuDomainSecretPrepare(virConnectPtr conn,
virDomainObjPtr vm)
{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
size_t i;
for (i = 0; i < vm->def->ndisks; i++) {
- if (qemuDomainSecretDiskPrepare(conn, vm->def->disks[i]) < 0)
+ if (qemuDomainSecretDiskPrepare(conn, priv, vm->def->disks[i]) < 0)
return -1;
}
for (i = 0; i < vm->def->nhostdevs; i++) {
- if (qemuDomainSecretHostdevPrepare(conn, vm->def->hostdevs[i]) < 0)
+ if (qemuDomainSecretHostdevPrepare(conn, priv,
+ vm->def->hostdevs[i]) < 0)
return -1;
}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 63f98ba..9b5f108 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -242,6 +242,7 @@ struct _qemuDomainObjPrivate {
/* Type of domain secret */
typedef enum {
VIR_DOMAIN_SECRET_INFO_PLAIN = 0,
+ VIR_DOMAIN_SECRET_INFO_IV = 1,
VIR_DOMAIN_SECRET_INFO_LAST
} qemuDomainSecretInfoType;
@@ -253,12 +254,24 @@ struct _qemuDomainSecretPlain {
char *secret;
};
+# define QEMU_DOMAIN_IV_KEY_LEN 16 /* 16 bytes for 128 bit random */
+ /* initialization vector key */
+typedef struct _qemuDomainSecretIV qemuDomainSecretIV;
+typedef struct _qemuDomainSecretIV *qemuDomainSecretIVPtr;
+struct _qemuDomainSecretIV {
+ char *username;
+ char *alias; /* generated alias for secret */
+ char *iv; /* base64 encoded initialization vector */
+ char *ciphertext; /* encoded/encrypted secret */
+};
+
typedef struct _qemuDomainSecretInfo qemuDomainSecretInfo;
typedef qemuDomainSecretInfo *qemuDomainSecretInfoPtr;
struct _qemuDomainSecretInfo {
int type; /* qemuDomainSecretInfoType */
union {
qemuDomainSecretPlain plain;
+ qemuDomainSecretIV iv;
} s;
};
@@ -631,15 +644,18 @@ void qemuDomainMasterKeyRemove(qemuDomainObjPrivatePtr priv);
void qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk)
ATTRIBUTE_NONNULL(1);
-int qemuDomainSecretDiskPrepare(virConnectPtr conn, virDomainDiskDefPtr disk)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuDomainSecretDiskPrepare(virConnectPtr conn,
+ qemuDomainObjPrivatePtr priv,
+ virDomainDiskDefPtr disk)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
void qemuDomainSecretHostdevDestroy(virDomainHostdevDefPtr disk)
ATTRIBUTE_NONNULL(1);
int qemuDomainSecretHostdevPrepare(virConnectPtr conn,
+ qemuDomainObjPrivatePtr priv,
virDomainHostdevDefPtr hostdev)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
void qemuDomainSecretDestroy(virDomainObjPtr vm)
ATTRIBUTE_NONNULL(1);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index c05f88c..a3989e9 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -354,7 +354,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
goto error;
- if (qemuDomainSecretDiskPrepare(conn, disk) < 0)
+ if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
goto error;
if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
@@ -581,7 +581,7 @@ qemuDomainAttachSCSIDisk(virConnectPtr conn,
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
goto error;
- if (qemuDomainSecretDiskPrepare(conn, disk) < 0)
+ if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
goto error;
if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
@@ -1976,7 +1976,7 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1)
< 0)
goto cleanup;
- if (qemuDomainSecretHostdevPrepare(conn, hostdev) < 0)
+ if (qemuDomainSecretHostdevPrepare(conn, priv, hostdev) < 0)
goto cleanup;
if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev, priv->qemuCaps)))
--
2.5.5