In common with VNC, the QEMU driver configuration file is used
specify the host level TLS certificate location and a default
password / listen address
* src/qemu/qemu.conf: Add spice_listen, spice_tls,
spice_tls_x509_cert_dir & spice_password config params
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Parsing of
spice config parameters and updating -spice arg generation
to use them
* tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args,
tests/qemuxml2argvtest.c: Expand test case to cover driver
level configuration
---
src/qemu/qemu.conf | 40 +++++++++++++
src/qemu/qemu_conf.c | 62 +++++++++++++++++++-
src/qemu/qemu_conf.h | 4 +
src/qemu/qemu_driver.c | 15 ++++-
.../qemuxml2argv-graphics-spice.args | 2 +-
tests/qemuxml2argvtest.c | 5 ++
6 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index e2c581e..f4f965e 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -80,6 +80,46 @@
+# SPICE is configured to listen on 127.0.0.1 by default.
+# To make it listen on all public interfaces, uncomment
+# this next option.
+#
+# NB, strong recommendation to enable TLS + x509 certificate
+# verification when allowing public access
+#
+# spice_listen = "0.0.0.0"
+
+
+# Enable use of TLS encryption on the SPICE server.
+#
+# It is necessary to setup CA and issue a server certificate
+# before enabling this.
+#
+# spice_tls = 1
+
+
+# Use of TLS requires that x509 certificates be issued. The
+# default it to keep them in /etc/pki/libvirt-spice. This directory
+# must contain
+#
+# ca-cert.pem - the CA master certificate
+# server-cert.pem - the server certificate signed with ca-cert.pem
+# server-key.pem - the server private key
+#
+# This option allows the certificate directory to be changed
+#
+# spice_tls_x509_cert_dir = "/etc/pki/libvirt-spice"
+
+
+# The default SPICE password. This parameter is only used if the
+# per-domain XML config does not already provide a password. To
+# allow access without passwords, leave this commented out. An
+# empty string will still enable passwords, but be rejected by
+# QEMU effectively preventing any use of SPICE. Obviously change
+# this example here before you set this
+#
+# spice_password = "XYZ12345"
+
# The default security driver is SELinux. If SELinux is disabled
# on the host, then the security driver will automatically disable
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index b551b8d..c76893c 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -116,6 +116,15 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
return -1;
}
+ if (!(driver->spiceListen = strdup("127.0.0.1"))) {
+ virReportOOMError();
+ return -1;
+ }
+ if (!(driver->spiceTLSx509certdir = strdup(SYSCONF_DIR
"/pki/libvirt-spice"))) {
+ virReportOOMError();
+ return -1;
+ }
+
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
/* For privileged driver, try and find hugepage mount automatically.
* Non-privileged driver requires admin to create a dir for the
@@ -219,6 +228,43 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
}
}
+ p = virConfGetValue (conf, "spice_tls");
+ CHECK_TYPE ("spice_tls", VIR_CONF_LONG);
+ if (p) driver->spiceTLS = p->l;
+
+ p = virConfGetValue (conf, "spice_tls_x509_cert_dir");
+ CHECK_TYPE ("spice_tls_x509_cert_dir", VIR_CONF_STRING);
+ if (p && p->str) {
+ VIR_FREE(driver->spiceTLSx509certdir);
+ if (!(driver->spiceTLSx509certdir = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ }
+
+ p = virConfGetValue (conf, "spice_listen");
+ CHECK_TYPE ("spice_listen", VIR_CONF_STRING);
+ if (p && p->str) {
+ VIR_FREE(driver->spiceListen);
+ if (!(driver->spiceListen = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ }
+
+ p = virConfGetValue (conf, "spice_password");
+ CHECK_TYPE ("spice_password", VIR_CONF_STRING);
+ if (p && p->str) {
+ VIR_FREE(driver->spicePassword);
+ if (!(driver->spicePassword = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ }
+
p = virConfGetValue (conf, "user");
CHECK_TYPE ("user", VIR_CONF_STRING);
if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) {
@@ -4959,11 +5005,25 @@ int qemudBuildCommandLine(virConnectPtr conn,
virBufferVSprintf(&opt, "port=%u",
def->graphics[0]->data.spice.port);
- if (def->graphics[0]->data.spice.tlsPort)
+ if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort !=
-1)
virBufferVSprintf(&opt, ",tls-port=%u",
def->graphics[0]->data.spice.tlsPort);
if (def->graphics[0]->data.spice.listenAddr)
virBufferVSprintf(&opt, ",addr=%s",
def->graphics[0]->data.spice.listenAddr);
+ else if (driver->spiceListen)
+ virBufferVSprintf(&opt, ",addr=%s", driver->spiceListen);
+
+ /* In the password case we set it via monitor command, to avoid
+ * making it visible on CLI, so there's no use of password=XXX
+ * in this bit of the code */
+ if (!def->graphics[0]->data.spice.passwd &&
+ !driver->spicePassword)
+ virBufferAddLit(&opt, ",disable-ticketing");
+
+ if (driver->spiceTLS)
+ virBufferVSprintf(&opt, ",x509-dir=%s",
+ driver->spiceTLSx509certdir);
+
if (virBufferError(&opt))
goto no_memory;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 6cfbfe0..7df5794 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -140,6 +140,10 @@ struct qemud_driver {
char *vncListen;
char *vncPassword;
char *vncSASLdir;
+ unsigned int spiceTLS : 1;
+ char *spiceTLSx509certdir;
+ char *spiceListen;
+ char *spicePassword;
char *hugetlbfs_mount;
char *hugepage_path;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index fbb0a68..5854c44 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3900,13 +3900,22 @@ static int qemudStartVMDaemon(virConnectPtr conn,
} else if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE
&&
vm->def->graphics[0]->data.spice.autoport) {
int port = qemudNextFreePort(driver, 5900);
- int tlsPort = port == -1 ? -1 : qemudNextFreePort(driver, port + 1);
- if (port < 0 || tlsPort < 0) {
+ int tlsPort = -1;
+ if (port < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Unable to find unused SPICE
ports"));
+ "%s", _("Unable to find an unused SPICE
port"));
goto cleanup;
}
+ if (driver->spiceTLS) {
+ tlsPort = qemudNextFreePort(driver, port + 1);
+ if (tlsPort < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused
SPICE TLS port"));
+ goto cleanup;
+ }
+ }
+
vm->def->graphics[0]->data.spice.port = port;
vm->def->graphics[0]->data.spice.tlsPort = tlsPort;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
index 8d195e5..e412fdb 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
@@ -1 +1 @@
-LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=spice
/usr/bin/qemu -S -M pc -m 214 -smp 1 -nodefaults -monitor
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb
-spice port=5903,tls-port=5904,addr=127.0.0.1 -vga qxl -device
virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=spice
/usr/bin/qemu -S -M pc -m 214 -smp 1 -nodefaults -monitor
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb
-spice port=5903,tls-port=5904,addr=127.0.0.1,x509-dir=/etc/pki/libvirt-spice -vga qxl
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index c89f249..9a6f78a 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -214,6 +214,11 @@ mymain(int argc, char **argv)
return EXIT_FAILURE;
if ((driver.hugepage_path = strdup("/dev/hugepages/libvirt/qemu")) ==
NULL)
return EXIT_FAILURE;
+ driver.spiceTLS = 1;
+ if (!(driver.spiceTLSx509certdir = strdup("/etc/pki/libvirt-spice")))
+ return EXIT_FAILURE;
+ if (!(driver.spicePassword = strdup("123456")))
+ return EXIT_FAILURE;
# define DO_TEST_FULL(name, extraFlags, migrateFrom, expectError) \
do { \
--
1.7.2.3