1# Copyright 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 ConstraintUseError
25
26
27class ConstraintQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery):
28
29    """
30    Query constraint rules, (mls)constrain/(mls)validatetrans.
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    tclass            The object class(es) to match.
38    tclass_regex      If true, use a regular expression for
39                      matching the rule's object class.
40    perms             The permission(s) to match.
41    perms_equal       If true, the permission set of the rule
42                      must exactly match the permissions
43                      criteria.  If false, any set intersection
44                      will match.
45    perms_regex       If true, regular expression matching will be used
46                      on the permission names instead of set logic.
47    role              The name of the role to match in the
48                      constraint expression.
49    role_indirect     If true, members of an attribute will be
50                      matched rather than the attribute itself.
51    role_regex        If true, regular expression matching will
52                      be used on the role.
53    type_             The name of the type/attribute to match in the
54                      constraint expression.
55    type_indirect     If true, members of an attribute will be
56                      matched rather than the attribute itself.
57    type_regex        If true, regular expression matching will
58                      be used on the type/attribute.
59    user              The name of the user to match in the
60                      constraint expression.
61    user_regex        If true, regular expression matching will
62                      be used on the user.
63    """
64
65    ruletype = RuletypeDescriptor("validate_constraint_ruletype")
66    user = CriteriaDescriptor("user_regex", "lookup_user")
67    user_regex = False
68    role = CriteriaDescriptor("role_regex", "lookup_role")
69    role_regex = False
70    role_indirect = True
71    type_ = CriteriaDescriptor("type_regex", "lookup_type_or_attr")
72    type_regex = False
73    type_indirect = True
74
75    def _match_expr(self, expr, criteria, indirect, regex):
76        """
77        Match roles/types/users in a constraint expression,
78        optionally by expanding the contents of attributes.
79
80        Parameters:
81        expr        The expression to match.
82        criteria    The criteria to match.
83        indirect    If attributes in the expression should be expanded.
84        regex       If regular expression matching should be used.
85        """
86
87        if indirect:
88            obj = set()
89            for item in expr:
90                obj.update(item.expand())
91        else:
92            obj = expr
93
94        return self._match_in_set(obj, criteria, regex)
95
96    def results(self):
97        """Generator which yields all matching constraints rules."""
98        self.log.info("Generating results from {0.policy}".format(self))
99        self.log.debug("Ruletypes: {0.ruletype}".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("User: {0.user!r}, regex: {0.user_regex}".format(self))
104        self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self))
105        self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self))
106
107        for c in self.policy.constraints():
108            if self.ruletype:
109                if c.ruletype not in self.ruletype:
110                    continue
111
112            if not self._match_object_class(c):
113                continue
114
115            try:
116                if not self._match_perms(c):
117                    continue
118            except ConstraintUseError:
119                    continue
120
121            if self.role and not self._match_expr(
122                        c.roles,
123                        self.role,
124                        self.role_indirect,
125                        self.role_regex):
126                    continue
127
128            if self.type_ and not self._match_expr(
129                        c.types,
130                        self.type_,
131                        self.type_indirect,
132                        self.type_regex):
133                    continue
134
135            if self.user and not self._match_expr(
136                        c.users,
137                        self.user,
138                        False,
139                        self.user_regex):
140                    continue
141
142            yield c
143