1#!/usr/bin/python
2# Copyright 2014-2015, Tresys Technology, LLC
3#
4# This file is part of SETools.
5#
6# SETools is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 2 of the License, or
9# (at your option) any later version.
10#
11# SETools is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with SETools.  If not, see <http://www.gnu.org/licenses/>.
18#
19
20from __future__ import print_function
21import setools
22import argparse
23import sys
24import logging
25
26parser = argparse.ArgumentParser(
27    description="SELinux policy rule search tool.",
28    epilog="TE/MLS rule searches cannot be mixed with RBAC rule searches.")
29parser.add_argument("--version", action="version", version=setools.__version__)
30parser.add_argument("policy", help="Path to the SELinux policy to search.", nargs="?")
31parser.add_argument("-v", "--verbose", action="store_true",
32                    help="Print extra informational messages")
33parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.")
34
35rtypes = parser.add_argument_group("TE Rule Types")
36rtypes.add_argument("-A", "--allow", action="append_const",
37                    const="allow", dest="tertypes",
38                    help="Search allow rules.")
39rtypes.add_argument("--auditallow", action="append_const",
40                    const="auditallow", dest="tertypes",
41                    help="Search auditallow rules.")
42rtypes.add_argument("--dontaudit", action="append_const",
43                    const="dontaudit", dest="tertypes",
44                    help="Search dontaudit rules.")
45rtypes.add_argument("-T", "--type_trans", action="append_const",
46                    const="type_transition", dest="tertypes",
47                    help="Search type_transition rules.")
48rtypes.add_argument("--type_change", action="append_const",
49                    const="type_change", dest="tertypes",
50                    help="Search type_change rules.")
51rtypes.add_argument("--type_member", action="append_const",
52                    const="type_member", dest="tertypes",
53                    help="Search type_member rules.")
54
55rbacrtypes = parser.add_argument_group("RBAC Rule Types")
56rbacrtypes.add_argument("--role_allow", action="append_const",
57                        const="allow", dest="rbacrtypes",
58                        help="Search role allow rules.")
59rbacrtypes.add_argument("--role_trans", action="append_const",
60                        const="role_transition", dest="rbacrtypes",
61                        help="Search role_transition rules.")
62
63mlsrtypes = parser.add_argument_group("MLS Rule Types")
64mlsrtypes.add_argument("--range_trans", action="append_const",
65                       const="range_transition", dest="mlsrtypes",
66                       help="Search range_transition rules.")
67
68expr = parser.add_argument_group("Expressions")
69expr.add_argument("-s", "--source",
70                  help="Source type/role of the TE/RBAC rule.")
71expr.add_argument("-t", "--target",
72                  help="Target type/role of the TE/RBAC rule.")
73expr.add_argument("-c", "--class", dest="tclass",
74                  help="Comma separated list of object classes")
75expr.add_argument("-p", "--perms", metavar="PERMS",
76                  help="Comma separated list of permissions.")
77expr.add_argument("-D", "--default",
78                  help="Default of the rule. (type/role/range transition rules)")
79expr.add_argument("-b", "--bool", dest="boolean", metavar="BOOL",
80                  help="Comma separated list of Booleans in the conditional expression.")
81
82opts = parser.add_argument_group("Search options")
83opts.add_argument("-eb", action="store_true", dest="boolean_equal",
84                  help="Match Boolean list exactly instead of matching any listed Boolean.")
85opts.add_argument("-ep", action="store_true", dest="perms_equal",
86                  help="Match permission set exactly instead of matching any listed permission.")
87opts.add_argument("-ds", action="store_false", dest="source_indirect",
88                  help="Match source attributes directly instead of matching member types/roles.")
89opts.add_argument("-dt", action="store_false", dest="target_indirect",
90                  help="Match target attributes directly instead of matching member types/roles.")
91opts.add_argument("-rs", action="store_true", dest="source_regex",
92                  help="Use regular expression matching for the source type/role.")
93opts.add_argument("-rt", action="store_true", dest="target_regex",
94                  help="Use regular expression matching for the target type/role.")
95opts.add_argument("-rc", action="store_true", dest="tclass_regex",
96                  help="Use regular expression matching for the object class.")
97opts.add_argument("-rd", action="store_true", dest="default_regex",
98                  help="Use regular expression matching for the default type/role.")
99opts.add_argument("-rb", action="store_true", dest="boolean_regex",
100                  help="Use regular expression matching for Booleans.")
101
102args = parser.parse_args()
103
104if not args.tertypes and not args.mlsrtypes and not args.rbacrtypes:
105    parser.error("At least one rule type must be specified.")
106
107if args.debug:
108    logging.basicConfig(level=logging.DEBUG,
109                        format='%(asctime)s|%(levelname)s|%(name)s|%(message)s')
110elif args.verbose:
111    logging.basicConfig(level=logging.INFO, format='%(message)s')
112else:
113    logging.basicConfig(level=logging.WARNING, format='%(message)s')
114
115try:
116    p = setools.SELinuxPolicy(args.policy)
117
118    if args.tertypes:
119        q = setools.TERuleQuery(p,
120                                ruletype=args.tertypes,
121                                source=args.source,
122                                source_indirect=args.source_indirect,
123                                source_regex=args.source_regex,
124                                target=args.target,
125                                target_indirect=args.target_indirect,
126                                target_regex=args.target_regex,
127                                tclass_regex=args.tclass_regex,
128                                perms_equal=args.perms_equal,
129                                default=args.default,
130                                default_regex=args.default_regex,
131                                boolean_regex=args.boolean_regex,
132                                boolean_equal=args.boolean_equal)
133
134        # these are broken out from the above statement to prevent making a list
135        # with an empty string in it (split on empty string)
136        if args.tclass:
137            if args.tclass_regex:
138                q.tclass = args.tclass
139            else:
140                q.tclass = args.tclass.split(",")
141
142        if args.perms:
143            q.perms = args.perms.split(",")
144
145        if args.boolean:
146            if args.boolean_regex:
147                q.boolean = args.boolean
148            else:
149                q.boolean = args.boolean.split(",")
150
151        for r in sorted(q.results()):
152            print(r)
153
154    if args.rbacrtypes:
155        q = setools.RBACRuleQuery(p,
156                                  ruletype=args.rbacrtypes,
157                                  source=args.source,
158                                  source_indirect=args.source_indirect,
159                                  source_regex=args.source_regex,
160                                  target=args.target,
161                                  target_indirect=args.target_indirect,
162                                  target_regex=args.target_regex,
163                                  default=args.default,
164                                  default_regex=args.default_regex,
165                                  tclass_regex=args.tclass_regex)
166
167        # these are broken out from the above statement to prevent making a list
168        # with an empty string in it (split on empty string)
169        if args.tclass:
170            if args.tclass_regex:
171                q.tclass = args.tclass
172            else:
173                q.tclass = args.tclass.split(",")
174
175        for r in sorted(q.results()):
176            print(r)
177
178    if args.mlsrtypes:
179        q = setools.MLSRuleQuery(p,
180                                 ruletype=args.mlsrtypes,
181                                 source=args.source,
182                                 source_regex=args.source_regex,
183                                 target=args.target,
184                                 target_regex=args.target_regex,
185                                 tclass_regex=args.tclass_regex,
186                                 default=args.default)
187
188        # these are broken out from the above statement to prevent making a list
189        # with an empty string in it (split on empty string)
190        if args.tclass:
191            if args.tclass_regex:
192                q.tclass = args.tclass
193            else:
194                q.tclass = args.tclass.split(",")
195
196        for r in sorted(q.results()):
197            print(r)
198
199except Exception as err:
200    if args.debug:
201        import traceback
202        traceback.print_exc()
203    else:
204        print(err)
205
206    sys.exit(-1)
207