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