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