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 
     21 
     22 class PolicyQuery(object):
     23 
     24     """Base class for SELinux policy queries."""
     25 
     26     def __init__(self, policy, **kwargs):
     27         self.log = logging.getLogger(self.__class__.__name__)
     28 
     29         self.policy = policy
     30 
     31         # keys are sorted in reverse order so regex settings
     32         # are set before the criteria, e.g. name_regex
     33         # is set before name.  This ensures correct behavior
     34         # since the criteria descriptors are sensitve to
     35         # regex settings.
     36         for name in sorted(kwargs.keys(), reverse=True):
     37             attr = getattr(self, name, None)  # None is not callable
     38             if callable(attr):
     39                 raise ValueError("Keyword parameter {0} conflicts with a callable.".format(name))
     40 
     41             setattr(self, name, kwargs[name])
     42 
     43     @staticmethod
     44     def _match_regex(obj, criteria, regex):
     45         """
     46         Match the object with optional regular expression.
     47 
     48         Parameters:
     49         obj         The object to match.
     50         criteria    The criteria to match.
     51         regex       If regular expression matching should be used.
     52         """
     53 
     54         if regex:
     55             return bool(criteria.search(str(obj)))
     56         else:
     57             return obj == criteria
     58 
     59     @staticmethod
     60     def _match_set(obj, criteria, equal):
     61         """
     62         Match the object (a set) with optional set equality.
     63 
     64         Parameters:
     65         obj         The object to match. (a set)
     66         criteria    The criteria to match. (a set)
     67         equal       If set equality should be used. Otherwise
     68                     any set intersection will match.
     69         """
     70 
     71         if equal:
     72             return obj == criteria
     73         else:
     74             return bool(obj.intersection(criteria))
     75 
     76     @staticmethod
     77     def _match_in_set(obj, criteria, regex):
     78         """
     79         Match if the criteria is in the list, with optional
     80         regular expression matching.
     81 
     82         Parameters:
     83         obj         The object to match.
     84         criteria    The criteria to match.
     85         regex       If regular expression matching should be used.
     86         """
     87 
     88         if regex:
     89             return [m for m in obj if criteria.search(str(m))]
     90         else:
     91             return criteria in obj
     92 
     93     @staticmethod
     94     def _match_indirect_regex(obj, criteria, indirect, regex):
     95         """
     96         Match the object with optional regular expression and indirection.
     97 
     98         Parameters:
     99         obj         The object to match.
    100         criteria    The criteria to match.
    101         regex       If regular expression matching should be used.
    102         indirect    If object indirection should be used, e.g.
    103                     expanding an attribute.
    104         """
    105 
    106         if indirect:
    107             return PolicyQuery._match_in_set((obj.expand()), criteria, regex)
    108         else:
    109             return PolicyQuery._match_regex(obj, criteria, regex)
    110 
    111     @staticmethod
    112     def _match_regex_or_set(obj, criteria, equal, regex):
    113         """
    114         Match the object (a set) with either set comparisons
    115         (equality or intersection) or by regex matching of the
    116         set members.  Regular expression matching will override
    117         the set equality option.
    118 
    119         Parameters:
    120         obj         The object to match. (a set)
    121         criteria    The criteria to match.
    122         equal       If set equality should be used.  Otherwise
    123                     any set intersection will match. Ignored
    124                     if regular expression matching is used.
    125         regex       If regular expression matching should be used.
    126         """
    127 
    128         if regex:
    129             return [m for m in obj if criteria.search(str(m))]
    130         else:
    131             return PolicyQuery._match_set(obj, set(criteria), equal)
    132 
    133     @staticmethod
    134     def _match_range(obj, criteria, subset, overlap, superset, proper):
    135         """
    136         Match ranges of objects.
    137 
    138         obj         An object with attributes named "low" and "high", representing the range.
    139         criteria    An object with attributes named "low" and "high", representing the criteria.
    140         subset      If true, the criteria will match if it is a subset obj's range.
    141         overlap     If true, the criteria will match if it overlaps any of the obj's range.
    142         superset    If true, the criteria will match if it is a superset of the obj's range.
    143         proper      If true, use proper superset/subset operations.
    144                     No effect if not using set operations.
    145         """
    146 
    147         if overlap:
    148             return ((obj.low <= criteria.low <= obj.high) or (
    149                      obj.low <= criteria.high <= obj.high) or (
    150                      criteria.low <= obj.low and obj.high <= criteria.high))
    151         elif subset:
    152             if proper:
    153                 return ((obj.low < criteria.low and criteria.high <= obj.high) or (
    154                          obj.low <= criteria.low and criteria.high < obj.high))
    155             else:
    156                 return obj.low <= criteria.low and criteria.high <= obj.high
    157         elif superset:
    158             if proper:
    159                 return ((criteria.low < obj.low and obj.high <= criteria.high) or (
    160                          criteria.low <= obj.low and obj.high < criteria.high))
    161             else:
    162                 return (criteria.low <= obj.low and obj.high <= criteria.high)
    163         else:
    164             return criteria.low == obj.low and obj.high == criteria.high
    165 
    166     @staticmethod
    167     def _match_level(obj, criteria, dom, domby, incomp):
    168         """
    169         Match the an MLS level.
    170 
    171         obj         The level to match.
    172         criteria    The criteria to match. (a level)
    173         dom         If true, the criteria will match if it dominates obj.
    174         domby       If true, the criteria will match if it is dominated by obj.
    175         incomp      If true, the criteria will match if it is incomparable to obj.
    176         """
    177 
    178         if dom:
    179             return (criteria >= obj)
    180         elif domby:
    181             return (criteria <= obj)
    182         elif incomp:
    183             return (criteria ^ obj)
    184         else:
    185             return (criteria == obj)
    186 
    187     def results(self):
    188         """
    189         Generator which returns the matches for the query.  This method
    190         should be overridden by subclasses.
    191         """
    192         raise NotImplementedError
    193