ia64/xen-unstable

changeset 9836:681a18bf049e

This patch integrates the new access control management tools into 'xm'
and 'xend' and supports label/ssid translation support for
migration/life-migration/resume.

Signed-off by: Reiner Sailer <sailer@us.ibm.com>
author smh22@firebug.cl.cam.ac.uk
date Mon Apr 24 10:59:17 2006 +0100 (2006-04-24)
parents cf20dbbf5c2b
children c7b9b8a64755
files tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xm/create.py tools/python/xen/xm/main.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomain.py	Mon Apr 24 10:58:25 2006 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomain.py	Mon Apr 24 10:59:17 2006 +0100
     1.3 @@ -38,6 +38,7 @@ from xen.xend.XendError import XendError
     1.4  from xen.xend.XendLogging import log
     1.5  from xen.xend.xenstore.xstransact import xstransact
     1.6  from xen.xend.xenstore.xswatch import xswatch
     1.7 +from xen.util import security
     1.8  
     1.9  
    1.10  xc = xen.lowlevel.xc.xc()
    1.11 @@ -265,7 +266,7 @@ class XendDomain:
    1.12              # handling in the relocation-socket handling code (relocate.py) is
    1.13              # poor, so we need to log this for debugging.
    1.14              log.exception("Restore failed")
    1.15 -            raise
    1.16 +            raise XendError("Restore failed")
    1.17  
    1.18  
    1.19      def restore_(self, config):
    1.20 @@ -283,6 +284,7 @@ class XendDomain:
    1.21          """
    1.22          self.domains_lock.acquire()
    1.23          try:
    1.24 +            security.refresh_ssidref(config)
    1.25              dominfo = XendDomainInfo.restore(config)
    1.26              self._add_domain(dominfo)
    1.27              return dominfo
     2.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Mon Apr 24 10:58:25 2006 +0100
     2.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Mon Apr 24 10:59:17 2006 +0100
     2.3 @@ -33,7 +33,7 @@ import threading
     2.4  import xen.lowlevel.xc
     2.5  from xen.util import asserts
     2.6  from xen.util.blkif import blkdev_uname_to_file
     2.7 -
     2.8 +from xen.util import security
     2.9  import balloon
    2.10  import image
    2.11  import sxp
    2.12 @@ -126,7 +126,6 @@ VM_CONFIG_PARAMS = [
    2.13  # file, so those are handled separately.
    2.14  ROUNDTRIPPING_CONFIG_ENTRIES = [
    2.15      ('uuid',       str),
    2.16 -    ('ssidref',    int),
    2.17      ('vcpus',      int),
    2.18      ('vcpu_avail', int),
    2.19      ('cpu_weight', float),
    2.20 @@ -144,7 +143,6 @@ ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFI
    2.21  #
    2.22  VM_STORE_ENTRIES = [
    2.23      ('uuid',       str),
    2.24 -    ('ssidref',    int),
    2.25      ('vcpus',      int),
    2.26      ('vcpu_avail', int),
    2.27      ('memory',     int),
    2.28 @@ -297,6 +295,9 @@ def parseConfig(config):
    2.29      result['cpu']   = get_cfg('cpu',  int)
    2.30      result['cpus']  = get_cfg('cpus', str)
    2.31      result['image'] = get_cfg('image')
    2.32 +    tmp_security = get_cfg('security')
    2.33 +    if tmp_security:
    2.34 +        result['security'] = tmp_security
    2.35  
    2.36      try:
    2.37          if result['image']:
    2.38 @@ -443,7 +444,7 @@ class XendDomainInfo:
    2.39          self.validateInfo()
    2.40  
    2.41          self.image = None
    2.42 -
    2.43 +        self.security = None
    2.44          self.store_port = None
    2.45          self.store_mfn = None
    2.46          self.console_port = None
    2.47 @@ -521,6 +522,7 @@ class XendDomainInfo:
    2.48          else:
    2.49              entries = VM_STORE_ENTRIES
    2.50          entries.append(('image', str))
    2.51 +        entries.append(('security', str))
    2.52  
    2.53          map(lambda x, y: useIfNeeded(x[0], y), entries,
    2.54              self.readVMDetails(entries))
    2.55 @@ -544,7 +546,6 @@ class XendDomainInfo:
    2.56  
    2.57          try:
    2.58              defaultInfo('name',         lambda: "Domain-%d" % self.domid)
    2.59 -            defaultInfo('ssidref',      lambda: 0)
    2.60              defaultInfo('on_poweroff',  lambda: "destroy")
    2.61              defaultInfo('on_reboot',    lambda: "restart")
    2.62              defaultInfo('on_crash',     lambda: "restart")
    2.63 @@ -571,12 +572,16 @@ class XendDomainInfo:
    2.64              defaultInfo('backend',      lambda: [])
    2.65              defaultInfo('device',       lambda: [])
    2.66              defaultInfo('image',        lambda: None)
    2.67 +            defaultInfo('security',     lambda: None)
    2.68  
    2.69              self.check_name(self.info['name'])
    2.70  
    2.71              if isinstance(self.info['image'], str):
    2.72                  self.info['image'] = sxp.from_string(self.info['image'])
    2.73  
    2.74 +            if isinstance(self.info['security'], str):
    2.75 +                self.info['security'] = sxp.from_string(self.info['security'])
    2.76 +
    2.77              if self.info['memory'] == 0:
    2.78                  if self.infoIsSet('mem_kb'):
    2.79                      self.info['memory'] = (self.info['mem_kb'] + 1023) / 1024
    2.80 @@ -674,6 +679,20 @@ class XendDomainInfo:
    2.81          if self.infoIsSet('image'):
    2.82              to_store['image'] = sxp.to_string(self.info['image'])
    2.83  
    2.84 +        if self.infoIsSet('security'):
    2.85 +            security = self.info['security']
    2.86 +            to_store['security'] = sxp.to_string(security)
    2.87 +            for idx in range(0, len(security)):
    2.88 +                if security[idx][0] == 'access_control':
    2.89 +                    to_store['security/access_control'] = sxp.to_string([ security[idx][1] , security[idx][2] ])
    2.90 +                    for aidx in range(1, len(security[idx])):
    2.91 +                        if security[idx][aidx][0] == 'label':
    2.92 +                            to_store['security/access_control/label'] = security[idx][aidx][1]
    2.93 +                        if security[idx][aidx][0] == 'policy':
    2.94 +                            to_store['security/access_control/policy'] = security[idx][aidx][1]
    2.95 +                if security[idx][0] == 'ssidref':
    2.96 +                    to_store['security/ssidref'] = str(security[idx][1])
    2.97 +
    2.98          log.debug("Storing VM details: %s", to_store)
    2.99  
   2.100          self.writeVm(to_store)
   2.101 @@ -766,9 +785,8 @@ class XendDomainInfo:
   2.102          self.storeVm('vcpu_avail', self.info['vcpu_avail'])
   2.103          self.writeDom(self.vcpuDomDetails())
   2.104  
   2.105 -
   2.106 -    def getSsidref(self):
   2.107 -        return self.info['ssidref']
   2.108 +    def getLabel(self):
   2.109 +        return security.get_security_info(self.info, 'label')
   2.110  
   2.111      def getMemoryTarget(self):
   2.112          """Get this domain's target memory size, in KB."""
   2.113 @@ -960,12 +978,21 @@ class XendDomainInfo:
   2.114          """
   2.115  
   2.116          log.trace("XendDomainInfo.update(%s) on domain %d", info, self.domid)
   2.117 -
   2.118          if not info:
   2.119              info = dom_get(self.domid)
   2.120              if not info:
   2.121                  return
   2.122              
   2.123 +        #manually update ssidref / security fields
   2.124 +        if security.on() and info.has_key('ssidref'):
   2.125 +            if (info['ssidref'] != 0) and self.info.has_key('security'):
   2.126 +                security_field = self.info['security']
   2.127 +                if not security_field:
   2.128 +                    #create new security element
   2.129 +                    self.info.update({'security': [['ssidref', str(info['ssidref'])]]})
   2.130 +            #ssidref field not used any longer
   2.131 +        info.pop('ssidref')
   2.132 +
   2.133          self.info.update(info)
   2.134          self.validateInfo()
   2.135          self.refreshShutdown(info)
   2.136 @@ -1002,7 +1029,6 @@ class XendDomainInfo:
   2.137          s += " id=" + str(self.domid)
   2.138          s += " name=" + self.info['name']
   2.139          s += " memory=" + str(self.info['memory'])
   2.140 -        s += " ssidref=" + str(self.info['ssidref'])
   2.141          s += ">"
   2.142          return s
   2.143  
   2.144 @@ -1064,6 +1090,9 @@ class XendDomainInfo:
   2.145          if self.infoIsSet('image'):
   2.146              sxpr.append(['image', self.info['image']])
   2.147  
   2.148 +        if self.infoIsSet('security'):
   2.149 +            sxpr.append(['security', self.info['security']])
   2.150 +
   2.151          for cls in controllerClasses:
   2.152              for config in self.getDeviceConfigurations(cls):
   2.153                  sxpr.append(['device', config])
   2.154 @@ -1165,12 +1194,11 @@ class XendDomainInfo:
   2.155          @raise: VmError on error
   2.156          """
   2.157  
   2.158 -        log.debug('XendDomainInfo.construct: %s %s',
   2.159 -                  self.domid,
   2.160 -                  self.info['ssidref'])
   2.161 +        log.debug('XendDomainInfo.construct: %s',
   2.162 +                  self.domid)
   2.163  
   2.164          self.domid = xc.domain_create(
   2.165 -            dom = 0, ssidref = self.info['ssidref'],
   2.166 +            dom = 0, ssidref = security.get_security_info(self.info, 'ssidref'),
   2.167              handle = uuid.fromString(self.info['uuid']))
   2.168  
   2.169          if self.domid < 0:
     3.1 --- a/tools/python/xen/xm/create.py	Mon Apr 24 10:58:25 2006 +0100
     3.2 +++ b/tools/python/xen/xm/create.py	Mon Apr 24 10:59:17 2006 +0100
     3.3 @@ -35,6 +35,7 @@ import xen.xend.XendClient
     3.4  from xen.xend.XendClient import server
     3.5  from xen.xend.XendBootloader import bootloader
     3.6  from xen.util import blkif
     3.7 +from xen.util import security
     3.8  
     3.9  from xen.xm.opts import *
    3.10  
    3.11 @@ -145,10 +146,6 @@ gopts.var('memory', val='MEMORY',
    3.12            fn=set_int, default=128,
    3.13            use="Domain memory in MB.")
    3.14  
    3.15 -gopts.var('ssidref', val='SSIDREF',
    3.16 -          fn=set_u32, default=0, 
    3.17 -          use="Security Identifier.")
    3.18 -
    3.19  gopts.var('maxmem', val='MEMORY',
    3.20            fn=set_int, default=None,
    3.21            use="Maximum domain memory in MB.")
    3.22 @@ -293,6 +290,14 @@ gopts.var('vtpm', val="instance=INSTANCE
    3.23            number can be found in /etc/xen/vtpm.db. Use the backend in the
    3.24            given domain.""")
    3.25  
    3.26 +gopts.var('access_control', val="policy=POLICY,label=LABEL",
    3.27 +          fn=append_value, default=[],
    3.28 +          use="""Add a security label and the security policy reference that defines it.
    3.29 +          The local ssid reference is calculated when starting/resuming the domain. At
    3.30 +          this time, the policy is checked against the active policy as well. This way,
    3.31 +          migrating through save/restore is covered and local labels are automatically
    3.32 +          created correctly on the system where a domain is started / resumed.""")
    3.33 +
    3.34  gopts.var('nics', val="NUM",
    3.35            fn=set_int, default=-1,
    3.36            use="""DEPRECATED.  Use empty vif entries instead.
    3.37 @@ -502,6 +507,43 @@ def configure_usb(config_devs, vals):
    3.38          config_usb = ['usb', ['path', path]]
    3.39          config_devs.append(['device', config_usb])
    3.40  
    3.41 +
    3.42 +def configure_security(config, vals):
    3.43 +    """Create the config for ACM security labels.
    3.44 +    """
    3.45 +    access_control = vals.access_control
    3.46 +    num = len(access_control)
    3.47 +    if num == 1:
    3.48 +        d = access_control[0]
    3.49 +        policy = d.get('policy')
    3.50 +        label = d.get('label')
    3.51 +        if policy != security.active_policy:
    3.52 +            err("Security policy (" + policy + ") incompatible with enforced policy ("
    3.53 +                + security.active_policy + ")." )
    3.54 +        config_access_control = ['access_control',
    3.55 +                                 ['policy', policy],
    3.56 +                                 ['label', label] ]
    3.57 +
    3.58 +        #ssidref cannot be specified together with access_control
    3.59 +        if sxp.child_value(config, 'ssidref'):
    3.60 +            err("ERROR: SSIDREF and access_control are mutually exclusive but both specified!")
    3.61 +        #else calculate ssidre from label
    3.62 +        ssidref = security.label2ssidref(label, policy)
    3.63 +        if not ssidref :
    3.64 +            err("ERROR calculating ssidref from access_control.")
    3.65 +        security_label = ['security', [ config_access_control, ['ssidref' , ssidref ] ] ]
    3.66 +        config.append(security_label)
    3.67 +    elif num == 0:
    3.68 +        if hasattr(vals, 'ssidref'):
    3.69 +            if not security.on():
    3.70 +                err("ERROR: Security ssidref specified but no policy active.")
    3.71 +            ssidref = getattr(vals, 'ssidref')
    3.72 +            security_label = ['security', [ [ 'ssidref' , int(ssidref) ] ] ]
    3.73 +            config.append(security_label)
    3.74 +    elif num > 1:
    3.75 +        err("VM config error: Multiple access_control definitions!")
    3.76 +
    3.77 +
    3.78  def configure_vtpm(config_devs, vals):
    3.79      """Create the config for virtual TPM interfaces.
    3.80      """
    3.81 @@ -595,9 +637,9 @@ def make_config(vals):
    3.82              if v:
    3.83                  config.append([n, v])
    3.84  
    3.85 -    map(add_conf, ['name', 'memory', 'ssidref', 'maxmem', 'restart',
    3.86 -                   'on_poweroff', 'on_reboot', 'on_crash', 'vcpus'])
    3.87 -    
    3.88 +    map(add_conf, ['name', 'memory', 'maxmem', 'restart', 'on_poweroff',
    3.89 +                   'on_reboot', 'on_crash', 'vcpus'])
    3.90 +
    3.91      if vals.uuid is not None:
    3.92          config.append(['uuid', vals.uuid])
    3.93      if vals.cpu is not None:
    3.94 @@ -628,6 +670,7 @@ def make_config(vals):
    3.95      configure_vifs(config_devs, vals)
    3.96      configure_usb(config_devs, vals)
    3.97      configure_vtpm(config_devs, vals)
    3.98 +    configure_security(config, vals)
    3.99      config += config_devs
   3.100  
   3.101      return config
   3.102 @@ -696,6 +739,29 @@ def preprocess_vtpm(vals):
   3.103          vtpms.append(d)
   3.104      vals.vtpm = vtpms
   3.105  
   3.106 +def preprocess_access_control(vals):
   3.107 +    if not vals.access_control:
   3.108 +        return
   3.109 +    access_controls = []
   3.110 +    num = len(vals.access_control)
   3.111 +    if num == 1:
   3.112 +        access_control = (vals.access_control)[0]
   3.113 +        d = {}
   3.114 +        a = access_control.split(',')
   3.115 +        if len(a) > 2:
   3.116 +            err('Too many elements in access_control specifier: ' + access_control)
   3.117 +        for b in a:
   3.118 +            (k, v) = b.strip().split('=', 1)
   3.119 +            k = k.strip()
   3.120 +            v = v.strip()
   3.121 +            if k not in ['policy','label']:
   3.122 +                err('Invalid access_control specifier: ' + access_control)
   3.123 +            d[k] = v
   3.124 +        access_controls.append(d)
   3.125 +        vals.access_control = access_controls
   3.126 +    elif num > 1:
   3.127 +        err('Multiple access_control definitions.')
   3.128 +
   3.129  def preprocess_ip(vals):
   3.130      if vals.ip or vals.dhcp != 'off':
   3.131          dummy_nfs_server = '1.2.3.4'
   3.132 @@ -785,6 +851,7 @@ def preprocess(vals):
   3.133      preprocess_nfs(vals)
   3.134      preprocess_vnc(vals)
   3.135      preprocess_vtpm(vals)
   3.136 +    preprocess_access_control(vals)
   3.137  
   3.138  
   3.139  def comma_sep_kv_to_dict(c):
     4.1 --- a/tools/python/xen/xm/main.py	Mon Apr 24 10:58:25 2006 +0100
     4.2 +++ b/tools/python/xen/xm/main.py	Mon Apr 24 10:59:17 2006 +0100
     4.3 @@ -40,6 +40,7 @@ from xen.xm.opts import *
     4.4  import console
     4.5  import xen.xend.XendClient
     4.6  from xen.xend.XendClient import server
     4.7 +from xen.util import security
     4.8  
     4.9  # getopt.gnu_getopt is better, but only exists in Python 2.3+.  Use
    4.10  # getopt.getopt if gnu_getopt is not available.  This will mean that options
    4.11 @@ -55,6 +56,8 @@ create_help =  """create [-c] <ConfigFil
    4.12  destroy_help = "destroy <DomId>                  Terminate a domain immediately"
    4.13  help_help =    "help                             Display this message"
    4.14  list_help =    "list [--long] [DomId, ...]       List information about domains"
    4.15 +list_label_help = "list [--label] [DomId, ...]      List information about domains including their labels"
    4.16 +
    4.17  mem_max_help = "mem-max <DomId> <Mem>            Set maximum memory reservation for a domain"
    4.18  mem_set_help = "mem-set <DomId> <Mem>            Adjust the current memory usage for a domain"
    4.19  migrate_help = "migrate <DomId> <Host>           Migrate a domain to another machine"
    4.20 @@ -114,6 +117,12 @@ vnet_list_help = "vnet-list [-l|--long] 
    4.21  vnet_create_help = "vnet-create <config>             create a vnet from a config file"
    4.22  vnet_delete_help = "vnet-delete <vnetid>             delete a vnet"
    4.23  vtpm_list_help = "vtpm-list <DomId> [--long]       list virtual TPM devices"
    4.24 +addlabel_help =  "addlabel <ConfigFile> <label>    Add security label to ConfigFile"
    4.25 +cfgbootpolicy_help = "cfgbootpolicy <policy>           Add policy to boot configuration "
    4.26 +dumppolicy_help = "dumppolicy                       Print hypervisor ACM state information"
    4.27 +loadpolicy_help = "loadpolicy <policy>              Load binary policy into hypervisor"
    4.28 +makepolicy_help = "makepolicy <policy>              Build policy and create .bin/.map files"
    4.29 +labels_help     = "labels [policy] [type=DOM|..]    List <type> labels for (active) policy."
    4.30  
    4.31  short_command_list = [
    4.32      "console",
    4.33 @@ -140,6 +149,7 @@ domain_commands = [
    4.34      "domid",
    4.35      "domname",
    4.36      "list",
    4.37 +    "list_label",
    4.38      "mem-max",
    4.39      "mem-set",
    4.40      "migrate",
    4.41 @@ -185,8 +195,17 @@ vnet_commands = [
    4.42      "vnet-delete",
    4.43      ]
    4.44  
    4.45 +acm_commands = [
    4.46 +    "labels",
    4.47 +    "addlabel",
    4.48 +    "makepolicy",
    4.49 +    "loadpolicy",
    4.50 +    "cfgbootpolicy",
    4.51 +    "dumppolicy"
    4.52 +    ]
    4.53 +
    4.54  all_commands = (domain_commands + host_commands + scheduler_commands +
    4.55 -                device_commands + vnet_commands)
    4.56 +                device_commands + vnet_commands + acm_commands)
    4.57  
    4.58  
    4.59  def commandToHelp(cmd):
    4.60 @@ -225,6 +244,9 @@ xm full list of subcommands:
    4.61    Vnet commands:
    4.62     """ + help_spacer.join(map(commandToHelp,  vnet_commands)) + """
    4.63  
    4.64 +  Access Control commands:
    4.65 +   """ + help_spacer.join(map(commandToHelp,  acm_commands)) + """
    4.66 +
    4.67  <DomName> can be substituted for <DomId> in xm subcommands.
    4.68  
    4.69  For a short list of subcommands run 'xm help'
    4.70 @@ -332,8 +354,9 @@ def getDomains(domain_names):
    4.71  def xm_list(args):
    4.72      use_long = 0
    4.73      show_vcpus = 0
    4.74 +    show_labels = 0
    4.75      try:
    4.76 -        (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus'])
    4.77 +        (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus','label'])
    4.78      except getopt.GetoptError, opterr:
    4.79          err(opterr)
    4.80          sys.exit(1)
    4.81 @@ -343,6 +366,8 @@ def xm_list(args):
    4.82              use_long = 1
    4.83          if k in ['-v', '--vcpus']:
    4.84              show_vcpus = 1
    4.85 +        if k in ['--label']:
    4.86 +            show_labels = 1
    4.87  
    4.88      if show_vcpus:
    4.89          print >>sys.stderr, (
    4.90 @@ -354,6 +379,8 @@ def xm_list(args):
    4.91  
    4.92      if use_long:
    4.93          map(PrettyPrint.prettyprint, doms)
    4.94 +    elif show_labels:
    4.95 +        xm_label_list(doms)
    4.96      else:
    4.97          xm_brief_list(doms)
    4.98  
    4.99 @@ -369,7 +396,7 @@ def parse_doms_info(info):
   4.100          'vcpus'    : get_info('online_vcpus', int,   0),
   4.101          'state'    : get_info('state',        str,   '??'),
   4.102          'cpu_time' : get_info('cpu_time',     float, 0),
   4.103 -        'ssidref'  : get_info('ssidref',      int,   0),
   4.104 +        'seclabel' : security.get_security_printlabel(info),
   4.105          }
   4.106  
   4.107  
   4.108 @@ -391,13 +418,29 @@ def xm_brief_list(doms):
   4.109      print 'Name                              ID Mem(MiB) VCPUs State  Time(s)'
   4.110      for dom in doms:
   4.111          d = parse_doms_info(dom)
   4.112 -        if (d['ssidref'] != 0):
   4.113 -            d['ssidstr'] = (" s:%04x/p:%04x" % 
   4.114 -                            ((d['ssidref'] >> 16) & 0xffff,
   4.115 -                              d['ssidref']        & 0xffff))
   4.116 +        print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f" % d)
   4.117 +
   4.118 +
   4.119 +def xm_label_list(doms):
   4.120 +    output = []
   4.121 +    print 'Name                              ID Mem(MiB) VCPUs State  Time(s)  Label'
   4.122 +    for dom in doms:
   4.123 +        d = parse_doms_info(dom)
   4.124 +        l = "%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f  " % d
   4.125 +        if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
   4.126 +            if d['seclabel']:
   4.127 +                line = (l, d['seclabel'])
   4.128 +            else:
   4.129 +                line = (l, "ERROR")
   4.130 +        elif security.active_policy in ['DEFAULT']:
   4.131 +            line = (l, "DEFAULT")
   4.132          else:
   4.133 -            d['ssidstr'] = ""
   4.134 -        print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f%(ssidstr)s" % d)
   4.135 +            line = (l, "INACTIVE")
   4.136 +        output.append(line)
   4.137 +    #sort by labels
   4.138 +    output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
   4.139 +    for l in output:
   4.140 +        print l[0] + l[1]
   4.141  
   4.142  
   4.143  def xm_vcpu_list(args):
   4.144 @@ -1010,7 +1053,13 @@ subcommands = [
   4.145      'create',
   4.146      'migrate',
   4.147      'sysrq',
   4.148 -    'shutdown'
   4.149 +    'shutdown',
   4.150 +    'labels',
   4.151 +    'addlabel',
   4.152 +    'cfgbootpolicy',
   4.153 +    'makepolicy',
   4.154 +    'loadpolicy',
   4.155 +    'dumppolicy'
   4.156      ]
   4.157  
   4.158  for c in subcommands: