1 # Copyright 2014-2016, 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 itertools 20 21 from . import exception 22 from . import qpol 23 from . import rule 24 from . import typeattr 25 from . import boolcond 26 27 28 def te_rule_factory(policy, symbol): 29 """Factory function for creating TE rule objects.""" 30 31 if isinstance(symbol, qpol.qpol_avrule_t): 32 return AVRule(policy, symbol) 33 elif isinstance(symbol, (qpol.qpol_terule_t, qpol.qpol_filename_trans_t)): 34 return TERule(policy, symbol) 35 else: 36 raise TypeError("TE rules cannot be looked-up.") 37 38 39 def expanded_te_rule_factory(original, source, target): 40 """ 41 Factory function for creating expanded TE rules. 42 43 original The TE rule the expanded rule originates from. 44 source The source type of the expanded rule. 45 target The target type of the expanded rule. 46 """ 47 48 if isinstance(original, AVRule): 49 rule = ExpandedAVRule(original.policy, original.qpol_symbol) 50 elif isinstance(original, TERule): 51 rule = ExpandedTERule(original.policy, original.qpol_symbol) 52 elif isinstance(original, (ExpandedAVRule, ExpandedTERule)): 53 return original 54 else: 55 raise TypeError("The original rule must be a TE rule class.") 56 57 rule.source = source 58 rule.target = target 59 rule.origin = original 60 return rule 61 62 63 def validate_ruletype(t): 64 """Validate TE Rule types.""" 65 if t not in ["allow", "auditallow", "dontaudit", "neverallow", 66 "type_transition", "type_member", "type_change"]: 67 raise exception.InvalidTERuleType("{0} is not a valid TE rule type.".format(t)) 68 69 return t 70 71 72 class BaseTERule(rule.PolicyRule): 73 74 """A type enforcement rule.""" 75 76 @property 77 def source(self): 78 """The rule's source type/attribute.""" 79 return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.source_type(self.policy)) 80 81 @property 82 def target(self): 83 """The rule's target type/attribute.""" 84 return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) 85 86 @property 87 def filename(self): 88 raise NotImplementedError 89 90 @property 91 def conditional(self): 92 """The rule's conditional expression.""" 93 try: 94 return boolcond.condexpr_factory(self.policy, self.qpol_symbol.cond(self.policy)) 95 except (AttributeError, ValueError): 96 # AttributeError: name filetrans rules cannot be conditional 97 # so no member function 98 # ValueError: The rule is not conditional 99 raise exception.RuleNotConditional 100 101 @property 102 def conditional_block(self): 103 """The conditional block of the rule (T/F)""" 104 try: 105 return bool(self.qpol_symbol.which_list(self.policy)) 106 except (AttributeError, ValueError): 107 # AttributeError: name filetrans rules cannot be conditional 108 # so no member function 109 # ValueError: The rule is not conditional 110 raise exception.RuleNotConditional 111 112 def expand(self): 113 """Expand the rule into an equivalent set of rules without attributes.""" 114 for s, t in itertools.product(self.source.expand(), self.target.expand()): 115 yield expanded_te_rule_factory(self, s, t) 116 117 118 class AVRule(BaseTERule): 119 120 """An access vector type enforcement rule.""" 121 122 def __str__(self): 123 try: 124 return self._rule_string 125 except AttributeError: 126 self._rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} ".format(self) 127 128 perms = self.perms 129 130 # allow/dontaudit/auditallow/neverallow rules 131 if len(perms) > 1: 132 self._rule_string += "{{ {0} }};".format(' '.join(perms)) 133 else: 134 # convert to list since sets cannot be indexed 135 self._rule_string += "{0};".format(list(perms)[0]) 136 137 try: 138 self._rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) 139 except exception.RuleNotConditional: 140 pass 141 142 return self._rule_string 143 144 @property 145 def perms(self): 146 """The rule's permission set.""" 147 return set(self.qpol_symbol.perm_iter(self.policy)) 148 149 @property 150 def default(self): 151 """The rule's default type.""" 152 raise exception.RuleUseError("{0} rules do not have a default type.".format(self.ruletype)) 153 154 @property 155 def filename(self): 156 raise exception.RuleUseError("{0} rules do not have file names".format(self.ruletype)) 157 158 159 class TERule(BaseTERule): 160 161 """A type_* type enforcement rule.""" 162 163 def __str__(self): 164 try: 165 return self._rule_string 166 except AttributeError: 167 self._rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default}".format( 168 self) 169 170 try: 171 self._rule_string += " \"{0}\";".format(self.filename) 172 except (exception.TERuleNoFilename, exception.RuleUseError): 173 # invalid use for type_change/member 174 self._rule_string += ";" 175 176 try: 177 self._rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) 178 except exception.RuleNotConditional: 179 pass 180 181 return self._rule_string 182 183 def __hash__(self): 184 try: 185 cond = self.conditional 186 cond_block = self.conditional_block 187 except exception.RuleNotConditional: 188 cond = None 189 cond_block = None 190 191 try: 192 filename = self.filename 193 except (exception.TERuleNoFilename, exception.RuleUseError): 194 filename = None 195 196 return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{1}|{2}|{3}".format( 197 self, filename, cond, cond_block)) 198 199 @property 200 def perms(self): 201 """The rule's permission set.""" 202 raise exception.RuleUseError( 203 "{0} rules do not have a permission set.".format(self.ruletype)) 204 205 @property 206 def default(self): 207 """The rule's default type.""" 208 return typeattr.type_factory(self.policy, self.qpol_symbol.default_type(self.policy)) 209 210 @property 211 def filename(self): 212 """The type_transition rule's file name.""" 213 try: 214 return self.qpol_symbol.filename(self.policy) 215 except AttributeError: 216 if self.ruletype == "type_transition": 217 raise exception.TERuleNoFilename 218 else: 219 raise exception.RuleUseError("{0} rules do not have file names". 220 format(self.ruletype)) 221 222 223 class ExpandedAVRule(AVRule): 224 225 """An expanded access vector type enforcement rule.""" 226 227 source = None 228 target = None 229 origin = None 230 231 232 class ExpandedTERule(TERule): 233 234 """An expanded type_* type enforcement rule.""" 235 236 source = None 237 target = None 238 origin = None 239