From d19d94db033ee5dbe0a736bf0714d8105cb10b10 Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Tue, 9 Mar 2010 17:59:45 +0000
Subject: [PATCH] KVM: add security model and domain parameters

Initially we only support the "user" model (in which the user running
the virtual machine can be specified as an additional parameter).

We use usernames rather than uids in this mode, because the kvm -runas
flag doesn't support uids anyway, and we check the passed username for
validity.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/constants.py         |  2 ++
 lib/hypervisor/hv_kvm.py | 41 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/lib/constants.py b/lib/constants.py
index d11fce022..2789beac5 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -700,6 +700,8 @@ HVC_DEFAULTS = {
     HV_MIGRATION_PORT: 8102,
     HV_USE_LOCALTIME: False,
     HV_DISK_CACHE: HT_CACHE_DEFAULT,
+    HV_SECURITY_MODEL: HT_SM_NONE,
+    HV_SECURITY_DOMAIN: '',
     },
   HT_FAKE: {
     },
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 2b42a0971..f0db81b78 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -29,6 +29,7 @@ import re
 import tempfile
 import time
 import logging
+import pwd
 from cStringIO import StringIO
 
 from ganeti import utils
@@ -76,6 +77,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
     constants.HV_DISK_CACHE:
       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
+    constants.HV_SECURITY_MODEL:
+      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
+    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
     }
 
   _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
@@ -325,6 +329,10 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
     boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
 
+    security_model = hvp[constants.HV_SECURITY_MODEL]
+    if security_model == constants.HT_SM_USER:
+      kvm_cmd.extend(['-runas', hvp[constants.HV_SECURITY_DOMAIN]])
+
     if boot_network:
       kvm_cmd.extend(['-boot', 'n'])
 
@@ -791,6 +799,39 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Cannot boot from cdrom without an"
                                    " ISO path")
 
+    security_model = hvparams[constants.HV_SECURITY_MODEL]
+    if security_model == constants.HT_SM_USER:
+      if not hvparams[constants.HV_SECURITY_DOMAIN]:
+        raise errors.HypervisorError("A security domain (user to run kvm as)"
+                                     " must be specified")
+    elif (security_model == constants.HT_SM_NONE or
+          security_model == constants.HT_SM_POOL):
+      if hvparams[constants.HV_SECURITY_DOMAIN]:
+        raise errors.HypervisorError("Cannot have a security domain when the"
+                                     " security model is 'none' or 'pool'")
+    if security_model == constants.HT_SM_POOL:
+      raise errors.HypervisorError("Security model pool is not supported yet")
+
+  @classmethod
+  def ValidateParameters(cls, hvparams):
+    """Check the given parameters for validity.
+
+    @type hvparams:  dict
+    @param hvparams: dictionary with parameter names/value
+    @raise errors.HypervisorError: when a parameter is not valid
+
+    """
+    super(KVMHypervisor, cls).ValidateParameters(hvparams)
+
+    security_model = hvparams[constants.HV_SECURITY_MODEL]
+    if security_model == constants.HT_SM_USER:
+      username = hvparams[constants.HV_SECURITY_DOMAIN]
+      try:
+        pwdentry = pwd.getpwnam(username)
+      except KeyError:
+        raise errors.HypervisorError("Unknown security domain user %s"
+                                     % username)
+
   @classmethod
   def PowercycleNode(cls):
     """KVM powercycle, just a wrapper over Linux powercycle.
-- 
GitLab