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 InvalidType, RuleUseError
25
26
27class RBACRuleQuery(mixins.MatchObjClass, query.PolicyQuery):
28
29    """
30    Query the RBAC 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 role/attribute to match.
38    source_indirect If true, members of an attribute will be
39                    matched rather than the attribute itself.
40    source_regex    If true, regular expression matching will
41                    be used on the source role/attribute.
42                    Obeys the source_indirect option.
43    target          The name of the target role/attribute to match.
44    target_indirect If true, members of an attribute will be
45                    matched rather than the attribute itself.
46    target_regex    If true, regular expression matching will
47                    be used on the target role/attribute.
48                    Obeys target_indirect option.
49    tclass          The object class(es) to match.
50    tclass_regex    If true, use a regular expression for
51                    matching the rule's object class.
52    default         The name of the default role to match.
53    default_regex   If true, regular expression matching will
54                    be used on the default role.
55    """
56
57    ruletype = RuletypeDescriptor("validate_rbac_ruletype")
58    source = CriteriaDescriptor("source_regex", "lookup_role")
59    source_regex = False
60    source_indirect = True
61    _target = None
62    target_regex = False
63    target_indirect = True
64    tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class")
65    tclass_regex = False
66    default = CriteriaDescriptor("default_regex", "lookup_role")
67    default_regex = False
68
69    @property
70    def target(self):
71        return self._target
72
73    @target.setter
74    def target(self, value):
75        if not value:
76            self._target = None
77        elif self.target_regex:
78            self._target = re.compile(value)
79        else:
80            try:
81                self._target = self.policy.lookup_type_or_attr(value)
82            except InvalidType:
83                self._target = self.policy.lookup_role(value)
84
85    def results(self):
86        """Generator which yields all matching RBAC rules."""
87        self.log.info("Generating results from {0.policy}".format(self))
88        self.log.debug("Ruletypes: {0.ruletype}".format(self))
89        self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, "
90                       "regex: {0.source_regex}".format(self))
91        self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, "
92                       "regex: {0.target_regex}".format(self))
93        self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self))
94        self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self))
95
96        for rule in self.policy.rbacrules():
97            #
98            # Matching on rule type
99            #
100            if self.ruletype:
101                if rule.ruletype not in self.ruletype:
102                    continue
103
104            #
105            # Matching on source role
106            #
107            if self.source and not self._match_indirect_regex(
108                    rule.source,
109                    self.source,
110                    self.source_indirect,
111                    self.source_regex):
112                continue
113
114            #
115            # Matching on target type (role_transition)/role(allow)
116            #
117            if self.target and not self._match_indirect_regex(
118                    rule.target,
119                    self.target,
120                    self.target_indirect,
121                    self.target_regex):
122                continue
123
124            #
125            # Matching on object class
126            #
127            try:
128                if not self._match_object_class(rule):
129                    continue
130            except RuleUseError:
131                continue
132
133            #
134            # Matching on default role
135            #
136            if self.default:
137                try:
138                    if not self._match_regex(
139                            rule.default,
140                            self.default,
141                            self.default_regex):
142                        continue
143                except RuleUseError:
144                    continue
145
146            # if we get here, we have matched all available criteria
147            yield rule
148