ia64/xen-unstable

annotate tools/python/xen/xend/XendXSPolicyAdmin.py @ 16521:5255eac35270

Implement legacy XML-RPC interface for ACM commands.

This patch implements a (non Xen-API) legacy XML-RPC interface for the
ACM commands and funnels the calls into code introduced by the Xen-API
support for ACM security management. Since some of the functionality
has changed, also the xm applications have changed. In particular the
following old commands have been removed along with some tools the
have become obsolete now:

- loadpolicy (included in: setpolicy)
- makepolicy (included in: setpolicy)
- cfgbootpolicy (included in: setpolicy)

and the following commands been introduced:

- setpolicy
- getpolicy
- resetpolicy

All tools have been adapted to work in Xen-API and legacy XML-RPC
mode. Both modes support the same functionality.

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