mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-13 08:56:09 -06:00
Support SPICE channel security options
This extends the SPICE XML to allow channel security options <graphics type='spice' port='-1' tlsPort='-1' autoport='yes'> <channel name='main' mode='secure'/> <channel name='record' mode='insecure'/> </graphics> Any non-specified channel uses the default, which allows both secure & insecure usage * src/conf/domain_conf.c, src/conf/domain_conf.h, src/libvirt_private.syms: Add XML syntax for specifying per channel security options for spice. * src/qemu/qemu_conf.c: Configure channel security with spice
This commit is contained in:
parent
6794a44b85
commit
b0ef5c5367
@ -1108,6 +1108,7 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
</dd>
|
</dd>
|
||||||
<dt><code>"spice"</code></dt>
|
<dt><code>"spice"</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
<p>
|
||||||
Starts a SPICE server. The <code>port</code> attribute specifies the TCP
|
Starts a SPICE server. The <code>port</code> attribute specifies the TCP
|
||||||
port number (with -1 as legacy syntax indicating that it should be
|
port number (with -1 as legacy syntax indicating that it should be
|
||||||
auto-allocated), while <code>tlsPort</code> gives an alternative
|
auto-allocated), while <code>tlsPort</code> gives an alternative
|
||||||
@ -1119,6 +1120,20 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
to use. It is possible to set a limit on the validity of the password
|
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>
|
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.
|
assumed to be in UTC. NB, this may not be supported by all hypervisors.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When SPICE has both a normal and TLS secured TCP port configured, it
|
||||||
|
can be desirable to restrict what channels can be run on each port.
|
||||||
|
This is achieved by adding one or more <channel> elements inside
|
||||||
|
the main <graphics> element. Valid channel names include
|
||||||
|
<code>main</code>,<code>display</code>,<code>inputs</code>,<code>cursor</code>,
|
||||||
|
<code>playback</code>,<code>record</code>.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<graphics type='spice' port='-1' tlsPort='-1' autoport='yes'>
|
||||||
|
<channel name='main' mode='secure'/>
|
||||||
|
<channel name='record' mode='insecure'/>
|
||||||
|
</graphics></pre>
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>"rdp"</code></dt>
|
<dt><code>"rdp"</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
@ -1093,6 +1093,27 @@
|
|||||||
<text/>
|
<text/>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="channel">
|
||||||
|
<attribute name="name">
|
||||||
|
<choice>
|
||||||
|
<value>main</value>
|
||||||
|
<value>display</value>
|
||||||
|
<value>inputs</value>
|
||||||
|
<value>cursor</value>
|
||||||
|
<value>playback</value>
|
||||||
|
<value>record</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="mode">
|
||||||
|
<choice>
|
||||||
|
<value>any</value>
|
||||||
|
<value>secure</value>
|
||||||
|
<value>insecure</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<attribute name="type">
|
<attribute name="type">
|
||||||
|
@ -271,6 +271,21 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
|
|||||||
"desktop",
|
"desktop",
|
||||||
"spice")
|
"spice")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
|
||||||
|
"main",
|
||||||
|
"display",
|
||||||
|
"inputs",
|
||||||
|
"cursor",
|
||||||
|
"playback",
|
||||||
|
"record");
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelMode,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_LAST,
|
||||||
|
"any",
|
||||||
|
"secure",
|
||||||
|
"insecure");
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
|
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
|
||||||
"subsystem",
|
"subsystem",
|
||||||
"capabilities")
|
"capabilities")
|
||||||
@ -3274,6 +3289,7 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
|
|||||||
|
|
||||||
def->data.desktop.display = virXMLPropString(node, "display");
|
def->data.desktop.display = virXMLPropString(node, "display");
|
||||||
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
||||||
|
xmlNodePtr cur;
|
||||||
char *port = virXMLPropString(node, "port");
|
char *port = virXMLPropString(node, "port");
|
||||||
char *tlsPort;
|
char *tlsPort;
|
||||||
char *autoport;
|
char *autoport;
|
||||||
@ -3318,6 +3334,40 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
|
|||||||
def->data.spice.keymap = virXMLPropString(node, "keymap");
|
def->data.spice.keymap = virXMLPropString(node, "keymap");
|
||||||
if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0)
|
if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
cur = node->children;
|
||||||
|
while (cur != NULL) {
|
||||||
|
if (cur->type == XML_ELEMENT_NODE) {
|
||||||
|
if (xmlStrEqual(cur->name, BAD_CAST "channel")) {
|
||||||
|
const char *name, *mode;
|
||||||
|
int nameval, modeval;
|
||||||
|
name = virXMLPropString(cur, "name");
|
||||||
|
mode = virXMLPropString(cur, "mode");
|
||||||
|
|
||||||
|
if (!name || !mode) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("spice channel missing name/mode"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown spice channel name %s"),
|
||||||
|
name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown spice channel mode %s"),
|
||||||
|
mode);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
def->data.spice.channels[nameval] = modeval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -6572,6 +6622,8 @@ virDomainGraphicsDefFormat(virBufferPtr buf,
|
|||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
const char *type = virDomainGraphicsTypeToString(def->type);
|
const char *type = virDomainGraphicsTypeToString(def->type);
|
||||||
|
int children = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -6673,7 +6725,28 @@ virDomainGraphicsDefFormat(virBufferPtr buf,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virBufferAddLit(buf, "/>\n");
|
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
||||||
|
for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
|
||||||
|
int mode = def->data.spice.channels[i];
|
||||||
|
if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!children) {
|
||||||
|
virBufferAddLit(buf, ">\n");
|
||||||
|
children = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virBufferVSprintf(buf, " <channel name='%s' mode='%s'/>\n",
|
||||||
|
virDomainGraphicsSpiceChannelNameTypeToString(i),
|
||||||
|
virDomainGraphicsSpiceChannelModeTypeToString(mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children) {
|
||||||
|
virBufferAddLit(buf, " </graphics>\n");
|
||||||
|
} else {
|
||||||
|
virBufferAddLit(buf, "/>\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -525,6 +525,24 @@ struct _virDomainGraphicsAuthDef {
|
|||||||
time_t validTo; /* seconds since epoch */
|
time_t validTo; /* seconds since epoch */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum virDomainGraphicsSpiceChannelName {
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MAIN,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_DISPLAY,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_INPUT,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_CURSOR,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_PLAYBACK,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_RECORD,
|
||||||
|
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum virDomainGraphicsSpiceChannelMode {
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE,
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE,
|
||||||
|
|
||||||
|
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_LAST
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _virDomainGraphicsDef virDomainGraphicsDef;
|
typedef struct _virDomainGraphicsDef virDomainGraphicsDef;
|
||||||
typedef virDomainGraphicsDef *virDomainGraphicsDefPtr;
|
typedef virDomainGraphicsDef *virDomainGraphicsDefPtr;
|
||||||
@ -561,6 +579,7 @@ struct _virDomainGraphicsDef {
|
|||||||
char *keymap;
|
char *keymap;
|
||||||
virDomainGraphicsAuthDef auth;
|
virDomainGraphicsAuthDef auth;
|
||||||
unsigned int autoport :1;
|
unsigned int autoport :1;
|
||||||
|
int channels[VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST];
|
||||||
} spice;
|
} spice;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
@ -1234,6 +1253,8 @@ VIR_ENUM_DECL(virDomainHostdevSubsys)
|
|||||||
VIR_ENUM_DECL(virDomainInput)
|
VIR_ENUM_DECL(virDomainInput)
|
||||||
VIR_ENUM_DECL(virDomainInputBus)
|
VIR_ENUM_DECL(virDomainInputBus)
|
||||||
VIR_ENUM_DECL(virDomainGraphics)
|
VIR_ENUM_DECL(virDomainGraphics)
|
||||||
|
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelName)
|
||||||
|
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelMode)
|
||||||
/* from libvirt.h */
|
/* from libvirt.h */
|
||||||
VIR_ENUM_DECL(virDomainState)
|
VIR_ENUM_DECL(virDomainState)
|
||||||
VIR_ENUM_DECL(virDomainSeclabel)
|
VIR_ENUM_DECL(virDomainSeclabel)
|
||||||
|
@ -204,6 +204,10 @@ virDomainFindByName;
|
|||||||
virDomainFindByUUID;
|
virDomainFindByUUID;
|
||||||
virDomainGetRootFilesystem;
|
virDomainGetRootFilesystem;
|
||||||
virDomainGraphicsDefFree;
|
virDomainGraphicsDefFree;
|
||||||
|
virDomainGraphicsSpiceChannelModeTypeFromString;
|
||||||
|
virDomainGraphicsSpiceChannelModeTypeToString;
|
||||||
|
virDomainGraphicsSpiceChannelNameTypeFromString;
|
||||||
|
virDomainGraphicsSpiceChannelNameTypeToString;
|
||||||
virDomainGraphicsTypeFromString;
|
virDomainGraphicsTypeFromString;
|
||||||
virDomainGraphicsTypeToString;
|
virDomainGraphicsTypeToString;
|
||||||
virDomainHostdevDefFree;
|
virDomainHostdevDefFree;
|
||||||
|
@ -5177,6 +5177,19 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
virBufferVSprintf(&opt, ",x509-dir=%s",
|
virBufferVSprintf(&opt, ",x509-dir=%s",
|
||||||
driver->spiceTLSx509certdir);
|
driver->spiceTLSx509certdir);
|
||||||
|
|
||||||
|
for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
|
||||||
|
int mode = def->graphics[0]->data.spice.channels[i];
|
||||||
|
switch (mode) {
|
||||||
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
||||||
|
virBufferVSprintf(&opt, ",tls-channel=%s",
|
||||||
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
||||||
|
break;
|
||||||
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
||||||
|
virBufferVSprintf(&opt, ",plaintext-channel=%s",
|
||||||
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (virBufferError(&opt))
|
if (virBufferError(&opt))
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
|
@ -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,x509-dir=/etc/pki/libvirt-spice -vga qxl -device qxl,id=video1,bus=pci.0,addr=0x4 -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,tls-channel=main,plaintext-channel=inputs -vga qxl -device qxl,id=video1,bus=pci.0,addr=0x4 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
|
||||||
|
@ -21,7 +21,10 @@
|
|||||||
</disk>
|
</disk>
|
||||||
<controller type='ide' index='0'/>
|
<controller type='ide' index='0'/>
|
||||||
<input type='mouse' bus='ps2'/>
|
<input type='mouse' bus='ps2'/>
|
||||||
<graphics type='spice' port='5903' tlsPort='5904' autoport='no' listen='127.0.0.1'/>
|
<graphics type='spice' port='5903' tlsPort='5904' autoport='no' listen='127.0.0.1'>
|
||||||
|
<channel name='main' mode='secure'/>
|
||||||
|
<channel name='inputs' mode='insecure'/>
|
||||||
|
</graphics>
|
||||||
<video>
|
<video>
|
||||||
<model type='qxl' vram='65536' heads='1'/>
|
<model type='qxl' vram='65536' heads='1'/>
|
||||||
</video>
|
</video>
|
||||||
|
Loading…
Reference in New Issue
Block a user