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