mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 09:17:52 +03:00
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:
parent
2f4d2496a8
commit
30c43afd73
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -270,6 +270,8 @@ virDomainFindByID;
|
||||
virDomainFindByName;
|
||||
virDomainFindByUUID;
|
||||
virDomainGetRootFilesystem;
|
||||
virDomainGraphicsAuthConnectedTypeFromString;
|
||||
virDomainGraphicsAuthConnectedTypeToString;
|
||||
virDomainGraphicsDefFree;
|
||||
virDomainGraphicsSpiceChannelModeTypeFromString;
|
||||
virDomainGraphicsSpiceChannelModeTypeToString;
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user