ia64/xen-unstable

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