ia64/xen-unstable

view tools/python/xen/util/acmpolicy.py @ 17796:1de5d17497fd

acm: check for duplicate labels and types
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 09 09:37:56 2008 +0100 (2008-06-09)
parents 931932f5fc6d
children a41d14c3bf19
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 #============================================================================
19 import os
20 import sha
21 import stat
22 import array
23 import struct
24 import shutil
25 import commands
26 from xml.dom import minidom, Node
27 from xen.xend.XendLogging import log
28 from xen.util import xsconstants, bootloader, mkdir
29 from xen.util.xspolicy import XSPolicy
30 from xen.xend.XendError import SecurityError
31 import xen.util.xsm.acm.acm as security
32 from xen.util.xsm.xsm import XSMError
33 from xen.xend import XendOptions
35 ACM_POLICIES_DIR = security.policy_dir_prefix + "/"
37 # Constants needed for generating a binary policy from its XML
38 # representation
39 ACM_POLICY_VERSION = 4 # Latest one
40 ACM_CHWALL_VERSION = 1
42 ACM_STE_VERSION = 1
44 ACM_MAGIC = 0x001debc;
46 ACM_NULL_POLICY = 0
47 ACM_CHINESE_WALL_POLICY = 1
48 ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2
49 ACM_POLICY_UNDEFINED = 15
52 ACM_LABEL_UNLABELED = "__UNLABELED__"
53 ACM_LABEL_UNLABELED_DISPLAY = "unlabeled"
55 """
56 Error codes reported in when trying to test for a new policy
57 These error codes are reported in an array of tuples where
58 each error code is followed by a parameter describing the error
59 more closely, such as a domain id.
60 """
61 ACM_EVTCHN_SHARING_VIOLATION = 0x100
62 ACM_GNTTAB_SHARING_VIOLATION = 0x101
63 ACM_DOMAIN_LOOKUP = 0x102
64 ACM_CHWALL_CONFLICT = 0x103
65 ACM_SSIDREF_IN_USE = 0x104
68 DEFAULT_policy = \
69 "<?xml version=\"1.0\" ?>\n" +\
70 "<SecurityPolicyDefinition xmlns=\"http://www.ibm.com\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.ibm.com ../../security_policy.xsd\">\n" +\
71 " <PolicyHeader>\n" +\
72 " <PolicyName>DEFAULT</PolicyName>\n" +\
73 " <Version>1.0</Version>\n" +\
74 " </PolicyHeader>\n" +\
75 " <SimpleTypeEnforcement>\n" +\
76 " <SimpleTypeEnforcementTypes>\n" +\
77 " <Type>SystemManagement</Type>\n" +\
78 " <Type>__UNLABELED__</Type>\n" +\
79 " </SimpleTypeEnforcementTypes>\n" +\
80 " </SimpleTypeEnforcement>\n" +\
81 " <ChineseWall>\n" +\
82 " <ChineseWallTypes>\n" +\
83 " <Type>SystemManagement</Type>\n" +\
84 " </ChineseWallTypes>\n" +\
85 " </ChineseWall>\n" +\
86 " <SecurityLabelTemplate>\n" +\
87 " <SubjectLabels bootstrap=\"SystemManagement\">\n" +\
88 " <VirtualMachineLabel>\n" +\
89 " <Name%s>SystemManagement</Name>\n" +\
90 " <SimpleTypeEnforcementTypes>\n" +\
91 " <Type>SystemManagement</Type>\n" +\
92 " <Type>__UNLABELED__</Type>\n" +\
93 " </SimpleTypeEnforcementTypes>\n" +\
94 " <ChineseWallTypes>\n" +\
95 " <Type/>\n" +\
96 " </ChineseWallTypes>\n" +\
97 " </VirtualMachineLabel>\n" +\
98 " <VirtualMachineLabel>\n" +\
99 " <Name>__UNLABELED__</Name>\n" +\
100 " <SimpleTypeEnforcementTypes>\n" +\
101 " <Type>__UNLABELED__</Type>\n" +\
102 " </SimpleTypeEnforcementTypes>\n" +\
103 " <ChineseWallTypes>\n" +\
104 " <Type/>\n" +\
105 " </ChineseWallTypes>\n" +\
106 " </VirtualMachineLabel>\n" +\
107 " </SubjectLabels>\n" +\
108 " <ObjectLabels>\n" +\
109 " <ResourceLabel>\n" +\
110 " <Name>__UNLABELED__</Name>\n" +\
111 " <SimpleTypeEnforcementTypes>\n" +\
112 " <Type>__UNLABELED__</Type>\n" +\
113 " </SimpleTypeEnforcementTypes>\n" +\
114 " </ResourceLabel>\n" +\
115 " </ObjectLabels>\n" +\
116 " </SecurityLabelTemplate>\n" +\
117 "</SecurityPolicyDefinition>\n"
119 ACM_SCHEMA="""<?xml version="1.0" encoding="UTF-8"?>
120 <!-- Author: Ray Valdez, Reiner Sailer {rvaldez,sailer}@us.ibm.com -->
121 <!-- This file defines the schema, which is used to define -->
122 <!-- the security policy and the security labels in Xen. -->
124 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ibm.com" xmlns="http://www.ibm.com" elementFormDefault="qualified">
125 <xsd:element name="SecurityPolicyDefinition">
126 <xsd:complexType>
127 <xsd:sequence>
128 <xsd:element ref="PolicyHeader" minOccurs="1" maxOccurs="1"></xsd:element>
129 <xsd:element ref="SimpleTypeEnforcement" minOccurs="0" maxOccurs="1"></xsd:element>
130 <xsd:element ref="ChineseWall" minOccurs="0" maxOccurs="1"></xsd:element>
131 <xsd:element ref="SecurityLabelTemplate" minOccurs="1" maxOccurs="1"></xsd:element>
132 </xsd:sequence>
133 </xsd:complexType>
134 </xsd:element>
135 <xsd:element name="PolicyHeader">
136 <xsd:complexType>
137 <xsd:sequence>
138 <xsd:element name="PolicyName" minOccurs="1" maxOccurs="1" type="xsd:string"></xsd:element>
139 <xsd:element name="PolicyUrl" minOccurs="0" maxOccurs="1" type="xsd:string"></xsd:element>
140 <xsd:element name="Reference" type="xsd:string" minOccurs="0" maxOccurs="1" />
141 <xsd:element name="Date" minOccurs="0" maxOccurs="1" type="xsd:string"></xsd:element>
142 <xsd:element name="NameSpaceUrl" minOccurs="0" maxOccurs="1" type="xsd:string"></xsd:element>
143 <xsd:element name="Version" minOccurs="1" maxOccurs="1" type="VersionFormat"/>
144 <xsd:element ref="FromPolicy" minOccurs="0" maxOccurs="1"/>
145 </xsd:sequence>
146 </xsd:complexType>
147 </xsd:element>
148 <xsd:element name="ChineseWall">
149 <xsd:complexType>
150 <xsd:sequence>
151 <xsd:element ref="ChineseWallTypes" minOccurs="1" maxOccurs="1" />
152 <xsd:element ref="ConflictSets" minOccurs="0" maxOccurs="1" />
153 </xsd:sequence>
154 <xsd:attribute name="priority" type="PolicyOrder" use="optional"></xsd:attribute>
155 </xsd:complexType>
156 </xsd:element>
157 <xsd:element name="SimpleTypeEnforcement">
158 <xsd:complexType>
159 <xsd:sequence>
160 <xsd:element ref="SimpleTypeEnforcementTypes" />
161 </xsd:sequence>
162 <xsd:attribute name="priority" type="PolicyOrder" use="optional"></xsd:attribute>
163 </xsd:complexType>
164 </xsd:element>
165 <xsd:element name="SecurityLabelTemplate">
166 <xsd:complexType>
167 <xsd:sequence>
168 <xsd:element name="SubjectLabels" minOccurs="0" maxOccurs="1">
169 <xsd:complexType>
170 <xsd:sequence>
171 <xsd:element ref="VirtualMachineLabel" minOccurs="1" maxOccurs="unbounded"></xsd:element>
172 </xsd:sequence>
173 <xsd:attribute name="bootstrap" type="xsd:string" use="required"></xsd:attribute>
174 </xsd:complexType>
175 </xsd:element>
176 <xsd:element name="ObjectLabels" minOccurs="0" maxOccurs="1">
177 <xsd:complexType>
178 <xsd:sequence>
179 <xsd:element ref="ResourceLabel" minOccurs="1" maxOccurs="unbounded"></xsd:element>
180 </xsd:sequence>
181 </xsd:complexType>
182 </xsd:element>
183 </xsd:sequence>
184 </xsd:complexType>
185 </xsd:element>
186 <xsd:element name="ChineseWallTypes">
187 <xsd:complexType>
188 <xsd:sequence>
189 <xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
190 </xsd:sequence>
191 </xsd:complexType>
192 </xsd:element>
193 <xsd:element name="ConflictSets">
194 <xsd:complexType>
195 <xsd:sequence>
196 <xsd:element maxOccurs="unbounded" minOccurs="1" ref="Conflict" />
197 </xsd:sequence>
198 </xsd:complexType>
199 </xsd:element>
200 <xsd:element name="SimpleTypeEnforcementTypes">
201 <xsd:complexType>
202 <xsd:sequence>
203 <xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
204 </xsd:sequence>
205 </xsd:complexType>
206 </xsd:element>
207 <xsd:element name="Conflict">
208 <xsd:complexType>
209 <xsd:sequence>
210 <xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
211 </xsd:sequence>
212 <xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute>
213 </xsd:complexType>
214 </xsd:element>
215 <xsd:element name="VirtualMachineLabel">
216 <xsd:complexType>
217 <xsd:sequence>
218 <xsd:element name="Name" type="NameWithFrom"></xsd:element>
219 <xsd:element ref="SimpleTypeEnforcementTypes" minOccurs="0" maxOccurs="unbounded" />
220 <xsd:element ref="ChineseWallTypes" minOccurs="0" maxOccurs="unbounded" />
221 </xsd:sequence>
222 </xsd:complexType>
223 </xsd:element>
224 <xsd:element name="ResourceLabel">
225 <xsd:complexType>
226 <xsd:sequence>
227 <xsd:element name="Name" type="NameWithFrom"></xsd:element>
228 <xsd:element name="SimpleTypeEnforcementTypes" type="SingleSimpleTypeEnforcementType" />
229 </xsd:sequence>
230 </xsd:complexType>
231 </xsd:element>
232 <xsd:element name="Name" type="xsd:string" />
233 <xsd:element name="Type" type="xsd:string" />
234 <xsd:simpleType name="PolicyOrder">
235 <xsd:restriction base="xsd:string">
236 <xsd:enumeration value="PrimaryPolicyComponent"></xsd:enumeration>
237 </xsd:restriction>
238 </xsd:simpleType>
239 <xsd:element name="FromPolicy">
240 <xsd:complexType>
241 <xsd:sequence>
242 <xsd:element name="PolicyName" minOccurs="1" maxOccurs="1" type="xsd:string"/>
243 <xsd:element name="Version" minOccurs="1" maxOccurs="1" type="VersionFormat"/>
244 </xsd:sequence>
245 </xsd:complexType>
246 </xsd:element>
247 <xsd:simpleType name="VersionFormat">
248 <xsd:restriction base="xsd:string">
249 <xsd:pattern value="[0-9]{1,8}.[0-9]{1,8}"></xsd:pattern>
250 </xsd:restriction>
251 </xsd:simpleType>
252 <xsd:complexType name="NameWithFrom">
253 <xsd:simpleContent>
254 <xsd:extension base="xsd:string">
255 <xsd:attribute name="from" type="xsd:string" use="optional"></xsd:attribute>
256 </xsd:extension>
257 </xsd:simpleContent>
258 </xsd:complexType>
259 <xsd:complexType name="SingleSimpleTypeEnforcementType">
260 <xsd:sequence>
261 <xsd:element maxOccurs="1" minOccurs="1" ref="Type" />
262 </xsd:sequence>
263 </xsd:complexType>
264 </xsd:schema>"""
267 def get_DEFAULT_policy(dom0label=""):
268 fromnode = ""
269 if dom0label != "":
270 fromnode = " from=\"%s\"" % dom0label
271 return DEFAULT_policy % fromnode
273 def initialize():
274 xoptions = XendOptions.instance()
275 basedir = xoptions.get_xend_security_path()
276 policiesdir = basedir + "/policies"
277 mkdir.parents(policiesdir, stat.S_IRWXU)
279 instdir = security.install_policy_dir_prefix
280 DEF_policy_file = "DEFAULT-security_policy.xml"
282 #Install default policy.
283 f = open(policiesdir + "/" + DEF_policy_file, 'w')
284 if f:
285 f.write(get_DEFAULT_policy())
286 f.close()
287 else:
288 log.error("Could not write the default policy's file.")
289 defpol = ACMPolicy(xml=get_DEFAULT_policy())
290 defpol.compile()
293 class ACMPolicy(XSPolicy):
294 """
295 ACMPolicy class. Implements methods for getting information from
296 the XML representation of the policy as well as compilation and
297 loading of a policy into the HV.
298 """
300 def __init__(self, name=None, dom=None, ref=None, xml=None):
301 if name:
302 self.name = name
303 try:
304 self.dom = minidom.parse(self.path_from_policy_name(name))
305 except Exception, e:
306 raise SecurityError(-xsconstants.XSERR_XML_PROCESSING,
307 str(e))
308 elif dom:
309 self.dom = dom
310 self.name = self.get_name()
311 elif xml:
312 try:
313 self.dom = minidom.parseString(xml)
314 except Exception, e:
315 raise SecurityError(-xsconstants.XSERR_XML_PROCESSING,
316 str(e))
317 self.name = self.get_name()
318 rc = self.validate()
319 if rc != xsconstants.XSERR_SUCCESS:
320 raise SecurityError(rc)
321 if ref:
322 from xen.xend.XendXSPolicy import XendACMPolicy
323 self.xendacmpolicy = XendACMPolicy(self, {}, ref)
324 else:
325 self.xendacmpolicy = None
326 XSPolicy.__init__(self, name=self.name, ref=ref)
328 def get_dom(self):
329 return self.dom
331 def get_name(self):
332 return self.policy_dom_get_hdr_item("PolicyName")
334 def get_type(self):
335 return xsconstants.XS_POLICY_ACM
337 def get_type_name(self):
338 return xsconstants.ACM_POLICY_ID
340 def __str__(self):
341 return self.get_name()
344 def validate(self):
345 """
346 validate against the policy's schema Does not fail if the
347 libxml2 python lib is not installed
348 """
349 rc = xsconstants.XSERR_SUCCESS
350 try:
351 import libxml2
352 except Exception, e:
353 log.warn("Libxml2 python-wrapper is not installed on the system.")
354 return xsconstants.XSERR_SUCCESS
355 try:
356 parserctxt = libxml2.schemaNewMemParserCtxt(ACM_SCHEMA,
357 len(ACM_SCHEMA))
358 schemaparser = parserctxt.schemaParse()
359 valid = schemaparser.schemaNewValidCtxt()
360 doc = libxml2.parseDoc(self.toxml())
361 if doc.schemaValidateDoc(valid) != 0:
362 rc = -xsconstants.XSERR_BAD_XML
363 except Exception, e:
364 log.warn("Problem with the schema: %s" % str(e))
365 rc = -xsconstants.XSERR_GENERAL_FAILURE
366 if rc != xsconstants.XSERR_SUCCESS:
367 log.warn("XML did not validate against schema")
368 if rc == xsconstants.XSERR_SUCCESS:
369 rc = self.__validate_name_and_labels()
370 return rc
372 def __validate_name_and_labels(self):
373 """ no ':' allowed in the policy name and the labels """
374 if ':' in self.get_name():
375 return -xsconstants.XSERR_BAD_POLICY_NAME
376 for s in self.policy_get_resourcelabel_names():
377 if ':' in s:
378 return -xsconstants.XSERR_BAD_LABEL
379 for s in self.policy_get_virtualmachinelabel_names():
380 if ':' in s:
381 return -xsconstants.XSERR_BAD_LABEL
382 return xsconstants.XSERR_SUCCESS
385 def is_default_policy(self):
386 """
387 Determine whether this is the default policy
388 """
389 default = ['SystemManagement', ACM_LABEL_UNLABELED ]
390 if self.policy_get_virtualmachinelabel_names() == default and \
391 self.policy_get_bootstrap_vmlabel() == default[0] and \
392 self.policy_get_stetypes_types() == default and \
393 self.policy_get_stes_of_vmlabel(default[0]) == default and \
394 self.policy_get_stes_of_vmlabel(default[1]) == [default[1]] and \
395 self.policy_get_resourcelabel_names() == [default[1]] and \
396 self.policy_get_chwall_types() == [ default[0] ] and \
397 self.get_name() == "DEFAULT":
398 return True
399 return False
401 def update(self, xml_new):
402 """
403 Update the policy with the new XML. The hypervisor decides
404 whether the new policy can be applied.
405 """
406 rc = -xsconstants.XSERR_XML_PROCESSING
407 errors = ""
408 acmpol_old = self
409 try:
410 acmpol_new = ACMPolicy(xml=xml_new)
411 except Exception:
412 return -xsconstants.XSERR_XML_PROCESSING, errors
414 vmlabel_map = acmpol_new.policy_get_vmlabel_translation_map()
416 # An update requires version information in the current
417 # and new policy. The version number of the current policy
418 # must be the same as what is in the FromPolicy/Version node
419 # in the new one and the current policy's name must be the
420 # same as in FromPolicy/PolicyName
421 # The default policy when it is set skips this step.
422 if not acmpol_new.is_default_policy() and \
423 not acmpol_old.is_default_policy():
424 irc = self.__do_update_version_check(acmpol_new)
425 if irc != xsconstants.XSERR_SUCCESS:
426 return irc, errors
428 if self.isloaded():
429 newvmnames = \
430 acmpol_new.policy_get_virtualmachinelabel_names_sorted()
431 oldvmnames = \
432 acmpol_old.policy_get_virtualmachinelabel_names_sorted()
433 del_array = ""
434 chg_array = ""
436 for o in oldvmnames:
437 if o not in newvmnames:
438 old_idx = oldvmnames.index(o)
439 if vmlabel_map.has_key(o):
440 #not a deletion, but a renaming
441 new = vmlabel_map[o]
442 new_idx = newvmnames.index(new)
443 chg_array += struct.pack("ii", old_idx, new_idx)
444 else:
445 del_array += struct.pack("i", old_idx)
446 for v in newvmnames:
447 if v in oldvmnames:
448 old_idx = oldvmnames.index(v)
449 new_idx = newvmnames.index(v)
450 if old_idx != new_idx:
451 chg_array += struct.pack("ii", old_idx, new_idx)
453 # VM labels indicated in the 'from' attribute of a VM or
454 # resource node but that did not exist in the old policy
455 # are considered bad labels.
456 bad_renamings = set(vmlabel_map.keys()) - set(oldvmnames)
457 if len(bad_renamings) > 0:
458 log.error("Bad VM label renamings: %s" %
459 list(bad_renamings))
460 return -xsconstants.XSERR_BAD_LABEL, errors
462 reslabel_map = acmpol_new.policy_get_reslabel_translation_map()
463 oldresnames = acmpol_old.policy_get_resourcelabel_names()
464 bad_renamings = set(reslabel_map.keys()) - set(oldresnames)
465 if len(bad_renamings) > 0:
466 log.error("Bad resource label renamings: %s" %
467 list(bad_renamings))
468 return -xsconstants.XSERR_BAD_LABEL, errors
470 #Get binary and map from the new policy
471 rc, pol_map, bin_pol = acmpol_new.policy_create_map_and_bin()
472 if rc != xsconstants.XSERR_SUCCESS:
473 log.error("Could not build the map and binary policy.")
474 return rc, errors
476 #Need to do / check the following:
477 # - relabel all resources where there is a 'from' field in
478 # the policy and mark those as unlabeled where the label
479 # does not appear in the new policy anymore
480 # - relabel all VMs where there is a 'from' field in the
481 # policy and mark those as unlabeled where the label
482 # does not appear in the new policy anymore; no running
483 # or paused VM may be unlabeled through this
484 # - check that under the new labeling conditions the VMs
485 # still have access to their resources as before. Unlabeled
486 # resources are inaccessible. If this check fails, the
487 # update failed.
488 # - Attempt changes in the hypervisor; if this step fails,
489 # roll back the relabeling of resources and VMs
490 # - Commit the relabeling of resources
493 rc, errors = security.change_acm_policy(bin_pol,
494 del_array, chg_array,
495 vmlabel_map, reslabel_map,
496 self, acmpol_new,
497 acmpol_new.is_default_policy())
499 if rc == 0:
500 # Replace the old DOM with the new one and save it
501 self.dom = acmpol_new.dom
502 self.compile()
503 log.info("ACM policy update was successful")
504 else:
505 #Not loaded in HV
506 self.dom = acmpol_new.dom
507 rc = self.compile()
508 return rc, errors
510 def force_default_policy(klass):
511 """
512 Force the installation of the DEFAULT policy if for
513 example no XML of the current policy is available and
514 the update path with comparisons of old and new policy
515 cannot be taken.
516 This only succeeds if only Domain-0 is running or
517 all guest have the same ssidref as Domain-0.
518 """
519 errors = ""
521 acmpol_new = ACMPolicy(xml = get_DEFAULT_policy())
523 from xen.lowlevel import acm
524 dom0_ssidref = acm.getssid(0)
525 del_array = ""
526 chg_array = struct.pack("ii",
527 dom0_ssidref['ssidref'] & 0xffff,
528 0x1)
530 rc, pol_map, bin_pol = acmpol_new.policy_create_map_and_bin()
531 if rc != xsconstants.XSERR_SUCCESS:
532 return rc, errors, acmpol_new
533 rc, errors = security.hv_chg_policy(bin_pol, del_array, chg_array)
534 return rc, errors, acmpol_new
536 force_default_policy = classmethod(force_default_policy)
538 def get_reset_policy_xml(klass):
539 dom0_label = security.get_ssid(0)[1]
540 return get_DEFAULT_policy(dom0_label)
542 get_reset_policy_xml = classmethod(get_reset_policy_xml)
544 def __do_update_version_check(self, acmpol_new):
545 acmpol_old = self
547 now_vers = acmpol_old.policy_dom_get_hdr_item("Version")
548 now_name = acmpol_old.policy_dom_get_hdr_item("PolicyName")
549 req_oldvers = acmpol_new.policy_dom_get_frompol_item("Version")
550 req_oldname = acmpol_new.policy_dom_get_frompol_item("PolicyName")
552 if now_vers == "" or \
553 now_vers != req_oldvers or \
554 now_name != req_oldname:
555 log.info("Policy rejected: %s != %s or %s != %s" % \
556 (now_vers,req_oldvers,now_name,req_oldname))
557 return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE
559 if not self.isVersionUpdate(acmpol_new):
560 log.info("Policy rejected since new version is not an update.")
561 return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE
563 return xsconstants.XSERR_SUCCESS
566 def compareVersions(self, v1, v2):
567 """
568 Compare two policy versions given their tuples of major and
569 minor.
570 Return '0' if versions are equal, '>0' if v1 > v2 and
571 '<' if v1 < v2
572 """
573 rc = v1[0] - v2[0]
574 if rc == 0:
575 rc = v1[1] - v2[1]
576 return rc
578 def getVersionTuple(self, item="Version"):
579 v_str = self.policy_dom_get_hdr_item(item)
580 return self.__convVersionToTuple(v_str)
582 def get_version(self):
583 return self.policy_dom_get_hdr_item("Version")
585 def isVersionUpdate(self, polnew):
586 if self.compareVersions(polnew.getVersionTuple(),
587 self.getVersionTuple()) > 0:
588 return True
589 return False
591 def __convVersionToTuple(self, v_str):
592 """ Convert a version string, formatted according to the scheme
593 "%d.%d" into a tuple of (major, minor). Return (0,0) if the
594 string is empty.
595 """
596 major = 0
597 minor = 0
598 if v_str != "":
599 tmp = v_str.split(".")
600 major = int(tmp[0])
601 if len(tmp) > 1:
602 minor = int(tmp[1])
603 return (major, minor)
605 def get_policies_path(self):
606 xoptions = XendOptions.instance()
607 basedir = xoptions.get_xend_security_path()
608 return basedir + "/policies/"
610 def policy_path(self, name):
611 prefix = self.get_policies_path()
612 path = prefix + name.replace('.','/')
613 _path = path.split("/")
614 del _path[-1]
615 mkdir.parents("/".join(_path), stat.S_IRWXU)
616 return path
618 def path_from_policy_name(self, name):
619 return self.policy_path(name) + "-security_policy.xml"
621 #
622 # Functions interacting with the bootloader
623 #
624 def vmlabel_to_ssidref(self, vm_label):
625 """ Convert a VMlabel into an ssidref given the current
626 policy
627 Return xsconstants.INVALID_SSIDREF if conversion failed.
628 """
629 ssidref = xsconstants.INVALID_SSIDREF
630 names = self.policy_get_virtualmachinelabel_names_sorted()
631 try:
632 vmidx = names.index(vm_label)
633 ssidref = (vmidx << 16) | vmidx
634 except:
635 pass
636 return ssidref
638 def set_vm_bootlabel(self, vm_label, remove=False):
639 parms="<>"
640 if vm_label != "":
641 ssidref = self.vmlabel_to_ssidref(vm_label)
642 if ssidref == xsconstants.INVALID_SSIDREF:
643 return -xsconstants.XSERR_BAD_LABEL
644 parms = "0x%08x:%s:%s:%s" % \
645 (ssidref, xsconstants.ACM_POLICY_ID, \
646 self.get_name(),vm_label)
647 else:
648 ssidref = 0 #Identifier for removal
650 if remove == True:
651 parms = "<>"
653 try:
654 def_title = bootloader.get_default_title()
655 bootloader.set_kernel_attval(def_title, "ssidref", parms)
656 except:
657 return -xsconstants.XSERR_GENERAL_FAILURE
658 return ssidref
660 #
661 # Utility functions related to the policy's files
662 #
663 def get_filename(self, postfix, prefix=None, dotted=False):
664 """
665 Create the filename for the policy. The prefix is prepended
666 to the path. If dotted is True, then a policy name like
667 'a.b.c' will remain as is, otherwise it will become 'a/b/c'
668 """
669 if prefix == None:
670 prefix = self.get_policies_path()
671 name = self.get_name()
672 if name:
673 p = name.split(".")
674 path = ""
675 if dotted:
676 sep = "."
677 else:
678 sep = "/"
679 if len(p) > 1:
680 path = sep.join(p[0:len(p)-1])
681 if prefix != "" or path != "":
682 allpath = prefix + path + sep + p[-1] + postfix
683 else:
684 allpath = p[-1] + postfix
685 return allpath
686 return None
688 def __readfile(self, name):
689 cont = ""
690 filename = self.get_filename(name)
691 f = open(filename, "r")
692 if f:
693 cont = f.read()
694 f.close()
695 return cont
697 def get_map(self):
698 return self.__readfile(".map")
700 def get_bin(self):
701 return self.__readfile(".bin")
703 def copy_policy_file(self, suffix, destdir):
704 spolfile = self.get_filename(suffix)
705 dpolfile = destdir + "/" + self.get_filename(suffix,"",dotted=True)
706 try:
707 shutil.copyfile(spolfile, dpolfile)
708 except Exception, e:
709 log.error("Could not copy policy file %s to %s: %s" %
710 (spolfile, dpolfile, str(e)))
711 return -xsconstants.XSERR_FILE_ERROR
712 return xsconstants.XSERR_SUCCESS
714 #
715 # DOM-related functions
716 #
718 def policy_dom_get(self, parent, key, createit=False):
719 for node in parent.childNodes:
720 if node.nodeType == Node.ELEMENT_NODE:
721 if node.nodeName == key:
722 return node
723 if createit:
724 self.dom_create_node(parent, key)
725 return self.policy_dom_get(parent, key)
727 def dom_create_node(self, parent, newname, value=" "):
728 xml = "<a><"+newname+">"+ value +"</"+newname+"></a>"
729 frag = minidom.parseString(xml)
730 frag.childNodes[0].nodeType = Node.DOCUMENT_FRAGMENT_NODE
731 parent.appendChild(frag.childNodes[0])
732 return frag.childNodes[0]
734 def dom_get_node(self, path, createit=False):
735 node = None
736 parts = path.split("/")
737 doc = self.get_dom()
738 if len(parts) > 0:
739 node = self.policy_dom_get(doc.documentElement, parts[0])
740 if node:
741 i = 1
742 while i < len(parts):
743 _node = self.policy_dom_get(node, parts[i], createit)
744 if not _node:
745 if not createit:
746 break
747 else:
748 self.dom_create_node(node, parts[i])
749 _node = self.policy_dom_get(node, parts[i])
750 node = _node
751 i += 1
752 return node
754 #
755 # Header-related functions
756 #
757 def policy_dom_get_header_subnode(self, nodename):
758 node = self.dom_get_node("PolicyHeader/%s" % nodename)
759 return node
761 def policy_dom_get_hdr_item(self, name, default=""):
762 node = self.policy_dom_get_header_subnode(name)
763 if node and len(node.childNodes) > 0:
764 return node.childNodes[0].nodeValue
765 return default
767 def policy_dom_get_frompol_item(self, name, default="", createit=False):
768 node = self.dom_get_node("PolicyHeader/FromPolicy",createit)
769 if node:
770 node = self.policy_dom_get(node, name, createit)
771 if node and len(node.childNodes) > 0:
772 return node.childNodes[0].nodeValue
773 return default
775 def get_header_fields_map(self):
776 header = {
777 'policyname' : self.policy_dom_get_hdr_item("PolicyName"),
778 'policyurl' : self.policy_dom_get_hdr_item("PolicyUrl"),
779 'reference' : self.policy_dom_get_hdr_item("Reference"),
780 'date' : self.policy_dom_get_hdr_item("Date"),
781 'namespaceurl' : self.policy_dom_get_hdr_item("NameSpaceUrl"),
782 'version' : self.policy_dom_get_hdr_item("Version")
783 }
784 return header
786 def set_frompolicy_name(self, name):
787 """ For tools to adapt the header of the policy """
788 node = self.dom_get_node("PolicyHeader/FromPolicy/PolicyName",
789 createit=True)
790 node.childNodes[0].nodeValue = name
792 def set_frompolicy_version(self, version):
793 """ For tools to adapt the header of the policy """
794 node = self.dom_get_node("PolicyHeader/FromPolicy/Version",
795 createit=True)
796 node.childNodes[0].nodeValue = version
798 def set_policy_name(self, name):
799 """ For tools to adapt the header of the policy """
800 node = self.dom_get_node("PolicyHeader/PolicyName")
801 node.childNodes[0].nodeValue = name
803 def set_policy_version(self, version):
804 """ For tools to adapt the header of the policy """
805 node = self.dom_get_node("PolicyHeader/Version")
806 node.childNodes[0].nodeValue = version
808 def update_frompolicy(self, curpol):
809 self.set_frompolicy_name(curpol.policy_dom_get_hdr_item("PolicyName"))
810 version = curpol.policy_dom_get_hdr_item("Version")
811 self.set_frompolicy_version(version)
812 (maj, minor) = self.__convVersionToTuple(version)
813 self.set_policy_version("%s.%s" % (maj, minor+1))
815 #
816 # Get all types that are part of a node
817 #
819 def policy_get_types(self, node):
820 strings = []
821 i = 0
822 while i < len(node.childNodes):
823 if node.childNodes[i].nodeName == "Type" and \
824 len(node.childNodes[i].childNodes) > 0:
825 strings.append(node.childNodes[i].childNodes[0].nodeValue)
826 i += 1
827 return strings
829 #
830 # Simple Type Enforcement-related functions
831 #
833 def policy_get_stetypes_node(self):
834 node = self.dom_get_node("SimpleTypeEnforcement/SimpleTypeEnforcementTypes")
835 return node
837 def policy_get_stetypes_types(self):
838 strings = []
839 node = self.policy_get_stetypes_node()
840 if node:
841 strings = self.policy_get_types(node)
842 return strings
844 #
845 # Chinese Wall Type-related functions
846 #
848 def policy_get_chwall_types(self):
849 strings = []
850 node = self.dom_get_node("ChineseWall/ChineseWallTypes")
851 if node:
852 strings = self.policy_get_types(node)
853 return strings
855 def policy_get_chwall_cfses(self):
856 cfs = []
857 node = self.dom_get_node("ChineseWall/ConflictSets")
858 if node:
859 i = 0
860 while i < len(node.childNodes):
861 _cfs = {}
862 if node.childNodes[i].nodeName == "Conflict":
863 _cfs['name'] = node.childNodes[i].getAttribute('name')
864 _cfs['chws'] = self.policy_get_types(node.childNodes[i])
865 cfs.append(_cfs)
866 i += 1
867 return cfs
869 def policy_get_chwall_cfses_names_sorted(self):
870 """
871 Return the list of all conflict set names in alphabetical
872 order.
873 """
874 cfs_names = []
875 node = self.dom_get_node("ChineseWall/ConflictSets")
876 if node:
877 i = 0
878 while i < len(node.childNodes):
879 if node.childNodes[i].nodeName == "Conflict":
880 n = node.childNodes[i].getAttribute('name')
881 #it better have a name!
882 if n:
883 cfs_names.append(n)
884 i += 1
885 cfs_names.sort()
886 return cfs_names
888 #
889 # Subject Label-related functions
890 #
892 def policy_get_bootstrap_vmlabel(self):
893 node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
894 if node:
895 vmlabel = node.getAttribute("bootstrap")
896 return vmlabel
898 # Get the names of all virtual machine labels; returns an array
899 def policy_get_virtualmachinelabel_names(self):
900 strings = []
901 node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
902 if node:
903 i = 0
904 while i < len(node.childNodes):
905 if node.childNodes[i].nodeName == "VirtualMachineLabel":
906 name = self.policy_dom_get(node.childNodes[i], "Name")
907 if len(name.childNodes) > 0:
908 strings.append(name.childNodes[0].nodeValue)
909 i += 1
910 return strings
912 def policy_sort_virtualmachinelabel_names(self, vmnames):
913 bootstrap = self.policy_get_bootstrap_vmlabel()
914 if bootstrap not in vmnames:
915 raise SecurityError(-xsconstants.XSERR_POLICY_INCONSISTENT)
916 vmnames.remove(bootstrap)
917 vmnames.sort()
918 vmnames.insert(0, bootstrap)
919 if ACM_LABEL_UNLABELED in vmnames:
920 vmnames.remove(ACM_LABEL_UNLABELED)
921 vmnames.insert(0, ACM_LABEL_UNLABELED)
922 return vmnames
924 def policy_get_virtualmachinelabel_names_sorted(self):
925 """ Get a sorted list of VMlabel names. The bootstrap VM's
926 label will be the first one in that list, followed
927 by an alphabetically sorted list of VM label names """
928 vmnames = self.policy_get_virtualmachinelabel_names()
929 res = self.policy_sort_virtualmachinelabel_names(vmnames)
930 if res[0] != ACM_LABEL_UNLABELED:
931 res.insert(0, ACM_LABEL_UNLABELED)
932 return res
934 def policy_get_virtualmachinelabels(self):
935 """ Get a list of all virtual machine labels in this policy """
936 res = []
937 node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
938 if node:
939 i = 0
940 while i < len(node.childNodes):
941 if node.childNodes[i].nodeName == "VirtualMachineLabel":
942 name = self.policy_dom_get(node.childNodes[i], "Name")
943 if len(name.childNodes) > 0:
944 _res = {}
945 _res['type'] = xsconstants.ACM_LABEL_VM
946 _res['name'] = name.childNodes[0].nodeValue
947 stes = self.policy_dom_get(node.childNodes[i],
948 "SimpleTypeEnforcementTypes")
949 if stes:
950 _res['stes'] = self.policy_get_types(stes)
951 else:
952 _res['stes'] = []
953 chws = self.policy_dom_get(node.childNodes[i],
954 "ChineseWallTypes")
955 if chws:
956 _res['chws'] = self.policy_get_types(chws)
957 else:
958 _res['chws'] = []
959 res.append(_res)
960 i += 1
961 return res
963 def policy_get_stes_of_vmlabel(self, vmlabel):
964 """ Get a list of all STEs of a given VMlabel """
965 return self.__policy_get_stes_of_labeltype(vmlabel,
966 "/SubjectLabels", "VirtualMachineLabel")
968 def policy_get_stes_of_resource(self, reslabel):
969 """ Get a list of all resources of a given VMlabel """
970 return self.__policy_get_stes_of_labeltype(reslabel,
971 "/ObjectLabels", "ResourceLabel")
973 def __policy_get_stes_of_labeltype(self, label, path, labeltype):
974 node = self.dom_get_node("SecurityLabelTemplate" + path)
975 if node:
976 i = 0
977 while i < len(node.childNodes):
978 if node.childNodes[i].nodeName == labeltype:
979 name = self.policy_dom_get(node.childNodes[i], "Name")
980 if len(name.childNodes) > 0 and \
981 name.childNodes[0].nodeValue == label:
982 stes = self.policy_dom_get(node.childNodes[i],
983 "SimpleTypeEnforcementTypes")
984 if not stes:
985 return []
986 return self.policy_get_types(stes)
987 i += 1
988 return []
990 def policy_check_vmlabel_against_reslabels(self, vmlabel, resources):
991 """
992 Check whether the given vmlabel is compatible with the given
993 resource labels. Do this by getting all the STEs of the
994 vmlabel and the STEs of the resources. Any STE type of the
995 VM label must match an STE type of the resource.
996 """
997 vm_stes = self.policy_get_stes_of_vmlabel(vmlabel)
998 if len(vm_stes) == 0:
999 return False
1000 for res in resources:
1001 res_stes = self.policy_get_stes_of_resource(res)
1002 if len(res_stes) == 0 or \
1003 len( set(res_stes).intersection( set(vm_stes) ) ) == 0:
1004 return False
1005 return True
1007 def __policy_get_label_translation_map(self, path, labeltype):
1008 res = {}
1009 node = self.dom_get_node("SecurityLabelTemplate/" + path)
1010 if node:
1011 i = 0
1012 while i < len(node.childNodes):
1013 if node.childNodes[i].nodeName == labeltype:
1014 name = self.policy_dom_get(node.childNodes[i], "Name")
1015 from_name = name.getAttribute("from")
1016 if from_name and len(name.childNodes) > 0:
1017 res.update({from_name : name.childNodes[0].nodeValue})
1018 i += 1
1019 return res
1021 def policy_get_vmlabel_translation_map(self):
1022 """
1023 Get a dictionary of virtual machine mappings from their
1024 old VMlabel name to the new VMlabel name.
1025 """
1026 return self.__policy_get_label_translation_map("SubjectLabels",
1027 "VirtualMachineLabel")
1029 def policy_get_reslabel_translation_map(self):
1030 """
1031 Get a dictionary of resource mappings from their
1032 old resource label name to the new resource label name.
1033 """
1034 return self.__policy_get_label_translation_map("ObjectLabels",
1035 "ResourceLabel")
1038 # Object Label-related functions
1040 def policy_get_resourcelabel_names(self):
1041 """
1042 Get the names of all resource labels in an array but
1043 only those that actually have types
1044 """
1045 strings = []
1046 node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels")
1047 if node:
1048 i = 0
1049 while i < len(node.childNodes):
1050 if node.childNodes[i].nodeName == "ResourceLabel":
1051 name = self.policy_dom_get(node.childNodes[i], "Name")
1052 stes = self.policy_dom_get(node.childNodes[i],
1053 "SimpleTypeEnforcementTypes")
1054 if stes and len(name.childNodes) > 0:
1055 strings.append(name.childNodes[0].nodeValue)
1056 i += 1
1057 return strings
1059 def policy_get_resourcelabels(self):
1060 """
1061 Get all information about all resource labels of this policy.
1062 """
1063 res = []
1064 node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels")
1065 if node:
1066 i = 0
1067 while i < len(node.childNodes):
1068 if node.childNodes[i].nodeName == "ResourceLabel":
1069 name = self.policy_dom_get(node.childNodes[i], "Name")
1070 if len(name.childNodes) > 0:
1071 _res = {}
1072 _res['type'] = xsconstants.ACM_LABEL_RES
1073 _res['name'] = name.childNodes[0].nodeValue
1074 stes = self.policy_dom_get(node.childNodes[i],
1075 "SimpleTypeEnforcementTypes")
1076 if stes:
1077 _res['stes'] = self.policy_get_types(stes)
1078 else:
1079 _res['stes'] = []
1080 _res['chws'] = []
1081 res.append(_res)
1082 i += 1
1083 return res
1086 def policy_find_reslabels_with_stetype(self, stetype):
1087 """
1088 Find those resource labels that hold a given STE type.
1089 """
1090 res = []
1091 reslabels = self.policy_get_resourcelabels()
1092 for resl in reslabels:
1093 if stetype in resl['stes']:
1094 res.append(resl['name'])
1095 return res
1098 def toxml(self):
1099 dom = self.get_dom()
1100 if dom:
1101 return dom.toxml()
1102 return None
1104 def hash(self):
1105 """ Calculate a SAH1 hash of the XML policy """
1106 return sha.sha(self.toxml())
1108 def save(self):
1109 ### Save the XML policy into a file ###
1110 rc = -xsconstants.XSERR_FILE_ERROR
1111 name = self.get_name()
1112 if name:
1113 path = self.path_from_policy_name(name)
1114 if path:
1115 f = open(path, 'w')
1116 if f:
1117 try:
1118 try:
1119 f.write(self.toxml())
1120 rc = 0
1121 except:
1122 pass
1123 finally:
1124 f.close()
1125 return rc
1127 def __write_to_file(self, suffix, data):
1128 #write the data into a file with the given suffix
1129 f = open(self.get_filename(suffix),"w")
1130 if f:
1131 try:
1132 try:
1133 f.write(data)
1134 except Exception, e:
1135 log.error("Error writing file: %s" % str(e))
1136 return -xsconstants.XSERR_FILE_ERROR
1137 finally:
1138 f.close()
1139 else:
1140 return -xsconstants.XSERR_FILE_ERROR
1141 return xsconstants.XSERR_SUCCESS
1144 def compile(self):
1145 rc = self.save()
1146 if rc == 0:
1147 rc, mapfile, bin_pol = self.policy_create_map_and_bin()
1149 if rc == 0:
1150 try:
1151 security.mapfile_lock()
1153 rc = self.__write_to_file(".map", mapfile)
1154 if rc != 0:
1155 log.error("Error writing map file")
1157 finally:
1158 security.mapfile_unlock()
1160 if rc == 0:
1161 rc = self.__write_to_file(".bin", bin_pol)
1162 if rc != 0:
1163 log.error("Error writing binary policy file")
1164 return rc
1166 def loadintohv(self):
1167 """
1168 load this policy into the hypervisor
1169 if successful,the policy's flags will indicate that the
1170 policy is the one loaded into the hypervisor
1171 """
1172 if not self.isloaded():
1173 (ret, output) = commands.getstatusoutput(
1174 security.xensec_tool +
1175 " loadpolicy " +
1176 self.get_filename(".bin"))
1177 if ret != 0:
1178 return -xsconstants.XSERR_POLICY_LOAD_FAILED
1179 return xsconstants.XSERR_SUCCESS
1181 def isloaded(self):
1182 """
1183 Determine whether this policy is the active one.
1184 """
1185 if self.get_name() == security.get_active_policy_name():
1186 return True
1187 return False
1189 def destroy(self):
1190 """
1191 Destroy the policy including its binary, mapping and
1192 XML files.
1193 This only works if the policy is not the one that's loaded
1194 """
1195 if self.isloaded():
1196 return -xsconstants.XSERR_POLICY_LOADED
1197 files = [ self.get_filename(".map",""),
1198 self.get_filename(".bin","") ]
1199 for f in files:
1200 try:
1201 os.unlink(f)
1202 except:
1203 pass
1204 if self.xendacmpolicy:
1205 self.xendacmpolicy.destroy()
1206 XSPolicy.destroy(self)
1207 return xsconstants.XSERR_SUCCESS
1209 def policy_get_domain_label(self, domid):
1210 """
1211 Given a domain's ID, retrieve the label it has using
1212 its ssidref for reverse calculation.
1213 """
1214 try:
1215 mgmt_dom = security.get_ssid(domid)
1216 except:
1217 return ""
1218 return self.policy_get_domain_label_by_ssidref(int(mgmt_dom[3]))
1220 def policy_get_domain_label_by_ssidref(self, ssidref):
1221 """ Given an ssidref, find the corresponding VM label """
1222 chwall_ref = ssidref & 0xffff
1223 try:
1224 allvmtypes = self.policy_get_virtualmachinelabel_names_sorted()
1225 except:
1226 return None
1227 return allvmtypes[chwall_ref]
1229 def policy_get_domain_label_formatted(self, domid):
1230 label = self.policy_get_domain_label(domid)
1231 if label == "":
1232 label = ACM_LABEL_UNLABELED
1233 return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label)
1235 def policy_get_domain_label_by_ssidref_formatted(self, ssidref):
1236 label = self.policy_get_domain_label_by_ssidref(ssidref)
1237 if label == "":
1238 return ""
1239 return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label)
1241 def policy_create_map_and_bin(self):
1242 """
1243 Create the policy's map and binary files -- compile the policy.
1244 """
1245 def roundup8(len):
1246 return ((len + 7) & ~7)
1248 rc = xsconstants.XSERR_SUCCESS
1249 mapfile = ""
1250 primpolcode = ACM_POLICY_UNDEFINED
1251 secpolcode = ACM_POLICY_UNDEFINED
1252 unknown_ste = set()
1253 unknown_chw = set()
1254 unlabeled_ste = "__NULL_LABEL__"
1255 unlabeled_chw = "__NULL_LABEL__"
1257 rc = self.validate()
1258 if rc:
1259 return rc, "", ""
1261 stes = self.policy_get_stetypes_types()
1262 if stes:
1263 stes.sort()
1265 chws = self.policy_get_chwall_types()
1266 if chws:
1267 chws.sort()
1269 vms = self.policy_get_virtualmachinelabels()
1270 bootstrap = self.policy_get_bootstrap_vmlabel()
1272 vmlabels = self.policy_get_virtualmachinelabel_names_sorted()
1273 if bootstrap not in vmlabels:
1274 log.error("Bootstrap label '%s' not found among VM labels '%s'." \
1275 % (bootstrap, vmlabels))
1276 return -xsconstants.XSERR_POLICY_INCONSISTENT, "", ""
1278 vms_with_chws = []
1279 chws_by_vm = { ACM_LABEL_UNLABELED : [] }
1280 for v in vms:
1281 if v.has_key("chws"):
1282 vms_with_chws.append(v["name"])
1283 chws_by_vm[v["name"]] = v["chws"]
1286 if bootstrap in vms_with_chws:
1287 vms_with_chws.remove(bootstrap)
1288 vms_with_chws.sort()
1289 vms_with_chws.insert(0, bootstrap)
1290 else:
1291 vms_with_chws.sort()
1293 if ACM_LABEL_UNLABELED in vms_with_chws:
1294 unlabeled_chw = ACM_LABEL_UNLABELED
1295 vms_with_chws.remove(ACM_LABEL_UNLABELED) ; # @1
1297 vms_with_stes = []
1298 stes_by_vm = { ACM_LABEL_UNLABELED : [] }
1299 for v in vms:
1300 if v.has_key("stes"):
1301 vms_with_stes.append(v["name"])
1302 stes_by_vm[v["name"]] = v["stes"]
1304 if bootstrap in vms_with_stes:
1305 vms_with_stes.remove(bootstrap)
1306 vms_with_stes.sort()
1307 vms_with_stes.insert(0, bootstrap)
1308 else:
1309 vms_with_stes.sort()
1311 if ACM_LABEL_UNLABELED in vms_with_stes:
1312 unlabeled_ste = ACM_LABEL_UNLABELED
1313 vms_with_stes.remove(ACM_LABEL_UNLABELED) ; # @2
1315 resnames = self.policy_get_resourcelabel_names()
1316 resnames.sort()
1317 stes_by_res = {}
1318 res = self.policy_get_resourcelabels()
1319 for r in res:
1320 if r.has_key("stes"):
1321 stes_by_res[r["name"]] = r["stes"]
1323 if ACM_LABEL_UNLABELED in resnames:
1324 resnames.remove(ACM_LABEL_UNLABELED)
1326 # check for duplicate labels
1327 if len(vmlabels) != len(set(vmlabels)) or \
1328 len(resnames) != len(set(resnames)) or \
1329 len(stes) != len(set(stes)) or \
1330 len(chws) != len(set(chws)):
1331 return -xsconstants.XSERR_POLICY_HAS_DUPLICATES, "", ""
1333 max_chw_ssids = 1 + len(vms_with_chws)
1334 max_chw_types = 1 + len(vms_with_chws)
1335 max_ste_ssids = 1 + len(vms_with_stes) + len(resnames)
1336 max_ste_types = 1 + len(vms_with_stes) + len(resnames)
1338 mapfile = "POLICYREFERENCENAME %s\n" % self.get_name()
1339 mapfile += "MAGIC %08x\n" % ACM_MAGIC
1340 mapfile += "POLICFILE %s\n" % \
1341 self.path_from_policy_name(self.get_name())
1342 mapfile += "BINARYFILE %s\n" % self.get_filename(".bin")
1343 mapfile += "MAX-CHWALL-TYPES %08x\n" % len(chws)
1344 mapfile += "MAX-CHWALL-SSIDS %08x\n" % max_chw_ssids
1345 mapfile += "MAX-CHWALL-LABELS %08x\n" % max_chw_ssids
1346 mapfile += "MAX-STE-TYPES %08x\n" % len(stes)
1347 mapfile += "MAX-STE-SSIDS %08x\n" % max_ste_ssids
1348 mapfile += "MAX-STE-LABELS %08x\n" % max_ste_ssids
1349 mapfile += "\n"
1351 if chws:
1352 mapfile += \
1353 "PRIMARY CHWALL\n"
1354 primpolcode = ACM_CHINESE_WALL_POLICY
1355 if stes:
1356 mapfile += \
1357 "SECONDARY STE\n"
1358 else:
1359 mapfile += \
1360 "SECONDARY NULL\n"
1361 secpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY
1362 else:
1363 if stes:
1364 mapfile += \
1365 "PRIMARY STE\n"
1366 primpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY
1367 mapfile += \
1368 "SECONDARY NULL\n"
1370 mapfile += "\n"
1372 if len(vms_with_chws) > 0:
1373 mapfile += \
1374 "LABEL->SSID ANY CHWALL %-20s %x\n" % \
1375 (unlabeled_chw, 0)
1376 i = 0
1377 for v in vms_with_chws:
1378 mapfile += \
1379 "LABEL->SSID VM CHWALL %-20s %x\n" % \
1380 (v, i+1)
1381 i += 1
1382 mapfile += "\n"
1384 if len(vms_with_stes) > 0 or len(resnames) > 0:
1385 mapfile += \
1386 "LABEL->SSID ANY STE %-20s %08x\n" % \
1387 (unlabeled_ste, 0)
1388 i = 0
1389 for v in vms_with_stes:
1390 mapfile += \
1391 "LABEL->SSID VM STE %-20s %x\n" % (v, i+1)
1392 i += 1
1393 j = 0
1394 for r in resnames:
1395 mapfile += \
1396 "LABEL->SSID RES STE %-20s %x\n" % (r, j+i+1)
1397 j += 1
1398 mapfile += "\n"
1400 if vms_with_chws:
1401 mapfile += \
1402 "SSID->TYPE CHWALL %08x\n" % 0
1403 i = 1
1404 for v in vms_with_chws:
1405 mapfile += \
1406 "SSID->TYPE CHWALL %08x" % i
1407 for c in chws_by_vm[v]:
1408 mapfile += " %s" % c
1409 mapfile += "\n"
1410 i += 1
1411 mapfile += "\n"
1413 if len(vms_with_stes) > 0 or len(resnames) > 0:
1414 mapfile += \
1415 "SSID->TYPE STE %08x\n" % 0
1416 i = 1
1417 for v in vms_with_stes:
1418 mapfile += \
1419 "SSID->TYPE STE %08x" % i
1420 for s in stes_by_vm[v]:
1421 mapfile += " %s" % s
1422 mapfile += "\n"
1423 i += 1
1425 for r in resnames:
1426 mapfile += \
1427 "SSID->TYPE STE %08x" % i
1428 for s in stes_by_res[r]:
1429 mapfile += " %s" % s
1430 mapfile += "\n"
1431 i += 1
1432 mapfile += "\n"
1434 if chws:
1435 i = 0
1436 while i < len(chws):
1437 mapfile += \
1438 "TYPE CHWALL %-20s %d\n" % (chws[i], i)
1439 i += 1
1440 mapfile += "\n"
1441 if stes:
1442 i = 0
1443 while i < len(stes):
1444 mapfile += \
1445 "TYPE STE %-20s %d\n" % (stes[i], i)
1446 i += 1
1447 mapfile += "\n"
1449 mapfile += "\n"
1451 # Build header with policy name
1452 length = roundup8(4 + len(self.get_name()) + 1)
1453 polname = self.get_name();
1454 pr_bin = struct.pack("!i", len(polname)+1)
1455 pr_bin += polname;
1456 while len(pr_bin) < length:
1457 pr_bin += "\x00"
1459 # Build chinese wall part
1460 vms_with_chws.insert(0, ACM_LABEL_UNLABELED)
1462 cfses_names = self.policy_get_chwall_cfses_names_sorted()
1463 cfses = self.policy_get_chwall_cfses()
1465 chwformat = "!iiiiiiiii"
1466 max_chw_cfs = len(cfses)
1467 chw_ssid_offset = struct.calcsize(chwformat)
1468 chw_confset_offset = chw_ssid_offset + \
1469 2 * len(chws) * max_chw_types
1470 chw_running_types_offset = 0
1471 chw_conf_agg_offset = 0
1473 chw_bin = struct.pack(chwformat,
1474 ACM_CHWALL_VERSION,
1475 ACM_CHINESE_WALL_POLICY,
1476 len(chws),
1477 max_chw_ssids,
1478 max_chw_cfs,
1479 chw_ssid_offset,
1480 chw_confset_offset,
1481 chw_running_types_offset,
1482 chw_conf_agg_offset)
1483 chw_bin_body = ""
1485 # VMs that are listed and their chinese walls
1486 for v in vms_with_chws:
1487 for c in chws:
1488 unknown_chw |= (set(chws_by_vm[v]) - set(chws))
1489 if c in chws_by_vm[v]:
1490 chw_bin_body += struct.pack("!h",1)
1491 else:
1492 chw_bin_body += struct.pack("!h",0)
1494 # Conflict sets -- they need to be processed in alphabetical order
1495 for cn in cfses_names:
1496 if cn == "" or cn is None:
1497 return -xsconstants.XSERR_BAD_CONFLICTSET, "", ""
1498 i = 0
1499 while i < len(cfses):
1500 if cfses[i]['name'] == cn:
1501 conf = cfses[i]['chws']
1502 break
1503 i += 1
1504 for c in chws:
1505 if c in conf:
1506 chw_bin_body += struct.pack("!h",1)
1507 else:
1508 chw_bin_body += struct.pack("!h",0)
1509 del cfses[i]
1511 if len(cfses) != 0:
1512 return -xsconstants.XSERR_BAD_CONFLICTSET, "", ""
1514 chw_bin += chw_bin_body
1516 while len(chw_bin) < roundup8(len(chw_bin)):
1517 chw_bin += "\x00"
1519 # Build STE part
1520 vms_with_stes.insert(0, ACM_LABEL_UNLABELED) # Took out in @2
1522 steformat="!iiiii"
1523 ste_bin = struct.pack(steformat,
1524 ACM_STE_VERSION,
1525 ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
1526 len(stes),
1527 max_ste_types,
1528 struct.calcsize(steformat))
1529 ste_bin_body = ""
1530 if stes:
1531 # VMs that are listed and their STE types
1532 for v in vms_with_stes:
1533 unknown_ste |= (set(stes_by_vm[v]) - set(stes))
1534 for s in stes:
1535 if s in stes_by_vm[v]:
1536 ste_bin_body += struct.pack("!h",1)
1537 else:
1538 ste_bin_body += struct.pack("!h",0)
1539 for r in resnames:
1540 unknown_ste |= (set(stes_by_res[r]) - set(stes))
1541 for s in stes:
1542 if s in stes_by_res[r]:
1543 ste_bin_body += struct.pack("!h",1)
1544 else:
1545 ste_bin_body += struct.pack("!h",0)
1547 ste_bin += ste_bin_body;
1549 while len(ste_bin) < roundup8(len(ste_bin)):
1550 ste_bin += "\x00"
1552 #Write binary header:
1553 headerformat="!iiiiiiiiii20s"
1554 totallen_bin = struct.calcsize(headerformat) + \
1555 len(pr_bin) + len(chw_bin) + len(ste_bin)
1556 polref_offset = struct.calcsize(headerformat)
1557 primpoloffset = polref_offset + len(pr_bin)
1558 if primpolcode == ACM_CHINESE_WALL_POLICY:
1559 secpoloffset = primpoloffset + len(chw_bin)
1560 elif primpolcode == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
1561 secpoloffset = primpoloffset + len(ste_bin)
1562 else:
1563 secpoloffset = primpoloffset
1565 (major, minor) = self.getVersionTuple()
1566 hdr_bin = struct.pack(headerformat,
1567 ACM_MAGIC,
1568 ACM_POLICY_VERSION,
1569 totallen_bin,
1570 polref_offset,
1571 primpolcode,
1572 primpoloffset,
1573 secpolcode,
1574 secpoloffset,
1575 major, minor,
1576 self.hash().digest())
1578 all_bin = array.array('B')
1579 for s in [ hdr_bin, pr_bin, chw_bin, ste_bin ]:
1580 for c in s:
1581 all_bin.append(ord(c))
1583 log.info("Compiled policy: rc = %s" % hex(rc))
1584 if len(unknown_ste) > 0:
1585 log.info("The following STEs in VM/res labels were unknown:" \
1586 " %s" % list(unknown_ste))
1587 rc = -xsconstants.XSERR_BAD_LABEL
1588 if len(unknown_chw) > 0:
1589 log.info("The following Ch. Wall types in labels were unknown:" \
1590 " %s" % list(unknown_chw))
1591 rc = -xsconstants.XSERR_BAD_LABEL
1592 return rc, mapfile, all_bin.tostring()
1594 def validate_enforced_policy_hash(self):
1595 """ verify that the policy hash embedded in the binary policy
1596 that is currently enforce matches the one of the XML policy.
1597 """
1598 if self.hash().digest() != self.get_enforced_policy_hash():
1599 raise Exception('Policy hashes do not match')
1601 def get_enforced_policy_hash(self):
1602 binpol = self.get_enforced_binary()
1603 headerformat="!iiiiiiiiii20s"
1604 res = struct.unpack(headerformat, binpol[:60])
1605 if len(res) >= 11:
1606 return res[10]
1607 return None
1609 def get_enforced_binary(self):
1610 rc, binpol = security.hv_get_policy()
1611 if rc != 0:
1612 raise SecurityError(-xsconstants.XSERR_HV_OP_FAILED)
1613 return binpol
1615 get_enforced_binary = classmethod(get_enforced_binary)