Home | History | Annotate | Download | only in setools
      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 #
     19 import logging
     20 import re
     21 
     22 from . import mixins, query
     23 from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor
     24 from .policyrep import ioctlSet
     25 from .policyrep.exception import RuleUseError, RuleNotConditional
     26 from .util import match_regex, match_indirect_regex, match_regex_or_set
     27 
     28 
     29 class TERuleQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery):
     30 
     31     """
     32     Query the Type Enforcement rules.
     33 
     34     Parameter:
     35     policy            The policy to query.
     36 
     37     Keyword Parameters/Class attributes:
     38     ruletype          The list of rule type(s) to match.
     39     source            The name of the source type/attribute to match.
     40     source_indirect   If true, members of an attribute will be
     41                       matched rather than the attribute itself.
     42                       Default is true.
     43     source_regex      If true, regular expression matching will
     44                       be used on the source type/attribute.
     45                       Obeys the source_indirect option.
     46                       Default is false.
     47     target            The name of the target type/attribute to match.
     48     target_indirect   If true, members of an attribute will be
     49                       matched rather than the attribute itself.
     50                       Default is true.
     51     target_regex      If true, regular expression matching will
     52                       be used on the target type/attribute.
     53                       Obeys target_indirect option.
     54                       Default is false.
     55     tclass            The object class(es) to match.
     56     tclass_regex      If true, use a regular expression for
     57                       matching the rule's object class.
     58                       Default is false.
     59     perms             The set of permission(s) to match.
     60     perms_equal       If true, the permission set of the rule
     61                       must exactly match the permissions
     62                       criteria.  If false, any set intersection
     63                       will match.
     64                       Default is false.
     65     perms_regex       If true, regular expression matching will be used
     66                       on the permission names instead of set logic.
     67                       Default is false.
     68     perms_subset      If true, the rule matches if the permissions criteria
     69                       is a subset of the rule's permission set.
     70                       Default is false.
     71     default           The name of the default type to match.
     72     default_regex     If true, regular expression matching will be
     73                       used on the default type.
     74                       Default is false.
     75     boolean           The set of boolean(s) to match.
     76     boolean_regex     If true, regular expression matching will be
     77                       used on the booleans.
     78                       Default is false.
     79     boolean_equal     If true, the booleans in the conditional
     80                       expression of the rule must exactly match the
     81                       criteria.  If false, any set intersection
     82                       will match.  Default is false.
     83     """
     84 
     85     ruletype = CriteriaSetDescriptor(lookup_function="validate_te_ruletype")
     86     source = CriteriaDescriptor("source_regex", "lookup_type_or_attr")
     87     source_regex = False
     88     source_indirect = True
     89     target = CriteriaDescriptor("target_regex", "lookup_type_or_attr")
     90     target_regex = False
     91     target_indirect = True
     92     default = CriteriaDescriptor("default_regex", "lookup_type_or_attr")
     93     default_regex = False
     94     boolean = CriteriaSetDescriptor("boolean_regex", "lookup_boolean")
     95     boolean_regex = False
     96     boolean_equal = False
     97     _xperms = None
     98     xperms_equal = False
     99 
    100     @property
    101     def xperms(self):
    102         return self._xperms
    103 
    104     @xperms.setter
    105     def xperms(self, value):
    106         if value:
    107             pending_xperms = ioctlSet()
    108 
    109             for low, high in value:
    110                 if not (0 <= low <= 0xffff):
    111                     raise ValueError("{0:#07x} is not a valid ioctl.".format(low))
    112 
    113                 if not (0 <= high <= 0xffff):
    114                     raise ValueError("{0:#07x} is not a valid ioctl.".format(high))
    115 
    116                 if high < low:
    117                     high, low = low, high
    118 
    119                 pending_xperms.update(i for i in range(low, high+1))
    120 
    121             self._xperms = pending_xperms
    122         else:
    123             self._xperms = None
    124 
    125     def __init__(self, policy, **kwargs):
    126         super(TERuleQuery, self).__init__(policy, **kwargs)
    127         self.log = logging.getLogger(__name__)
    128 
    129     def results(self):
    130         """Generator which yields all matching TE rules."""
    131         self.log.info("Generating TE rule results from {0.policy}".format(self))
    132         self.log.debug("Ruletypes: {0.ruletype}".format(self))
    133         self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, "
    134                        "regex: {0.source_regex}".format(self))
    135         self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, "
    136                        "regex: {0.target_regex}".format(self))
    137         self._match_object_class_debug(self.log)
    138         self._match_perms_debug(self.log)
    139         self.log.debug("Xperms: {0.xperms!r}, eq: {0.xperms_equal}".format(self))
    140         self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self))
    141         self.log.debug("Boolean: {0.boolean!r}, eq: {0.boolean_equal}, "
    142                        "regex: {0.boolean_regex}".format(self))
    143 
    144         for rule in self.policy.terules():
    145             #
    146             # Matching on rule type
    147             #
    148             if self.ruletype:
    149                 if rule.ruletype not in self.ruletype:
    150                     continue
    151 
    152             #
    153             # Matching on source type
    154             #
    155             if self.source and not match_indirect_regex(
    156                     rule.source,
    157                     self.source,
    158                     self.source_indirect,
    159                     self.source_regex):
    160                 continue
    161 
    162             #
    163             # Matching on target type
    164             #
    165             if self.target and not match_indirect_regex(
    166                     rule.target,
    167                     self.target,
    168                     self.target_indirect,
    169                     self.target_regex):
    170                 continue
    171 
    172             #
    173             # Matching on object class
    174             #
    175             if not self._match_object_class(rule):
    176                 continue
    177 
    178             #
    179             # Matching on permission set
    180             #
    181             try:
    182                 if self.perms and rule.extended:
    183                     if self.perms_equal and len(self.perms) > 1:
    184                         # if criteria is more than one standard permission,
    185                         # extended perm rules can never match if the
    186                         # permission set equality option is on.
    187                         continue
    188 
    189                     if rule.xperm_type not in self.perms:
    190                         continue
    191                 elif not self._match_perms(rule):
    192                     continue
    193             except RuleUseError:
    194                 continue
    195 
    196             #
    197             # Matching on extended permissions
    198             #
    199             try:
    200                 if self.xperms and not match_regex_or_set(
    201                         rule.perms,
    202                         self.xperms,
    203                         self.xperms_equal,
    204                         False):
    205                     continue
    206 
    207             except RuleUseError:
    208                 continue
    209 
    210             #
    211             # Matching on default type
    212             #
    213             if self.default:
    214                 try:
    215                     # because default type is always a single
    216                     # type, hard-code indirect to True
    217                     # so the criteria can be an attribute
    218                     if not match_indirect_regex(
    219                             rule.default,
    220                             self.default,
    221                             True,
    222                             self.default_regex):
    223                         continue
    224                 except RuleUseError:
    225                     continue
    226 
    227             #
    228             # Match on Boolean in conditional expression
    229             #
    230             if self.boolean:
    231                 try:
    232                     if not match_regex_or_set(
    233                             rule.conditional.booleans,
    234                             self.boolean,
    235                             self.boolean_equal,
    236                             self.boolean_regex):
    237                         continue
    238                 except RuleNotConditional:
    239                     continue
    240 
    241             # if we get here, we have matched all available criteria
    242             yield rule
    243