• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3 -Es
2# Copyright (C) 2012 Red Hat
3# AUTHOR: Dan Walsh <dwalsh@redhat.com>
4# see file 'COPYING' for use and warranty information
5#
6# semanage is a tool for managing SELinux configuration files
7#
8#    This program is free software; you can redistribute it and/or
9#    modify it under the terms of the GNU General Public License as
10#    published by the Free Software Foundation; either version 2 of
11#    the License, or (at your option) any later version.
12#
13#    This program is distributed in the hope that it will be useful,
14#    but WITHOUT ANY WARRANTY; without even the implied warranty of
15#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16#    GNU General Public License for more details.
17#
18#    You should have received a copy of the GNU General Public License
19#    along with this program; if not, write to the Free Software
20#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21#                                        02111-1307  USA
22#
23#
24import os
25import sys
26import selinux
27import sepolicy
28from sepolicy import get_os_version, get_conditionals, get_conditionals_format_text
29import argparse
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
48usage = "sepolicy generate [-h] [-n NAME] [-p PATH] ["
49usage_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 ]",)}
50
51
52class CheckPath(argparse.Action):
53
54    def __call__(self, parser, namespace, values, option_string=None):
55        if not os.path.exists(values):
56            raise ValueError("%s does not exist" % values)
57        setattr(namespace, self.dest, values)
58
59
60class CheckType(argparse.Action):
61
62    def __call__(self, parser, namespace, values, option_string=None):
63        if isinstance(values, str):
64            setattr(namespace, self.dest, values)
65        else:
66            newval = getattr(namespace, self.dest)
67            if not newval:
68                newval = []
69
70            for v in values:
71                newval.append(v)
72            setattr(namespace, self.dest, newval)
73
74
75class CheckBoolean(argparse.Action):
76
77    def __call__(self, parser, namespace, values, option_string=None):
78        booleans = sepolicy.get_all_booleans()
79        newval = getattr(namespace, self.dest)
80        if not newval:
81            newval = []
82
83        if isinstance(values, str):
84            v = selinux.selinux_boolean_sub(values)
85            if v not in booleans:
86                raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (v, ", ".join(booleans)))
87            newval.append(v)
88            setattr(namespace, self.dest, newval)
89        else:
90            for value in values:
91                v = selinux.selinux_boolean_sub(value)
92                if v not in booleans:
93                    raise ValueError("%s must be an SELinux boolean:\nValid boolean: %s" % (v, ", ".join(booleans)))
94                newval.append(v)
95            setattr(namespace, self.dest, newval)
96
97
98class CheckDomain(argparse.Action):
99
100    def __call__(self, parser, namespace, values, option_string=None):
101        domains = sepolicy.get_all_domains()
102
103        if isinstance(values, str):
104            values = sepolicy.get_real_type_name(values)
105            if values not in domains:
106                raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (values, ", ".join(domains)))
107            setattr(namespace, self.dest, values)
108        else:
109            newval = getattr(namespace, self.dest)
110            if not newval:
111                newval = []
112
113            for v in values:
114                v = sepolicy.get_real_type_name(v)
115                if v not in domains:
116                    raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (v, ", ".join(domains)))
117                newval.append(v)
118            setattr(namespace, self.dest, newval)
119
120all_classes = None
121
122
123class CheckClass(argparse.Action):
124
125    def __call__(self, parser, namespace, values, option_string=None):
126        global all_classes
127        if not all_classes:
128            all_classes = map(lambda x: x['name'], sepolicy.info(sepolicy.TCLASS))
129        if values not in all_classes:
130            raise ValueError("%s must be an SELinux class:\nValid classes: %s" % (values, ", ".join(all_classes)))
131
132        setattr(namespace, self.dest, values)
133
134
135class CheckAdmin(argparse.Action):
136
137    def __call__(self, parser, namespace, values, option_string=None):
138        from sepolicy.interface import get_admin
139        newval = getattr(namespace, self.dest)
140        if not newval:
141            newval = []
142        admins = get_admin()
143        if values not in admins:
144            raise ValueError("%s must be an SELinux admin domain:\nValid admin domains: %s" % (values, ", ".join(admins)))
145        newval.append(values)
146        setattr(namespace, self.dest, newval)
147
148
149class CheckPort(argparse.Action):
150
151    def __call__(self, parser, namespace, values, option_string=None):
152        newval = getattr(namespace, self.dest)
153        if not newval:
154            newval = []
155        for v in values:
156            if v < 1 or v > 65536:
157                raise ValueError("%s must be an integer between 1 and 65536" % v)
158            newval.append(v)
159        setattr(namespace, self.dest, newval)
160
161
162class CheckPortType(argparse.Action):
163
164    def __call__(self, parser, namespace, values, option_string=None):
165        port_types = sepolicy.get_all_port_types()
166        newval = getattr(namespace, self.dest)
167        if not newval:
168            newval = []
169        for v in values:
170            v = sepolicy.get_real_type_name(v)
171            if v not in port_types:
172                raise ValueError("%s must be an SELinux port type:\nValid port types: %s" % (v, ", ".join(port_types)))
173            newval.append(v)
174        setattr(namespace, self.dest, newval)
175
176
177class LoadPolicy(argparse.Action):
178
179    def __call__(self, parser, namespace, values, option_string=None):
180        import sepolicy
181        sepolicy.policy(values)
182        setattr(namespace, self.dest, values)
183
184
185class CheckUser(argparse.Action):
186
187    def __call__(self, parser, namespace, value, option_string=None):
188        newval = getattr(namespace, self.dest)
189        if not newval:
190            newval = []
191        users = sepolicy.get_all_users()
192        if value not in users:
193            raise ValueError("%s must be an SELinux user:\nValid users: %s" % (value, ", ".join(users)))
194        newval.append(value)
195        setattr(namespace, self.dest, newval)
196
197
198class CheckRole(argparse.Action):
199
200    def __call__(self, parser, namespace, value, option_string=None):
201        newval = getattr(namespace, self.dest)
202        if not newval:
203            newval = []
204        roles = sepolicy.get_all_roles()
205        if value not in roles:
206            raise ValueError("%s must be an SELinux role:\nValid roles: %s" % (value, ", ".join(roles)))
207        newval.append(value[:-2])
208        setattr(namespace, self.dest, newval)
209
210
211class InterfaceInfo(argparse.Action):
212
213    def __call__(self, parser, namespace, values, option_string=None):
214        from sepolicy.interface import get_interface_dict
215        interface_dict = get_interface_dict()
216        for v in values:
217            if v not in interface_dict.keys():
218                raise ValueError(_("Interface %s does not exist.") % v)
219
220        setattr(namespace, self.dest, values)
221
222
223def generate_custom_usage(usage_text, usage_dict):
224    sorted_keys = []
225    for i in usage_dict.keys():
226        sorted_keys.append(i)
227    sorted_keys.sort()
228    for k in sorted_keys:
229        usage_text += "%s %s |" % (k, (" ".join(usage_dict[k])))
230    usage_text = usage_text[:-1] + "]"
231    usage_text = _(usage_text)
232
233    return usage_text
234
235# expects formats:
236# "22 (sshd_t)", "80, 8080 (httpd_t)", "all ports (port_type)"
237def port_string_to_num(val):
238    try:
239        return int(val.split(" ")[0].split(",")[0].split("-")[0])
240    except:
241        return 99999999
242
243
244def _print_net(src, protocol, perm):
245    import sepolicy.network
246    portdict = sepolicy.network.get_network_connect(src, protocol, perm)
247    if len(portdict) > 0:
248        bold_start = "\033[1m"
249        bold_end = "\033[0;0m"
250        print("\n" + bold_start + "%s: %s %s" % (src, protocol, perm) + bold_end)
251        port_strings = []
252        boolean_text = ""
253        for p in portdict:
254            for t, recs in portdict[p]:
255                cond = get_conditionals(src, t, "%s_socket" % protocol, [perm])
256                if cond:
257                    boolean_text = get_conditionals_format_text(cond)
258                    port_strings.append("%s (%s) %s" % (", ".join(recs), t, boolean_text))
259                else:
260                    port_strings.append("%s (%s)" % (", ".join(recs), t))
261        port_strings.sort(key=lambda param: port_string_to_num(param))
262        for p in port_strings:
263            print("\t" + p)
264
265
266def network(args):
267    portrecs, portrecsbynum = sepolicy.gen_port_dict()
268    all_ports = []
269    if args.list_ports:
270        for i in portrecs:
271            if i[0] not in all_ports:
272                all_ports.append(i[0])
273        all_ports.sort()
274        print("\n".join(all_ports))
275
276    for port in args.port:
277        found = False
278        for i in portrecsbynum:
279            if i[0] <= port and port <= i[1]:
280                if i[0] == i[1]:
281                    range = i[0]
282                else:
283                    range = "%s-%s" % (i[0], i[1])
284                found = True
285                print("%d: %s %s %s" % (port, i[2], portrecsbynum[i][0], range))
286        if not found:
287            if port < 500:
288                print("Undefined reserved port type")
289            else:
290                print("Undefined port type")
291
292    for t in args.type:
293        if (t, 'tcp') in portrecs.keys():
294            print("%s: tcp: %s" % (t, ",".join(portrecs[t, 'tcp'])))
295        if (t, 'udp') in portrecs.keys():
296            print( "%s: udp: %s" % (t, ",".join(portrecs[t, 'udp'])))
297
298    for a in args.applications:
299        d = sepolicy.get_init_transtype(a)
300        if d:
301            args.domain.append(d)
302
303    for d in args.domain:
304        _print_net(d, "tcp", "name_connect")
305        for net in ("tcp", "udp"):
306            _print_net(d, net, "name_bind")
307
308
309def gui_run(args):
310    try:
311        import sepolicy.gui
312        sepolicy.gui.SELinuxGui(args.domain, args.test)
313        pass
314    except ImportError:
315        raise ValueError(_("You need to install policycoreutils-gui package to use the gui option"))
316
317
318def gen_gui_args(parser):
319    gui = parser.add_parser("gui",
320                            help=_('Graphical User Interface for SELinux Policy'))
321    gui.add_argument("-d", "--domain", default=None,
322                     action=CheckDomain,
323                     help=_("Domain name(s) of man pages to be created"))
324    gui.add_argument("-t", "--test", default=False, action="store_true",
325                     help=argparse.SUPPRESS)
326    gui.set_defaults(func=gui_run)
327
328
329def manpage(args):
330    from sepolicy.manpage import ManPage, HTMLManPages, manpage_domains, manpage_roles, gen_domains
331
332    path = args.path
333    if not args.policy and args.root != "/":
334        sepolicy.policy(sepolicy.get_installed_policy(args.root))
335    if args.source_files and args.root == "/":
336        raise ValueError(_("Alternative root needs to be setup"))
337
338    if args.all:
339        test_domains = gen_domains()
340    else:
341        test_domains = args.domain
342
343    for domain in test_domains:
344        m = ManPage(domain, path, args.root, args.source_files, args.web)
345        print(m.get_man_page_path())
346
347    if args.web:
348        HTMLManPages(manpage_roles, manpage_domains, path, args.os)
349
350
351def gen_manpage_args(parser):
352    man = parser.add_parser("manpage",
353                            help=_('Generate SELinux man pages'))
354
355    man.add_argument("-p", "--path", dest="path", default="/tmp",
356                     help=_("path in which the generated SELinux man pages will be stored"))
357    man.add_argument("-o", "--os", dest="os", default=get_os_version(),
358                     help=_("name of the OS for man pages"))
359    man.add_argument("-w", "--web", dest="web", default=False, action="store_true",
360                     help=_("Generate HTML man pages structure for selected SELinux man page"))
361    man.add_argument("-r", "--root", dest="root", default="/",
362                     help=_("Alternate root directory, defaults to /"))
363    man.add_argument("--source_files", dest="source_files", default=False, action="store_true",
364                     help=_("With this flag, alternative root path needs to include file context files and policy.xml file"))
365    group = man.add_mutually_exclusive_group(required=True)
366    group.add_argument("-a", "--all", dest="all", default=False,
367                       action="store_true",
368                       help=_("All domains"))
369    group.add_argument("-d", "--domain", nargs="+",
370                       action=CheckDomain,
371                       help=_("Domain name(s) of man pages to be created"))
372    man.set_defaults(func=manpage)
373
374
375def gen_network_args(parser):
376    net = parser.add_parser("network",
377                            help=_('Query SELinux policy network information'))
378
379    group = net.add_mutually_exclusive_group(required=True)
380    group.add_argument("-l", "--list", dest="list_ports",
381                       action="store_true",
382                       help=_("list all SELinux port types"))
383    group.add_argument("-p", "--port", dest="port", default=[],
384                       action=CheckPort, nargs="+", type=int,
385                       help=_("show SELinux type related to the port"))
386    group.add_argument("-t", "--type", dest="type", default=[],
387                       action=CheckPortType, nargs="+",
388                       help=_("Show ports defined for this SELinux type"))
389    group.add_argument("-d", "--domain", dest="domain", default=[],
390                       action=CheckDomain, nargs="+",
391                       help=_("show ports to which this domain can bind and/or connect"))
392    group.add_argument("-a", "--application", dest="applications", default=[],
393                       nargs="+",
394                       help=_("show ports to which this application can bind and/or connect"))
395    net.set_defaults(func=network)
396
397
398def communicate(args):
399    from sepolicy.communicate import get_types
400
401    writable = get_types(args.source, args.tclass, args.sourceaccess.split(","))
402    readable = get_types(args.target, args.tclass, args.targetaccess.split(","))
403    out = list(set(writable) & set(readable))
404
405    for t in out:
406        print(t)
407
408
409def gen_communicate_args(parser):
410    comm = parser.add_parser("communicate",
411                             help=_('query SELinux policy to see if domains can communicate with each other'))
412    comm.add_argument("-s", "--source", dest="source",
413                      action=CheckDomain, required=True,
414                      help=_("Source Domain"))
415    comm.add_argument("-t", "--target", dest="target",
416                      action=CheckDomain, required=True,
417                      help=_("Target Domain"))
418    comm.add_argument("-c", "--class", required=False, dest="tclass",
419                      action=CheckClass,
420                      default="file", help="class to use for communications, Default 'file'")
421    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'")
422    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'")
423    comm.set_defaults(func=communicate)
424
425
426def booleans(args):
427    from sepolicy import boolean_desc
428    if args.all:
429        rc, args.booleans = selinux.security_get_boolean_names()
430    args.booleans.sort()
431
432    for b in args.booleans:
433        print("%s=_(\"%s\")" % (b, boolean_desc(b)))
434
435
436def gen_booleans_args(parser):
437    bools = parser.add_parser("booleans",
438                              help=_('query SELinux Policy to see description of booleans'))
439    group = bools.add_mutually_exclusive_group(required=True)
440    group.add_argument("-a", "--all", dest="all", default=False,
441                       action="store_true",
442                       help=_("get all booleans descriptions"))
443    group.add_argument("-b", "--boolean", dest="booleans", nargs="+",
444                       action=CheckBoolean, required=False,
445                       help=_("boolean to get description"))
446    bools.set_defaults(func=booleans)
447
448
449def transition(args):
450    from sepolicy.transition import setrans
451    mytrans = setrans(args.source, args.target)
452    mytrans.output()
453
454
455def gen_transition_args(parser):
456    trans = parser.add_parser("transition",
457                              help=_('query SELinux Policy to see how a source process domain can transition to the target process domain'))
458    trans.add_argument("-s", "--source", dest="source",
459                       action=CheckDomain, required=True,
460                       help=_("source process domain"))
461    trans.add_argument("-t", "--target", dest="target",
462                       action=CheckDomain,
463                       help=_("target process domain"))
464    trans.set_defaults(func=transition)
465
466
467def print_interfaces(interfaces, args, append=""):
468    from sepolicy.interface import get_interface_format_text, interface_compile_test
469    for i in interfaces:
470        if args.verbose:
471            try:
472                print(get_interface_format_text(i + append))
473            except KeyError:
474                print(i)
475        if args.compile:
476            try:
477                interface_compile_test(i)
478            except KeyError:
479                print(i)
480        else:
481            print(i)
482
483
484def interface(args):
485    from sepolicy.interface import get_admin, get_user, get_interface_dict, get_all_interfaces
486    if args.list_admin:
487        print_interfaces(get_admin(args.file), args, "_admin")
488    if args.list_user:
489        print_interfaces(get_user(args.file), args, "_role")
490    if args.list:
491        print_interfaces(get_all_interfaces(args.file), args)
492    if args.interfaces:
493        print_interfaces(args.interfaces, args)
494
495
496def generate(args):
497    from sepolicy.generate import policy, AUSER, RUSER, EUSER, USERS, SANDBOX, APPLICATIONS, NEWTYPE
498    cmd = None
499# numbers present POLTYPE defined in sepolicy.generate
500    conflict_args = {'TYPES': (NEWTYPE,), 'DOMAIN': (EUSER,), 'ADMIN_DOMAIN': (AUSER, RUSER, EUSER,)}
501    error_text = ""
502
503    if args.policytype is None:
504        generate_usage = generate_custom_usage(usage, usage_dict)
505        for k in usage_dict:
506            error_text += "%s" % (k)
507        print(generate_usage)
508        print(_("sepolicy generate: error: one of the arguments %s is required") % error_text)
509        sys.exit(1)
510
511    if args.policytype in APPLICATIONS:
512        if not args.command:
513            raise ValueError(_("Command required for this type of policy"))
514        cmd = os.path.realpath(args.command)
515        if not args.name:
516            args.name = os.path.basename(cmd).replace("-", "_")
517
518    mypolicy = policy(args.name, args.policytype)
519    if cmd:
520        mypolicy.set_program(cmd)
521
522    if args.types:
523        if args.policytype not in conflict_args['TYPES']:
524            raise ValueError(_("-t option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
525        mypolicy.set_types(args.types)
526
527    if args.domain:
528        if args.policytype not in conflict_args['DOMAIN']:
529            raise ValueError(_("-d option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
530
531    if args.admin_domain:
532        if args.policytype not in conflict_args['ADMIN_DOMAIN']:
533            raise ValueError(_("-a option can not be used with '%s' domains. Read usage for more details.") % sepolicy.generate.poltype[args.policytype])
534
535    if len(args.writepaths) > 0 and args.policytype == NEWTYPE:
536
537        raise ValueError(_("-w option can not be used with the --newtype option"))
538
539    for p in args.writepaths:
540        if os.path.isdir(p):
541            mypolicy.add_dir(p)
542        else:
543            mypolicy.add_file(p)
544
545    mypolicy.set_transition_users(args.user)
546    mypolicy.set_admin_roles(args.role)
547    mypolicy.set_admin_domains(args.admin_domain)
548    mypolicy.set_existing_domains(args.domain)
549
550    if args.policytype in APPLICATIONS:
551        mypolicy.gen_writeable()
552        mypolicy.gen_symbols()
553    print(mypolicy.generate(args.path))
554
555
556def gen_interface_args(parser):
557    itf = parser.add_parser("interface",
558                            help=_('List SELinux Policy interfaces'))
559    itf.add_argument("-c", "--compile", dest="compile",
560                     action="store_true", default=False,
561                     help="Run compile test for selected interface")
562    itf.add_argument("-v", "--verbose", dest="verbose",
563                     action="store_true", default=False,
564                     help="Show verbose information")
565    itf.add_argument("-f", "--file", dest="file",
566                     help="Interface file")
567    group = itf.add_mutually_exclusive_group(required=True)
568    group.add_argument("-a", "--list_admin", dest="list_admin", action="store_true", default=False,
569                       help="List all domains with admin interface - DOMAIN_admin()")
570    group.add_argument("-u", "--list_user", dest="list_user", action="store_true",
571                       default=False,
572                       help="List all domains with SELinux user role interface - DOMAIN_role()")
573    group.add_argument("-l", "--list", dest="list", action="store_true",
574                       default=False,
575                       help="List all interfaces")
576    group.add_argument("-i", "--interfaces", nargs="+", dest="interfaces",
577                       action=InterfaceInfo,
578                       help=_("Enter interface names, you wish to query"))
579    itf.set_defaults(func=interface)
580
581
582def gen_generate_args(parser):
583    from sepolicy.generate import get_poltype_desc, poltype, DAEMON, DBUS, INETD, CGI, SANDBOX, USER, EUSER, TUSER, XUSER, LUSER, AUSER, RUSER, NEWTYPE
584
585    generate_usage = generate_custom_usage(usage, usage_dict)
586
587    pol = parser.add_parser("generate", usage=generate_usage,
588                            help=_('Generate SELinux Policy module template'))
589    pol.add_argument("-d", "--domain", dest="domain", default=[],
590                     action=CheckDomain, nargs="*",
591                     help=_("Enter domain type which you will be extending"))
592    pol.add_argument("-u", "--user", dest="user", default=[],
593                     action=CheckUser,
594                     help=_("Enter SELinux user(s) which will transition to this domain"))
595    pol.add_argument("-r", "--role", dest="role", default=[],
596                     action=CheckRole,
597                     help=_("Enter SELinux role(s) to which the administror domain will transition"))
598    pol.add_argument("-a", "--admin", dest="admin_domain", default=[],
599                     action=CheckAdmin,
600                     help=_("Enter domain(s) which this confined admin will administrate"))
601    pol.add_argument("-n", "--name", dest="name",
602                     default=None,
603                     help=_("name of policy to generate"))
604    pol.add_argument("-T", "--test", dest="test", default=False, action="store_true",
605                     help=argparse.SUPPRESS)
606    pol.add_argument("-t", "--type", dest="types", default=[], nargs="*",
607                     action=CheckType,
608                     help="Enter type(s) for which you will generate new definition and rule(s)")
609    pol.add_argument("-p", "--path", dest="path", default=os.getcwd(),
610                     help=_("path in which the generated policy files will be stored"))
611    pol.add_argument("-w", "--writepath", dest="writepaths", nargs="*", default=[],
612                     help=_("path to which the confined processes will need to write"))
613    cmdtype = pol.add_argument_group(_("Policy types which require a command"))
614    cmdgroup = cmdtype.add_mutually_exclusive_group(required=False)
615    cmdgroup.add_argument("--application", dest="policytype", const=USER,
616                          action="store_const",
617                          help=_("Generate '%s' policy") % poltype[USER])
618    cmdgroup.add_argument("--cgi", dest="policytype", const=CGI,
619                          action="store_const",
620                          help=_("Generate '%s' policy") % poltype[CGI])
621    cmdgroup.add_argument("--dbus", dest="policytype", const=DBUS,
622                          action="store_const",
623                          help=_("Generate '%s' policy") % poltype[DBUS])
624    cmdgroup.add_argument("--inetd", dest="policytype", const=INETD,
625                          action="store_const",
626                          help=_("Generate '%s' policy") % poltype[INETD])
627    cmdgroup.add_argument("--init", dest="policytype", const=DAEMON,
628                          action="store_const", default=DAEMON,
629                          help=_("Generate '%s' policy") % poltype[DAEMON])
630
631    type = pol.add_argument_group("Policy types which do not require a command")
632    group = type.add_mutually_exclusive_group(required=False)
633    group.add_argument("--admin_user", dest="policytype", const=AUSER,
634                       action="store_const",
635                       help=_("Generate '%s' policy") % poltype[AUSER])
636    group.add_argument("--confined_admin", dest="policytype", const=RUSER,
637                       action="store_const",
638                       help=_("Generate '%s' policy") % poltype[RUSER])
639    group.add_argument("--customize", dest="policytype", const=EUSER,
640                       action="store_const",
641                       help=_("Generate '%s' policy") % poltype[EUSER])
642    group.add_argument("--desktop_user", dest="policytype", const=LUSER,
643                       action="store_const",
644                       help=_("Generate '%s' policy ") % poltype[LUSER])
645    group.add_argument("--newtype", dest="policytype", const=NEWTYPE,
646                       action="store_const",
647                       help=_("Generate '%s' policy") % poltype[NEWTYPE])
648    group.add_argument("--sandbox", dest="policytype", const=SANDBOX,
649                       action="store_const",
650                       help=_("Generate '%s' policy") % poltype[SANDBOX])
651    group.add_argument("--term_user", dest="policytype", const=TUSER,
652                       action="store_const",
653                       help=_("Generate '%s' policy") % poltype[TUSER])
654    group.add_argument("--x_user", dest="policytype", const=XUSER,
655                       action="store_const",
656                       help=_("Generate '%s' policy") % poltype[XUSER])
657    pol.add_argument("command", nargs="?", default=None,
658                     help=_("executable to confine"))
659    pol.set_defaults(func=generate)
660
661if __name__ == '__main__':
662    parser = argparse.ArgumentParser(description='SELinux Policy Inspection Tool')
663    subparsers = parser.add_subparsers(help=_("commands"))
664    parser.add_argument("-P", "--policy", dest="policy",
665                        action=LoadPolicy,
666                        default=None, help=_("Alternate SELinux policy, defaults to /sys/fs/selinux/policy"))
667    gen_booleans_args(subparsers)
668    gen_communicate_args(subparsers)
669    gen_generate_args(subparsers)
670    gen_gui_args(subparsers)
671    gen_interface_args(subparsers)
672    gen_manpage_args(subparsers)
673    gen_network_args(subparsers)
674    gen_transition_args(subparsers)
675
676    try:
677        if os.path.basename(sys.argv[0]) == "sepolgen":
678            parser_args = [ "generate" ] + sys.argv[1:]
679        elif len(sys.argv) > 1:
680            parser_args = sys.argv[1:]
681        else:
682            parser_args = ["-h"]
683        args = parser.parse_args(args=parser_args)
684        args.func(args)
685        sys.exit(0)
686    except ValueError as e:
687        sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
688        sys.exit(1)
689    except IOError as e:
690        sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
691        sys.exit(1)
692    except KeyboardInterrupt:
693        print("Out")
694        sys.exit(0)
695