From 30c43afd73e8c2931dc210562066ba37a8b9fe26 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Thu, 26 May 2011 16:15:54 +0200 Subject: [PATCH] graphics: add support for action_if_connected in qemu This option accepts 3 values: -keep, to keep current client connected (Spice+VNC) -disconnect, to disconnect client (Spice) -fail, to fail setting password if there is a client connected (Spice) --- docs/formatdomain.html.in | 23 +++++++--- docs/schemas/domain.rng | 16 +++++++ src/conf/domain_conf.c | 44 +++++++++++++++++-- src/conf/domain_conf.h | 11 +++++ src/libvirt_private.syms | 2 + src/qemu/qemu_hotplug.c | 15 +++++-- .../qemuxml2argv-graphics-spice-timeout.xml | 2 +- 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 10d87a9bb6..fa4e0c23b7 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1896,11 +1896,14 @@ qemu-kvm -net nic,model=? /dev/null specifies the keymap to use. It is possible to set a limit on the validity of the password be giving an timestamp passwdValidTo='2010-04-09T15:51:00' - assumed to be in UTC. NB, this may not be supported by all - hypervisors.

Rather than using listen/port, - QEMU supports a socket attribute for - listening on a unix domain socket - path.Since 0.8.8 + assumed to be in UTC. The connected attribute + allows control of connected client during password changes. + VNC accepts keep value only. + since 0.9.3 + NB, this may not be supported by all hypervisors.

+ Rather than using listen/port, QEMU supports a + socket attribute for listening on a unix + domain socket path.Since 0.8.8
"spice"
@@ -1918,8 +1921,14 @@ qemu-kvm -net nic,model=? /dev/null attribute specifies the keymap to use. It is possible to set a limit on the validity of the password be giving an timestamp passwdValidTo='2010-04-09T15:51:00' - assumed to be in UTC. NB, this may not be supported by - all hypervisors."spice" since 0.8.6. + assumed to be in UTC. The connected attribute + allows control of connected client during password changes. + SPICE accepts keep to keep client connected, + disconnect to disconnect client and + fail to fail changing password. + Since 0.9.3 + NB, this may not be supported by all hypervisors. + "spice" since 0.8.6.

When SPICE has both a normal and TLS secured TCP port diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 3c8414eef0..c01801e4cd 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1294,6 +1294,13 @@ + + + + keep + + + @@ -1337,6 +1344,15 @@ + + + + fail + disconnect + keep + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2275d3ae5b..a680b114e8 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -317,6 +317,13 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST, "desktop", "spice") +VIR_ENUM_IMPL(virDomainGraphicsAuthConnected, + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST, + "default", + "fail", + "disconnect", + "keep") + VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName, VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST, "main", @@ -3945,9 +3952,12 @@ error: static int -virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr def) +virDomainGraphicsAuthDefParseXML(xmlNodePtr node, + virDomainGraphicsAuthDefPtr def, + int type) { char *validTo = NULL; + char *connected = virXMLPropString(node, "connected"); def->passwd = virXMLPropString(node, "passwd"); @@ -3988,6 +3998,28 @@ virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr de def->expires = 1; } + if (connected) { + int action = virDomainGraphicsAuthConnectedTypeFromString(connected); + if (action <= 0) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown connected value %s"), + connected); + VIR_FREE(connected); + return -1; + } + VIR_FREE(connected); + + /* VNC supports connected='keep' only */ + if (type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + action != VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC supports connected='keep' only")); + return -1; + } + + def->connected = action; + } + return 0; } @@ -4058,7 +4090,8 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, unsigned int flags) !def->data.vnc.listenAddr[0]) VIR_FREE(def->data.vnc.listenAddr); - if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0) + if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth, + def->type) < 0) goto error; } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { char *fullscreen = virXMLPropString(node, "fullscreen"); @@ -4194,7 +4227,8 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, unsigned int flags) !def->data.spice.listenAddr[0]) VIR_FREE(def->data.spice.listenAddr); - if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth) < 0) + if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth, + def->type) < 0) goto error; cur = node->children; @@ -9280,6 +9314,10 @@ virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf, strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm); virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf); } + + if (def->connected) + virBufferEscapeString(buf, " connected='%s'", + virDomainGraphicsAuthConnectedTypeToString(def->connected)); } static int diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index ddfe18e3d9..15adc70b88 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -639,12 +639,22 @@ enum virDomainGraphicsType { VIR_DOMAIN_GRAPHICS_TYPE_LAST, }; +enum virDomainGraphicsAuthConnectedType { + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DEFAULT = 0, + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL, + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT, + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP, + + VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST +}; + typedef struct _virDomainGraphicsAuthDef virDomainGraphicsAuthDef; typedef virDomainGraphicsAuthDef *virDomainGraphicsAuthDefPtr; struct _virDomainGraphicsAuthDef { char *passwd; unsigned int expires: 1; /* Whether there is an expiry time set */ time_t validTo; /* seconds since epoch */ + int connected; /* action if connected */ }; enum virDomainGraphicsSpiceChannelName { @@ -1582,6 +1592,7 @@ VIR_ENUM_DECL(virDomainHostdevSubsys) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) +VIR_ENUM_DECL(virDomainGraphicsAuthConnected) VIR_ENUM_DECL(virDomainGraphicsSpiceChannelName) VIR_ENUM_DECL(virDomainGraphicsSpiceChannelMode) VIR_ENUM_DECL(virDomainGraphicsSpiceImageCompression) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 28a34045f7..1112398642 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -270,6 +270,8 @@ virDomainFindByID; virDomainFindByName; virDomainFindByUUID; virDomainGetRootFilesystem; +virDomainGraphicsAuthConnectedTypeFromString; +virDomainGraphicsAuthConnectedTypeToString; virDomainGraphicsDefFree; virDomainGraphicsSpiceChannelModeTypeFromString; virDomainGraphicsSpiceChannelModeTypeToString; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index a7f11ab436..58689f688a 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1065,10 +1065,12 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, return -1; } - /* If a password lifetime was, or is set, then we must always run, - * even if new password matches old password */ + /* If a password lifetime was, or is set, or action if connected has + * changed, then we must always run, even if new password matches + * old password */ if (olddev->data.vnc.auth.expires || dev->data.vnc.auth.expires || + olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected || STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd, dev->data.vnc.auth.passwd)) { VIR_DEBUG("Updating password on VNC server %p %p", @@ -1084,6 +1086,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, dev->data.vnc.auth.passwd = NULL; olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo; olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires; + olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected; } else { ret = 0; } @@ -1116,6 +1119,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, * even if new password matches old password */ if (olddev->data.spice.auth.expires || dev->data.spice.auth.expires || + olddev->data.spice.auth.connected != dev->data.spice.auth.connected || STRNEQ_NULLABLE(olddev->data.spice.auth.passwd, dev->data.spice.auth.passwd)) { VIR_DEBUG("Updating password on SPICE server %p %p", @@ -1131,6 +1135,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, dev->data.spice.auth.passwd = NULL; olddev->data.spice.auth.validTo = dev->data.spice.auth.validTo; olddev->data.spice.auth.expires = dev->data.spice.auth.expires; + olddev->data.spice.auth.connected = dev->data.spice.auth.connected; } else { VIR_DEBUG("Not updating since password didn't change"); ret = 0; @@ -1874,16 +1879,20 @@ qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver, qemuDomainObjPrivatePtr priv = vm->privateData; time_t now = time(NULL); char expire_time [64]; + const char *connected = NULL; int ret; if (!auth->passwd && !driver->vncPassword) return 0; + if (auth->connected) + connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected); + qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorSetPassword(priv->mon, type, auth->passwd ? auth->passwd : defaultPasswd, - NULL); + connected); if (ret == -2) { if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) { diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml index 4c0c57edf2..6389de54ad 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml @@ -71,7 +71,7 @@ - +