aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/python/xen/util/dictio.py50
-rw-r--r--tools/python/xen/util/security.py98
-rw-r--r--tools/python/xen/xend/server/blkif.py12
-rw-r--r--tools/python/xen/xm/addlabel.py152
-rw-r--r--tools/python/xen/xm/create.py121
-rw-r--r--tools/python/xen/xm/dry-run.py56
-rw-r--r--tools/python/xen/xm/getlabel.py114
-rw-r--r--tools/python/xen/xm/main.py30
-rw-r--r--tools/python/xen/xm/resources.py56
-rw-r--r--tools/python/xen/xm/rmlabel.py118
10 files changed, 765 insertions, 42 deletions
diff --git a/tools/python/xen/util/dictio.py b/tools/python/xen/util/dictio.py
new file mode 100644
index 0000000000..4fcebdb88a
--- /dev/null
+++ b/tools/python/xen/util/dictio.py
@@ -0,0 +1,50 @@
+#===========================================================================
+# 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 International Business Machines Corp.
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+
+def dict_read(dictname, filename):
+ """Loads <filename> and returns the dictionary named <dictname> from
+ the file.
+ """
+ dict = {}
+
+ # read in the config file
+ globs = {}
+ locs = {}
+ execfile(filename, globs, locs)
+
+ for (k, v) in locs.items():
+ if k == dictname:
+ dict = v
+ break
+
+ return dict
+
+def dict_write(dict, dictname, filename):
+ """Writes <dict> to <filename> using the name <dictname>. If the file
+ contains any other data, it will be overwritten.
+ """
+ prefix = dictname + " = {\n"
+ suffix = "}\n"
+ fd = open(filename, "wb")
+ fd.write(prefix)
+ for key in dict:
+ line = " '" + str(key) + "': " + str(dict[key]) + ",\n"
+ fd.write(line)
+ fd.write(suffix)
+ fd.close()
diff --git a/tools/python/xen/util/security.py b/tools/python/xen/util/security.py
index f778cbc1fe..015de985b1 100644
--- a/tools/python/xen/util/security.py
+++ b/tools/python/xen/util/security.py
@@ -14,6 +14,7 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
import commands
@@ -23,9 +24,12 @@ import traceback
import shutil
from xen.lowlevel import acm
from xen.xend import sxp
+from xen.xend.XendLogging import log
+from xen.util import dictio
#global directories and tools for security management
policy_dir_prefix = "/etc/xen/acm-security/policies"
+res_label_filename = policy_dir_prefix + "/resource_labels"
boot_filename = "/boot/grub/menu.lst"
xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
xensec_tool = "/usr/sbin/xensec_tool"
@@ -530,3 +534,97 @@ def list_labels(policy_name, condition):
if label not in labels:
labels.append(label)
return labels
+
+
+def get_res_label(resource):
+ """Returns resource label information (label, policy) if it exists.
+ Otherwise returns null label and policy.
+ """
+ def default_res_label():
+ ssidref = NULL_SSIDREF
+ if on():
+ 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)
+
+
+def get_res_security_details(resource):
+ """Returns the (label, ssidref, policy) associated with a given
+ resource from the global resource label file.
+ """
+ def default_security_details():
+ ssidref = NULL_SSIDREF
+ if on():
+ label = ssidref2label(ssidref)
+ else:
+ label = None
+ policy = active_policy
+ return (label, ssidref, policy)
+
+ (label, ssidref, policy) = default_security_details()
+
+ # find the entry associated with this resource
+ (label, policy) = get_res_label(resource)
+ if policy == 'NULL':
+ log.info("Resource label for "+resource+" not in file, using DEFAULT.")
+ return default_security_details()
+
+ # 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 res_security_check(resource, domain_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():
+ (label, ssidref, policy) = get_res_security_details(resource)
+ domac = ['access_control']
+ domac.append(['policy', active_policy])
+ domac.append(['label', domain_label])
+ domac.append(['type', 'dom'])
+ decision = get_decision(domac, ['ssidref', str(ssidref)])
+
+ # provide descriptive error messages
+ if decision == 'DENIED':
+ if label == ssidref2label(NULL_SSIDREF):
+ raise ACMError("Resource '"+resource+"' is not labeled")
+ rtnval = 0
+ else:
+ raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
+ rtnval = 0
+
+ # security is off, make sure resource isn't labeled
+ else:
+ (label, policy) = get_res_label(resource)
+ if policy != 'NULL':
+ raise ACMError("Security is off, but '"+resource+"' is labeled")
+ rtnval = 0
+
+ return rtnval
diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py
index 02cd4f26f7..986d065be9 100644
--- a/tools/python/xen/xend/server/blkif.py
+++ b/tools/python/xen/xend/server/blkif.py
@@ -21,6 +21,7 @@ import re
import string
from xen.util import blkif
+from xen.util import security
from xen.xend import sxp
from xen.xend.XendError import VmError
@@ -40,15 +41,22 @@ class BlkifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
+ uname = sxp.child_value(config, 'uname')
dev = sxp.child_value(config, 'dev')
- (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
+ (typ, params) = string.split(uname, ':', 1)
back = { 'dev' : dev,
'type' : typ,
'params' : params,
'mode' : sxp.child_value(config, 'mode', 'r')
- }
+ }
+
+ if security.on():
+ (label, ssidref, policy) = security.get_res_security_details(uname)
+ back.update({'acm_label' : label,
+ 'acm_ssidref': str(ssidref),
+ 'acm_policy' : policy})
if 'ioemu:' in dev:
(dummy, dev1) = string.split(dev, ':', 1)
diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py
index 57b0f79691..1831ec2f80 100644
--- a/tools/python/xen/xm/addlabel.py
+++ b/tools/python/xen/xm/addlabel.py
@@ -14,59 +14,139 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer <sailer@us.ibm.com>
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
-"""Labeling a domain configuration file.
+"""Labeling a domain configuration file or a resoruce.
"""
import sys, os
+import string
import traceback
+from xen.util import dictio
+from xen.util import security
+def usage():
+ print "\nUsage: xm addlabel <label> dom <configfile> [<policy>]"
+ print " xm addlabel <label> res <resource> [<policy>]\n"
+ print " This program adds an acm_label entry into the 'configfile'"
+ print " for a domain or to the global resource label file for a"
+ print " resource. It derives the policy from the running hypervisor"
+ print " if it is not given (optional parameter). If a label already"
+ print " exists for the given domain or resource, then addlabel fails.\n"
+
+
+def validate_config_file(configfile):
+ """Performs a simple sanity check on the configuration file passed on
+ the command line. We basically just want to make sure that it's
+ not a domain image file so we check for a few configuration values
+ and then we are satisfied. Returned 1 on success, otherwise 0.
+ """
+ # read in the config file
+ globs = {}
+ locs = {}
+ try:
+ execfile(configfile, globs, locs)
+ except:
+ print "Invalid configuration file."
+ return 0
-from xen.util.security import ACMError, err, active_policy, label2ssidref, on, access_control_re
+ # sanity check on the data from the file
+ count = 0
+ required = ['kernel', 'memory', 'name']
+ for (k, v) in locs.items():
+ if k in required:
+ count += 1
+ if count != 3:
+ print "Invalid configuration file."
+ return 0
+ else:
+ return 1
-def usage():
- print "\nUsage: xm addlabel <configfile> <label> [<policy>]\n"
- print " This program adds an acm_label entry into the 'configfile'."
- print " It derives the policy from the running hypervisor if it"
- print " is not given (optional parameter). If the configfile is"
- print " already labeled, then addlabel fails.\n"
- err("Usage")
+def add_resource_label(label, resource, policyref):
+ """Adds a resource label to the global resource label file.
+ """
+ # sanity check: make sure this label can be instantiated later on
+ ssidref = security.label2ssidref(label, policyref, 'res')
+
+ # sanity check on resource name
+ (type, file) = resource.split(":")
+ if type == "phy":
+ file = "/dev/" + file
+ if not os.path.exists(file):
+ print "Invalid resource '"+resource+"'"
+ return
+
+ # see if this resource is already in the file
+ access_control = {}
+ file = security.res_label_filename
+ try:
+ access_control = dictio.dict_read("resources", file)
+ except:
+ print "Resource file not found, creating new file at:"
+ print "%s" % (file)
+
+ if access_control.has_key(resource):
+ security.err("This resource is already labeled.")
+ # write the data to file
+ new_entry = { resource : tuple([policyref, label]) }
+ access_control.update(new_entry)
+ dictio.dict_write(access_control, "resources", file)
-def main(argv):
+
+def add_domain_label(label, configfile, policyref):
+ # sanity checks: make sure this label can be instantiated later on
+ ssidref = security.label2ssidref(label, policyref, 'dom')
+
+ new_label = "access_control = ['policy=%s,label=%s']\n" % (policyref, label)
+ if not os.path.isfile(configfile):
+ security.err("Configuration file \'" + configfile + "\' not found.")
+ config_fd = open(configfile, "ra+")
+ for line in config_fd:
+ if not security.access_control_re.match(line):
+ continue
+ config_fd.close()
+ security.err("Config file \'" + configfile + "\' is already labeled.")
+ config_fd.write(new_label)
+ config_fd.close()
+
+
+def main (argv):
try:
policyref = None
- if len(argv) not in [3,4]:
+ if len(argv) not in [4,5]:
usage()
- configfile = argv[1]
- label = argv[2]
+ return
+
+ label = argv[1]
- if len(argv) == 4:
- policyref = argv[3]
- elif on():
- policyref = active_policy
+ if len(argv) == 5:
+ policyref = argv[4]
+ elif security.on():
+ policyref = security.active_policy
else:
- err("No active policy. Policy must be specified in command line.")
-
- #sanity checks: make sure this label can be instantiated later on
- ssidref = label2ssidref(label, policyref, 'dom')
-
- new_label = "access_control = ['policy=%s,label=%s']\n" % (policyref, label)
- if not os.path.isfile(configfile):
- err("Configuration file \'" + configfile + "\' not found.")
- config_fd = open(configfile, "ra+")
- for line in config_fd:
- if not access_control_re.match(line):
- continue
- config_fd.close()
- err("Config file \'" + configfile + "\' is already labeled.")
- config_fd.write(new_label)
- config_fd.close()
+ security.err("No active policy. Policy must be specified in command line.")
- except ACMError:
- pass
- except:
+ if argv[2].lower() == "dom":
+ configfile = argv[3]
+ if configfile[0] != '/':
+ for prefix in [".", "/etc/xen"]:
+ configfile = prefix + "/" + configfile
+ if os.path.isfile(configfile):
+ fd = open(configfile, "rb")
+ break
+ if not validate_config_file(configfile):
+ usage()
+ else:
+ add_domain_label(label, configfile, policyref)
+ elif argv[2].lower() == "res":
+ resource = argv[3]
+ add_resource_label(label, resource, policyref)
+ else:
+ usage()
+
+ except security.ACMError:
traceback.print_exc(limit=1)
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 5b9137510a..b9c775e5dc 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -25,6 +25,7 @@ import sys
import socket
import re
import xmlrpclib
+import traceback
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -985,6 +986,117 @@ def parseCommandLine(argv):
return (gopts, config)
+def check_domain_label(config, verbose):
+ """All that we need to check here is that the domain label exists and
+ is not null when security is on. Other error conditions are
+ handled when the config file is parsed.
+ """
+ answer = 0
+ default_label = None
+ secon = 0
+ if security.on():
+ default_label = security.ssidref2label(security.NULL_SSIDREF)
+ secon = 1
+
+ # get the domain acm_label
+ dom_label = None
+ dom_name = None
+ for x in sxp.children(config):
+ if sxp.name(x) == 'security':
+ dom_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
+ if sxp.name(x) == 'name':
+ dom_name = sxp.child0(x)
+
+ # sanity check on domain label
+ if verbose:
+ print "Checking domain:"
+ if (not secon) and (not dom_label):
+ answer = 1
+ if verbose:
+ print " %s: PERMITTED" % (dom_name)
+ elif (secon) and (dom_label) and (dom_label != default_label):
+ answer = 1
+ if verbose:
+ print " %s: PERMITTED" % (dom_name)
+ else:
+ print " %s: DENIED" % (dom_name)
+ if not secon:
+ print " --> Security off, but domain labeled"
+ else:
+ print " --> Domain not labeled"
+ answer = 0
+
+ return answer
+
+
+def config_security_check(config, verbose):
+ """Checks each resource listed in the config to see if the active
+ policy will permit creation of a new domain using the config.
+ Returns 1 if the config passes all tests, otherwise 0.
+ """
+ answer = 1
+
+ # get the domain acm_label
+ domain_label = None
+ domain_policy = None
+ for x in sxp.children(config):
+ if sxp.name(x) == 'security':
+ domain_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
+ domain_policy = sxp.child_value(sxp.name(sxp.child0(x)), 'policy')
+
+ # if no domain label, use default
+ if not domain_label and security.on():
+ try:
+ domain_label = security.ssidref2label(security.NULL_SSIDREF)
+ except:
+ traceback.print_exc(limit=1)
+ return 0
+ domain_policy = 'NULL'
+ elif not domain_label:
+ domain_label = ""
+ domain_policy = 'NULL'
+
+ if verbose:
+ print "Checking resources:"
+
+ # build a list of all resources in the config file
+ resources = []
+ for x in sxp.children(config):
+ if sxp.name(x) == 'device':
+ if sxp.name(sxp.child0(x)) == 'vbd':
+ resources.append(sxp.child_value(sxp.child0(x), 'uname'))
+
+ # perform a security check on each resource
+ for resource in resources:
+ try:
+ security.res_security_check(resource, domain_label)
+ if verbose:
+ print " %s: PERMITTED" % (resource)
+
+ except security.ACMError:
+ print " %s: DENIED" % (resource)
+ (res_label, res_policy) = security.get_res_label(resource)
+ print " --> res:"+res_label+" ("+res_policy+")"
+ print " --> dom:"+domain_label+" ("+domain_policy+")"
+ answer = 0
+
+ return answer
+
+
+def create_security_check(config):
+ passed = 0
+ try:
+ if check_domain_label(config, verbose=0):
+ if config_security_check(config, verbose=0):
+ passed = 1
+ else:
+ print "Checking resources: (skipped)"
+ except security.ACMError:
+ traceback.print_exc(limit=1)
+
+ return passed
+
+
def main(argv):
try:
(opts, config) = parseCommandLine(argv)
@@ -997,9 +1109,12 @@ def main(argv):
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
- dom = make_domain(opts, config)
- if opts.vals.console_autoconnect:
- console.execConsole(dom)
+ if not create_security_check(config):
+ print "Security configuration prevents domain from starting"
+ else:
+ dom = make_domain(opts, config)
+ if opts.vals.console_autoconnect:
+ console.execConsole(dom)
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/dry-run.py b/tools/python/xen/xm/dry-run.py
new file mode 100644
index 0000000000..4290528636
--- /dev/null
+++ b/tools/python/xen/xm/dry-run.py
@@ -0,0 +1,56 @@
+#============================================================================
+# 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 International Business Machines Corp.
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Tests the security settings for a domain and its resources.
+"""
+from xen.util import security
+from xen.xm import create
+from xen.xend import sxp
+
+def usage():
+ print "\nUsage: xm dry-run <configfile>\n"
+ print "This program checks each resource listed in the configfile"
+ print "to see if the domain created by the configfile can access"
+ print "the resources. The status of each resource is listed"
+ print "individually along with the final security decision.\n"
+
+
+def main (argv):
+ if len(argv) != 2:
+ usage()
+ return
+
+ try:
+ passed = 0
+ (opts, config) = create.parseCommandLine(argv)
+ if create.check_domain_label(config, verbose=1):
+ if create.config_security_check(config, verbose=1):
+ passed = 1
+ else:
+ print "Checking resources: (skipped)"
+
+ if passed:
+ print "Dry Run: PASSED"
+ else:
+ print "Dry Run: FAILED"
+ except security.ACMError:
+ pass
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/tools/python/xen/xm/getlabel.py b/tools/python/xen/xm/getlabel.py
new file mode 100644
index 0000000000..c74e29f7a2
--- /dev/null
+++ b/tools/python/xen/xm/getlabel.py
@@ -0,0 +1,114 @@
+#============================================================================
+# 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 International Business Machines Corp.
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Show the label for a domain or resoruce.
+"""
+import sys, os, re
+import string
+import traceback
+from xen.util import dictio
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm getlabel dom <configfile>"
+ print " xm getlabel res <resource>\n"
+ print " This program shows the label for a domain or resource.\n"
+
+
+def get_resource_label(resource):
+ """Gets the resource label
+ """
+ # read in the resource file
+ file = security.res_label_filename
+ try:
+ access_control = dictio.dict_read("resources", file)
+ except:
+ print "Resource label file not found"
+ return
+
+ # get the entry and print label
+ if access_control.has_key(resource):
+ policy = access_control[resource][0]
+ label = access_control[resource][1]
+ print "policy="+policy+",label="+label
+ else:
+ print "Resource not labeled"
+
+
+def get_domain_label(configfile):
+ # open the domain config file
+ fd = None
+ file = None
+ if configfile[0] == '/':
+ fd = open(configfile, "rb")
+ else:
+ for prefix in [".", "/etc/xen"]:
+ file = prefix + "/" + configfile
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ break
+ if not fd:
+ print "Configuration file '"+configfile+"' not found."
+ return
+
+ # read in the domain config file, finding the label line
+ ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
+ ac_exit_re = re.compile(".*'\].*")
+ acline = ""
+ record = 0
+ for line in fd.readlines():
+ if ac_entry_re.match(line):
+ record = 1
+ if record:
+ acline = acline + line
+ if record and ac_exit_re.match(line):
+ record = 0
+ fd.close()
+
+ # send error message if we didn't find anything
+ if acline == "":
+ print "Label does not exist in domain configuration file."
+ return
+
+ # print out the label
+ (title, data) = acline.split("=", 1)
+ data = data.strip()
+ data = data.lstrip("[\'")
+ data = data.rstrip("\']")
+ print data
+
+
+def main (argv):
+ if len(argv) != 3:
+ usage()
+ return
+
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ get_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ get_resource_label(resource)
+ else:
+ usage()
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index d13e96eebf..791c18eacd 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -30,6 +30,7 @@ import socket
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
import xmlrpclib
+import traceback
import xen.xend.XendProtocol
@@ -119,7 +120,11 @@ vnet_list_help = "vnet-list [-l|--long] list vnets"
vnet_create_help = "vnet-create <config> create a vnet from a config file"
vnet_delete_help = "vnet-delete <vnetid> delete a vnet"
vtpm_list_help = "vtpm-list <DomId> [--long] list virtual TPM devices"
-addlabel_help = "addlabel <ConfigFile> <label> Add security label to ConfigFile"
+addlabel_help = "addlabel <label> dom <configfile> Add security label to domain\n <label> res <resource> or resource"
+rmlabel_help = "rmlabel dom <configfile> Remove security label from domain\n res <resource> or resource"
+getlabel_help = "getlabel dom <configfile> Show security label for domain\n res <resource> or resource"
+dry_run_help = "dry-run <configfile> Tests if domain can access its resources"
+resources_help = "resources Show info for each labeled resource"
cfgbootpolicy_help = "cfgbootpolicy <policy> Add policy to boot configuration "
dumppolicy_help = "dumppolicy Print hypervisor ACM state information"
loadpolicy_help = "loadpolicy <policy> Load binary policy into hypervisor"
@@ -203,6 +208,10 @@ vnet_commands = [
acm_commands = [
"labels",
"addlabel",
+ "rmlabel",
+ "getlabel",
+ "dry-run",
+ "resources",
"makepolicy",
"loadpolicy",
"cfgbootpolicy",
@@ -992,6 +1001,21 @@ def xm_block_attach(args):
if len(args) == 5:
vbd.append(['backend', args[4]])
+ # verify that policy permits attaching this resource
+ try:
+ if security.on():
+ dominfo = server.xend.domain(dom)
+ label = security.get_security_printlabel(dominfo)
+ else:
+ label = None
+ security.res_security_check(args[1], label)
+ except security.ACMError, e:
+ print e.value
+ sys.exit(1)
+ except:
+ traceback.print_exc(limit=1)
+ sys.exit(1)
+
server.xend.domain.device_create(dom, vbd)
@@ -1124,6 +1148,10 @@ subcommands = [
'shutdown',
'labels',
'addlabel',
+ 'rmlabel',
+ 'getlabel',
+ 'dry-run',
+ 'resources',
'cfgbootpolicy',
'makepolicy',
'loadpolicy',
diff --git a/tools/python/xen/xm/resources.py b/tools/python/xen/xm/resources.py
new file mode 100644
index 0000000000..ef1184eec8
--- /dev/null
+++ b/tools/python/xen/xm/resources.py
@@ -0,0 +1,56 @@
+#============================================================================
+# 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 International Business Machines Corp.
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""List the resource label information from the global resource label file
+"""
+import sys, os
+import string
+from xen.util import dictio
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm resource\n"
+ print " This program lists information for each resource in the"
+ print " global resource label file\n"
+
+
+def print_resource_data(access_control):
+ """Prints out a resource dictionary to stdout
+ """
+ for resource in access_control:
+ (policy, label) = access_control[resource]
+ print resource
+ print " policy: "+policy
+ print " label: "+label
+
+
+def main (argv):
+ try:
+ file = security.res_label_filename
+ access_control = dictio.dict_read("resources", file)
+ except:
+ print "Resource file not found."
+ return
+
+ print_resource_data(access_control)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+
diff --git a/tools/python/xen/xm/rmlabel.py b/tools/python/xen/xm/rmlabel.py
new file mode 100644
index 0000000000..ebd94a3163
--- /dev/null
+++ b/tools/python/xen/xm/rmlabel.py
@@ -0,0 +1,118 @@
+#============================================================================
+# 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 International Business Machines Corp.
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Remove a label from a domain configuration file or a resoruce.
+"""
+import sys, os, re
+import string
+import traceback
+from xen.util import dictio
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm rmlabel dom <configfile>"
+ print " xm rmlabel res <resource>\n"
+ print " This program removes an acm_label entry from the 'configfile'"
+ print " for a domain or from the global resource label file for a"
+ print " resource. If the label does not exist for the given domain or"
+ print " resource, then rmlabel fails.\n"
+
+
+def rm_resource_label(resource):
+ """Removes a resource label from the global resource label file.
+ """
+ # read in the resource file
+ file = security.res_label_filename
+ try:
+ access_control = dictio.dict_read("resources", file)
+ except:
+ security.err("Resource file not found, cannot remove label!")
+
+ # remove the entry and update file
+ if access_control.has_key(resource):
+ del access_control[resource]
+ dictio.dict_write(access_control, "resources", file)
+ else:
+ security.err("Label does not exist in resource label file.")
+
+
+def rm_domain_label(configfile):
+ # open the domain config file
+ fd = None
+ file = None
+ if configfile[0] == '/':
+ fd = open(configfile, "rb")
+ else:
+ for prefix in [".", "/etc/xen"]:
+ file = prefix + "/" + configfile
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ break
+ if not fd:
+ security.err("Configuration file '"+configfile+"' not found.")
+
+ # read in the domain config file, removing label
+ ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
+ ac_exit_re = re.compile(".*'\].*")
+ file_contents = ""
+ comment = 0
+ removed = 0
+ for line in fd.readlines():
+ if ac_entry_re.match(line):
+ comment = 1
+ if comment:
+ removed = 1
+ line = "#"+line
+ if comment and ac_exit_re.match(line):
+ comment = 0
+ file_contents = file_contents + line
+ fd.close()
+
+ # send error message if we didn't find anything to remove
+ if not removed:
+ security.err("Label does not exist in domain configuration file.")
+
+ # write the data back out to the file
+ fd = open(file, "wb")
+ fd.writelines(file_contents)
+ fd.close()
+
+
+def main (argv):
+ try:
+ if len(argv) != 3:
+ usage()
+ return
+
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ rm_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ rm_resource_label(resource)
+ else:
+ usage()
+
+ except security.ACMError:
+ traceback.print_exc(limit=1)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+