Home | History | Annotate | Download | only in setools
      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 #
     19 # pylint: disable=attribute-defined-outside-init,no-member
     20 import re
     21 
     22 from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor
     23 from .util import match_in_set, match_regex, match_range, match_regex_or_set
     24 
     25 
     26 class MatchAlias(object):
     27 
     28     """Mixin for matching an object's aliases."""
     29 
     30     alias = CriteriaDescriptor("alias_regex")
     31     alias_regex = False
     32 
     33     def _match_alias_debug(self, log):
     34         """Emit log debugging info for alias matching."""
     35         log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self))
     36 
     37     def _match_alias(self, obj):
     38         """
     39         Match the alias criteria
     40 
     41         Parameter:
     42         obj     An object with an alias generator method named "aliases"
     43         """
     44 
     45         if not self.alias:
     46             # if there is no criteria, everything matches.
     47             return True
     48 
     49         return match_in_set(obj.aliases(), self.alias, self.alias_regex)
     50 
     51 
     52 class MatchContext(object):
     53 
     54     """
     55     Mixin for matching contexts.
     56 
     57     Class attributes:
     58     user            The user to match in the context.
     59     user_regex      If true, regular expression matching
     60                     will be used on the user.
     61     role            The role to match in the context.
     62     role_regex      If true, regular expression matching
     63                     will be used on the role.
     64     type_           The type to match in the context.
     65     type_regex      If true, regular expression matching
     66                     will be used on the type.
     67     range_          The range to match in the context.
     68     range_subset    If true, the criteria will match if it
     69                     is a subset of the context's range.
     70     range_overlap   If true, the criteria will match if it
     71                     overlaps any of the context's range.
     72     range_superset  If true, the criteria will match if it
     73                     is a superset of the context's range.
     74     range_proper    If true, use proper superset/subset
     75                     on range matching operations.
     76                     No effect if not using set operations.
     77     """
     78 
     79     user = CriteriaDescriptor("user_regex", "lookup_user")
     80     user_regex = False
     81     role = CriteriaDescriptor("role_regex", "lookup_role")
     82     role_regex = False
     83     type_ = CriteriaDescriptor("type_regex", "lookup_type")
     84     type_regex = False
     85     range_ = CriteriaDescriptor(lookup_function="lookup_range")
     86     range_overlap = False
     87     range_subset = False
     88     range_superset = False
     89     range_proper = False
     90 
     91     def _match_context_debug(self, log):
     92         """Emit log debugging info for context matching."""
     93         log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self))
     94         log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self))
     95         log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self))
     96         log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, "
     97                   "superset: {0.range_superset}, proper: {0.range_proper}".format(self))
     98 
     99     def _match_context(self, context):
    100         """
    101         Match the context criteria.
    102 
    103         Parameter:
    104         obj     An object with context attributes "user", "role",
    105                 "type_" and "range_".
    106         """
    107 
    108         if self.user and not match_regex(
    109                 context.user,
    110                 self.user,
    111                 self.user_regex):
    112             return False
    113 
    114         if self.role and not match_regex(
    115                 context.role,
    116                 self.role,
    117                 self.role_regex):
    118             return False
    119 
    120         if self.type_ and not match_regex(
    121                 context.type_,
    122                 self.type_,
    123                 self.type_regex):
    124             return False
    125 
    126         if self.range_ and not match_range(
    127                 context.range_,
    128                 self.range_,
    129                 self.range_subset,
    130                 self.range_overlap,
    131                 self.range_superset,
    132                 self.range_proper):
    133             return False
    134 
    135         return True
    136 
    137 
    138 class MatchName(object):
    139 
    140     """Mixin for matching an object's name."""
    141 
    142     name = CriteriaDescriptor("name_regex")
    143     name_regex = False
    144 
    145     def _match_name_debug(self, log):
    146         """Log debugging messages for name matching."""
    147         log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self))
    148 
    149     def _match_name(self, obj):
    150         """Match the object to the name criteria."""
    151         if not self.name:
    152             # if there is no criteria, everything matches.
    153             return True
    154 
    155         return match_regex(obj, self.name, self.name_regex)
    156 
    157 
    158 class MatchObjClass(object):
    159 
    160     """Mixin for matching an object's class."""
    161 
    162     tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class")
    163     tclass_regex = False
    164 
    165     def _match_object_class_debug(self, log):
    166         """Emit log debugging info for permission matching."""
    167         log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self))
    168 
    169     def _match_object_class(self, obj):
    170         """
    171         Match the object class criteria
    172 
    173         Parameter:
    174         obj     An object with an object class attribute named "tclass"
    175         """
    176 
    177         if not self.tclass:
    178             # if there is no criteria, everything matches.
    179             return True
    180         elif self.tclass_regex:
    181             return bool(self.tclass.search(str(obj.tclass)))
    182         else:
    183             return obj.tclass in self.tclass
    184 
    185 
    186 class MatchPermission(object):
    187 
    188     """Mixin for matching an object's permissions."""
    189 
    190     perms = CriteriaSetDescriptor("perms_regex")
    191     perms_equal = False
    192     perms_regex = False
    193     perms_subset = False
    194 
    195     def _match_perms_debug(self, log):
    196         """Emit log debugging info for permission matching."""
    197         log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}, "
    198                   "subset: {0.perms_subset!r}".format(self))
    199 
    200     def _match_perms(self, obj):
    201         """
    202         Match the permission criteria
    203 
    204         Parameter:
    205         obj     An object with a permission set class attribute named "perms"
    206         """
    207 
    208         if not self.perms:
    209             # if there is no criteria, everything matches.
    210             return True
    211 
    212         if self.perms_subset:
    213             return obj.perms >= self.perms
    214         else:
    215             return match_regex_or_set(obj.perms, self.perms, self.perms_equal, self.perms_regex)
    216