1 # Copyright 2014, 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 from . import exception 20 from . import qpol 21 from . import symbol 22 23 24 def _symbol_lookup(qpol_policy, name): 25 """Look up the low-level qpol policy reference""" 26 if isinstance(name, qpol.qpol_type_t): 27 return name 28 29 try: 30 return qpol.qpol_type_t(qpol_policy, str(name)) 31 except ValueError: 32 raise exception.InvalidType("{0} is not a valid type/attribute".format(name)) 33 34 35 def attribute_factory(qpol_policy, name): 36 """Factory function for creating attribute objects.""" 37 38 if isinstance(name, TypeAttribute): 39 assert name.policy == qpol_policy 40 return name 41 42 qpol_symbol = _symbol_lookup(qpol_policy, name) 43 44 if not qpol_symbol.isattr(qpol_policy): 45 raise TypeError("{0} is a type".format(qpol_symbol.name(qpol_policy))) 46 47 return TypeAttribute(qpol_policy, qpol_symbol) 48 49 50 def type_factory(qpol_policy, name, deref=False): 51 """Factory function for creating type objects.""" 52 53 if isinstance(name, Type): 54 assert name.policy == qpol_policy 55 return name 56 57 qpol_symbol = _symbol_lookup(qpol_policy, name) 58 59 if qpol_symbol.isattr(qpol_policy): 60 raise TypeError("{0} is an attribute".format(qpol_symbol.name(qpol_policy))) 61 elif qpol_symbol.isalias(qpol_policy) and not deref: 62 raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) 63 64 return Type(qpol_policy, qpol_symbol) 65 66 67 def type_or_attr_factory(qpol_policy, name, deref=False): 68 """Factory function for creating type or attribute objects.""" 69 70 if isinstance(name, (Type, TypeAttribute)): 71 assert name.policy == qpol_policy 72 return name 73 74 qpol_symbol = _symbol_lookup(qpol_policy, name) 75 76 if qpol_symbol.isalias(qpol_policy) and not deref: 77 raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) 78 79 if qpol_symbol.isattr(qpol_policy): 80 return TypeAttribute(qpol_policy, qpol_symbol) 81 else: 82 return Type(qpol_policy, qpol_symbol) 83 84 85 class BaseType(symbol.PolicySymbol): 86 87 """Type/attribute base class.""" 88 89 @property 90 def ispermissive(self): 91 raise NotImplementedError 92 93 def expand(self): 94 """Generator that expands this attribute into its member types.""" 95 raise NotImplementedError 96 97 def attributes(self): 98 """Generator that yields all attributes for this type.""" 99 raise NotImplementedError 100 101 def aliases(self): 102 """Generator that yields all aliases for this type.""" 103 raise NotImplementedError 104 105 106 class Type(BaseType): 107 108 """A type.""" 109 110 @property 111 def ispermissive(self): 112 """(T/F) the type is permissive.""" 113 return self.qpol_symbol.ispermissive(self.policy) 114 115 def expand(self): 116 """Generator that expands this into its member types.""" 117 yield self 118 119 def attributes(self): 120 """Generator that yields all attributes for this type.""" 121 for attr in self.qpol_symbol.attr_iter(self.policy): 122 yield attribute_factory(self.policy, attr) 123 124 def aliases(self): 125 """Generator that yields all aliases for this type.""" 126 for alias in self.qpol_symbol.alias_iter(self.policy): 127 yield alias 128 129 def statement(self): 130 attrs = list(self.attributes()) 131 aliases = list(self.aliases()) 132 stmt = "type {0}".format(self) 133 if aliases: 134 if len(aliases) > 1: 135 stmt += " alias {{ {0} }}".format(' '.join(aliases)) 136 else: 137 stmt += " alias {0}".format(aliases[0]) 138 for attr in attrs: 139 stmt += ", {0}".format(attr) 140 stmt += ";" 141 return stmt 142 143 144 class TypeAttribute(BaseType): 145 146 """An attribute.""" 147 148 def __contains__(self, other): 149 for type_ in self.expand(): 150 if other == type_: 151 return True 152 153 return False 154 155 def expand(self): 156 """Generator that expands this attribute into its member types.""" 157 for type_ in self.qpol_symbol.type_iter(self.policy): 158 yield type_factory(self.policy, type_) 159 160 def attributes(self): 161 """Generator that yields all attributes for this type.""" 162 raise TypeError("{0} is an attribute, thus does not have attributes.".format(self)) 163 164 def aliases(self): 165 """Generator that yields all aliases for this type.""" 166 raise TypeError("{0} is an attribute, thus does not have aliases.".format(self)) 167 168 @property 169 def ispermissive(self): 170 """(T/F) the type is permissive.""" 171 raise TypeError("{0} is an attribute, thus cannot be permissive.".format(self)) 172 173 def statement(self): 174 return "attribute {0};".format(self) 175