]> xenbits.xensource.com Git - libvirt.git/commitdiff
Support SPICE channel security options
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 9 Apr 2010 16:56:00 +0000 (17:56 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 9 Nov 2010 11:47:26 +0000 (11:47 +0000)
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

docs/formatdomain.html.in
docs/schemas/domain.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms
src/qemu/qemu_conf.c
tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.xml

index a4ff500e576a99598e273552b6b9a025d8bb1ae8..8db8b52b25bacdeeb64b6f4fe0ca9eaa7d23bb68 100644 (file)
@@ -1108,6 +1108,7 @@ qemu-kvm -net nic,model=? /dev/null
           </dd>
           <dt><code>"spice"</code></dt>
           <dd>
+           <p>
   Starts a SPICE server. The <code>port</code> attribute specifies the TCP
   port number (with -1 as legacy syntax indicating that it should be
   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
   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.
+           </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>
           <dt><code>"rdp"</code></dt>
           <dd>
index 79030006801b2a2e743452b37f14d019db005581..5b7ecc2a9f0fa6f23c4636cc6f4e3acc087184a5 100644 (file)
               <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">
index b9e4f4c6fdb419980866dd5d97be0ad1a7730048..655449c7f6aff7812b604ce2b8661d20022e5691 100644 (file)
@@ -271,6 +271,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")
@@ -3274,6 +3289,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;
@@ -3318,6 +3334,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:
@@ -6572,6 +6622,8 @@ virDomainGraphicsDefFormat(virBufferPtr buf,
                            int flags)
 {
     const char *type = virDomainGraphicsTypeToString(def->type);
+    int children = 0;
+    int i;
 
     if (!type) {
         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;
 }
index d66aaa3232ae4b2de9354de5b925e93d3a6bd219..7d2d6f5edcfea4c9cef2ad67bc02aea634c21732 100644 (file)
@@ -525,6 +525,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;
@@ -561,6 +579,7 @@ struct _virDomainGraphicsDef {
             char *keymap;
             virDomainGraphicsAuthDef auth;
             unsigned int autoport :1;
+            int channels[VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST];
         } spice;
     } data;
 };
@@ -1234,6 +1253,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)
index 8f267f6f2aceb0bf1bf7e328529e44b57cb72d96..39eb6489bdc50ce66229d7e106d8b76306364153 100644 (file)
@@ -204,6 +204,10 @@ virDomainFindByName;
 virDomainFindByUUID;
 virDomainGetRootFilesystem;
 virDomainGraphicsDefFree;
+virDomainGraphicsSpiceChannelModeTypeFromString;
+virDomainGraphicsSpiceChannelModeTypeToString;
+virDomainGraphicsSpiceChannelNameTypeFromString;
+virDomainGraphicsSpiceChannelNameTypeToString;
 virDomainGraphicsTypeFromString;
 virDomainGraphicsTypeToString;
 virDomainHostdevDefFree;
index 32b486b01242c1d511e6a34709c3033b3f830af7..9e6e16262386ed5d21eff2f3c63bdfce375eaba9 100644 (file)
@@ -5177,6 +5177,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;
index 44809b040d815b7ee5158855ff19394d7f1eb7f5..87b8c0646a058ba7547f99f253a4a9ba8c38c838 100644 (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
index 6fe9a60c0669ee18e10daf22d5fd75494e30eff5..bdce04b3771c0bbd866aa832d564b1f0d7f8ea08 100644 (file)
     </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>