ia64/xen-unstable

annotate tools/python/xen/xend/XendXSPolicyAdmin.py @ 15615:9c077fc8ccf1

[Xend] More security-related fixes

This patch provides some more fixes related to the recent
security-related extensions to xend.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Wed Jul 18 10:09:06 2007 +0100 (2007-07-18)
parents c64a59ff9880
children f1aed243f3f0
rev   line source
kfraser@15548 1 #============================================================================
kfraser@15548 2 # This library is free software; you can redistribute it and/or
kfraser@15548 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
kfraser@15548 4 # License as published by the Free Software Foundation.
kfraser@15548 5 #
kfraser@15548 6 # This library is distributed in the hope that it will be useful,
kfraser@15548 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
kfraser@15548 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kfraser@15548 9 # Lesser General Public License for more details.
kfraser@15548 10 #
kfraser@15548 11 # You should have received a copy of the GNU Lesser General Public
kfraser@15548 12 # License along with this library; if not, write to the Free Software
kfraser@15548 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kfraser@15548 14 #============================================================================
kfraser@15548 15 # Copyright (C) 2006,2007 International Business Machines Corp.
kfraser@15548 16 # Author: Stefan Berger <stefanb@us.ibm.com>
kfraser@15548 17 #============================================================================
kfraser@15548 18 import os
kfraser@15548 19 import shutil
kfraser@15548 20
kfraser@15548 21 from xml.dom import minidom, Node
kfraser@15548 22
kfraser@15548 23 from xen.xend.XendLogging import log
kfraser@15548 24 from xen.xend import uuid
kfraser@15548 25 from xen.util import security, xsconstants, dictio, bootloader
kfraser@15548 26 from xen.util.xspolicy import XSPolicy
kfraser@15548 27 from xen.util.acmpolicy import ACMPolicy
kfraser@15548 28 from xen.xend.XendError import SecurityError
kfraser@15548 29
kfraser@15548 30 XS_MANAGED_POLICIES_FILE = "/etc/xen/acm-security/policies/managed_policies"
kfraser@15548 31
kfraser@15548 32 class XSPolicyAdmin:
kfraser@15548 33 """ The class that handles the managed policies in the system.
kfraser@15548 34 Handles adding and removing managed policies. All managed
kfraser@15548 35 policies are handled using a reference (UUID) which is
kfraser@15548 36 assigned to the policy by this class.
kfraser@15548 37 """
kfraser@15548 38
kfraser@15548 39 def __init__(self, maxpolicies):
kfraser@15548 40 """ Create a management class for managing the system's
kfraser@15548 41 policies.
kfraser@15548 42
kfraser@15548 43 @param maxpolicies: The max. number of policies allowed
kfraser@15548 44 on the system (currently '1')
kfraser@15548 45 """
kfraser@15548 46 self.maxpolicies = maxpolicies
kfraser@15548 47 try:
kfraser@15548 48 self.policies = dictio.dict_read("managed_policies",
kfraser@15548 49 XS_MANAGED_POLICIES_FILE)
kfraser@15548 50 except Exception, e:
kfraser@15548 51 self.policies = {}
kfraser@15548 52
kfraser@15548 53 self.xsobjs = {}
kfraser@15548 54 for ref, data in self.policies.items():
kfraser@15548 55 name = data[0]
kfraser@15548 56 typ = data[1]
kfraser@15548 57 try:
kfraser@15548 58 if typ == xsconstants.ACM_POLICY_ID:
kfraser@15615 59 try:
kfraser@15615 60 self.xsobjs[ref] = ACMPolicy(name=name, ref=ref)
kfraser@15615 61 except Exception, e:
kfraser@15615 62 del self.policies[ref]
kfraser@15548 63 else:
kfraser@15548 64 del self.policies[ref]
kfraser@15548 65 except Exception, e:
kfraser@15548 66 log.error("XSPolicyAdmin: Could not find policy '%s': %s" %
kfraser@15548 67 (name, str(e)))
kfraser@15548 68 del self.policies[ref]
kfraser@15548 69 log.debug("XSPolicyAdmin: Known policies: %s" % self.policies)
kfraser@15548 70
kfraser@15548 71 def isXSEnabled(self):
kfraser@15548 72 """ Check whether 'security' is enabled on this system.
kfraser@15548 73 This currently only checks for ACM-enablement.
kfraser@15548 74 """
kfraser@15548 75 rc = 0
kfraser@15548 76 if security.on():
kfraser@15548 77 rc |= xsconstants.XS_POLICY_ACM
kfraser@15548 78 return rc
kfraser@15548 79
kfraser@15548 80 def add_acmpolicy_to_system(self, xmltext, flags, overwrite):
kfraser@15548 81 """ Add an ACM policy's xml representation to the system. The
kfraser@15548 82 policy will automatically be compiled
kfraser@15548 83 flags:
kfraser@15548 84 XS_INST_BOOT : make policy the one to boot the system with
kfraser@15548 85 by default; if there's a policy already installed,
kfraser@15548 86 refuse to install this policy unless its one with
kfraser@15548 87 the same name
kfraser@15548 88 XS_INST_LOAD : load the policy immediately; if this does not work
kfraser@15548 89 refuse to install this policy
kfraser@15548 90 overwrite:
kfraser@15548 91 If any policy is installed and this is False, refuse to install
kfraser@15548 92 this policy
kfraser@15548 93 If flags is True, then any existing policy will be removed from
kfraser@15548 94 the system and the new one will be installed
kfraser@15548 95 """
kfraser@15548 96 errors = ""
kfraser@15548 97 loadedpol = self.get_loaded_policy()
kfraser@15548 98 if loadedpol:
kfraser@15548 99 # This is meant as an update to a currently loaded policy
kfraser@15548 100 if flags & xsconstants.XS_INST_LOAD == 0:
kfraser@15548 101 raise SecurityError(-xsconstants.XSERR_POLICY_LOADED)
kfraser@15548 102 rc, errors = loadedpol.update(xmltext)
kfraser@15548 103 if rc == 0:
kfraser@15548 104 self.rm_bootpolicy()
kfraser@15548 105 irc = self.activate_xspolicy(loadedpol, flags)
kfraser@15548 106 return (loadedpol, rc, errors)
kfraser@15548 107
kfraser@15548 108 try:
kfraser@15548 109 dom = minidom.parseString(xmltext.encode("utf-8"))
kfraser@15548 110 except:
kfraser@15548 111 raise SecurityError(-xsconstants.XSERR_BAD_XML)
kfraser@15548 112
kfraser@15548 113 ref = uuid.createString()
kfraser@15548 114
kfraser@15548 115 acmpol = ACMPolicy(dom=dom, ref=ref)
kfraser@15548 116
kfraser@15548 117 #First some basic tests that do not modify anything:
kfraser@15548 118
kfraser@15548 119 if flags & xsconstants.XS_INST_BOOT and not overwrite:
kfraser@15548 120 filename = acmpol.get_filename(".bin","",dotted=True)
kfraser@15548 121 if bootloader.get_default_policy != None and \
kfraser@15548 122 not bootloader.loads_default_policy(filename):
kfraser@15548 123 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
kfraser@15548 124
kfraser@15548 125 if not overwrite and len(self.policies) >= self.maxpolicies:
kfraser@15548 126 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
kfraser@15548 127
kfraser@15548 128 if overwrite:
kfraser@15548 129 #This should only give one key since only one policy is
kfraser@15548 130 #allowed.
kfraser@15548 131 keys = self.policies.keys()
kfraser@15548 132 for k in keys:
kfraser@15548 133 self.rm_bootpolicy()
kfraser@15548 134 rc = self.rm_policy_from_system(k, force=overwrite)
kfraser@15548 135 if rc != xsconstants.XSERR_SUCCESS:
kfraser@15548 136 raise SecurityError(rc)
kfraser@15548 137
kfraser@15548 138 rc = acmpol.compile()
kfraser@15548 139 if rc != 0:
kfraser@15548 140 raise SecurityError(rc)
kfraser@15548 141
kfraser@15548 142 if flags & xsconstants.XS_INST_LOAD:
kfraser@15548 143 rc = acmpol.loadintohv()
kfraser@15548 144 if rc != 0:
kfraser@15548 145 raise SecurityError(rc)
kfraser@15548 146
kfraser@15548 147 if flags & xsconstants.XS_INST_BOOT:
kfraser@15548 148 rc = self.make_boot_policy(acmpol)
kfraser@15548 149 if rc != 0:
kfraser@15548 150 # If it cannot be installed due to unsupported
kfraser@15548 151 # bootloader, let it be ok.
kfraser@15548 152 pass
kfraser@15548 153
kfraser@15548 154 if dom:
kfraser@15548 155 new_entry = { ref : tuple([acmpol.get_name(),
kfraser@15548 156 xsconstants.ACM_POLICY_ID]) }
kfraser@15548 157 self.policies.update(new_entry)
kfraser@15548 158 self.xsobjs[ref] = acmpol
kfraser@15548 159 dictio.dict_write(self.policies,
kfraser@15548 160 "managed_policies",
kfraser@15548 161 XS_MANAGED_POLICIES_FILE)
kfraser@15548 162 return (acmpol, xsconstants.XSERR_SUCCESS, errors)
kfraser@15548 163
kfraser@15548 164 def make_boot_policy(self, acmpol):
kfraser@15548 165 spolfile = acmpol.get_filename(".bin")
kfraser@15548 166 dpolfile = "/boot/" + acmpol.get_filename(".bin","",dotted=True)
kfraser@15548 167 if not os.path.isfile(spolfile):
kfraser@15548 168 log.error("binary policy file does not exist.")
kfraser@15548 169 return -xsconstants.XSERR_FILE_ERROR
kfraser@15548 170 try:
kfraser@15548 171 shutil.copyfile(spolfile, dpolfile)
kfraser@15548 172 except:
kfraser@15548 173 return -xsconstants.XSERR_FILE_ERROR
kfraser@15548 174
kfraser@15548 175 try:
kfraser@15548 176 filename = acmpol.get_filename(".bin","",dotted=True)
kfraser@15548 177 if bootloader.set_default_boot_policy(filename) != True:
kfraser@15548 178 return xsconstants.XSERR_BOOTPOLICY_INSTALL_ERROR
kfraser@15548 179 except:
kfraser@15548 180 return xsconstants.XSERR_FILE_ERROR
kfraser@15548 181 return xsconstants.XSERR_SUCCESS
kfraser@15548 182
kfraser@15548 183 def activate_xspolicy(self, xspol, flags):
kfraser@15548 184 rc = xsconstants.XSERR_SUCCESS
kfraser@15548 185 if flags & xsconstants.XS_INST_LOAD:
kfraser@15548 186 rc = xspol.loadintohv()
kfraser@15548 187 if rc == xsconstants.XSERR_SUCCESS and \
kfraser@15548 188 flags & xsconstants.XS_INST_BOOT:
kfraser@15548 189 rc = self.make_boot_policy(xspol)
kfraser@15548 190 if rc == xsconstants.XSERR_SUCCESS:
kfraser@15548 191 rc = flags
kfraser@15548 192 return rc
kfraser@15548 193
kfraser@15548 194 def rm_policy_from_system(self, ref, force=False):
kfraser@15548 195 if self.policies.has_key(ref):
kfraser@15548 196 acmpol = self.xsobjs[ref]
kfraser@15548 197 rc = acmpol.destroy()
kfraser@15548 198 if rc == xsconstants.XSERR_SUCCESS or force:
kfraser@15548 199 del self.policies[ref]
kfraser@15548 200 del self.xsobjs[ref]
kfraser@15548 201 dictio.dict_write(self.policies,
kfraser@15548 202 "managed_policies",
kfraser@15548 203 XS_MANAGED_POLICIES_FILE)
kfraser@15548 204 rc = xsconstants.XSERR_SUCCESS
kfraser@15548 205 return rc
kfraser@15548 206
kfraser@15548 207 def rm_bootpolicy(self):
kfraser@15548 208 """ Remove any (ACM) boot policy from the grub configuration file
kfraser@15548 209 """
kfraser@15548 210 rc = 0
kfraser@15548 211 title = bootloader.get_default_title()
kfraser@15548 212 if title != None:
kfraser@15548 213 polnames = []
kfraser@15548 214 for (k, v) in self.xsobjs.items():
kfraser@15548 215 polnames.append(v.get_filename(".bin","",dotted=True))
kfraser@15548 216 bootloader.rm_policy_from_boottitle(title, polnames)
kfraser@15548 217 else:
kfraser@15548 218 rc = -xsconstants.XSERR_NO_DEFAULT_BOOT_TITLE
kfraser@15548 219 return rc
kfraser@15548 220
kfraser@15548 221 def get_policy_flags(self, acmpol):
kfraser@15548 222 """ Get the currently active flags of a policy, i.e., whether the
kfraser@15548 223 system is using this policy as its boot policy for the default
kfraser@15548 224 boot title.
kfraser@15548 225 """
kfraser@15548 226 flags = 0
kfraser@15548 227
kfraser@15548 228 filename = acmpol.get_filename(".bin","", dotted=True)
kfraser@15548 229 if bootloader.loads_default_policy(filename):
kfraser@15548 230 flags |= xsconstants.XS_INST_BOOT
kfraser@15548 231
kfraser@15548 232 if acmpol.isloaded():
kfraser@15548 233 flags |= xsconstants.XS_INST_LOAD
kfraser@15548 234 return flags
kfraser@15548 235
kfraser@15548 236 def get_policies(self):
kfraser@15548 237 """ Get all managed policies. """
kfraser@15548 238 return self.xsobjs.values()
kfraser@15548 239
kfraser@15548 240 def get_policies_refs(self):
kfraser@15548 241 """ Get all managed policies' references. """
kfraser@15548 242 return self.xsobjs.keys()
kfraser@15548 243
kfraser@15548 244 def has_ref(self, ref):
kfraser@15548 245 """ Check whether there is a policy with the given reference """
kfraser@15548 246 return self.xsobjs.has_key(ref)
kfraser@15548 247
kfraser@15548 248 def policy_from_ref(self, ref):
kfraser@15548 249 """ Get the policy's object given its reference """
kfraser@15548 250 if ref in self.xsobjs.keys():
kfraser@15548 251 return self.xsobjs[ref]
kfraser@15548 252 return None
kfraser@15548 253
kfraser@15548 254 def ref_from_polname(self, polname):
kfraser@15548 255 """ Get the reference of the policy given its name """
kfraser@15548 256 ref = None
kfraser@15548 257 for (k, v) in self.xsobjs.items():
kfraser@15548 258 if v.get_name() == polname:
kfraser@15548 259 ref = k
kfraser@15548 260 break
kfraser@15548 261 return ref
kfraser@15548 262
kfraser@15548 263 def lock_policy(self, ref):
kfraser@15548 264 """ get exclusive access to a policy """
kfraser@15548 265 self.xsobjs[ref].grab_lock()
kfraser@15548 266
kfraser@15548 267 def unlock_policy(self, ref):
kfraser@15548 268 """ release exclusive access to a policy """
kfraser@15548 269 self.xsobjs[ref].unlock()
kfraser@15548 270
kfraser@15548 271 def get_loaded_policy(self):
kfraser@15548 272 for pol in self.xsobjs.values():
kfraser@15548 273 if pol.isloaded():
kfraser@15548 274 return pol
kfraser@15548 275 return None
kfraser@15548 276
kfraser@15615 277 def get_hv_loaded_policy_name(self):
kfraser@15615 278 security.refresh_security_policy()
kfraser@15615 279 return security.active_policy
kfraser@15615 280
kfraser@15548 281 def get_policy_by_name(self, name):
kfraser@15548 282 for pol in self.xsobjs.values():
kfraser@15548 283 if pol.get_name() == name:
kfraser@15548 284 return pol
kfraser@15548 285 return None
kfraser@15548 286
kfraser@15548 287 def get_domain0_bootlabel(self):
kfraser@15548 288 """ Get the domain0 bootlabel from the default boot title """
kfraser@15548 289 title = ""
kfraser@15548 290 def_title = bootloader.get_default_title()
kfraser@15548 291 line = bootloader.get_kernel_val(def_title, "ssidref")
kfraser@15548 292 if line:
kfraser@15548 293 parms = line.split(":",1)
kfraser@15548 294 if len(parms) > 1:
kfraser@15548 295 title = parms[1]
kfraser@15548 296 return title
kfraser@15548 297
kfraser@15548 298 def set_domain0_bootlabel(self, xspol, label):
kfraser@15548 299 """ Set the domain-0 bootlabel under the given policy """
kfraser@15548 300 return xspol.set_vm_bootlabel(label)
kfraser@15548 301
kfraser@15548 302 def rm_domain0_bootlabel(self):
kfraser@15548 303 """ Remove the domain-0 bootlabel from the default boot title """
kfraser@15548 304 def_title = bootloader.get_default_title()
kfraser@15548 305 return bootloader.set_kernel_attval(def_title, "ssidref", None)
kfraser@15548 306
kfraser@15548 307 def ssidref_to_vmlabel(self, ssidref):
kfraser@15548 308 """ Given an ssidref, return the vmlabel under the current policy """
kfraser@15548 309 vmlabel = ""
kfraser@15548 310 pol = self.get_loaded_policy()
kfraser@15548 311 if pol:
kfraser@15548 312 vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref)
kfraser@15548 313 return vmlabel
kfraser@15548 314
kfraser@15548 315 poladmin = None
kfraser@15548 316
kfraser@15548 317 def XSPolicyAdminInstance(maxpolicies=1):
kfraser@15548 318 global poladmin
kfraser@15548 319 if poladmin == None:
kfraser@15548 320 poladmin = XSPolicyAdmin(maxpolicies)
kfraser@15551 321 return poladmin