[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1183989104 -3600
# Node ID aa640601575fb4b509befd9f032f0f3d577a46fc
# Parent  83fd4ad219cd321024c6b5f01b85464cd64faf2d
[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@xxxxxxxxxx>
---
 tools/python/xen/util/acmpolicy.py          | 1199 ++++++++++++++++++++++++++++
 tools/python/xen/util/bootloader.py         |  521 ++++++++++++
 tools/python/xen/util/security.py           |  791 ++++++++++++++++--
 tools/python/xen/util/xsconstants.py        |  104 ++
 tools/python/xen/util/xspolicy.py           |   66 +
 tools/python/xen/xend/XendAPI.py            |   66 +
 tools/python/xen/xend/XendConfig.py         |   36 
 tools/python/xen/xend/XendDomain.py         |    3 
 tools/python/xen/xend/XendDomainInfo.py     |  180 +++-
 tools/python/xen/xend/XendError.py          |   18 
 tools/python/xen/xend/XendVDI.py            |   12 
 tools/python/xen/xend/XendXSPolicy.py       |  222 +++++
 tools/python/xen/xend/XendXSPolicyAdmin.py  |  313 +++++++
 tools/python/xen/xend/server/blkif.py       |   15 
 tools/security/policies/security_policy.xsd |   29 
 15 files changed, 3414 insertions(+), 161 deletions(-)

diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/util/acmpolicy.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/acmpolicy.py        Mon Jul 09 14:51:44 2007 +0100
@@ -0,0 +1,1199 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006,2007 International Business Machines Corp.
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
+#============================================================================
+
+import os
+import commands
+import struct
+import stat
+import array
+from xml.dom import minidom, Node
+from xen.xend.XendLogging import log
+from xen.util import security, xsconstants, bootloader, mkdir
+from xen.util.xspolicy import XSPolicy
+from xen.util.security import ACMError
+from xen.xend.XendError import SecurityError
+
+ACM_POLICIES_DIR = security.policy_dir_prefix + "/"
+
+# Constants needed for generating a binary policy from its XML
+# representation
+ACM_POLICY_VERSION = 3  # Latest one
+ACM_CHWALL_VERSION = 1
+
+ACM_STE_VERSION = 1
+
+ACM_MAGIC = 0x001debc;
+
+ACM_NULL_POLICY = 0
+ACM_CHINESE_WALL_POLICY = 1
+ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2
+ACM_POLICY_UNDEFINED = 15
+
+
+ACM_SCHEMA_FILE = "/etc/xen/acm-security/policies/security_policy.xsd"
+
+class ACMPolicy(XSPolicy):
+    """
+     ACMPolicy class. Implements methods for getting information from
+     the XML representation of the policy as well as compilation and
+     loading of a policy into the HV.
+    """
+
+    def __init__(self, name=None, dom=None, ref=None, xml=None):
+        if name:
+            self.name = name
+            self.dom = minidom.parse(self.path_from_policy_name(name))
+        elif dom:
+            self.dom = dom
+            self.name = self.get_name()
+        elif xml:
+            self.dom = minidom.parseString(xml)
+            self.name = self.get_name()
+        rc = self.validate()
+        if rc != xsconstants.XSERR_SUCCESS:
+            raise SecurityError(rc)
+        mkdir.parents(ACM_POLICIES_DIR, stat.S_IRWXU)
+        if ref:
+            from xen.xend.XendXSPolicy import XendACMPolicy
+            self.xendacmpolicy = XendACMPolicy(self, {}, ref)
+        else:
+            self.xendacmpolicy = None
+        XSPolicy.__init__(self, name=self.name, ref=ref)
+
+    def get_dom(self):
+        return self.dom
+
+    def get_name(self):
+        return self.policy_dom_get_hdr_item("PolicyName")
+
+    def get_type(self):
+        return xsconstants.XS_POLICY_ACM
+
+    def get_type_name(self):
+        return xsconstants.ACM_POLICY_ID
+
+    def __str__(self):
+        return self.get_name()
+
+
+    def validate(self):
+        """
+            validate against the policy's schema Does not fail if the
+            libxml2 python lib is not installed
+        """
+        rc = xsconstants.XSERR_SUCCESS
+        try:
+            import libxml2
+        except Exception, e:
+            log.warn("Libxml2 python-wrapper is not installed on the system.")
+            return xsconstants.XSERR_SUCCESS
+        try:
+            parserctxt = libxml2.schemaNewParserCtxt(ACM_SCHEMA_FILE)
+            schemaparser = parserctxt.schemaParse()
+            valid = schemaparser.schemaNewValidCtxt()
+            doc = libxml2.parseDoc(self.toxml())
+            if doc.schemaValidateDoc(valid) != 0:
+                rc = -xsconstants.XSERR_BAD_XML
+        except Exception, e:
+            log.warn("Problem with the schema: %s" % str(e))
+            rc = -xsconstants.XSERR_GENERAL_FAILURE
+        if rc != xsconstants.XSERR_SUCCESS:
+            log.warn("XML did not validate against schema")
+        rc = self.__validate_name_and_labels()
+        return rc
+
+    def __validate_name_and_labels(self):
+        """ no ':' allowed in the policy name and the labels """
+        if ':' in self.get_name():
+            return -xsconstants.XSERR_BAD_POLICY_NAME
+        for s in self.policy_get_resourcelabel_names():
+            if ':' in s:
+                return -xsconstants.XSERR_BAD_LABEL
+        for s in self.policy_get_virtualmachinelabel_names():
+            if ':' in s:
+                return -xsconstants.XSERR_BAD_LABEL
+        return xsconstants.XSERR_SUCCESS
+
+
+    def update(self, xml_new):
+        """
+            Update the policy with the new XML. The hypervisor decides
+            whether the new policy can be applied.
+        """
+        rc = -xsconstants.XSERR_XML_PROCESSING
+        errors = ""
+        acmpol_old = self
+        try:
+            acmpol_new = ACMPolicy(xml=xml_new)
+        except Exception:
+            return -xsconstants.XSERR_XML_PROCESSING, errors
+
+        vmlabel_map = acmpol_new.policy_get_vmlabel_translation_map()
+        # An update requires version information in the current
+        # and new policy. The version number of the current policy
+        # must be the same as what is in the FromPolicy/Version node
+        # in the new one and the current policy's name must be the
+        # same as in FromPolicy/PolicyName
+
+        now_vers    = acmpol_old.policy_dom_get_hdr_item("Version")
+        now_name    = acmpol_old.policy_dom_get_hdr_item("PolicyName")
+        req_oldvers = acmpol_new.policy_dom_get_frompol_item("Version")
+        req_oldname = acmpol_new.policy_dom_get_frompol_item("PolicyName")
+
+        if now_vers == "" or \
+           now_vers != req_oldvers or \
+           now_name != req_oldname:
+            log.info("Policy rejected: %s != %s or %s != %s" % \
+                     (now_vers,req_oldvers,now_name,req_oldname))
+            return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE, errors
+
+        if not self.isVersionUpdate(acmpol_new):
+            log.info("Policy rejected since new version is not an update.")
+            return -xsconstants.XSERR_VERSION_PREVENTS_UPDATE, errors
+
+        if self.isloaded():
+            newvmnames = \
+                 acmpol_new.policy_get_virtualmachinelabel_names_sorted()
+            oldvmnames = \
+                 acmpol_old.policy_get_virtualmachinelabel_names_sorted()
+            del_array = ""
+            chg_array = ""
+            for o in oldvmnames:
+                if o not in newvmnames:
+                    old_idx = oldvmnames.index(o) + 1 # for _NULL_LABEL_
+                    if vmlabel_map.has_key(o):
+                        #not a deletion, but a renaming
+                        new = vmlabel_map[o]
+                        new_idx = newvmnames.index(new) + 1 # for _NULL_LABEL_
+                        chg_array += struct.pack("ii", old_idx, new_idx)
+                    else:
+                        del_array += struct.pack("i", old_idx)
+            for v in newvmnames:
+                if v in oldvmnames:
+                    old_idx = oldvmnames.index(v) + 1 # for _NULL_LABEL_
+                    new_idx = newvmnames.index(v) + 1 # for _NULL_LABEL_
+                    if old_idx != new_idx:
+                        chg_array += struct.pack("ii", old_idx, new_idx)
+
+            # VM labels indicated in the 'from' attribute of a VM or
+            # resource node but that did not exist in the old policy
+            # are considered bad labels.
+            bad_renamings = set(vmlabel_map.keys()) - set(oldvmnames)
+            if len(bad_renamings) > 0:
+                log.error("Bad VM label renamings: %s" %
+                          list(bad_renamings))
+                return -xsconstants.XSERR_BAD_LABEL, errors
+
+            reslabel_map = acmpol_new.policy_get_reslabel_translation_map()
+            oldresnames  = acmpol_old.policy_get_resourcelabel_names()
+            bad_renamings = set(reslabel_map.keys()) - set(oldresnames)
+            if len(bad_renamings) > 0:
+                log.error("Bad resource label renamings: %s" %
+                          list(bad_renamings))
+                return -xsconstants.XSERR_BAD_LABEL, errors
+
+            #Get binary and map from the new policy
+            rc, map, bin_pol = acmpol_new.policy_create_map_and_bin()
+            if rc != xsconstants.XSERR_SUCCESS:
+                log.error("Could not build the map and binary policy.")
+                return rc, errors
+
+            #Need to do / check the following:
+            # - relabel all resources where there is a 'from' field in
+            #   the policy and mark those as unlabeled where the label
+            #   does not appear in the new policy anymore
+            # - relabel all VMs where there is a 'from' field in the
+            #   policy and mark those as unlabeled where the label
+            #   does not appear in the new policy anymore; no running
+            #   or paused VM may be unlabeled through this
+            # - check that under the new labeling conditions the VMs
+            #   still have access to their resources as before. Unlabeled
+            #   resources are inaccessible. If this check fails, the
+            #   update failed.
+            # - Attempt changes in the hypervisor; if this step fails,
+            #   roll back the relabeling of resources and VMs
+            # - Commit the relabeling of resources
+
+
+            rc, errors = security.change_acm_policy(bin_pol,
+                                        del_array, chg_array,
+                                        vmlabel_map, reslabel_map,
+                                        self, acmpol_new)
+
+            if rc == 0:
+                # Replace the old DOM with the new one and save it
+                self.dom = acmpol_new.dom
+                self.compile()
+                log.info("ACM policy update was successful")
+        else:
+            #Not loaded in HV
+            self.dom = acmpol_new.dom
+            self.compile()
+        return rc, errors
+
+    def compareVersions(self, v1, v2):
+        """
+            Compare two policy versions given their tuples of major and
+            minor.
+            Return '0' if versions are equal, '>0' if v1 > v2 and
+            '<' if v1 < v2
+        """
+        rc = v1[0] - v2[0]
+        if rc == 0:
+            rc = v1[1] - v2[1]
+        return rc
+
+    def getVersionTuple(self, item="Version"):
+        v_str = self.policy_dom_get_hdr_item(item)
+        return self.__convVersionToTuple(v_str)
+
+    def get_version(self):
+        return self.policy_dom_get_hdr_item("Version")
+
+    def isVersionUpdate(self, polnew):
+        if self.compareVersions(polnew.getVersionTuple(),
+                                self.getVersionTuple()) > 0:
+            return True
+        return False
+
+    def __convVersionToTuple(self, v_str):
+        """ Convert a version string, formatted according to the scheme
+            "%d.%d" into a tuple of (major, minor). Return (0,0) if the
+            string is empty.
+        """
+        major = 0
+        minor = 0
+        if v_str != "":
+            tmp = v_str.split(".")
+            major = int(tmp[0])
+            if len(tmp) > 1:
+                minor = int(tmp[1])
+        return (major, minor)
+
+
+    def policy_path(self, name, prefix = ACM_POLICIES_DIR ):
+        path = prefix + name.replace('.','/')
+        _path = path.split("/")
+        del _path[-1]
+        mkdir.parents("/".join(_path), stat.S_IRWXU)
+        return path
+
+    def path_from_policy_name(self, name):
+        return self.policy_path(name) + "-security_policy.xml"
+
+    #
+    # Functions interacting with the bootloader
+    #
+    def vmlabel_to_ssidref(self, vm_label):
+        """ Convert a VMlabel into an ssidref given the current
+            policy
+            Return xsconstants.INVALID_SSIDREF if conversion failed.
+        """
+        ssidref = xsconstants.INVALID_SSIDREF
+        names = self.policy_get_virtualmachinelabel_names_sorted()
+        try:
+            vmidx = names.index(vm_label) + 1 # for _NULL_LABEL_
+            ssidref = (vmidx << 16) | vmidx
+        except:
+            pass
+        return ssidref
+
+    def set_vm_bootlabel(self, vm_label):
+        parms="<>"
+        if vm_label != "":
+            ssidref = self.vmlabel_to_ssidref(vm_label)
+            if ssidref == xsconstants.INVALID_SSIDREF:
+                return -xsconstants.XSERR_BAD_LABEL
+            parms = "0x%08x:%s:%s:%s" % \
+                        (ssidref, xsconstants.ACM_POLICY_ID, \
+                         self.get_name(),vm_label)
+        else:
+            ssidref = 0 #Identifier for removal
+        try:
+            def_title = bootloader.get_default_title()
+            bootloader.set_kernel_attval(def_title, "ssidref", parms)
+        except:
+            return -xsconstants.XSERR_GENERAL_FAILURE
+        return ssidref
+
+    #
+    # Utility functions related to the policy's files
+    #
+    def get_filename(self, postfix, prefix = ACM_POLICIES_DIR, dotted=False):
+        """
+           Create the filename for the policy. The prefix is prepended
+           to the path. If dotted is True, then a policy name like
+           'a.b.c' will remain as is, otherwise it will become 'a/b/c'
+        """
+        name = self.get_name()
+        if name:
+            p = name.split(".")
+            path = ""
+            if dotted == True:
+                sep = "."
+            else:
+                sep = "/"
+            if len(p) > 1:
+                path = sep.join(p[0:len(p)-1])
+            if prefix != "" or path != "":
+                allpath = prefix + path + sep + p[-1] + postfix
+            else:
+                allpath = p[-1] + postfix
+            return allpath
+        return None
+
+    def __readfile(self, name):
+        cont = ""
+        filename = self.get_filename(name)
+        f = open(filename, "r")
+        if f:
+            cont = f.read()
+            f.close()
+        return cont
+
+    def get_map(self):
+        return self.__readfile(".map")
+
+    def get_bin(self):
+        return self.__readfile(".bin")
+
+    #
+    # DOM-related functions
+    #
+
+    def policy_dom_get(self, parent, key, createit=False):
+        for node in parent.childNodes:
+            if node.nodeType == Node.ELEMENT_NODE:
+                if node.nodeName == key:
+                    return node
+        if createit:
+            self.dom_create_node(parent, key)
+            return self.policy_dom_get(parent, key)
+
+    def dom_create_node(self, parent, newname, value=" "):
+        xml = "<a><"+newname+">"+ value +"</"+newname+"></a>"
+        frag = minidom.parseString(xml)
+        frag.childNodes[0].nodeType = Node.DOCUMENT_FRAGMENT_NODE
+        parent.appendChild(frag.childNodes[0])
+        return frag.childNodes[0]
+
+    def dom_get_node(self, path, createit=False):
+        node = None
+        parts = path.split("/")
+        doc = self.get_dom()
+        if len(parts) > 0:
+            node = self.policy_dom_get(doc.documentElement, parts[0])
+            if node:
+                i = 1
+                while i < len(parts):
+                    _node = self.policy_dom_get(node, parts[i], createit)
+                    if not _node:
+                        if not createit:
+                            break
+                        else:
+                            self.dom_create_node(node, parts[i])
+                            _node = self.policy_dom_get(node, parts[i])
+                    node = _node
+                    i += 1
+        return node
+
+    #
+    # Header-related functions
+    #
+    def policy_dom_get_header_subnode(self, nodename):
+        node = self.dom_get_node("PolicyHeader/%s" % nodename)
+        return node
+
+    def policy_dom_get_hdr_item(self, name, default=""):
+        node = self.policy_dom_get_header_subnode(name)
+        if node and len(node.childNodes) > 0:
+            return node.childNodes[0].nodeValue
+        return default
+
+    def policy_dom_get_frompol_item(self, name, default="", createit=False):
+        node = self.dom_get_node("PolicyHeader/FromPolicy",createit)
+        if node:
+            node = self.policy_dom_get(node, name, createit)
+            if node and len(node.childNodes) > 0:
+                return node.childNodes[0].nodeValue
+        return default
+
+    def get_header_fields_map(self):
+        header = {
+          'policyname'   : self.policy_dom_get_hdr_item("PolicyName"),
+          'policyurl'    : self.policy_dom_get_hdr_item("PolicyUrl"),
+          'reference'    : self.policy_dom_get_hdr_item("Reference"),
+          'date'         : self.policy_dom_get_hdr_item("Date"),
+          'namespaceurl' : self.policy_dom_get_hdr_item("NameSpaceUrl"),
+          'version'      : self.policy_dom_get_hdr_item("Version")
+        }
+        return header
+
+    def set_frompolicy_name(self, name):
+        """ For tools to adapt the header of the policy """
+        node = self.dom_get_node("PolicyHeader/FromPolicy/PolicyName",
+                                 createit=True)
+        node.childNodes[0].nodeValue = name
+
+    def set_frompolicy_version(self, version):
+        """ For tools to adapt the header of the policy """
+        node = self.dom_get_node("PolicyHeader/FromPolicy/Version",
+                                 createit=True)
+        node.childNodes[0].nodeValue = version
+
+    def set_policy_name(self, name):
+        """ For tools to adapt the header of the policy """
+        node = self.dom_get_node("PolicyHeader/PolicyName")
+        node.childNodes[0].nodeValue = name
+
+    def set_policy_version(self, version):
+        """ For tools to adapt the header of the policy """
+        node = self.dom_get_node("PolicyHeader/Version")
+        node.childNodes[0].nodeValue = version
+
+    def update_frompolicy(self, curpol):
+        self.set_frompolicy_name(curpol.policy_dom_get_hdr_item("PolicyName"))
+        version = curpol.policy_dom_get_hdr_item("Version")
+        self.set_frompolicy_version(version)
+        (maj, min) = self.__convVersionToTuple(version)
+        self.set_policy_version("%s.%s" % (maj, min+1))
+
+    #
+    # Get all types that are part of a node
+    #
+
+    def policy_get_types(self, node):
+        strings = []
+        i = 0
+        while i < len(node.childNodes):
+            if node.childNodes[i].nodeName == "Type":
+                strings.append(node.childNodes[i].childNodes[0].nodeValue)
+            i += 1
+        return strings
+
+    #
+    # Simple Type Enforcement-related functions
+    #
+
+    def policy_get_stetypes_node(self):
+        node = 
self.dom_get_node("SimpleTypeEnforcement/SimpleTypeEnforcementTypes")
+        return node
+
+    def policy_get_stetypes_types(self):
+        strings = []
+        node = self.policy_get_stetypes_node()
+        if node:
+            strings = self.policy_get_types(node)
+        return strings
+
+    #
+    # Chinese Wall Type-related functions
+    #
+
+    def policy_get_chwall_types(self):
+        strings = []
+        node = self.dom_get_node("ChineseWall/ChineseWallTypes")
+        if node:
+            strings = self.policy_get_types(node)
+        return strings
+
+    def policy_get_chwall_cfses(self):
+        cfs = []
+        node = self.dom_get_node("ChineseWall/ConflictSets")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                _cfs = {}
+                if node.childNodes[i].nodeName == "Conflict":
+                    _cfs['name']  = node.childNodes[i].getAttribute('name')
+                    _cfs['chws'] = self.policy_get_types(node.childNodes[i])
+                    cfs.append(_cfs)
+                i += 1
+        return cfs
+
+    def policy_get_chwall_cfses_names_sorted(self):
+        """
+           Return the list of all conflict set names in alphabetical
+           order.
+        """
+        cfs_names = []
+        node = self.dom_get_node("ChineseWall/ConflictSets")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == "Conflict":
+                    n  = node.childNodes[i].getAttribute('name')
+                    #it better have a name!
+                    if n:
+                        cfs_names.append(n)
+                i += 1
+        cfs_names.sort()
+        return cfs_names
+
+    #
+    # Subject Label-related functions
+    #
+
+    def policy_get_bootstrap_vmlabel(self):
+        node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
+        if node:
+            vmlabel = node.getAttribute("bootstrap")
+        return vmlabel
+
+    # Get the names of all virtual machine labels; returns an array
+    def policy_get_virtualmachinelabel_names(self):
+        strings = []
+        node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == "VirtualMachineLabel":
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    strings.append(name.childNodes[0].nodeValue)
+                i += 1
+        return strings
+
+    def policy_sort_virtualmachinelabel_names(self, vmnames):
+        bootstrap = self.policy_get_bootstrap_vmlabel()
+        if bootstrap not in vmnames:
+            raise SecurityError(-xsconstants.XSERR_POLICY_INCONSISTENT)
+        vmnames.remove(bootstrap)
+        vmnames.sort()
+        vmnames.insert(0, bootstrap)
+        return vmnames
+
+    def policy_get_virtualmachinelabel_names_sorted(self):
+        """ Get a sorted list of VMlabel names. The bootstrap VM's
+            label will be the first one in that list, followed
+            by an alphabetically sorted list of VM label names """
+        vmnames = self.policy_get_virtualmachinelabel_names()
+        return self.policy_sort_virtualmachinelabel_names(vmnames)
+
+    def policy_get_virtualmachinelabels(self):
+        """ Get a list of all virtual machine labels in this policy """
+        res = []
+        node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == "VirtualMachineLabel":
+                    _res = {}
+                    _res['type'] = xsconstants.ACM_LABEL_VM
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    _res['name'] = name.childNodes[0].nodeValue
+                    stes = self.policy_dom_get(node.childNodes[i],
+                                               "SimpleTypeEnforcementTypes")
+                    if stes:
+                        _res['stes'] = self.policy_get_types(stes)
+                    else:
+                        _res['stes'] = []
+                    chws = self.policy_dom_get(node.childNodes[i],
+                                               "ChineseWallTypes")
+                    if chws:
+                        _res['chws'] = self.policy_get_types(chws)
+                    else:
+                        _res['chws'] = []
+                    res.append(_res)
+                i += 1
+        return res
+
+    def policy_get_stes_of_vmlabel(self, vmlabel):
+        """ Get a list of all STEs of a given VMlabel """
+        return self.__policy_get_stes_of_labeltype(vmlabel,
+                                                   "VirtualMachineLabel")
+
+    def policy_get_stes_of_resource(self, reslabel):
+        """ Get a list of all resources of a given VMlabel """
+        return self.__policy_get_stes_of_labeltype(reslabel, "ResourceLabel")
+
+    def __policy_get_stes_of_labeltype(self, label, labeltype):
+        node = self.dom_get_node("SecurityLabelTemplate/SubjectLabels")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == labeltype:
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    if name.childNodes[0].nodeValue == label:
+                        stes = self.policy_dom_get(node.childNodes[i],
+                                            "SimpleTypeEnforcementTypes")
+                        if not stes:
+                            return []
+                        return self.policy_get_types(stes)
+                i += 1
+        return []
+
+    def policy_check_vmlabel_against_reslabels(self, vmlabel, resources):
+        """
+           Check whether the given vmlabel is compatible with the given
+           resource labels. Do this by getting all the STEs of the
+           vmlabel and the STEs of the resources. Any STE type of the
+           VM label must match an STE type of the resource.
+        """
+        vm_stes = self.policy_get_stes_of_vmlabel(vmlabel)
+        if len(vm_stes) == 0:
+            return False
+        for res in resources:
+            res_stes = self.policy_get_stes_of_resource(res)
+            if len( set(res_stes).union( set(vm_stes) ) ) == 0:
+                return False
+        return True
+
+    def __policy_get_label_translation_map(self, path, labeltype):
+        res = {}
+        node = self.dom_get_node("SecurityLabelTemplate/" + path)
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == labeltype:
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    from_name = name.getAttribute("from")
+                    if from_name:
+                        res.update({from_name : name.childNodes[0].nodeValue})
+                i += 1
+        return res
+
+    def policy_get_vmlabel_translation_map(self):
+        """
+            Get a dictionary of virtual machine mappings from their
+            old VMlabel name to the new VMlabel name.
+        """
+        return self.__policy_get_label_translation_map("SubjectLabels",
+                                                       "VirtualMachineLabel")
+
+    def policy_get_reslabel_translation_map(self):
+        """
+            Get a dictionary of resource mappings from their
+            old resource label name to the new resource label name.
+        """
+        return self.__policy_get_label_translation_map("ObjectLabels",
+                                                       "ResourceLabel")
+
+    #
+    # Object Label-related functions
+    #
+    def policy_get_resourcelabel_names(self):
+        """
+            Get the names of all resource labels in an array but
+            only those that actually have types
+        """
+        strings = []
+        node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == "ResourceLabel":
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    stes = self.policy_dom_get(node.childNodes[i],
+                                          "SimpleTypeEnforcementTypes")
+                    if stes:
+                        strings.append(name.childNodes[0].nodeValue)
+                i += 1
+        return strings
+
+    def policy_get_resourcelabels(self):
+        """
+           Get all information about all resource labels of this policy.
+        """
+        res = []
+        node = self.dom_get_node("SecurityLabelTemplate/ObjectLabels")
+        if node:
+            i = 0
+            while i < len(node.childNodes):
+                if node.childNodes[i].nodeName == "ResourceLabel":
+                    _res = {}
+                    _res['type'] = xsconstants.ACM_LABEL_RES
+                    name = self.policy_dom_get(node.childNodes[i], "Name")
+                    _res['name'] = name.childNodes[0].nodeValue
+                    stes = self.policy_dom_get(node.childNodes[i],
+                                               "SimpleTypeEnforcementTypes")
+                    if stes:
+                        _res['stes'] = self.policy_get_types(stes)
+                    else:
+                        _res['stes'] = []
+                    _res['chws'] = []
+                    res.append(_res)
+                i += 1
+        return res
+
+
+    def policy_find_reslabels_with_stetype(self, stetype):
+        """
+           Find those resource labels that hold a given STE type.
+        """
+        res = []
+        reslabels = self.policy_get_resourcelabels()
+        for resl in reslabels:
+            if stetype in resl['stes']:
+                res.append(resl['name'])
+        return res
+
+
+    def toxml(self):
+        dom = self.get_dom()
+        if dom:
+            return dom.toxml()
+        return None
+
+    def save(self):
+        ### Save the XML policy into a file ###
+        rc = -xsconstants.XSERR_FILE_ERROR
+        name = self.get_name()
+        if name:
+            path = self.path_from_policy_name(name)
+            if path:
+                f = open(path, 'w')
+                if f:
+                    f.write(self.toxml())
+                    f.close()
+                    rc = 0
+        return rc
+
+    def __write_to_file(self, suffix, data):
+        #write the data into a file with the given suffix
+        f = open(self.get_filename(suffix),"w")
+        if f:
+            try:
+                try:
+                    f.write(data)
+                except Exception, e:
+                    log.error("Error writing file: %s" % str(e))
+                    return -xsconstants.XSERR_FILE_ERROR
+            finally:
+                f.close()
+        else:
+            return -xsconstants.XSERR_FILE_ERROR
+        return xsconstants.XSERR_SUCCESS
+
+
+    def compile(self):
+        rc = self.save()
+        if rc == 0:
+            rc, mapfile, bin_pol = self.policy_create_map_and_bin()
+
+            if rc == 0:
+                rc = self.__write_to_file(".map", mapfile)
+                if rc != 0:
+                    log.error("Error writing map file")
+
+            if rc == 0:
+                rc = self.__write_to_file(".bin", bin_pol)
+                if rc != 0:
+                    log.error("Error writing binary policy file")
+        return rc
+
+    def loadintohv(self):
+        """
+            load this policy into the hypervisor
+            if successful,the policy's flags will indicate that the
+            policy is the one loaded into the hypervisor
+        """
+        (ret, output) = commands.getstatusoutput(
+                                   security.xensec_tool +
+                                   " loadpolicy " +
+                                   self.get_filename(".bin"))
+        if ret != 0:
+            return -xsconstants.XSERR_POLICY_LOAD_FAILED
+        return xsconstants.XSERR_SUCCESS
+
+    def isloaded(self):
+        """
+            Determine whether this policy is the active one.
+        """
+        security.refresh_security_policy()
+        if self.get_name() == security.active_policy:
+            return True
+        return False
+
+    def destroy(self):
+        """
+            Destroy the policy including its binary, mapping and
+            XML files.
+            This only works if the policy is not the one that's loaded
+        """
+        if self.isloaded():
+            return -xsconstants.XSERR_POLICY_LOADED
+        files = [ self.get_filename(".map",""),
+                  self.get_filename(".bin",""),
+                  self.path_from_policy_name(self.get_name())]
+        for f in files:
+            try:
+                os.unlink(f)
+            except:
+                pass
+        if self.xendacmpolicy:
+            self.xendacmpolicy.destroy()
+        XSPolicy.destroy(self)
+        return xsconstants.XSERR_SUCCESS
+
+    def policy_get_domain_label(self, domid):
+        """
+           Given a domain's ID, retrieve the label it has using
+           its ssidref for reverse calculation.
+        """
+        try:
+            mgmt_dom = security.get_ssid(domid)
+        except:
+            return ""
+        return self.policy_get_domain_label_by_ssidref(int(mgmt_dom[3]))
+
+    def policy_get_domain_label_by_ssidref(self, ssidref):
+        """ Given an ssidref, find the corresponding VM label """
+        chwall_ref = ssidref & 0xffff
+        try:
+            allvmtypes = self.policy_get_virtualmachinelabel_names_sorted()
+        except:
+            return None
+        return allvmtypes[chwall_ref-1] # skip _NULL_LABEL_
+
+    def policy_get_domain_label_formatted(self, domid):
+        label = self.policy_get_domain_label(domid)
+        if label == "":
+            return ""
+        return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label)
+
+    def policy_get_domain_label_by_ssidref_formatted(self, ssidref):
+        label = self.policy_get_domain_label_by_ssidref(ssidref)
+        if label == "":
+            return ""
+        return "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, self.get_name(), label)
+
+    def policy_create_map_and_bin(self):
+        """
+            Create the policy's map and binary files -- compile the policy.
+        """
+        def roundup8(len):
+            return ((len + 7) & ~7)
+
+        rc = xsconstants.XSERR_SUCCESS
+        mapfile = ""
+        primpolcode = ACM_POLICY_UNDEFINED
+        secpolcode  = ACM_POLICY_UNDEFINED
+        unknown_ste = set()
+        unknown_chw = set()
+
+        rc = self.validate()
+        if rc:
+            return rc, "", ""
+
+        stes = self.policy_get_stetypes_types()
+        if stes:
+            stes.sort()
+
+        chws = self.policy_get_chwall_types()
+        if chws:
+            chws.sort()
+
+        vms = self.policy_get_virtualmachinelabels()
+        bootstrap = self.policy_get_bootstrap_vmlabel()
+
+        vmlabels = self.policy_get_virtualmachinelabel_names_sorted()
+        if bootstrap not in vmlabels:
+            log.error("Bootstrap label '%s' not found among VM labels '%s'." \
+                      % (bootstrap, vmlabels))
+            return -xsconstants.XSERR_POLICY_INCONSISTENT, "", ""
+
+        vms_with_chws = []
+        chws_by_vm = {}
+        for v in vms:
+            if v.has_key("chws"):
+                vms_with_chws.append(v["name"])
+                chws_by_vm[v["name"]] = v["chws"]
+        if bootstrap in vms_with_chws:
+            vms_with_chws.remove(bootstrap)
+            vms_with_chws.sort()
+            vms_with_chws.insert(0, bootstrap)
+        else:
+            vms_with_chws.sort()
+
+        vms_with_stes = []
+        stes_by_vm = {}
+        for v in vms:
+            if v.has_key("stes"):
+                vms_with_stes.append(v["name"])
+                stes_by_vm[v["name"]] = v["stes"]
+        if bootstrap in vms_with_stes:
+            vms_with_stes.remove(bootstrap)
+            vms_with_stes.sort()
+            vms_with_stes.insert(0, bootstrap)
+        else:
+            vms_with_stes.sort()
+
+        resnames = self.policy_get_resourcelabel_names()
+        resnames.sort()
+        stes_by_res = {}
+        res = self.policy_get_resourcelabels()
+        for r in res:
+            if r.has_key("stes"):
+                stes_by_res[r["name"]] = r["stes"]
+
+        max_chw_ssids = 1 + len(vms_with_chws)
+        max_chw_types = 1 + len(vms_with_chws)
+        max_ste_ssids = 1 + len(vms_with_stes) + len(resnames)
+        max_ste_types = 1 + len(vms_with_stes) + len(resnames)
+
+        mapfile  = "POLICYREFERENCENAME    %s\n" % self.get_name()
+        mapfile += "MAGIC                  %08x\n" % ACM_MAGIC
+        mapfile += "POLICFILE              %s\n" % \
+            self.path_from_policy_name(self.get_name())
+        mapfile += "BINARYFILE             %s\n" % self.get_filename(".bin")
+        mapfile += "MAX-CHWALL-TYPES       %08x\n" % len(chws)
+        mapfile += "MAX-CHWALL-SSIDS       %08x\n" % max_chw_ssids
+        mapfile += "MAX-CHWALL-LABELS      %08x\n" % max_chw_ssids
+        mapfile += "MAX-STE-TYPES          %08x\n" % len(stes)
+        mapfile += "MAX-STE-SSIDS          %08x\n" % max_ste_ssids
+        mapfile += "MAX-STE-LABELS         %08x\n" % max_ste_ssids
+        mapfile += "\n"
+
+        if chws:
+            mapfile += \
+                 "PRIMARY                CHWALL\n"
+            primpolcode = ACM_CHINESE_WALL_POLICY
+            if stes:
+                mapfile += \
+                     "SECONDARY              STE\n"
+            else:
+                mapfile += \
+                     "SECONDARY             NULL\n"
+            secpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY
+        else:
+            if stes:
+                mapfile += \
+                     "PRIMARY                STE\n"
+                primpolcode = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY
+            mapfile += \
+                     "SECONDARY             NULL\n"
+
+        mapfile += "\n"
+
+        if len(vms_with_chws) > 0:
+            mapfile += \
+                 "LABEL->SSID ANY CHWALL __NULL_LABEL__       %x\n" % 0
+            i = 0
+            for v in vms_with_chws:
+                mapfile += \
+                 "LABEL->SSID VM  CHWALL %-20s %x\n" % \
+                  (v, i+1)
+                i += 1
+            mapfile += "\n"
+
+        if len(vms_with_stes) > 0 or len(resnames) > 0:
+            mapfile += \
+                 "LABEL->SSID ANY STE    __NULL_LABEL__       %08x\n" % 0
+            i = 0
+            for v in vms_with_stes:
+                mapfile += \
+                 "LABEL->SSID VM  STE    %-20s %x\n" % (v, i+1)
+                i += 1
+            j = 0
+            for r in resnames:
+                mapfile += \
+                 "LABEL->SSID RES STE    %-20s %x\n" % (r, j+i+1)
+                j += 1
+            mapfile += "\n"
+
+        if vms_with_chws:
+            mapfile += \
+                 "SSID->TYPE CHWALL      %08x\n" % 0
+            i = 1
+            for v in vms_with_chws:
+                mapfile += \
+                 "SSID->TYPE CHWALL      %08x" % i
+                for c in chws_by_vm[v]:
+                    mapfile += " %s" % c
+                mapfile += "\n"
+                i += 1
+            mapfile += "\n"
+
+        if len(vms_with_stes) > 0 or len(resnames) > 0:
+            mapfile += \
+                 "SSID->TYPE STE         %08x\n" % 0
+            i = 1
+            for v in vms_with_stes:
+                mapfile += \
+                 "SSID->TYPE STE         %08x" % i
+                for s in stes_by_vm[v]:
+                    mapfile += " %s" % s
+                mapfile += "\n"
+                i += 1
+
+            for r in resnames:
+                mapfile += \
+                 "SSID->TYPE STE         %08x" % i
+                for s in stes_by_res[r]:
+                    mapfile += " %s" % s
+                mapfile += "\n"
+                i += 1
+            mapfile += "\n"
+
+        if chws:
+            i = 0
+            while i < len(chws):
+                mapfile += \
+                 "TYPE CHWALL            %-20s %d\n" % (chws[i], i)
+                i += 1
+            mapfile += "\n"
+        if stes:
+            i = 0
+            while i < len(stes):
+                mapfile += \
+                 "TYPE STE               %-20s %d\n" % (stes[i], i)
+                i += 1
+            mapfile += "\n"
+
+        mapfile += "\n"
+
+        # Build header with policy name
+        length = roundup8(4 + len(self.get_name()) + 1)
+        polname = self.get_name();
+        pr_bin = struct.pack("!i", len(polname)+1)
+        pr_bin += polname;
+        while len(pr_bin) < length:
+             pr_bin += "\x00"
+
+        # Build chinese wall part
+        cfses_names = self.policy_get_chwall_cfses_names_sorted()
+        cfses = self.policy_get_chwall_cfses()
+
+        chwformat = "!iiiiiiiii"
+        max_chw_cfs = len(cfses)
+        chw_ssid_offset = struct.calcsize(chwformat)
+        chw_confset_offset = chw_ssid_offset + \
+                             2 * len(chws) * max_chw_types
+        chw_running_types_offset = 0
+        chw_conf_agg_offset = 0
+
+        chw_bin = struct.pack(chwformat,
+                              ACM_CHWALL_VERSION,
+                              ACM_CHINESE_WALL_POLICY,
+                              len(chws),
+                              max_chw_ssids,
+                              max_chw_cfs,
+                              chw_ssid_offset,
+                              chw_confset_offset,
+                              chw_running_types_offset,
+                              chw_conf_agg_offset)
+        chw_bin_body = ""
+        # simulate __NULL_LABEL__
+        for c in chws:
+            chw_bin_body += struct.pack("!h",0)
+        # VMs that are listed and their chinese walls
+        for v in vms_with_chws:
+            for c in chws:
+                unknown_chw |= (set(chws_by_vm[v]) - set(chws))
+                if c in chws_by_vm[v]:
+                    chw_bin_body += struct.pack("!h",1)
+                else:
+                    chw_bin_body += struct.pack("!h",0)
+
+        # Conflict sets -- they need to be processed in alphabetical order
+        for cn in cfses_names:
+            if cn == "" or cn is None:
+                return -xsconstants.XSERR_BAD_CONFLICTSET, "", ""
+            i = 0
+            while i < len(cfses):
+                if cfses[i]['name'] == cn:
+                    conf = cfses[i]['chws']
+                    break
+                i += 1
+            for c in chws:
+                if c in conf:
+                    chw_bin_body += struct.pack("!h",1)
+                else:
+                    chw_bin_body += struct.pack("!h",0)
+            del cfses[i]
+
+        if len(cfses) != 0:
+            return -xsconstants.XSERR_BAD_CONFLICTSET, "", ""
+
+        chw_bin += chw_bin_body
+
+        while len(chw_bin) < roundup8(len(chw_bin)):
+            chw_bin += "\x00"
+
+        # Build STE part
+        steformat="!iiiii"
+        ste_bin = struct.pack(steformat,
+                              ACM_STE_VERSION,
+                              ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+                              len(stes),
+                              max_ste_types,
+                              struct.calcsize(steformat))
+        ste_bin_body = ""
+        if stes:
+            # Simulate __NULL_LABEL__
+            for s in stes:
+                ste_bin_body += struct.pack("!h",0)
+            # VMs that are listed and their chinese walls
+            for v in vms_with_stes:
+                unknown_ste |= (set(stes_by_vm[v]) - set(stes))
+                for s in stes:
+                    if s in stes_by_vm[v]:
+                        ste_bin_body += struct.pack("!h",1)
+                    else:
+                        ste_bin_body += struct.pack("!h",0)
+            for r in resnames:
+                unknown_ste |= (set(stes_by_res[r]) - set(stes))
+                for s in stes:
+                    if s in stes_by_res[r]:
+                        ste_bin_body += struct.pack("!h",1)
+                    else:
+                        ste_bin_body += struct.pack("!h",0)
+
+        ste_bin += ste_bin_body;
+
+        while len(ste_bin) < roundup8(len(ste_bin)):
+            ste_bin += "\x00"
+
+        #Write binary header:
+        headerformat="!iiiiiiiiii"
+        totallen_bin = struct.calcsize(headerformat) + \
+                       len(pr_bin) + len(chw_bin) + len(ste_bin)
+        polref_offset = struct.calcsize(headerformat)
+        primpoloffset = polref_offset + len(pr_bin)
+        if primpolcode == ACM_CHINESE_WALL_POLICY:
+            secpoloffset = primpoloffset + len(chw_bin)
+        elif primpolcode == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+            secpoloffset = primpoloffset + len(ste_bin)
+        else:
+            secpoloffset = primpoloffset
+
+        (major, minor) = self.getVersionTuple()
+        hdr_bin = struct.pack(headerformat,
+                              ACM_POLICY_VERSION,
+                              ACM_MAGIC,
+                              totallen_bin,
+                              polref_offset,
+                              primpolcode,
+                              primpoloffset,
+                              secpolcode,
+                              secpoloffset,
+                              major, minor)
+
+        all_bin = array.array('B')
+        for s in [ hdr_bin, pr_bin, chw_bin, ste_bin ]:
+            for c in s:
+                all_bin.append(ord(c))
+
+        log.info("Compiled policy: rc = %s" % hex(rc))
+        if len(unknown_ste) > 0:
+            log.info("The following STEs in VM/res labels were unknown:" \
+                     " %s" % list(unknown_ste))
+        if len(unknown_chw) > 0:
+            log.info("The following Ch. Wall types in labels were unknown:" \
+                     " %s" % list(unknown_chw))
+        return rc, mapfile, all_bin.tostring()
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/util/bootloader.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/bootloader.py       Mon Jul 09 14:51:44 2007 +0100
@@ -0,0 +1,521 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006,2007 International Business Machines Corp.
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
+#============================================================================
+
+import re
+import os, stat
+import tempfile
+import shutil
+import threading
+from xen.xend.XendLogging import log
+
+__bootloader = None
+
+#
+# Functions for modifying entries in the bootloader, i.e. adding
+# a module to boot the system with a policy.
+#
+
+def get_default_title():
+    """ See description in Bootloader class below """
+    return __bootloader.get_default_title()
+
+
+def get_boot_policies():
+    """ See description in Bootloader class below """
+    return __bootloader.get_boot_policies()
+
+
+def add_boot_policy(index, binpolname):
+    """ See description in Bootloader class below """
+    return __bootloader.add_boot_policy(index, binpolname)
+
+
+def rm_policy_from_boottitle(index, unamelist):
+    """ See description in Bootloader class below """
+    return __bootloader.rm_policy_from_boottitle(index, unamelist)
+
+
+def set_kernel_attval(index, att, val):
+    """ See description in Bootloader class below """
+    return __bootloader.set_kernel_attval(index, att, val)
+
+
+def get_kernel_val(index, att):
+    """ See description in Bootloader class below """
+    return __bootloader.get_kernel_val(index, att)
+
+
+def set_boot_policy(title_idx, filename):
+    boottitles = get_boot_policies()
+    if boottitles.has_key(title_idx):
+        rm_policy_from_boottitle(title_idx, [ boottitles[title_idx] ])
+    rc = add_boot_policy(title_idx, filename)
+    return rc
+
+
+def loads_default_policy(filename):
+    """ Determine whether the given policy is loaded by the default boot title 
"""
+    polfile = get_default_policy()
+    if polfile != None:
+        if     polfile == filename or \
+           "/"+polfile == filename:
+            return True
+    return False
+
+
+def get_default_policy():
+    """ Get the name of the policy loaded by the default boot title """
+    title = get_default_title()
+    policies = get_boot_policies()
+    return policies.get(title)
+
+
+def set_default_boot_policy(filename):
+    """ Set the boot policy in the default title to the given name. """
+    title = get_default_title()
+    return set_boot_policy(title, filename)
+
+
+def __is_bootdir_mounted():
+    """
+       Determine whether the boot partition /boot is mounted or not
+    """
+    rc = False
+    file = open("/proc/mounts")
+    for line in file:
+        tmp = line.split(" ")
+        if tmp[1] == "/boot":
+            rc = True
+            break
+    return rc
+
+def get_prefix():
+    if __is_bootdir_mounted():
+        return "/"
+    else:
+        return "/boot/"
+
+
+
+class Bootloader:
+    """ Bootloader class that real bootloader implementations must overwrite 
"""
+    def __init__(self):
+        pass
+
+    def probe(self):
+        """ Test whether this implementation of a bootloader is supported on 
the
+            local system """
+        return True
+
+    def get_default_title(self):
+        """ Get the index (starting with 0) of the default boot title
+            This number is read from the grub configuration file.
+            In case of an error '-1' is returned
+            @rtype: int
+            @return: the index of the default boot title
+        """
+        return None
+
+    def get_boot_policies(self):
+        """ Get a dictionary of policies that the system is booting with.
+            @rtype: dict
+            @return: dictionary of boot titles where the keys are the
+                     indices of the boot titles
+        """
+        return {}
+
+    def add_boot_policy(self, index, binpolname):
+        """ Add the binary policy for automatic loading when
+            booting the system. Add it to the boot title at index
+            'index'.
+        """
+        return False
+
+    def rm_policy_from_boottitle(self, index, unamelist):
+        """ Remove a policy from the given title. A list of possible policies
+            must be given to detect what module to remove
+        """
+        return False
+
+    def set_kernel_attval(self, index, att, val):
+        """
+            Append an attribut/value pair to the kernel line.
+            @param index : The index of the title to modify
+            @param att   : The attribute to add
+            @param val   : The value to add. If no value or the special value
+                           '<>' is given, then the attribute will be removed.
+                           If an empty value is given, then only the attribute
+                           is added in the format "att", otherwise "att=val"
+                           is added.
+        """
+        return False
+
+    def get_kernel_val(self, index, att):
+        """
+            Get an attribute's value from the kernel line.
+            @param index : The index of the title to get the attribute/value 
from
+            @param att   : The attribute to read the value of
+        """
+        return None
+
+
+class Grub(Bootloader):
+    """ Implementation for manipulating bootloader entries in grub according
+        to the 'Bootloader' class interface """
+
+    def __init__(self):
+        self.__bootfile_lock = threading.RLock()
+        self.title_re = re.compile("\s*title\s", re.IGNORECASE)
+        self.module_re = re.compile("\s+module\s", re.IGNORECASE)
+        self.policy_re = re.compile(".*\.bin", re.IGNORECASE)
+        self.kernel_re = re.compile("\s*kernel\s", re.IGNORECASE)
+        Bootloader.__init__(self)
+
+    def probe(self):
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return False
+        return True
+
+
+    def __get_bootfile(self):
+        """ Get the name of the bootfile """
+        boot_file = "/boot/grub/grub.conf"
+        alt_boot_file = "/boot/grub/menu.lst"
+
+        if not os.path.isfile(boot_file):
+            #take alternate boot file instead
+            boot_file = alt_boot_file
+
+        #follow symlink since menue.lst might be linked to grub.conf
+        if not os.path.exists(boot_file):
+            raise IOError("Boot file \'%s\' not found." % boot_file)
+
+        if stat.S_ISLNK(os.lstat(boot_file)[stat.ST_MODE]):
+            new_name = os.readlink(boot_file)
+            if new_name[0] == "/":
+                boot_file = new_name
+            else:
+                path = boot_file.split('/')
+                path[len(path)-1] = new_name
+                boot_file = '/'.join(path)
+        if not os.path.exists(boot_file):
+            raise IOError("Boot file \'%s\' not found." % boot_file)
+        return boot_file
+
+
+    def __get_titles(self):
+        """ Get the names of all boot titles in the grub config file
+          @rtype: list
+          @return: list of names of available boot titles
+        """
+        titles = []
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return []
+        try:
+            self.__bootfile_lock.acquire()
+            grub_fd = open(boot_file)
+            for line in grub_fd:
+                if self.title_re.match(line):
+                    line = line.rstrip().lstrip()
+                    titles.append(line.lstrip('title').lstrip())
+        finally:
+            self.__bootfile_lock.release()
+        return titles
+
+
+    def get_default_title(self):
+        """ Get the index (starting with 0) of the default boot title
+            This number is read from the grub configuration file.
+            In case of an error '-1' is returned
+            @rtype: int
+            @return: the index of the default boot title
+        """
+        def_re = re.compile("default", re.IGNORECASE)
+        default = None
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return default
+        try:
+            self.__bootfile_lock.acquire()
+            grub_fd = open(boot_file)
+            for line in grub_fd:
+                line = line.rstrip()
+                if def_re.match(line):
+                    line = line.rstrip()
+                    line = line.lstrip("default=")
+                    default = int(line)
+                    break
+        finally:
+            self.__bootfile_lock.release()
+        return default
+
+
+    def get_boot_policies(self):
+        """ Get a dictionary of policies that the system is booting with.
+            @rtype: dict
+            @return: dictionary of boot titles where the keys are the
+                     indices of the boot titles
+        """
+        policies = {}
+        within_title = 0
+        idx = -1
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return policies
+        try:
+            self.__bootfile_lock.acquire()
+
+            grub_fd = open(boot_file)
+            for line in grub_fd:
+                if self.title_re.match(line):
+                    within_title = 1
+                    idx = idx + 1
+                if within_title and self.module_re.match(line):
+                    if self.policy_re.match(line):
+                        start = line.find("module")
+                        pol = line[start+6:]
+                        pol = pol.lstrip().rstrip()
+                        if pol[0] == '/':
+                            pol = pol[1:]
+                        if pol[0:5] == "boot/":
+                            pol = pol[5:]
+                        policies[idx] = pol
+        finally:
+            self.__bootfile_lock.release()
+        return policies
+
+
+    def add_boot_policy(self, index, binpolname):
+        """ Add the binary policy for automatic loading when
+            booting the system. Add it to the boot title at index
+            'index'.
+        """
+        ctr = 0
+        module_line = ""
+        within_title = 0
+        found = False
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return False
+        try:
+            self.__bootfile_lock.acquire()
+            grub_fd = open(boot_file)
+            (tmp_fd, tmp_grub) = tempfile.mkstemp()
+            for line in grub_fd:
+                if self.title_re.match(line):
+                    if module_line != "" and not found:
+                        os.write(tmp_fd, module_line)
+                        found = True
+
+                    if ctr == index:
+                        within_title = 1
+                    else:
+                        within_title = 0
+                    ctr = ctr + 1
+                elif within_title and self.module_re.match(line):
+                    start = line.find("module")
+                    l = line[start+6:len(line)]
+                    l = l.lstrip()
+                    if l[0] == '/':
+                        prefix = "/"
+                    else:
+                        prefix = ""
+                    prefix = get_prefix()
+                    module_line = "\tmodule %s%s\n" % (prefix,binpolname)
+                else:
+                    if module_line != "" and not found:
+                        os.write(tmp_fd, module_line)
+                        found = True
+
+                os.write(tmp_fd, line)
+
+            if module_line != "" and not found:
+                os.write(tmp_fd, module_line)
+                found = True
+
+            shutil.move(boot_file, boot_file+"_save")
+            shutil.copyfile(tmp_grub, boot_file)
+            os.close(tmp_fd)
+            try:
+                os.remove(tmp_grub)
+            except:
+                pass
+        finally:
+            self.__bootfile_lock.release()
+        return found
+
+
+    def rm_policy_from_boottitle(self, index, unamelist):
+        """ Remove a policy from the given title. A list of possible policies
+            must be given to detect what module to remove
+        """
+        found = False
+        ctr = 0
+        within_title = 0
+
+        prefix = get_prefix()
+        namelist = [prefix+name for name in unamelist]
+
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return False
+        try:
+            self.__bootfile_lock.acquire()
+
+            grub_fd = open(boot_file)
+            (tmp_fd, tmp_grub) = tempfile.mkstemp()
+            for line in grub_fd:
+                omit_line = False
+                if self.title_re.match(line):
+                    if ctr == index:
+                        within_title = 1
+                    else:
+                        within_title = 0
+                    ctr = ctr + 1
+                if within_title and self.module_re.match(line):
+                    if self.policy_re.match(line):
+                        start = line.find("module")
+                        pol = line[start+6:len(line)]
+                        pol = pol.lstrip().rstrip()
+                        if pol in namelist:
+                            omit_line = True
+                            found = True
+                if not omit_line:
+                    os.write(tmp_fd, line)
+            if found:
+                shutil.move(boot_file, boot_file+"_save")
+                shutil.copyfile(tmp_grub, boot_file)
+            os.close(tmp_fd)
+            try:
+                os.remove(tmp_grub)
+            except:
+                pass
+        finally:
+            self.__bootfile_lock.release()
+        return found
+
+
+    def set_kernel_attval(self, index, att, val):
+        """
+            Append an attribut/value pair to the kernel line.
+            @param index : The index of the title to modify
+            @param att   : The attribute to add
+            @param val   : The value to add. If no value or the special value
+                           '<>' is given, then the attribute will be removed.
+                           If an empty value is given, then only the attribute
+                           is added in the format "att", otherwise "att=val"
+                           is added.
+        """
+        found = False
+        ctr = 0
+        within_title = 0
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            False
+        try:
+            self.__bootfile_lock.acquire()
+
+            grub_fd = open(boot_file)
+            (tmp_fd, tmp_grub) = tempfile.mkstemp()
+            for line in grub_fd:
+                if self.title_re.match(line):
+                    if ctr == index:
+                        within_title = 1
+                    else:
+                        within_title = 0
+                    ctr = ctr + 1
+                if within_title and self.kernel_re.match(line):
+                    nitems = []
+                    items = line.split(" ")
+                    i = 0
+                    while i < len(items):
+                        el = items[i].split("=",1)
+                        if el[0] != att:
+                            nitems.append(items[i].rstrip("\n"))
+                        i += 1
+                    if val == "":
+                        nitems.append("%s" % (att))
+                    elif val != None and val != "<>":
+                        nitems.append("%s=%s" % (att,val))
+                    line = " ".join(nitems) + "\n"
+                os.write(tmp_fd, line)
+            shutil.move(boot_file, boot_file+"_save")
+            shutil.copyfile(tmp_grub, boot_file)
+            os.close(tmp_fd)
+            try:
+                os.remove(tmp_grub)
+            except:
+                pass
+        finally:
+            self.__bootfile_lock.release()
+        return found
+
+
+    def get_kernel_val(self, index, att):
+        """
+            Get an attribute's value from the kernel line.
+            @param index : The index of the title to get the attribute/value 
from
+            @param att   : The attribute to read the value of
+        """
+        ctr = 0
+        within_title = 0
+        try:
+            boot_file = self.__get_bootfile()
+        except:
+            return None
+        try:
+            self.__bootfile_lock.acquire()
+
+            grub_fd = open(boot_file)
+            for line in grub_fd:
+                if self.title_re.match(line):
+                    if ctr == index:
+                        within_title = 1
+                    else:
+                        within_title = 0
+                    ctr = ctr + 1
+                if within_title and self.kernel_re.match(line):
+                    line = line.rstrip().lstrip()
+                    items = line.split(" ")
+                    i = 0
+                    while i < len(items):
+                        el = items[i].split("=",1)
+                        if el[0] == att:
+                            if len(el) == 1:
+                                return "<>"
+                            return el[1]
+                        i += 1
+        finally:
+            self.__bootfile_lock.release()
+        return None # Not found
+
+
+__bootloader = Bootloader()
+
+grub = Grub()
+if grub.probe() == True:
+    __bootloader = grub
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/util/security.py
--- a/tools/python/xen/util/security.py Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/util/security.py Mon Jul 09 14:51:44 2007 +0100
@@ -15,17 +15,22 @@
 # Copyright (C) 2006 International Business Machines Corp.
 # Author: Reiner Sailer
 # Author: Bryan D. Payne <bdpayne@xxxxxxxxxx>
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
 #============================================================================
 
 import commands
 import logging
-import sys, os, string, re
-import traceback
-import shutil
+import os, string, re
+import threading
+import struct
+import stat
 from xen.lowlevel import acm
 from xen.xend import sxp
+from xen.xend import XendConstants
 from xen.xend.XendLogging import log
-from xen.util import dictio
+from xen.xend.XendError import VmError
+from xen.util import dictio, xsconstants
+from xen.xend.XendConstants import *
 
 #global directories and tools for security management
 policy_dir_prefix = "/etc/xen/acm-security/policies"
@@ -60,6 +65,10 @@ policy_name_re = re.compile(".*[chwall|s
 #other global variables
 NULL_SSIDREF = 0
 
+#general Rlock for map files; only one lock for all mapfiles
+__mapfile_lock = threading.RLock()
+__resfile_lock = threading.RLock()
+
 log = logging.getLogger("xend.util.security")
 
 # Our own exception definition. It is masked (pass) if raised and
@@ -75,12 +84,18 @@ def err(msg):
 def err(msg):
     """Raise ACM exception.
     """
-    sys.stderr.write("ACMError: " + msg + "\n")
     raise ACMError(msg)
 
 
 
 active_policy = None
+
+
+def mapfile_lock():
+    __mapfile_lock.acquire()
+
+def mapfile_unlock():
+    __mapfile_lock.release()
 
 
 def refresh_security_policy():
@@ -106,6 +121,39 @@ def on():
     return (active_policy not in ['INACTIVE', 'NULL'])
 
 
+def calc_dom_ssidref_from_info(info):
+    """
+       Calculate a domain's ssidref from the security_label in its
+       info.
+       This function is called before the domain is started and
+       makes sure that:
+        - the type of the policy is the same as indicated in the label
+        - the name of the policy is the same as indicated in the label
+        - calculates an up-to-date ssidref for the domain
+       The latter is necessary since the domain's ssidref could have
+       changed due to changes to the policy.
+    """
+    import xen.xend.XendConfig
+    if isinstance(info, xen.xend.XendConfig.XendConfig):
+        if info.has_key('security_label'):
+            seclab = info['security_label']
+            tmp = seclab.split(":")
+            if len(tmp) != 3:
+                raise VmError("VM label '%s' in wrong format." % seclab)
+            typ, policyname, vmlabel = seclab.split(":")
+            if typ != xsconstants.ACM_POLICY_ID:
+                raise VmError("Policy type '%s' not supported." % typ)
+            refresh_security_policy()
+            if active_policy != policyname:
+                raise VmError("Active policy '%s' different than "
+                              "what in VM's label ('%s')." %
+                              (active_policy, policyname))
+            ssidref = label2ssidref(vmlabel, policyname, "dom")
+            return ssidref
+        else:
+            return 0
+    raise VmError("security.calc_dom_ssidref_from_info: info of type '%s'"
+                  "not supported." % type(info))
 
 # Assumes a 'security' info  [security access_control ...] [ssidref ...]
 def get_security_info(info, field):
@@ -144,7 +192,6 @@ def get_security_info(info, field):
         return 0
     else:
         return None
-
 
 
 def get_security_printlabel(info):
@@ -250,32 +297,37 @@ def ssidref2label(ssidref_var):
     else:
         err("Instance type of ssidref not supported (must be of type 'str' or 
'int')")
 
-    (primary, secondary, f, pol_exists) = getmapfile(None)
-    if not f:
-        if (pol_exists):
-            err("Mapping file for policy \'" + policyname + "\' not found.\n" +
-                "Please use makepolicy command to create mapping file!")
-        else:
-            err("Policy file for \'" + active_policy + "\' not found.")
-
-    #2. get labelnames for both ssidref parts
-    pri_ssid = ssidref & 0xffff
-    sec_ssid = ssidref >> 16
-    pri_null_ssid = NULL_SSIDREF & 0xffff
-    sec_null_ssid = NULL_SSIDREF >> 16
-    pri_labels = []
-    sec_labels = []
-    labels = []
-
-    for line in f:
-        l = line.split()
-        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-            continue
-        if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
-            pri_labels.append(l[3])
-        if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
-            sec_labels.append(l[3])
-    f.close()
+    try:
+        mapfile_lock()
+
+        (primary, secondary, f, pol_exists) = getmapfile(None)
+        if not f:
+            if (pol_exists):
+                err("Mapping file for policy not found.\n" +
+                    "Please use makepolicy command to create mapping file!")
+            else:
+                err("Policy file for \'" + active_policy + "\' not found.")
+
+        #2. get labelnames for both ssidref parts
+        pri_ssid = ssidref & 0xffff
+        sec_ssid = ssidref >> 16
+        pri_null_ssid = NULL_SSIDREF & 0xffff
+        sec_null_ssid = NULL_SSIDREF >> 16
+        pri_labels = []
+        sec_labels = []
+        labels = []
+
+        for line in f:
+            l = line.split()
+            if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+                continue
+            if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
+                pri_labels.append(l[3])
+            if secondary and (l[2] == secondary) and (int(l[4], 16) == 
sec_ssid):
+                sec_labels.append(l[3])
+        f.close()
+    finally:
+        mapfile_unlock()
 
     #3. get the label that is in both lists (combination must be a single 
label)
     if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != 
sec_null_ssid):
@@ -297,7 +349,7 @@ def ssidref2label(ssidref_var):
 
 
 
-def label2ssidref(labelname, policyname, type):
+def label2ssidref(labelname, policyname, typ):
     """
     returns ssidref corresponding to labelname;
     maps current policy to default directory
@@ -307,42 +359,51 @@ def label2ssidref(labelname, policyname,
         err("Cannot translate labels for \'" + policyname + "\' policy.")
 
     allowed_types = ['ANY']
-    if type == 'dom':
+    if typ == 'dom':
         allowed_types.append('VM')
-    elif type == 'res':
+    elif typ == 'res':
         allowed_types.append('RES')
     else:
         err("Invalid type.  Must specify 'dom' or 'res'.")
 
-    (primary, secondary, f, pol_exists) = getmapfile(policyname)
-
-    #2. get labelnames for ssidref parts and find a common label
-    pri_ssid = []
-    sec_ssid = []
-    for line in f:
-        l = line.split()
-        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-            continue
-        if primary and (l[1] in allowed_types) and (l[2] == primary) and (l[3] 
== labelname):
-            pri_ssid.append(int(l[4], 16))
-        if secondary and (l[1] in allowed_types) and (l[2] == secondary) and 
(l[3] == labelname):
-            sec_ssid.append(int(l[4], 16))
-    f.close()
-    if (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
-        pri_ssid.append(NULL_SSIDREF)
-    elif (type == 'res') and (secondary == "CHWALL") and (len(sec_ssid) == 0):
-        sec_ssid.append(NULL_SSIDREF)
-
-    #3. sanity check and composition of ssidref
-    if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and (secondary != 
"NULL")):
-        err("Label \'" + labelname + "\' not found.")
-    elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
-        err("Label \'" + labelname + "\' not unique in policy (policy error)")
-    if secondary == "NULL":
-        return pri_ssid[0]
-    else:
-        return (sec_ssid[0] << 16) | pri_ssid[0]
-
+    try:
+        mapfile_lock()
+        (primary, secondary, f, pol_exists) = getmapfile(policyname)
+
+        #2. get labelnames for ssidref parts and find a common label
+        pri_ssid = []
+        sec_ssid = []
+        for line in f:
+            l = line.split()
+            if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+                continue
+            if primary and (l[1] in allowed_types) and \
+                           (l[2] == primary) and \
+                           (l[3] == labelname):
+                pri_ssid.append(int(l[4], 16))
+            if secondary and (l[1] in allowed_types) and \
+                             (l[2] == secondary) and \
+                             (l[3] == labelname):
+                sec_ssid.append(int(l[4], 16))
+        f.close()
+        if (typ == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
+            pri_ssid.append(NULL_SSIDREF)
+        elif (typ == 'res') and (secondary == "CHWALL") and \
+             (len(sec_ssid) == 0):
+            sec_ssid.append(NULL_SSIDREF)
+
+        #3. sanity check and composition of ssidref
+        if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and \
+            (secondary != "NULL")):
+            err("Label \'" + labelname + "\' not found.")
+        elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
+            err("Label \'" + labelname + "\' not unique in policy (policy 
error)")
+        if secondary == "NULL":
+            return pri_ssid[0]
+        else:
+            return (sec_ssid[0] << 16) | pri_ssid[0]
+    finally:
+       mapfile_unlock()
 
 
 def refresh_ssidref(config):
@@ -381,8 +442,9 @@ def refresh_ssidref(config):
                     err("Illegal field in access_control")
     #verify policy is correct
     if active_policy != policyname:
-        err("Policy \'" + policyname + "\' in label does not match active 
policy \'"
-            + active_policy +"\'!")
+        err("Policy \'" + str(policyname) +
+            "\' in label does not match active policy \'"
+            + str(active_policy) +"\'!")
 
     new_ssidref = label2ssidref(labelname, policyname, 'dom')
     if not new_ssidref:
@@ -470,6 +532,25 @@ def get_decision(arg1, arg2):
         err("Cannot determine decision (Invalid parameter).")
 
 
+def hv_chg_policy(bin_pol, del_array, chg_array):
+    """
+        Change the binary policy in the hypervisor
+        The 'del_array' and 'chg_array' give hints about deleted ssidrefs
+        and changed ssidrefs which can be due to deleted VM labels
+        or reordered VM labels
+    """
+    rc = -xsconstants.XSERR_GENERAL_FAILURE
+    errors = ""
+    if not on():
+        err("No policy active.")
+    try:
+        rc, errors = acm.chgpolicy(bin_pol, del_array, chg_array)
+    except Exception, e:
+        pass
+    if (len(errors) > 0):
+        rc = -xsconstants.XSERR_HV_OP_FAILED
+    return rc, errors
+
 
 def make_policy(policy_name):
     policy_file = string.join(string.split(policy_name, "."), "/")
@@ -479,8 +560,6 @@ def make_policy(policy_name):
     (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + 
policy_dir_prefix + " " + policy_file)
     if ret:
         err("Creating policy failed:\n" + output)
-
-
 
 def load_policy(policy_name):
     global active_policy
@@ -538,8 +617,8 @@ def list_labels(policy_name, condition):
 
 
 def get_res_label(resource):
-    """Returns resource label information (label, policy) if it exists.
-       Otherwise returns null label and policy.
+    """Returns resource label information (policytype, label, policy) if
+       it exists. Otherwise returns null label and policy.
     """
     def default_res_label():
         ssidref = NULL_SSIDREF
@@ -547,23 +626,19 @@ def get_res_label(resource):
             label = ssidref2label(ssidref)
         else:
             label = None
-        return (label, 'NULL')
-
-    (label, policy) = default_res_label()
-
-    # load the resource label file
-    res_label_cache = {}
-    try:
-        res_label_cache = dictio.dict_read("resources", res_label_filename)
-    except:
-        log.info("Resource label file not found.")
-        return default_res_label()
-
-    # find the resource information
-    if res_label_cache.has_key(resource):
-        (policy, label) = res_label_cache[resource]
-
-    return (label, policy)
+        return (xsconstants.ACM_POLICY_ID, 'NULL', label)
+
+
+    tmp = get_resource_label(resource)
+    if len(tmp) == 2:
+        policytype = xsconstants.ACM_POLICY_ID
+        policy, label = tmp
+    elif len(tmp) == 3:
+        policytype, policy, label = tmp
+    else:
+        policytype, policy, label = default_res_label()
+
+    return (policytype, label, policy)
 
 
 def get_res_security_details(resource):
@@ -582,7 +657,7 @@ def get_res_security_details(resource):
     (label, ssidref, policy) = default_security_details()
 
     # find the entry associated with this resource
-    (label, policy) = get_res_label(resource)
+    (policytype, label, policy) = get_res_label(resource)
     if policy == 'NULL':
         log.info("Resource label for "+resource+" not in file, using DEFAULT.")
         return default_security_details()
@@ -596,8 +671,29 @@ def get_res_security_details(resource):
 
     return (label, ssidref, policy)
 
-
-def unify_resname(resource):
+def security_label_to_details(seclab):
+    """ Convert a Xen-API type of security label into details """
+    def default_security_details():
+        ssidref = NULL_SSIDREF
+        if on():
+            label = ssidref2label(ssidref)
+        else:
+            label = None
+        policy = active_policy
+        return (label, ssidref, policy)
+
+    (policytype, policy, label) = seclab.split(":")
+
+    # is this resource label for the running policy?
+    if policy == active_policy:
+        ssidref = label2ssidref(label, policy, 'res')
+    else:
+        log.info("Resource label not for active policy, using DEFAULT.")
+        return default_security_details()
+
+    return (label, ssidref, policy)
+
+def unify_resname(resource, mustexist=True):
     """Makes all resource locations absolute. In case of physical
     resources, '/dev/' is added to local file names"""
 
@@ -606,28 +702,53 @@ def unify_resname(resource):
 
     # sanity check on resource name
     try:
-        (type, resfile) = resource.split(":", 1)
+        (typ, resfile) = resource.split(":", 1)
     except:
         err("Resource spec '%s' contains no ':' delimiter" % resource)
 
-    if type == "tap":
+    if typ == "tap":
         try:
             (subtype, resfile) = resfile.split(":")
         except:
             err("Resource spec '%s' contains no tap subtype" % resource)
 
-    if type in ["phy", "tap"]:
+    import os
+    if typ in ["phy", "tap"]:
         if not resfile.startswith("/"):
             resfile = "/dev/" + resfile
+        if mustexist:
+            stats = os.lstat(resfile)
+            if stat.S_ISLNK(stats[stat.ST_MODE]):
+                resolved = os.readlink(resfile)
+                if resolved[0] != "/":
+                    resfile = os.path.join(os.path.dirname(resfile), resolved)
+                    resfile = os.path.abspath(resfile)
+                else:
+                    resfile = resolved
+                stats = os.lstat(resfile)
+            if not (stat.S_ISBLK(stats[stat.ST_MODE])):
+                err("Invalid resource")
+
+    if typ in [ "file", "tap" ]:
+        if mustexist:
+            stats = os.lstat(resfile)
+            if stat.S_ISLNK(stats[stat.ST_MODE]):
+                resfile = os.readlink(resfile)
+                stats = os.lstat(resfile)
+            if not stat.S_ISREG(stats[stat.ST_MODE]):
+                err("Invalid resource")
 
     #file: resources must specified with absolute path
-    if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
-        err("Invalid resource.")
+    #vlan resources don't start with '/'
+    if typ != "vlan":
+        if (not resfile.startswith("/")) or \
+           (mustexist and not os.path.exists(resfile)):
+            err("Invalid resource.")
 
     # from here on absolute file names with resources
-    if type == "tap":
-        type = type + ":" + subtype
-    resource = type + ":" + resfile
+    if typ == "tap":
+        typ = typ + ":" + subtype
+    resource = typ + ":" + resfile
     return resource
 
 
@@ -662,9 +783,481 @@ def res_security_check(resource, domain_
     else:
         # Note, we can't canonicalise the resource here, because people using
         # xm without ACM are free to use relative paths.
-        (label, policy) = get_res_label(resource)
+        (policytype, label, policy) = get_res_label(resource)
         if policy != 'NULL':
             raise ACMError("Security is off, but '"+resource+"' is labeled")
             rtnval = 0
 
     return rtnval
+
+def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label):
+    """Checks if the given resource can be used by the given domain
+       label.  Returns 1 if the resource can be used, otherwise 0.
+    """
+    rtnval = 1
+    # if security is on, ask the hypervisor for a decision
+    if on():
+        typ, dpolicy, domain_label = xapi_dom_label.split(":")
+        if not dpolicy or not domain_label:
+            raise VmError("VM security label in wrong format.")
+        if active_policy != rpolicy:
+            raise VmError("Resource's policy '%s' != active policy '%s'" %
+                          (rpolicy, active_policy))
+        domac = ['access_control']
+        domac.append(['policy', active_policy])
+        domac.append(['label', domain_label])
+        domac.append(['type', 'dom'])
+        decision = get_decision(domac, ['ssidref', str(rssidref)])
+
+        log.info("Access Control Decision : %s" % decision)
+        # provide descriptive error messages
+        if decision == 'DENIED':
+            if rlabel == ssidref2label(NULL_SSIDREF):
+                #raise ACMError("Resource is not labeled")
+                rtnval = 0
+            else:
+                #raise ACMError("Permission denied for resource because label 
'"+rlabel+"' is not allowed")
+                rtnval = 0
+
+    # security is off, make sure resource isn't labeled
+    else:
+        # Note, we can't canonicalise the resource here, because people using
+        # xm without ACM are free to use relative paths.
+        if rpolicy != 'NULL':
+            #raise ACMError("Security is off, but resource is labeled")
+            rtnval = 0
+
+    return rtnval
+
+
+def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi):
+    """Assign a resource label to a resource
+    @param resource: The name of a resource, i.e., "phy:/dev/hda", or
+              "tap:qcow:/path/to/file.qcow"
+
+    @param reslabel_xapi: A resource label foramtted as in all other parts of
+                          the Xen-API, i.e., ACM:xm-test:blue"
+    @rtype: int
+    @return Success (0) or failure value (< 0)
+    """
+    olabel = ""
+    if reslabel_xapi == "":
+        return rm_resource_label(resource, oldlabel_xapi)
+    typ, policyref, label = reslabel_xapi.split(":")
+    if typ != xsconstants.ACM_POLICY_ID:
+        return -xsconstants.XSERR_WRONG_POLICY_TYPE
+    if not policyref or not label:
+        return -xsconstants.XSERR_BAD_LABEL_FORMAT
+    if oldlabel_xapi not in [ "" ]:
+        tmp = oldlabel_xapi.split(":")
+        if len(tmp) != 3:
+            return -xsconstants.XSERR_BAD_LABEL_FORMAT
+        otyp, opolicyref, olabel = tmp
+        # Only ACM is supported
+        if otyp != xsconstants.ACM_POLICY_ID:
+            return -xsconstants.XSERR_WRONG_POLICY_TYPE
+    return set_resource_label(resource, typ, policyref, label, olabel)
+
+def is_resource_in_use(resource):
+    """ Investigate all running domains whether they use this device """
+    from xen.xend import XendDomain
+    dominfos = XendDomain.instance().list('all')
+    lst = []
+    for dominfo in dominfos:
+        if is_resource_in_use_by_dom(dominfo, resource):
+            lst.append(dominfo)
+    return lst
+
+def devices_equal(res1, res2):
+    """ Determine whether two devices are equal """
+    return (unify_resname(res1) == unify_resname(res2))
+
+def is_resource_in_use_by_dom(dominfo, resource):
+    """ Determine whether a resources is in use by a given domain
+        @return True or False
+    """
+    if not dominfo.domid:
+        return False
+    if dominfo._stateGet() not in [ DOM_STATE_RUNNING ]:
+        return False
+    devs = dominfo.info['devices']
+    uuids = devs.keys()
+    for uuid in uuids:
+        dev = devs[uuid]
+        if len(dev) >= 2 and dev[1].has_key('uname'):
+            # dev[0] is type, i.e. 'vbd'
+            if devices_equal(dev[1]['uname'], resource):
+                log.info("RESOURCE IN USE: Domain %d uses %s." %
+                         (dominfo.domid, resource))
+                return True
+    return False
+
+
+def get_domain_resources(dominfo):
+    """ Collect all resources of a domain in a map where each entry of
+        the map is a list.
+        Entries are strored in the following formats:
+          tap:qcow:/path/xyz.qcow
+    """
+    resources = { 'vbd' : [], 'tap' : []}
+    devs = dominfo.info['devices']
+    uuids = devs.keys()
+    for uuid in uuids:
+        dev = devs[uuid]
+        typ = dev[0]
+        if typ in [ 'vbd', 'tap' ]:
+            resources[typ].append(dev[1]['uname'])
+
+    return resources
+
+
+def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel):
+    """
+       Check whether the resources' labels are compatible with the
+       given VM label. This is a function to be used when for example
+       a running domain is to get the new label 'vmlabel'
+    """
+    if not xspol:
+        return False
+
+    try:
+        __resfile_lock.acquire()
+        try:
+            access_control = dictio.dict_read("resources",
+                                              res_label_filename)
+        except:
+            return False
+        return __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
+                                                   access_control)
+    finally:
+        __resfile_lock.release()
+    return False
+
+
+def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
+                                        access_control):
+    """
+        Check whether the resources' labels are compatible with the
+        given VM label. The access_control parameter provides a
+        dictionary of the resource name to resource label mappings
+        under which the evaluation should be done.
+    """
+    resources = get_domain_resources(dominfo)
+    reslabels = []  # all resource labels
+    polname = xspol.get_name()
+    for key in resources.keys():
+        for res in resources[key]:
+            try:
+                tmp = access_control[res]
+                if len(tmp) != 3:
+                    return False
+
+                if polname != tmp[1]:
+                    return False
+                label = tmp[2]
+                if not label in reslabels:
+                    reslabels.append(label)
+            except:
+                return False
+    # Check that all resource labes have a common STE type with the
+    # vmlabel
+    rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
+    return rc;
+
+def set_resource_label(resource, policytype, policyref, reslabel, \
+                       oreslabel = None):
+    """Assign a label to a resource
+       If the old label (oreslabel) is given, then the resource must have
+       that old label.
+       A resource label may be changed if
+       - the resource is not in use
+    @param resource  : The name of a resource, i.e., "phy:/dev/hda"
+    @param policyref : The name of the policy
+    @param reslabel     : the resource label within the policy
+    @param oreslabel    : optional current resource label
+
+    @rtype: int
+    @return Success (0) or failure value (< 0)
+    """
+    try:
+        resource = unify_resname(resource, mustexist=False)
+    except Exception:
+        return -xsconstants.XSERR_BAD_RESOURCE_FORMAT
+
+    domains = is_resource_in_use(resource)
+    if len(domains) > 0:
+        return -xsconstants.XSERR_RESOURCE_IN_USE
+
+    try:
+        __resfile_lock.acquire()
+        access_control = {}
+        try:
+             access_control = dictio.dict_read("resources", res_label_filename)
+        except:
+            pass
+        if oreslabel:
+            if not access_control.has_key(resource):
+                return -xsconstants.XSERR_BAD_LABEL
+            tmp = access_control[resource]
+            if len(tmp) != 3:
+                return -xsconstants.XSERR_BAD_LABEL
+            if tmp[2] != oreslabel:
+                return -xsconstants.XSERR_BAD_LABEL
+        if reslabel != "":
+            new_entry = { resource : tuple([policytype, policyref, reslabel])}
+            access_control.update(new_entry)
+        else:
+            if access_control.has_key(resource):
+                del access_control[resource]
+        dictio.dict_write(access_control, "resources", res_label_filename)
+    finally:
+        __resfile_lock.release()
+    return xsconstants.XSERR_SUCCESS
+
+def rm_resource_label(resource, oldlabel_xapi):
+    """Remove a resource label from a physical resource
+    @param resource: The name of a resource, i.e., "phy:/dev/hda"
+
+    @rtype: int
+    @return Success (0) or failure value (< 0)
+    """
+    tmp = oldlabel_xapi.split(":")
+    if len(tmp) != 3:
+        return -xsconstants.XSERR_BAD_LABEL_FORMAT
+    otyp, opolicyref, olabel = tmp
+    # Only ACM is supported
+    if otyp != xsconstants.ACM_POLICY_ID and \
+       otyp != xsconstants.INVALID_POLICY_PREFIX + xsconstants.ACM_POLICY_ID:
+        return -xsconstants.XSERR_WRONG_POLICY_TYPE
+    return set_resource_label(resource, "", "", "", olabel)
+
+def get_resource_label_xapi(resource):
+    """Get the assigned resource label of a physical resource
+      in the format used by then Xen-API, i.e., "ACM:xm-test:blue"
+
+      @rtype: string
+      @return the string representing policy type, policy name and label of
+              the resource
+    """
+    res = get_resource_label(resource)
+    return format_resource_label(res)
+
+def format_resource_label(res):
+    if res:
+        if len(res) == 2:
+            return xsconstants.ACM_POLICY_ID + ":" + res[0] + ":" + res[1]
+        if len(res) == 3:
+            return ":".join(res)
+    return ""
+
+def get_resource_label(resource):
+    """Get the assigned resource label of a given resource
+    @param resource: The name of a resource, i.e., "phy:/dev/hda"
+
+    @rtype: list
+    @return tuple of (policy name, resource label), i.e., (xm-test, blue)
+    """
+    try:
+        resource = unify_resname(resource, mustexist=False)
+    except Exception:
+        return []
+
+    reslabel_map = get_labeled_resources()
+
+    if reslabel_map.has_key(resource):
+        return list(reslabel_map[resource])
+    else:
+        #Try to resolve each label entry
+        for key, value in reslabel_map.items():
+            try:
+                if resource == unify_resname(key):
+                    return list(value)
+            except:
+                pass
+
+    return []
+
+
+def get_labeled_resources_xapi():
+    """ Get a map of all labeled resource with the labels formatted in the
+        xen-api resource label format.
+    """
+    reslabel_map = get_labeled_resources()
+    for key, labeldata in reslabel_map.items():
+        reslabel_map[key] = format_resource_label(labeldata)
+    return reslabel_map
+
+
+def get_labeled_resources():
+    """Get a map of all labeled resources
+    @rtype: list
+    @return list of labeled resources
+    """
+    try:
+        __resfile_lock.acquire()
+        try:
+            access_control = dictio.dict_read("resources", res_label_filename)
+        except:
+            return {}
+    finally:
+        __resfile_lock.release()
+    return access_control
+
+
+def relabel_domains(relabel_list):
+    """
+      Relabel the given domains to have a new ssidref.
+      @param relabel_list: a list containing tuples of domid, ssidref
+                           example: [ [0, 0x00020002] ]
+    """
+    rel_rules = ""
+    for r in relabel_list:
+        log.info("Relabeling domain with domid %d to new ssidref 0x%08x",
+                r[0], r[1])
+        rel_rules += struct.pack("ii", r[0], r[1])
+    try:
+        rc, errors = acm.relabel_domains(rel_rules)
+    except Exception, e:
+        log.info("Error after relabel_domains: %s" % str(e))
+        rc = -xsconstants.XSERR_GENERAL_FAILURE
+        errors = ""
+    if (len(errors) > 0):
+        rc = -xsconstants.XSERR_HV_OP_FAILED
+    return rc, errors
+
+
+def change_acm_policy(bin_pol, del_array, chg_array,
+                      vmlabel_map, reslabel_map, cur_acmpol, new_acmpol):
+    """
+       Change the ACM policy of the system by relabeling
+       domains and resources first and doing some access checks.
+       Then update the policy in the hypervisor. If this is all successful,
+       relabel the domains permanently and commit the relabed resources.
+
+       Need to do / check the following:
+        - relabel all resources where there is a 'from' field in
+          the policy. [ NOT DOING THIS: and mark those as unlabeled where the 
label
+          does not appear in the new policy anymore (deletion) ]
+        - relabel all VMs where there is a 'from' field in the
+          policy and mark those as unlabeled where the label
+          does not appear in the new policy anymore; no running
+          or paused VM may be unlabeled through this
+        - check that under the new labeling conditions the VMs
+          still have access to their resources as before. Unlabeled
+          resources are inaccessible. If this check fails, the
+          update failed.
+        - Attempt changes in the hypervisor; if this step fails,
+          roll back the relabeling of resources and VMs
+        - Make the relabeling of resources and VMs permanent
+    """
+    rc = xsconstants.XSERR_SUCCESS
+
+    domain_label_map = {}
+    new_policyname = new_acmpol.get_name()
+    new_policytype = new_acmpol.get_type_name()
+    cur_policyname = cur_acmpol.get_name()
+    cur_policytype = cur_acmpol.get_type_name()
+    polnew_reslabels = new_acmpol.policy_get_resourcelabel_names()
+    errors=""
+
+    try:
+        __resfile_lock.acquire()
+        mapfile_lock()
+
+        # Get all domains' dominfo.
+        from xen.xend import XendDomain
+        dominfos = XendDomain.instance().list('all')
+
+        log.info("----------------------------------------------")
+        # relabel resources
+
+        access_control = {}
+        try:
+            access_control = dictio.dict_read("resources", res_label_filename)
+        finally:
+            pass
+        for key, labeldata in access_control.items():
+            if len(labeldata) == 2:
+                policy, label = labeldata
+                policytype = xsconstants.ACM_POLICY_ID
+            elif len(labeldata) == 3:
+                policytype, policy, label = labeldata
+            else:
+                return -xsconstants.XSERR_BAD_LABEL_FORMAT, ""
+
+            if policytype != cur_policytype or \
+               policy     != cur_policyname:
+                continue
+
+            # label been renamed or deleted?
+            if reslabel_map.has_key(label) and cur_policyname == policy:
+                label = reslabel_map[label]
+            elif label not in polnew_reslabels:
+                policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
+            # Update entry
+            access_control[key] = \
+                   tuple([ policytype, new_policyname, label ])
+
+        # All resources have new labels in the access_control map
+        # There may still be labels in there that are invalid now.
+
+        # Do this in memory without writing to disk:
+        #  - Relabel all domains independent of whether they are running
+        #    or not
+        #  - later write back to config files
+        polnew_vmlabels = new_acmpol.policy_get_virtualmachinelabel_names()
+
+        for dominfo in dominfos:
+            sec_lab = dominfo.get_security_label()
+            if not sec_lab:
+                continue
+            policytype, policy, vmlabel = sec_lab.split(":")
+            name  = dominfo.getName()
+
+            if policytype != cur_policytype or \
+               policy     != cur_policyname:
+                continue
+
+            new_vmlabel = vmlabel
+            if vmlabel_map.has_key(vmlabel):
+                new_vmlabel = vmlabel_map[vmlabel]
+            if new_vmlabel not in polnew_vmlabels:
+                policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
+            new_seclab = "%s:%s:%s" % \
+                    (policytype, new_policyname, new_vmlabel)
+
+            domain_label_map[dominfo] = [ sec_lab, new_seclab ]
+
+            if dominfo._stateGet() in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
+                compatible = __resources_compatible_with_vmlabel(new_acmpol,
+                                                      dominfo,
+                                                      new_vmlabel,
+                                                      access_control)
+                log.info("Domain %s with new label '%s' can access its "
+                         "resources? : %s" %
+                         (name, new_vmlabel, str(compatible)))
+                log.info("VM labels in new domain: %s" %
+                         new_acmpol.policy_get_virtualmachinelabel_names())
+                if not compatible:
+                    return (-xsconstants.XSERR_RESOURCE_ACCESS, "")
+
+        rc, errors = hv_chg_policy(bin_pol, del_array, chg_array)
+        if rc == 0:
+            # Write the relabeled resources back into the file
+            dictio.dict_write(access_control, "resources", res_label_filename)
+            # Properly update all VMs to their new labels
+            for dominfo, labels in domain_label_map.items():
+                sec_lab, new_seclab = labels
+                if sec_lab != new_seclab:
+                    log.info("Updating domain %s to new label '%s'." % \
+                             (new_seclab, sec_lab))
+                    # This better be working!
+                    dominfo.set_security_label(new_seclab,
+                                               sec_lab,
+                                               new_acmpol)
+    finally:
+        log.info("----------------------------------------------")
+        mapfile_unlock()
+        __resfile_lock.release()
+
+    return rc, errors
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/util/xsconstants.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsconstants.py      Mon Jul 09 14:51:44 2007 +0100
@@ -0,0 +1,104 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2007 International Business Machines Corp.
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
+#============================================================================
+
+XS_INST_NONE = 0
+XS_INST_BOOT = (1 << 0)
+XS_INST_LOAD = (1 << 1)
+
+XS_POLICY_NONE  = 0
+XS_POLICY_ACM = (1 << 0)
+
+# Some internal variables used by the Xen-API
+ACM_LABEL_VM  = (1 << 0)
+ACM_LABEL_RES = (1 << 1)
+
+# Base for XS error codes for collision avoidance with other error codes
+XSERR_BASE = 0x1000
+
+# XS error codes as used by the Xen-API
+XSERR_SUCCESS                  =  0
+XSERR_GENERAL_FAILURE          =  1 + XSERR_BASE
+XSERR_BAD_XML                  =  2 + XSERR_BASE  # XML is wrong (not 
according to schema)
+XSERR_XML_PROCESSING           =  3 + XSERR_BASE
+XSERR_POLICY_INCONSISTENT      =  4 + XSERR_BASE  # i.e., bootstrap name not a 
VM label
+XSERR_FILE_ERROR               =  5 + XSERR_BASE
+XSERR_BAD_RESOURCE_FORMAT      =  6 + XSERR_BASE  # badly formatted resource
+XSERR_BAD_LABEL_FORMAT         =  7 + XSERR_BASE
+XSERR_RESOURCE_NOT_LABELED     =  8 + XSERR_BASE
+XSERR_RESOURCE_ALREADY_LABELED =  9 + XSERR_BASE
+XSERR_WRONG_POLICY_TYPE        = 10 + XSERR_BASE
+XSERR_BOOTPOLICY_INSTALLED     = 11 + XSERR_BASE
+XSERR_NO_DEFAULT_BOOT_TITLE    = 12 + XSERR_BASE
+XSERR_POLICY_LOAD_FAILED       = 13 + XSERR_BASE
+XSERR_POLICY_LOADED            = 14 + XSERR_BASE
+XSERR_POLICY_TYPE_UNSUPPORTED  = 15 + XSERR_BASE
+XSERR_BAD_CONFLICTSET          = 16 + XSERR_BASE
+XSERR_RESOURCE_IN_USE          = 17 + XSERR_BASE
+XSERR_BAD_POLICY_NAME          = 18 + XSERR_BASE
+XSERR_VERSION_PREVENTS_UPDATE  = 19 + XSERR_BASE
+XSERR_BAD_LABEL                = 20 + XSERR_BASE
+XSERR_VM_WRONG_STATE           = 21 + XSERR_BASE
+XSERR_POLICY_NOT_LOADED        = 22 + XSERR_BASE
+XSERR_RESOURCE_ACCESS          = 23 + XSERR_BASE
+XSERR_HV_OP_FAILED             = 24 + XSERR_BASE
+XSERR_BOOTPOLICY_INSTALL_ERROR = 25 + XSERR_BASE
+XSERR_LAST                     = 25 + XSERR_BASE ## KEEP LAST
+
+XSERR_MESSAGES = [
+    '',
+    'General Failure',
+    'XML is malformed',
+    'Error while processing XML',
+    'Policy has inconsistencies',
+    'A file access error occurred',
+    'The resource format is not valid',
+    'The label format is not valid',
+    'The resource is not labeld',
+    'The resource is already labeld',
+    'The policy type is wrong',
+    'The system boot policy is installed',
+    'Could not find the default boot title',
+    'Loading of the policy failed',
+    'The policy is loaded',
+    'The policy type is unsupported',
+    'There is a bad conflict set',
+    'The resource is in use',
+    'The policy has an invalid name',
+    'The version of the policy prevents an update',
+    'The label is bad',
+    'Operation not premittend - the VM is in the wrong state',
+    'The policy is not loaded',
+    'Error accessing resource',
+    'Operation failed in hypervisor',
+    'Boot policy installation error'
+]
+
+def xserr2string(err):
+    if err == XSERR_SUCCESS:
+        return "Success"
+    if err >= XSERR_GENERAL_FAILURE and \
+       err <= XSERR_LAST:
+        return XSERR_MESSAGES[err - XSERR_BASE]
+    return "Unknown XSERR code '%s'." % (hex(err))
+
+# Policy identifiers used in labels
+ACM_POLICY_ID = "ACM"
+
+INVALID_POLICY_PREFIX = "INV_"
+
+INVALID_SSIDREF = 0xFFFFFFFF
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/util/xspolicy.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xspolicy.py Mon Jul 09 14:51:44 2007 +0100
@@ -0,0 +1,66 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006,2007 International Business Machines Corp.
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
+#============================================================================
+
+import threading
+import xsconstants
+
+class XSPolicy:
+    """
+       The base policy class for all policies administered through
+       XSPolicyAdmin.
+    """
+
+    def __init__(self, name=None, ref=None):
+        self.lock = threading.Lock()
+        self.ref = ref
+        self.name = name
+        if ref:
+            from xen.xend.XendXSPolicy import XendXSPolicy
+            self.xendxspolicy = XendXSPolicy(self, {}, ref)
+        else:
+            self.xendxspolicy = None
+
+    def grab_lock(self):
+        self.lock.acquire()
+
+    def unlock(self):
+        self.lock.release()
+
+    def get_ref(self):
+        return self.ref
+
+    def destroy(self):
+        if self.xendxspolicy:
+            self.xendxspolicy.destroy()
+
+    # All methods below should be overwritten by the inheriting class
+
+    def isloaded(self):
+        return False
+
+    def loadintohv(self):
+        return xsconstants.XSERR_POLICY_LOAD_FAILED
+
+    def get_type(self):
+        return xsconstants.XS_POLICY_NONE
+
+    def get_type_name(self):
+        return ""
+
+    def update(self, repr_new):
+        return -xsconstants.XSERR_GENERAL_FAILURE, ""
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendAPI.py
--- a/tools/python/xen/xend/XendAPI.py  Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendAPI.py  Mon Jul 09 14:51:44 2007 +0100
@@ -40,11 +40,13 @@ from XendVMMetrics import XendVMMetrics
 from XendVMMetrics import XendVMMetrics
 from XendPIF import XendPIF
 from XendPBD import XendPBD
+from XendXSPolicy import XendXSPolicy, XendACMPolicy
 
 from XendAPIConstants import *
 from xen.util.xmlrpclib2 import stringify
 
 from xen.util.blkif import blkdev_name_to_number
+from xen.util import xsconstants
 
 
 AUTH_NONE = 'none'
@@ -467,6 +469,8 @@ classes = {
     'console'      : valid_console,
     'SR'           : valid_sr,
     'task'         : valid_task,
+    'XSPolicy'     : valid_object("XSPolicy"),
+    'ACMPolicy'    : valid_object("ACMPolicy"),
     'debug'        : valid_debug,
     'network'      : valid_object("network"),
     'PIF'          : valid_object("PIF"),
@@ -481,6 +485,8 @@ autoplug_classes = {
     'VM_metrics'  : XendVMMetrics,
     'PBD'         : XendPBD,
     'PIF_metrics' : XendPIFMetrics,
+    'XSPolicy'    : XendXSPolicy,
+    'ACMPolicy'   : XendACMPolicy,
 }
 
 class XendAPI(object):
@@ -1170,7 +1176,8 @@ class XendAPI(object):
                   'HVM_boot_params',
                   'platform',
                   'PCI_bus',
-                  'other_config']
+                  'other_config',
+                  'security_label']
 
     VM_methods = [('clone', 'VM'),
                   ('start', None),
@@ -1230,7 +1237,8 @@ class XendAPI(object):
         'HVM_boot_params',
         'platform',
         'PCI_bus',
-        'other_config']
+        'other_config',
+        'security_label']
         
     def VM_get(self, name, session, vm_ref):
         return xen_api_success(
@@ -1601,7 +1609,22 @@ class XendAPI(object):
         if dom:
             return xen_api_success([dom.get_uuid()])
         return xen_api_success([])
-    
+
+    def VM_get_security_label(self, session, vm_ref):
+        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+        label = dom.get_security_label()
+        return xen_api_success(label)
+
+    def VM_set_security_label(self, session, vm_ref, sec_label, old_label):
+        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+        (rc, errors, oldlabel, new_ssidref) = \
+                                 dom.set_security_label(sec_label, old_label)
+        if rc != xsconstants.XSERR_SUCCESS:
+            return xen_api_error(['SECURITY_ERROR', rc])
+        if rc == 0:
+            rc = new_ssidref
+        return xen_api_success(rc)
+
     def VM_create(self, session, vm_struct):
         xendom = XendDomain.instance()
         domuuid = XendTask.log_progress(0, 100,
@@ -1655,6 +1678,7 @@ class XendAPI(object):
             'domid': domid is None and -1 or domid,
             'is_control_domain': xeninfo.info['is_control_domain'],
             'metrics': xeninfo.get_metrics(),
+            'security_label': xeninfo.get_security_label(),
             'crash_dumps': []
         }
         return xen_api_success(record)
@@ -1952,7 +1976,8 @@ class XendAPI(object):
                    'runtime_properties']
     VIF_attr_rw = ['device',
                    'MAC',
-                   'MTU']
+                   'MTU',
+                   'security_label']
 
     VIF_attr_inst = VIF_attr_rw
 
@@ -2054,7 +2079,10 @@ class XendAPI(object):
         except Exception, exn:
             log.exception(exn)
             return xen_api_success({})
-    
+
+    def VIF_get_security_label(self, session, vif_ref):
+        return self._VIF_get(vif_ref, 'security_label')
+
     # Xen API: Class VIF_metrics
     # ----------------------------------------------------------------
 
@@ -2098,7 +2126,8 @@ class XendAPI(object):
                    'virtual_size',
                    'sharable',
                    'read_only',
-                   'other_config']
+                   'other_config',
+                   'security_label']
     VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
 
     VDI_methods = [('destroy', None)]
@@ -2206,13 +2235,24 @@ class XendAPI(object):
         xennode = XendNode.instance()
         return xen_api_success(xennode.get_vdi_by_name_label(name))
 
+    def VDI_set_security_label(self, session, vdi_ref, sec_lab, old_lab):
+        vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
+        rc = vdi.set_security_label(sec_lab, old_lab)
+        if rc < 0:
+            return xen_api_error(['SECURITY_ERROR', rc])
+        return xen_api_success(rc)
+
+    def VDI_get_security_label(self, session, vdi_ref):
+        vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
+        return xen_api_success(vdi.get_security_label())
 
     # Xen API: Class VTPM
     # ----------------------------------------------------------------
 
     VTPM_attr_rw = [ ]
     VTPM_attr_ro = ['VM',
-                    'backend']
+                    'backend',
+                    'runtime_properties' ]
 
     VTPM_attr_inst = VTPM_attr_rw
 
@@ -2289,6 +2329,18 @@ class XendAPI(object):
         vtpms = [d.get_vtpms() for d in XendDomain.instance().list('all')]
         vtpms = reduce(lambda x, y: x + y, vtpms)
         return xen_api_success(vtpms)
+
+    def VTPM_get_runtime_properties(self, _, vtpm_ref):
+        xendom = XendDomain.instance()
+        dominfo = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+        device = dominfo.get_dev_config_by_uuid('vtpm', vtpm_ref)
+
+        try:
+            device_sxps = dominfo.getDeviceSxprs('vtpm')
+            device_dict = dict(device_sxps[0][1])
+            return xen_api_success(device_dict)
+        except:
+            return xen_api_success({})
 
     # Xen API: Class console
     # ----------------------------------------------------------------
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendConfig.py       Mon Jul 09 14:51:44 2007 +0100
@@ -30,6 +30,8 @@ from xen.xend.XendConstants import DOM_S
 from xen.xend.XendConstants import DOM_STATE_HALTED
 from xen.xend.server.netif import randomMAC
 from xen.util.blkif import blkdev_name_to_number
+from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+from xen.util import xsconstants
 
 log = logging.getLogger("xend.XendConfig")
 log.setLevel(logging.WARN)
@@ -160,6 +162,7 @@ XENAPI_CFG_TYPES = {
     'platform': dict,
     'tools_version': dict,
     'other_config': dict,
+    'security_label': str,
 }
 
 # List of legacy configuration keys that have no equivalent in the
@@ -168,7 +171,6 @@ LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
     # roundtripped (dynamic, unmodified)
     'shadow_memory',
-    'security',
     'vcpu_avail',
     'cpu_weight',
     'cpu_cap',
@@ -319,7 +321,6 @@ class XendConfig(dict):
             'memory_static_max': 0,
             'memory_dynamic_max': 0,
             'devices': {},
-            'security': None,
             'on_xend_start': 'ignore',
             'on_xend_stop': 'ignore',
             'cpus': [],
@@ -425,9 +426,10 @@ class XendConfig(dict):
             self._memory_sanity_check()
 
         self['cpu_time'] = dominfo['cpu_time']/1e9
-        # TODO: i don't know what the security stuff expects here
         if dominfo.get('ssidref'):
-            self['security'] = [['ssidref', dominfo['ssidref']]]
+            ssidref = int(dominfo.get('ssidref'))
+            self['security_label'] = 
XSPolicyAdminInstance().ssidref_to_vmlabel(ssidref)
+
         self['shutdown_reason'] = dominfo['shutdown_reason']
 
         # parse state into Xen API states
@@ -634,8 +636,26 @@ class XendConfig(dict):
                 except ValueError, e:
                     raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
 
-        if 'security' in cfg and isinstance(cfg['security'], str):
-            cfg['security'] = sxp.from_string(cfg['security'])
+        if 'security' in cfg and not cfg.get('security_label'):
+            secinfo = cfg['security']
+            if isinstance(secinfo, list):
+                # The xm command sends a list formatted like this:
+                # [['access_control', ['policy', 'xm-test'],['label', 'red']],
+                #                     ['ssidref', 196611]]
+                policy = ""
+                label = ""
+                policytype = xsconstants.ACM_POLICY_ID
+                for idx in range(0, len(secinfo)):
+                    if secinfo[idx][0] == "access_control":
+                        for aidx in range(1, len(secinfo[idx])):
+                            if secinfo[idx][aidx][0] == "policy":
+                                policy = secinfo[idx][aidx][1]
+                            if secinfo[idx][aidx][0] == "label":
+                                label  = secinfo[idx][aidx][1]
+                if label != "" and policy != "":
+                    cfg['security_label'] = "%s:%s:%s" % \
+                            (policytype, policy, label)
+                    del cfg['security']
 
         old_state = sxp.child_value(sxp_cfg, 'state')
         if old_state:
@@ -778,7 +798,6 @@ class XendConfig(dict):
                     self[sxp_arg] = val
 
         _set_cfg_if_exists('shadow_memory')
-        _set_cfg_if_exists('security')
         _set_cfg_if_exists('features')
         _set_cfg_if_exists('on_xend_stop')
         _set_cfg_if_exists('on_xend_start')
@@ -890,6 +909,9 @@ class XendConfig(dict):
                 continue
             if self.has_key(legacy) and self[legacy] not in (None, []):
                 sxpr.append([legacy, self[legacy]])
+
+        if self.has_key('security_label'):
+            sxpr.append(['security_label', self['security_label']])
 
         sxpr.append(['image', self.image_sxpr()])
         sxpr.append(['status', domain._stateGet()])
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py       Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendDomain.py       Mon Jul 09 14:51:44 2007 +0100
@@ -49,7 +49,7 @@ from xen.xend.XendAPIConstants import *
 
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.xenstore.xswatch import xswatch
-from xen.util import mkdir, security
+from xen.util import mkdir
 from xen.xend import uuid
 
 xc = xen.lowlevel.xc.xc()
@@ -486,7 +486,6 @@ class XendDomain:
         """
         self.domains_lock.acquire()
         try:
-            security.refresh_ssidref(config)
             dominfo = XendDomainInfo.restore(config)
             return dominfo
         finally:
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py   Mon Jul 09 14:51:44 2007 +0100
@@ -830,6 +830,9 @@ class XendDomainInfo:
             else:
                 f('image/%s' % n, v)
 
+        if self.info.has_key('security_label'):
+            f('security_label', self.info['security_label'])
+
         to_store.update(self._vcpuDomDetails())
 
         log.debug("Storing domain details: %s", scrub_password(to_store))
@@ -999,9 +1002,6 @@ class XendDomainInfo:
             xen.xend.XendDomain.instance().managed_config_save(self)
         log.info("Set VCPU count on domain %s to %d", self.info['name_label'],
                  vcpus)
-
-    def getLabel(self):
-        return security.get_security_info(self.info, 'label')
 
     def getMemoryTarget(self):
         """Get this domain's target memory size, in KB."""
@@ -1446,11 +1446,20 @@ class XendDomainInfo:
         # allocation of 1MB. We free up 2MB here to be on the safe side.
         balloon.free(2*1024) # 2MB should be plenty
 
-        self.domid = xc.domain_create(
-            domid = 0,
-            ssidref = security.get_security_info(self.info, 'ssidref'),
-            handle = uuid.fromString(self.info['uuid']),
-            hvm = int(hvm))
+        ssidref = security.calc_dom_ssidref_from_info(self.info)
+        if ssidref == 0 and security.on():
+            raise VmError('VM is not properly labeled.')
+
+        try:
+            self.domid = xc.domain_create(
+                domid = 0,
+                ssidref = ssidref,
+                handle = uuid.fromString(self.info['uuid']),
+                hvm = int(hvm))
+        except Exception, e:
+            # may get here if due to ACM the operation is not permitted
+            if security.on():
+                raise VmError('Domain in conflict set with running domain?')
 
         if self.domid < 0:
             raise VmError('Creating domain failed: name=%s' %
@@ -1965,24 +1974,6 @@ class XendDomainInfo:
         image_sxpr = self.info.image_sxpr()
         if image_sxpr:
             to_store['image'] = sxp.to_string(image_sxpr)
-
-        if self._infoIsSet('security'):
-            secinfo = self.info['security']
-            to_store['security'] = sxp.to_string(secinfo)
-            for idx in range(0, len(secinfo)):
-                if secinfo[idx][0] == 'access_control':
-                    to_store['security/access_control'] = sxp.to_string(
-                        [secinfo[idx][1], secinfo[idx][2]])
-                    for aidx in range(1, len(secinfo[idx])):
-                        if secinfo[idx][aidx][0] == 'label':
-                            to_store['security/access_control/label'] = \
-                                secinfo[idx][aidx][1]
-                        if secinfo[idx][aidx][0] == 'policy':
-                            to_store['security/access_control/policy'] = \
-                                secinfo[idx][aidx][1]
-                if secinfo[idx][0] == 'ssidref':
-                    to_store['security/ssidref'] = str(secinfo[idx][1])
-
 
         if not self._readVm('xend/restart_count'):
             to_store['xend/restart_count'] = str(0)
@@ -2101,15 +2092,6 @@ class XendDomainInfo:
             info["maxmem_kb"] = XendNode.instance() \
                                 .physinfo_dict()['total_memory'] * 1024
 
-        #manually update ssidref / security fields
-        if security.on() and info.has_key('ssidref'):
-            if (info['ssidref'] != 0) and self.info.has_key('security'):
-                security_field = self.info['security']
-                if not security_field:
-                    #create new security element
-                    self.info.update({'security':
-                                      [['ssidref', str(info['ssidref'])]]})
-                    
         #ssidref field not used any longer
         if 'ssidref' in info:
             info.pop('ssidref')
@@ -2193,7 +2175,133 @@ class XendDomainInfo:
         return self.info.get('tools_version', {})
     def get_metrics(self):
         return self.metrics.get_uuid();
-    
+
+
+    def get_security_label(self):
+        domid = self.getDomid()
+
+        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+        xspol = XSPolicyAdminInstance().get_loaded_policy()
+
+        if domid == 0:
+            if xspol:
+                label = xspol.policy_get_domain_label_formatted(domid)
+            else:
+                label = ""
+        else:
+            label = self.info.get('security_label', '')
+        return label
+
+    def set_security_label(self, seclab, old_seclab, xspol=None):
+        """
+           Set the security label of a domain from its old to
+           a new value.
+           @param seclab  New security label formatted in the form
+                          <policy type>:<policy name>:<vm label>
+           @param old_seclab  The current security label that the
+                          VM must have.
+           @param xspol   An optional policy under which this
+                          update should be done. If not given,
+                          then the current active policy is used.
+           @return Returns return code, a string with errors from
+                   the hypervisor's operation, old label of the
+                   domain
+        """
+        rc = 0
+        errors = ""
+        old_label = ""
+        new_ssidref = 0
+        domid = self.getDomid()
+        res_labels = None
+
+        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+        from xen.util import xsconstants
+
+        state = self._stateGet()
+        # Relabel only HALTED or RUNNING or PAUSED domains
+        if domid != 0 and \
+           state not in \
+              [ DOM_STATE_HALTED, DOM_STATE_RUNNING, DOM_STATE_PAUSED, \
+                DOM_STATE_SUSPENDED ]:
+            log.warn("Relabeling domain not possible in state '%s'" %
+                     DOM_STATES[state])
+            return (-xsconstants.XSERR_VM_WRONG_STATE, "", "", 0)
+
+        # Remove security label. Works only for halted domains
+        if not seclab or seclab == "":
+            if state not in [ DOM_STATE_HALTED ]:
+                return (-xsconstants.XSERR_VM_WRONG_STATE, "", "", 0)
+
+            if self.info.has_key('security_label'):
+                old_label = self.info['security_label']
+                # Check label against expected one.
+                if old_label != old_seclab:
+                    return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+                del self.info['security_label']
+                xen.xend.XendDomain.instance().managed_config_save(self)
+                return (xsconstants.XSERR_SUCCESS, "", "", 0)
+
+        tmp = seclab.split(":")
+        if len(tmp) != 3:
+            return (-xsconstants.XSERR_BAD_LABEL_FORMAT, "", "", 0)
+        typ, policy, label = tmp
+
+        poladmin = XSPolicyAdminInstance()
+        if not xspol:
+            xspol = poladmin.get_policy_by_name(policy)
+
+        if state in [ DOM_STATE_RUNNING, DOM_STATE_PAUSED ]:
+            #if domain is running or paused try to relabel in hypervisor
+            if not xspol:
+                return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
+
+            if typ != xspol.get_type_name() or \
+               policy != xspol.get_name():
+                return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+
+            if typ == xsconstants.ACM_POLICY_ID:
+                new_ssidref = xspol.vmlabel_to_ssidref(label)
+                if new_ssidref == xsconstants.INVALID_SSIDREF:
+                    return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+
+                # Check that all used resources are accessible under the
+                # new label
+                if not security.resources_compatible_with_vmlabel(xspol,
+                          self, label):
+                    return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+
+                #Check label against expected one.
+                old_label = self.get_security_label()
+                if old_label != old_seclab:
+                    return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+
+                # relabel domain in the hypervisor
+                rc, errors = security.relabel_domains([[domid, new_ssidref]])
+                log.info("rc from relabeling in HV: %d" % rc)
+            else:
+                return (-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED, "", "", 0)
+
+        if rc == 0:
+            # HALTED, RUNNING or PAUSED
+            if domid == 0:
+                if xspol:
+                    ssidref = poladmin.set_domain0_bootlabel(xspol, label)
+                else:
+                    return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
+            else:
+                if self.info.has_key('security_label'):
+                    old_label = self.info['security_label']
+                    # Check label against expected one, unless wildcard
+                    if old_label != old_seclab:
+                        return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+
+                self.info['security_label'] = seclab
+                try:
+                    xen.xend.XendDomain.instance().managed_config_save(self)
+                except:
+                    pass
+        return (rc, errors, old_label, new_ssidref)
+
     def get_on_shutdown(self):
         after_shutdown = self.info.get('actions_after_shutdown')
         if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT:
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendError.py
--- a/tools/python/xen/xend/XendError.py        Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendError.py        Mon Jul 09 14:51:44 2007 +0100
@@ -174,6 +174,23 @@ class NetworkError(XendAPIError):
 
     def __str__(self):
         return 'NETWORK_ERROR: %s %s' % (self.error, self.network)
+
+from xen.util.xsconstants import xserr2string
+
+class SecurityError(XendAPIError):
+    def __init__(self, error, message=None):
+        XendAPIError.__init__(self)
+        self.error = error
+        if not message:
+            self.message = xserr2string(-error)
+        else:
+            self.message = message
+
+    def get_api_error(self):
+        return ['SECURITY_ERROR', self.error, self.message]
+
+    def __str__(self):
+        return 'SECURITY_ERROR: %s:%s' % (self.error, self.message)
     
 XEND_ERROR_AUTHENTICATION_FAILED = ('ELUSER', 'Authentication Failed')
 XEND_ERROR_SESSION_INVALID       = ('EPERMDENIED', 'Session Invalid')
@@ -188,4 +205,5 @@ XEND_ERROR_VTPM_INVALID          = ('EVT
 XEND_ERROR_VTPM_INVALID          = ('EVTPMINVALID', 'VTPM Invalid')
 XEND_ERROR_VDI_INVALID           = ('EVDIINVALID', 'VDI Invalid')
 XEND_ERROR_SR_INVALID           = ('ESRINVALID', 'SR Invalid')
+XEND_ERROR_XSPOLICY_INVALID      = ('EXSPOLICYINVALID', 'XS Invalid')
 XEND_ERROR_TODO                  = ('ETODO', 'Lazy Programmer Error')
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendVDI.py
--- a/tools/python/xen/xend/XendVDI.py  Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/XendVDI.py  Mon Jul 09 14:51:44 2007 +0100
@@ -23,6 +23,7 @@ import os
 
 from xen.util.xmlrpclib2 import stringify
 from xmlrpclib import dumps, loads
+from xen.util import security, xsconstants
 
 KB = 1024
 MB = 1024 * 1024
@@ -160,6 +161,17 @@ class XendVDI(AutoSaveObject):
 
     def get_location(self):
         raise NotImplementedError()
+
+    def set_security_label(self, sec_lab, old_lab):
+        image = self.get_location()
+        rc = security.set_resource_label_xapi(image, sec_lab, old_lab)
+        if rc != xsconstants.XSERR_SUCCESS:
+            raise SecurityError(rc)
+        return rc
+
+    def get_security_label(self):
+        image = self.get_location()
+        return security.get_resource_label_xapi(image)
                 
 
 class XendQCoWVDI(XendVDI):
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendXSPolicy.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendXSPolicy.py     Mon Jul 09 14:51:44 2007 +0100
@@ -0,0 +1,222 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (c) 2007 IBM Corporation
+# Copyright (c) 2006 Xensource
+#============================================================================
+
+import logging
+from xen.xend.XendBase import XendBase
+from xen.xend.XendError import *
+from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+from xen.util import xsconstants, security
+import base64
+
+log = logging.getLogger("xend.XendXSPolicy")
+log.setLevel(logging.TRACE)
+
+
+class XendXSPolicy(XendBase):
+    """ Administration class for an XSPolicy. """
+
+    def getClass(self):
+        return "XSPolicy"
+
+    def getMethods(self):
+        methods = ['activate_xspolicy']
+        return XendBase.getMethods() + methods
+
+    def getFuncs(self):
+        funcs = [ 'get_xstype',
+                  'set_xspolicy',
+                  'get_xspolicy',
+                  'rm_xsbootpolicy',
+                  'get_resource_label',
+                  'set_resource_label',
+                  'get_labeled_resources' ]
+        return XendBase.getFuncs() + funcs
+
+    getClass    = classmethod(getClass)
+    getMethods  = classmethod(getMethods)
+    getFuncs    = classmethod(getFuncs)
+
+    def __init__(self, xspol, record, uuid):
+        """ xspol = actual XSPolicy  object """
+        self.xspol = xspol
+        XendBase.__init__(self, uuid, record)
+
+    def get_record(self):
+        xspol_record = {
+          'uuid'   : self.get_uuid(),
+          'flags'  : XSPolicyAdminInstance().get_policy_flags(self.xspol),
+          'repr'   : self.xspol.toxml(),
+          'type'   : self.xspol.get_type(),
+        }
+        return xspol_record
+
+    def get_xstype(self):
+        return XSPolicyAdminInstance().isXSEnabled()
+
+    def set_xspolicy(self, xstype, xml, flags, overwrite):
+        ref = ""
+        xstype = int(xstype)
+        flags  = int(flags)
+
+        polstate = { 'xs_ref': "", 'repr'   : "", 'type'   : 0,
+                     'flags' : 0 , 'version': 0 , 'errors' : "", 'xserr' : 0 }
+        if xstype == xsconstants.XS_POLICY_ACM:
+            poladmin = XSPolicyAdminInstance()
+            try:
+                (xspol, rc, errors) = poladmin.add_acmpolicy_to_system(
+                                                                   xml, flags,
+                                                                   overwrite)
+                if rc != 0:
+                    polstate.update( { 'xserr' : rc,
+                                       'errors': base64.b64encode(errors) } )
+                else:
+                    ref = xspol.get_ref()
+                    polstate = {
+                      'xs_ref' : ref,
+                      'flags'  : poladmin.get_policy_flags(xspol),
+                      'type'   : xstype,
+                      'repr'   : "",
+                      'version': xspol.get_version(),
+                      'errors' : base64.b64encode(errors),
+                      'xserr'  : rc,
+                    }
+            except Exception, e:
+                raise
+        else:
+            raise SecurityError(-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED)
+        return polstate
+
+    def activate_xspolicy(self, flags):
+        flags = int(flags)
+        rc = -xsconstants.XSERR_GENERAL_FAILURE
+        poladmin = XSPolicyAdminInstance()
+        try:
+            rc = poladmin.activate_xspolicy(self.xspol, flags)
+        except Exception, e:
+            log.info("Activate_policy: %s" % str(e))
+        if rc != flags:
+            raise SecurityError(rc)
+        return flags
+
+    def get_xspolicy(self):
+        polstate = { 'xs_ref' : "",
+                     'repr'   : "",
+                     'type'   : 0,
+                     'flags'  : 0,
+                     'version': "",
+                     'errors' : "",
+                     'xserr'  : 0 }
+        poladmin = XSPolicyAdminInstance()
+        refs = poladmin.get_policies_refs()
+        # Will return one or no policy
+        if refs and len(refs) > 0:
+            ref = refs[0]
+            xspol = XSPolicyAdminInstance().policy_from_ref(ref)
+            try:
+                xspol.grab_lock()
+
+                polstate = {
+                  'xs_ref' : ref,
+                  'repr'   : xspol.toxml(),
+                  'type'   : xspol.get_type(),
+                  'flags'  : poladmin.get_policy_flags(xspol),
+                  'version': xspol.get_version(),
+                  'errors' : "",
+                  'xserr'  : 0,
+                }
+            finally:
+                if xspol:
+                    xspol.unlock()
+        return polstate
+
+    def rm_xsbootpolicy(self):
+        rc = XSPolicyAdminInstance().rm_bootpolicy()
+        if rc != xsconstants.XSERR_SUCCESS:
+            raise SecurityError(rc)
+
+    def get_labeled_resources(self):
+        return security.get_labeled_resources_xapi()
+
+    def set_resource_label(self, resource, sec_lab, old_lab):
+        rc = security.set_resource_label_xapi(resource, sec_lab, old_lab)
+        if rc != xsconstants.XSERR_SUCCESS:
+            raise SecurityError(rc)
+
+    def get_resource_label(self, resource):
+        res = security.get_resource_label_xapi(resource)
+        return res
+
+    get_xstype      = classmethod(get_xstype)
+    get_xspolicy    = classmethod(get_xspolicy)
+    set_xspolicy    = classmethod(set_xspolicy)
+    rm_xsbootpolicy = classmethod(rm_xsbootpolicy)
+    set_resource_label = classmethod(set_resource_label)
+    get_resource_label = classmethod(get_resource_label)
+    get_labeled_resources = classmethod(get_labeled_resources)
+
+
+class XendACMPolicy(XendXSPolicy):
+    """ Administration class of an ACMPolicy """
+
+    def getClass(self):
+        return "ACMPolicy"
+
+    def getAttrRO(self):
+        attrRO = [ 'xml',
+                   'map',
+                   'binary',
+                   'header' ]
+        return XendXSPolicy.getAttrRO() + attrRO
+
+    getClass    = classmethod(getClass)
+    getAttrRO   = classmethod(getAttrRO)
+
+    def __init__(self, acmpol, record, uuid):
+        """ acmpol = actual ACMPolicy object """
+        self.acmpol = acmpol
+        XendXSPolicy.__init__(self, acmpol, record, uuid)
+
+    def get_record(self):
+        polstate = {
+          'uuid'   : self.get_uuid(),
+          'flags'  : XSPolicyAdminInstance().get_policy_flags(self.acmpol),
+          'repr'   : self.acmpol.toxml(),
+          'type'   : self.acmpol.get_type(),
+        }
+        return polstate
+
+    def get_header(self):
+        header = {
+          'policyname'   : "", 'policyurl'    : "", 'reference'    : "",
+          'date'         : "", 'namespaceurl' : "", 'version'      : "",
+        }
+        try:
+            header = self.acmpol.get_header_fields_map()
+        except:
+            pass
+        return header
+
+    def get_xml(self):
+        return self.acmpol.toxml()
+
+    def get_map(self):
+        return self.acmpol.get_map()
+
+    def get_binary(self):
+        polbin = self.acmpol.get_bin()
+        return base64.b64encode(polbin)
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/XendXSPolicyAdmin.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendXSPolicyAdmin.py        Mon Jul 09 14:51:44 
2007 +0100
@@ -0,0 +1,313 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006,2007 International Business Machines Corp.
+# Author: Stefan Berger <stefanb@xxxxxxxxxx>
+#============================================================================
+import os
+import shutil
+
+from xml.dom import minidom, Node
+
+from xen.xend.XendLogging import log
+from xen.xend import uuid
+from xen.util import security, xsconstants, dictio, bootloader
+from xen.util.xspolicy import XSPolicy
+from xen.util.acmpolicy import ACMPolicy
+from xen.xend.XendError import SecurityError
+
+XS_MANAGED_POLICIES_FILE = "/etc/xen/acm-security/policies/managed_policies"
+
+class XSPolicyAdmin:
+    """ The class that handles the managed policies in the system.
+        Handles adding and removing managed policies. All managed
+        policies are handled using a reference (UUID) which is
+        assigned to the policy by this class.
+    """
+
+    def __init__(self, maxpolicies):
+        """ Create a management class for managing the system's
+            policies.
+
+            @param maxpolicies: The max. number of policies allowed
+                                on the system (currently '1')
+        """
+        self.maxpolicies = maxpolicies
+        try:
+            self.policies = dictio.dict_read("managed_policies",
+                                             XS_MANAGED_POLICIES_FILE)
+        except Exception, e:
+            self.policies = {}
+
+        self.xsobjs = {}
+        for ref, data in self.policies.items():
+            name = data[0]
+            typ = data[1]
+            try:
+                if typ == xsconstants.ACM_POLICY_ID:
+                    self.xsobjs[ref] = ACMPolicy(name=name, ref=ref)
+                else:
+                    del self.policies[ref]
+            except Exception, e:
+                log.error("XSPolicyAdmin: Could not find policy '%s': %s" %
+                         (name, str(e)))
+                del self.policies[ref]
+        log.debug("XSPolicyAdmin: Known policies: %s" % self.policies)
+
+    def isXSEnabled(self):
+        """ Check whether 'security' is enabled on this system.
+            This currently only checks for ACM-enablement.
+        """
+        rc = 0
+        if security.on():
+            rc |= xsconstants.XS_POLICY_ACM
+        return rc
+
+    def add_acmpolicy_to_system(self, xmltext, flags, overwrite):
+        """ Add an ACM policy's xml representation to the system. The
+            policy will automatically be compiled
+         flags:
+          XS_INST_BOOT : make policy the one to boot the system with
+                         by default; if there's a policy already installed,
+                         refuse to install this policy unless its one with
+                         the same name
+          XS_INST_LOAD : load the policy immediately; if this does not work
+                         refuse to install this policy
+         overwrite:
+          If any policy is installed and this is False, refuse to install
+          this policy
+          If flags is True, then any existing policy will be removed from
+          the system and the new one will be installed
+        """
+        errors = ""
+        loadedpol = self.get_loaded_policy()
+        if loadedpol:
+            # This is meant as an update to a currently loaded policy
+            if flags & xsconstants.XS_INST_LOAD == 0:
+                raise SecurityError(-xsconstants.XSERR_POLICY_LOADED)
+            rc, errors = loadedpol.update(xmltext)
+            if rc == 0:
+                self.rm_bootpolicy()
+                irc = self.activate_xspolicy(loadedpol, flags)
+            return (loadedpol, rc, errors)
+
+        try:
+            dom = minidom.parseString(xmltext.encode("utf-8"))
+        except:
+            raise SecurityError(-xsconstants.XSERR_BAD_XML)
+
+        ref = uuid.createString()
+
+        acmpol = ACMPolicy(dom=dom, ref=ref)
+
+        #First some basic tests that do not modify anything:
+
+        if flags & xsconstants.XS_INST_BOOT and not overwrite:
+            filename = acmpol.get_filename(".bin","",dotted=True)
+            if bootloader.get_default_policy != None and \
+               not bootloader.loads_default_policy(filename):
+                raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
+
+        if not overwrite and len(self.policies) >= self.maxpolicies:
+            raise SecurityError(-xsconstants.XSERR_BOOTPOLICY_INSTALLED)
+
+        if overwrite:
+            #This should only give one key since only one policy is
+            #allowed.
+            keys = self.policies.keys()
+            for k in keys:
+                self.rm_bootpolicy()
+                rc = self.rm_policy_from_system(k, force=overwrite)
+                if rc != xsconstants.XSERR_SUCCESS:
+                    raise SecurityError(rc)
+
+        rc = acmpol.compile()
+        if rc != 0:
+            raise SecurityError(rc)
+
+        if flags & xsconstants.XS_INST_LOAD:
+            rc = acmpol.loadintohv()
+            if rc != 0:
+                raise SecurityError(rc)
+
+        if flags & xsconstants.XS_INST_BOOT:
+            rc = self.make_boot_policy(acmpol)
+            if rc != 0:
+                # If it cannot be installed due to unsupported
+                # bootloader, let it be ok.
+                pass
+
+        if dom:
+            new_entry = { ref : tuple([acmpol.get_name(),
+                                       xsconstants.ACM_POLICY_ID]) }
+            self.policies.update(new_entry)
+            self.xsobjs[ref]  = acmpol
+            dictio.dict_write(self.policies,
+                              "managed_policies",
+                              XS_MANAGED_POLICIES_FILE)
+        return (acmpol, xsconstants.XSERR_SUCCESS, errors)
+
+    def make_boot_policy(self, acmpol):
+        spolfile = acmpol.get_filename(".bin")
+        dpolfile = "/boot/" + acmpol.get_filename(".bin","",dotted=True)
+        if not os.path.isfile(spolfile):
+            log.error("binary policy file does not exist.")
+            return -xsconstants.XSERR_FILE_ERROR
+        try:
+            shutil.copyfile(spolfile, dpolfile)
+        except:
+            return -xsconstants.XSERR_FILE_ERROR
+
+        try:
+            filename = acmpol.get_filename(".bin","",dotted=True)
+            if bootloader.set_default_boot_policy(filename) != True:
+                return xsconstants.XSERR_BOOTPOLICY_INSTALL_ERROR
+        except:
+            return xsconstants.XSERR_FILE_ERROR
+        return xsconstants.XSERR_SUCCESS
+
+    def activate_xspolicy(self, xspol, flags):
+        rc = xsconstants.XSERR_SUCCESS
+        if flags & xsconstants.XS_INST_LOAD:
+            rc = xspol.loadintohv()
+        if rc == xsconstants.XSERR_SUCCESS and \
+           flags & xsconstants.XS_INST_BOOT:
+            rc = self.make_boot_policy(xspol)
+        if rc == xsconstants.XSERR_SUCCESS:
+            rc = flags
+        return rc
+
+    def rm_policy_from_system(self, ref, force=False):
+        if self.policies.has_key(ref):
+            acmpol = self.xsobjs[ref]
+            rc = acmpol.destroy()
+            if rc == xsconstants.XSERR_SUCCESS or force:
+                del self.policies[ref]
+                del self.xsobjs[ref]
+                dictio.dict_write(self.policies,
+                                  "managed_policies",
+                                  XS_MANAGED_POLICIES_FILE)
+                rc = xsconstants.XSERR_SUCCESS
+            return rc
+
+    def rm_bootpolicy(self):
+        """ Remove any (ACM) boot policy from the grub configuration file
+        """
+        rc = 0
+        title = bootloader.get_default_title()
+        if title != None:
+            polnames = []
+            for (k, v) in self.xsobjs.items():
+                polnames.append(v.get_filename(".bin","",dotted=True))
+            bootloader.rm_policy_from_boottitle(title, polnames)
+        else:
+            rc = -xsconstants.XSERR_NO_DEFAULT_BOOT_TITLE
+        return rc
+
+    def get_policy_flags(self, acmpol):
+        """ Get the currently active flags of a policy, i.e., whether the
+            system is using this policy as its boot policy for the default
+            boot title.
+        """
+        flags = 0
+
+        filename = acmpol.get_filename(".bin","", dotted=True)
+        if bootloader.loads_default_policy(filename):
+            flags |= xsconstants.XS_INST_BOOT
+
+        if acmpol.isloaded():
+            flags |= xsconstants.XS_INST_LOAD
+        return flags
+
+    def get_policies(self):
+        """ Get all managed policies. """
+        return self.xsobjs.values()
+
+    def get_policies_refs(self):
+        """ Get all managed policies' references. """
+        return self.xsobjs.keys()
+
+    def has_ref(self, ref):
+        """ Check whether there is a policy with the given reference """
+        return self.xsobjs.has_key(ref)
+
+    def policy_from_ref(self, ref):
+        """ Get the policy's object given its reference """
+        if ref in self.xsobjs.keys():
+            return self.xsobjs[ref]
+        return None
+
+    def ref_from_polname(self, polname):
+        """ Get the reference of the policy given its name """
+        ref = None
+        for (k, v) in self.xsobjs.items():
+            if v.get_name() == polname:
+                ref = k
+                break
+        return ref
+
+    def lock_policy(self, ref):
+        """ get exclusive access to a policy """
+        self.xsobjs[ref].grab_lock()
+
+    def unlock_policy(self, ref):
+        """ release exclusive access to a policy """
+        self.xsobjs[ref].unlock()
+
+    def get_loaded_policy(self):
+        for pol in self.xsobjs.values():
+            if pol.isloaded():
+                return pol
+        return None
+
+    def get_policy_by_name(self, name):
+        for pol in self.xsobjs.values():
+            if pol.get_name() == name:
+                return pol
+        return None
+
+    def get_domain0_bootlabel(self):
+        """ Get the domain0 bootlabel from the default boot title """
+        title = ""
+        def_title = bootloader.get_default_title()
+        line = bootloader.get_kernel_val(def_title, "ssidref")
+        if line:
+            parms = line.split(":",1)
+            if len(parms) > 1:
+                title = parms[1]
+        return title
+
+    def set_domain0_bootlabel(self, xspol, label):
+        """ Set the domain-0 bootlabel under the given policy """
+        return xspol.set_vm_bootlabel(label)
+
+    def rm_domain0_bootlabel(self):
+        """ Remove the domain-0 bootlabel from the default boot title """
+        def_title = bootloader.get_default_title()
+        return bootloader.set_kernel_attval(def_title, "ssidref", None)
+
+    def ssidref_to_vmlabel(self, ssidref):
+        """ Given an ssidref, return the vmlabel under the current policy """
+        vmlabel = ""
+        pol = self.get_loaded_policy()
+        if pol:
+            vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref)
+        return vmlabel
+
+poladmin = None
+
+def XSPolicyAdminInstance(maxpolicies=1):
+    global poladmin
+    if poladmin == None:
+        poladmin = XSPolicyAdmin(maxpolicies)
diff -r 83fd4ad219cd -r aa640601575f tools/python/xen/xend/server/blkif.py
--- a/tools/python/xen/xend/server/blkif.py     Mon Jul 09 14:30:46 2007 +0100
+++ b/tools/python/xen/xend/server/blkif.py     Mon Jul 09 14:51:44 2007 +0100
@@ -73,10 +73,17 @@ class BlkifController(DevController):
             back['uuid'] = uuid
 
         if security.on():
-            (label, ssidref, policy) = security.get_res_security_details(uname)
-            back.update({'acm_label'  : label,
-                         'acm_ssidref': str(ssidref),
-                         'acm_policy' : policy})
+            (label, ssidref, policy) = \
+                                 security.get_res_security_details(uname)
+            domain_label = self.vm.get_security_label()
+            if domain_label:
+                rc = security.res_security_check_xapi(label, ssidref, policy,
+                                                      domain_label)
+                if rc == 0:
+                    raise VmError("VM's access to block device '%s' denied." %
+                                  uname)
+            else:
+                raise VmError("VM must have a security label.")
 
         devid = blkif.blkdev_name_to_number(dev)
         if devid is None:
diff -r 83fd4ad219cd -r aa640601575f tools/security/policies/security_policy.xsd
--- a/tools/security/policies/security_policy.xsd       Mon Jul 09 14:30:46 
2007 +0100
+++ b/tools/security/policies/security_policy.xsd       Mon Jul 09 14:51:44 
2007 +0100
@@ -22,7 +22,7 @@
                                <xsd:element name="Reference" type="xsd:string" 
minOccurs="0" maxOccurs="1" />
                                <xsd:element name="Date" minOccurs="0" 
maxOccurs="1" type="xsd:string"></xsd:element>
                                <xsd:element name="NameSpaceUrl" minOccurs="0" 
maxOccurs="1" type="xsd:string"></xsd:element>
-                               <xsd:element name="Version" minOccurs="0" 
maxOccurs="1" type="VersionFormat"/>
+                               <xsd:element name="Version" minOccurs="1" 
maxOccurs="1" type="VersionFormat"/>
                                <xsd:element ref="FromPolicy" minOccurs="0" 
maxOccurs="1"/>
                        </xsd:sequence>
                </xsd:complexType>
@@ -91,23 +91,23 @@
                        <xsd:sequence>
                                <xsd:element maxOccurs="unbounded" 
minOccurs="1" ref="Type" />
                        </xsd:sequence>
-                       <xsd:attribute name="name" type="xsd:string" 
use="optional"></xsd:attribute>
+                       <xsd:attribute name="name" type="xsd:string" 
use="required"></xsd:attribute>
                </xsd:complexType>
        </xsd:element>
        <xsd:element name="VirtualMachineLabel">
                <xsd:complexType>
                        <xsd:sequence>
-                               <xsd:element ref="Name"></xsd:element>
+                               <xsd:element name="Name" 
type="NameWithFrom"></xsd:element>
                                <xsd:element ref="SimpleTypeEnforcementTypes" 
minOccurs="0" maxOccurs="unbounded" />
-                               <xsd:element ref="ChineseWallTypes" 
minOccurs="0" maxOccurs="unbounded" />
+                               <xsd:element name="ChineseWallTypes" 
type="SingleChineseWallType" />
                        </xsd:sequence>
                </xsd:complexType>
        </xsd:element>
        <xsd:element name="ResourceLabel">
                <xsd:complexType>
                        <xsd:sequence>
-                               <xsd:element ref="Name"></xsd:element>
-                               <xsd:element ref="SimpleTypeEnforcementTypes" 
minOccurs="0" maxOccurs="unbounded" />
+                               <xsd:element name="Name" 
type="NameWithFrom"></xsd:element>
+                               <xsd:element name="SimpleTypeEnforcementTypes" 
type="SingleSimpleTypeEnforcementType" />
                        </xsd:sequence>
                </xsd:complexType>
        </xsd:element>
@@ -131,4 +131,21 @@
                        <xsd:pattern 
value="[0-9]{1,8}.[0-9]{1,8}"></xsd:pattern>
                </xsd:restriction>
        </xsd:simpleType>
+       <xsd:complexType name="NameWithFrom">
+               <xsd:simpleContent>
+                       <xsd:extension base="xsd:string">
+                               <xsd:attribute name="from" type="xsd:string" 
use="optional"></xsd:attribute>
+                       </xsd:extension>
+               </xsd:simpleContent>
+       </xsd:complexType>
+       <xsd:complexType name="SingleSimpleTypeEnforcementType">
+               <xsd:sequence>
+                       <xsd:element maxOccurs="1" minOccurs="1" ref="Type" />
+               </xsd:sequence>
+       </xsd:complexType>
+       <xsd:complexType name="SingleChineseWallType">
+               <xsd:sequence>
+                       <xsd:element maxOccurs="1" minOccurs="1" ref="Type" />
+               </xsd:sequence>
+       </xsd:complexType>
 </xsd:schema>

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.