1#!/usr/bin/python3 -Es 2# Copyright (C) 2012-2013 Red Hat 3# AUTHOR: Miroslav Grepl <mgrepl@redhat.com> 4# AUTHOR: David Quigley <selinux@davequigley.com> 5# see file 'COPYING' for use and warranty information 6# 7# semanage is a tool for managing SELinux configuration files 8# 9# This program is free software; you can redistribute it and/or 10# modify it under the terms of the GNU General Public License as 11# published by the Free Software Foundation; either version 2 of 12# the License, or (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program; if not, write to the Free Software 21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 22# 02111-1307 USA 23# 24# 25 26import traceback 27import argparse 28import seobject 29import sys 30PROGNAME = "policycoreutils" 31try: 32 import gettext 33 kwargs = {} 34 if sys.version_info < (3,): 35 kwargs['unicode'] = True 36 gettext.install(PROGNAME, 37 localedir="/usr/share/locale", 38 codeset='utf-8', 39 **kwargs) 40except: 41 try: 42 import builtins 43 builtins.__dict__['_'] = str 44 except ImportError: 45 import __builtin__ 46 __builtin__.__dict__['_'] = unicode 47 48# define custom usages for selected main actions 49usage_login = "semanage login [-h] [-n] [-N] [-S STORE] [" 50usage_login_dict = {' --add': ('-s SEUSER', '-r RANGE', 'LOGIN',), ' --modify': ('-s SEUSER', '-r RANGE', 'LOGIN',), ' --delete': ('LOGIN',), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 51 52usage_fcontext = "semanage fcontext [-h] [-n] [-N] [-S STORE] [" 53usage_fcontext_dict = {' --add': ('(', '-t TYPE', '-f FTYPE', '-r RANGE', '-s SEUSER', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --delete': ('(', '-t TYPE', '-f FTYPE', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --modify': ('(', '-t TYPE', '-f FTYPE', '-r RANGE', '-s SEUSER', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --list': ('[-C]',), ' --extract': ('',), ' --deleteall': ('',)} 54 55usage_user = "semanage user [-h] [-n] [-N] [-S STORE] [" 56usage_user_dict = {' --add': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', 'SEUSER', ')'), ' --delete': ('SEUSER',), ' --modify': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'SEUSER', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 57 58usage_port = "semanage port [-h] [-n] [-N] [-S STORE] [" 59usage_port_dict = {' --add': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --modify': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --delete': ('-p PROTOCOL', '(', 'port_name', '|', 'port_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 60 61usage_ibpkey = "semanage ibpkey [-h] [-n] [-N] [-s STORE] [" 62usage_ibpkey_dict = {' --add': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --modify': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --delete': ('-x SUBNET_PREFIX', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 63 64usage_ibendport = "semanage ibendport [-h] [-n] [-N] [-s STORE] [" 65usage_ibendport_dict = {' --add': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --modify': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --delete': ('-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 66 67usage_node = "semanage node [-h] [-n] [-N] [-S STORE] [" 68usage_node_dict = {' --add': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --modify': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --delete': ('-M NETMASK', '-p PROTOCOL', 'node'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 69 70usage_interface = "semanage interface [-h] [-n] [-N] [-S STORE] [" 71usage_interface_dict = {' --add': ('-t TYPE', '-r RANGE', 'interface'), ' --modify': ('-t TYPE', '-r RANGE', 'interface'), ' --delete': ('interface',), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 72 73usage_boolean = "semanage boolean [-h] [-n] [-N] [-S STORE] [" 74usage_boolean_dict = {' --modify': ('(', '--on', '|', '--off', ')', 'boolean'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)} 75 76 77 78 79class CheckRole(argparse.Action): 80 81 def __call__(self, parser, namespace, value, option_string=None): 82 newval = getattr(namespace, self.dest) 83 if not newval: 84 newval = [] 85 try: 86 # sepolicy tries to load the SELinux policy and raises ValueError if it fails. 87 import sepolicy 88 roles = sepolicy.get_all_roles() 89 except ValueError: 90 roles = [] 91 for v in value.split(): 92 if v not in roles: 93 raise ValueError("%s must be an SELinux role:\nValid roles: %s" % (v, ", ".join(roles))) 94 newval.append(v) 95 setattr(namespace, self.dest, newval) 96 97 98class seParser(argparse.ArgumentParser): 99 100 def error(self, message): 101 if len(sys.argv) == 2: 102 self.print_help() 103 else: 104 self.print_usage() 105 self.exit(2, ('%s: error: %s\n') % (self.prog, message)) 106 107 108class SetExportFile(argparse.Action): 109 110 def __call__(self, parser, namespace, values, option_string=None): 111 if values: 112 if values != "-": 113 try: 114 sys.stdout = open(values, 'w') 115 except: 116 sys.stderr.write(traceback.format_exc()) 117 sys.exit(1) 118 setattr(namespace, self.dest, values) 119 120 121class SetImportFile(argparse.Action): 122 123 def __call__(self, parser, namespace, values, option_string=None): 124 if values and values != "-": 125 try: 126 sys.stdin = open(values, 'r') 127 except IOError as e: 128 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) 129 sys.exit(1) 130 setattr(namespace, self.dest, values) 131 132# define dictonary for seobject OBEJCTS 133object_dict = { 134 'login': seobject.loginRecords, 135 'user': seobject.seluserRecords, 136 'port': seobject.portRecords, 137 'module': seobject.moduleRecords, 138 'interface': seobject.interfaceRecords, 139 'node': seobject.nodeRecords, 140 'fcontext': seobject.fcontextRecords, 141 'boolean': seobject.booleanRecords, 142 'permissive': seobject.permissiveRecords, 143 'dontaudit': seobject.dontauditClass, 144 'ibpkey': seobject.ibpkeyRecords, 145 'ibendport': seobject.ibendportRecords 146} 147 148def generate_custom_usage(usage_text, usage_dict): 149 # generate custom usage from given text and dictonary 150 sorted_keys = [] 151 for i in usage_dict.keys(): 152 sorted_keys.append(i) 153 sorted_keys.sort() 154 for k in sorted_keys: 155 usage_text += "%s %s |" % (k, (" ".join(usage_dict[k]))) 156 usage_text = usage_text[:-1] + "]" 157 usage_text = _(usage_text) 158 159 return usage_text 160 161 162def handle_opts(args, dict, target_key): 163 # handle conflict and required options for given dictonary 164 # {action:[conflict_opts,require_opts]} 165 166 # first we need to catch conflicts 167 for k in args.__dict__.keys(): 168 try: 169 if k in dict[target_key][0] and args.__dict__[k]: 170 print("%s option can not be used with --%s" % (target_key, k)) 171 sys.exit(2) 172 except KeyError: 173 continue 174 175 for k in args.__dict__.keys(): 176 try: 177 if k in dict[target_key][1] and not args.__dict__[k]: 178 print("%s option is needed for %s" % (k, target_key)) 179 sys.exit(2) 180 except KeyError: 181 continue 182 183 184def handleLogin(args): 185 # {action:[conflict_opts,require_opts]} 186 login_args = {'list': [('login', 'seuser'), ('')], 'add': [('locallist'), ('seuser', 'login')], 'modify': [('locallist'), ('login')], 'delete': [('locallist'), ('login')], 'extract': [('locallist', 'login', 'seuser'), ('')], 'deleteall': [('locallist'), ('')]} 187 188 handle_opts(args, login_args, args.action) 189 190 OBJECT = object_dict['login'](args) 191 192 if args.action == "add": 193 OBJECT.add(args.login, args.seuser, args.range) 194 if args.action == "modify": 195 OBJECT.modify(args.login, args.seuser, args.range) 196 if args.action == "delete": 197 OBJECT.delete(args.login) 198 if args.action == "list": 199 OBJECT.list(args.noheading, args.locallist) 200 if args.action == "deleteall": 201 OBJECT.deleteall() 202 if args.action == "extract": 203 for i in OBJECT.customized(): 204 print("login %s" % (str(i))) 205 206 207def parser_add_store(parser, name): 208 parser.add_argument('-S', '--store', default='', help=_("Select an alternate SELinux Policy Store to manage")) 209 210 211def parser_add_priority(parser, name): 212 parser.add_argument('-P', '--priority', type=int, default=400, help=_("Select a priority for module operations")) 213 214 215def parser_add_noheading(parser, name): 216 parser.add_argument('-n', '--noheading', action='store_false', default=True, help=_("Do not print heading when listing %s object types") % name) 217 218 219def parser_add_noreload(parser, name): 220 parser.add_argument('-N', '--noreload', action='store_true', default=False, help=_('Do not reload policy after commit')) 221 222 223def parser_add_locallist(parser, name): 224 parser.add_argument('-C', '--locallist', action='store_true', default=False, help=_("List %s local customizations") % name) 225 226 227def parser_add_add(parser, name): 228 parser.add_argument('-a', '--add', dest='action', action='store_const', const='add', help=_("Add a record of the %s object type") % name) 229 230 231def parser_add_type(parser, name): 232 parser.add_argument('-t', '--type', help=_('SELinux Type for the object')) 233 234 235def parser_add_level(parser, name): 236 parser.add_argument('-L', '--level', default='s0', help=_('Default SELinux Level for SELinux user, s0 Default. (MLS/MCS Systems only)')) 237 238 239def parser_add_range(parser, name): 240 parser.add_argument('-r', '--range', default="s0", 241 help=_(''' 242MLS/MCS Security Range (MLS/MCS Systems only) 243SELinux Range for SELinux login mapping 244defaults to the SELinux user record range. 245SELinux Range for SELinux user defaults to s0. 246''')) 247 248 249def parser_add_proto(parser, name): 250 parser.add_argument('-p', '--proto', help=_(''' 251 Protocol for the specified port (tcp|udp) or internet protocol 252 version for the specified node (ipv4|ipv6). 253''')) 254 255def parser_add_subnet_prefix(parser, name): 256 parser.add_argument('-x', '--subnet_prefix', help=_(''' 257 Subnet prefix for the specified infiniband ibpkey. 258''')) 259 260def parser_add_ibdev_name(parser, name): 261 parser.add_argument('-z', '--ibdev_name', help=_(''' 262 Name for the specified infiniband end port. 263''')) 264 265def parser_add_modify(parser, name): 266 parser.add_argument('-m', '--modify', dest='action', action='store_const', const='modify', help=_("Modify a record of the %s object type") % name) 267 268 269def parser_add_list(parser, name): 270 parser.add_argument('-l', '--list', dest='action', action='store_const', const='list', help=_("List records of the %s object type") % name) 271 272 273def parser_add_delete(parser, name): 274 parser.add_argument('-d', '--delete', dest='action', action='store_const', const='delete', help=_("Delete a record of the %s object type") % name) 275 276 277def parser_add_extract(parser, name): 278 parser.add_argument('-E', '--extract', dest='action', action='store_const', const='extract', help=_("Extract customizable commands, for use within a transaction")) 279 280 281def parser_add_deleteall(parser, name): 282 parser.add_argument('-D', '--deleteall', dest='action', action='store_const', const='deleteall', help=_('Remove all %s objects local customizations') % name) 283 284 285def parser_add_seuser(parser, name): 286 parser.add_argument('-s', '--seuser', default="", help=_("SELinux user name")) 287 288 289def setupLoginParser(subparsers): 290 generated_usage = generate_custom_usage(usage_login, usage_login_dict) 291 loginParser = subparsers.add_parser('login', usage=generated_usage, help=_("Manage login mappings between linux users and SELinux confined users")) 292 parser_add_locallist(loginParser, "login") 293 parser_add_noheading(loginParser, "login") 294 parser_add_noreload(loginParser, "login") 295 parser_add_store(loginParser, "login") 296 parser_add_range(loginParser, "login") 297 298 login_action = loginParser.add_mutually_exclusive_group(required=True) 299 300 parser_add_add(login_action, "login") 301 parser_add_delete(login_action, "login") 302 parser_add_modify(login_action, "login") 303 parser_add_list(login_action, "login") 304 parser_add_extract(login_action, "login") 305 parser_add_deleteall(login_action, "login") 306 parser_add_seuser(loginParser, "login") 307 308 loginParser.add_argument('login', nargs='?', default=None, help=_("login_name | %%groupname")) 309 310 loginParser.set_defaults(func=handleLogin) 311 312 313def handleFcontext(args): 314 fcontext_args = {'list': [('equal', 'ftype', 'seuser', 'type'), ('')], 'add': [('locallist'), ('type', 'file_spec')], 'modify': [('locallist'), ('type', 'file_spec')], 'delete': [('locallist'), ('file_spec')], 'extract': [('locallist', 'equal', 'ftype', 'seuser', 'type'), ('')], 'deleteall': [('locallist'), ('')]} 315 # we can not use mutually for equal because we can define some actions together with equal 316 fcontext_equal_args = {'equal': [('list', 'locallist', 'type', 'ftype', 'seuser', 'deleteall', 'extract'), ()]} 317 318 if args.action and args.equal: 319 handle_opts(args, fcontext_equal_args, "equal") 320 else: 321 handle_opts(args, fcontext_args, args.action) 322 323 OBJECT = object_dict['fcontext'](args) 324 325 if args.action == "add": 326 if args.equal: 327 OBJECT.add_equal(args.file_spec, args.equal) 328 else: 329 OBJECT.add(args.file_spec, args.type, args.ftype, args.range, args.seuser) 330 if args.action == "modify": 331 if args.equal: 332 OBJECT.add_equal(args.file_spec, args.equal) 333 else: 334 OBJECT.modify(args.file_spec, args.type, args.ftype, args.range, args.seuser) 335 if args.action == "delete": 336 if args.equal: 337 OBJECT.delete(args.file_spec, args.equal) 338 else: 339 OBJECT.delete(args.file_spec, args.ftype) 340 if args.action == "list": 341 OBJECT.list(args.noheading, args.locallist) 342 if args.action == "deleteall": 343 OBJECT.deleteall() 344 if args.action == "extract": 345 for i in OBJECT.customized(): 346 print("fcontext %s" % str(i)) 347 348 349def setupFcontextParser(subparsers): 350 ftype_help = ''' 351File Type. This is used with fcontext. Requires a file type 352as shown in the mode field by ls, e.g. use d to match only 353directories or f to match only regular files. The following 354file type options can be passed: 355f (regular file),d (directory),c (character device), 356b (block device),s (socket),l (symbolic link),p (named pipe) 357If you do not specify a file type, the file type will default to "all files". 358''' 359 generate_usage = generate_custom_usage(usage_fcontext, usage_fcontext_dict) 360 fcontextParser = subparsers.add_parser('fcontext', usage=generate_usage, help=_("Manage file context mapping definitions")) 361 parser_add_locallist(fcontextParser, "fcontext") 362 parser_add_noheading(fcontextParser, "fcontext") 363 parser_add_noreload(fcontextParser, "fcontext") 364 parser_add_store(fcontextParser, "fcontext") 365 366 fcontext_action = fcontextParser.add_mutually_exclusive_group(required=True) 367 parser_add_add(fcontext_action, "fcontext") 368 parser_add_delete(fcontext_action, "fcontext") 369 parser_add_modify(fcontext_action, "fcontext") 370 parser_add_list(fcontext_action, "fcontext") 371 parser_add_extract(fcontext_action, "fcontext") 372 parser_add_deleteall(fcontext_action, "fcontext") 373 374 fcontextParser.add_argument('-e', '--equal', help=_('''Substitute target path with sourcepath when generating default 375 label. This is used with fcontext. Requires source and target 376 path arguments. The context labeling for the target subtree is 377 made equivalent to that defined for the source.''')) 378 fcontextParser.add_argument('-f', '--ftype', default="", choices=["a", "f", "d", "c", "b", "s", "l", "p"], help=_(ftype_help)) 379 parser_add_seuser(fcontextParser, "fcontext") 380 parser_add_type(fcontextParser, "fcontext") 381 parser_add_range(fcontextParser, "fcontext") 382 fcontextParser.add_argument('file_spec', nargs='?', default=None, help=_('file_spec')) 383 fcontextParser.set_defaults(func=handleFcontext) 384 385 386def handleUser(args): 387 user_args = {'list': [('selinux_name', 'seuser', 'roles'), ('')], 'add': [('locallist'), ('roles', 'selinux_name')], 'modify': [('locallist'), ('selinux_name')], 'delete': [('locallist'), ('selinux_name')], 'extract': [('locallist', 'selinux_name', 'seuser', 'role'), ('')], 'deleteall': [('locallist'), ('')]} 388 389 handle_opts(args, user_args, args.action) 390 391 OBJECT = object_dict['user'](args) 392 393 if args.action == "add": 394 OBJECT.add(args.selinux_name, args.roles, args.level, args.range, args.prefix) 395 if args.action == "modify": 396 OBJECT.modify(args.selinux_name, args.roles, args.level, args.range, args.prefix) 397 if args.action == "delete": 398 OBJECT.delete(args.selinux_name) 399 if args.action == "list": 400 OBJECT.list(args.noheading, args.locallist) 401 if args.action == "deleteall": 402 OBJECT.deleteall() 403 if args.action == "extract": 404 for i in OBJECT.customized(): 405 print("user %s" % str(i)) 406 407 408def setupUserParser(subparsers): 409 generated_usage = generate_custom_usage(usage_user, usage_user_dict) 410 userParser = subparsers.add_parser('user', usage=generated_usage, help=_('Manage SELinux confined users (Roles and levels for an SELinux user)')) 411 parser_add_locallist(userParser, "user") 412 parser_add_noheading(userParser, "user") 413 parser_add_noreload(userParser, "user") 414 parser_add_store(userParser, "user") 415 416 user_action = userParser.add_mutually_exclusive_group(required=True) 417 parser_add_add(user_action, "user") 418 parser_add_delete(user_action, "user") 419 parser_add_modify(user_action, "user") 420 parser_add_list(user_action, "user") 421 parser_add_extract(user_action, "user") 422 parser_add_deleteall(user_action, "user") 423 424 parser_add_level(userParser, "user") 425 parser_add_range(userParser, "user") 426 userParser.add_argument('-R', '--roles', default=[], 427 action=CheckRole, 428 help=_(''' 429SELinux Roles. You must enclose multiple roles within quotes, separate by spaces. Or specify -R multiple times. 430''')) 431 userParser.add_argument('-P', '--prefix', default="user", help=argparse.SUPPRESS) 432 userParser.add_argument('selinux_name', nargs='?', default=None, help=_('selinux_name')) 433 userParser.set_defaults(func=handleUser) 434 435 436def handlePort(args): 437 port_args = {'list': [('port', 'type', 'proto'), ('')], 'add': [('locallist'), ('type', 'port', 'proto')], 'modify': [('localist'), ('port', 'proto')], 'delete': [('locallist'), ('port', 'proto')], 'extract': [('locallist', 'port', 'type', 'proto'), ('')], 'deleteall': [('locallist'), ('')]} 438 439 handle_opts(args, port_args, args.action) 440 441 OBJECT = object_dict['port'](args) 442 443 if args.action == "add": 444 OBJECT.add(args.port, args.proto, args.range, args.type) 445 if args.action == "modify": 446 OBJECT.modify(args.port, args.proto, args.range, args.type) 447 if args.action == "delete": 448 OBJECT.delete(args.port, args.proto) 449 if args.action == "list": 450 OBJECT.list(args.noheading, args.locallist) 451 if args.action == "deleteall": 452 OBJECT.deleteall() 453 if args.action == "extract": 454 for i in OBJECT.customized(): 455 print("port %s" % str(i)) 456 457 458def setupPortParser(subparsers): 459 generated_usage = generate_custom_usage(usage_port, usage_port_dict) 460 portParser = subparsers.add_parser('port', usage=generated_usage, help=_('Manage network port type definitions')) 461 parser_add_locallist(portParser, "port") 462 parser_add_noheading(portParser, "port") 463 parser_add_noreload(portParser, "port") 464 parser_add_store(portParser, "port") 465 466 port_action = portParser.add_mutually_exclusive_group(required=True) 467 parser_add_add(port_action, "port") 468 parser_add_delete(port_action, "port") 469 parser_add_modify(port_action, "port") 470 parser_add_list(port_action, "port") 471 parser_add_extract(port_action, "port") 472 parser_add_deleteall(port_action, "port") 473 parser_add_type(portParser, "port") 474 parser_add_range(portParser, "port") 475 parser_add_proto(portParser, "port") 476 portParser.add_argument('port', nargs='?', default=None, help=_('port | port_range')) 477 portParser.set_defaults(func=handlePort) 478 479 480 481def handlePkey(args): 482 ibpkey_args = {'list': [('ibpkey', 'type', 'subnet_prefix'), ('')], 'add': [('locallist'), ('type', 'ibpkey', 'subnet_prefix')], 'modify': [('localist'), ('ibpkey', 'subnet_prefix')], 'delete': [('locallist'), ('ibpkey', 'subnet_prefix')], 'extract': [('locallist', 'ibpkey', 'type', 'subnet prefix'), ('')], 'deleteall': [('locallist'), ('')]} 483 484 handle_opts(args, ibpkey_args, args.action) 485 486 OBJECT = object_dict['ibpkey'](args) 487 488 if args.action == "add": 489 OBJECT.add(args.ibpkey, args.subnet_prefix, args.range, args.type) 490 if args.action == "modify": 491 OBJECT.modify(args.ibpkey, args.subnet_prefix, args.range, args.type) 492 if args.action == "delete": 493 OBJECT.delete(args.ibpkey, args.subnet_prefix) 494 if args.action == "list": 495 OBJECT.list(args.noheading, args.locallist) 496 if args.action == "deleteall": 497 OBJECT.deleteall() 498 if args.action == "extract": 499 for i in OBJECT.customized(): 500 print("ibpkey %s" % str(i)) 501 502 503def setupPkeyParser(subparsers): 504 generated_usage = generate_custom_usage(usage_ibpkey, usage_ibpkey_dict) 505 ibpkeyParser = subparsers.add_parser('ibpkey', usage=generated_usage, help=_('Manage infiniband ibpkey type definitions')) 506 parser_add_locallist(ibpkeyParser, "ibpkey") 507 parser_add_noheading(ibpkeyParser, "ibpkey") 508 parser_add_noreload(ibpkeyParser, "ibpkey") 509 parser_add_store(ibpkeyParser, "ibpkey") 510 511 ibpkey_action = ibpkeyParser.add_mutually_exclusive_group(required=True) 512 parser_add_add(ibpkey_action, "ibpkey") 513 parser_add_delete(ibpkey_action, "ibpkey") 514 parser_add_modify(ibpkey_action, "ibpkey") 515 parser_add_list(ibpkey_action, "ibpkey") 516 parser_add_extract(ibpkey_action, "ibpkey") 517 parser_add_deleteall(ibpkey_action, "ibpkey") 518 parser_add_type(ibpkeyParser, "ibpkey") 519 parser_add_range(ibpkeyParser, "ibpkey") 520 parser_add_subnet_prefix(ibpkeyParser, "ibpkey") 521 ibpkeyParser.add_argument('ibpkey', nargs='?', default=None, help=_('pkey | pkey_range')) 522 ibpkeyParser.set_defaults(func=handlePkey) 523 524def handleIbendport(args): 525 ibendport_args = {'list': [('ibendport', 'type', 'ibdev_name'), ('')], 'add': [('locallist'), ('type', 'ibendport', 'ibdev_name'), ('')], 'modify': [('localist'), ('ibendport', 'ibdev_name')], 'delete': [('locallist'), ('ibendport', 'ibdev_name')], 'extract': [('locallist', 'ibendport', 'type', 'ibdev_name'), ('')], 'deleteall': [('locallist'), ('')]} 526 527 handle_opts(args, ibendport_args, args.action) 528 529 OBJECT = object_dict['ibendport'](args) 530 531 if args.action == "add": 532 OBJECT.add(args.ibendport, args.ibdev_name, args.range, args.type) 533 if args.action == "modify": 534 OBJECT.modify(args.ibendport, args.ibdev_name, args.range, args.type) 535 if args.action == "delete": 536 OBJECT.delete(args.ibendport, args.ibdev_name) 537 if args.action == "list": 538 OBJECT.list(args.noheading, args.locallist) 539 if args.action == "deleteall": 540 OBJECT.deleteall() 541 if args.action == "extract": 542 for i in OBJECT.customized(): 543 print("ibendport %s" % str(i)) 544 545 546def setupIbendportParser(subparsers): 547 generated_usage = generate_custom_usage(usage_ibendport, usage_ibendport_dict) 548 ibendportParser = subparsers.add_parser('ibendport', usage=generated_usage, help=_('Manage infiniband end port type definitions')) 549 parser_add_locallist(ibendportParser, "ibendport") 550 parser_add_noheading(ibendportParser, "ibendport") 551 parser_add_noreload(ibendportParser, "ibendport") 552 parser_add_store(ibendportParser, "ibendport") 553 554 ibendport_action = ibendportParser.add_mutually_exclusive_group(required=True) 555 parser_add_add(ibendport_action, "ibendport") 556 parser_add_delete(ibendport_action, "ibendport") 557 parser_add_modify(ibendport_action, "ibendport") 558 parser_add_list(ibendport_action, "ibendport") 559 parser_add_extract(ibendport_action, "ibendport") 560 parser_add_deleteall(ibendport_action, "ibendport") 561 parser_add_type(ibendportParser, "ibendport") 562 parser_add_range(ibendportParser, "ibendport") 563 parser_add_ibdev_name(ibendportParser, "ibendport") 564 ibendportParser.add_argument('ibendport', nargs='?', default=None, help=_('ibendport')) 565 ibendportParser.set_defaults(func=handleIbendport) 566 567def handleInterface(args): 568 interface_args = {'list': [('interface'), ('')], 'add': [('locallist'), ('type', 'interface')], 'modify': [('locallist'), ('type', 'interface')], 'delete': [('locallist'), ('interface')], 'extract': [('locallist', 'interface', 'type'), ('')], 'deleteall': [('locallist'), ('')]} 569 570 handle_opts(args, interface_args, args.action) 571 572 OBJECT = object_dict['interface'](args) 573 574 if args.action == "add": 575 OBJECT.add(args.interface, args.range, args.type) 576 if args.action == "modify": 577 OBJECT.modify(args.interface, args.range, args.type) 578 if args.action == "delete": 579 OBJECT.delete(args.interface) 580 if args.action == "list": 581 OBJECT.list(args.noheading, args.locallist) 582 if args.action == "deleteall": 583 OBJECT.deleteall() 584 if args.action == "extract": 585 for i in OBJECT.customized(): 586 print("interface %s" % str(i)) 587 588 589def setupInterfaceParser(subparsers): 590 generated_usage = generate_custom_usage(usage_interface, usage_interface_dict) 591 interfaceParser = subparsers.add_parser('interface', usage=generated_usage, help=_('Manage network interface type definitions')) 592 parser_add_locallist(interfaceParser, "interface") 593 parser_add_noheading(interfaceParser, "interface") 594 parser_add_noreload(interfaceParser, "interface") 595 parser_add_store(interfaceParser, "interface") 596 parser_add_type(interfaceParser, "interface") 597 parser_add_range(interfaceParser, "interface") 598 599 interface_action = interfaceParser.add_mutually_exclusive_group(required=True) 600 parser_add_add(interface_action, "interface") 601 parser_add_delete(interface_action, "interface") 602 parser_add_modify(interface_action, "interface") 603 parser_add_list(interface_action, "interface") 604 parser_add_extract(interface_action, "interface") 605 parser_add_deleteall(interface_action, "interface") 606 interfaceParser.add_argument('interface', nargs='?', default=None, help=_('interface_spec')) 607 interfaceParser.set_defaults(func=handleInterface) 608 609 610def handleModule(args): 611 OBJECT = seobject.moduleRecords(args) 612 if args.action_add: 613 OBJECT.add(args.action_add[0], args.priority) 614 if args.action_enable: 615 OBJECT.set_enabled(" ".join(args.action_enable), True) 616 if args.action_disable: 617 OBJECT.set_enabled(" ".join(args.action_disable), False) 618 if args.action_remove: 619 OBJECT.delete(" ".join(args.action_remove), args.priority) 620 if args.action == "deleteall": 621 OBJECT.deleteall() 622 if args.action == "list": 623 OBJECT.list(args.noheading, args.locallist) 624 if args.action == "extract": 625 for i in OBJECT.customized(): 626 print("module %s" % str(i)) 627 628 629def setupModuleParser(subparsers): 630 moduleParser = subparsers.add_parser('module', help=_('Manage SELinux policy modules')) 631 parser_add_noheading(moduleParser, "module") 632 parser_add_noreload(moduleParser, "module") 633 parser_add_store(moduleParser, "module") 634 parser_add_locallist(moduleParser, "module") 635 parser_add_priority(moduleParser, "module") 636 637 mgroup = moduleParser.add_mutually_exclusive_group(required=True) 638 parser_add_list(mgroup, "module") 639 parser_add_extract(mgroup, "module") 640 parser_add_deleteall(mgroup, "module") 641 mgroup.add_argument('-a', '--add', dest='action_add', action='store', nargs=1, metavar='module_name', help=_("Add a module")) 642 mgroup.add_argument('-r', '--remove', dest='action_remove', action='store', nargs='+', metavar='module_name', help=_("Remove a module")) 643 mgroup.add_argument('-d', '--disable', dest='action_disable', action='store', nargs='+', metavar='module_name', help=_("Disable a module")) 644 mgroup.add_argument('-e', '--enable', dest='action_enable', action='store', nargs='+', metavar='module_name', help=_("Enable a module")) 645 moduleParser.set_defaults(func=handleModule) 646 647 648def handleNode(args): 649 node_args = {'list': [('node', 'type', 'proto', 'netmask'), ('')], 'add': [('locallist'), ('type', 'node', 'proto', 'netmask')], 'modify': [('locallist'), ('node', 'netmask', 'proto')], 'delete': [('locallist'), ('node', 'netmask', 'prototype')], 'extract': [('locallist', 'node', 'type', 'proto', 'netmask'), ('')], 'deleteall': [('locallist'), ('')]} 650 handle_opts(args, node_args, args.action) 651 652 OBJECT = object_dict['node'](args) 653 654 if args.action == "add": 655 OBJECT.add(args.node, args.netmask, args.proto, args.range, args.type) 656 if args.action == "modify": 657 OBJECT.modify(args.node, args.netmask, args.proto, args.range, args.type) 658 if args.action == "delete": 659 OBJECT.delete(args.node, args.netmask, args.proto) 660 if args.action == "list": 661 OBJECT.list(args.noheading, args.locallist) 662 if args.action == "deleteall": 663 OBJECT.deleteall() 664 if args.action == "extract": 665 for i in OBJECT.customized(): 666 print("node %s" % str(i)) 667 668 669def setupNodeParser(subparsers): 670 generated_usage = generate_custom_usage(usage_node, usage_node_dict) 671 nodeParser = subparsers.add_parser('node', usage=generated_usage, help=_('Manage network node type definitions')) 672 parser_add_locallist(nodeParser, "node") 673 parser_add_noheading(nodeParser, "node") 674 parser_add_noreload(nodeParser, "node") 675 parser_add_store(nodeParser, "node") 676 677 node_action = nodeParser.add_mutually_exclusive_group(required=True) 678 parser_add_add(node_action, "node") 679 parser_add_delete(node_action, "node") 680 parser_add_modify(node_action, "node") 681 parser_add_list(node_action, "node") 682 parser_add_extract(node_action, "node") 683 parser_add_deleteall(node_action, "node") 684 685 nodeParser.add_argument('-M', '--netmask', help=_('Network Mask')) 686 parser_add_type(nodeParser, "node") 687 parser_add_range(nodeParser, "node") 688 parser_add_proto(nodeParser, "node") 689 nodeParser.add_argument('node', nargs='?', default=None, help=_('node')) 690 nodeParser.set_defaults(func=handleNode) 691 692 693def handleBoolean(args): 694 boolean_args = {'list': [('state', 'boolean'), ('')], 'modify': [('localist'), ('boolean', 'state')], 'extract': [('locallist', 'state', 'boolean'), ('')], 'deleteall': [('locallist'), ('')], 'state': [('locallist', 'list', 'extract', 'deleteall'), ('modify')]} 695 696 handle_opts(args, boolean_args, args.action) 697 698 OBJECT = object_dict['boolean'](args) 699 700 if args.action == "modify": 701 if args.boolean: 702 OBJECT.modify(args.boolean, args.state, False) 703 if args.action == "list": 704 OBJECT.list(args.noheading, args.locallist) 705 if args.action == "deleteall": 706 OBJECT.deleteall() 707 if args.action == "extract": 708 for i in OBJECT.customized(): 709 print("boolean %s" % str(i)) 710 711 712def setupBooleanParser(subparsers): 713 generated_usage = generate_custom_usage(usage_boolean, usage_boolean_dict) 714 booleanParser = subparsers.add_parser('boolean', usage=generated_usage, help=_('Manage booleans to selectively enable functionality')) 715 parser_add_locallist(booleanParser, "boolean") 716 parser_add_noheading(booleanParser, "boolean") 717 parser_add_noreload(booleanParser, "boolean") 718 parser_add_store(booleanParser, "boolean") 719 booleanParser.add_argument('boolean', nargs="?", default=None, help=_('boolean')) 720 721 boolean_action = booleanParser.add_mutually_exclusive_group(required=True) 722 #add_add(boolean_action) 723 parser_add_modify(boolean_action, "boolean") 724 parser_add_list(boolean_action, "boolean") 725 parser_add_extract(boolean_action, "boolean") 726 parser_add_deleteall(boolean_action, "boolean") 727 728 booleanGroup = booleanParser.add_mutually_exclusive_group(required=False) 729 booleanGroup.add_argument('-1', '--on', dest='state', action='store_const', const='on', help=_('Enable the boolean')) 730 booleanGroup.add_argument('-0', '--off', dest='state', action='store_const', const='off', help=_('Disable the boolean')) 731 732 booleanParser.set_defaults(func=handleBoolean) 733 734 735def handlePermissive(args): 736 OBJECT = object_dict['permissive'](args) 737 738 if args.action == "list": 739 OBJECT.list(args.noheading) 740 elif args.type is not None: 741 if args.action == "add": 742 OBJECT.add(args.type) 743 if args.action == "delete": 744 OBJECT.delete(args.type) 745 else: 746 args.parser.error(message=_('semanage permissive: error: the following argument is required: type\n')) 747 748 749def setupPermissiveParser(subparsers): 750 permissiveParser = subparsers.add_parser('permissive', help=_('Manage process type enforcement mode')) 751 752 pgroup = permissiveParser.add_mutually_exclusive_group(required=True) 753 parser_add_add(pgroup, "permissive") 754 parser_add_delete(pgroup, "permissive") 755 parser_add_list(pgroup, "permissive") 756 #TODO: probably should be also added => need to implement own option handling 757 #parser_add_deleteall(pgroup) 758 759 parser_add_noheading(permissiveParser, "permissive") 760 parser_add_noreload(permissiveParser, "permissive") 761 parser_add_store(permissiveParser, "permissive") 762 permissiveParser.add_argument('type', nargs='?', default=None, help=_('type')) 763 permissiveParser.set_defaults(func=handlePermissive) 764 permissiveParser.set_defaults(parser=permissiveParser) 765 766 767def handleDontaudit(args): 768 OBJECT = object_dict['dontaudit'](args) 769 OBJECT.toggle(args.action) 770 771 772def setupDontauditParser(subparsers): 773 dontauditParser = subparsers.add_parser('dontaudit', help=_('Disable/Enable dontaudit rules in policy')) 774 parser_add_noreload(dontauditParser, "dontaudit") 775 parser_add_store(dontauditParser, "dontaudit") 776 dontauditParser.add_argument('action', choices=["on", "off"]) 777 dontauditParser.set_defaults(func=handleDontaudit) 778 779 780def handleExport(args): 781 manageditems = ["boolean", "login", "interface", "user", "port", "node", "fcontext", "module", "ibendport", "ibpkey"] 782 for i in manageditems: 783 print("%s -D" % i) 784 for i in manageditems: 785 OBJECT = object_dict[i](args) 786 for c in OBJECT.customized(): 787 print("%s %s" % (i, str(c))) 788 789 sys.exit(0) 790 791 792def setupExportParser(subparsers): 793 exportParser = subparsers.add_parser('export', help=_('Output local customizations')) 794 parser_add_store(exportParser, "export") 795 exportParser.add_argument('-f', '--output_file', dest='output_file', action=SetExportFile, help=_('Output file')) 796 exportParser.set_defaults(func=handleExport) 797 798import re 799 800 801def mkargv(line): 802 dquote = "\"" 803 squote = "\'" 804 l = line.split() 805 ret = [] 806 i = 0 807 while i < len(l): 808 cnt = len(re.findall(dquote, l[i])) 809 if cnt > 1: 810 ret.append(l[i].strip(dquote)) 811 i = i + 1 812 continue 813 if cnt == 1: 814 quote = [l[i].strip(dquote)] 815 i = i + 1 816 817 while i < len(l) and dquote not in l[i]: 818 quote.append(l[i]) 819 i = i + 1 820 quote.append(l[i].strip(dquote)) 821 ret.append(" ".join(quote)) 822 i = i + 1 823 continue 824 825 cnt = len(re.findall(squote, l[i])) 826 if cnt > 1: 827 ret.append(l[i].strip(squote)) 828 i = i + 1 829 continue 830 if cnt == 1: 831 quote = [l[i].strip(squote)] 832 i = i + 1 833 while i < len(l) and squote not in l[i]: 834 quote.append(l[i]) 835 i = i + 1 836 837 quote.append(l[i].strip(squote)) 838 ret.append(" ".join(quote)) 839 i = i + 1 840 continue 841 842 ret.append(l[i]) 843 i = i + 1 844 845 return ret 846 847 848def handleImport(args): 849 trans = seobject.semanageRecords(args) 850 trans.start() 851 852 for l in sys.stdin.readlines(): 853 if len(l.strip()) == 0: 854 continue 855 856 try: 857 commandParser = createCommandParser() 858 args = commandParser.parse_args(mkargv(l)) 859 args.func(args) 860 except ValueError as e: 861 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) 862 sys.exit(1) 863 except IOError as e: 864 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) 865 sys.exit(1) 866 except KeyboardInterrupt: 867 sys.exit(0) 868 869 trans.finish() 870 871 872def setupImportParser(subparsers): 873 importParser = subparsers.add_parser('import', help=_('Import local customizations')) 874 parser_add_noreload(importParser, "import") 875 parser_add_store(importParser, "import") 876 importParser.add_argument('-f', '--input_file', dest='input_file', action=SetImportFile, help=_('Input file')) 877 importParser.set_defaults(func=handleImport) 878 879 880def createCommandParser(): 881 commandParser = seParser(prog='semanage', 882 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 883 description='''semanage is used to configure certain elements 884 of SELinux policy with-out requiring modification 885 to or recompilation from policy source.''') 886 887 #To add a new subcommand define the parser for it in a function above and call it here. 888 subparsers = commandParser.add_subparsers(dest='subcommand') 889 subparsers.required = True 890 setupImportParser(subparsers) 891 setupExportParser(subparsers) 892 setupLoginParser(subparsers) 893 setupUserParser(subparsers) 894 setupPortParser(subparsers) 895 setupPkeyParser(subparsers) 896 setupIbendportParser(subparsers) 897 setupInterfaceParser(subparsers) 898 setupModuleParser(subparsers) 899 setupNodeParser(subparsers) 900 setupFcontextParser(subparsers) 901 setupBooleanParser(subparsers) 902 setupPermissiveParser(subparsers) 903 setupDontauditParser(subparsers) 904 905 return commandParser 906 907 908def make_io_args(args): 909 # import/export backward compability 910 args_origin = ["-S", "-o", "-i", "targeted", "minimum", "mls"] 911 args_file = [] 912 args_ie = [] 913 args_subcommand = [] 914 915 for i in args: 916 if i == "-o": 917 args_subcommand = ["export"] 918 continue 919 if i == "-i": 920 args_subcommand = ["import"] 921 continue 922 if i not in args_origin: 923 args_file = ["-f", i] 924 continue 925 args_ie.append(i) 926 927 return args_subcommand + args_ie + args_file 928 929 930def make_args(sys_args): 931 args = [] 932 if "-o" in sys_args[1:] or "-i" in sys_args[1:]: 933 args = make_io_args(sys_args[1:]) 934 else: 935 args = sys_args[1:] 936 937 return args 938 939 940def do_parser(): 941 try: 942 commandParser = createCommandParser() 943 args = commandParser.parse_args(make_args(sys.argv)) 944 args.func(args) 945 sys.exit(0) 946 except IOError as e: 947 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) 948 sys.exit(1) 949 except KeyboardInterrupt: 950 sys.exit(0) 951 except ValueError as e: 952 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0])) 953 sys.exit(1) 954 except KeyError as e: 955 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0])) 956 sys.exit(1) 957 except OSError as e: 958 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[1])) 959 sys.exit(1) 960 except RuntimeError as e: 961 sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0])) 962 sys.exit(1) 963 964if __name__ == '__main__': 965 do_parser() 966