https://bugzilla.redhat.com/show_bug.cgi?id=1182074
If they're available and we need to pass secrets to qemu, then use the
qemu domain secret object in order to pass the secrets for iSCSI and
RBD volumes instead of passing plaintext or base64 encoded secrets on
the command line.
New APIs:
qemuDomainGetIVKeyAlias:
Generate/return the secret object alias for an initialization
vector (IV) secret info type. This will be saved in the secret
info block.
qemuDomainSecretInfoGetAlias:
Return a pointer to the alias to the specific secret info as
long as the secret object is supported (future patches may add
a new secret info type with a different pointer to return).
qemuDomainSecretHaveEncrypt:
Boolean function to determine whether the underly encryption
API is available. This function will utilize a similar mechanism
as the 'gnutls_rnd' did in configure.ac. This function creates
the encrypted secret based upon the domain master key, an
initialization vector (16 byte random value), and the stored secret.
qemuDomainSecretIVSetup: (private)
This API handles the details of the generation of the IV secret
and saves the pieces that need to be passed to qemu in order for
the secret to be decrypted. The requirement from qemu is the IV
and encrypted secret are to be base64 encoded. They can be passed
either directly or within a file. This implementation chooses
to pass directly rather than a file (file passing is shown below).
qemuBuildiSCSICommandLine: (private)
qemuBuildDiskiSCSICommandLine
qemuBuildHostdeviSCSICommandLine
These API's will handle adding the IV secret onto an '-iscsi'
command line option.
qemuBuildSecretInfoProps: (private)
Generate/return a JSON properties object for the IV secret to
be used by both the command building and eventually the hotplug
code in order to add the secret object.
Changes for qemuDomainSecret{Disk|Hostdev}Prepare:
If both the encryption API exists and the secret object exist, then
setup the IV secret (qemuDomainSecretIVSetup) as the default means
for the disk/hostdev to provide the secret to qemu. Prior to command
line generation and during hotplug, these prepare API's are called
allowing for code after the API to perform the right steps.
Command Building:
Adjust the qemuBuild{General|RBD}SecinfoURI API's in order to generate
the specific command options for an IV secret, such as:
For iSCSI:
-object secret,id=sec0,keyid=$masterKey,filename=/path/to/example.pw
or
-object secret,id=sec0,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-iscsi -initiator-name=$iqn,user=user,password-secret=sec0
-drive
file=iscsi://example.com/$iqn/1,...
For RBD:
-object secret,id=secret0,keyid=$masterKey,file=/path/to/poolkey.b64,
format=base64
or
-object secret,id=secret0,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-drive file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
mon_host=mon1.example.org\:6321,password-secret=secret0,...
where for both 'id=' value is the secret object alias, the 'keyid=
$masterKey' is the master key shared with qemu, and the -drive
syntax will reference that alias as the 'password-secret'. For
the iSCSI object 'user=' replaces the URI generated 'user:secret@'
prepended to the iSCSI 'host' name (
example.com). For the RBD -drive
syntax, the 'id=myname' is kept to define the username, while the
'key=$base64 encoded secret' is removed.
While according to the syntax described for qemu commits 'b189346eb'
(iSCSI) and '60390a21' (RBD) or as seen in the email archive:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg04083.html
it is possible to pass a plaintext password via a file, the qemu
commit 'ac1d8878' describes the more feature rich 'keyid=' option
based upon the shared masterKey.
Tests:
Add mock's for virRandomBytes and gnutls_rnd in order to return a
constant stream of '0xff' in the bytes for a non random key in order
to generate "constant" values for the secrets so that the tests can
use those results to compare results.
Hotplug:
Since the hotplug code doesn't add command line arguments, passing
the encoded/plaintext secrets directly to the monitor will suffice.
Besides, it's passing the IV secret via '-iscsi' won't be possible.
Perhaps when the -drive command is modified to accept not only the
initiator-name, but -user and -password-secret arguments, then the
IV code can be utilized for hotplug secrets.
The goal is to make this the default and have no user interaction
required in order to allow using the IV mechanism. If the mechanism
is not available, then fall back to the current mechanism.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
configure.ac | 1 +
src/qemu/qemu_alias.c | 23 ++
src/qemu/qemu_alias.h | 2 +
src/qemu/qemu_command.c | 257 ++++++++++++++++++++-
src/qemu/qemu_domain.c | 207 ++++++++++++++++-
src/qemu/qemu_domain.h | 3 +
...uxml2argv-disk-drive-network-iscsi-auth-IV.args | 39 ++++
...muxml2argv-disk-drive-network-iscsi-auth-IV.xml | 43 ++++
...emuxml2argv-disk-drive-network-rbd-auth-IV.args | 31 +++
...qemuxml2argv-disk-drive-network-rbd-auth-IV.xml | 42 ++++
...emuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.args | 41 ++++
...qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.xml | 48 ++++
...xml2argv-hostdev-scsi-virtio-iscsi-auth-IV.args | 43 ++++
...uxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.xml | 48 ++++
tests/qemuxml2argvmock.c | 31 ++-
tests/qemuxml2argvtest.c | 19 ++
16 files changed, 865 insertions(+), 13 deletions(-)
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.args
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.xml
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.args
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.xml
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.args
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.xml
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.args
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.xml
diff --git a/configure.ac b/configure.ac
index 450f02c..f9c66e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1305,6 +1305,7 @@ if test "x$with_gnutls" != "xno"; then
]])
AC_CHECK_FUNCS([gnutls_rnd])
+ AC_CHECK_FUNCS([gnutls_cipher_encrypt])
CFLAGS="$old_CFLAGS"
LIBS="$old_LIBS"
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index ade2033..de9a74f 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -556,3 +556,26 @@ qemuDomainGetMasterKeyAlias(void)
return alias;
}
+
+
+/* qemuDomainGetIVKeyAlias:
+ *
+ * Generate and return an initialization vector alias
+ *
+ * Returns NULL or a string containing the IV key alias
+ */
+char *
+qemuDomainGetIVKeyAlias(const char *srcalias)
+{
+ char *alias;
+
+ if (!srcalias) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("secret iv alias requires valid source alias"));
+ return NULL;
+ }
+
+ ignore_value(virAsprintf(&alias, "%s-ivKey0", srcalias));
+
+ return alias;
+}
diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h
index 2d7bc9b..435747e 100644
--- a/src/qemu/qemu_alias.h
+++ b/src/qemu/qemu_alias.h
@@ -69,4 +69,6 @@ char *qemuAliasFromDisk(const virDomainDiskDef *disk);
char *qemuDomainGetMasterKeyAlias(void);
+char *qemuDomainGetIVKeyAlias(const char *srcalias);
+
#endif /* __QEMU_ALIAS_H__*/
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a8cacb3..db851ed 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -607,9 +607,131 @@ qemuNetworkDriveGetPort(int protocol,
}
+/* qemuBuildiSCSICommandLine:
+ * @cmd: Pointer to the command string
+ * @src: Pointer to a possible disk source
+ * @secinfo: Pointer to a possible secinfo
+ *
+ * Add an "-iscsi" argument for the command line. This provides the
+ * capability to add just an "iqn." string to the command line in order
+ * to override the default IQN (iqn.2008-11.org.linux-kvm) for qemu.
+ * Additionally, this will be the mechanism used to pass the IV secret
+ * to qemu since (currently - as of 2.6), the "user=" and
"password-secret="
+ * arguments are only handled with the "-iscsi" argument.
+ *
+ * RFC 3720 indicates that the IQN is made up of at least one part - a
+ * string starting with "iqn." which describes the naming authority. The
+ * standard references an optional field after a colon (:) is naming
+ * authority specific. For libvirt XML, an iSCSI name string typically
+ * has both the "iqn." and the colon along with a '/#' field denoting
the
+ * iSCSI LUN to use, e.g.:
+ *
+ * iqn.2016-04.com.example:storage/1
+ *
+ * We can pass this entire iqn string in the "initiator-name=" option
+ * of the "-iscsi" switch. As it turns out the "id=" option is not
+ * required, so no need to break our string. Although it would be
+ * possible to split at the colon, passing the "iqn." as just the
+ * "initiator-name=" option and adjusting the "storage/1" to
"storage_1"
+ * and passing in the "id=" option. This second option has limitations
+ * since the "id=" value must be letters, digits, '-', '.', and
"_"
+ * starting with a letter.
+ *
+ * Returns 0 on success or if not necessary, -1 on some sort of failure
+ */
+static int
+qemuBuildiSCSICommandLine(virCommandPtr cmd,
+ const char *path,
+ qemuDomainSecretInfoPtr secinfo)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ char *bufstr;
+
+ virBufferAsprintf(&opt, "initiator-name=%s", path);
+
+ /* If we have a secinfo, then append on the user/password-secret as
+ * this will be something for an iSCSI disk using IV secrets */
+ if (secinfo) {
+ virBufferAsprintf(&opt, ",user=%s,password-secret=%s",
+ secinfo->s.iv.username,
+ secinfo->s.iv.alias);
+ }
+
+ if (virBufferCheckError(&opt) < 0) {
+ virBufferFreeAndReset(&opt);
+ return -1;
+ }
+
+ bufstr = virBufferContentAndReset(&opt);
+ virCommandAddArg(cmd, "-iscsi");
+ virCommandAddArg(cmd, bufstr);
+ VIR_FREE(bufstr);
+
+ return 0;
+}
+
+
+/* qemuBuildDiskiSCSICommandLine:
+ * @cmd: Pointer to the command string
+ * @src: Pointer to a possible disk source
+ * @secinfo: Pointer to a possible secinfo
+ *
+ * Adding an IV secret to the command line for an iSCSI disk is a multistep
+ * and complicated endeavor. It is not possible to simply append "user=name,
+ * password-secret=alias-id" to a "-drive file=iscsi://..." command.
Instead,
+ * one must first add an -iscsi option with the IQN data in order to utilize
+ * the "user" and "password-secret" options.
+ *
+ * This function will check the storage source to see if it requires
+ * an '-iscsi' argument and make the call to do.
+ *
+ * Returns 0 on success, -1 w/ error on some sort of failure.
+ */
+static int
+qemuBuildDiskiSCSICommandLine(virCommandPtr cmd,
+ virStorageSourcePtr src,
+ qemuDomainSecretInfoPtr secinfo)
+{
+ /* Only necessary for networked, iSCSI disks with an IV secret to
+ * hide as qemu parsing logic parses the user and password-secret
+ * using the -iscsi command argument.
+ */
+ if (virStorageSourceIsEmpty(src) ||
+ src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI ||
+ !secinfo || secinfo->type != VIR_DOMAIN_SECRET_INFO_IV)
+ return 0;
+
+ return qemuBuildiSCSICommandLine(cmd, src->path, secinfo);
+}
+
+
+/* qemuBuildHostdeviSCSICommandLine:
+ * @cmd: Pointer to the command string
+ * @hostdev: Pointer to a host device
+ * @secinfo: Pointer to a possible secinfo
+ *
+ * See qemuBuildDiskiSCSICommandLine for details.
+ */
+static int
+qemuBuildHostdeviSCSICommandLine(virCommandPtr cmd,
+ virDomainHostdevDefPtr hostdev,
+ qemuDomainSecretInfoPtr secinfo)
+{
+ virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
+ virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
+
+ /* Only necessary for hostdev's using the IV secret */
+ if (!secinfo || secinfo->type != VIR_DOMAIN_SECRET_INFO_IV)
+ return 0;
+
+ return qemuBuildiSCSICommandLine(cmd, iscsisrc->path, secinfo);
+}
+
+
/* qemuBuildGeneralSecinfoURI:
* @uri: Pointer to the URI structure to add to
* @secinfo: Pointer to the secret info data (if present)
+ * @protocol: Protocol for the source device
*
* If we have a secinfo, then build the command line options for
* the secret info for the "general" case (somewhat a misnomer since
@@ -620,7 +742,8 @@ qemuNetworkDriveGetPort(int protocol,
*/
static int
qemuBuildGeneralSecinfoURI(virURIPtr uri,
- qemuDomainSecretInfoPtr secinfo)
+ qemuDomainSecretInfoPtr secinfo,
+ int protocol)
{
if (!secinfo)
return 0;
@@ -639,6 +762,13 @@ qemuBuildGeneralSecinfoURI(virURIPtr uri,
break;
case VIR_DOMAIN_SECRET_INFO_IV:
+ /* iSCSI has a completely different way to handle this
+ * see qemuBuildiSCSICommandLine */
+ if (protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI &&
+ VIR_STRDUP(uri->user, secinfo->s.iv.username) < 0)
+ return -1;
+ break;
+
case VIR_DOMAIN_SECRET_INFO_LAST:
return -1;
}
@@ -677,6 +807,10 @@ qemuBuildRBDSecinfoURI(virBufferPtr buf,
break;
case VIR_DOMAIN_SECRET_INFO_IV:
+ virBufferEscape(buf, '\\', ":",
":id=%s:auth_supported=cephx\\;none",
+ secinfo->s.iv.username);
+ break;
+
case VIR_DOMAIN_SECRET_INFO_LAST:
return -1;
}
@@ -801,7 +935,7 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
goto cleanup;
- if (qemuBuildGeneralSecinfoURI(uri, secinfo) < 0)
+ if (qemuBuildGeneralSecinfoURI(uri, secinfo, src->protocol) < 0)
goto cleanup;
if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
@@ -1069,6 +1203,97 @@ qemuCheckFips(void)
}
+/**
+ * qemuBuildSecretInfoProps:
+ * @secinfo: pointer to the secret info object
+ * @type: returns a pointer to a character string for object name
+ * @props: json properties to return
+ *
+ * Build the JSON properties for the secret info type.
+ *
+ * Returns 0 on success with the filled in JSON property; otherwise,
+ * returns -1 on failure error message set.
+ */
+static int
+qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo,
+ const char **type,
+ virJSONValuePtr *propsret)
+{
+ int ret = -1;
+ char *keyid = NULL;
+ virJSONValuePtr props = NULL;
+
+ *type = "secret";
+
+ if (!(keyid = qemuDomainGetMasterKeyAlias()))
+ return -1;
+
+ if (!(props = virJSONValueNewObject()))
+ goto cleanup;
+
+ if (virJSONValueObjectAdd(props,
+ "s:data", secinfo->s.iv.ciphertext,
+ "s:keyid", keyid,
+ "s:iv", secinfo->s.iv.iv,
+ "s:format", "base64", NULL) < 0)
+ goto cleanup;
+
+ *propsret = props;
+ props = NULL;
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(keyid);
+ virJSONValueFree(props);
+
+ return ret;
+}
+
+
+/**
+ * qemuBuildSecretIVCommandLine:
+ * @cmd: the command to modify
+ * @secinfo: pointer to the secret info object
+ * @qemuCaps: pointer to the emulator capabilities
+ *
+ * If the secinfo is available and associated with an IV secret,
+ * then format the command line for the secret object. This object
+ * will be referenced by the device that needs/uses it, so it needs
+ * to be in place first.
+ *
+ * Returns 0 on success, -1 w/ error message on failure
+ */
+static int
+qemuBuildSecretIVCommandLine(virCommandPtr cmd,
+ qemuDomainSecretInfoPtr secinfo,
+ virQEMUCapsPtr qemuCaps)
+{
+ int ret = -1;
+ virJSONValuePtr props = NULL;
+ const char *objAlias;
+ const char *type;
+ char *tmp = NULL;
+
+ if (!(objAlias = qemuDomainSecretInfoGetAlias(secinfo, qemuCaps)))
+ return 0;
+
+ if (qemuBuildSecretInfoProps(secinfo, &type, &props) < 0)
+ return -1;
+
+ if (!(tmp = qemuBuildObjectCommandlineFromJSON(type, objAlias, props)))
+ goto cleanup;
+
+ virCommandAddArgList(cmd, "-object", tmp, NULL);
+ ret = 0;
+
+ cleanup:
+ virJSONValueFree(props);
+ VIR_FREE(tmp);
+
+ return ret;
+}
+
+
char *
qemuBuildDriveStr(virDomainDiskDefPtr disk,
bool bootable,
@@ -1083,6 +1308,7 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
char *source = NULL;
int actualType = virStorageSourceGetActualType(disk->src);
qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+ qemuDomainSecretInfoPtr secinfo = diskPriv->secinfo;
if (idx < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1164,7 +1390,7 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
break;
}
- if (qemuGetDriveSourceString(disk->src, diskPriv->secinfo, &source) <
0)
+ if (qemuGetDriveSourceString(disk->src, secinfo, &source) < 0)
goto error;
if (source &&
@@ -1215,6 +1441,11 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
virBufferEscape(&opt, ',', ",", "%s,", source);
+ if (disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD &&
+ secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_IV) {
+ virBufferAsprintf(&opt, "password-secret=%s,",
secinfo->s.iv.alias);
+ }
+
if (disk->src->format > 0 &&
disk->src->type != VIR_STORAGE_TYPE_DIR)
virBufferAsprintf(&opt, "format=%s,",
@@ -1888,6 +2119,8 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
virDomainDiskDefPtr disk = def->disks[i];
bool withDeviceArg = false;
bool deviceFlagMasked = false;
+ qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+ qemuDomainSecretInfoPtr secinfo = diskPriv->secinfo;
/* Unless we have -device, then USB disks need special
handling */
@@ -1930,6 +2163,12 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
break;
}
+ if (qemuBuildSecretIVCommandLine(cmd, secinfo, qemuCaps) < 0)
+ return -1;
+
+ if (qemuBuildDiskiSCSICommandLine(cmd, disk->src, secinfo) < 0)
+ return -1;
+
virCommandAddArg(cmd, "-drive");
/* Unfortunately it is not possible to use
@@ -4551,7 +4790,9 @@ qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev,
if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
if (!(source = qemuBuildSCSIiSCSIHostdevDrvStr(dev)))
goto error;
+
virBufferAsprintf(&buf, "file=%s,if=none,format=raw", source);
+
} else {
if (!(source = qemuBuildSCSIHostHostdevDrvStr(dev)))
goto error;
@@ -4992,8 +5233,18 @@ qemuBuildHostdevCommandLine(virCommandPtr cmd,
subsys->type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
+
+ qemuDomainHostdevPrivatePtr hostdevPriv =
+ QEMU_DOMAIN_HOSTDEV_PRIVATE(hostdev);
+ qemuDomainSecretInfoPtr secinfo = hostdevPriv->secinfo;
char *drvstr;
+ if (qemuBuildSecretIVCommandLine(cmd, secinfo, qemuCaps) < 0)
+ return -1;
+
+ if (qemuBuildHostdeviSCSICommandLine(cmd, hostdev, secinfo) < 0)
+ return -1;
+
virCommandAddArg(cmd, "-drive");
if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev, qemuCaps)))
return -1;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 17577ef..3f4f7f9 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -772,6 +772,32 @@ qemuDomainSecretInfoFree(qemuDomainSecretInfoPtr *secinfo)
}
+/* qemuDomainSecretInfoGetAlias:
+ * @secinfo: pointer to the secret info object
+ * @qemuCaps: pointer to the emulator capabilities
+ *
+ * If the emulator supports it, secinfo is available and associated with
+ * an IV secret, then return the alias created during the disk or hostdev
+ * prepare step.
+ *
+ * Returns pointer to the object alias string or NULL if not found/supported
+ */
+const char *
+qemuDomainSecretInfoGetAlias(qemuDomainSecretInfoPtr secinfo,
+ virQEMUCapsPtr qemuCaps)
+{
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_SECRET)) {
+ VIR_INFO("secret object is not supported by this QEMU binary");
+ return NULL;
+ }
+
+ if (!secinfo || secinfo->type != VIR_DOMAIN_SECRET_INFO_IV)
+ return NULL;
+
+ return secinfo->s.iv.alias;
+}
+
+
static virClassPtr qemuDomainDiskPrivateClass;
static void qemuDomainDiskPrivateDispose(void *obj);
@@ -896,6 +922,142 @@ qemuDomainSecretPlainSetup(virConnectPtr conn,
}
+/* qemuDomainSecretHaveEncypt:
+ *
+ * Returns true if we can support the encryption code, false otherwise
+ */
+static bool
+qemuDomainSecretHaveEncrypt(void)
+{
+#ifdef HAVE_GNUTLS_CIPHER_ENCRYPT
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+/* qemuDomainSecretIVSetup:
+ * @conn: Pointer to connection
+ * @priv: pointer to domain private object
+ * @secinfo: Pointer to secret info
+ * @protocol: Protocol for secret
+ * @authdef: Pointer to auth data
+ *
+ * Taking a secinfo, fill in the initialization vector information
+ *
+ * Returns 0 on success, -1 on failure with error message
+ */
+static int
+qemuDomainSecretIVSetup(virConnectPtr conn,
+ qemuDomainObjPrivatePtr priv,
+ qemuDomainSecretInfoPtr secinfo,
+ const char *srcalias,
+ virStorageNetProtocol protocol,
+ virStorageAuthDefPtr authdef)
+{
+ int ret = -1;
+ int rc;
+ uint8_t *raw_iv = NULL;
+ char *secret = NULL;
+ uint8_t *ciphertext = NULL;
+ size_t secretlen = 0, ciphertextlen = 0, paddinglen;
+ int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
+ const char *protocolstr = virStorageNetProtocolTypeToString(protocol);
+ gnutls_cipher_hd_t handle = NULL;
+ gnutls_datum_t enc_key;
+ gnutls_datum_t iv_key;
+
+ secinfo->type = VIR_DOMAIN_SECRET_INFO_IV;
+ if (VIR_STRDUP(secinfo->s.iv.username, authdef->username) < 0)
+ return -1;
+
+ if (protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
+ secretType = VIR_SECRET_USAGE_TYPE_CEPH;
+
+ if (!(secinfo->s.iv.alias = qemuDomainGetIVKeyAlias(srcalias)))
+ return -1;
+
+ /* Create a random initialization vector */
+ if (!(raw_iv = qemuDomainGenerateRandomKey(QEMU_DOMAIN_IV_KEY_LEN)))
+ return -1;
+
+ /* Encode the IV and save that since qemu will need it */
+ base64_encode_alloc((const char *)raw_iv, QEMU_DOMAIN_IV_KEY_LEN,
+ &secinfo->s.iv.iv);
+ if (!secinfo->s.iv.iv) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to encode initialization vector"));
+ goto cleanup;
+ }
+
+ /* Grab the unencoded secret */
+ if (!(secret = virSecretGetSecretString(conn, protocolstr, false,
+ authdef, secretType)))
+ goto cleanup;
+
+ /* Allocate a padded buffer */
+ secretlen = strlen(secret);
+ paddinglen = 16 - (secretlen % 16);
+ ciphertextlen = secretlen + paddinglen;
+ if (VIR_ALLOC_N(ciphertext, ciphertextlen) < 0)
+ goto cleanup;
+ memcpy(ciphertext, secret, secretlen);
+ memset(ciphertext + secretlen, paddinglen, paddinglen);
+
+ /* clear secret so that it doesn't hang around */
+ memset(secret, 0, strlen(secret));
+
+ /* Initialize the gnutls cipher */
+ enc_key.size = QEMU_DOMAIN_MASTER_KEY_LEN;
+ enc_key.data = priv->masterKey;
+ iv_key.size = QEMU_DOMAIN_IV_KEY_LEN;
+ iv_key.data = raw_iv;
+ if ((rc = gnutls_cipher_init(&handle, GNUTLS_CIPHER_AES_256_CBC,
+ &enc_key, &iv_key)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to initialize cipher: '%s'"),
+ gnutls_strerror(rc));
+ goto cleanup;
+ }
+
+ /* Encrypt the secret and free the memory for cipher operations */
+ rc = gnutls_cipher_encrypt(handle, ciphertext, ciphertextlen);
+ gnutls_cipher_deinit(handle);
+ if (rc < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to encrypt the secret: '%s'"),
+ gnutls_strerror(rc));
+ goto cleanup;
+ }
+
+ /* Now base64 encode the ciphertext and store to be passed to qemu */
+ base64_encode_alloc((const char *)ciphertext, ciphertextlen,
+ &secinfo->s.iv.ciphertext);
+ if (!secinfo->s.iv.ciphertext) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to encode ciphertext"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+
+ /* Clear and free the raw_iv, plaintext secret, and ciphertext */
+ memset(raw_iv, 0, QEMU_DOMAIN_IV_KEY_LEN);
+ VIR_FREE(raw_iv);
+
+ memset(secret, 0, secretlen);
+ VIR_FREE(secret);
+
+ memset(ciphertext, 0, ciphertextlen);
+ VIR_FREE(ciphertext);
+
+ return ret;
+}
+
+
/* qemuDomainSecretDiskDestroy:
* @disk: Pointer to a disk definition
*
@@ -924,7 +1086,7 @@ qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk)
*/
int
qemuDomainSecretDiskPrepare(virConnectPtr conn,
- qemuDomainObjPrivatePtr priv ATTRIBUTE_UNUSED,
+ qemuDomainObjPrivatePtr priv,
virDomainDiskDefPtr disk)
{
virStorageSourcePtr src = disk->src;
@@ -941,9 +1103,23 @@ qemuDomainSecretDiskPrepare(virConnectPtr conn,
if (VIR_ALLOC(secinfo) < 0)
return -1;
- if (qemuDomainSecretPlainSetup(conn, secinfo, src->protocol,
- src->auth) < 0)
- goto error;
+ /* If we have the encryption API present and can support a
+ * secret object, then build the IV secret - this is the magic
+ * decision point for utilizing the IV secrets for a disk
+ * whether it's an iSCSI or an RBD disk.
+ */
+ if (qemuDomainSecretHaveEncrypt() &&
+ virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET)) {
+ if (qemuDomainSecretIVSetup(conn, priv, secinfo,
+ disk->info.alias,
+ src->protocol,
+ src->auth) < 0)
+ goto error;
+ } else {
+ if (qemuDomainSecretPlainSetup(conn, secinfo, src->protocol,
+ src->auth) < 0)
+ goto error;
+ }
diskPriv->secinfo = secinfo;
}
@@ -985,7 +1161,7 @@ qemuDomainSecretHostdevDestroy(virDomainHostdevDefPtr hostdev)
*/
int
qemuDomainSecretHostdevPrepare(virConnectPtr conn,
- qemuDomainObjPrivatePtr priv ATTRIBUTE_UNUSED,
+ qemuDomainObjPrivatePtr priv,
virDomainHostdevDefPtr hostdev)
{
virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
@@ -1006,10 +1182,23 @@ qemuDomainSecretHostdevPrepare(virConnectPtr conn,
if (VIR_ALLOC(secinfo) < 0)
return -1;
- if (qemuDomainSecretPlainSetup(conn, secinfo,
- VIR_STORAGE_NET_PROTOCOL_ISCSI,
- iscsisrc->auth) < 0)
- goto error;
+ /* If we have the encryption API present and can support a
+ * secret object, then build the IV secret. This is the magic
+ * decision point for utilizing IV secrets for an iSCSI hostdev
+ */
+ if (qemuDomainSecretHaveEncrypt() &&
+ virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET)) {
+ if (qemuDomainSecretIVSetup(conn, priv, secinfo,
+ hostdev->info->alias,
+ VIR_STORAGE_NET_PROTOCOL_ISCSI,
+ iscsisrc->auth) < 0)
+ goto error;
+ } else {
+ if (qemuDomainSecretPlainSetup(conn, secinfo,
+ VIR_STORAGE_NET_PROTOCOL_ISCSI,
+ iscsisrc->auth) < 0)
+ goto error;
+ }
hostdevPriv->secinfo = secinfo;
}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 9b5f108..c52679a 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -641,6 +641,9 @@ int qemuDomainMasterKeyCreate(virQEMUDriverPtr driver,
void qemuDomainMasterKeyRemove(qemuDomainObjPrivatePtr priv);
+const char *qemuDomainSecretInfoGetAlias(qemuDomainSecretInfoPtr secinfo,
+ virQEMUCapsPtr qemuCaps);
+
void qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk)
ATTRIBUTE_NONNULL(1);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.args
b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.args
new file mode 100644
index 0000000..bce8d2f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.args
@@ -0,0 +1,39 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-object secret,id=virtio-disk0-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/1,user=myname,\
+password-secret=virtio-disk0-ivKey0 \
+-drive file=iscsi://example.org:6000/iqn.1992-01.com.example%3Astorage/1,\
+format=raw,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,\
+id=virtio-disk0 \
+-object secret,id=virtio-disk1-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/2,user=myname,\
+password-secret=virtio-disk1-ivKey0 \
+-drive file=iscsi://example.org:6000/iqn.1992-01.com.example%3Astorage/2,\
+format=raw,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk1,\
+id=virtio-disk1
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.xml
b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.xml
new file mode 100644
index 0000000..1f80d3b
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-iscsi-auth-IV.xml
@@ -0,0 +1,43 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='network' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/1'>
+ <host name='example.org' port='6000'/>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <disk type='network' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/2'>
+ <host name='example.org' port='6000'/>
+ </source>
+ <target dev='vdb' bus='virtio'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.args
b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.args
new file mode 100644
index 0000000..f6c0906
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.args
@@ -0,0 +1,31 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-object secret,id=virtio-disk0-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-drive 'file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
+mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;mon3.example.org\:6322,\
+password-secret=virtio-disk0-ivKey0,format=raw,if=none,id=drive-virtio-disk0' \
+-device virtio-blk-pci,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,\
+id=virtio-disk0
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.xml
b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.xml
new file mode 100644
index 0000000..ac2e942
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-auth-IV.xml
@@ -0,0 +1,42 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <disk type='network' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <auth username='myname'>
+ <secret type='ceph' usage='mycluster_myname'/>
+ </auth>
+ <source protocol='rbd' name='pool/image'>
+ <host name='mon1.example.org' port='6321'/>
+ <host name='mon2.example.org' port='6322'/>
+ <host name='mon3.example.org' port='6322'/>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.args
b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.args
new file mode 100644
index 0000000..6b86aef
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.args
@@ -0,0 +1,41 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest2 \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest2/master-key.aes \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9466-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest2/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-device lsi,id=scsi0,bus=pci.0,addr=0x3 \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-object secret,id=hostdev0-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/1,user=myname,\
+password-secret=hostdev0-ivKey0 \
+-drive file=iscsi://example.org:3260/iqn.1992-01.com.example%3Astorage/1,if=none,\
+format=raw,id=drive-hostdev0 \
+-device scsi-generic,bus=scsi0.0,scsi-id=4,drive=drive-hostdev0,id=hostdev0 \
+-object secret,id=hostdev1-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/2,user=myname,\
+password-secret=hostdev1-ivKey0 \
+-drive file=iscsi://example.org:3260/iqn.1992-01.com.example%3Astorage/2,if=none,\
+format=raw,id=drive-hostdev1 \
+-device scsi-generic,bus=scsi0.0,scsi-id=5,drive=drive-hostdev1,id=hostdev1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.xml
b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.xml
new file mode 100644
index 0000000..f988165
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth-IV.xml
@@ -0,0 +1,48 @@
+<domain type='qemu'>
+ <name>QEMUGuest2</name>
+ <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='scsi' index='0'/>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <hostdev mode='subsystem' type='scsi' managed='yes'>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/1'>
+ <host name='example.org' port='3260'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ </source>
+ <address type='drive' controller='0' bus='0'
target='0' unit='4'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='scsi' managed='yes'>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/2'>
+ <host name='example.org' port='3260'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ </source>
+ <address type='drive' controller='0' bus='0'
target='0' unit='5'/>
+ </hostdev>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.args
b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.args
new file mode 100644
index 0000000..4ecbe53
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.args
@@ -0,0 +1,43 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest2 \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest2/master-key.aes \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9466-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest2/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-object secret,id=hostdev0-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/1,user=myname,\
+password-secret=hostdev0-ivKey0 \
+-drive file=iscsi://example.org:3260/iqn.1992-01.com.example%3Astorage/1,if=none,\
+format=raw,id=drive-hostdev0 \
+-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=2,lun=4,drive=drive-hostdev0,\
+id=hostdev0 \
+-object secret,id=hostdev1-ivKey0,\
+data=/i1QO1S81K4UELoLXmtCNQzxOaE1Tc4DvecFBfyvFKKWUAawbjGD+yZaz9oyEcnW,\
+keyid=masterKey0,iv=/////////////////////w==,format=base64 \
+-iscsi initiator-name=iqn.1992-01.com.example:storage/2,user=myname,\
+password-secret=hostdev1-ivKey0 \
+-drive file=iscsi://example.org:3260/iqn.1992-01.com.example%3Astorage/2,if=none,\
+format=raw,id=drive-hostdev1 \
+-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=2,lun=5,drive=drive-hostdev1,\
+id=hostdev1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.xml
b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.xml
new file mode 100644
index 0000000..b70b84e
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth-IV.xml
@@ -0,0 +1,48 @@
+<domain type='qemu'>
+ <name>QEMUGuest2</name>
+ <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='scsi' index='0'
model='virtio-scsi'/>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <hostdev mode='subsystem' type='scsi' managed='yes'>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/1'>
+ <host name='example.org' port='3260'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ </source>
+ <address type='drive' controller='0' bus='0'
target='2' unit='4'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='scsi' managed='yes'>
+ <source protocol='iscsi'
name='iqn.1992-01.com.example:storage/2'>
+ <host name='example.org' port='3260'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ </source>
+ <address type='drive' controller='0' bus='0'
target='2' unit='5'/>
+ </hostdev>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c
index 1616eed..2bfbf6b 100644
--- a/tests/qemuxml2argvmock.c
+++ b/tests/qemuxml2argvmock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014-2016 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
@@ -30,6 +30,13 @@
#include "virstring.h"
#include "virtpm.h"
#include "virutil.h"
+#include "virrandom.h"
+#ifdef WITH_GNUTLS
+# include <gnutls/gnutls.h>
+# if HAVE_GNUTLS_CRYPTO_H
+# include <gnutls/crypto.h>
+# endif
+#endif
#include <time.h>
#include <unistd.h>
@@ -145,3 +152,25 @@ virCommandPassFD(virCommandPtr cmd ATTRIBUTE_UNUSED,
{
/* nada */
}
+
+int
+virRandomBytes(unsigned char *buf,
+ size_t buflen)
+{
+ size_t i;
+
+ for (i = 0; i < buflen; i++)
+ buf[i] = 0xff;
+
+ return 0;
+}
+
+#ifdef WITH_GNUTLS
+int
+gnutls_rnd(gnutls_rnd_level_t level ATTRIBUTE_UNUSED,
+ void *data,
+ size_t len)
+{
+ return virRandomBytes(data, len);
+#endif
+}
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 8842b2f..c444410 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -26,6 +26,7 @@
# include "virstring.h"
# include "storage/storage_driver.h"
# include "virmock.h"
+# include "virrandom.h"
# include "testutilsqemu.h"
@@ -330,6 +331,14 @@ static int testCompareXMLToArgvFiles(const char *xml,
}
}
+ /* Create a fake master key */
+ if (VIR_ALLOC_N(priv->masterKey, QEMU_DOMAIN_MASTER_KEY_LEN) < 0)
+ goto out;
+
+ if (virRandomBytes(priv->masterKey, QEMU_DOMAIN_MASTER_KEY_LEN) < 0)
+ goto out;
+ priv->masterKeyLen = QEMU_DOMAIN_MASTER_KEY_LEN;
+
if (!(cmd = qemuProcessCreatePretendCmd(conn, &driver, vm, migrateURI,
(flags & FLAG_FIPS), false,
VIR_QEMU_PROCESS_START_COLD))) {
@@ -769,6 +778,8 @@ mymain(void)
DO_TEST("disk-drive-network-nbd-unix", NONE);
DO_TEST("disk-drive-network-iscsi", NONE);
DO_TEST("disk-drive-network-iscsi-auth", NONE);
+ DO_TEST("disk-drive-network-iscsi-auth-IV",
+ QEMU_CAPS_OBJECT_SECRET);
DO_TEST("disk-drive-network-iscsi-lun",
QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI,
QEMU_CAPS_VIRTIO_BLK_SG_IO, QEMU_CAPS_SCSI_BLOCK);
@@ -776,6 +787,8 @@ mymain(void)
DO_TEST("disk-drive-network-rbd", NONE);
DO_TEST("disk-drive-network-sheepdog", NONE);
DO_TEST("disk-drive-network-rbd-auth", NONE);
+ DO_TEST("disk-drive-network-rbd-auth-IV",
+ QEMU_CAPS_OBJECT_SECRET);
DO_TEST("disk-drive-network-rbd-ipv6", NONE);
DO_TEST_FAILURE("disk-drive-network-rbd-no-colon", NONE);
DO_TEST("disk-drive-no-boot",
@@ -1606,12 +1619,18 @@ mymain(void)
DO_TEST("hostdev-scsi-lsi-iscsi-auth",
QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_SCSI_LSI,
QEMU_CAPS_DEVICE_SCSI_GENERIC);
+ DO_TEST("hostdev-scsi-lsi-iscsi-auth-IV",
+ QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_SCSI_LSI,
+ QEMU_CAPS_DEVICE_SCSI_GENERIC, QEMU_CAPS_OBJECT_SECRET);
DO_TEST("hostdev-scsi-virtio-iscsi",
QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_VIRTIO_SCSI,
QEMU_CAPS_DEVICE_SCSI_GENERIC);
DO_TEST("hostdev-scsi-virtio-iscsi-auth",
QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_VIRTIO_SCSI,
QEMU_CAPS_DEVICE_SCSI_GENERIC);
+ DO_TEST("hostdev-scsi-virtio-iscsi-auth-IV",
+ QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_VIRTIO_SCSI,
+ QEMU_CAPS_DEVICE_SCSI_GENERIC, QEMU_CAPS_OBJECT_SECRET);
DO_TEST("mlock-on", QEMU_CAPS_MLOCK);
DO_TEST_FAILURE("mlock-on", NONE);
--
2.5.5