ia64/xen-unstable

annotate tools/python/xen/xend/XendXSPolicyAdmin.py @ 16522:54482c56e435

Implement legacy XML-RPC interface for ACM commands.

This patch moves the directory of files where xend is writing policies
and resource labels into to /var/lib/xend/security/policies.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 05 09:45:13 2007 +0000 (2007-12-05)
parents 5255eac35270
children 3221dff4b460
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
keir@16522 25 from xen.util import xsconstants, bootloader
kfraser@15817 26 import xen.util.xsm.acm.acm as security
kfraser@15548 27 from xen.util.xspolicy import XSPolicy
keir@16522 28 from xen.util.acmpolicy import ACMPolicy, initialize
kfraser@15548 29 from xen.xend.XendError import SecurityError
kfraser@15548 30
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
keir@16219 47 self.policies = {}
kfraser@15548 48 self.xsobjs = {}
keir@16219 49
keir@16219 50 act_pol_name = self.get_hv_loaded_policy_name()
keir@16522 51 initialize()
keir@16219 52
keir@16219 53 ref = uuid.createString()
keir@16219 54 try:
keir@16219 55 self.xsobjs[ref] = ACMPolicy(name=act_pol_name, ref=ref)
keir@16219 56 self.policies[ref] = (act_pol_name, xsconstants.ACM_POLICY_ID)
keir@16219 57 except Exception, e:
keir@16219 58 log.error("Could not find XML representation of policy '%s': "
keir@16219 59 "%s" % (act_pol_name,e))
keir@16219 60
kfraser@15548 61 log.debug("XSPolicyAdmin: Known policies: %s" % self.policies)
kfraser@15548 62
keir@16522 63
kfraser@15548 64 def isXSEnabled(self):
kfraser@15548 65 """ Check whether 'security' is enabled on this system.
kfraser@15548 66 This currently only checks for ACM-enablement.
kfraser@15548 67 """
kfraser@15548 68 rc = 0
kfraser@15548 69 if security.on():
kfraser@15548 70 rc |= xsconstants.XS_POLICY_ACM
kfraser@15548 71 return rc
kfraser@15548 72
kfraser@15548 73 def add_acmpolicy_to_system(self, xmltext, flags, overwrite):
kfraser@15548 74 """ Add an ACM policy's xml representation to the system. The
kfraser@15548 75 policy will automatically be compiled
kfraser@15548 76 flags:
kfraser@15548 77 XS_INST_BOOT : make policy the one to boot the system with
kfraser@15548 78 by default; if there's a policy already installed,
kfraser@15548 79 refuse to install this policy unless its one with
kfraser@15548 80 the same name
kfraser@15548 81 XS_INST_LOAD : load the policy immediately; if this does not work
kfraser@15548 82 refuse to install this policy
kfraser@15548 83 overwrite:
kfraser@15548 84 If any policy is installed and this is False, refuse to install
kfraser@15548 85 this policy
kfraser@15548 86 If flags is True, then any existing policy will be removed from
kfraser@15548 87 the system and the new one will be installed
kfraser@15548 88 """
keir@16081 89 from xen.xend import XendDomain
keir@16081 90 domains = XendDomain.instance()
keir@16081 91 try:
keir@16081 92 domains.domains_lock.acquire()
keir@16081 93 return self.__add_acmpolicy_to_system(xmltext, flags, overwrite)
keir@16081 94 finally:
keir@16081 95 domains.domains_lock.release()
keir@16081 96
keir@16081 97 def __add_acmpolicy_to_system(self, xmltext, flags, overwrite):
kfraser@15548 98 errors = ""
kfraser@15548 99 loadedpol = self.get_loaded_policy()
kfraser@15548 100 if loadedpol:
kfraser@15548 101 # This is meant as an update to a currently loaded policy
kfraser@15548 102 if flags & xsconstants.XS_INST_LOAD == 0:
kfraser@15548 103 raise SecurityError(-xsconstants.XSERR_POLICY_LOADED)
keir@16522 104
keir@16522 105 # Remember old flags, so they can be restored if update fails
keir@16522 106 old_flags = self.get_policy_flags(loadedpol)
keir@16522 107
keir@16522 108 # Remove policy from bootloader in case of new name of policy
keir@16522 109 self.rm_bootpolicy()
keir@16522 110
kfraser@15548 111 rc, errors = loadedpol.update(xmltext)
kfraser@15548 112 if rc == 0:
kfraser@15548 113 irc = self.activate_xspolicy(loadedpol, flags)
keir@16219 114 # policy is loaded; if setting the boot flag fails it's ok.
keir@16522 115 else:
keir@16522 116 old_flags = old_flags & xsconstants.XS_INST_BOOT
keir@16522 117 log.info("OLD FLAGS TO RESTORE: %s" % str(old_flags))
keir@16522 118 if old_flags != 0:
keir@16522 119 self.activate_xspolicy(loadedpol, xsconstants.XS_INST_BOOT)
keir@16522 120
kfraser@15548 121 return (loadedpol, rc, errors)
kfraser@15548 122
kfraser@15548 123 try:
kfraser@15548 124 dom = minidom.parseString(xmltext.encode("utf-8"))
kfraser@15548 125 except:
kfraser@15548 126 raise SecurityError(-xsconstants.XSERR_BAD_XML)
kfraser@15548 127
kfraser@15548 128 ref = uuid.createString()
kfraser@15548 129
kfraser@15548 130 acmpol = ACMPolicy(dom=dom, ref=ref)
kfraser@15548 131
kfraser@15548 132 #First some basic tests that do not modify anything:
kfraser@15548 133
kfraser@15548 134 if flags & xsconstants.XS_INST_BOOT and not overwrite:
kfraser@15548 135 filename = acmpol.get_filename(".bin","",dotted=True)
kfraser@15548 136 if bootloader.get_default_policy != None and \
kfraser@15548 137 not bootloader.loads_default_policy(filename):
kfraser@15548 138 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
kfraser@15548 139
kfraser@15548 140 if not overwrite and len(self.policies) >= self.maxpolicies:
kfraser@15548 141 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
kfraser@15548 142
kfraser@15548 143 if overwrite:
kfraser@15548 144 #This should only give one key since only one policy is
kfraser@15548 145 #allowed.
kfraser@15548 146 keys = self.policies.keys()
kfraser@15548 147 for k in keys:
kfraser@15548 148 self.rm_bootpolicy()
kfraser@15548 149 rc = self.rm_policy_from_system(k, force=overwrite)
kfraser@15548 150 if rc != xsconstants.XSERR_SUCCESS:
kfraser@15548 151 raise SecurityError(rc)
kfraser@15548 152
kfraser@15548 153 rc = acmpol.compile()
kfraser@15548 154 if rc != 0:
kfraser@15548 155 raise SecurityError(rc)
kfraser@15548 156
kfraser@15548 157 if flags & xsconstants.XS_INST_LOAD:
kfraser@15548 158 rc = acmpol.loadintohv()
kfraser@15548 159 if rc != 0:
kfraser@15548 160 raise SecurityError(rc)
kfraser@15548 161
kfraser@15548 162 if flags & xsconstants.XS_INST_BOOT:
kfraser@15548 163 rc = self.make_boot_policy(acmpol)
kfraser@15548 164 if rc != 0:
kfraser@15548 165 # If it cannot be installed due to unsupported
kfraser@15548 166 # bootloader, let it be ok.
kfraser@15548 167 pass
kfraser@15548 168
kfraser@15548 169 if dom:
kfraser@15548 170 new_entry = { ref : tuple([acmpol.get_name(),
kfraser@15548 171 xsconstants.ACM_POLICY_ID]) }
kfraser@15548 172 self.policies.update(new_entry)
kfraser@15548 173 self.xsobjs[ref] = acmpol
kfraser@15548 174 return (acmpol, xsconstants.XSERR_SUCCESS, errors)
kfraser@15548 175
kfraser@15548 176 def make_boot_policy(self, acmpol):
keir@16522 177 if acmpol.is_default_policy():
keir@16522 178 return xsconstants.XSERR_SUCCESS
keir@16522 179 rc = acmpol.copy_policy_file(".bin","/boot")
keir@16522 180 if rc != xsconstants.XSERR_SUCCESS:
keir@16522 181 return rc
kfraser@15548 182
kfraser@15548 183 try:
kfraser@15548 184 filename = acmpol.get_filename(".bin","",dotted=True)
kfraser@15548 185 if bootloader.set_default_boot_policy(filename) != True:
kfraser@15548 186 return xsconstants.XSERR_BOOTPOLICY_INSTALL_ERROR
kfraser@15548 187 except:
kfraser@15548 188 return xsconstants.XSERR_FILE_ERROR
kfraser@15548 189 return xsconstants.XSERR_SUCCESS
kfraser@15548 190
kfraser@15548 191 def activate_xspolicy(self, xspol, flags):
keir@16081 192 from xen.xend import XendDomain
keir@16081 193 domains = XendDomain.instance()
keir@16081 194 try:
keir@16081 195 domains.domains_lock.acquire()
keir@16081 196 return self.__activate_xspolicy(xspol, flags)
keir@16081 197 finally:
keir@16081 198 domains.domains_lock.release()
keir@16081 199
keir@16081 200 def __activate_xspolicy(self, xspol, flags):
kfraser@15548 201 rc = xsconstants.XSERR_SUCCESS
kfraser@15548 202 if flags & xsconstants.XS_INST_LOAD:
kfraser@15548 203 rc = xspol.loadintohv()
kfraser@15548 204 if rc == xsconstants.XSERR_SUCCESS and \
kfraser@15548 205 flags & xsconstants.XS_INST_BOOT:
kfraser@15548 206 rc = self.make_boot_policy(xspol)
kfraser@15548 207 if rc == xsconstants.XSERR_SUCCESS:
kfraser@15548 208 rc = flags
kfraser@15548 209 return rc
kfraser@15548 210
kfraser@15548 211 def rm_policy_from_system(self, ref, force=False):
kfraser@15548 212 if self.policies.has_key(ref):
kfraser@15548 213 acmpol = self.xsobjs[ref]
kfraser@15548 214 rc = acmpol.destroy()
kfraser@15548 215 if rc == xsconstants.XSERR_SUCCESS or force:
kfraser@15548 216 del self.policies[ref]
kfraser@15548 217 del self.xsobjs[ref]
kfraser@15548 218 rc = xsconstants.XSERR_SUCCESS
kfraser@15548 219 return rc
kfraser@15548 220
kfraser@15548 221 def rm_bootpolicy(self):
kfraser@15548 222 """ Remove any (ACM) boot policy from the grub configuration file
kfraser@15548 223 """
kfraser@15548 224 rc = 0
kfraser@15548 225 title = bootloader.get_default_title()
kfraser@15548 226 if title != None:
kfraser@15548 227 polnames = []
kfraser@15548 228 for (k, v) in self.xsobjs.items():
kfraser@15548 229 polnames.append(v.get_filename(".bin","",dotted=True))
kfraser@15548 230 bootloader.rm_policy_from_boottitle(title, polnames)
kfraser@15548 231 else:
kfraser@15548 232 rc = -xsconstants.XSERR_NO_DEFAULT_BOOT_TITLE
kfraser@15548 233 return rc
kfraser@15548 234
kfraser@15548 235 def get_policy_flags(self, acmpol):
kfraser@15548 236 """ Get the currently active flags of a policy, i.e., whether the
kfraser@15548 237 system is using this policy as its boot policy for the default
kfraser@15548 238 boot title.
kfraser@15548 239 """
kfraser@15548 240 flags = 0
kfraser@15548 241
kfraser@15548 242 filename = acmpol.get_filename(".bin","", dotted=True)
keir@16522 243 if bootloader.loads_default_policy(filename) or \
keir@16522 244 acmpol.is_default_policy():
kfraser@15548 245 flags |= xsconstants.XS_INST_BOOT
kfraser@15548 246
kfraser@15548 247 if acmpol.isloaded():
kfraser@15548 248 flags |= xsconstants.XS_INST_LOAD
kfraser@15548 249 return flags
kfraser@15548 250
kfraser@15548 251 def get_policies(self):
kfraser@15548 252 """ Get all managed policies. """
kfraser@15548 253 return self.xsobjs.values()
kfraser@15548 254
kfraser@15548 255 def get_policies_refs(self):
kfraser@15548 256 """ Get all managed policies' references. """
kfraser@15548 257 return self.xsobjs.keys()
kfraser@15548 258
kfraser@15548 259 def has_ref(self, ref):
kfraser@15548 260 """ Check whether there is a policy with the given reference """
kfraser@15548 261 return self.xsobjs.has_key(ref)
kfraser@15548 262
kfraser@15548 263 def policy_from_ref(self, ref):
kfraser@15548 264 """ Get the policy's object given its reference """
kfraser@15548 265 if ref in self.xsobjs.keys():
kfraser@15548 266 return self.xsobjs[ref]
kfraser@15548 267 return None
kfraser@15548 268
kfraser@15548 269 def ref_from_polname(self, polname):
kfraser@15548 270 """ Get the reference of the policy given its name """
kfraser@15548 271 ref = None
kfraser@15548 272 for (k, v) in self.xsobjs.items():
kfraser@15548 273 if v.get_name() == polname:
kfraser@15548 274 ref = k
kfraser@15548 275 break
kfraser@15548 276 return ref
kfraser@15548 277
kfraser@15548 278 def lock_policy(self, ref):
kfraser@15548 279 """ get exclusive access to a policy """
kfraser@15548 280 self.xsobjs[ref].grab_lock()
kfraser@15548 281
kfraser@15548 282 def unlock_policy(self, ref):
kfraser@15548 283 """ release exclusive access to a policy """
kfraser@15548 284 self.xsobjs[ref].unlock()
kfraser@15548 285
kfraser@15548 286 def get_loaded_policy(self):
kfraser@15548 287 for pol in self.xsobjs.values():
kfraser@15548 288 if pol.isloaded():
kfraser@15548 289 return pol
kfraser@15548 290 return None
kfraser@15548 291
kfraser@15615 292 def get_hv_loaded_policy_name(self):
keir@16521 293 return security.get_active_policy_name()
kfraser@15615 294
kfraser@15548 295 def get_policy_by_name(self, name):
kfraser@15548 296 for pol in self.xsobjs.values():
kfraser@15548 297 if pol.get_name() == name:
kfraser@15548 298 return pol
kfraser@15548 299 return None
kfraser@15548 300
kfraser@15548 301 def get_domain0_bootlabel(self):
kfraser@15548 302 """ Get the domain0 bootlabel from the default boot title """
kfraser@15548 303 title = ""
kfraser@15548 304 def_title = bootloader.get_default_title()
kfraser@15548 305 line = bootloader.get_kernel_val(def_title, "ssidref")
kfraser@15548 306 if line:
kfraser@15548 307 parms = line.split(":",1)
kfraser@15548 308 if len(parms) > 1:
kfraser@15548 309 title = parms[1]
kfraser@15548 310 return title
kfraser@15548 311
kfraser@15548 312 def set_domain0_bootlabel(self, xspol, label):
keir@16521 313 """ Set the domain-0 bootlabel under the given policy. If the
keir@16521 314 current policy is the default policy, it will remove it. """
keir@16521 315 rm_entry = (xspol.get_name() == "DEFAULT")
keir@16521 316 return xspol.set_vm_bootlabel(label, rm_entry)
kfraser@15548 317
kfraser@15548 318 def rm_domain0_bootlabel(self):
kfraser@15548 319 """ Remove the domain-0 bootlabel from the default boot title """
kfraser@15548 320 def_title = bootloader.get_default_title()
kfraser@15548 321 return bootloader.set_kernel_attval(def_title, "ssidref", None)
kfraser@15548 322
kfraser@15548 323 def ssidref_to_vmlabel(self, ssidref):
kfraser@15548 324 """ Given an ssidref, return the vmlabel under the current policy """
kfraser@15548 325 vmlabel = ""
kfraser@15548 326 pol = self.get_loaded_policy()
kfraser@15548 327 if pol:
kfraser@15548 328 vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref)
kfraser@15548 329 return vmlabel
kfraser@15548 330
kfraser@15625 331 def get_stes_of_vmlabel(self, vmlabel_xapi):
kfraser@15625 332 """ Get the list of STEs given a VM label in XenAPI format """
kfraser@15625 333 stes = []
kfraser@15625 334 loadedpol = self.get_loaded_policy()
kfraser@15625 335 if loadedpol:
kfraser@15625 336 tmp = vmlabel_xapi.split(":")
kfraser@15625 337 if len(tmp) != 3:
kfraser@15625 338 return []
kfraser@15625 339 stes = loadedpol.policy_get_stes_of_vmlabel(tmp[2])
kfraser@15625 340 return stes
kfraser@15625 341
keir@16051 342 def get_enforced_binary(self, xstype):
keir@16051 343 res = None
keir@16051 344 if xstype == xsconstants.XS_POLICY_ACM:
keir@16051 345 res = ACMPolicy.get_enforced_binary()
keir@16051 346 return res
kfraser@15625 347
kfraser@15548 348 poladmin = None
kfraser@15548 349
kfraser@15548 350 def XSPolicyAdminInstance(maxpolicies=1):
kfraser@15548 351 global poladmin
kfraser@15548 352 if poladmin == None:
kfraser@15548 353 poladmin = XSPolicyAdmin(maxpolicies)
kfraser@15551 354 return poladmin