WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [Xen-API] Extension of the Xen-API for ma

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [Xen-API] Extension of the Xen-API for managing Xen Security Policies
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 09 Jul 2007 09:52:56 -0700
Delivery-date: Mon, 09 Jul 2007 09:51:19 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [Xen-API] Extension of the Xen-API for managing Xen Security Policies, Xen patchbot-unstable <=