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)
This commit is contained in:
Michal Privoznik 2011-05-26 16:15:54 +02:00
parent 2f4d2496a8
commit 30c43afd73
7 changed files with 99 additions and 14 deletions

View File

@ -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 <code>passwdValidTo='2010-04-09T15:51:00'</code>
assumed to be in UTC. NB, this may not be supported by all
hypervisors.<br/> <br/> Rather than using listen/port,
QEMU supports a <code>socket</code> attribute for
listening on a unix domain socket
path.<span class="since">Since 0.8.8</span>
assumed to be in UTC. The <code>connected</code> attribute
allows control of connected client during password changes.
VNC accepts <code>keep</code> value only.
<span class="since">since 0.9.3</span>
NB, this may not be supported by all hypervisors.<br/> <br/>
Rather than using listen/port, QEMU supports a
<code>socket</code> attribute for listening on a unix
domain socket path.<span class="since">Since 0.8.8</span>
</dd>
<dt><code>"spice"</code></dt>
<dd>
@ -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 <code>passwdValidTo='2010-04-09T15:51:00'</code>
assumed to be in UTC. NB, this may not be supported by
all hypervisors.<span class="since">"spice" since 0.8.6</span>.
assumed to be in UTC. The <code>connected</code> attribute
allows control of connected client during password changes.
SPICE accepts <code>keep</code> to keep client connected,
<code>disconnect</code> to disconnect client and
<code>fail</code> to fail changing password.
<span class="since">Since 0.9.3</span>
NB, this may not be supported by all hypervisors.
<span class="since">"spice" since 0.8.6</span>.
</p>
<p>
When SPICE has both a normal and TLS secured TCP port

View File

@ -1294,6 +1294,13 @@
<data type="dateTime"/>
</attribute>
</optional>
<optional>
<attribute name="connected">
<choice>
<value>keep</value>
</choice>
</attribute>
</optional>
</group>
<group>
<attribute name="type">
@ -1337,6 +1344,15 @@
<data type="dateTime"/>
</attribute>
</optional>
<optional>
<attribute name="connected">
<choice>
<value>fail</value>
<value>disconnect</value>
<value>keep</value>
</choice>
</attribute>
</optional>
<interleave>
<zeroOrMore>
<element name="channel">

View File

@ -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

View File

@ -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)

View File

@ -270,6 +270,8 @@ virDomainFindByID;
virDomainFindByName;
virDomainFindByUUID;
virDomainGetRootFilesystem;
virDomainGraphicsAuthConnectedTypeFromString;
virDomainGraphicsAuthConnectedTypeToString;
virDomainGraphicsDefFree;
virDomainGraphicsSpiceChannelModeTypeFromString;
virDomainGraphicsSpiceChannelModeTypeToString;

View File

@ -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) {

View File

@ -71,7 +71,7 @@
</console>
<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<graphics type='spice' port='5900' autoport='no' passwd='sercet' passwdValidTo='2011-05-31T16:11:22'/>
<graphics type='spice' port='5900' autoport='no' passwd='sercet' passwdValidTo='2011-05-31T16:11:22' connected='disconnect'/>
<sound model='ac97'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</sound>