ia64/xen-unstable

annotate tools/python/xen/xend/XendXSPolicyAdmin.py @ 15548:aa640601575f

[Xen-API] Extension of the Xen-API for managing Xen Security Policies

This patch implements extensions for managing security policies in
xend. The XSPolicy and ACMPolicy classes provide the interface for the
Xen-API and implement functionality for setting, updating and
activating of a Xen security policy as well as labeling of virtual
machines and resources such as block devices. Labeling of network
devices will follow.

The acmpolicy class implements a compiler for translating an XML
policy into their binary format and provides functionality for
comparing a current policy against a new one when changing/updating a
policy.

The xspolicyadmin class administers the policy of the system.

Some of the xend-internal code deals with transforming the labeling
information from the S-Expression format into the new Xen-API
format. This is similar to much of the other code that is already
there.

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