921 lines
36 KiB
Python
921 lines
36 KiB
Python
#! /usr/bin/python -Es
|
|
# Copyright (C) 2012-2013 Red Hat
|
|
# AUTHOR: Miroslav Grepl <mgrepl@redhat.com>
|
|
# AUTHOR: David Quigley <selinux@davequigley.com>
|
|
# see file 'COPYING' for use and warranty information
|
|
#
|
|
# semanage is a tool for managing SELinux configuration files
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
# published by the Free Software Foundation; either version 2 of
|
|
# the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
# 02111-1307 USA
|
|
#
|
|
#
|
|
|
|
import traceback
|
|
import argparse
|
|
import seobject
|
|
import sys
|
|
PROGNAME = "policycoreutils"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
if sys.version_info < (3,):
|
|
kwargs['unicode'] = True
|
|
gettext.install(PROGNAME,
|
|
localedir="/usr/share/locale",
|
|
codeset='utf-8',
|
|
**kwargs)
|
|
except:
|
|
try:
|
|
import builtins
|
|
builtins.__dict__['_'] = str
|
|
except ImportError:
|
|
import __builtin__
|
|
__builtin__.__dict__['_'] = unicode
|
|
|
|
# define custom usages for selected main actions
|
|
usage_login = "semanage login [-h] [-n] [-N] [-S STORE] ["
|
|
usage_login_dict = {' --add': ('-s SEUSER', '-r RANGE', 'LOGIN',), ' --modify': ('-s SEUSER', '-r RANGE', 'LOGIN',), ' --delete': ('LOGIN',), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_fcontext = "semanage fcontext [-h] [-n] [-N] [-S STORE] ["
|
|
usage_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': ('',)}
|
|
|
|
usage_user = "semanage user [-h] [-n] [-N] [-S STORE] ["
|
|
usage_user_dict = {' --add': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'selinux_name'')'), ' --delete': ('selinux_name',), ' --modify': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'selinux_name', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_port = "semanage port [-h] [-n] [-N] [-S STORE] ["
|
|
usage_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': ('',)}
|
|
|
|
usage_node = "semanage node [-h] [-n] [-N] [-S STORE] ["
|
|
usage_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': ('',)}
|
|
|
|
usage_interface = "semanage interface [-h] [-n] [-N] [-S STORE] ["
|
|
usage_interface_dict = {' --add': ('-t TYPE', '-r RANGE', 'interface'), ' --modify': ('-t TYPE', '-r RANGE', 'interface'), ' --delete': ('interface',), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_boolean = "semanage boolean [-h] [-n] [-N] [-S STORE] ["
|
|
usage_boolean_dict = {' --modify': ('(', '--on', '|', '--off', ')', 'boolean'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
import sepolicy
|
|
|
|
|
|
class CheckRole(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, value, option_string=None):
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
roles = sepolicy.get_all_roles()
|
|
for v in value.split():
|
|
if v not in roles:
|
|
raise ValueError("%s must be an SELinux role:\nValid roles: %s" % (v, ", ".join(roles)))
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
store = ''
|
|
|
|
|
|
class SetStore(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
global store
|
|
store = values
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
class seParser(argparse.ArgumentParser):
|
|
|
|
def error(self, message):
|
|
if len(sys.argv) == 2:
|
|
self.print_help()
|
|
else:
|
|
self.print_usage()
|
|
self.exit(2, ('%s: error: %s\n') % (self.prog, message))
|
|
|
|
|
|
class SetExportFile(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
if values:
|
|
if values is not "-":
|
|
try:
|
|
sys.stdout = open(values, 'w')
|
|
except:
|
|
sys.stderr.write(traceback.format_exc())
|
|
sys.exit(1)
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
class SetImportFile(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
if values and values is not "-":
|
|
try:
|
|
sys.stdin = open(values, 'r')
|
|
except IOError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
|
|
sys.exit(1)
|
|
setattr(namespace, self.dest, values)
|
|
|
|
# functions for OBJECT initialization
|
|
|
|
|
|
def login_ini():
|
|
OBJECT = seobject.loginRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def user_ini():
|
|
OBJECT = seobject.seluserRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def port_ini():
|
|
OBJECT = seobject.portRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def module_ini():
|
|
OBJECT = seobject.moduleRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def interface_ini():
|
|
OBJECT = seobject.interfaceRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def node_ini():
|
|
OBJECT = seobject.nodeRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def fcontext_ini():
|
|
OBJECT = seobject.fcontextRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def boolean_ini():
|
|
OBJECT = seobject.booleanRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def permissive_ini():
|
|
OBJECT = seobject.permissiveRecords(store)
|
|
return OBJECT
|
|
|
|
|
|
def dontaudit_ini():
|
|
OBJECT = seobject.dontauditClass(store)
|
|
return OBJECT
|
|
|
|
# define dictonary for seobject OBEJCTS
|
|
object_dict = {'login': login_ini, 'user': user_ini, 'port': port_ini, 'module': module_ini, 'interface': interface_ini, 'node': node_ini, 'fcontext': fcontext_ini, 'boolean': boolean_ini, 'permissive': permissive_ini, 'dontaudit': dontaudit_ini}
|
|
|
|
|
|
def generate_custom_usage(usage_text, usage_dict):
|
|
# generate custom usage from given text and dictonary
|
|
sorted_keys = []
|
|
for i in usage_dict.keys():
|
|
sorted_keys.append(i)
|
|
sorted_keys.sort()
|
|
for k in sorted_keys:
|
|
usage_text += "%s %s |" % (k, (" ".join(usage_dict[k])))
|
|
usage_text = usage_text[:-1] + "]"
|
|
usage_text = _(usage_text)
|
|
|
|
return usage_text
|
|
|
|
|
|
def handle_opts(args, dict, target_key):
|
|
# handle conflict and required options for given dictonary
|
|
# {action:[conflict_opts,require_opts]}
|
|
|
|
# first we need to catch conflicts
|
|
for k in args.__dict__.keys():
|
|
try:
|
|
if k in dict[target_key][0] and args.__dict__[k]:
|
|
print("%s option can not be used with --%s" % (target_key, k))
|
|
sys.exit(2)
|
|
except KeyError:
|
|
continue
|
|
|
|
for k in args.__dict__.keys():
|
|
try:
|
|
if k in dict[target_key][1] and not args.__dict__[k]:
|
|
print("%s option is needed for %s" % (k, target_key))
|
|
sys.exit(2)
|
|
except KeyError:
|
|
continue
|
|
|
|
|
|
def handleLogin(args):
|
|
# {action:[conflict_opts,require_opts]}
|
|
login_args = {'list': [('login', 'seuser'), ('')], 'add': [('locallist'), ('seuser', 'login')], 'modify': [('locallist'), ('login')], 'delete': [('locallist'), ('login')], 'extract': [('locallist', 'login', 'seuser'), ('')], 'deleteall': [('locallist'), ('')]}
|
|
|
|
handle_opts(args, login_args, args.action)
|
|
|
|
OBJECT = object_dict['login']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
OBJECT.add(args.login, args.seuser, args.range)
|
|
if args.action is "modify":
|
|
OBJECT.modify(args.login, args.seuser, args.range)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.login)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("login %s" % (str(i)))
|
|
|
|
|
|
def parser_add_store(parser, name):
|
|
parser.add_argument('-S', '--store', action=SetStore, help=_("Select an alternate SELinux Policy Store to manage"))
|
|
|
|
|
|
def parser_add_priority(parser, name):
|
|
parser.add_argument('-P', '--priority', type=int, default=400, help=_("Select a priority for module operations"))
|
|
|
|
|
|
def parser_add_noheading(parser, name):
|
|
parser.add_argument('-n', '--noheading', action='store_false', default=True, help=_("Do not print heading when listing %s object types") % name)
|
|
|
|
|
|
def parser_add_noreload(parser, name):
|
|
parser.add_argument('-N', '--noreload', action='store_false', default=True, help=_('Do not reload policy after commit'))
|
|
|
|
|
|
def parser_add_locallist(parser, name):
|
|
parser.add_argument('-C', '--locallist', action='store_true', default=False, help=_("List %s local customizations") % name)
|
|
|
|
|
|
def parser_add_add(parser, name):
|
|
parser.add_argument('-a', '--add', dest='action', action='store_const', const='add', help=_("Add a record of the %s object type") % name)
|
|
|
|
|
|
def parser_add_type(parser, name):
|
|
parser.add_argument('-t', '--type', help=_('SELinux Type for the object'))
|
|
|
|
|
|
def parser_add_level(parser, name):
|
|
parser.add_argument('-L', '--level', default='s0', help=_('Default SELinux Level for SELinux user, s0 Default. (MLS/MCS Systems only)'))
|
|
|
|
|
|
def parser_add_range(parser, name):
|
|
parser.add_argument('-r', '--range', default="s0",
|
|
help=_('''
|
|
MLS/MCS Security Range (MLS/MCS Systems only)
|
|
SELinux Range for SELinux login mapping
|
|
defaults to the SELinux user record range.
|
|
SELinux Range for SELinux user defaults to s0.
|
|
'''))
|
|
|
|
|
|
def parser_add_proto(parser, name):
|
|
parser.add_argument('-p', '--proto', help=_('''
|
|
Protocol for the specified port (tcp|udp) or internet protocol
|
|
version for the specified node (ipv4|ipv6).
|
|
'''))
|
|
|
|
|
|
def parser_add_modify(parser, name):
|
|
parser.add_argument('-m', '--modify', dest='action', action='store_const', const='modify', help=_("Modify a record of the %s object type") % name)
|
|
|
|
|
|
def parser_add_list(parser, name):
|
|
parser.add_argument('-l', '--list', dest='action', action='store_const', const='list', help=_("List records of the %s object type") % name)
|
|
|
|
|
|
def parser_add_delete(parser, name):
|
|
parser.add_argument('-d', '--delete', dest='action', action='store_const', const='delete', help=_("Delete a record of the %s object type") % name)
|
|
|
|
|
|
def parser_add_extract(parser, name):
|
|
parser.add_argument('-E', '--extract', dest='action', action='store_const', const='extract', help=_("Extract customizable commands, for use within a transaction"))
|
|
|
|
|
|
def parser_add_deleteall(parser, name):
|
|
parser.add_argument('-D', '--deleteall', dest='action', action='store_const', const='deleteall', help=_('Remove all %s objects local customizations') % name)
|
|
|
|
|
|
def parser_add_seuser(parser, name):
|
|
parser.add_argument('-s', '--seuser', default="", help=_("SELinux user name"))
|
|
|
|
|
|
def setupLoginParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_login, usage_login_dict)
|
|
loginParser = subparsers.add_parser('login', usage=generated_usage, help=_("Manage login mappings between linux users and SELinux confined users"))
|
|
parser_add_locallist(loginParser, "login")
|
|
parser_add_noheading(loginParser, "login")
|
|
parser_add_noreload(loginParser, "login")
|
|
parser_add_store(loginParser, "login")
|
|
parser_add_range(loginParser, "login")
|
|
|
|
login_action = loginParser.add_mutually_exclusive_group(required=True)
|
|
|
|
parser_add_add(login_action, "login")
|
|
parser_add_delete(login_action, "login")
|
|
parser_add_modify(login_action, "login")
|
|
parser_add_list(login_action, "login")
|
|
parser_add_extract(login_action, "login")
|
|
parser_add_deleteall(login_action, "login")
|
|
parser_add_seuser(loginParser, "login")
|
|
|
|
loginParser.add_argument('login', nargs='?', default=None, help=_("login_name | %%groupname"))
|
|
|
|
loginParser.set_defaults(func=handleLogin)
|
|
|
|
|
|
def handleFcontext(args):
|
|
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'), ('')]}
|
|
# we can not use mutually for equal because we can define some actions together with equal
|
|
fcontext_equal_args = {'equal': [('list', 'locallist', 'type', 'ftype', 'seuser', 'deleteall', 'extract'), ()]}
|
|
|
|
if args.action and args.equal:
|
|
handle_opts(args, fcontext_equal_args, "equal")
|
|
else:
|
|
handle_opts(args, fcontext_args, args.action)
|
|
|
|
OBJECT = object_dict['fcontext']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
if args.equal:
|
|
OBJECT.add_equal(args.file_spec, args.equal)
|
|
else:
|
|
OBJECT.add(args.file_spec, args.type, args.ftype, args.range, args.seuser)
|
|
if args.action is "modify":
|
|
if args.equal:
|
|
OBJECT.add_equal(args.file_spec, args.equal)
|
|
else:
|
|
OBJECT.modify(args.file_spec, args.type, args.ftype, args.range, args.seuser)
|
|
if args.action is "delete":
|
|
if args.equal:
|
|
OBJECT.delete(args.file_spec, args.equal)
|
|
else:
|
|
OBJECT.delete(args.file_spec, args.ftype)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("fcontext %s" % str(i))
|
|
|
|
|
|
def setupFcontextParser(subparsers):
|
|
ftype_help = '''
|
|
File Type. This is used with fcontext. Requires a file type
|
|
as shown in the mode field by ls, e.g. use d to match only
|
|
directories or f to match only regular files. The following
|
|
file type options can be passed:
|
|
f (regular file),d (directory),c (character device),
|
|
b (block device),s (socket),l (symbolic link),p (named pipe)
|
|
If you do not specify a file type, the file type will default to "all files".
|
|
'''
|
|
generate_usage = generate_custom_usage(usage_fcontext, usage_fcontext_dict)
|
|
fcontextParser = subparsers.add_parser('fcontext', usage=generate_usage, help=_("Manage file context mapping definitions"))
|
|
parser_add_locallist(fcontextParser, "fcontext")
|
|
parser_add_noheading(fcontextParser, "fcontext")
|
|
parser_add_noreload(fcontextParser, "fcontext")
|
|
parser_add_store(fcontextParser, "fcontext")
|
|
|
|
fcontext_action = fcontextParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(fcontext_action, "fcontext")
|
|
parser_add_delete(fcontext_action, "fcontext")
|
|
parser_add_modify(fcontext_action, "fcontext")
|
|
parser_add_list(fcontext_action, "fcontext")
|
|
parser_add_extract(fcontext_action, "fcontext")
|
|
parser_add_deleteall(fcontext_action, "fcontext")
|
|
|
|
fcontextParser.add_argument('-e', '--equal', help=_('''Substitute target path with sourcepath when generating default
|
|
label. This is used with fcontext. Requires source and target
|
|
path arguments. The context labeling for the target subtree is
|
|
made equivalent to that defined for the source.'''))
|
|
fcontextParser.add_argument('-f', '--ftype', default="", choices=["a", "f", "d", "c", "b", "s", "l", "p"], help=_(ftype_help))
|
|
parser_add_seuser(fcontextParser, "fcontext")
|
|
parser_add_type(fcontextParser, "fcontext")
|
|
parser_add_range(fcontextParser, "fcontext")
|
|
fcontextParser.add_argument('file_spec', nargs='?', default=None, help=_('file_spec'))
|
|
fcontextParser.set_defaults(func=handleFcontext)
|
|
|
|
|
|
def handleUser(args):
|
|
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'), ('')]}
|
|
|
|
handle_opts(args, user_args, args.action)
|
|
|
|
OBJECT = object_dict['user']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
OBJECT.add(args.selinux_name, args.roles, args.level, args.range, args.prefix)
|
|
if args.action is "modify":
|
|
OBJECT.modify(args.selinux_name, args.roles, args.level, args.range, args.prefix)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.selinux_name)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("user %s" % str(i))
|
|
|
|
|
|
def setupUserParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_user, usage_user_dict)
|
|
userParser = subparsers.add_parser('user', usage=generated_usage, help=_('Manage SELinux confined users (Roles and levels for an SELinux user)'))
|
|
parser_add_locallist(userParser, "user")
|
|
parser_add_noheading(userParser, "user")
|
|
parser_add_noreload(userParser, "user")
|
|
parser_add_store(userParser, "user")
|
|
|
|
user_action = userParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(user_action, "user")
|
|
parser_add_delete(user_action, "user")
|
|
parser_add_modify(user_action, "user")
|
|
parser_add_list(user_action, "user")
|
|
parser_add_extract(user_action, "user")
|
|
parser_add_deleteall(user_action, "user")
|
|
|
|
parser_add_level(userParser, "user")
|
|
parser_add_range(userParser, "user")
|
|
userParser.add_argument('-R', '--roles', default=[],
|
|
action=CheckRole,
|
|
help=_('''
|
|
SELinux Roles. You must enclose multiple roles within quotes, separate by spaces. Or specify -R multiple times.
|
|
'''))
|
|
userParser.add_argument('-P', '--prefix', default="user", help=argparse.SUPPRESS)
|
|
userParser.add_argument('selinux_name', nargs='?', default=None, help=_('selinux_name'))
|
|
userParser.set_defaults(func=handleUser)
|
|
|
|
|
|
def handlePort(args):
|
|
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'), ('')]}
|
|
|
|
handle_opts(args, port_args, args.action)
|
|
|
|
OBJECT = object_dict['port']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
OBJECT.add(args.port, args.proto, args.range, args.type)
|
|
if args.action is "modify":
|
|
OBJECT.modify(args.port, args.proto, args.range, args.type)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.port, args.proto)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("port %s" % str(i))
|
|
|
|
|
|
def setupPortParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_port, usage_port_dict)
|
|
portParser = subparsers.add_parser('port', usage=generated_usage, help=_('Manage network port type definitions'))
|
|
parser_add_locallist(portParser, "port")
|
|
parser_add_noheading(portParser, "port")
|
|
parser_add_noreload(portParser, "port")
|
|
parser_add_store(portParser, "port")
|
|
|
|
port_action = portParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(port_action, "port")
|
|
parser_add_delete(port_action, "port")
|
|
parser_add_modify(port_action, "port")
|
|
parser_add_list(port_action, "port")
|
|
parser_add_extract(port_action, "port")
|
|
parser_add_deleteall(port_action, "port")
|
|
parser_add_type(portParser, "port")
|
|
parser_add_range(portParser, "port")
|
|
parser_add_proto(portParser, "port")
|
|
portParser.add_argument('port', nargs='?', default=None, help=_('port | port_range'))
|
|
portParser.set_defaults(func=handlePort)
|
|
|
|
|
|
def handleInterface(args):
|
|
interface_args = {'list': [('interface'), ('')], 'add': [('locallist'), ('type', 'interface')], 'modify': [('locallist'), ('type', 'interface')], 'delete': [('locallist'), ('interface')], 'extract': [('locallist', 'interface', 'type'), ('')], 'deleteall': [('locallist'), ('')]}
|
|
|
|
handle_opts(args, interface_args, args.action)
|
|
|
|
OBJECT = object_dict['interface']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
OBJECT.add(args.interface, args.range, args.type)
|
|
if args.action is "modify":
|
|
OBJECT.modify(args.interface, args.range, args.type)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.interface)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("interface %s" % str(i))
|
|
|
|
|
|
def setupInterfaceParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_interface, usage_interface_dict)
|
|
interfaceParser = subparsers.add_parser('interface', usage=generated_usage, help=_('Manage network interface type definitions'))
|
|
parser_add_locallist(interfaceParser, "interface")
|
|
parser_add_noheading(interfaceParser, "interface")
|
|
parser_add_noreload(interfaceParser, "interface")
|
|
parser_add_store(interfaceParser, "interface")
|
|
parser_add_type(interfaceParser, "interface")
|
|
parser_add_range(interfaceParser, "interface")
|
|
|
|
interface_action = interfaceParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(interface_action, "interface")
|
|
parser_add_delete(interface_action, "interface")
|
|
parser_add_modify(interface_action, "interface")
|
|
parser_add_list(interface_action, "interface")
|
|
parser_add_extract(interface_action, "interface")
|
|
parser_add_deleteall(interface_action, "interface")
|
|
interfaceParser.add_argument('interface', nargs='?', default=None, help=_('interface_spec'))
|
|
interfaceParser.set_defaults(func=handleInterface)
|
|
|
|
|
|
def handleModule(args):
|
|
OBJECT = seobject.moduleRecords(store)
|
|
OBJECT.set_reload(args.noreload)
|
|
if args.action == "add":
|
|
OBJECT.add(args.module_name, args.priority)
|
|
if args.action == "enable":
|
|
OBJECT.set_enabled(args.module_name, True)
|
|
if args.action == "disable":
|
|
OBJECT.set_enabled(args.module_name, False)
|
|
if args.action == "remove":
|
|
OBJECT.delete(args.module_name, args.priority)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action == "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("module %s" % str(i))
|
|
|
|
|
|
def setupModuleParser(subparsers):
|
|
moduleParser = subparsers.add_parser('module', help=_('Manage SELinux policy modules'))
|
|
parser_add_noheading(moduleParser, "module")
|
|
parser_add_noreload(moduleParser, "module")
|
|
parser_add_store(moduleParser, "module")
|
|
parser_add_locallist(moduleParser, "module")
|
|
parser_add_priority(moduleParser, "module")
|
|
|
|
mgroup = moduleParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(mgroup, "module")
|
|
parser_add_list(mgroup, "module")
|
|
parser_add_extract(mgroup, "module")
|
|
parser_add_deleteall(mgroup, "module")
|
|
mgroup.add_argument('-r', '--remove', dest='action', action='store_const', const='remove', help=_("Remove a module"))
|
|
mgroup.add_argument('-d', '--disable', dest='action', action='store_const', const='disable', help=_("Disable a module"))
|
|
mgroup.add_argument('-e', '--enable', dest='action', action='store_const', const='enable', help=_("Enable a module"))
|
|
moduleParser.add_argument('module_name', nargs='?', default=None, help=_('Name of the module to act on'))
|
|
moduleParser.set_defaults(func=handleModule)
|
|
|
|
|
|
def handleNode(args):
|
|
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'), ('')]}
|
|
handle_opts(args, node_args, args.action)
|
|
|
|
OBJECT = object_dict['node']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "add":
|
|
OBJECT.add(args.node, args.netmask, args.proto, args.range, args.type)
|
|
if args.action is "modify":
|
|
OBJECT.modify(args.node, args.netmask, args.proto, args.range, args.type)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.node, args.netmask, args.proto)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("node %s" % str(i))
|
|
|
|
|
|
def setupNodeParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_node, usage_node_dict)
|
|
nodeParser = subparsers.add_parser('node', usage=generated_usage, help=_('Manage network node type definitions'))
|
|
parser_add_locallist(nodeParser, "node")
|
|
parser_add_noheading(nodeParser, "node")
|
|
parser_add_noreload(nodeParser, "node")
|
|
parser_add_store(nodeParser, "node")
|
|
|
|
node_action = nodeParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(node_action, "node")
|
|
parser_add_delete(node_action, "node")
|
|
parser_add_modify(node_action, "node")
|
|
parser_add_list(node_action, "node")
|
|
parser_add_extract(node_action, "node")
|
|
parser_add_deleteall(node_action, "node")
|
|
|
|
nodeParser.add_argument('-M', '--netmask', help=_('Network Mask'))
|
|
parser_add_type(nodeParser, "node")
|
|
parser_add_range(nodeParser, "node")
|
|
parser_add_proto(nodeParser, "node")
|
|
nodeParser.add_argument('node', nargs='?', default=None, help=_('node'))
|
|
nodeParser.set_defaults(func=handleNode)
|
|
|
|
|
|
def handleBoolean(args):
|
|
boolean_args = {'list': [('state', 'boolean'), ('')], 'modify': [('localist'), ('boolean', 'state')], 'extract': [('locallist', 'state', 'boolean'), ('')], 'deleteall': [('locallist'), ('')], 'state': [('locallist', 'list', 'extract', 'deleteall'), ('modify')]}
|
|
|
|
handle_opts(args, boolean_args, args.action)
|
|
|
|
OBJECT = object_dict['boolean']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "modify":
|
|
if args.boolean:
|
|
OBJECT.modify(args.boolean, args.state, False)
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
if args.action is "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action is "extract":
|
|
for i in OBJECT.customized():
|
|
print("boolean %s" % str(i))
|
|
|
|
|
|
def setupBooleanParser(subparsers):
|
|
generated_usage = generate_custom_usage(usage_boolean, usage_boolean_dict)
|
|
booleanParser = subparsers.add_parser('boolean', usage=generated_usage, help=_('Manage booleans to selectively enable functionality'))
|
|
parser_add_locallist(booleanParser, "boolean")
|
|
parser_add_noheading(booleanParser, "boolean")
|
|
parser_add_noreload(booleanParser, "boolean")
|
|
parser_add_store(booleanParser, "boolean")
|
|
booleanParser.add_argument('boolean', nargs="?", default=None, help=_('boolean'))
|
|
|
|
boolean_action = booleanParser.add_mutually_exclusive_group(required=True)
|
|
#add_add(boolean_action)
|
|
parser_add_modify(boolean_action, "boolean")
|
|
parser_add_list(boolean_action, "boolean")
|
|
parser_add_extract(boolean_action, "boolean")
|
|
parser_add_deleteall(boolean_action, "boolean")
|
|
|
|
booleanGroup = booleanParser.add_mutually_exclusive_group(required=False)
|
|
booleanGroup.add_argument('-1', '--on', dest='state', action='store_const', const='on', help=_('Enable the boolean'))
|
|
booleanGroup.add_argument('-0', '--off', dest='state', action='store_const', const='off', help=_('Disable the boolean'))
|
|
|
|
booleanParser.set_defaults(func=handleBoolean)
|
|
|
|
|
|
def handlePermissive(args):
|
|
OBJECT = object_dict['permissive']()
|
|
OBJECT.set_reload(args.noreload)
|
|
|
|
if args.action is "list":
|
|
OBJECT.list(args.noheading)
|
|
elif args.type is not None:
|
|
if args.action is "add":
|
|
OBJECT.add(args.type)
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.type)
|
|
else:
|
|
args.parser.print_usage(sys.stderr)
|
|
sys.stderr.write(_('semanage permissive: error: the following argument is required: type\n'))
|
|
sys.exit(1)
|
|
|
|
|
|
def setupPermissiveParser(subparsers):
|
|
permissiveParser = subparsers.add_parser('permissive', help=_('Manage process type enforcement mode'))
|
|
|
|
pgroup = permissiveParser.add_mutually_exclusive_group(required=True)
|
|
parser_add_add(pgroup, "permissive")
|
|
parser_add_delete(pgroup, "permissive")
|
|
parser_add_list(pgroup, "permissive")
|
|
#TODO: probably should be also added => need to implement own option handling
|
|
#parser_add_deleteall(pgroup)
|
|
|
|
parser_add_noheading(permissiveParser, "permissive")
|
|
parser_add_noreload(permissiveParser, "permissive")
|
|
parser_add_store(permissiveParser, "permissive")
|
|
permissiveParser.add_argument('type', nargs='?', default=None, help=_('type'))
|
|
permissiveParser.set_defaults(func=handlePermissive)
|
|
permissiveParser.set_defaults(parser=permissiveParser)
|
|
|
|
|
|
def handleDontaudit(args):
|
|
OBJECT = object_dict['dontaudit']()
|
|
OBJECT.set_reload(args.noreload)
|
|
OBJECT.toggle(args.action)
|
|
|
|
|
|
def setupDontauditParser(subparsers):
|
|
dontauditParser = subparsers.add_parser('dontaudit', help=_('Disable/Enable dontaudit rules in policy'))
|
|
parser_add_noreload(dontauditParser, "dontaudit")
|
|
parser_add_store(dontauditParser, "dontaudit")
|
|
dontauditParser.add_argument('action', choices=["on", "off"])
|
|
dontauditParser.set_defaults(func=handleDontaudit)
|
|
|
|
|
|
def handleExport(args):
|
|
manageditems = ["boolean", "login", "interface", "user", "port", "node", "fcontext", "module"]
|
|
for i in manageditems:
|
|
print("%s -D" % i)
|
|
for i in manageditems:
|
|
OBJECT = object_dict[i]()
|
|
for c in OBJECT.customized():
|
|
print("%s %s" % (i, str(c)))
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
def setupExportParser(subparsers):
|
|
exportParser = subparsers.add_parser('export', help=_('Output local customizations'))
|
|
parser_add_store(exportParser, "export")
|
|
exportParser.add_argument('-f', '--output_file', dest='output_file', action=SetExportFile, help=_('Output file'))
|
|
exportParser.set_defaults(func=handleExport)
|
|
|
|
import re
|
|
|
|
|
|
def mkargv(line):
|
|
dquote = "\""
|
|
squote = "\'"
|
|
l = line.split()
|
|
ret = []
|
|
i = 0
|
|
while i < len(l):
|
|
cnt = len(re.findall(dquote, l[i]))
|
|
if cnt > 1:
|
|
ret.append(l[i].strip(dquote))
|
|
i = i + 1
|
|
continue
|
|
if cnt == 1:
|
|
quote = [l[i].strip(dquote)]
|
|
i = i + 1
|
|
|
|
while i < len(l) and dquote not in l[i]:
|
|
quote.append(l[i])
|
|
i = i + 1
|
|
quote.append(l[i].strip(dquote))
|
|
ret.append(" ".join(quote))
|
|
i = i + 1
|
|
continue
|
|
|
|
cnt = len(re.findall(squote, l[i]))
|
|
if cnt > 1:
|
|
ret.append(l[i].strip(squote))
|
|
i = i + 1
|
|
continue
|
|
if cnt == 1:
|
|
quote = [l[i].strip(squote)]
|
|
i = i + 1
|
|
while i < len(l) and squote not in l[i]:
|
|
quote.append(l[i])
|
|
i = i + 1
|
|
|
|
quote.append(l[i].strip(squote))
|
|
ret.append(" ".join(quote))
|
|
i = i + 1
|
|
continue
|
|
|
|
ret.append(l[i])
|
|
i = i + 1
|
|
|
|
return ret
|
|
|
|
|
|
def handleImport(args):
|
|
trans = seobject.semanageRecords(store)
|
|
trans.start()
|
|
|
|
for l in sys.stdin.readlines():
|
|
if len(l.strip()) == 0:
|
|
continue
|
|
|
|
try:
|
|
commandParser = createCommandParser()
|
|
args = commandParser.parse_args(mkargv(l))
|
|
args.func(args)
|
|
except ValueError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
|
|
sys.exit(1)
|
|
except IOError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
|
|
sys.exit(1)
|
|
except KeyboardInterrupt:
|
|
sys.exit(0)
|
|
|
|
trans.set_reload(args.noreload)
|
|
trans.finish()
|
|
|
|
|
|
def setupImportParser(subparsers):
|
|
importParser = subparsers.add_parser('import', help=_('Import local customizations'))
|
|
parser_add_noreload(importParser, "import")
|
|
parser_add_store(importParser, "import")
|
|
importParser.add_argument('-f', '--input_file', dest='input_file', action=SetImportFile, help=_('Input file'))
|
|
importParser.set_defaults(func=handleImport)
|
|
|
|
|
|
def createCommandParser():
|
|
commandParser = seParser(prog='semanage',
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
description='''semanage is used to configure certain elements
|
|
of SELinux policy with-out requiring modification
|
|
to or recompilation from policy source.''')
|
|
|
|
#To add a new subcommand define the parser for it in a function above and call it here.
|
|
subparsers = commandParser.add_subparsers(dest='subcommand')
|
|
subparsers.required = True
|
|
setupImportParser(subparsers)
|
|
setupExportParser(subparsers)
|
|
setupLoginParser(subparsers)
|
|
setupUserParser(subparsers)
|
|
setupPortParser(subparsers)
|
|
setupInterfaceParser(subparsers)
|
|
setupModuleParser(subparsers)
|
|
setupNodeParser(subparsers)
|
|
setupFcontextParser(subparsers)
|
|
setupBooleanParser(subparsers)
|
|
setupPermissiveParser(subparsers)
|
|
setupDontauditParser(subparsers)
|
|
|
|
return commandParser
|
|
|
|
|
|
def make_io_args(args):
|
|
# import/export backward compability
|
|
args_origin = ["-S", "-o", "-i", "targeted", "minimum", "mls"]
|
|
args_file = []
|
|
args_ie = []
|
|
args_subcommand = []
|
|
|
|
for i in args:
|
|
if i == "-o":
|
|
args_subcommand = ["export"]
|
|
continue
|
|
if i == "-i":
|
|
args_subcommand = ["import"]
|
|
continue
|
|
if i not in args_origin:
|
|
args_file = ["-f", i]
|
|
continue
|
|
args_ie.append(i)
|
|
|
|
return args_subcommand + args_ie + args_file
|
|
|
|
|
|
def make_args(sys_args):
|
|
args = []
|
|
if "-o" in sys_args[1:] or "-i" in sys_args[1:]:
|
|
args = make_io_args(sys_args[1:])
|
|
else:
|
|
args = sys_args[1:]
|
|
|
|
return args
|
|
|
|
|
|
def do_parser():
|
|
try:
|
|
commandParser = createCommandParser()
|
|
args = commandParser.parse_args(make_args(sys.argv))
|
|
args.func(args)
|
|
sys.exit(0)
|
|
except IOError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
|
|
sys.exit(1)
|
|
except KeyboardInterrupt:
|
|
sys.exit(0)
|
|
except ValueError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0]))
|
|
sys.exit(1)
|
|
except KeyError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0]))
|
|
sys.exit(1)
|
|
except OSError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[1]))
|
|
sys.exit(1)
|
|
except RuntimeError as e:
|
|
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, e.args[0]))
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
do_parser()
|