713 lines
29 KiB
Python
Executable File
713 lines
29 KiB
Python
Executable File
#!/usr/bin/python3 -EsI
|
|
# Copyright (C) 2012 Red Hat
|
|
# AUTHOR: Dan Walsh <dwalsh@redhat.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 os
|
|
import sys
|
|
import selinux
|
|
import sepolicy
|
|
from multiprocessing import Pool
|
|
from sepolicy import get_os_version, get_conditionals, get_conditionals_format_text
|
|
import argparse
|
|
PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
if sys.version_info < (3,):
|
|
kwargs['unicode'] = True
|
|
t = gettext.translation(PROGNAME,
|
|
localedir="/usr/share/locale",
|
|
**kwargs,
|
|
fallback=True)
|
|
_ = t.gettext
|
|
except:
|
|
try:
|
|
import builtins
|
|
builtins.__dict__['_'] = str
|
|
except ImportError:
|
|
import __builtin__
|
|
__builtin__.__dict__['_'] = unicode
|
|
|
|
usage = "sepolicy generate [-h] [-n NAME] [-p PATH] ["
|
|
usage_dict = {' --newtype': ('-t [TYPES [TYPES ...]]',), ' --customize': ('-d DOMAIN', '-a ADMIN_DOMAIN', "[ -w WRITEPATHS ]",), ' --admin_user': ('[-r TRANSITION_ROLE ]', "[ -w WRITEPATHS ]",), ' --application': ('COMMAND', "[ -w WRITEPATHS ]",), ' --cgi': ('COMMAND', "[ -w WRITEPATHS ]",), ' --confined_admin': ('-a ADMIN_DOMAIN', "[ -w WRITEPATHS ]",), ' --dbus': ('COMMAND', "[ -w WRITEPATHS ]",), ' --desktop_user': ('', "[ -w WRITEPATHS ]",), ' --inetd': ('COMMAND', "[ -w WRITEPATHS ]",), ' --init': ('COMMAND', "[ -w WRITEPATHS ]",), ' --sandbox': ("[ -w WRITEPATHS ]",), ' --term_user': ("[ -w WRITEPATHS ]",), ' --x_user': ("[ -w WRITEPATHS ]",)}
|
|
|
|
|
|
class CheckPath(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
if not os.path.exists(values):
|
|
raise ValueError("%s does not exist" % values)
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
class CheckType(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
if isinstance(values, str):
|
|
setattr(namespace, self.dest, values)
|
|
else:
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
|
|
for v in values:
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class CheckBoolean(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
booleans = sepolicy.get_all_booleans()
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
|
|
if isinstance(values, str):
|
|
v = selinux.selinux_boolean_sub(values)
|
|
if v not in booleans:
|
|
raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (v, ", ".join(booleans)))
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
else:
|
|
for value in values:
|
|
v = selinux.selinux_boolean_sub(value)
|
|
if v not in booleans:
|
|
raise ValueError("%s must be an SELinux boolean:\nValid boolean: %s" % (v, ", ".join(booleans)))
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class CheckDomain(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
domains = sepolicy.get_all_domains()
|
|
|
|
if isinstance(values, str):
|
|
values = sepolicy.get_real_type_name(values)
|
|
if values not in domains:
|
|
raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (values, ", ".join(domains)))
|
|
setattr(namespace, self.dest, values)
|
|
else:
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
|
|
for v in values:
|
|
v = sepolicy.get_real_type_name(v)
|
|
if v not in domains:
|
|
raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (v, ", ".join(domains)))
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
all_classes = None
|
|
|
|
|
|
class CheckClass(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
global all_classes
|
|
if not all_classes:
|
|
all_classes = map(lambda x: x['name'], sepolicy.info(sepolicy.TCLASS))
|
|
if values not in all_classes:
|
|
raise ValueError("%s must be an SELinux class:\nValid classes: %s" % (values, ", ".join(all_classes)))
|
|
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
class CheckAdmin(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
from sepolicy.interface import get_admin
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
admins = get_admin()
|
|
if values not in admins:
|
|
raise ValueError("%s must be an SELinux admin domain:\nValid admin domains: %s" % (values, ", ".join(admins)))
|
|
newval.append(values)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class CheckPort(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
for v in values:
|
|
if v < 1 or v > 65536:
|
|
raise ValueError("%s must be an integer between 1 and 65536" % v)
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class CheckPortType(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
port_types = sepolicy.get_all_port_types()
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
for v in values:
|
|
v = sepolicy.get_real_type_name(v)
|
|
if v not in port_types:
|
|
raise ValueError("%s must be an SELinux port type:\nValid port types: %s" % (v, ", ".join(port_types)))
|
|
newval.append(v)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class LoadPolicy(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
import sepolicy
|
|
sepolicy.policy(values)
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
class CheckUser(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, value, option_string=None):
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
users = sepolicy.get_all_users()
|
|
if value not in users:
|
|
raise ValueError("%s must be an SELinux user:\nValid users: %s" % (value, ", ".join(users)))
|
|
newval.append(value)
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
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()
|
|
if value not in roles:
|
|
raise ValueError("%s must be an SELinux role:\nValid roles: %s" % (value, ", ".join(roles)))
|
|
newval.append(value[:-2])
|
|
setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class InterfaceInfo(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
from sepolicy.interface import get_interface_dict
|
|
interface_dict = get_interface_dict()
|
|
for v in values:
|
|
if v not in interface_dict.keys():
|
|
raise ValueError(_("Interface %s does not exist.") % v)
|
|
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
def generate_custom_usage(usage_text, usage_dict):
|
|
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
|
|
|
|
# expects formats:
|
|
# "22 (sshd_t)", "80, 8080 (httpd_t)", "all ports (port_type)"
|
|
def port_string_to_num(val):
|
|
try:
|
|
return int(val.split(" ")[0].split(",")[0].split("-")[0])
|
|
except:
|
|
return 99999999
|
|
|
|
|
|
def _print_net(src, protocol, perm):
|
|
import sepolicy.network
|
|
portdict = sepolicy.network.get_network_connect(src, protocol, perm)
|
|
if len(portdict) > 0:
|
|
bold_start = "\033[1m"
|
|
bold_end = "\033[0;0m"
|
|
print("\n" + bold_start + "%s: %s %s" % (src, protocol, perm) + bold_end)
|
|
port_strings = []
|
|
boolean_text = ""
|
|
for p in portdict:
|
|
for t, recs in portdict[p]:
|
|
cond = get_conditionals(src, t, "%s_socket" % protocol, [perm])
|
|
if cond:
|
|
boolean_text = get_conditionals_format_text(cond)
|
|
port_strings.append("%s (%s) %s" % (", ".join(recs), t, boolean_text))
|
|
else:
|
|
port_strings.append("%s (%s)" % (", ".join(recs), t))
|
|
port_strings.sort(key=lambda param: port_string_to_num(param))
|
|
for p in port_strings:
|
|
print("\t" + p)
|
|
|
|
|
|
def network(args):
|
|
portrecs, portrecsbynum = sepolicy.gen_port_dict()
|
|
all_ports = []
|
|
if args.list_ports:
|
|
for i in portrecs:
|
|
if i[0] not in all_ports:
|
|
all_ports.append(i[0])
|
|
all_ports.sort()
|
|
print("\n".join(all_ports))
|
|
|
|
for port in args.port:
|
|
found = False
|
|
for i in portrecsbynum:
|
|
if i[0] <= port and port <= i[1]:
|
|
if i[0] == i[1]:
|
|
range = i[0]
|
|
else:
|
|
range = "%s-%s" % (i[0], i[1])
|
|
found = True
|
|
print("%d: %s %s %s" % (port, i[2], portrecsbynum[i][0], range))
|
|
if not found:
|
|
if port < 500:
|
|
print("Undefined reserved port type")
|
|
else:
|
|
print("Undefined port type")
|
|
|
|
for t in args.type:
|
|
if (t, 'tcp') in portrecs.keys():
|
|
print("%s: tcp: %s" % (t, ",".join(portrecs[t, 'tcp'])))
|
|
if (t, 'udp') in portrecs.keys():
|
|
print( "%s: udp: %s" % (t, ",".join(portrecs[t, 'udp'])))
|
|
|
|
for a in args.applications:
|
|
d = sepolicy.get_init_transtype(a)
|
|
if d:
|
|
args.domain.append(d)
|
|
|
|
for d in args.domain:
|
|
_print_net(d, "tcp", "name_connect")
|
|
for net in ("tcp", "udp"):
|
|
_print_net(d, net, "name_bind")
|
|
|
|
|
|
def gui_run(args):
|
|
try:
|
|
import sepolicy.gui
|
|
sepolicy.gui.SELinuxGui(args.domain, args.test)
|
|
pass
|
|
except ImportError:
|
|
raise ValueError(_("You need to install policycoreutils-gui package to use the gui option"))
|
|
|
|
|
|
def gen_gui_args(parser):
|
|
gui = parser.add_parser("gui",
|
|
help=_('Graphical User Interface for SELinux Policy'))
|
|
gui.add_argument("-d", "--domain", default=None,
|
|
action=CheckDomain,
|
|
help=_("Domain name(s) of man pages to be created"))
|
|
gui.add_argument("-t", "--test", default=False, action="store_true",
|
|
help=argparse.SUPPRESS)
|
|
gui.set_defaults(func=gui_run)
|
|
|
|
|
|
def manpage_work(domain, path, root, source_files, web):
|
|
from sepolicy.manpage import ManPage
|
|
m = ManPage(domain, path, root, source_files, web)
|
|
print(m.get_man_page_path())
|
|
return (m.manpage_domains, m.manpage_roles)
|
|
|
|
def manpage(args):
|
|
from sepolicy.manpage import HTMLManPages, gen_domains
|
|
|
|
path = args.path
|
|
if not args.policy and args.root != "/":
|
|
sepolicy.policy(sepolicy.get_installed_policy(args.root))
|
|
if args.source_files and args.root == "/":
|
|
raise ValueError(_("Alternative root needs to be setup"))
|
|
|
|
if args.all:
|
|
test_domains = gen_domains()
|
|
else:
|
|
test_domains = args.domain
|
|
|
|
manpage_domains = set()
|
|
manpage_roles = set()
|
|
p = Pool()
|
|
async_results = []
|
|
for domain in test_domains:
|
|
async_results.append(p.apply_async(manpage_work, [domain, path, args.root, args.source_files, args.web]))
|
|
for result in async_results:
|
|
domains, roles = result.get()
|
|
manpage_domains.update(domains)
|
|
manpage_roles.update(roles)
|
|
|
|
p.close()
|
|
p.join()
|
|
|
|
if args.web:
|
|
HTMLManPages(manpage_roles, manpage_domains, path, args.os)
|
|
|
|
|
|
def gen_manpage_args(parser):
|
|
man = parser.add_parser("manpage",
|
|
help=_('Generate SELinux man pages'))
|
|
|
|
man.add_argument("-p", "--path", dest="path", default="/tmp",
|
|
help=_("path in which the generated SELinux man pages will be stored"))
|
|
man.add_argument("-o", "--os", dest="os", default=get_os_version(),
|
|
help=_("name of the OS for man pages"))
|
|
man.add_argument("-w", "--web", dest="web", default=False, action="store_true",
|
|
help=_("Generate HTML man pages structure for selected SELinux man page"))
|
|
man.add_argument("-r", "--root", dest="root", default="/",
|
|
help=_("Alternate root directory, defaults to /"))
|
|
man.add_argument("--source_files", dest="source_files", default=False, action="store_true",
|
|
help=_("With this flag, alternative root path needs to include file context files and policy.xml file"))
|
|
group = man.add_mutually_exclusive_group(required=True)
|
|
group.add_argument("-a", "--all", dest="all", default=False,
|
|
action="store_true",
|
|
help=_("All domains"))
|
|
group.add_argument("-d", "--domain", nargs="+",
|
|
action=CheckDomain,
|
|
help=_("Domain name(s) of man pages to be created"))
|
|
man.set_defaults(func=manpage)
|
|
|
|
|
|
def gen_network_args(parser):
|
|
net = parser.add_parser("network",
|
|
help=_('Query SELinux policy network information'))
|
|
|
|
group = net.add_mutually_exclusive_group(required=True)
|
|
group.add_argument("-l", "--list", dest="list_ports",
|
|
action="store_true",
|
|
help=_("list all SELinux port types"))
|
|
group.add_argument("-p", "--port", dest="port", default=[],
|
|
action=CheckPort, nargs="+", type=int,
|
|
help=_("show SELinux type related to the port"))
|
|
group.add_argument("-t", "--type", dest="type", default=[],
|
|
action=CheckPortType, nargs="+",
|
|
help=_("Show ports defined for this SELinux type"))
|
|
group.add_argument("-d", "--domain", dest="domain", default=[],
|
|
action=CheckDomain, nargs="+",
|
|
help=_("show ports to which this domain can bind and/or connect"))
|
|
group.add_argument("-a", "--application", dest="applications", default=[],
|
|
nargs="+",
|
|
help=_("show ports to which this application can bind and/or connect"))
|
|
net.set_defaults(func=network)
|
|
|
|
|
|
def communicate(args):
|
|
from sepolicy.communicate import get_types
|
|
|
|
writable = get_types(args.source, args.tclass, args.sourceaccess.split(","))
|
|
readable = get_types(args.target, args.tclass, args.targetaccess.split(","))
|
|
out = list(set(writable) & set(readable))
|
|
|
|
for t in out:
|
|
print(t)
|
|
|
|
|
|
def gen_communicate_args(parser):
|
|
comm = parser.add_parser("communicate",
|
|
help=_('query SELinux policy to see if domains can communicate with each other'))
|
|
comm.add_argument("-s", "--source", dest="source",
|
|
action=CheckDomain, required=True,
|
|
help=_("Source Domain"))
|
|
comm.add_argument("-t", "--target", dest="target",
|
|
action=CheckDomain, required=True,
|
|
help=_("Target Domain"))
|
|
comm.add_argument("-c", "--class", required=False, dest="tclass",
|
|
action=CheckClass,
|
|
default="file", help="class to use for communications, Default 'file'")
|
|
comm.add_argument("-S", "--sourceaccess", required=False, dest="sourceaccess", default="open,write", help="comma separate list of permissions for the source type to use, Default 'open,write'")
|
|
comm.add_argument("-T", "--targetaccess", required=False, dest="targetaccess", default="open,read", help="comma separated list of permissions for the target type to use, Default 'open,read'")
|
|
comm.set_defaults(func=communicate)
|
|
|
|
|
|
def booleans(args):
|
|
from sepolicy import boolean_desc
|
|
if args.all:
|
|
rc, args.booleans = selinux.security_get_boolean_names()
|
|
args.booleans.sort()
|
|
|
|
for b in args.booleans:
|
|
print("%s=_(\"%s\")" % (b, boolean_desc(b)))
|
|
|
|
|
|
def gen_booleans_args(parser):
|
|
bools = parser.add_parser("booleans",
|
|
help=_('query SELinux Policy to see description of booleans'))
|
|
group = bools.add_mutually_exclusive_group(required=True)
|
|
group.add_argument("-a", "--all", dest="all", default=False,
|
|
action="store_true",
|
|
help=_("get all booleans descriptions"))
|
|
group.add_argument("-b", "--boolean", dest="booleans", nargs="+",
|
|
action=CheckBoolean, required=False,
|
|
help=_("boolean to get description"))
|
|
bools.set_defaults(func=booleans)
|
|
|
|
|
|
def transition(args):
|
|
from sepolicy.transition import setrans
|
|
mytrans = setrans(args.source, args.target)
|
|
mytrans.output()
|
|
|
|
|
|
def gen_transition_args(parser):
|
|
trans = parser.add_parser("transition",
|
|
help=_('query SELinux Policy to see how a source process domain can transition to the target process domain'))
|
|
trans.add_argument("-s", "--source", dest="source",
|
|
action=CheckDomain, required=True,
|
|
help=_("source process domain"))
|
|
trans.add_argument("-t", "--target", dest="target",
|
|
action=CheckDomain,
|
|
help=_("target process domain"))
|
|
trans.set_defaults(func=transition)
|
|
|
|
|
|
def print_interfaces(interfaces, args, append=""):
|
|
from sepolicy.interface import get_interface_format_text, interface_compile_test
|
|
for i in interfaces:
|
|
if args.verbose:
|
|
try:
|
|
print(get_interface_format_text(i + append))
|
|
except KeyError:
|
|
print(i)
|
|
if args.compile:
|
|
try:
|
|
interface_compile_test(i)
|
|
except KeyError:
|
|
print(i)
|
|
else:
|
|
print(i)
|
|
|
|
|
|
def interface(args):
|
|
from sepolicy.interface import get_admin, get_user, get_interface_dict, get_all_interfaces
|
|
if args.list_admin:
|
|
print_interfaces(get_admin(args.file), args, "_admin")
|
|
if args.list_user:
|
|
print_interfaces(get_user(args.file), args, "_role")
|
|
if args.list:
|
|
print_interfaces(get_all_interfaces(args.file), args)
|
|
if args.interfaces:
|
|
print_interfaces(args.interfaces, args)
|
|
|
|
|
|
def generate(args):
|
|
from sepolicy.generate import policy, AUSER, RUSER, EUSER, USERS, SANDBOX, APPLICATIONS, NEWTYPE
|
|
cmd = None
|
|
# numbers present POLTYPE defined in sepolicy.generate
|
|
conflict_args = {'TYPES': (NEWTYPE,), 'DOMAIN': (EUSER,), 'ADMIN_DOMAIN': (AUSER, RUSER, EUSER,)}
|
|
error_text = ""
|
|
|
|
if args.policytype is None:
|
|
generate_usage = generate_custom_usage(usage, usage_dict)
|
|
for k in usage_dict:
|
|
error_text += "%s" % (k)
|
|
print(generate_usage)
|
|
print(_("sepolicy generate: error: one of the arguments %s is required") % error_text)
|
|
sys.exit(1)
|
|
|
|
if args.policytype in APPLICATIONS:
|
|
if not args.command:
|
|
raise ValueError(_("Command required for this type of policy"))
|
|
cmd = os.path.realpath(args.command)
|
|
if not args.name:
|
|
args.name = os.path.basename(cmd).replace("-", "_")
|
|
|
|
mypolicy = policy(args.name, args.policytype)
|
|
if cmd:
|
|
mypolicy.set_program(cmd)
|
|
|
|
if args.types:
|
|
if args.policytype not in conflict_args['TYPES']:
|
|
raise ValueError(_("-t option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
|
|
mypolicy.set_types(args.types)
|
|
|
|
if args.domain:
|
|
if args.policytype not in conflict_args['DOMAIN']:
|
|
raise ValueError(_("-d option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
|
|
|
|
if args.admin_domain:
|
|
if args.policytype not in conflict_args['ADMIN_DOMAIN']:
|
|
raise ValueError(_("-a option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
|
|
|
|
if len(args.writepaths) > 0 and args.policytype == NEWTYPE:
|
|
|
|
raise ValueError(_("-w option can not be used with the --newtype option"))
|
|
|
|
for p in args.writepaths:
|
|
if os.path.isdir(p):
|
|
mypolicy.add_dir(p)
|
|
else:
|
|
mypolicy.add_file(p)
|
|
|
|
mypolicy.set_transition_users(args.user)
|
|
mypolicy.set_admin_roles(args.role)
|
|
mypolicy.set_admin_domains(args.admin_domain)
|
|
mypolicy.set_existing_domains(args.domain)
|
|
|
|
if args.policytype in APPLICATIONS:
|
|
mypolicy.gen_writeable()
|
|
mypolicy.gen_symbols()
|
|
print(mypolicy.generate(args.path))
|
|
|
|
|
|
def gen_interface_args(parser):
|
|
itf = parser.add_parser("interface",
|
|
help=_('List SELinux Policy interfaces'))
|
|
itf.add_argument("-c", "--compile", dest="compile",
|
|
action="store_true", default=False,
|
|
help="Run compile test for selected interface")
|
|
itf.add_argument("-v", "--verbose", dest="verbose",
|
|
action="store_true", default=False,
|
|
help="Show verbose information")
|
|
itf.add_argument("-f", "--file", dest="file",
|
|
help="Interface file")
|
|
group = itf.add_mutually_exclusive_group(required=True)
|
|
group.add_argument("-a", "--list_admin", dest="list_admin", action="store_true", default=False,
|
|
help="List all domains with admin interface - DOMAIN_admin()")
|
|
group.add_argument("-u", "--list_user", dest="list_user", action="store_true",
|
|
default=False,
|
|
help="List all domains with SELinux user role interface - DOMAIN_role()")
|
|
group.add_argument("-l", "--list", dest="list", action="store_true",
|
|
default=False,
|
|
help="List all interfaces")
|
|
group.add_argument("-i", "--interfaces", nargs="+", dest="interfaces",
|
|
action=InterfaceInfo,
|
|
help=_("Enter interface names, you wish to query"))
|
|
itf.set_defaults(func=interface)
|
|
|
|
|
|
def gen_generate_args(parser):
|
|
from sepolicy.generate import get_poltype_desc, poltype, DAEMON, DBUS, INETD, CGI, SANDBOX, USER, EUSER, TUSER, XUSER, LUSER, AUSER, RUSER, NEWTYPE
|
|
|
|
generate_usage = generate_custom_usage(usage, usage_dict)
|
|
|
|
pol = parser.add_parser("generate", usage=generate_usage,
|
|
help=_('Generate SELinux Policy module template'))
|
|
pol.add_argument("-d", "--domain", dest="domain", default=[],
|
|
action=CheckDomain, nargs="*",
|
|
help=_("Enter domain type which you will be extending"))
|
|
pol.add_argument("-u", "--user", dest="user", default=[],
|
|
action=CheckUser,
|
|
help=_("Enter SELinux user(s) which will transition to this domain"))
|
|
pol.add_argument("-r", "--role", dest="role", default=[],
|
|
action=CheckRole,
|
|
help=_("Enter SELinux role(s) to which the administror domain will transition"))
|
|
pol.add_argument("-a", "--admin", dest="admin_domain", default=[],
|
|
action=CheckAdmin,
|
|
help=_("Enter domain(s) which this confined admin will administrate"))
|
|
pol.add_argument("-n", "--name", dest="name",
|
|
default=None,
|
|
help=_("name of policy to generate"))
|
|
pol.add_argument("-T", "--test", dest="test", default=False, action="store_true",
|
|
help=argparse.SUPPRESS)
|
|
pol.add_argument("-t", "--type", dest="types", default=[], nargs="*",
|
|
action=CheckType,
|
|
help="Enter type(s) for which you will generate new definition and rule(s)")
|
|
pol.add_argument("-p", "--path", dest="path", default=os.getcwd(),
|
|
help=_("path in which the generated policy files will be stored"))
|
|
pol.add_argument("-w", "--writepath", dest="writepaths", nargs="*", default=[],
|
|
help=_("path to which the confined processes will need to write"))
|
|
cmdtype = pol.add_argument_group(_("Policy types which require a command"))
|
|
cmdgroup = cmdtype.add_mutually_exclusive_group(required=False)
|
|
cmdgroup.add_argument("--application", dest="policytype", const=USER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[USER])
|
|
cmdgroup.add_argument("--cgi", dest="policytype", const=CGI,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[CGI])
|
|
cmdgroup.add_argument("--dbus", dest="policytype", const=DBUS,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[DBUS])
|
|
cmdgroup.add_argument("--inetd", dest="policytype", const=INETD,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[INETD])
|
|
cmdgroup.add_argument("--init", dest="policytype", const=DAEMON,
|
|
action="store_const", default=DAEMON,
|
|
help=_("Generate '%s' policy") % poltype[DAEMON])
|
|
|
|
type = pol.add_argument_group("Policy types which do not require a command")
|
|
group = type.add_mutually_exclusive_group(required=False)
|
|
group.add_argument("--admin_user", dest="policytype", const=AUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[AUSER])
|
|
group.add_argument("--confined_admin", dest="policytype", const=RUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[RUSER])
|
|
group.add_argument("--customize", dest="policytype", const=EUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[EUSER])
|
|
group.add_argument("--desktop_user", dest="policytype", const=LUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy ") % poltype[LUSER])
|
|
group.add_argument("--newtype", dest="policytype", const=NEWTYPE,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[NEWTYPE])
|
|
group.add_argument("--sandbox", dest="policytype", const=SANDBOX,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[SANDBOX])
|
|
group.add_argument("--term_user", dest="policytype", const=TUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[TUSER])
|
|
group.add_argument("--x_user", dest="policytype", const=XUSER,
|
|
action="store_const",
|
|
help=_("Generate '%s' policy") % poltype[XUSER])
|
|
pol.add_argument("command", nargs="?", default=None,
|
|
help=_("executable to confine"))
|
|
pol.set_defaults(func=generate)
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(description='SELinux Policy Inspection Tool')
|
|
subparsers = parser.add_subparsers(help=_("commands"))
|
|
parser.add_argument("-P", "--policy", dest="policy",
|
|
action=LoadPolicy,
|
|
default=None, help=_("Alternate SELinux policy, defaults to /sys/fs/selinux/policy"))
|
|
gen_booleans_args(subparsers)
|
|
gen_communicate_args(subparsers)
|
|
gen_generate_args(subparsers)
|
|
gen_gui_args(subparsers)
|
|
gen_interface_args(subparsers)
|
|
gen_manpage_args(subparsers)
|
|
gen_network_args(subparsers)
|
|
gen_transition_args(subparsers)
|
|
|
|
try:
|
|
if os.path.basename(sys.argv[0]) == "sepolgen":
|
|
parser_args = [ "generate" ] + sys.argv[1:]
|
|
elif len(sys.argv) > 1:
|
|
parser_args = sys.argv[1:]
|
|
else:
|
|
parser_args = ["-h"]
|
|
args = parser.parse_args(args=parser_args)
|
|
args.func(args)
|
|
sys.exit(0)
|
|
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:
|
|
print("Out")
|
|
sys.exit(0)
|