This extends the SPICE XML to allow channel security options <graphics type='spice' port='5901' 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 --- docs/schemas/domain.rng | 21 ++++++ src/conf/domain_conf.c | 75 +++++++++++++++++++- src/conf/domain_conf.h | 21 ++++++ src/libvirt_private.syms | 4 + src/qemu/qemu_conf.c | 13 ++++ .../qemuxml2argv-graphics-spice-rhel6.args | 2 +- .../qemuxml2argv-graphics-spice-rhel6.xml | 5 +- 7 files changed, 138 insertions(+), 3 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index edd0b7c..17d7b88 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1012,6 +1012,27 @@ <text/> </attribute> </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> <attribute name="type"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index eee78b1..ffc446f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -218,6 +218,21 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST, "desktop", "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, "subsystem", "capabilities") @@ -2920,6 +2935,7 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { def->data.desktop.display = virXMLPropString(node, "display"); } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { + xmlNodePtr cur; char *port = virXMLPropString(node, "port"); char *tlsPort; char *autoport; @@ -2964,6 +2980,40 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { def->data.spice.keymap = virXMLPropString(node, "keymap"); if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0) 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: @@ -5706,6 +5756,8 @@ virDomainGraphicsDefFormat(virBufferPtr buf, int flags) { const char *type = virDomainGraphicsTypeToString(def->type); + int children = 0; + int i; if (!type) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -5811,7 +5863,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; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bbd7e84..d7ea1e0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -485,6 +485,24 @@ struct _virDomainGraphicsAuthDef { 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 virDomainGraphicsDef *virDomainGraphicsDefPtr; @@ -521,6 +539,7 @@ struct _virDomainGraphicsDef { char *keymap; virDomainGraphicsAuthDef auth; unsigned int autoport :1; + int channels[VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST]; } spice; } data; }; @@ -1103,6 +1122,8 @@ VIR_ENUM_DECL(virDomainHostdevSubsys) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) +VIR_ENUM_DECL(virDomainGraphicsSpiceChannelName) +VIR_ENUM_DECL(virDomainGraphicsSpiceChannelMode) /* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainSeclabel) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7950bcd..f1a91f7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -146,6 +146,10 @@ virDomainGetRootFilesystem; virDomainGraphicsTypeFromString; virDomainGraphicsTypeToString; virDomainGraphicsDefFree; +virDomainGraphicsSpiceChannelNameTypeFromString; +virDomainGraphicsSpiceChannelNameTypeToString; +virDomainGraphicsSpiceChannelModeTypeFromString; +virDomainGraphicsSpiceChannelModeTypeToString; virDomainHostdevDefFree; virDomainHostdevModeTypeToString; virDomainHostdevSubsysTypeToString; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 78778ef..31214b1 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -4519,6 +4519,19 @@ int qemudBuildCommandLine(virConnectPtr conn, virBufferVSprintf(&opt, ",x509-dir=%s", 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)) goto no_memory; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args index 44809b0..87b8c06 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args @@ -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 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.xml b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.xml index 6fe9a60..bdce04b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.xml @@ -21,7 +21,10 @@ </disk> <controller type='ide' index='0'/> <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> <model type='qxl' vram='65536' heads='1'/> </video> -- 1.6.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list