On Mon, Oct 24, 2016 at 06:46:20PM -0400, John Ferlan wrote:
Add the secret object so the 'passwordid=' can be added if
the command line
if there's a secret defined in/on the host for TCP chardev TLS objects.
Preparation for the secret involves adding the secinfo to the char source
device prior to command line processing. There are multiple possibilities
for TCP chardev source backend usage.
Add test for at least a serial chardev as an example.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/qemu/qemu_command.c | 30 +++-
src/qemu/qemu_command.h | 1 +
src/qemu/qemu_domain.c | 173 ++++++++++++++++++++-
src/qemu/qemu_domain.h | 17 +-
src/qemu/qemu_hotplug.c | 1 +
src/qemu/qemu_process.c | 9 +-
...xml2argv-serial-tcp-tlsx509-secret-chardev.args | 38 +++++
...uxml2argv-serial-tcp-tlsx509-secret-chardev.xml | 50 ++++++
tests/qemuxml2argvtest.c | 17 ++
9 files changed, 327 insertions(+), 9 deletions(-)
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6bf6510..1c07959 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -695,6 +695,7 @@ qemuBuildRBDSecinfoURI(virBufferPtr buf,
* @tlspath: path to the TLS credentials
* @listen: boolen listen for client or server setting
* @verifypeer: boolean to enable peer verification (form of authorization)
+ * @secalias: if one exists, the alias of the security object for passwordid
* @qemuCaps: capabilities
* @propsret: json properties to return
*
@@ -706,6 +707,7 @@ int
qemuBuildTLSx509BackendProps(const char *tlspath,
bool isListen,
bool verifypeer,
+ const char *secalias,
virQEMUCapsPtr qemuCaps,
virJSONValuePtr *propsret)
{
@@ -731,6 +733,10 @@ qemuBuildTLSx509BackendProps(const char *tlspath,
NULL) < 0)
goto cleanup;
+ if (secalias &&
+ virJSONValueObjectAdd(*propsret, "s:passwordid", secalias, NULL) <
0)
+ goto cleanup;
+
ret = 0;
cleanup:
@@ -745,6 +751,7 @@ qemuBuildTLSx509BackendProps(const char *tlspath,
* @tlspath: path to the TLS credentials
* @listen: boolen listen for client or server setting
* @verifypeer: boolean to enable peer verification (form of authorization)
+ * @addpasswordid: boolean to handle adding passwordid to object
* @inalias: Alias for the parent to generate object alias
* @qemuCaps: capabilities
*
@@ -757,6 +764,7 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd,
const char *tlspath,
bool isListen,
bool verifypeer,
+ bool addpasswordid,
const char *inalias,
virQEMUCapsPtr qemuCaps)
{
@@ -764,11 +772,16 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd,
char *objalias = NULL;
virJSONValuePtr props = NULL;
char *tmp = NULL;
+ char *secalias = NULL;
- if (qemuBuildTLSx509BackendProps(tlspath, isListen, verifypeer,
- qemuCaps, &props) < 0)
+ if (addpasswordid &&
+ !(secalias = qemuDomainGetSecretAESAlias(inalias, false)))
return -1;
+ if (qemuBuildTLSx509BackendProps(tlspath, isListen, verifypeer, secalias,
+ qemuCaps, &props) < 0)
+ goto cleanup;
+
if (!(objalias = qemuAliasTLSObjFromChardevAlias(inalias)))
goto cleanup;
@@ -784,6 +797,7 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd,
virJSONValueFree(props);
VIR_FREE(objalias);
VIR_FREE(tmp);
+ VIR_FREE(secalias);
return ret;
}
@@ -4936,11 +4950,23 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
virBufferAdd(&buf, nowait ? ",server,nowait" :
",server", -1);
if (dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
+ qemuDomainChrSourcePrivatePtr chrSourcePriv =
+ QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev);
char *objalias = NULL;
+ /* Add the secret object first if necessary. The
+ * secinfo is added only to a TCP serial device during
+ * qemuDomainSecretChardevPrepare. Subsequently called
+ * functions can just check the config fields */
+ if (chrSourcePriv && chrSourcePriv->secinfo &&
+ qemuBuildObjectSecretCommandLine(cmd,
+ chrSourcePriv->secinfo) < 0)
+ goto error;
+
if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir,
dev->data.tcp.listen,
cfg->chardevTLSx509verify,
+ !!cfg->chardevTLSx509secretUUID,
charAlias, qemuCaps) < 0)
goto error;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 2f2a6ff..a793fb6 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -69,6 +69,7 @@ int qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo,
int qemuBuildTLSx509BackendProps(const char *tlspath,
bool isListen,
bool verifypeer,
+ const char *secalias,
virQEMUCapsPtr qemuCaps,
virJSONValuePtr *propsret);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 41ac52d..38c0f18 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1042,7 +1042,8 @@ qemuDomainSecretSetup(virConnectPtr conn,
if (virCryptoHaveCipher(VIR_CRYPTO_CIPHER_AES256CBC) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET) &&
(secretUsageType == VIR_SECRET_USAGE_TYPE_CEPH ||
- secretUsageType == VIR_SECRET_USAGE_TYPE_VOLUME)) {
+ secretUsageType == VIR_SECRET_USAGE_TYPE_VOLUME ||
+ secretUsageType == VIR_SECRET_USAGE_TYPE_TLS)) {
if (qemuDomainSecretAESSetup(conn, priv, secinfo, srcalias,
secretUsageType, username,
seclookupdef, isLuks) < 0)
@@ -1220,6 +1221,97 @@ qemuDomainSecretHostdevPrepare(virConnectPtr conn,
}
+/* qemuDomainSecretChardevDestroy:
+ * @disk: Pointer to a chardev definition
+ *
+ * Clear and destroy memory associated with the secret
+ */
+void
+qemuDomainSecretChardevDestroy(virDomainChrSourceDefPtr dev)
+{
+ qemuDomainChrSourcePrivatePtr chrSourcePriv =
+ QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev);
+
+ if (!chrSourcePriv || !chrSourcePriv->secinfo)
+ return;
+
+ qemuDomainSecretInfoFree(&chrSourcePriv->secinfo);
+}
+
+
+/* qemuDomainSecretChardevPrepare:
+ * @conn: Pointer to connection
+ * @driver: Pointer to driver object
+ * @priv: pointer to domain private object
+ * @chrAlias: Alias of the chr device
+ * @dev: Pointer to a char source definition
+ *
+ * For a TCP character device, generate a qemuDomainSecretInfo to be used
+ * by the command line code to generate the secret for the tls-creds to use.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+qemuDomainSecretChardevPrepare(virConnectPtr conn,
+ virQEMUDriverPtr driver,
+ qemuDomainObjPrivatePtr priv,
+ const char *chrAlias,
+ virDomainChrSourceDefPtr dev)
+{
+ virQEMUDriverConfigPtr cfg;
+ virSecretLookupTypeDef seclookupdef = {0};
+ qemuDomainSecretInfoPtr secinfo = NULL;
+ char *charAlias = NULL;
+
+ if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP)
+ return 0;
+
+ cfg = virQEMUDriverGetConfig(driver);
The *driver* is used only to get the *cfg* and the whole function is used
in several loops so it would be better to pass *cfg* directly to this function
in order to save a lot of locks & unlocks and refs & unrefs.
+ if (dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES
&&
+ cfg->chardevTLSx509secretUUID) {
+ qemuDomainChrSourcePrivatePtr chrSourcePriv =
+ QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev);
+
+ if (virUUIDParse(cfg->chardevTLSx509secretUUID,
+ seclookupdef.u.uuid) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("malformed chardev TLS secret uuid in
qemu.conf"));
+ goto error;
+ }
+ seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID;
+
+ if (VIR_ALLOC(secinfo) < 0)
+ goto error;
+
+ if (!(charAlias = qemuAliasChardevFromDevAlias(chrAlias)))
+ goto error;
+
+ if (qemuDomainSecretSetup(conn, priv, secinfo, charAlias,
+ VIR_SECRET_USAGE_TYPE_TLS, NULL,
+ &seclookupdef, false) < 0)
+ goto error;
+
+ if (secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_PLAIN) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("TLS X.509 requires encrypted secrets "
+ "to be supported"));
+ goto error;
+ }
+
+ chrSourcePriv->secinfo = secinfo;
+ }
+
+ VIR_FREE(charAlias);
+ virObjectUnref(cfg);
+ return 0;
+
+ error:
+ virObjectUnref(cfg);
+ qemuDomainSecretInfoFree(&secinfo);
+ return -1;
+}
+
+
/* qemuDomainSecretDestroy:
* @vm: Domain object
*
@@ -1236,11 +1328,38 @@ qemuDomainSecretDestroy(virDomainObjPtr vm)
for (i = 0; i < vm->def->nhostdevs; i++)
qemuDomainSecretHostdevDestroy(vm->def->hostdevs[i]);
+
+ for (i = 0; i < vm->def->nserials; i++)
+ qemuDomainSecretChardevDestroy(vm->def->serials[i]->source);
+
+ for (i = 0; i < vm->def->nparallels; i++)
+ qemuDomainSecretChardevDestroy(vm->def->parallels[i]->source);
+
+ for (i = 0; i < vm->def->nchannels; i++)
+ qemuDomainSecretChardevDestroy(vm->def->channels[i]->source);
+
+ for (i = 0; i < vm->def->nconsoles; i++)
+ qemuDomainSecretChardevDestroy(vm->def->consoles[i]->source);
+
+ for (i = 0; i < vm->def->nsmartcards; i++) {
+ if (vm->def->smartcards[i]->type ==
+ VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH)
+
qemuDomainSecretChardevDestroy(vm->def->smartcards[i]->data.passthru);
+ }
+
+ for (i = 0; i < vm->def->nrngs; i++) {
+ if (vm->def->rngs[i]->backend == VIR_DOMAIN_RNG_BACKEND_EGD)
+ qemuDomainSecretChardevDestroy(vm->def->rngs[i]->source.chardev);
+ }
+
+ for (i = 0; i < vm->def->nredirdevs; i++)
+ qemuDomainSecretChardevDestroy(vm->def->redirdevs[i]->source);
}
/* qemuDomainSecretPrepare:
* @conn: Pointer to connection
+ * @driver: Pointer to driver object
* @vm: Domain object
*
* For any objects that may require an auth/secret setup, create a
@@ -1253,6 +1372,7 @@ qemuDomainSecretDestroy(virDomainObjPtr vm)
*/
int
qemuDomainSecretPrepare(virConnectPtr conn,
+ virQEMUDriverPtr driver,
virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -1269,6 +1389,57 @@ qemuDomainSecretPrepare(virConnectPtr conn,
return -1;
}
+ for (i = 0; i < vm->def->nserials; i++) {
+ if (qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->serials[i]->info.alias,
+ vm->def->serials[i]->source) <
0)
+ return -1;
+ }
+
+ for (i = 0; i < vm->def->nparallels; i++) {
+ if (qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->parallels[i]->info.alias,
+ vm->def->parallels[i]->source) <
0)
+ return -1;
+ }
+
+ for (i = 0; i < vm->def->nchannels; i++) {
+ if (qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->channels[i]->info.alias,
+ vm->def->channels[i]->source) <
0)
+ return -1;
+ }
+
+ for (i = 0; i < vm->def->nconsoles; i++) {
+ if (qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->consoles[i]->info.alias,
+ vm->def->consoles[i]->source) <
0)
+ return -1;
+ }
+
+ for (i = 0; i < vm->def->nsmartcards; i++)
+ if (vm->def->smartcards[i]->type ==
+ VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH &&
+ qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->smartcards[i]->info.alias,
+
vm->def->smartcards[i]->data.passthru) < 0)
+ return -1;
+
+ for (i = 0; i < vm->def->nrngs; i++) {
+ if (vm->def->rngs[i]->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
+ qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->rngs[i]->info.alias,
+ vm->def->rngs[i]->source.chardev)
< 0)
+ return -1;
+ }
+
+ for (i = 0; i < vm->def->nredirdevs; i++) {
+ if (qemuDomainSecretChardevPrepare(conn, driver, priv,
+ vm->def->redirdevs[i]->info.alias,
+ vm->def->redirdevs[i]->source) <
0)
+ return -1;
+ }
+
return 0;
}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 4f9bf82..0820afd 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -726,11 +726,24 @@ int qemuDomainSecretHostdevPrepare(virConnectPtr conn,
virDomainHostdevDefPtr hostdev)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void qemuDomainSecretChardevDestroy(virDomainChrSourceDefPtr dev)
+ ATTRIBUTE_NONNULL(1);
+
+int qemuDomainSecretChardevPrepare(virConnectPtr conn,
+ virQEMUDriverPtr driver,
+ qemuDomainObjPrivatePtr priv,
+ const char *chrAlias,
+ virDomainChrSourceDefPtr dev)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_NONNULL(4);
And ATTRIBUTE_NONNULL(5)
ACK with the issues fixed.
Pavel