ia64/xen-unstable

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