ia64/xen-unstable

annotate tools/python/xen/util/security.py @ 10720:8922c1fbe684

[XM][ACM] Add xm subcommands to work with security resource labels.

This patch adds new xm subcommands to support working with resource
labels. The new subcommands are 'xm resources', 'xm rmlabel', 'xm
getlabel' and 'xm dry-run'. In addition, the 'xm addlabel' subcommand
now uses an updated syntax to support labeling both domains and
resources. See the xm man page for details on each subcommand.

Beyond the new subcommands, this patch allows users to immediately see
when security checks will fail by pushing some basic security checking
into the beginning of 'xm create' and 'xm block-attach'. ACM security
attributes for block devices are added to XenStore in order to support
the final security enforcement, which will be performed in the kernel
and included in a separate patch.

Signed-off-by: Bryan D. Payne <bdpayne@us.ibm.com>
Signed-off-by: Reiner Sailer <sailer@us.ibm.com>
author kfraser@localhost.localdomain
date Mon Jul 10 17:18:07 2006 +0100 (2006-07-10)
parents 0de8a4a023d0
children 58144f4b102c
rev   line source
smh22@9835 1 #===========================================================================
smh22@9835 2 # This library is free software; you can redistribute it and/or
smh22@9835 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
smh22@9835 4 # License as published by the Free Software Foundation.
smh22@9835 5 #
smh22@9835 6 # This library is distributed in the hope that it will be useful,
smh22@9835 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
smh22@9835 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
smh22@9835 9 # Lesser General Public License for more details.
smh22@9835 10 #
smh22@9835 11 # You should have received a copy of the GNU Lesser General Public
smh22@9835 12 # License along with this library; if not, write to the Free Software
smh22@9835 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
smh22@9835 14 #============================================================================
smh22@9835 15 # Copyright (C) 2006 International Business Machines Corp.
smh22@9835 16 # Author: Reiner Sailer
kfraser@10720 17 # Author: Bryan D. Payne <bdpayne@us.ibm.com>
smh22@9835 18 #============================================================================
smh22@9835 19
smh22@9835 20 import commands
smh22@9835 21 import logging
smh22@9835 22 import sys, os, string, re
smh22@9835 23 import traceback
smh22@9835 24 import shutil
smh22@9835 25 from xen.lowlevel import acm
smh22@9835 26 from xen.xend import sxp
kfraser@10720 27 from xen.xend.XendLogging import log
kfraser@10720 28 from xen.util import dictio
smh22@9835 29
smh22@9835 30 #global directories and tools for security management
smh22@9835 31 policy_dir_prefix = "/etc/xen/acm-security/policies"
kfraser@10720 32 res_label_filename = policy_dir_prefix + "/resource_labels"
smh22@9835 33 boot_filename = "/boot/grub/menu.lst"
smh22@9835 34 xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
smh22@9835 35 xensec_tool = "/usr/sbin/xensec_tool"
smh22@9835 36
smh22@9835 37 #global patterns for map file
smh22@9835 38 #police_reference_tagname = "POLICYREFERENCENAME"
smh22@9835 39 primary_entry_re = re.compile("\s*PRIMARY\s+.*", re.IGNORECASE)
smh22@9835 40 secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE)
smh22@9835 41 label_template_re = re.compile(".*security_label_template.xml", re.IGNORECASE)
smh22@9835 42 mapping_filename_re = re.compile(".*\.map", re.IGNORECASE)
smh22@9835 43 policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE)
smh22@9835 44 vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE)
smh22@9835 45 res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE)
smh22@9835 46 all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE)
smh22@9835 47 access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE)
smh22@9835 48
smh22@9835 49 #global patterns for boot configuration file
smh22@9835 50 xen_title_re = re.compile("\s*title\s+XEN", re.IGNORECASE)
smh22@9835 51 any_title_re = re.compile("\s*title\s", re.IGNORECASE)
smh22@9835 52 xen_kernel_re = re.compile("\s*kernel.*xen.*\.gz", re.IGNORECASE)
smh22@9835 53 kernel_ver_re = re.compile("\s*module.*vmlinuz", re.IGNORECASE)
smh22@9835 54 any_module_re = re.compile("\s*module\s", re.IGNORECASE)
smh22@9835 55 empty_line_re = re.compile("^\s*$")
smh22@9835 56 binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
smh22@9835 57 policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
smh22@9835 58
kaf24@10396 59 #other global variables
kaf24@10396 60 NULL_SSIDREF = 0
smh22@9835 61
smh22@9835 62 log = logging.getLogger("xend.util.security")
smh22@9835 63
smh22@9835 64 # Our own exception definition. It is masked (pass) if raised and
smh22@9835 65 # whoever raises this exception must provide error information.
smh22@9835 66 class ACMError(Exception):
smh22@9835 67 def __init__(self,value):
smh22@9835 68 self.value = value
smh22@9835 69 def __str__(self):
smh22@9835 70 return repr(self.value)
smh22@9835 71
smh22@9835 72
smh22@9835 73
smh22@9835 74 def err(msg):
smh22@9835 75 """Raise ACM exception.
smh22@9835 76 """
smh22@9835 77 sys.stderr.write("ACMError: " + msg + "\n")
smh22@9835 78 raise ACMError(msg)
smh22@9835 79
smh22@9835 80
smh22@9835 81
smh22@9835 82 active_policy = None
smh22@9835 83
smh22@9835 84
smh22@9835 85 def refresh_security_policy():
smh22@9835 86 """
smh22@9835 87 retrieves security policy
smh22@9835 88 """
smh22@9835 89 global active_policy
smh22@9835 90
smh22@9835 91 try:
smh22@9835 92 active_policy = acm.policy()
smh22@9835 93 except:
smh22@9835 94 active_policy = "INACTIVE"
smh22@9835 95
smh22@9835 96 # now set active_policy
smh22@9835 97 refresh_security_policy()
smh22@9835 98
smh22@9835 99 def on():
smh22@9835 100 """
smh22@9835 101 returns none if security policy is off (not compiled),
smh22@9835 102 any string otherwise, use it: if not security.on() ...
smh22@9835 103 """
smh22@9835 104 refresh_security_policy()
smh22@9835 105 return (active_policy not in ['INACTIVE', 'NULL'])
smh22@9835 106
smh22@9835 107
smh22@9835 108
smh22@9835 109 # Assumes a 'security' info [security access_control ...] [ssidref ...]
smh22@9835 110 def get_security_info(info, field):
smh22@9835 111 """retrieves security field from self.info['security'])
smh22@9835 112 allowed search fields: ssidref, label, policy
smh22@9835 113 """
smh22@9835 114 if isinstance(info, dict):
smh22@9835 115 security = info['security']
smh22@9835 116 elif isinstance(info, list):
smh22@9835 117 security = sxp.child_value(info, 'security', )
smh22@9835 118 if not security:
smh22@9835 119 if field == 'ssidref':
smh22@9835 120 #return default ssid
smh22@9835 121 return 0
smh22@9835 122 else:
smh22@9835 123 err("Security information not found in info struct.")
smh22@9835 124
smh22@9835 125 if field == 'ssidref':
smh22@9835 126 search = 'ssidref'
smh22@9835 127 elif field in ['policy', 'label']:
smh22@9835 128 search = 'access_control'
smh22@9835 129 else:
smh22@9835 130 err("Illegal field in get_security_info.")
smh22@9835 131
smh22@9835 132 for idx in range(0, len(security)):
smh22@9835 133 if search != security[idx][0]:
smh22@9835 134 continue
smh22@9835 135 if search == 'ssidref':
smh22@9835 136 return int(security[idx][1])
smh22@9835 137 else:
smh22@9835 138 for aidx in range(0, len(security[idx])):
smh22@9835 139 if security[idx][aidx][0] == field:
smh22@9835 140 return str(security[idx][aidx][1])
smh22@9835 141
smh22@9835 142 if search == 'ssidref':
smh22@9835 143 return 0
smh22@9835 144 else:
smh22@9835 145 return None
smh22@9835 146
smh22@9835 147
smh22@9835 148
smh22@9835 149 def get_security_printlabel(info):
smh22@9835 150 """retrieves printable security label from self.info['security']),
smh22@9835 151 preferably the label name and otherwise (if label is not specified
smh22@9835 152 in config and cannot be found in mapping file) a hex string of the
smh22@9835 153 ssidref or none if both not available
smh22@9835 154 """
smh22@9835 155 try:
smh22@9835 156 if not on():
smh22@9835 157 return "INACTIVE"
smh22@9835 158 if active_policy in ["DEFAULT"]:
smh22@9835 159 return "DEFAULT"
smh22@9835 160
smh22@9835 161 printlabel = get_security_info(info, 'label')
smh22@9835 162 if printlabel:
smh22@9835 163 return printlabel
smh22@9835 164 ssidref = get_security_info(info, 'ssidref')
smh22@9835 165 if not ssidref:
smh22@9835 166 return None
smh22@9835 167 #try to translate ssidref to a label
smh22@9835 168 result = ssidref2label(ssidref)
smh22@9835 169 if not result:
smh22@9835 170 printlabel = "0x%08x" % ssidref
smh22@9835 171 else:
smh22@9835 172 printlabel = result
smh22@9835 173 return printlabel
smh22@9835 174 except ACMError:
smh22@9835 175 #don't throw an exception in xm list
smh22@9835 176 return "ERROR"
smh22@9835 177
smh22@9835 178
smh22@9835 179
smh22@9835 180 def getmapfile(policyname):
smh22@9835 181 """
smh22@9835 182 in: if policyname is None then the currently
smh22@9835 183 active hypervisor policy is used
smh22@9835 184 out: 1. primary policy, 2. secondary policy,
smh22@9835 185 3. open file descriptor for mapping file, and
smh22@9835 186 4. True if policy file is available, False otherwise
smh22@9835 187 """
smh22@9835 188 if not policyname:
smh22@9835 189 policyname = active_policy
smh22@9835 190 map_file_ok = False
smh22@9835 191 primary = None
smh22@9835 192 secondary = None
smh22@9835 193 #strip last part of policy as file name part
smh22@9835 194 policy_dir_list = string.split(policyname, ".")
smh22@9835 195 policy_file = policy_dir_list.pop()
smh22@9835 196 if len(policy_dir_list) > 0:
smh22@9835 197 policy_dir = string.join(policy_dir_list, "/") + "/"
smh22@9835 198 else:
smh22@9835 199 policy_dir = ""
smh22@9835 200
smh22@9835 201 map_filename = policy_dir_prefix + "/" + policy_dir + policy_file + ".map"
smh22@9835 202 # check if it is there, if not check if policy file is there
smh22@9835 203 if not os.path.isfile(map_filename):
smh22@9835 204 policy_filename = policy_dir_prefix + "/" + policy_dir + policy_file + "-security_policy.xml"
smh22@9835 205 if not os.path.isfile(policy_filename):
smh22@9835 206 err("Policy file \'" + policy_filename + "\' not found.")
smh22@9835 207 else:
smh22@9835 208 err("Mapping file \'" + map_filename + "\' not found." +
smh22@9835 209 " Use xm makepolicy to create it.")
smh22@9835 210
smh22@9835 211 f = open(map_filename)
smh22@9835 212 for line in f:
smh22@9835 213 if policy_reference_entry_re.match(line):
smh22@9835 214 l = line.split()
smh22@9835 215 if (len(l) == 2) and (l[1] == policyname):
smh22@9835 216 map_file_ok = True
smh22@9835 217 elif primary_entry_re.match(line):
smh22@9835 218 l = line.split()
smh22@9835 219 if len(l) == 2:
smh22@9835 220 primary = l[1]
smh22@9835 221 elif secondary_entry_re.match(line):
smh22@9835 222 l = line.split()
smh22@9835 223 if len(l) == 2:
smh22@9835 224 secondary = l[1]
smh22@9835 225 f.close()
smh22@9835 226 f = open(map_filename)
smh22@9835 227 if map_file_ok and primary and secondary:
smh22@9835 228 return (primary, secondary, f, True)
smh22@9835 229 else:
smh22@9835 230 err("Mapping file inconsistencies found. Try makepolicy to create a new one.")
smh22@9835 231
smh22@9835 232
smh22@9835 233
smh22@9835 234 def ssidref2label(ssidref_var):
smh22@9835 235 """
smh22@9835 236 returns labelname corresponding to ssidref;
smh22@9835 237 maps current policy to default directory
smh22@9835 238 to find mapping file
smh22@9835 239 """
smh22@9835 240 #1. translated permitted input formats
smh22@9835 241 if isinstance(ssidref_var, str):
smh22@9835 242 ssidref_var.strip()
smh22@9835 243 if ssidref_var[0:2] == "0x":
smh22@9835 244 ssidref = int(ssidref_var[2:], 16)
smh22@9835 245 else:
smh22@9835 246 ssidref = int(ssidref_var)
smh22@9835 247 elif isinstance(ssidref_var, int):
smh22@9835 248 ssidref = ssidref_var
smh22@9835 249 else:
smh22@9835 250 err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
smh22@9835 251
smh22@9835 252 (primary, secondary, f, pol_exists) = getmapfile(None)
smh22@9835 253 if not f:
smh22@9835 254 if (pol_exists):
smh22@9835 255 err("Mapping file for policy \'" + policyname + "\' not found.\n" +
smh22@9835 256 "Please use makepolicy command to create mapping file!")
smh22@9835 257 else:
smh22@9835 258 err("Policy file for \'" + active_policy + "\' not found.")
smh22@9835 259
smh22@9835 260 #2. get labelnames for both ssidref parts
smh22@9835 261 pri_ssid = ssidref & 0xffff
smh22@9835 262 sec_ssid = ssidref >> 16
kaf24@10396 263 pri_null_ssid = NULL_SSIDREF & 0xffff
kaf24@10396 264 sec_null_ssid = NULL_SSIDREF >> 16
smh22@9835 265 pri_labels = []
smh22@9835 266 sec_labels = []
smh22@9835 267 labels = []
smh22@9835 268
smh22@9835 269 for line in f:
smh22@9835 270 l = line.split()
smh22@9835 271 if (len(l) < 5) or (l[0] != "LABEL->SSID"):
smh22@9835 272 continue
smh22@9835 273 if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
smh22@9835 274 pri_labels.append(l[3])
smh22@9835 275 if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
smh22@9835 276 sec_labels.append(l[3])
smh22@9835 277 f.close()
smh22@9835 278
smh22@9835 279 #3. get the label that is in both lists (combination must be a single label)
kaf24@10396 280 if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid):
kaf24@10396 281 labels = sec_labels
kaf24@10396 282 elif (secondary == "CHWALL") and (pri_ssid != pri_null_ssid) and (sec_ssid == sec_null_ssid):
kaf24@10396 283 labels = pri_labels
kaf24@10396 284 elif secondary == "NULL":
smh22@9835 285 labels = pri_labels
smh22@9835 286 else:
smh22@9835 287 for i in pri_labels:
smh22@9835 288 for j in sec_labels:
smh22@9835 289 if (i==j):
smh22@9835 290 labels.append(i)
smh22@9835 291 if len(labels) != 1:
smh22@9835 292 err("Label for ssidref \'" + str(ssidref) +
smh22@9835 293 "\' unknown or not unique in policy \'" + active_policy + "\'")
smh22@9835 294
smh22@9835 295 return labels[0]
smh22@9835 296
smh22@9835 297
smh22@9835 298
kaf24@10396 299 def label2ssidref(labelname, policyname, type):
smh22@9835 300 """
smh22@9835 301 returns ssidref corresponding to labelname;
smh22@9835 302 maps current policy to default directory
smh22@9835 303 to find mapping file """
smh22@9835 304
smh22@9835 305 if policyname in ['NULL', 'INACTIVE', 'DEFAULT']:
smh22@9835 306 err("Cannot translate labels for \'" + policyname + "\' policy.")
smh22@9835 307
kaf24@10396 308 allowed_types = ['ANY']
kaf24@10396 309 if type == 'dom':
kaf24@10396 310 allowed_types.append('VM')
kaf24@10396 311 elif type == 'res':
kaf24@10396 312 allowed_types.append('RES')
kaf24@10396 313 else:
kaf24@10396 314 err("Invalid type. Must specify 'dom' or 'res'.")
kaf24@10396 315
smh22@9835 316 (primary, secondary, f, pol_exists) = getmapfile(policyname)
smh22@9835 317
smh22@9835 318 #2. get labelnames for ssidref parts and find a common label
smh22@9835 319 pri_ssid = []
smh22@9835 320 sec_ssid = []
smh22@9835 321 for line in f:
smh22@9835 322 l = line.split()
smh22@9835 323 if (len(l) < 5) or (l[0] != "LABEL->SSID"):
smh22@9835 324 continue
kaf24@10396 325 if primary and (l[1] in allowed_types) and (l[2] == primary) and (l[3] == labelname):
smh22@9835 326 pri_ssid.append(int(l[4], 16))
kaf24@10396 327 if secondary and (l[1] in allowed_types) and (l[2] == secondary) and (l[3] == labelname):
smh22@9835 328 sec_ssid.append(int(l[4], 16))
smh22@9835 329 f.close()
kaf24@10396 330 if (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
kaf24@10396 331 pri_ssid.append(NULL_SSIDREF)
kaf24@10396 332 elif (type == 'res') and (secondary == "CHWALL") and (len(sec_ssid) == 0):
kaf24@10396 333 sec_ssid.append(NULL_SSIDREF)
smh22@9835 334
smh22@9835 335 #3. sanity check and composition of ssidref
smh22@9835 336 if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and (secondary != "NULL")):
smh22@9835 337 err("Label \'" + labelname + "\' not found.")
smh22@9835 338 elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
smh22@9835 339 err("Label \'" + labelname + "\' not unique in policy (policy error)")
smh22@9835 340 if secondary == "NULL":
smh22@9835 341 return pri_ssid[0]
smh22@9835 342 else:
smh22@9835 343 return (sec_ssid[0] << 16) | pri_ssid[0]
smh22@9835 344
smh22@9835 345
smh22@9835 346
smh22@9835 347 def refresh_ssidref(config):
smh22@9835 348 """
smh22@9835 349 looks up ssidref from security field
smh22@9835 350 and refreshes the value if label exists
smh22@9835 351 """
smh22@9835 352 #called by dom0, policy could have changed after xen.utils.security was initialized
smh22@9835 353 refresh_security_policy()
smh22@9835 354
smh22@9835 355 security = None
smh22@9835 356 if isinstance(config, dict):
smh22@9835 357 security = config['security']
smh22@9835 358 elif isinstance(config, list):
smh22@9835 359 security = sxp.child_value(config, 'security',)
smh22@9835 360 else:
smh22@9835 361 err("Instance type of config parameter not supported.")
smh22@9835 362 if not security:
smh22@9835 363 #nothing to do (no security label attached)
smh22@9835 364 return config
smh22@9835 365
smh22@9835 366 policyname = None
smh22@9835 367 labelname = None
smh22@9835 368 # compose new security field
smh22@9835 369 for idx in range(0, len(security)):
smh22@9835 370 if security[idx][0] == 'ssidref':
smh22@9835 371 security.pop(idx)
smh22@9835 372 break
smh22@9835 373 elif security[idx][0] == 'access_control':
smh22@9835 374 for jdx in [1, 2]:
smh22@9835 375 if security[idx][jdx][0] == 'label':
smh22@9835 376 labelname = security[idx][jdx][1]
smh22@9835 377 elif security[idx][jdx][0] == 'policy':
smh22@9835 378 policyname = security[idx][jdx][1]
smh22@9835 379 else:
smh22@9835 380 err("Illegal field in access_control")
smh22@9835 381 #verify policy is correct
smh22@9835 382 if active_policy != policyname:
smh22@9835 383 err("Policy \'" + policyname + "\' in label does not match active policy \'"
smh22@9835 384 + active_policy +"\'!")
smh22@9835 385
kaf24@10396 386 new_ssidref = label2ssidref(labelname, policyname, 'dom')
smh22@9835 387 if not new_ssidref:
smh22@9835 388 err("SSIDREF refresh failed!")
smh22@9835 389
smh22@9835 390 security.append([ 'ssidref',str(new_ssidref)])
smh22@9835 391 security = ['security', security ]
smh22@9835 392
smh22@9835 393 for idx in range(0,len(config)):
smh22@9835 394 if config[idx][0] == 'security':
smh22@9835 395 config.pop(idx)
smh22@9835 396 break
smh22@9835 397 config.append(security)
smh22@9835 398
smh22@9835 399
smh22@9835 400
smh22@9835 401 def get_ssid(domain):
smh22@9835 402 """
smh22@9835 403 enables domains to retrieve the label / ssidref of a running domain
smh22@9835 404 """
smh22@9835 405 if not on():
smh22@9835 406 err("No policy active.")
smh22@9835 407
smh22@9835 408 if isinstance(domain, str):
smh22@9835 409 domain_int = int(domain)
smh22@9835 410 elif isinstance(domain, int):
smh22@9835 411 domain_int = domain
smh22@9835 412 else:
smh22@9835 413 err("Illegal parameter type.")
smh22@9835 414 try:
smh22@9835 415 ssid_info = acm.getssid(int(domain_int))
smh22@9835 416 except:
smh22@9835 417 err("Cannot determine security information.")
smh22@9835 418
smh22@9835 419 if active_policy in ["DEFAULT"]:
smh22@9835 420 label = "DEFAULT"
smh22@9835 421 else:
smh22@9835 422 label = ssidref2label(ssid_info["ssidref"])
smh22@9835 423 return(ssid_info["policyreference"],
smh22@9835 424 label,
smh22@9835 425 ssid_info["policytype"],
smh22@9835 426 ssid_info["ssidref"])
smh22@9835 427
smh22@9835 428
smh22@9835 429
smh22@9835 430 def get_decision(arg1, arg2):
smh22@9835 431 """
smh22@9835 432 enables domains to retrieve access control decisions from
smh22@9835 433 the hypervisor Access Control Module.
smh22@9835 434 IN: args format = ['domid', id] or ['ssidref', ssidref]
kaf24@10396 435 or ['access_control', ['policy', policy], ['label', label], ['type', type]]
smh22@9835 436 """
smh22@9835 437
smh22@9835 438 if not on():
smh22@9835 439 err("No policy active.")
smh22@9835 440
smh22@9835 441 #translate labels before calling low-level function
smh22@9835 442 if arg1[0] == 'access_control':
kaf24@10396 443 if (arg1[1][0] != 'policy') or (arg1[2][0] != 'label') or (arg1[3][0] != 'type'):
smh22@9835 444 err("Argument type not supported.")
kaf24@10396 445 ssidref = label2ssidref(arg1[2][1], arg1[1][1], arg1[3][1])
smh22@9835 446 arg1 = ['ssidref', str(ssidref)]
smh22@9835 447 if arg2[0] == 'access_control':
kaf24@10396 448 if (arg2[1][0] != 'policy') or (arg2[2][0] != 'label') or (arg2[3][0] != 'type'):
smh22@9835 449 err("Argument type not supported.")
kaf24@10396 450 ssidref = label2ssidref(arg2[2][1], arg2[1][1], arg2[3][1])
smh22@9835 451 arg2 = ['ssidref', str(ssidref)]
kaf24@10283 452
kaf24@10283 453 # accept only int or string types for domid and ssidref
kaf24@10283 454 if isinstance(arg1[1], int):
kaf24@10283 455 arg1[1] = str(arg1[1])
kaf24@10283 456 if isinstance(arg2[1], int):
kaf24@10283 457 arg2[1] = str(arg2[1])
kaf24@10283 458 if not isinstance(arg1[1], str) or not isinstance(arg2[1], str):
kaf24@10283 459 err("Invalid id or ssidref type, string or int required")
kaf24@10283 460
smh22@9835 461 try:
smh22@9835 462 decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
smh22@9835 463 except:
smh22@9835 464 err("Cannot determine decision.")
smh22@9835 465
smh22@9835 466 if decision:
smh22@9835 467 return decision
smh22@9835 468 else:
smh22@9835 469 err("Cannot determine decision (Invalid parameter).")
smh22@9835 470
smh22@9835 471
smh22@9835 472
smh22@9835 473 def make_policy(policy_name):
smh22@9835 474 policy_file = string.join(string.split(policy_name, "."), "/")
smh22@9835 475 if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"):
smh22@9835 476 err("Unknown policy \'" + policy_name + "\'")
smh22@9835 477
smh22@9835 478 (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file)
smh22@9835 479 if ret:
smh22@9835 480 err("Creating policy failed:\n" + output)
smh22@9835 481
smh22@9835 482
smh22@9835 483
smh22@9835 484 def load_policy(policy_name):
smh22@9835 485 global active_policy
smh22@9835 486 policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/")
smh22@9835 487 if not os.path.isfile(policy_file + ".bin"):
smh22@9835 488 if os.path.isfile(policy_file + "-security_policy.xml"):
smh22@9835 489 err("Binary file does not exist." +
smh22@9835 490 "Please use makepolicy to build the policy binary.")
smh22@9835 491 else:
smh22@9835 492 err("Unknown Policy " + policy_name)
smh22@9835 493
smh22@9835 494 #require this policy to be the first or the same as installed
smh22@9835 495 if active_policy not in ['DEFAULT', policy_name]:
smh22@9835 496 err("Active policy \'" + active_policy +
smh22@9835 497 "\' incompatible with new policy \'" + policy_name + "\'")
smh22@9835 498 (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin")
smh22@9835 499 if ret:
smh22@9835 500 err("Loading policy failed:\n" + output)
smh22@9835 501 else:
smh22@9835 502 # refresh active policy
smh22@9835 503 refresh_security_policy()
smh22@9835 504
smh22@9835 505
smh22@9835 506
smh22@9835 507 def dump_policy():
smh22@9835 508 if active_policy in ['NULL', 'INACTIVE']:
smh22@9835 509 err("\'" + active_policy + "\' policy. Nothing to dump.")
smh22@9835 510
smh22@9835 511 (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
smh22@9835 512 if ret:
smh22@9835 513 err("Dumping hypervisor policy failed:\n" + output)
smh22@9835 514 print output
smh22@9835 515
smh22@9835 516
smh22@9835 517
smh22@9835 518 def list_labels(policy_name, condition):
smh22@9835 519 if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
smh22@9835 520 err("Current policy \'" + active_policy + "\' has no labels defined.\n")
smh22@9835 521
smh22@9835 522 (primary, secondary, f, pol_exists) = getmapfile(policy_name)
smh22@9835 523 if not f:
smh22@9835 524 if pol_exists:
smh22@9835 525 err("Cannot find mapfile for policy \'" + policy_name +
smh22@9835 526 "\'.\nPlease use makepolicy to create mapping file.")
smh22@9835 527 else:
smh22@9835 528 err("Unknown policy \'" + policy_name + "\'")
smh22@9835 529
smh22@9835 530 labels = []
smh22@9835 531 for line in f:
smh22@9835 532 if condition.match(line):
smh22@9835 533 label = line.split()[3]
smh22@9835 534 if label not in labels:
smh22@9835 535 labels.append(label)
smh22@9835 536 return labels
kfraser@10720 537
kfraser@10720 538
kfraser@10720 539 def get_res_label(resource):
kfraser@10720 540 """Returns resource label information (label, policy) if it exists.
kfraser@10720 541 Otherwise returns null label and policy.
kfraser@10720 542 """
kfraser@10720 543 def default_res_label():
kfraser@10720 544 ssidref = NULL_SSIDREF
kfraser@10720 545 if on():
kfraser@10720 546 label = ssidref2label(ssidref)
kfraser@10720 547 else:
kfraser@10720 548 label = None
kfraser@10720 549 return (label, 'NULL')
kfraser@10720 550
kfraser@10720 551 (label, policy) = default_res_label()
kfraser@10720 552
kfraser@10720 553 # load the resource label file
kfraser@10720 554 res_label_cache = {}
kfraser@10720 555 try:
kfraser@10720 556 res_label_cache = dictio.dict_read("resources", res_label_filename)
kfraser@10720 557 except:
kfraser@10720 558 log.info("Resource label file not found.")
kfraser@10720 559 return default_res_label()
kfraser@10720 560
kfraser@10720 561 # find the resource information
kfraser@10720 562 if res_label_cache.has_key(resource):
kfraser@10720 563 (policy, label) = res_label_cache[resource]
kfraser@10720 564
kfraser@10720 565 return (label, policy)
kfraser@10720 566
kfraser@10720 567
kfraser@10720 568 def get_res_security_details(resource):
kfraser@10720 569 """Returns the (label, ssidref, policy) associated with a given
kfraser@10720 570 resource from the global resource label file.
kfraser@10720 571 """
kfraser@10720 572 def default_security_details():
kfraser@10720 573 ssidref = NULL_SSIDREF
kfraser@10720 574 if on():
kfraser@10720 575 label = ssidref2label(ssidref)
kfraser@10720 576 else:
kfraser@10720 577 label = None
kfraser@10720 578 policy = active_policy
kfraser@10720 579 return (label, ssidref, policy)
kfraser@10720 580
kfraser@10720 581 (label, ssidref, policy) = default_security_details()
kfraser@10720 582
kfraser@10720 583 # find the entry associated with this resource
kfraser@10720 584 (label, policy) = get_res_label(resource)
kfraser@10720 585 if policy == 'NULL':
kfraser@10720 586 log.info("Resource label for "+resource+" not in file, using DEFAULT.")
kfraser@10720 587 return default_security_details()
kfraser@10720 588
kfraser@10720 589 # is this resource label for the running policy?
kfraser@10720 590 if policy == active_policy:
kfraser@10720 591 ssidref = label2ssidref(label, policy, 'res')
kfraser@10720 592 else:
kfraser@10720 593 log.info("Resource label not for active policy, using DEFAULT.")
kfraser@10720 594 return default_security_details()
kfraser@10720 595
kfraser@10720 596 return (label, ssidref, policy)
kfraser@10720 597
kfraser@10720 598
kfraser@10720 599 def res_security_check(resource, domain_label):
kfraser@10720 600 """Checks if the given resource can be used by the given domain
kfraser@10720 601 label. Returns 1 if the resource can be used, otherwise 0.
kfraser@10720 602 """
kfraser@10720 603 rtnval = 1
kfraser@10720 604
kfraser@10720 605 # if security is on, ask the hypervisor for a decision
kfraser@10720 606 if on():
kfraser@10720 607 (label, ssidref, policy) = get_res_security_details(resource)
kfraser@10720 608 domac = ['access_control']
kfraser@10720 609 domac.append(['policy', active_policy])
kfraser@10720 610 domac.append(['label', domain_label])
kfraser@10720 611 domac.append(['type', 'dom'])
kfraser@10720 612 decision = get_decision(domac, ['ssidref', str(ssidref)])
kfraser@10720 613
kfraser@10720 614 # provide descriptive error messages
kfraser@10720 615 if decision == 'DENIED':
kfraser@10720 616 if label == ssidref2label(NULL_SSIDREF):
kfraser@10720 617 raise ACMError("Resource '"+resource+"' is not labeled")
kfraser@10720 618 rtnval = 0
kfraser@10720 619 else:
kfraser@10720 620 raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
kfraser@10720 621 rtnval = 0
kfraser@10720 622
kfraser@10720 623 # security is off, make sure resource isn't labeled
kfraser@10720 624 else:
kfraser@10720 625 (label, policy) = get_res_label(resource)
kfraser@10720 626 if policy != 'NULL':
kfraser@10720 627 raise ACMError("Security is off, but '"+resource+"' is labeled")
kfraser@10720 628 rtnval = 0
kfraser@10720 629
kfraser@10720 630 return rtnval