1# Copyright 2014-2015, Tresys Technology, LLC
2#
3# This file is part of SETools.
4#
5# SETools is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as
7# published by the Free Software Foundation, either version 2.1 of
8# the License, or (at your option) any later version.
9#
10# SETools is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public
16# License along with SETools.  If not, see
17# <http://www.gnu.org/licenses/>.
18#
19import logging
20import re
21
22from . import mixins, query
23from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, RuletypeDescriptor
24from .policyrep.exception import RuleUseError, RuleNotConditional
25
26
27class TERuleQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery):
28
29    """
30    Query the Type Enforcement rules.
31
32    Parameter:
33    policy            The policy to query.
34
35    Keyword Parameters/Class attributes:
36    ruletype          The list of rule type(s) to match.
37    source            The name of the source type/attribute to match.
38    source_indirect   If true, members of an attribute will be
39                      matched rather than the attribute itself.
40                      Default is true.
41    source_regex      If true, regular expression matching will
42                      be used on the source type/attribute.
43                      Obeys the source_indirect option.
44                      Default is false.
45    target            The name of the target type/attribute to match.
46    target_indirect   If true, members of an attribute will be
47                      matched rather than the attribute itself.
48                      Default is true.
49    target_regex      If true, regular expression matching will
50                      be used on the target type/attribute.
51                      Obeys target_indirect option.
52                      Default is false.
53    tclass            The object class(es) to match.
54    tclass_regex      If true, use a regular expression for
55                      matching the rule's object class.
56                      Default is false.
57    perms             The set of permission(s) to match.
58    perms_equal       If true, the permission set of the rule
59                      must exactly match the permissions
60                      criteria.  If false, any set intersection
61                      will match.
62                      Default is false.
63    perms_regex       If true, regular expression matching will be used
64                      on the permission names instead of set logic.
65    default           The name of the default type to match.
66    default_regex     If true, regular expression matching will be
67                      used on the default type.
68                      Default is false.
69    boolean           The set of boolean(s) to match.
70    boolean_regex     If true, regular expression matching will be
71                      used on the booleans.
72                      Default is false.
73    boolean_equal     If true, the booleans in the conditional
74                      expression of the rule must exactly match the
75                      criteria.  If false, any set intersection
76                      will match.  Default is false.
77    """
78
79    ruletype = RuletypeDescriptor("validate_te_ruletype")
80    source = CriteriaDescriptor("source_regex", "lookup_type_or_attr")
81    source_regex = False
82    source_indirect = True
83    target = CriteriaDescriptor("target_regex", "lookup_type_or_attr")
84    target_regex = False
85    target_indirect = True
86    default = CriteriaDescriptor("default_regex", "lookup_type")
87    default_regex = False
88    boolean = CriteriaSetDescriptor("boolean_regex", "lookup_boolean")
89    boolean_regex = False
90    boolean_equal = False
91
92    def results(self):
93        """Generator which yields all matching TE rules."""
94        self.log.info("Generating results from {0.policy}".format(self))
95        self.log.debug("Ruletypes: {0.ruletype}".format(self))
96        self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, "
97                       "regex: {0.source_regex}".format(self))
98        self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, "
99                       "regex: {0.target_regex}".format(self))
100        self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self))
101        self.log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}".
102                       format(self))
103        self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self))
104        self.log.debug("Boolean: {0.boolean!r}, eq: {0.boolean_equal}, "
105                       "regex: {0.boolean_regex}".format(self))
106
107        for rule in self.policy.terules():
108            #
109            # Matching on rule type
110            #
111            if self.ruletype:
112                if rule.ruletype not in self.ruletype:
113                    continue
114
115            #
116            # Matching on source type
117            #
118            if self.source and not self._match_indirect_regex(
119                    rule.source,
120                    self.source,
121                    self.source_indirect,
122                    self.source_regex):
123                continue
124
125            #
126            # Matching on target type
127            #
128            if self.target and not self._match_indirect_regex(
129                    rule.target,
130                    self.target,
131                    self.target_indirect,
132                    self.target_regex):
133                continue
134
135            #
136            # Matching on object class
137            #
138            if not self._match_object_class(rule):
139                continue
140
141            #
142            # Matching on permission set
143            #
144            try:
145                if not self._match_perms(rule):
146                    continue
147            except RuleUseError:
148                continue
149
150            #
151            # Matching on default type
152            #
153            if self.default:
154                try:
155                    if not self._match_regex(
156                            rule.default,
157                            self.default,
158                            self.default_regex):
159                        continue
160                except RuleUseError:
161                    continue
162
163            #
164            # Match on Boolean in conditional expression
165            #
166            if self.boolean:
167                try:
168                    if not self._match_regex_or_set(
169                            rule.conditional.booleans,
170                            self.boolean,
171                            self.boolean_equal,
172                            self.boolean_regex):
173                        continue
174                except RuleNotConditional:
175                    continue
176
177            # if we get here, we have matched all available criteria
178            yield rule
179