Added an optional parameter called spice_password_file that allows
the user to protect the SPICE login with the password contained in
the specified file.

Signed-off-by: Andrea Spadaccini <[email protected]>
---
 lib/constants.py         |    3 ++
 lib/hypervisor/hv_kvm.py |   47 +++++++++++++++++++++++++++++++++++++++++++--
 man/gnt-instance.rst     |    7 ++++++
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/lib/constants.py b/lib/constants.py
index 3cc6cb6..d945542 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -666,6 +666,7 @@ HV_VNC_X509 = "vnc_x509_path"
 HV_VNC_X509_VERIFY = "vnc_x509_verify"
 HV_KVM_SPICE_BIND = "spice_bind"
 HV_KVM_SPICE_IP_VERSION = "spice_ip_version"
+HV_KVM_SPICE_PASSWORD_FILE = "spice_password_file"
 HV_ACPI = "acpi"
 HV_PAE = "pae"
 HV_USE_BOOTLOADER = "use_bootloader"
@@ -711,6 +712,7 @@ HVS_PARAMETER_TYPES = {
   HV_VNC_X509_VERIFY: VTYPE_BOOL,
   HV_KVM_SPICE_BIND: VTYPE_STRING,
   HV_KVM_SPICE_IP_VERSION: VTYPE_INT,
+  HV_KVM_SPICE_PASSWORD_FILE: VTYPE_STRING,
   HV_ACPI: VTYPE_BOOL,
   HV_PAE: VTYPE_BOOL,
   HV_USE_BOOTLOADER: VTYPE_BOOL,
@@ -1291,6 +1293,7 @@ HVC_DEFAULTS = {
     HV_VNC_PASSWORD_FILE: "",
     HV_KVM_SPICE_BIND: "",
     HV_KVM_SPICE_IP_VERSION: IFACE_NO_IP_VERSION_SPECIFIED,
+    HV_KVM_SPICE_PASSWORD_FILE: "",
     HV_KVM_FLOPPY_IMAGE_PATH: "",
     HV_CDROM_IMAGE_PATH: "",
     HV_KVM_CDROM2_IMAGE_PATH: "",
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 622df48..14cb945 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -352,6 +352,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
                          x in constants.VALID_IP_VERSIONS),
        "the SPICE IP version should be 4 or 6",
        None, None),
+    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
     constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
     constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
     constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
@@ -949,8 +950,10 @@ class KVMHypervisor(hv_base.BaseHypervisor):
         # ValidateParameters checked it.
         spice_address = spice_bind
 
-      spice_arg = "addr=%s,port=%s,disable-ticketing" % (spice_address,
-                                                         instance.network_port)
+      spice_arg = "addr=%s,port=%s" % (spice_address, instance.network_port)
+      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
+        spice_arg = "%s,disable-ticketing" % spice_arg
+
       if spice_ip_version:
         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
 
@@ -1128,6 +1131,12 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       utils.EnsureDirs([(self._InstanceChrootDir(name),
                          constants.SECURE_DIR_MODE)])
 
+    # Automatically enable QMP if version is >= 0.14
+    if (v_major, v_min) >= (0, 14):
+      logging.debug("Enabling QMP")
+      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait"%
+                    self._InstanceQmpMonitor(instance.name)])
+
     # Configure the network now for starting instances and bridged interfaces,
     # during FinalizeMigration for incoming instances' routed interfaces
     for nic_seq, nic in enumerate(kvm_nics):
@@ -1164,6 +1173,26 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       change_cmd = "change vnc password %s" % vnc_pwd
       self._CallMonitorCommand(instance.name, change_cmd)
 
+    # Setting SPICE password. We are not vulnerable to malicious passwordless
+    # connection attempts because SPICE by default does not allow connections
+    # if neither a password nor the "disable_ticketing" options are specified.
+    # As soon as we send the password via QMP, that password is a valid ticket
+    # for connection.
+    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
+    if spice_password_file:
+      try:
+        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
+        qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
+        qmp.connect()
+        arguments = {
+            "protocol": "spice",
+            "password": spice_pwd,
+        }
+        qmp.Execute("set_password", arguments)
+      except EnvironmentError, err:
+        raise errors.HypervisorError("Failed to open SPICE password file %s: 
%s"
+                                     % (spice_password_file, err))
+
     for filename in temp_files:
       utils.RemoveFile(filename)
 
@@ -1486,8 +1515,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
                                      " security model is 'none' or 'pool'")
 
     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
+    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
+    spice_password_file = hvparams[constants.HV_KVM_SPICE_PASSWORD_FILE]
     if spice_bind:
-      spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
         # if an IP version is specified, the spice_bind parameter must be an
         # IP of that family
@@ -1502,6 +1532,17 @@ class KVMHypervisor(hv_base.BaseHypervisor):
           raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
                                        " the specified IP version is %s" %
                                        (spice_bind, spice_ip_version))
+    else:
+      if spice_ip_version:
+        raise errors.HypervisorError("spice: the %s option is useless"
+                                     " without %s" %
+                                     (constants.HV_KVM_SPICE_IP_VERSION,
+                                      constants.HV_KVM_SPICE_BIND))
+      if spice_password_file:
+        raise errors.HypervisorError("spice: the %s option is useless"
+                                     " without %s" %
+                                     (constants.HV_KVM_SPICE_PASSWORD_FILE,
+                                      constants.HV_KVM_SPICE_BIND))
 
   @classmethod
   def ValidateParameters(cls, hvparams):
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index 5d906a4..c3a0c92 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -300,6 +300,13 @@ spice\_ip\_version
     this case, if the ``spice_ip_version`` parameter is not used, the
     default IP version of the cluster will be used.
 
+spice\_password\_file
+    Valid for the KVM hypervisor.
+
+    Specifies a file containing the password that must be used when
+    connecting via the SPICE protocol. If the option is not specified,
+    passwordless connections are allowed.
+
 acpi
     Valid for the Xen HVM and KVM hypervisors.
 
-- 
1.7.3.1

Reply via email to