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:
Daniel P. Berrange 2010-04-09 17:56:00 +01:00
parent 6794a44b85
commit b0ef5c5367
8 changed files with 153 additions and 3 deletions

View File

@ -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 &lt;channel&gt; elements inside
the main &lt;graphics&gt; 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>
&lt;graphics type='spice' port='-1' tlsPort='-1' autoport='yes'&gt;
&lt;channel name='main' mode='secure'/&gt;
&lt;channel name='record' mode='insecure'/&gt;
&lt;/graphics&gt;</pre>
</dd> </dd>
<dt><code>"rdp"</code></dt> <dt><code>"rdp"</code></dt>
<dd> <dd>

View File

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

View File

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

View File

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

View File

@ -204,6 +204,10 @@ virDomainFindByName;
virDomainFindByUUID; virDomainFindByUUID;
virDomainGetRootFilesystem; virDomainGetRootFilesystem;
virDomainGraphicsDefFree; virDomainGraphicsDefFree;
virDomainGraphicsSpiceChannelModeTypeFromString;
virDomainGraphicsSpiceChannelModeTypeToString;
virDomainGraphicsSpiceChannelNameTypeFromString;
virDomainGraphicsSpiceChannelNameTypeToString;
virDomainGraphicsTypeFromString; virDomainGraphicsTypeFromString;
virDomainGraphicsTypeToString; virDomainGraphicsTypeToString;
virDomainHostdevDefFree; virDomainHostdevDefFree;

View File

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

View File

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

View File

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