ia64/xen-unstable

view tools/python/xen/xend/XendXSPolicyAdmin.py @ 16547:3221dff4b460

ACM: Recover if XML policy representation is missing.

Recover the system if the XML representation of the currently loaded
policy is missing. Force the installation of the DEFAULT policy.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Dec 06 12:13:12 2007 +0000 (2007-12-06)
parents 54482c56e435
children 433f6a6a862a
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2006,2007 International Business Machines Corp.
16 # Author: Stefan Berger <stefanb@us.ibm.com>
17 #============================================================================
18 import os
19 import shutil
21 from xml.dom import minidom, Node
23 from xen.xend.XendLogging import log
24 from xen.xend import uuid
25 from xen.util import xsconstants, bootloader
26 import xen.util.xsm.acm.acm as security
27 from xen.util.xspolicy import XSPolicy
28 from xen.util.acmpolicy import ACMPolicy, initialize
29 from xen.xend.XendError import SecurityError
32 class XSPolicyAdmin:
33 """ The class that handles the managed policies in the system.
34 Handles adding and removing managed policies. All managed
35 policies are handled using a reference (UUID) which is
36 assigned to the policy by this class.
37 """
39 def __init__(self, maxpolicies):
40 """ Create a management class for managing the system's
41 policies.
43 @param maxpolicies: The max. number of policies allowed
44 on the system (currently '1')
45 """
46 self.maxpolicies = maxpolicies
47 self.policies = {}
48 self.xsobjs = {}
50 act_pol_name = self.get_hv_loaded_policy_name()
51 initialize()
53 ref = uuid.createString()
54 try:
55 self.xsobjs[ref] = ACMPolicy(name=act_pol_name, ref=ref)
56 self.policies[ref] = (act_pol_name, xsconstants.ACM_POLICY_ID)
57 except Exception, e:
58 log.error("Could not find XML representation of policy '%s': "
59 "%s" % (act_pol_name,e))
60 rc, errors, acmpol_def = ACMPolicy.force_default_policy()
61 if rc == xsconstants.XSERR_SUCCESS:
62 self.xsobjs[ref] = acmpol_def
63 self.policies[ref] = (acmpol_def.get_name(),
64 xsconstants.ACM_POLICY_ID)
65 log.info("Switched to DEFAULT policy.")
67 log.debug("XSPolicyAdmin: Known policies: %s" % self.policies)
70 def isXSEnabled(self):
71 """ Check whether 'security' is enabled on this system.
72 This currently only checks for ACM-enablement.
73 """
74 rc = 0
75 if security.on():
76 rc |= xsconstants.XS_POLICY_ACM
77 return rc
79 def add_acmpolicy_to_system(self, xmltext, flags, overwrite):
80 """ Add an ACM policy's xml representation to the system. The
81 policy will automatically be compiled
82 flags:
83 XS_INST_BOOT : make policy the one to boot the system with
84 by default; if there's a policy already installed,
85 refuse to install this policy unless its one with
86 the same name
87 XS_INST_LOAD : load the policy immediately; if this does not work
88 refuse to install this policy
89 overwrite:
90 If any policy is installed and this is False, refuse to install
91 this policy
92 If flags is True, then any existing policy will be removed from
93 the system and the new one will be installed
94 """
95 from xen.xend import XendDomain
96 domains = XendDomain.instance()
97 try:
98 domains.domains_lock.acquire()
99 return self.__add_acmpolicy_to_system(xmltext, flags, overwrite)
100 finally:
101 domains.domains_lock.release()
103 def __add_acmpolicy_to_system(self, xmltext, flags, overwrite):
104 errors = ""
105 loadedpol = self.get_loaded_policy()
106 if loadedpol:
107 # This is meant as an update to a currently loaded policy
108 if flags & xsconstants.XS_INST_LOAD == 0:
109 raise SecurityError(-xsconstants.XSERR_POLICY_LOADED)
111 # Remember old flags, so they can be restored if update fails
112 old_flags = self.get_policy_flags(loadedpol)
114 # Remove policy from bootloader in case of new name of policy
115 self.rm_bootpolicy()
117 rc, errors = loadedpol.update(xmltext)
118 if rc == 0:
119 irc = self.activate_xspolicy(loadedpol, flags)
120 # policy is loaded; if setting the boot flag fails it's ok.
121 else:
122 old_flags = old_flags & xsconstants.XS_INST_BOOT
123 log.info("OLD FLAGS TO RESTORE: %s" % str(old_flags))
124 if old_flags != 0:
125 self.activate_xspolicy(loadedpol, xsconstants.XS_INST_BOOT)
127 return (loadedpol, rc, errors)
129 try:
130 dom = minidom.parseString(xmltext.encode("utf-8"))
131 except:
132 raise SecurityError(-xsconstants.XSERR_BAD_XML)
134 ref = uuid.createString()
136 acmpol = ACMPolicy(dom=dom, ref=ref)
138 #First some basic tests that do not modify anything:
140 if flags & xsconstants.XS_INST_BOOT and not overwrite:
141 filename = acmpol.get_filename(".bin","",dotted=True)
142 if bootloader.get_default_policy != None and \
143 not bootloader.loads_default_policy(filename):
144 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
146 if not overwrite and len(self.policies) >= self.maxpolicies:
147 raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
149 if overwrite:
150 #This should only give one key since only one policy is
151 #allowed.
152 keys = self.policies.keys()
153 for k in keys:
154 self.rm_bootpolicy()
155 rc = self.rm_policy_from_system(k, force=overwrite)
156 if rc != xsconstants.XSERR_SUCCESS:
157 raise SecurityError(rc)
159 rc = acmpol.compile()
160 if rc != 0:
161 raise SecurityError(rc)
163 if flags & xsconstants.XS_INST_LOAD:
164 rc = acmpol.loadintohv()
165 if rc != 0:
166 raise SecurityError(rc)
168 if flags & xsconstants.XS_INST_BOOT:
169 rc = self.make_boot_policy(acmpol)
170 if rc != 0:
171 # If it cannot be installed due to unsupported
172 # bootloader, let it be ok.
173 pass
175 if dom:
176 new_entry = { ref : tuple([acmpol.get_name(),
177 xsconstants.ACM_POLICY_ID]) }
178 self.policies.update(new_entry)
179 self.xsobjs[ref] = acmpol
180 return (acmpol, xsconstants.XSERR_SUCCESS, errors)
182 def make_boot_policy(self, acmpol):
183 if acmpol.is_default_policy():
184 return xsconstants.XSERR_SUCCESS
185 rc = acmpol.copy_policy_file(".bin","/boot")
186 if rc != xsconstants.XSERR_SUCCESS:
187 return rc
189 try:
190 filename = acmpol.get_filename(".bin","",dotted=True)
191 if bootloader.set_default_boot_policy(filename) != True:
192 return xsconstants.XSERR_BOOTPOLICY_INSTALL_ERROR
193 except:
194 return xsconstants.XSERR_FILE_ERROR
195 return xsconstants.XSERR_SUCCESS
197 def activate_xspolicy(self, xspol, flags):
198 from xen.xend import XendDomain
199 domains = XendDomain.instance()
200 try:
201 domains.domains_lock.acquire()
202 return self.__activate_xspolicy(xspol, flags)
203 finally:
204 domains.domains_lock.release()
206 def __activate_xspolicy(self, xspol, flags):
207 rc = xsconstants.XSERR_SUCCESS
208 if flags & xsconstants.XS_INST_LOAD:
209 rc = xspol.loadintohv()
210 if rc == xsconstants.XSERR_SUCCESS and \
211 flags & xsconstants.XS_INST_BOOT:
212 rc = self.make_boot_policy(xspol)
213 if rc == xsconstants.XSERR_SUCCESS:
214 rc = flags
215 return rc
217 def rm_policy_from_system(self, ref, force=False):
218 if self.policies.has_key(ref):
219 acmpol = self.xsobjs[ref]
220 rc = acmpol.destroy()
221 if rc == xsconstants.XSERR_SUCCESS or force:
222 del self.policies[ref]
223 del self.xsobjs[ref]
224 rc = xsconstants.XSERR_SUCCESS
225 return rc
227 def rm_bootpolicy(self):
228 """ Remove any (ACM) boot policy from the grub configuration file
229 """
230 rc = 0
231 title = bootloader.get_default_title()
232 if title != None:
233 polnames = []
234 for (k, v) in self.xsobjs.items():
235 polnames.append(v.get_filename(".bin","",dotted=True))
236 bootloader.rm_policy_from_boottitle(title, polnames)
237 else:
238 rc = -xsconstants.XSERR_NO_DEFAULT_BOOT_TITLE
239 return rc
241 def get_policy_flags(self, acmpol):
242 """ Get the currently active flags of a policy, i.e., whether the
243 system is using this policy as its boot policy for the default
244 boot title.
245 """
246 flags = 0
248 filename = acmpol.get_filename(".bin","", dotted=True)
249 if bootloader.loads_default_policy(filename) or \
250 acmpol.is_default_policy():
251 flags |= xsconstants.XS_INST_BOOT
253 if acmpol.isloaded():
254 flags |= xsconstants.XS_INST_LOAD
255 return flags
257 def get_policies(self):
258 """ Get all managed policies. """
259 return self.xsobjs.values()
261 def get_policies_refs(self):
262 """ Get all managed policies' references. """
263 return self.xsobjs.keys()
265 def has_ref(self, ref):
266 """ Check whether there is a policy with the given reference """
267 return self.xsobjs.has_key(ref)
269 def policy_from_ref(self, ref):
270 """ Get the policy's object given its reference """
271 if ref in self.xsobjs.keys():
272 return self.xsobjs[ref]
273 return None
275 def ref_from_polname(self, polname):
276 """ Get the reference of the policy given its name """
277 ref = None
278 for (k, v) in self.xsobjs.items():
279 if v.get_name() == polname:
280 ref = k
281 break
282 return ref
284 def lock_policy(self, ref):
285 """ get exclusive access to a policy """
286 self.xsobjs[ref].grab_lock()
288 def unlock_policy(self, ref):
289 """ release exclusive access to a policy """
290 self.xsobjs[ref].unlock()
292 def get_loaded_policy(self):
293 for pol in self.xsobjs.values():
294 if pol.isloaded():
295 return pol
296 return None
298 def get_hv_loaded_policy_name(self):
299 return security.get_active_policy_name()
301 def get_policy_by_name(self, name):
302 for pol in self.xsobjs.values():
303 if pol.get_name() == name:
304 return pol
305 return None
307 def get_domain0_bootlabel(self):
308 """ Get the domain0 bootlabel from the default boot title """
309 title = ""
310 def_title = bootloader.get_default_title()
311 line = bootloader.get_kernel_val(def_title, "ssidref")
312 if line:
313 parms = line.split(":",1)
314 if len(parms) > 1:
315 title = parms[1]
316 return title
318 def set_domain0_bootlabel(self, xspol, label):
319 """ Set the domain-0 bootlabel under the given policy. If the
320 current policy is the default policy, it will remove it. """
321 rm_entry = (xspol.get_name() == "DEFAULT")
322 return xspol.set_vm_bootlabel(label, rm_entry)
324 def rm_domain0_bootlabel(self):
325 """ Remove the domain-0 bootlabel from the default boot title """
326 def_title = bootloader.get_default_title()
327 return bootloader.set_kernel_attval(def_title, "ssidref", None)
329 def ssidref_to_vmlabel(self, ssidref):
330 """ Given an ssidref, return the vmlabel under the current policy """
331 vmlabel = ""
332 pol = self.get_loaded_policy()
333 if pol:
334 vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref)
335 return vmlabel
337 def get_stes_of_vmlabel(self, vmlabel_xapi):
338 """ Get the list of STEs given a VM label in XenAPI format """
339 stes = []
340 loadedpol = self.get_loaded_policy()
341 if loadedpol:
342 tmp = vmlabel_xapi.split(":")
343 if len(tmp) != 3:
344 return []
345 stes = loadedpol.policy_get_stes_of_vmlabel(tmp[2])
346 return stes
348 def get_enforced_binary(self, xstype):
349 res = None
350 if xstype == xsconstants.XS_POLICY_ACM:
351 res = ACMPolicy.get_enforced_binary()
352 return res
354 poladmin = None
356 def XSPolicyAdminInstance(maxpolicies=1):
357 global poladmin
358 if poladmin == None:
359 poladmin = XSPolicyAdmin(maxpolicies)
360 return poladmin