diff options
Diffstat (limited to 'lib/python2.7/site-packages/setoolsgui/setools')
52 files changed, 8462 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/setoolsgui/setools/__init__.py b/lib/python2.7/site-packages/setoolsgui/setools/__init__.py new file mode 100644 index 0000000..4d03553 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/__init__.py @@ -0,0 +1,68 @@ +"""The SETools SELinux policy analysis library.""" +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +#try: +# import pkg_resources +# # pylint: disable=no-member +# __version__ = pkg_resources.get_distribution("setools").version +#except ImportError: # pragma: no cover +# __version__ = "unknown" +__version__ = "3.3.8" + +# Python classes for policy representation +from . import policyrep +from .policyrep import SELinuxPolicy + +# Exceptions +from . import exception + +# Component Queries +from .boolquery import BoolQuery +from .categoryquery import CategoryQuery +from .commonquery import CommonQuery +from .objclassquery import ObjClassQuery +from .polcapquery import PolCapQuery +from .rolequery import RoleQuery +from .sensitivityquery import SensitivityQuery +from .typequery import TypeQuery +from .typeattrquery import TypeAttributeQuery +from .userquery import UserQuery + +# Rule Queries +from .mlsrulequery import MLSRuleQuery +from .rbacrulequery import RBACRuleQuery +from .terulequery import TERuleQuery + +# Constraint queries +from .constraintquery import ConstraintQuery + +# In-policy Context Queries +from .fsusequery import FSUseQuery +from .genfsconquery import GenfsconQuery +from .initsidquery import InitialSIDQuery +from .netifconquery import NetifconQuery +from .nodeconquery import NodeconQuery +from .portconquery import PortconQuery + +# Information Flow Analysis +from .infoflow import InfoFlowAnalysis +from .permmap import PermissionMap + +# Domain Transition Analysis +from .dta import DomainTransitionAnalysis diff --git a/lib/python2.7/site-packages/setoolsgui/setools/boolquery.py b/lib/python2.7/site-packages/setoolsgui/setools/boolquery.py new file mode 100644 index 0000000..b70b7d5 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/boolquery.py @@ -0,0 +1,66 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery +from .descriptors import CriteriaDescriptor + + +class BoolQuery(compquery.ComponentQuery): + + """Query SELinux policy Booleans. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The Boolean name to match. + name_regex If true, regular expression matching + will be used on the Boolean name. + default The default state to match. If this + is None, the default state not be matched. + """ + + _default = None + + @property + def default(self): + return self._default + + @default.setter + def default(self, value): + if value is None: + self._default = None + else: + self._default = bool(value) + + def results(self): + """Generator which yields all Booleans matching the criteria.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Default: {0.default}".format(self)) + + for boolean in self.policy.bools(): + if not self._match_name(boolean): + continue + + if self.default is not None and boolean.state != self.default: + continue + + yield boolean diff --git a/lib/python2.7/site-packages/setoolsgui/setools/categoryquery.py b/lib/python2.7/site-packages/setoolsgui/setools/categoryquery.py new file mode 100644 index 0000000..d4d7c4c --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/categoryquery.py @@ -0,0 +1,55 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery +from . import mixins + + +class CategoryQuery(mixins.MatchAlias, compquery.ComponentQuery): + + """ + Query MLS Categories + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the category to match. + name_regex If true, regular expression matching will + be used for matching the name. + alias The alias name to match. + alias_regex If true, regular expression matching + will be used on the alias names. + """ + + def results(self): + """Generator which yields all matching categories.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self)) + + for cat in self.policy.categories(): + if not self._match_name(cat): + continue + + if not self._match_alias(cat): + continue + + yield cat diff --git a/lib/python2.7/site-packages/setoolsgui/setools/commonquery.py b/lib/python2.7/site-packages/setoolsgui/setools/commonquery.py new file mode 100644 index 0000000..e105ccb --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/commonquery.py @@ -0,0 +1,60 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery, mixins + + +class CommonQuery(mixins.MatchPermission, compquery.ComponentQuery): + + """ + Query common permission sets. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the common to match. + name_regex If true, regular expression matching will + be used for matching the name. + perms The permissions to match. + perms_equal If true, only commons with permission sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + perms_regex If true, regular expression matching will be used + on the permission names instead of set logic. + """ + + def results(self): + """Generator which yields all matching commons.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}". + format(self)) + + for com in self.policy.commons(): + if not self._match_name(com): + continue + + if not self._match_perms(com): + continue + + yield com diff --git a/lib/python2.7/site-packages/setoolsgui/setools/compquery.py b/lib/python2.7/site-packages/setoolsgui/setools/compquery.py new file mode 100644 index 0000000..3d8851a --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/compquery.py @@ -0,0 +1,39 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +# pylint: disable=no-member,attribute-defined-outside-init,abstract-method +import re + +from . import query +from .descriptors import CriteriaDescriptor + + +class ComponentQuery(query.PolicyQuery): + + """Base class for SETools component queries.""" + + name = CriteriaDescriptor("name_regex") + name_regex = False + + def _match_name(self, obj): + """Match the object to the name criteria.""" + if not self.name: + # if there is no criteria, everything matches. + return True + + return self._match_regex(obj, self.name, self.name_regex) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/constraintquery.py b/lib/python2.7/site-packages/setoolsgui/setools/constraintquery.py new file mode 100644 index 0000000..82a6fc2 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/constraintquery.py @@ -0,0 +1,142 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import mixins, query +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, RuletypeDescriptor +from .policyrep.exception import ConstraintUseError + + +class ConstraintQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery): + + """ + Query constraint rules, (mls)constrain/(mls)validatetrans. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The list of rule type(s) to match. + tclass The object class(es) to match. + tclass_regex If true, use a regular expression for + matching the rule's object class. + perms The permission(s) to match. + perms_equal If true, the permission set of the rule + must exactly match the permissions + criteria. If false, any set intersection + will match. + perms_regex If true, regular expression matching will be used + on the permission names instead of set logic. + role The name of the role to match in the + constraint expression. + role_indirect If true, members of an attribute will be + matched rather than the attribute itself. + role_regex If true, regular expression matching will + be used on the role. + type_ The name of the type/attribute to match in the + constraint expression. + type_indirect If true, members of an attribute will be + matched rather than the attribute itself. + type_regex If true, regular expression matching will + be used on the type/attribute. + user The name of the user to match in the + constraint expression. + user_regex If true, regular expression matching will + be used on the user. + """ + + ruletype = RuletypeDescriptor("validate_constraint_ruletype") + user = CriteriaDescriptor("user_regex", "lookup_user") + user_regex = False + role = CriteriaDescriptor("role_regex", "lookup_role") + role_regex = False + role_indirect = True + type_ = CriteriaDescriptor("type_regex", "lookup_type_or_attr") + type_regex = False + type_indirect = True + + def _match_expr(self, expr, criteria, indirect, regex): + """ + Match roles/types/users in a constraint expression, + optionally by expanding the contents of attributes. + + Parameters: + expr The expression to match. + criteria The criteria to match. + indirect If attributes in the expression should be expanded. + regex If regular expression matching should be used. + """ + + if indirect: + obj = set() + for item in expr: + obj.update(item.expand()) + else: + obj = expr + + return self._match_in_set(obj, criteria, regex) + + def results(self): + """Generator which yields all matching constraints rules.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) + self.log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}". + format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + + for c in self.policy.constraints(): + if self.ruletype: + if c.ruletype not in self.ruletype: + continue + + if not self._match_object_class(c): + continue + + try: + if not self._match_perms(c): + continue + except ConstraintUseError: + continue + + if self.role and not self._match_expr( + c.roles, + self.role, + self.role_indirect, + self.role_regex): + continue + + if self.type_ and not self._match_expr( + c.types, + self.type_, + self.type_indirect, + self.type_regex): + continue + + if self.user and not self._match_expr( + c.users, + self.user, + False, + self.user_regex): + continue + + yield c diff --git a/lib/python2.7/site-packages/setoolsgui/setools/contextquery.py b/lib/python2.7/site-packages/setoolsgui/setools/contextquery.py new file mode 100644 index 0000000..5ce1632 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/contextquery.py @@ -0,0 +1,98 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +# pylint: disable=attribute-defined-outside-init,no-member +import re + +from . import query +from .descriptors import CriteriaDescriptor + + +class ContextQuery(query.PolicyQuery): + + """ + Base class for SETools in-policy labeling/context queries. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + context The object to match. + user The user to match in the context. + user_regex If true, regular expression matching + will be used on the user. + role The role to match in the context. + role_regex If true, regular expression matching + will be used on the role. + type_ The type to match in the context. + type_regex If true, regular expression matching + will be used on the type. + range_ The range to match in the context. + range_subset If true, the criteria will match if it + is a subset of the context's range. + range_overlap If true, the criteria will match if it + overlaps any of the context's range. + range_superset If true, the criteria will match if it + is a superset of the context's range. + range_proper If true, use proper superset/subset + on range matching operations. + No effect if not using set operations. + """ + + user = CriteriaDescriptor("user_regex", "lookup_user") + user_regex = False + role = CriteriaDescriptor("role_regex", "lookup_role") + role_regex = False + type_ = CriteriaDescriptor("type_regex", "lookup_type") + type_regex = False + range_ = CriteriaDescriptor(lookup_function="lookup_range") + range_overlap = False + range_subset = False + range_superset = False + range_proper = False + + def _match_context(self, context): + + if self.user and not query.PolicyQuery._match_regex( + context.user, + self.user, + self.user_regex): + return False + + if self.role and not query.PolicyQuery._match_regex( + context.role, + self.role, + self.role_regex): + return False + + if self.type_ and not query.PolicyQuery._match_regex( + context.type_, + self.type_, + self.type_regex): + return False + + if self.range_ and not query.PolicyQuery._match_range( + context.range_, + self.range_, + self.range_subset, + self.range_overlap, + self.range_superset, + self.range_proper): + return False + + return True diff --git a/lib/python2.7/site-packages/setoolsgui/setools/descriptors.py b/lib/python2.7/site-packages/setoolsgui/setools/descriptors.py new file mode 100644 index 0000000..eab9210 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/descriptors.py @@ -0,0 +1,230 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +""" +SETools descriptors. + +These classes override how a class's attributes are get/set/deleted. +This is how the @property decorator works. + +See https://docs.python.org/3/howto/descriptor.html +for more details. +""" + +import re +from collections import defaultdict +from weakref import WeakKeyDictionary + +# +# Query criteria descriptors +# +# Implementation note: if the name_regex attribute value +# is changed the criteria must be reset. +# + + +class CriteriaDescriptor(object): + + """ + Single item criteria descriptor. + + Parameters: + name_regex The name of instance's regex setting attribute; + used as name_regex below. If unset, + regular expressions will never be used. + lookup_function The name of the SELinuxPolicy lookup function, + e.g. lookup_type or lookup_boolean. + default_value The default value of the criteria. The default + is None. + + Read-only instance attribute use (obj parameter): + policy The instance of SELinuxPolicy + name_regex This attribute is read to determine if + the criteria should be looked up or + compiled into a regex. If the attribute + does not exist, False is assumed. + """ + + def __init__(self, name_regex=None, lookup_function=None, default_value=None): + assert name_regex or lookup_function, "A simple attribute should be used if there is " \ + "no regex nor lookup function." + self.regex = name_regex + self.default_value = default_value + self.lookup_function = lookup_function + + # use weak references so instances can be + # garbage collected, rather than unnecessarily + # kept around due to this descriptor. + self.instances = WeakKeyDictionary() + + def __get__(self, obj, objtype=None): + if obj is None: + return self + + return self.instances.setdefault(obj, self.default_value) + + def __set__(self, obj, value): + if not value: + self.instances[obj] = None + elif self.regex and getattr(obj, self.regex, False): + self.instances[obj] = re.compile(value) + elif self.lookup_function: + lookup = getattr(obj.policy, self.lookup_function) + self.instances[obj] = lookup(value) + else: + self.instances[obj] = value + + +class CriteriaSetDescriptor(CriteriaDescriptor): + + """Descriptor for a set of criteria.""" + + def __set__(self, obj, value): + if not value: + self.instances[obj] = None + elif self.regex and getattr(obj, self.regex, False): + self.instances[obj] = re.compile(value) + elif self.lookup_function: + lookup = getattr(obj.policy, self.lookup_function) + self.instances[obj] = set(lookup(v) for v in value) + else: + self.instances[obj] = set(value) + + +class RuletypeDescriptor(object): + + """ + Descriptor for a list of rule types. + + Parameters: + validator The name of the SELinuxPolicy ruletype + validator function, e.g. validate_te_ruletype + default_value The default value of the criteria. The default + is None. + + Read-only instance attribute use (obj parameter): + policy The instance of SELinuxPolicy + """ + + def __init__(self, validator): + self.validator = validator + + # use weak references so instances can be + # garbage collected, rather than unnecessarily + # kept around due to this descriptor. + self.instances = WeakKeyDictionary() + + def __get__(self, obj, objtype=None): + if obj is None: + return self + + return self.instances.setdefault(obj, None) + + def __set__(self, obj, value): + if value: + validate = getattr(obj.policy, self.validator) + validate(value) + self.instances[obj] = value + else: + self.instances[obj] = None + + +# +# NetworkX Graph Descriptors +# +# These descriptors are used to simplify all +# of the dictionary use in the NetworkX graph. +# + + +class NetworkXGraphEdgeDescriptor(object): + + """ + Descriptor base class for NetworkX graph edge attributes. + + Parameter: + name The edge property name + + Instance class attribute use (obj parameter): + G The NetworkX graph + source The edge's source node + target The edge's target node + """ + + def __init__(self, propname): + self.name = propname + + def __get__(self, obj, objtype=None): + if obj is None: + return self + + return obj.G[obj.source][obj.target][self.name] + + def __set__(self, obj, value): + raise NotImplementedError + + def __delete__(self, obj): + raise NotImplementedError + + +class EdgeAttrDict(NetworkXGraphEdgeDescriptor): + + """A descriptor for edge attributes that are dictionaries.""" + + def __set__(self, obj, value): + # None is a special value to initialize the attribute + if value is None: + obj.G[obj.source][obj.target][self.name] = defaultdict(list) + else: + raise ValueError("{0} dictionaries should not be assigned directly".format(self.name)) + + def __delete__(self, obj): + obj.G[obj.source][obj.target][self.name].clear() + + +class EdgeAttrIntMax(NetworkXGraphEdgeDescriptor): + + """ + A descriptor for edge attributes that are non-negative integers that always + keep the max assigned value until re-initialized. + """ + + def __set__(self, obj, value): + # None is a special value to initialize + if value is None: + obj.G[obj.source][obj.target][self.name] = 0 + else: + current_value = obj.G[obj.source][obj.target][self.name] + obj.G[obj.source][obj.target][self.name] = max(current_value, value) + + +class EdgeAttrList(NetworkXGraphEdgeDescriptor): + + """A descriptor for edge attributes that are lists.""" + + def __set__(self, obj, value): + # None is a special value to initialize + if value is None: + obj.G[obj.source][obj.target][self.name] = [] + else: + raise ValueError("{0} lists should not be assigned directly".format(self.name)) + + def __delete__(self, obj): + # in Python3 a .clear() function was added for lists + # keep this implementation for Python 2 compat + del obj.G[obj.source][obj.target][self.name][:] diff --git a/lib/python2.7/site-packages/setoolsgui/setools/dta.py b/lib/python2.7/site-packages/setoolsgui/setools/dta.py new file mode 100644 index 0000000..271efc4 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/dta.py @@ -0,0 +1,603 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import itertools +import logging +from collections import defaultdict, namedtuple + +import networkx as nx +from networkx.exception import NetworkXError, NetworkXNoPath + +from .descriptors import EdgeAttrDict, EdgeAttrList + +__all__ = ['DomainTransitionAnalysis'] + +# Return values for the analysis +# are in the following tuple formats: +step_output = namedtuple("step", ["source", + "target", + "transition", + "entrypoints", + "setexec", + "dyntransition", + "setcurrent"]) + +entrypoint_output = namedtuple("entrypoints", ["name", + "entrypoint", + "execute", + "type_transition"]) + + +class DomainTransitionAnalysis(object): + + """Domain transition analysis.""" + + def __init__(self, policy, reverse=False, exclude=None): + """ + Parameter: + policy The policy to analyze. + """ + self.log = logging.getLogger(self.__class__.__name__) + + self.policy = policy + self.exclude = exclude + self.reverse = reverse + self.rebuildgraph = True + self.rebuildsubgraph = True + self.G = nx.DiGraph() + self.subG = None + + @property + def reverse(self): + return self._reverse + + @reverse.setter + def reverse(self, direction): + self._reverse = bool(direction) + self.rebuildsubgraph = True + + @property + def exclude(self): + return self._exclude + + @exclude.setter + def exclude(self, types): + if types: + self._exclude = [self.policy.lookup_type(t) for t in types] + else: + self._exclude = None + + self.rebuildsubgraph = True + + def shortest_path(self, source, target): + """ + Generator which yields one shortest domain transition path + between the source and target types (there may be more). + + Parameters: + source The source type. + target The target type. + + Yield: generator(steps) + + steps A generator that returns the tuple of + source, target, and rules for each + domain transition. + """ + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating one shortest path from {0} to {1}...".format(s, t)) + + try: + yield self.__generate_steps(nx.shortest_path(self.subG, s, t)) + except (NetworkXNoPath, NetworkXError): + # NetworkXError: the type is valid but not in graph, e.g. excluded + # NetworkXNoPath: no paths or the target type is + # not in the graph + pass + + def all_paths(self, source, target, maxlen=2): + """ + Generator which yields all domain transition paths between + the source and target up to the specified maximum path + length. + + Parameters: + source The source type. + target The target type. + maxlen Maximum length of paths. + + Yield: generator(steps) + + steps A generator that returns the tuple of + source, target, and rules for each + domain transition. + """ + if maxlen < 1: + raise ValueError("Maximum path length must be positive.") + + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all paths from {0} to {1}, max len {2}...".format(s, t, maxlen)) + + try: + for path in nx.all_simple_paths(self.subG, s, t, maxlen): + yield self.__generate_steps(path) + except (NetworkXNoPath, NetworkXError): + # NetworkXError: the type is valid but not in graph, e.g. excluded + # NetworkXNoPath: no paths or the target type is + # not in the graph + pass + + def all_shortest_paths(self, source, target): + """ + Generator which yields all shortest domain transition paths + between the source and target types. + + Parameters: + source The source type. + target The target type. + + Yield: generator(steps) + + steps A generator that returns the tuple of + source, target, and rules for each + domain transition. + """ + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all shortest paths from {0} to {1}...".format(s, t)) + + try: + for path in nx.all_shortest_paths(self.subG, s, t): + yield self.__generate_steps(path) + except (NetworkXNoPath, NetworkXError, KeyError): + # NetworkXError: the type is valid but not in graph, e.g. excluded + # NetworkXNoPath: no paths or the target type is + # not in the graph + # KeyError: work around NetworkX bug + # when the source node is not in the graph + pass + + def transitions(self, type_): + """ + Generator which yields all domain transitions out of a + specified source type. + + Parameters: + type_ The starting type. + + Yield: generator(steps) + + steps A generator that returns the tuple of + source, target, and rules for each + domain transition. + """ + s = self.policy.lookup_type(type_) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all transitions {1} {0}". + format(s, "in to" if self.reverse else "out from")) + + try: + for source, target in self.subG.out_edges_iter(s): + edge = Edge(self.subG, source, target) + + if self.reverse: + real_source, real_target = target, source + else: + real_source, real_target = source, target + + yield step_output(real_source, real_target, + edge.transition, + self.__generate_entrypoints(edge), + edge.setexec, + edge.dyntransition, + edge.setcurrent) + + except NetworkXError: + # NetworkXError: the type is valid but not in graph, e.g. excluded + pass + + def get_stats(self): # pragma: no cover + """ + Get the domain transition graph statistics. + + Return: tuple(nodes, edges) + + nodes The number of nodes (types) in the graph. + edges The number of edges (domain transitions) in the graph. + """ + return (self.G.number_of_nodes(), self.G.number_of_edges()) + + # + # Internal functions follow + # + @staticmethod + def __generate_entrypoints(edge): + """ + Generator which yields the entrypoint, execute, and + type_transition rules for each entrypoint. + + Parameter: + data The dictionary of entrypoints. + + Yield: tuple(type, entry, exec, trans) + + type The entrypoint type. + entry The list of entrypoint rules. + exec The list of execute rules. + trans The list of type_transition rules. + """ + for e in edge.entrypoint: + yield entrypoint_output(e, edge.entrypoint[e], edge.execute[e], edge.type_transition[e]) + + def __generate_steps(self, path): + """ + Generator which yields the source, target, and associated rules + for each domain transition. + + Parameter: + path A list of graph node names representing an information flow path. + + Yield: tuple(source, target, transition, entrypoints, + setexec, dyntransition, setcurrent) + + source The source type for this step of the domain transition. + target The target type for this step of the domain transition. + transition The list of transition rules. + entrypoints Generator which yields entrypoint-related rules. + setexec The list of setexec rules. + dyntranstion The list of dynamic transition rules. + setcurrent The list of setcurrent rules. + """ + + for s in range(1, len(path)): + source = path[s - 1] + target = path[s] + edge = Edge(self.subG, source, target) + + # Yield the actual source and target. + # The above perspective is reversed + # if the graph has been reversed. + if self.reverse: + real_source, real_target = target, source + else: + real_source, real_target = source, target + + yield step_output(real_source, real_target, + edge.transition, + self.__generate_entrypoints(edge), + edge.setexec, + edge.dyntransition, + edge.setcurrent) + + # + # Graph building functions + # + + # Domain transition requirements: + # + # Standard transitions a->b: + # allow a b:process transition; + # allow a b_exec:file execute; + # allow b b_exec:file entrypoint; + # + # and at least one of: + # allow a self:process setexec; + # type_transition a b_exec:process b; + # + # Dynamic transition x->y: + # allow x y:process dyntransition; + # allow x self:process setcurrent; + # + # Algorithm summary: + # 1. iterate over all rules + # 1. skip non allow/type_transition rules + # 2. if process transition or dyntransition, create edge, + # initialize rule lists, add the (dyn)transition rule + # 3. if process setexec or setcurrent, add to appropriate dict + # keyed on the subject + # 4. if file exec, entrypoint, or type_transition:process, + # add to appropriate dict keyed on subject,object. + # 2. Iterate over all graph edges: + # 1. if there is a transition rule (else add to invalid + # transition list): + # 1. use set intersection to find matching exec + # and entrypoint rules. If none, add to invalid + # transition list. + # 2. for each valid entrypoint, add rules to the + # edge's lists if there is either a + # type_transition for it or the source process + # has setexec permissions. + # 3. If there are neither type_transitions nor + # setexec permissions, add to the invalid + # transition list + # 2. if there is a dyntransition rule (else add to invalid + # dyntrans list): + # 1. If the source has a setcurrent rule, add it + # to the edge's list, else add to invalid + # dyntransition list. + # 3. Iterate over all graph edges: + # 1. if the edge has an invalid trans and dyntrans, delete + # the edge. + # 2. if the edge has an invalid trans, clear the related + # lists on the edge. + # 3. if the edge has an invalid dyntrans, clear the related + # lists on the edge. + # + def _build_graph(self): + self.G.clear() + + self.log.info("Building graph from {0}...".format(self.policy)) + + # hash tables keyed on domain type + setexec = defaultdict(list) + setcurrent = defaultdict(list) + + # hash tables keyed on (domain, entrypoint file type) + # the parameter for defaultdict has to be callable + # hence the lambda for the nested defaultdict + execute = defaultdict(lambda: defaultdict(list)) + entrypoint = defaultdict(lambda: defaultdict(list)) + + # hash table keyed on (domain, entrypoint, target domain) + type_trans = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) + + for rule in self.policy.terules(): + if rule.ruletype == "allow": + if rule.tclass not in ["process", "file"]: + continue + + perms = rule.perms + + if rule.tclass == "process": + if "transition" in perms: + for s, t in itertools.product(rule.source.expand(), rule.target.expand()): + # only add edges if they actually + # transition to a new type + if s != t: + edge = Edge(self.G, s, t, create=True) + edge.transition.append(rule) + + if "dyntransition" in perms: + for s, t in itertools.product(rule.source.expand(), rule.target.expand()): + # only add edges if they actually + # transition to a new type + if s != t: + e = Edge(self.G, s, t, create=True) + e.dyntransition.append(rule) + + if "setexec" in perms: + for s in rule.source.expand(): + setexec[s].append(rule) + + if "setcurrent" in perms: + for s in rule.source.expand(): + setcurrent[s].append(rule) + + else: + if "execute" in perms: + for s, t in itertools.product( + rule.source.expand(), + rule.target.expand()): + execute[s][t].append(rule) + + if "entrypoint" in perms: + for s, t in itertools.product(rule.source.expand(), rule.target.expand()): + entrypoint[s][t].append(rule) + + elif rule.ruletype == "type_transition": + if rule.tclass != "process": + continue + + d = rule.default + for s, t in itertools.product(rule.source.expand(), rule.target.expand()): + type_trans[s][t][d].append(rule) + + invalid_edge = [] + clear_transition = [] + clear_dyntransition = [] + + for s, t in self.G.edges_iter(): + edge = Edge(self.G, s, t) + invalid_trans = False + invalid_dyntrans = False + + if edge.transition: + # get matching domain exec w/entrypoint type + entry = set(entrypoint[t].keys()) + exe = set(execute[s].keys()) + match = entry.intersection(exe) + + if not match: + # there are no valid entrypoints + invalid_trans = True + else: + # TODO try to improve the + # efficiency in this loop + for m in match: + if s in setexec or type_trans[s][m]: + # add key for each entrypoint + edge.entrypoint[m] += entrypoint[t][m] + edge.execute[m] += execute[s][m] + + if type_trans[s][m][t]: + edge.type_transition[m] += type_trans[s][m][t] + + if s in setexec: + edge.setexec.extend(setexec[s]) + + if not edge.setexec and not edge.type_transition: + invalid_trans = True + else: + invalid_trans = True + + if edge.dyntransition: + if s in setcurrent: + edge.setcurrent.extend(setcurrent[s]) + else: + invalid_dyntrans = True + else: + invalid_dyntrans = True + + # cannot change the edges while iterating over them, + # so keep appropriate lists + if invalid_trans and invalid_dyntrans: + invalid_edge.append(edge) + elif invalid_trans: + clear_transition.append(edge) + elif invalid_dyntrans: + clear_dyntransition.append(edge) + + # Remove invalid transitions + self.G.remove_edges_from(invalid_edge) + for edge in clear_transition: + # if only the regular transition is invalid, + # clear the relevant lists + del edge.transition + del edge.execute + del edge.entrypoint + del edge.type_transition + del edge.setexec + for edge in clear_dyntransition: + # if only the dynamic transition is invalid, + # clear the relevant lists + del edge.dyntransition + del edge.setcurrent + + self.rebuildgraph = False + self.rebuildsubgraph = True + self.log.info("Completed building graph.") + + def __remove_excluded_entrypoints(self): + invalid_edges = [] + for source, target in self.subG.edges_iter(): + edge = Edge(self.subG, source, target) + entrypoints = set(edge.entrypoint) + entrypoints.intersection_update(self.exclude) + + if not entrypoints: + # short circuit if there are no + # excluded entrypoint types on + # this edge. + continue + + for e in entrypoints: + # clear the entrypoint data + del edge.entrypoint[e] + del edge.execute[e] + + try: + del edge.type_transition[e] + except KeyError: # setexec + pass + + # cannot delete the edges while iterating over them + if not edge.entrypoint and not edge.dyntransition: + invalid_edges.append(edge) + + self.subG.remove_edges_from(invalid_edges) + + def _build_subgraph(self): + if self.rebuildgraph: + self._build_graph() + + self.log.info("Building subgraph.") + self.log.debug("Excluding {0}".format(self.exclude)) + self.log.debug("Reverse {0}".format(self.reverse)) + + # reverse graph for reverse DTA + if self.reverse: + self.subG = self.G.reverse(copy=True) + else: + self.subG = self.G.copy() + + if self.exclude: + # delete excluded domains from subgraph + self.subG.remove_nodes_from(self.exclude) + + # delete excluded entrypoints from subgraph + self.__remove_excluded_entrypoints() + + self.rebuildsubgraph = False + self.log.info("Completed building subgraph.") + + +class Edge(object): + + """ + A graph edge. Also used for returning domain transition steps. + + Parameters: + source The source type of the edge. + target The target tyep of the edge. + + Keyword Parameters: + create (T/F) create the edge if it does not exist. + The default is False. + """ + + transition = EdgeAttrList('transition') + setexec = EdgeAttrList('setexec') + dyntransition = EdgeAttrList('dyntransition') + setcurrent = EdgeAttrList('setcurrent') + entrypoint = EdgeAttrDict('entrypoint') + execute = EdgeAttrDict('execute') + type_transition = EdgeAttrDict('type_transition') + + def __init__(self, graph, source, target, create=False): + self.G = graph + self.source = source + self.target = target + + # a bit of a hack to make Edges work + # in NetworkX functions that work on + # 2-tuples of (source, target) + # (see __getitem__ below) + self.st_tuple = (source, target) + + if not self.G.has_edge(source, target): + if not create: + raise ValueError("Edge does not exist in graph") + else: + self.G.add_edge(source, target) + self.transition = None + self.entrypoint = None + self.execute = None + self.type_transition = None + self.setexec = None + self.dyntransition = None + self.setcurrent = None + + def __getitem__(self, key): + return self.st_tuple[key] diff --git a/lib/python2.7/site-packages/setoolsgui/setools/exception.py b/lib/python2.7/site-packages/setoolsgui/setools/exception.py new file mode 100644 index 0000000..c3505cd --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/exception.py @@ -0,0 +1,62 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# + +# +# Base class for exceptions +# + + +class SEToolsException(Exception): + + """Base class for all SETools exceptions.""" + pass + +# +# Permission map exceptions +# + + +class PermissionMapException(SEToolsException): + + """Base class for all permission map exceptions.""" + pass + + +class PermissionMapParseError(PermissionMapException): + + """Exception for parse errors while reading permission map files.""" + pass + + +class RuleTypeError(PermissionMapException): + + """Exception for using rules with incorrect rule type.""" + pass + + +class UnmappedClass(PermissionMapException): + + """Exception for classes that are unmapped""" + pass + + +class UnmappedPermission(PermissionMapException): + + """Exception for permissions that are unmapped""" + pass diff --git a/lib/python2.7/site-packages/setoolsgui/setools/fsusequery.py b/lib/python2.7/site-packages/setoolsgui/setools/fsusequery.py new file mode 100644 index 0000000..6825a45 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/fsusequery.py @@ -0,0 +1,87 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import contextquery +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor + + +class FSUseQuery(contextquery.ContextQuery): + + """ + Query fs_use_* statements. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The rule type(s) to match. + fs The criteria to match the file system type. + fs_regex If true, regular expression matching + will be used on the file system type. + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + ruletype = None + fs = CriteriaDescriptor("fs_regex") + fs_regex = False + + def results(self): + """Generator which yields all matching fs_use_* statements.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for fsu in self.policy.fs_uses(): + if self.ruletype and fsu.ruletype not in self.ruletype: + continue + + if self.fs and not self._match_regex( + fsu.fs, + self.fs, + self.fs_regex): + continue + + if not self._match_context(fsu.context): + continue + + yield fsu diff --git a/lib/python2.7/site-packages/setoolsgui/setools/genfsconquery.py b/lib/python2.7/site-packages/setoolsgui/setools/genfsconquery.py new file mode 100644 index 0000000..c67dfd6 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/genfsconquery.py @@ -0,0 +1,98 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import contextquery +from .descriptors import CriteriaDescriptor + + +class GenfsconQuery(contextquery.ContextQuery): + + """ + Query genfscon statements. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + fs The criteria to match the file system type. + fs_regex If true, regular expression matching + will be used on the file system type. + path The criteria to match the path. + path_regex If true, regular expression matching + will be used on the path. + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + filetype = None + fs = CriteriaDescriptor("fs_regex") + fs_regex = False + path = CriteriaDescriptor("path_regex") + path_regex = False + + def results(self): + """Generator which yields all matching genfscons.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) + self.log.debug("Path: {0.path!r}, regex: {0.path_regex}".format(self)) + self.log.debug("Filetype: {0.filetype!r}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for genfs in self.policy.genfscons(): + if self.fs and not self._match_regex( + genfs.fs, + self.fs, + self.fs_regex): + continue + + if self.path and not self._match_regex( + genfs.path, + self.path, + self.path_regex): + continue + + if self.filetype and not self.filetype == genfs.filetype: + continue + + if not self._match_context(genfs.context): + continue + + yield genfs diff --git a/lib/python2.7/site-packages/setoolsgui/setools/infoflow.py b/lib/python2.7/site-packages/setoolsgui/setools/infoflow.py new file mode 100644 index 0000000..ea3ec32 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/infoflow.py @@ -0,0 +1,403 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import itertools +import logging +from collections import namedtuple + +import networkx as nx +from networkx.exception import NetworkXError, NetworkXNoPath + +from .descriptors import EdgeAttrIntMax, EdgeAttrList + +__all__ = ['InfoFlowAnalysis'] + +# Return values for the analysis +# are in the following tuple format: +step_output = namedtuple("step", ["source", + "target", + "rules"]) + + +class InfoFlowAnalysis(object): + + """Information flow analysis.""" + + def __init__(self, policy, perm_map, min_weight=1, exclude=None): + """ + Parameters: + policy The policy to analyze. + perm_map The permission map or path to the permission map file. + minweight The minimum permission weight to include in the analysis. + (default is 1) + exclude The types excluded from the information flow analysis. + (default is none) + """ + self.log = logging.getLogger(self.__class__.__name__) + + self.policy = policy + + self.min_weight = min_weight + self.perm_map = perm_map + self.exclude = exclude + self.rebuildgraph = True + self.rebuildsubgraph = True + + self.G = nx.DiGraph() + self.subG = None + + @property + def min_weight(self): + return self._min_weight + + @min_weight.setter + def min_weight(self, weight): + if not 1 <= weight <= 10: + raise ValueError( + "Min information flow weight must be an integer 1-10.") + + self._min_weight = weight + self.rebuildsubgraph = True + + @property + def perm_map(self): + return self._perm_map + + @perm_map.setter + def perm_map(self, perm_map): + self._perm_map = perm_map + self.rebuildgraph = True + self.rebuildsubgraph = True + + @property + def exclude(self): + return self._exclude + + @exclude.setter + def exclude(self, types): + if types: + self._exclude = [self.policy.lookup_type(t) for t in types] + else: + self._exclude = [] + + self.rebuildsubgraph = True + + def shortest_path(self, source, target): + """ + Generator which yields one shortest path between the source + and target types (there may be more). + + Parameters: + source The source type. + target The target type. + + Yield: generator(steps) + + steps Yield: tuple(source, target, rules) + + source The source type for this step of the information flow. + target The target type for this step of the information flow. + rules The list of rules creating this information flow step. + """ + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating one shortest path from {0} to {1}...".format(s, t)) + + try: + yield self.__generate_steps(nx.shortest_path(self.subG, s, t)) + except (NetworkXNoPath, NetworkXError): + # NetworkXError: the type is valid but not in graph, e.g. + # excluded or disconnected due to min weight + # NetworkXNoPath: no paths or the target type is + # not in the graph + pass + + def all_paths(self, source, target, maxlen=2): + """ + Generator which yields all paths between the source and target + up to the specified maximum path length. This algorithm + tends to get very expensive above 3-5 steps, depending + on the policy complexity. + + Parameters: + source The source type. + target The target type. + maxlen Maximum length of paths. + + Yield: generator(steps) + + steps Yield: tuple(source, target, rules) + + source The source type for this step of the information flow. + target The target type for this step of the information flow. + rules The list of rules creating this information flow step. + """ + if maxlen < 1: + raise ValueError("Maximum path length must be positive.") + + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all paths from {0} to {1}, max len {2}...".format(s, t, maxlen)) + + try: + for path in nx.all_simple_paths(self.subG, s, t, maxlen): + yield self.__generate_steps(path) + except (NetworkXNoPath, NetworkXError): + # NetworkXError: the type is valid but not in graph, e.g. + # excluded or disconnected due to min weight + # NetworkXNoPath: no paths or the target type is + # not in the graph + pass + + def all_shortest_paths(self, source, target): + """ + Generator which yields all shortest paths between the source + and target types. + + Parameters: + source The source type. + target The target type. + + Yield: generator(steps) + + steps Yield: tuple(source, target, rules) + + source The source type for this step of the information flow. + target The target type for this step of the information flow. + rules The list of rules creating this information flow step. + """ + s = self.policy.lookup_type(source) + t = self.policy.lookup_type(target) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all shortest paths from {0} to {1}...".format(s, t)) + + try: + for path in nx.all_shortest_paths(self.subG, s, t): + yield self.__generate_steps(path) + except (NetworkXNoPath, NetworkXError, KeyError): + # NetworkXError: the type is valid but not in graph, e.g. + # excluded or disconnected due to min weight + # NetworkXNoPath: no paths or the target type is + # not in the graph + # KeyError: work around NetworkX bug + # when the source node is not in the graph + pass + + def infoflows(self, type_, out=True): + """ + Generator which yields all information flows in/out of a + specified source type. + + Parameters: + source The starting type. + + Keyword Parameters: + out If true, information flows out of the type will + be returned. If false, information flows in to the + type will be returned. Default is true. + + Yield: generator(steps) + + steps A generator that returns the tuple of + source, target, and rules for each + information flow. + """ + s = self.policy.lookup_type(type_) + + if self.rebuildsubgraph: + self._build_subgraph() + + self.log.info("Generating all infoflows out of {0}...".format(s)) + + if out: + flows = self.subG.out_edges_iter(s) + else: + flows = self.subG.in_edges_iter(s) + + try: + for source, target in flows: + edge = Edge(self.subG, source, target) + yield step_output(source, target, edge.rules) + except NetworkXError: + # NetworkXError: the type is valid but not in graph, e.g. + # excluded or disconnected due to min weight + pass + + def get_stats(self): # pragma: no cover + """ + Get the information flow graph statistics. + + Return: tuple(nodes, edges) + + nodes The number of nodes (types) in the graph. + edges The number of edges (information flows between types) + in the graph. + """ + return (self.G.number_of_nodes(), self.G.number_of_edges()) + + # + # Internal functions follow + # + + def __generate_steps(self, path): + """ + Generator which returns the source, target, and associated rules + for each information flow step. + + Parameter: + path A list of graph node names representing an information flow path. + + Yield: tuple(source, target, rules) + + source The source type for this step of the information flow. + target The target type for this step of the information flow. + rules The list of rules creating this information flow step. + """ + for s in range(1, len(path)): + edge = Edge(self.subG, path[s - 1], path[s]) + yield step_output(edge.source, edge.target, edge.rules) + + # + # + # Graph building functions + # + # + # 1. _build_graph determines the flow in each direction for each TE + # rule and then expands the rule. All information flows are + # included in this main graph: memory is traded off for efficiency + # as the main graph should only need to be rebuilt if permission + # weights change. + # 2. _build_subgraph derives a subgraph which removes all excluded + # types (nodes) and edges (information flows) which are below the + # minimum weight. This subgraph is rebuilt only if the main graph + # is rebuilt or the minimum weight or excluded types change. + + def _build_graph(self): + self.G.clear() + + self.perm_map.map_policy(self.policy) + + self.log.info("Building graph from {0}...".format(self.policy)) + + for rule in self.policy.terules(): + if rule.ruletype != "allow": + continue + + (rweight, wweight) = self.perm_map.rule_weight(rule) + + for s, t in itertools.product(rule.source.expand(), rule.target.expand()): + # only add flows if they actually flow + # in or out of the source type type + if s != t: + if wweight: + edge = Edge(self.G, s, t, create=True) + edge.rules.append(rule) + edge.weight = wweight + + if rweight: + edge = Edge(self.G, t, s, create=True) + edge.rules.append(rule) + edge.weight = rweight + + self.rebuildgraph = False + self.rebuildsubgraph = True + self.log.info("Completed building graph.") + + def _build_subgraph(self): + if self.rebuildgraph: + self._build_graph() + + self.log.info("Building subgraph...") + self.log.debug("Excluding {0!r}".format(self.exclude)) + self.log.debug("Min weight {0}".format(self.min_weight)) + + # delete excluded types from subgraph + nodes = [n for n in self.G.nodes() if n not in self.exclude] + self.subG = self.G.subgraph(nodes) + + # delete edges below minimum weight. + # no need if weight is 1, since that + # does not exclude any edges. + if self.min_weight > 1: + delete_list = [] + for s, t in self.subG.edges_iter(): + edge = Edge(self.subG, s, t) + if edge.weight < self.min_weight: + delete_list.append(edge) + + self.subG.remove_edges_from(delete_list) + + self.rebuildsubgraph = False + self.log.info("Completed building subgraph.") + + +class Edge(object): + + """ + A graph edge. Also used for returning information flow steps. + + Parameters: + source The source type of the edge. + target The target type of the edge. + + Keyword Parameters: + create (T/F) create the edge if it does not exist. + The default is False. + """ + + rules = EdgeAttrList('rules') + + # use capacity to store the info flow weight so + # we can use network flow algorithms naturally. + # The weight for each edge is 1 since each info + # flow step is no more costly than another + # (see below add_edge() call) + weight = EdgeAttrIntMax('capacity') + + def __init__(self, graph, source, target, create=False): + self.G = graph + self.source = source + self.target = target + + # a bit of a hack to make edges work + # in NetworkX functions that work on + # 2-tuples of (source, target) + # (see __getitem__ below) + self.st_tuple = (source, target) + + if not self.G.has_edge(source, target): + if create: + self.G.add_edge(source, target, weight=1) + self.rules = None + self.weight = None + else: + raise ValueError("Edge does not exist in graph") + + def __getitem__(self, key): + return self.st_tuple[key] diff --git a/lib/python2.7/site-packages/setoolsgui/setools/initsidquery.py b/lib/python2.7/site-packages/setoolsgui/setools/initsidquery.py new file mode 100644 index 0000000..1eb3790 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/initsidquery.py @@ -0,0 +1,74 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery +from . import contextquery + + +class InitialSIDQuery(compquery.ComponentQuery, contextquery.ContextQuery): + + """ + Initial SID (Initial context) query. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The Initial SID name to match. + name_regex If true, regular expression matching + will be used on the Initial SID name. + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + def results(self): + """Generator which yields all matching initial SIDs.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for i in self.policy.initialsids(): + if not self._match_name(i): + continue + + if not self._match_context(i.context): + continue + + yield i diff --git a/lib/python2.7/site-packages/setoolsgui/setools/mixins.py b/lib/python2.7/site-packages/setoolsgui/setools/mixins.py new file mode 100644 index 0000000..a31d420 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/mixins.py @@ -0,0 +1,91 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +# pylint: disable=attribute-defined-outside-init,no-member +import re + +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor + + +class MatchAlias(object): + + """Mixin for matching an object's aliases.""" + + alias = CriteriaDescriptor("alias_regex") + alias_regex = False + + def _match_alias(self, obj): + """ + Match the alias criteria + + Parameter: + obj An object with an alias generator method named "aliases" + """ + + if not self.alias: + # if there is no criteria, everything matches. + return True + + return self._match_in_set(obj.aliases(), self.alias, self.alias_regex) + + +class MatchObjClass(object): + + """Mixin for matching an object's class.""" + + tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") + tclass_regex = False + + def _match_object_class(self, obj): + """ + Match the object class criteria + + Parameter: + obj An object with an object class attribute named "tclass" + """ + + if not self.tclass: + # if there is no criteria, everything matches. + return True + elif self.tclass_regex: + return bool(self.tclass.search(str(obj.tclass))) + else: + return obj.tclass in self.tclass + + +class MatchPermission(object): + + """Mixin for matching an object's permissions.""" + + perms = CriteriaSetDescriptor("perms_regex") + perms_equal = False + perms_regex = False + + def _match_perms(self, obj): + """ + Match the permission criteria + + Parameter: + obj An object with a permission set class attribute named "perms" + """ + + if not self.perms: + # if there is no criteria, everything matches. + return True + + return self._match_regex_or_set(obj.perms, self.perms, self.perms_equal, self.perms_regex) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/mlsrulequery.py b/lib/python2.7/site-packages/setoolsgui/setools/mlsrulequery.py new file mode 100644 index 0000000..3a9e1bf --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/mlsrulequery.py @@ -0,0 +1,115 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import mixins, query +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, RuletypeDescriptor + + +class MLSRuleQuery(mixins.MatchObjClass, query.PolicyQuery): + + """ + Query MLS rules. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The list of rule type(s) to match. + source The name of the source type/attribute to match. + source_regex If true, regular expression matching will + be used on the source type/attribute. + target The name of the target type/attribute to match. + target_regex If true, regular expression matching will + be used on the target type/attribute. + tclass The object class(es) to match. + tclass_regex If true, use a regular expression for + matching the rule's object class. + """ + + ruletype = RuletypeDescriptor("validate_mls_ruletype") + source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") + source_regex = False + target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") + target_regex = False + tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") + tclass_regex = False + default = CriteriaDescriptor(lookup_function="lookup_range") + default_overlap = False + default_subset = False + default_superset = False + default_proper = False + + def results(self): + """Generator which yields all matching MLS rules.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + self.log.debug("Source: {0.source!r}, regex: {0.source_regex}".format(self)) + self.log.debug("Target: {0.target!r}, regex: {0.target_regex}".format(self)) + self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) + self.log.debug("Default: {0.default!r}, overlap: {0.default_overlap}, " + "subset: {0.default_subset}, superset: {0.default_superset}, " + "proper: {0.default_proper}".format(self)) + + for rule in self.policy.mlsrules(): + # + # Matching on rule type + # + if self.ruletype: + if rule.ruletype not in self.ruletype: + continue + + # + # Matching on source type + # + if self.source and not self._match_regex( + rule.source, + self.source, + self.source_regex): + continue + + # + # Matching on target type + # + if self.target and not self._match_regex( + rule.target, + self.target, + self.target_regex): + continue + + # + # Matching on object class + # + if not self._match_object_class(rule): + continue + + # + # Matching on range + # + if self.default and not self._match_range( + rule.default, + self.default, + self.default_subset, + self.default_overlap, + self.default_superset, + self.default_proper): + continue + + # if we get here, we have matched all available criteria + yield rule diff --git a/lib/python2.7/site-packages/setoolsgui/setools/netifconquery.py b/lib/python2.7/site-packages/setoolsgui/setools/netifconquery.py new file mode 100644 index 0000000..30db977 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/netifconquery.py @@ -0,0 +1,77 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery +from . import contextquery + + +class NetifconQuery(compquery.ComponentQuery, contextquery.ContextQuery): + + """ + Network interface context query. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the network interface to match. + name_regex If true, regular expression matching will + be used for matching the name. + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + def results(self): + """Generator which yields all matching netifcons.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for netif in self.policy.netifcons(): + if self.name and not self._match_regex( + netif.netif, + self.name, + self.name_regex): + continue + + if not self._match_context(netif.context): + continue + + yield netif diff --git a/lib/python2.7/site-packages/setoolsgui/setools/nodeconquery.py b/lib/python2.7/site-packages/setoolsgui/setools/nodeconquery.py new file mode 100644 index 0000000..eb21d81 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/nodeconquery.py @@ -0,0 +1,148 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +try: + import ipaddress +except ImportError: # pragma: no cover + pass + +import logging +from socket import AF_INET, AF_INET6 + +from . import contextquery + + +class NodeconQuery(contextquery.ContextQuery): + + """ + Query nodecon statements. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + network The IPv4/IPv6 address or IPv4/IPv6 network address + with netmask, e.g. 192.168.1.0/255.255.255.0 or + "192.168.1.0/24". + network_overlap If true, the net will match if it overlaps with + the nodecon's network instead of equality. + ip_version The IP version of the nodecon to match. (socket.AF_INET + for IPv4 or socket.AF_INET6 for IPv6) + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + _network = None + network_overlap = False + _ip_version = None + + @property + def ip_version(self): + return self._ip_version + + @ip_version.setter + def ip_version(self, value): + if value: + if not (value == AF_INET or value == AF_INET6): + raise ValueError( + "The address family must be {0} for IPv4 or {1} for IPv6.". + format(AF_INET, AF_INET6)) + + self._ip_version = value + else: + self._ip_version = None + + @property + def network(self): + return self._network + + @network.setter + def network(self, value): + if value: + try: + self._network = ipaddress.ip_network(value) + except NameError: # pragma: no cover + raise RuntimeError("Nodecon IP address/network functions require Python 3.3+.") + else: + self._network = None + + def results(self): + """Generator which yields all matching nodecons.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Network: {0.network!r}, overlap: {0.network_overlap}".format(self)) + self.log.debug("IP Version: {0.ip_version}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for nodecon in self.policy.nodecons(): + + if self.network: + try: + netmask = ipaddress.ip_address(nodecon.netmask) + except NameError: # pragma: no cover + # Should never actually hit this since the self.network + # setter raises the same exception. + raise RuntimeError("Nodecon IP address/network functions require Python 3.3+.") + + # Python 3.3's IPv6Network constructor does not support + # expanded netmasks, only CIDR numbers. Convert netmask + # into CIDR. + # This is Brian Kernighan's method for counting set bits. + # If the netmask happens to be invalid, this will + # not detect it. + CIDR = 0 + int_netmask = int(netmask) + while int_netmask: + int_netmask &= int_netmask - 1 + CIDR += 1 + + net = ipaddress.ip_network('{0}/{1}'.format(nodecon.address, CIDR)) + + if self.network_overlap: + if not self.network.overlaps(net): + continue + else: + if not net == self.network: + continue + + if self.ip_version and self.ip_version != nodecon.ip_version: + continue + + if not self._match_context(nodecon.context): + continue + + yield nodecon diff --git a/lib/python2.7/site-packages/setoolsgui/setools/objclassquery.py b/lib/python2.7/site-packages/setoolsgui/setools/objclassquery.py new file mode 100644 index 0000000..8f40df8 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/objclassquery.py @@ -0,0 +1,101 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor +from .policyrep.exception import NoCommon + + +class ObjClassQuery(compquery.ComponentQuery): + + """ + Query object classes. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the object set to match. + name_regex If true, regular expression matching will + be used for matching the name. + common The name of the inherited common to match. + common_regex If true, regular expression matching will + be used for matching the common name. + perms The permissions to match. + perms_equal If true, only commons with permission sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + perms_regex If true, regular expression matching + will be used on the permission names instead + of set logic. + comparison will not be used. + perms_indirect If false, permissions inherited from a common + permission set not will be evaluated. Default + is true. + """ + + common = CriteriaDescriptor("common_regex", "lookup_common") + common_regex = False + perms = CriteriaSetDescriptor("perms_regex") + perms_equal = False + perms_indirect = True + perms_regex = False + + def results(self): + """Generator which yields all matching object classes.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Common: {0.common!r}, regex: {0.common_regex}".format(self)) + self.log.debug("Perms: {0.perms}, regex: {0.perms_regex}, " + "eq: {0.perms_equal}, indirect: {0.perms_indirect}".format(self)) + + for class_ in self.policy.classes(): + if not self._match_name(class_): + continue + + if self.common: + try: + if not self._match_regex( + class_.common, + self.common, + self.common_regex): + continue + except NoCommon: + continue + + if self.perms: + perms = class_.perms + + if self.perms_indirect: + try: + perms |= class_.common.perms + except NoCommon: + pass + + if not self._match_regex_or_set( + perms, + self.perms, + self.perms_equal, + self.perms_regex): + continue + + yield class_ diff --git a/lib/python2.7/site-packages/setoolsgui/setools/permmap.py b/lib/python2.7/site-packages/setoolsgui/setools/permmap.py new file mode 100644 index 0000000..54cd9f9 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/permmap.py @@ -0,0 +1,363 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import sys +import logging +from errno import ENOENT + +from . import exception +from . import policyrep + + +class PermissionMap(object): + + """Permission Map for information flow analysis.""" + + valid_infoflow_directions = ["r", "w", "b", "n", "u"] + min_weight = 1 + max_weight = 10 + + def __init__(self, permmapfile=None): + """ + Parameter: + permmapfile The path to the permission map to load. + """ + self.log = logging.getLogger(self.__class__.__name__) + + if permmapfile: + self.load(permmapfile) + else: + for path in ["data/", sys.prefix + "/share/setools/"]: + try: + self.load(path + "perm_map") + break + except (IOError, OSError) as err: + if err.errno != ENOENT: + raise + else: + raise RuntimeError("Unable to load default permission map.") + + def load(self, permmapfile): + """ + Parameter: + permmapfile The path to the permission map to load. + """ + self.log.info("Opening permission map \"{0}\"".format(permmapfile)) + + # state machine + # 1 = read number of classes + # 2 = read class name and number of perms + # 3 = read perms + with open(permmapfile, "r") as mapfile: + class_count = 0 + num_classes = 0 + state = 1 + + self.permmap = dict() + + for line_num, line in enumerate(mapfile, start=1): + entry = line.split() + + if len(entry) == 0 or entry[0][0] == '#': + continue + + if state == 1: + try: + num_classes = int(entry[0]) + except ValueError: + raise exception.PermissionMapParseError( + "{0}:{1}:Invalid number of classes: {2}". + format(permmapfile, line_num, entry[0])) + + if num_classes < 1: + raise exception.PermissionMapParseError( + "{0}:{1}:Number of classes must be positive: {2}". + format(permmapfile, line_num, entry[0])) + + state = 2 + + elif state == 2: + if len(entry) != 3 or entry[0] != "class": + raise exception.PermissionMapParseError( + "{0}:{1}:Invalid class declaration: {2}". + format(permmapfile, line_num, entry)) + + class_name = str(entry[1]) + + try: + num_perms = int(entry[2]) + except ValueError: + raise exception.PermissionMapParseError( + "{0}:{1}:Invalid number of permissions: {2}". + format(permmapfile, line_num, entry[2])) + + if num_perms < 1: + raise exception.PermissionMapParseError( + "{0}:{1}:Number of permissions must be positive: {2}". + format(permmapfile, line_num, entry[2])) + + class_count += 1 + if class_count > num_classes: + raise exception.PermissionMapParseError( + "{0}:{1}:Extra class found: {2}". + format(permmapfile, line_num, class_name)) + + self.permmap[class_name] = dict() + perm_count = 0 + state = 3 + + elif state == 3: + perm_name = str(entry[0]) + + flow_direction = str(entry[1]) + if flow_direction not in self.valid_infoflow_directions: + raise exception.PermissionMapParseError( + "{0}:{1}:Invalid information flow direction: {2}". + format(permmapfile, line_num, entry[1])) + + try: + weight = int(entry[2]) + except ValueError: + raise exception.PermissionMapParseError( + "{0}:{1}:Invalid permission weight: {2}". + format(permmapfile, line_num, entry[2])) + + if not self.min_weight <= weight <= self.max_weight: + raise exception.PermissionMapParseError( + "{0}:{1}:Permission weight must be {3}-{4}: {2}". + format(permmapfile, line_num, entry[2], + self.min_weight, self.max_weight)) + + self.permmap[class_name][perm_name] = {'direction': flow_direction, + 'weight': weight, + 'enabled': True} + + perm_count += 1 + if perm_count >= num_perms: + state = 2 + + def exclude_class(self, class_): + """ + Exclude all permissions in an object class for calculating rule weights. + + Parameter: + class_ The object class to exclude. + + Exceptions: + UnmappedClass The specified object class is not mapped. + """ + + classname = str(class_) + + try: + for perm in self.permmap[classname]: + self.permmap[classname][perm]['enabled'] = False + except KeyError: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + def exclude_permission(self, class_, permission): + """ + Exclude a permission for calculating rule weights. + + Parameter: + class_ The object class of the permission. + permission The permission name to exclude. + + Exceptions: + UnmappedClass The specified object class is not mapped. + UnmappedPermission The specified permission is not mapped for the object class. + """ + classname = str(class_) + + if classname not in self.permmap: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + try: + self.permmap[classname][permission]['enabled'] = False + except KeyError: + raise exception.UnmappedPermission("{0}:{1} is not mapped.". + format(classname, permission)) + + def include_class(self, class_): + """ + Include all permissions in an object class for calculating rule weights. + + Parameter: + class_ The object class to include. + + Exceptions: + UnmappedClass The specified object class is not mapped. + """ + + classname = str(class_) + + try: + for perm in self.permmap[classname]: + self.permmap[classname][perm]['enabled'] = True + except KeyError: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + def include_permission(self, class_, permission): + """ + Include a permission for calculating rule weights. + + Parameter: + class_ The object class of the permission. + permission The permission name to include. + + Exceptions: + UnmappedClass The specified object class is not mapped. + UnmappedPermission The specified permission is not mapped for the object class. + """ + + classname = str(class_) + + if classname not in self.permmap: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + try: + self.permmap[classname][permission]['enabled'] = True + except KeyError: + raise exception.UnmappedPermission("{0}:{1} is not mapped.". + format(classname, permission)) + + def map_policy(self, policy): + """Create mappings for all classes and permissions in the specified policy.""" + for class_ in policy.classes(): + class_name = str(class_) + + if class_name not in self.permmap: + self.log.info("Adding unmapped class {0} from {1}".format(class_name, policy)) + self.permmap[class_name] = dict() + + perms = class_.perms + + try: + perms |= class_.common.perms + except policyrep.exception.NoCommon: + pass + + for perm_name in perms: + if perm_name not in self.permmap[class_name]: + self.log.info("Adding unmapped permission {0} in {1} from {2}". + format(perm_name, class_name, policy)) + self.permmap[class_name][perm_name] = {'direction': 'u', + 'weight': 1, + 'enabled': True} + + def rule_weight(self, rule): + """ + Get the type enforcement rule's information flow read and write weights. + + Parameter: + rule A type enforcement rule. + + Return: Tuple(read_weight, write_weight) + read_weight The type enforcement rule's read weight. + write_weight The type enforcement rule's write weight. + """ + + write_weight = 0 + read_weight = 0 + class_name = str(rule.tclass) + + if rule.ruletype != 'allow': + raise exception.RuleTypeError("{0} rules cannot be used for calculating a weight". + format(rule.ruletype)) + + if class_name not in self.permmap: + raise exception.UnmappedClass("{0} is not mapped.".format(class_name)) + + # iterate over the permissions and determine the + # weight of the rule in each direction. The result + # is the largest-weight permission in each direction + for perm_name in rule.perms: + try: + mapping = self.permmap[class_name][perm_name] + except KeyError: + raise exception.UnmappedPermission("{0}:{1} is not mapped.". + format(class_name, perm_name)) + + if not mapping['enabled']: + continue + + if mapping['direction'] == "r": + read_weight = max(read_weight, mapping['weight']) + elif mapping['direction'] == "w": + write_weight = max(write_weight, mapping['weight']) + elif mapping['direction'] == "b": + read_weight = max(read_weight, mapping['weight']) + write_weight = max(write_weight, mapping['weight']) + + return (read_weight, write_weight) + + def set_direction(self, class_, permission, direction): + """ + Set the information flow direction of a permission. + + Parameter: + class_ The object class of the permission. + permission The permission name. + direction The information flow direction the permission (r/w/b/n). + + Exceptions: + UnmappedClass The specified object class is not mapped. + UnmappedPermission The specified permission is not mapped for the object class. + """ + + if direction not in self.valid_infoflow_directions: + raise ValueError("Invalid information flow direction: {0}".format(direction)) + + classname = str(class_) + + if classname not in self.permmap: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + try: + self.permmap[classname][permission]['direction'] = direction + except KeyError: + raise exception.UnmappedPermission("{0}:{1} is not mapped.". + format(classname, permission)) + + def set_weight(self, class_, permission, weight): + """ + Set the weight of a permission. + + Parameter: + class_ The object class of the permission. + permission The permission name. + weight The weight of the permission (1-10). + + Exceptions: + UnmappedClass The specified object class is not mapped. + UnmappedPermission The specified permission is not mapped for the object class. + """ + + if not self.min_weight <= weight <= self.max_weight: + raise ValueError("Permission weights must be 1-10: {0}".format(weight)) + + classname = str(class_) + + if classname not in self.permmap: + raise exception.UnmappedClass("{0} is not mapped.".format(classname)) + + try: + self.permmap[classname][permission]['weight'] = weight + except KeyError: + raise exception.UnmappedPermission("{0}:{1} is not mapped.". + format(classname, permission)) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/polcapquery.py b/lib/python2.7/site-packages/setoolsgui/setools/polcapquery.py new file mode 100644 index 0000000..e024b05 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/polcapquery.py @@ -0,0 +1,47 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery + + +class PolCapQuery(compquery.ComponentQuery): + + """ + Query SELinux policy capabilities + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the policy capability to match. + name_regex If true, regular expression matching will + be used for matching the name. + """ + + def results(self): + """Generator which yields all matching policy capabilities.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + + for cap in self.policy.polcaps(): + if not self._match_name(cap): + continue + + yield cap diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/__init__.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/__init__.py new file mode 100644 index 0000000..b03e524 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/__init__.py @@ -0,0 +1,568 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +# pylint: disable=too-many-public-methods +# +# Create a Python representation of the policy. +# The idea is that this is module provides convenient +# abstractions and methods for accessing the policy +# structures. +import logging +from itertools import chain +from errno import ENOENT + +try: + import selinux +except ImportError: + pass + +from . import qpol + +# The libqpol SWIG class is not quite natural for +# Python the policy is repeatedly referenced in the +# function calls, which makes sense for C code +# but not for python code, so each object keeps +# a reference to the policy for internal use. +# This also makes sense since an object would only +# be valid for the policy it comes from. + +# Exceptions +from . import exception + +# Components +from . import boolcond +from . import default +from . import mls +from . import objclass +from . import polcap +from . import role +from . import typeattr +from . import user + +# Rules +from . import mlsrule +from . import rbacrule +from . import terule + +# Constraints +from . import constraint + +# In-policy Labeling +from . import fscontext +from . import initsid +from . import netcontext + + +class SELinuxPolicy(object): + + """The complete SELinux policy.""" + + def __init__(self, policyfile=None): + """ + Parameter: + policyfile Path to a policy to open. + """ + + self.log = logging.getLogger(self.__class__.__name__) + self.policy = None + self.filename = None + + if policyfile: + self._load_policy(policyfile) + else: + try: + self._load_running_policy() + except NameError: + raise RuntimeError("Loading the running policy requires libselinux Python bindings") + + def __repr__(self): + return "<SELinuxPolicy(\"{0}\")>".format(self.filename) + + def __str__(self): + return self.filename + + def __deepcopy__(self, memo): + # shallow copy as all of the members are immutable + newobj = SELinuxPolicy.__new__(SELinuxPolicy) + newobj.policy = self.policy + newobj.filename = self.filename + memo[id(self)] = newobj + return newobj + + # + # Policy loading functions + # + + def _load_policy(self, filename): + """Load the specified policy.""" + self.log.info("Opening SELinux policy \"{0}\"".format(filename)) + + try: + self.policy = qpol.qpol_policy_factory(str(filename)) + except SyntaxError as err: + raise exception.InvalidPolicy("Error opening policy file \"{0}\": {1}". + format(filename, err)) + + self.log.info("Successfully opened SELinux policy \"{0}\"".format(filename)) + self.filename = filename + + @staticmethod + def _potential_policies(): + """Generate a list of potential policies to use.""" + # Start with binary policies in the standard location + base_policy_path = selinux.selinux_binary_policy_path() + for version in range(qpol.QPOL_POLICY_MAX_VERSION, qpol.QPOL_POLICY_MIN_VERSION-1, -1): + yield "{0}.{1}".format(base_policy_path, version) + + # Last chance, try selinuxfs. This is not first, to avoid + # holding kernel memory for a long time + if selinux.selinuxfs_exists(): + yield selinux.selinux_current_policy_path() + + def _load_running_policy(self): + """Try to load the current running policy.""" + self.log.info("Attempting to locate current running policy.") + + for filename in self._potential_policies(): + try: + self._load_policy(filename) + except OSError as err: + if err.errno != ENOENT: + raise + else: + break + else: + raise RuntimeError("Unable to locate an SELinux policy to load.") + + # + # Policy properties + # + @property + def handle_unknown(self): + """The handle unknown permissions setting (allow,deny,reject)""" + return self.policy.handle_unknown() + + @property + def mls(self): + """(T/F) The policy has MLS enabled.""" + return mls.enabled(self.policy) + + @property + def version(self): + """The policy database version (e.g. v29)""" + return self.policy.version() + + # + # Policy statistics + # + + @property + def allow_count(self): + """The number of (type) allow rules.""" + return self.policy.avrule_allow_count() + + @property + def auditallow_count(self): + """The number of auditallow rules.""" + return self.policy.avrule_auditallow_count() + + @property + def boolean_count(self): + """The number of Booleans.""" + return self.policy.bool_count() + + @property + def category_count(self): + """The number of categories.""" + return sum(1 for _ in self.categories()) + + @property + def class_count(self): + """The number of object classes.""" + return self.policy.class_count() + + @property + def common_count(self): + """The number of common permission sets.""" + return self.policy.common_count() + + @property + def conditional_count(self): + """The number of conditionals.""" + return self.policy.cond_count() + + @property + def constraint_count(self): + """The number of standard constraints.""" + return sum(1 for c in self.constraints() if c.ruletype == "constrain") + + @property + def dontaudit_count(self): + """The number of dontaudit rules.""" + return self.policy.avrule_dontaudit_count() + + @property + def fs_use_count(self): + """fs_use_* statements.""" + return self.policy.fs_use_count() + + @property + def genfscon_count(self): + """The number of genfscon statements.""" + return self.policy.genfscon_count() + + @property + def initialsids_count(self): + """The number of initial sid statements.""" + return self.policy.isid_count() + + @property + def level_count(self): + """The number of levels.""" + return sum(1 for _ in self.levels()) + + @property + def mlsconstraint_count(self): + """The number of MLS constraints.""" + return sum(1 for c in self.constraints() if c.ruletype == "mlsconstrain") + + @property + def mlsvalidatetrans_count(self): + """The number of MLS validatetrans.""" + return sum(1 for v in self.constraints() if v.ruletype == "mlsvalidatetrans") + + @property + def netifcon_count(self): + """The number of netifcon statements.""" + return self.policy.netifcon_count() + + @property + def neverallow_count(self): + """The number of neverallow rules.""" + return self.policy.avrule_neverallow_count() + + @property + def nodecon_count(self): + """The number of nodecon statements.""" + return self.policy.nodecon_count() + + @property + def permission_count(self): + """The number of permissions.""" + return sum(len(c.perms) for c in chain(self.commons(), self.classes())) + + @property + def permissives_count(self): + """The number of permissive types.""" + return self.policy.permissive_count() + + @property + def polcap_count(self): + """The number of policy capabilities.""" + return self.policy.polcap_count() + + @property + def portcon_count(self): + """The number of portcon statements.""" + return self.policy.portcon_count() + + @property + def range_transition_count(self): + """The number of range_transition rules.""" + return self.policy.range_trans_count() + + @property + def role_count(self): + """The number of roles.""" + return self.policy.role_count() + + @property + def role_allow_count(self): + """The number of (role) allow rules.""" + return self.policy.role_allow_count() + + @property + def role_transition_count(self): + """The number of role_transition rules.""" + return self.policy.role_trans_count() + + @property + def type_attribute_count(self): + """The number of (type) attributes.""" + return sum(1 for _ in self.typeattributes()) + + @property + def type_count(self): + """The number of types.""" + return sum(1 for _ in self.types()) + + @property + def type_change_count(self): + """The number of type_change rules.""" + return self.policy.terule_change_count() + + @property + def type_member_count(self): + """The number of type_member rules.""" + return self.policy.terule_member_count() + + @property + def type_transition_count(self): + """The number of type_transition rules.""" + return self.policy.terule_trans_count() + self.policy.filename_trans_count() + + @property + def user_count(self): + """The number of users.""" + return self.policy.user_count() + + @property + def validatetrans_count(self): + """The number of validatetrans.""" + return sum(1 for v in self.constraints() if v.ruletype == "validatetrans") + + # + # Policy components lookup functions + # + def lookup_boolean(self, name): + """Look up a Boolean.""" + return boolcond.boolean_factory(self.policy, name) + + def lookup_class(self, name): + """Look up an object class.""" + return objclass.class_factory(self.policy, name) + + def lookup_common(self, name): + """Look up a common permission set.""" + return objclass.common_factory(self.policy, name) + + def lookup_initialsid(self, name): + """Look up an initial sid.""" + return initsid.initialsid_factory(self.policy, name) + + def lookup_level(self, level): + """Look up a MLS level.""" + return mls.level_factory(self.policy, level) + + def lookup_sensitivity(self, name): + """Look up a MLS sensitivity by name.""" + return mls.sensitivity_factory(self.policy, name) + + def lookup_range(self, range_): + """Look up a MLS range.""" + return mls.range_factory(self.policy, range_) + + def lookup_role(self, name): + """Look up a role by name.""" + return role.role_factory(self.policy, name) + + def lookup_type(self, name): + """Look up a type by name.""" + return typeattr.type_factory(self.policy, name, deref=True) + + def lookup_type_or_attr(self, name): + """Look up a type or type attribute by name.""" + return typeattr.type_or_attr_factory(self.policy, name, deref=True) + + def lookup_typeattr(self, name): + """Look up a type attribute by name.""" + return typeattr.attribute_factory(self.policy, name) + + def lookup_user(self, name): + """Look up a user by name.""" + return user.user_factory(self.policy, name) + + # + # Policy components generators + # + + def bools(self): + """Generator which yields all Booleans.""" + for bool_ in self.policy.bool_iter(): + yield boolcond.boolean_factory(self.policy, bool_) + + def categories(self): + """Generator which yields all MLS categories.""" + for cat in self.policy.cat_iter(): + try: + yield mls.category_factory(self.policy, cat) + except TypeError: + # libqpol unfortunately iterates over aliases too + pass + + def classes(self): + """Generator which yields all object classes.""" + for class_ in self.policy.class_iter(): + yield objclass.class_factory(self.policy, class_) + + def commons(self): + """Generator which yields all commons.""" + for common in self.policy.common_iter(): + yield objclass.common_factory(self.policy, common) + + def defaults(self): + """Generator which yields all default_* statements.""" + for default_ in self.policy.default_iter(): + try: + for default_obj in default.default_factory(self.policy, default_): + yield default_obj + except exception.NoDefaults: + # qpol iterates over all classes. Handle case + # where a class has no default_* settings. + pass + + def levels(self): + """Generator which yields all level declarations.""" + for level in self.policy.level_iter(): + + try: + yield mls.level_decl_factory(self.policy, level) + except TypeError: + # libqpol unfortunately iterates over levels and sens aliases + pass + + def polcaps(self): + """Generator which yields all policy capabilities.""" + for cap in self.policy.polcap_iter(): + yield polcap.polcap_factory(self.policy, cap) + + def roles(self): + """Generator which yields all roles.""" + for role_ in self.policy.role_iter(): + yield role.role_factory(self.policy, role_) + + def sensitivities(self): + """Generator which yields all sensitivities.""" + # see mls.py for more info on why level_iter is used here. + for sens in self.policy.level_iter(): + try: + yield mls.sensitivity_factory(self.policy, sens) + except TypeError: + # libqpol unfortunately iterates over sens and aliases + pass + + def types(self): + """Generator which yields all types.""" + for type_ in self.policy.type_iter(): + try: + yield typeattr.type_factory(self.policy, type_) + except TypeError: + # libqpol unfortunately iterates over attributes and aliases + pass + + def typeattributes(self): + """Generator which yields all (type) attributes.""" + for type_ in self.policy.type_iter(): + try: + yield typeattr.attribute_factory(self.policy, type_) + except TypeError: + # libqpol unfortunately iterates over attributes and aliases + pass + + def users(self): + """Generator which yields all users.""" + for user_ in self.policy.user_iter(): + yield user.user_factory(self.policy, user_) + + # + # Policy rules generators + # + def mlsrules(self): + """Generator which yields all MLS rules.""" + for rule in self.policy.range_trans_iter(): + yield mlsrule.mls_rule_factory(self.policy, rule) + + def rbacrules(self): + """Generator which yields all RBAC rules.""" + for rule in chain(self.policy.role_allow_iter(), + self.policy.role_trans_iter()): + yield rbacrule.rbac_rule_factory(self.policy, rule) + + def terules(self): + """Generator which yields all type enforcement rules.""" + for rule in chain(self.policy.avrule_iter(), + self.policy.terule_iter(), + self.policy.filename_trans_iter()): + yield terule.te_rule_factory(self.policy, rule) + + # + # Policy rule type validators + # + @staticmethod + def validate_constraint_ruletype(types): + """Validate constraint types.""" + constraint.validate_ruletype(types) + + @staticmethod + def validate_mls_ruletype(types): + """Validate MLS rule types.""" + mlsrule.validate_ruletype(types) + + @staticmethod + def validate_rbac_ruletype(types): + """Validate RBAC rule types.""" + rbacrule.validate_ruletype(types) + + @staticmethod + def validate_te_ruletype(types): + """Validate type enforcement rule types.""" + terule.validate_ruletype(types) + + # + # Constraints generators + # + + def constraints(self): + """Generator which yields all constraints (regular and MLS).""" + for constraint_ in chain(self.policy.constraint_iter(), + self.policy.validatetrans_iter()): + + yield constraint.constraint_factory(self.policy, constraint_) + + # + # In-policy Labeling statement generators + # + def fs_uses(self): + """Generator which yields all fs_use_* statements.""" + for fs_use in self.policy.fs_use_iter(): + yield fscontext.fs_use_factory(self.policy, fs_use) + + def genfscons(self): + """Generator which yields all genfscon statements.""" + for fscon in self.policy.genfscon_iter(): + yield fscontext.genfscon_factory(self.policy, fscon) + + def initialsids(self): + """Generator which yields all initial SID statements.""" + for sid in self.policy.isid_iter(): + yield initsid.initialsid_factory(self.policy, sid) + + def netifcons(self): + """Generator which yields all netifcon statements.""" + for ifcon in self.policy.netifcon_iter(): + yield netcontext.netifcon_factory(self.policy, ifcon) + + def nodecons(self): + """Generator which yields all nodecon statements.""" + for node in self.policy.nodecon_iter(): + yield netcontext.nodecon_factory(self.policy, node) + + def portcons(self): + """Generator which yields all portcon statements.""" + for port in self.policy.portcon_iter(): + yield netcontext.portcon_factory(self.policy, port) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/_qpol.so b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/_qpol.so Binary files differnew file mode 100755 index 0000000..aaccf28 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/_qpol.so diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/boolcond.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/boolcond.py new file mode 100644 index 0000000..c3c0608 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/boolcond.py @@ -0,0 +1,167 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import symbol + + +def boolean_factory(policy, name): + """Factory function for creating Boolean statement objects.""" + + if isinstance(name, Boolean): + assert name.policy == policy + return name + elif isinstance(name, qpol.qpol_bool_t): + return Boolean(policy, name) + + try: + return Boolean(policy, qpol.qpol_bool_t(policy, str(name))) + except ValueError: + raise exception.InvalidBoolean("{0} is not a valid Boolean".format(name)) + + +def condexpr_factory(policy, name): + """Factory function for creating conditional expression objects.""" + + if not isinstance(name, qpol.qpol_cond_t): + raise TypeError("Conditional expressions cannot be looked up.") + + return ConditionalExpr(policy, name) + + +class Boolean(symbol.PolicySymbol): + + """A Boolean.""" + + @property + def state(self): + """The default state of the Boolean.""" + return bool(self.qpol_symbol.state(self.policy)) + + def statement(self): + """The policy statement.""" + return "bool {0} {1};".format(self, str(self.state).lower()) + + +class ConditionalExpr(symbol.PolicySymbol): + + """A conditional policy expression.""" + + _cond_expr_val_to_text = { + qpol.QPOL_COND_EXPR_NOT: "!", + qpol.QPOL_COND_EXPR_OR: "||", + qpol.QPOL_COND_EXPR_AND: "&&", + qpol.QPOL_COND_EXPR_XOR: "^", + qpol.QPOL_COND_EXPR_EQ: "==", + qpol.QPOL_COND_EXPR_NEQ: "!="} + + _cond_expr_val_to_precedence = { + qpol.QPOL_COND_EXPR_NOT: 5, + qpol.QPOL_COND_EXPR_OR: 1, + qpol.QPOL_COND_EXPR_AND: 3, + qpol.QPOL_COND_EXPR_XOR: 2, + qpol.QPOL_COND_EXPR_EQ: 4, + qpol.QPOL_COND_EXPR_NEQ: 4} + + def __contains__(self, other): + for expr_node in self.qpol_symbol.expr_node_iter(self.policy): + expr_node_type = expr_node.expr_type(self.policy) + + if expr_node_type == qpol.QPOL_COND_EXPR_BOOL and other == \ + boolean_factory(self.policy, expr_node.get_boolean(self.policy)): + return True + + return False + + def __str__(self): + # qpol representation is in postfix notation. This code + # converts it to infix notation. Parentheses are added + # to ensure correct expressions, though they may end up + # being overused. Set previous operator at start to the + # highest precedence (NOT) so if there is a single binary + # operator, no parentheses are output + stack = [] + prev_op_precedence = self._cond_expr_val_to_precedence[qpol.QPOL_COND_EXPR_NOT] + for expr_node in self.qpol_symbol.expr_node_iter(self.policy): + expr_node_type = expr_node.expr_type(self.policy) + + if expr_node_type == qpol.QPOL_COND_EXPR_BOOL: + # append the boolean name + nodebool = boolean_factory( + self.policy, expr_node.get_boolean(self.policy)) + stack.append(str(nodebool)) + elif expr_node_type == qpol.QPOL_COND_EXPR_NOT: # unary operator + operand = stack.pop() + operator = self._cond_expr_val_to_text[expr_node_type] + op_precedence = self._cond_expr_val_to_precedence[expr_node_type] + + # NOT is the highest precedence, so only need + # parentheses if the operand is a subexpression + if isinstance(operand, list): + subexpr = [operator, "(", operand, ")"] + else: + subexpr = [operator, operand] + + stack.append(subexpr) + prev_op_precedence = op_precedence + else: + operand1 = stack.pop() + operand2 = stack.pop() + operator = self._cond_expr_val_to_text[expr_node_type] + op_precedence = self._cond_expr_val_to_precedence[expr_node_type] + + if prev_op_precedence > op_precedence: + # if previous operator is of higher precedence + # no parentheses are needed. + subexpr = [operand1, operator, operand2] + else: + subexpr = ["(", operand1, operator, operand2, ")"] + + stack.append(subexpr) + prev_op_precedence = op_precedence + + return self.__unwind_subexpression(stack) + + def __unwind_subexpression(self, expr): + ret = [] + + # do a string.join on sublists (subexpressions) + for i in expr: + if isinstance(i, list): + ret.append(self.__unwind_subexpression(i)) + else: + ret.append(i) + + return ' '.join(ret) + + @property + def booleans(self): + """The set of Booleans in the expression.""" + bools = set() + + for expr_node in self.qpol_symbol.expr_node_iter(self.policy): + expr_node_type = expr_node.expr_type(self.policy) + + if expr_node_type == qpol.QPOL_COND_EXPR_BOOL: + bools.add(boolean_factory(self.policy, expr_node.get_boolean(self.policy))) + + return bools + + def statement(self): + raise exception.NoStatement diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/constraint.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/constraint.py new file mode 100644 index 0000000..9994c5b --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/constraint.py @@ -0,0 +1,297 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import role +from . import symbol +from . import objclass +from . import typeattr +from . import user + + +def _is_mls(policy, sym): + """Determine if this is a regular or MLS constraint/validatetrans.""" + # this can only be determined by inspecting the expression. + for expr_node in sym.expr_iter(policy): + sym_type = expr_node.sym_type(policy) + expr_type = expr_node.expr_type(policy) + + if expr_type == qpol.QPOL_CEXPR_TYPE_ATTR and sym_type >= qpol.QPOL_CEXPR_SYM_L1L2: + return True + + return False + + +def validate_ruletype(types): + """Validate constraint rule types.""" + for t in types: + if t not in ["constrain", "mlsconstrain", "validatetrans", "mlsvalidatetrans"]: + raise exception.InvalidConstraintType("{0} is not a valid constraint type.".format(t)) + + +def constraint_factory(policy, sym): + """Factory function for creating constraint objects.""" + + try: + if _is_mls(policy, sym): + if isinstance(sym, qpol.qpol_constraint_t): + return Constraint(policy, sym, "mlsconstrain") + else: + return Validatetrans(policy, sym, "mlsvalidatetrans") + else: + if isinstance(sym, qpol.qpol_constraint_t): + return Constraint(policy, sym, "constrain") + else: + return Validatetrans(policy, sym, "validatetrans") + + except AttributeError: + raise TypeError("Constraints cannot be looked-up.") + + +class BaseConstraint(symbol.PolicySymbol): + + """Base class for constraint rules.""" + + _expr_type_to_text = { + qpol.QPOL_CEXPR_TYPE_NOT: "not", + qpol.QPOL_CEXPR_TYPE_AND: "and", + qpol.QPOL_CEXPR_TYPE_OR: "\n\tor"} + + _expr_op_to_text = { + qpol.QPOL_CEXPR_OP_EQ: "==", + qpol.QPOL_CEXPR_OP_NEQ: "!=", + qpol.QPOL_CEXPR_OP_DOM: "dom", + qpol.QPOL_CEXPR_OP_DOMBY: "domby", + qpol.QPOL_CEXPR_OP_INCOMP: "incomp"} + + _sym_to_text = { + qpol.QPOL_CEXPR_SYM_USER: "u1", + qpol.QPOL_CEXPR_SYM_ROLE: "r1", + qpol.QPOL_CEXPR_SYM_TYPE: "t1", + qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_TARGET: "u2", + qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_TARGET: "r2", + qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_TARGET: "t2", + qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_XTARGET: "u3", + qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_XTARGET: "r3", + qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_XTARGET: "t3", + qpol.QPOL_CEXPR_SYM_L1L2: "l1", + qpol.QPOL_CEXPR_SYM_L1H2: "l1", + qpol.QPOL_CEXPR_SYM_H1L2: "h1", + qpol.QPOL_CEXPR_SYM_H1H2: "h1", + qpol.QPOL_CEXPR_SYM_L1H1: "l1", + qpol.QPOL_CEXPR_SYM_L2H2: "l2", + qpol.QPOL_CEXPR_SYM_L1L2 + qpol.QPOL_CEXPR_SYM_TARGET: "l2", + qpol.QPOL_CEXPR_SYM_L1H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2", + qpol.QPOL_CEXPR_SYM_H1L2 + qpol.QPOL_CEXPR_SYM_TARGET: "l2", + qpol.QPOL_CEXPR_SYM_H1H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2", + qpol.QPOL_CEXPR_SYM_L1H1 + qpol.QPOL_CEXPR_SYM_TARGET: "h1", + qpol.QPOL_CEXPR_SYM_L2H2 + qpol.QPOL_CEXPR_SYM_TARGET: "h2"} + + # Boolean operators + _expr_type_to_precedence = { + qpol.QPOL_CEXPR_TYPE_NOT: 3, + qpol.QPOL_CEXPR_TYPE_AND: 2, + qpol.QPOL_CEXPR_TYPE_OR: 1} + + # Logical operators have the same precedence + _logical_op_precedence = 4 + + def __init__(self, policy, qpol_symbol, ruletype): + symbol.PolicySymbol.__init__(self, policy, qpol_symbol) + self.ruletype = ruletype + + def __str__(self): + raise NotImplementedError + + def _build_expression(self): + # qpol representation is in postfix notation. This code + # converts it to infix notation. Parentheses are added + # to ensure correct expressions, though they may end up + # being overused. Set previous operator at start to the + # highest precedence (op) so if there is a single binary + # operator, no parentheses are output + + stack = [] + prev_op_precedence = self._logical_op_precedence + for expr_node in self.qpol_symbol.expr_iter(self.policy): + op = expr_node.op(self.policy) + sym_type = expr_node.sym_type(self.policy) + expr_type = expr_node.expr_type(self.policy) + + if expr_type == qpol.QPOL_CEXPR_TYPE_ATTR: + # logical operator with symbol (e.g. u1 == u2) + operand1 = self._sym_to_text[sym_type] + operand2 = self._sym_to_text[sym_type + qpol.QPOL_CEXPR_SYM_TARGET] + operator = self._expr_op_to_text[op] + + stack.append([operand1, operator, operand2]) + + prev_op_precedence = self._logical_op_precedence + elif expr_type == qpol.QPOL_CEXPR_TYPE_NAMES: + # logical operator with type or attribute list (e.g. t1 == { spam_t eggs_t }) + operand1 = self._sym_to_text[sym_type] + operator = self._expr_op_to_text[op] + + names = list(expr_node.names_iter(self.policy)) + + if not names: + operand2 = "<empty set>" + elif len(names) == 1: + operand2 = names[0] + else: + operand2 = "{{ {0} }}".format(' '.join(names)) + + stack.append([operand1, operator, operand2]) + + prev_op_precedence = self._logical_op_precedence + elif expr_type == qpol.QPOL_CEXPR_TYPE_NOT: + # unary operator (not) + operand = stack.pop() + operator = self._expr_type_to_text[expr_type] + + stack.append([operator, "(", operand, ")"]) + + prev_op_precedence = self._expr_type_to_precedence[expr_type] + else: + # binary operator (and/or) + operand1 = stack.pop() + operand2 = stack.pop() + operator = self._expr_type_to_text[expr_type] + op_precedence = self._expr_type_to_precedence[expr_type] + + # if previous operator is of higher precedence + # no parentheses are needed. + if op_precedence < prev_op_precedence: + stack.append([operand1, operator, operand2]) + else: + stack.append(["(", operand1, operator, operand2, ")"]) + + prev_op_precedence = op_precedence + + return self.__unwind_subexpression(stack) + + def _get_symbols(self, syms, factory): + """ + Internal generator for getting users/roles/types in a constraint + expression. Symbols will be yielded multiple times if they appear + in the expression multiple times. + + Parameters: + syms List of qpol symbol types. + factory The factory function related to these symbols. + """ + for expr_node in self.qpol_symbol.expr_iter(self.policy): + sym_type = expr_node.sym_type(self.policy) + expr_type = expr_node.expr_type(self.policy) + + if expr_type == qpol.QPOL_CEXPR_TYPE_NAMES and sym_type in syms: + for s in expr_node.names_iter(self.policy): + yield factory(self.policy, s) + + def __unwind_subexpression(self, expr): + ret = [] + + # do a string.join on sublists (subexpressions) + for i in expr: + if isinstance(i, list): + ret.append(self.__unwind_subexpression(i)) + else: + ret.append(i) + + return ' '.join(ret) + + # There is no levels function as specific + # levels cannot be used in expressions, only + # the l1, h1, etc. symbols + + @property + def roles(self): + """The roles used in the expression.""" + role_syms = [qpol.QPOL_CEXPR_SYM_ROLE, + qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_TARGET, + qpol.QPOL_CEXPR_SYM_ROLE + qpol.QPOL_CEXPR_SYM_XTARGET] + + return set(self._get_symbols(role_syms, role.role_factory)) + + @property + def perms(self): + raise NotImplementedError + + def statement(self): + return str(self) + + @property + def tclass(self): + """Object class for this constraint.""" + return objclass.class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) + + @property + def types(self): + """The types and type attributes used in the expression.""" + type_syms = [qpol.QPOL_CEXPR_SYM_TYPE, + qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_TARGET, + qpol.QPOL_CEXPR_SYM_TYPE + qpol.QPOL_CEXPR_SYM_XTARGET] + + return set(self._get_symbols(type_syms, typeattr.type_or_attr_factory)) + + @property + def users(self): + """The users used in the expression.""" + user_syms = [qpol.QPOL_CEXPR_SYM_USER, + qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_TARGET, + qpol.QPOL_CEXPR_SYM_USER + qpol.QPOL_CEXPR_SYM_XTARGET] + + return set(self._get_symbols(user_syms, user.user_factory)) + + +class Constraint(BaseConstraint): + + """A constraint rule (constrain/mlsconstrain).""" + + def __str__(self): + rule_string = "{0.ruletype} {0.tclass} ".format(self) + + perms = self.perms + if len(perms) > 1: + rule_string += "{{ {0} }} (\n".format(' '.join(perms)) + else: + # convert to list since sets cannot be indexed + rule_string += "{0} (\n".format(list(perms)[0]) + + rule_string += "\t{0}\n);".format(self._build_expression()) + + return rule_string + + @property + def perms(self): + """The constraint's permission set.""" + return set(self.qpol_symbol.perm_iter(self.policy)) + + +class Validatetrans(BaseConstraint): + + """A validatetrans rule (validatetrans/mlsvalidatetrans).""" + + def __str__(self): + return "{0.ruletype} {0.tclass}\n\t{1}\n);".format(self, self._build_expression()) + + @property + def perms(self): + raise exception.ConstraintUseError("{0} rules do not have permissions.". + format(self.ruletype)) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/context.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/context.py new file mode 100644 index 0000000..f2f3fc7 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/context.py @@ -0,0 +1,68 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import symbol +from . import user +from . import role +from . import typeattr +from . import mls + + +def context_factory(policy, name): + """Factory function for creating context objects.""" + + if not isinstance(name, qpol.qpol_context_t): + raise TypeError("Contexts cannot be looked-up.") + + return Context(policy, name) + + +class Context(symbol.PolicySymbol): + + """A SELinux security context/security attribute.""" + + def __str__(self): + try: + return "{0.user}:{0.role}:{0.type_}:{0.range_}".format(self) + except exception.MLSDisabled: + return "{0.user}:{0.role}:{0.type_}".format(self) + + @property + def user(self): + """The user portion of the context.""" + return user.user_factory(self.policy, self.qpol_symbol.user(self.policy)) + + @property + def role(self): + """The role portion of the context.""" + return role.role_factory(self.policy, self.qpol_symbol.role(self.policy)) + + @property + def type_(self): + """The type portion of the context.""" + return typeattr.type_factory(self.policy, self.qpol_symbol.type_(self.policy)) + + @property + def range_(self): + """The MLS range of the context.""" + return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) + + def statement(self): + raise exception.NoStatement diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/default.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/default.py new file mode 100644 index 0000000..175b709 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/default.py @@ -0,0 +1,128 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import symbol +from . import objclass +from . import qpol + + +def default_factory(policy, sym): + """Factory generator for creating default_* statement objects.""" + + # The low level policy groups default_* settings by object class. + # Since each class can have up to four default_* statements, + # this factory function is a generator which yields up to + # four Default objects. + + if not isinstance(sym, qpol.qpol_default_object_t): + raise NotImplementedError + + # qpol will essentially iterate over all classes + # and emit None for classes that don't set a default + if not sym.object_class(policy): + raise exception.NoDefaults + + if sym.user_default(policy): + yield UserDefault(policy, sym) + + if sym.role_default(policy): + yield RoleDefault(policy, sym) + + if sym.type_default(policy): + yield TypeDefault(policy, sym) + + if sym.range_default(policy): + yield RangeDefault(policy, sym) + + +class Default(symbol.PolicySymbol): + + """Base class for default_* statements.""" + + def __str__(self): + raise NotImplementedError + + @property + def object_class(self): + """The object class.""" + return objclass.class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) + + @property + def default(self): + raise NotImplementedError + + def statement(self): + return str(self) + + +class UserDefault(Default): + + """A default_user statement.""" + + def __str__(self): + return "default_user {0.object_class} {0.default};".format(self) + + @property + def default(self): + """The default user location (source/target).""" + return self.qpol_symbol.user_default(self.policy) + + +class RoleDefault(Default): + + """A default_role statement.""" + + def __str__(self): + return "default_role {0.object_class} {0.default};".format(self) + + @property + def default(self): + """The default role location (source/target).""" + return self.qpol_symbol.role_default(self.policy) + + +class TypeDefault(Default): + + """A default_type statement.""" + + def __str__(self): + return "default_type {0.object_class} {0.default};".format(self) + + @property + def default(self): + """The default type location (source/target).""" + return self.qpol_symbol.type_default(self.policy) + + +class RangeDefault(Default): + + """A default_range statement.""" + + def __str__(self): + return "default_range {0.object_class} {0.default} {0.default_range};".format(self) + + @property + def default(self): + """The default range location (source/target).""" + return self.qpol_symbol.range_default(self.policy).split()[0] + + @property + def default_range(self): + """The default range setting (low/high/low_high).""" + return self.qpol_symbol.range_default(self.policy).split()[1] diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/exception.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/exception.py new file mode 100644 index 0000000..ce367c0 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/exception.py @@ -0,0 +1,248 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from ..exception import SEToolsException + +# +# Policyrep base exception +# + + +class PolicyrepException(SEToolsException): + + """Base class for all policyrep exceptions.""" + pass + + +# +# General Policyrep exceptions +# + + +class InvalidPolicy(SyntaxError, PolicyrepException): + + """Exception for invalid policy.""" + pass + + +class MLSDisabled(PolicyrepException): + + """ + Exception when MLS is disabled. + """ + pass + + +# +# Invalid component exceptions +# +class InvalidSymbol(ValueError, PolicyrepException): + + """ + Base class for invalid symbols. Typically this is attempting to + look up an object in the policy, but it does not exist. + """ + pass + + +class InvalidBoolean(InvalidSymbol): + + """Exception for invalid Booleans.""" + pass + + +class InvalidCategory(InvalidSymbol): + + """Exception for invalid MLS categories.""" + pass + + +class InvalidClass(InvalidSymbol): + + """Exception for invalid object classes.""" + pass + + +class InvalidCommon(InvalidSymbol): + + """Exception for invalid common permission sets.""" + pass + + +class InvalidInitialSid(InvalidSymbol): + + """Exception for invalid initial sids.""" + pass + + +class InvalidLevel(InvalidSymbol): + + """ + Exception for an invalid level. + """ + pass + + +class InvalidLevelDecl(InvalidSymbol): + + """ + Exception for an invalid level declaration. + """ + pass + + +class InvalidRange(InvalidSymbol): + + """ + Exception for an invalid range. + """ + pass + + +class InvalidRole(InvalidSymbol): + + """Exception for invalid roles.""" + pass + + +class InvalidSensitivity(InvalidSymbol): + + """ + Exception for an invalid sensitivity. + """ + pass + + +class InvalidType(InvalidSymbol): + + """Exception for invalid types and attributes.""" + pass + + +class InvalidUser(InvalidSymbol): + + """Exception for invalid users.""" + pass + +# +# Rule type exceptions +# + + +class InvalidRuleType(InvalidSymbol): + + """Exception for invalid rule types.""" + pass + + +class InvalidConstraintType(InvalidSymbol): + + """Exception for invalid constraint types.""" + # This is not a rule but is similar. + pass + + +class InvalidMLSRuleType(InvalidRuleType): + + """Exception for invalid MLS rule types.""" + pass + + +class InvalidRBACRuleType(InvalidRuleType): + + """Exception for invalid RBAC rule types.""" + pass + + +class InvalidTERuleType(InvalidRuleType): + + """Exception for invalid TE rule types.""" + pass + + +# +# Object use errors +# +class SymbolUseError(PolicyrepException): + + """ + Base class for incorrectly using an object. Typically this is + for classes with strong similarities, but with slight variances in + functionality, e.g. allow vs type_transition rules. + """ + pass + + +class RuleUseError(SymbolUseError): + + """ + Base class for incorrect parameters for a rule. For + example, trying to get the permissions of a rule that has no + permissions. + """ + pass + + +class ConstraintUseError(SymbolUseError): + + """Exception when getting permissions from a validatetrans.""" + pass + + +class NoStatement(SymbolUseError): + + """ + Exception for objects that have no inherent statement, such + as conditional expressions and MLS ranges. + """ + pass + + +# +# Other exceptions +# +class NoCommon(PolicyrepException): + + """ + Exception when a class does not inherit a common permission set. + """ + pass + + +class NoDefaults(InvalidSymbol): + + """Exception for classes that have no default_* statements.""" + pass + + +class RuleNotConditional(PolicyrepException): + + """ + Exception when getting the conditional expression for rules + that are unconditional (not conditional). + """ + pass + + +class TERuleNoFilename(PolicyrepException): + + """ + Exception when getting the file name of a + type_transition rule that has no file name. + """ + pass diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/fscontext.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/fscontext.py new file mode 100644 index 0000000..a17b0bc --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/fscontext.py @@ -0,0 +1,123 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import stat + +from . import qpol +from . import symbol +from . import context + + +def fs_use_factory(policy, name): + """Factory function for creating fs_use_* objects.""" + + if not isinstance(name, qpol.qpol_fs_use_t): + raise TypeError("fs_use_* cannot be looked-up.") + + return FSUse(policy, name) + + +def genfscon_factory(policy, name): + """Factory function for creating genfscon objects.""" + + if not isinstance(name, qpol.qpol_genfscon_t): + raise TypeError("Genfscons cannot be looked-up.") + + return Genfscon(policy, name) + + +class FSContext(symbol.PolicySymbol): + + """Base class for in-policy labeling rules.""" + + def __str__(self): + raise NotImplementedError + + @property + def fs(self): + """The filesystem type for this statement.""" + return self.qpol_symbol.name(self.policy) + + @property + def context(self): + """The context for this statement.""" + return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) + + def statement(self): + return str(self) + + +class Genfscon(FSContext): + + """A genfscon statement.""" + + _filetype_to_text = { + 0: "", + stat.S_IFBLK: "-b", + stat.S_IFCHR: "-c", + stat.S_IFDIR: "-d", + stat.S_IFIFO: "-p", + stat.S_IFREG: "--", + stat.S_IFLNK: "-l", + stat.S_IFSOCK: "-s"} + + def __str__(self): + return "genfscon {0.fs} {0.path} {1} {0.context}".format( + self, self._filetype_to_text[self.filetype]) + + def __eq__(self, other): + # Libqpol allocates new C objects in the + # genfscons iterator, so pointer comparison + # in the PolicySymbol object doesn't work. + try: + return (self.fs == other.fs and + self.path == other.path and + self.filetype == other.filetype and + self.context == other.context) + except AttributeError: + return str(self) == str(other) + + @property + def filetype(self): + """The file type (e.g. stat.S_IFBLK) for this genfscon statement.""" + return self.qpol_symbol.object_class(self.policy) + + @property + def path(self): + """The path for this genfscon statement.""" + return self.qpol_symbol.path(self.policy) + + +class FSUse(FSContext): + + """A fs_use_* statement.""" + + # there are more rule types, but modern SELinux + # only supports these three. + _ruletype_to_text = { + qpol.QPOL_FS_USE_XATTR: 'fs_use_xattr', + qpol.QPOL_FS_USE_TRANS: 'fs_use_trans', + qpol.QPOL_FS_USE_TASK: 'fs_use_task'} + + def __str__(self): + return "{0.ruletype} {0.fs} {0.context};".format(self) + + @property + def ruletype(self): + """The rule type for this fs_use_* statement.""" + return self._ruletype_to_text[self.qpol_symbol.behavior(self.policy)] diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/initsid.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/initsid.py new file mode 100644 index 0000000..0197c74 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/initsid.py @@ -0,0 +1,50 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import symbol +from . import context + + +def initialsid_factory(policy, name): + """Factory function for creating initial sid objects.""" + + if isinstance(name, InitialSID): + assert name.policy == policy + return name + elif isinstance(name, qpol.qpol_isid_t): + return InitialSID(policy, name) + + try: + return InitialSID(policy, qpol.qpol_isid_t(policy, name)) + except ValueError: + raise exception.InvalidInitialSid("{0} is not a valid initial sid".format(name)) + + +class InitialSID(symbol.PolicySymbol): + + """An initial SID statement.""" + + @property + def context(self): + """The context for this initial SID.""" + return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) + + def statement(self): + return "sid {0} {0.context}".format(self) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mls.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mls.py new file mode 100644 index 0000000..2541704 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mls.py @@ -0,0 +1,463 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +# pylint: disable=protected-access +import itertools + +from . import exception +from . import qpol +from . import symbol + +# qpol does not expose an equivalent of a sensitivity declaration. +# qpol_level_t is equivalent to the level declaration: +# level s0:c0.c1023; + +# qpol_mls_level_t represents a level as used in contexts, +# such as range_transitions or labeling statements such as +# portcon and nodecon. + +# Here qpol_level_t is also used for MLSSensitivity +# since it has the sensitivity name, dominance, and there +# is a 1:1 correspondence between the sensitivity declarations +# and level declarations. + +# Hashing has to be handled below because the qpol references, +# normally used for a hash key, are not the same for multiple +# instances of the same object (except for level decl). + + +def enabled(policy): + """Determine if MLS is enabled.""" + return policy.capability(qpol.QPOL_CAP_MLS) + + +def category_factory(policy, sym): + """Factory function for creating MLS category objects.""" + + if not enabled(policy): + raise exception.MLSDisabled + + if isinstance(sym, Category): + assert sym.policy == policy + return sym + elif isinstance(sym, qpol.qpol_cat_t): + if sym.isalias(policy): + raise TypeError("{0} is an alias".format(sym.name(policy))) + + return Category(policy, sym) + + try: + return Category(policy, qpol.qpol_cat_t(policy, str(sym))) + except ValueError: + raise exception.InvalidCategory("{0} is not a valid category".format(sym)) + + +def sensitivity_factory(policy, sym): + """Factory function for creating MLS sensitivity objects.""" + + if not enabled(policy): + raise exception.MLSDisabled + + if isinstance(sym, Sensitivity): + assert sym.policy == policy + return sym + elif isinstance(sym, qpol.qpol_level_t): + if sym.isalias(policy): + raise TypeError("{0} is an alias".format(sym.name(policy))) + + return Sensitivity(policy, sym) + + try: + return Sensitivity(policy, qpol.qpol_level_t(policy, str(sym))) + except ValueError: + raise exception.InvalidSensitivity("{0} is not a valid sensitivity".format(sym)) + + +def level_factory(policy, sym): + """ + Factory function for creating MLS level objects (e.g. levels used + in contexts of labeling statements) + """ + + if not enabled(policy): + raise exception.MLSDisabled + + if isinstance(sym, Level): + assert sym.policy == policy + return sym + elif isinstance(sym, qpol.qpol_mls_level_t): + return Level(policy, sym) + + sens_split = str(sym).split(":") + + sens = sens_split[0] + try: + semantic_level = qpol.qpol_semantic_level_t(policy, sens) + except ValueError: + raise exception.InvalidLevel("{0} is invalid ({1} is not a valid sensitivity)". + format(sym, sens)) + + try: + cats = sens_split[1] + except IndexError: + pass + else: + for group in cats.split(","): + catrange = group.split(".") + + if len(catrange) == 2: + try: + semantic_level.add_cats(policy, catrange[0], catrange[1]) + except ValueError: + raise exception.InvalidLevel( + "{0} is invalid ({1} is not a valid category range)".format(sym, group)) + elif len(catrange) == 1: + try: + semantic_level.add_cats(policy, catrange[0], catrange[0]) + except ValueError: + raise exception.InvalidLevel("{0} is invalid ({1} is not a valid category)". + format(sym, group)) + else: + raise exception.InvalidLevel("{0} is invalid (level parsing error)".format(sym)) + + # convert to level object + try: + policy_level = qpol.qpol_mls_level_t(policy, semantic_level) + except ValueError: + raise exception.InvalidLevel( + "{0} is invalid (one or more categories are not associated with the sensitivity)". + format(sym)) + + return Level(policy, policy_level) + + +def level_decl_factory(policy, sym): + """ + Factory function for creating MLS level declaration objects. + (level statements) Lookups are only by sensitivity name. + """ + + if not enabled(policy): + raise exception.MLSDisabled + + if isinstance(sym, LevelDecl): + assert sym.policy == policy + return sym + elif isinstance(sym, qpol.qpol_level_t): + if sym.isalias(policy): + raise TypeError("{0} is an alias".format(sym.name(policy))) + + return LevelDecl(policy, sym) + + try: + return LevelDecl(policy, qpol.qpol_level_t(policy, str(sym))) + except ValueError: + raise exception.InvalidLevelDecl("{0} is not a valid sensitivity".format(sym)) + + +def range_factory(policy, sym): + """Factory function for creating MLS range objects.""" + + if not enabled(policy): + raise exception.MLSDisabled + + if isinstance(sym, Range): + assert sym.policy == policy + return sym + elif isinstance(sym, qpol.qpol_mls_range_t): + return Range(policy, sym) + + # build range: + levels = str(sym).split("-") + + # strip() levels to handle ranges with spaces in them, + # e.g. s0:c1 - s0:c0.c255 + try: + low = level_factory(policy, levels[0].strip()) + except exception.InvalidLevel as ex: + raise exception.InvalidRange("{0} is not a valid range ({1}).".format(sym, ex)) + + try: + high = level_factory(policy, levels[1].strip()) + except exception.InvalidLevel as ex: + raise exception.InvalidRange("{0} is not a valid range ({1}).".format(sym, ex)) + except IndexError: + high = low + + # convert to range object + try: + policy_range = qpol.qpol_mls_range_t(policy, low.qpol_symbol, high.qpol_symbol) + except ValueError: + raise exception.InvalidRange("{0} is not a valid range ({1} is not dominated by {2})". + format(sym, low, high)) + + return Range(policy, policy_range) + + +class BaseMLSComponent(symbol.PolicySymbol): + + """Base class for sensitivities and categories.""" + + @property + def _value(self): + """ + The value of the component. + + This is a low-level policy detail exposed for internal use only. + """ + return self.qpol_symbol.value(self.policy) + + def aliases(self): + """Generator that yields all aliases for this category.""" + + for alias in self.qpol_symbol.alias_iter(self.policy): + yield alias + + +class Category(BaseMLSComponent): + + """An MLS category.""" + + def statement(self): + aliases = list(self.aliases()) + stmt = "category {0}".format(self) + if aliases: + if len(aliases) > 1: + stmt += " alias {{ {0} }}".format(' '.join(aliases)) + else: + stmt += " alias {0}".format(aliases[0]) + stmt += ";" + return stmt + + +class Sensitivity(BaseMLSComponent): + + """An MLS sensitivity""" + + def __eq__(self, other): + try: + return self._value == other._value + except AttributeError: + return str(self) == str(other) + + def __ge__(self, other): + return self._value >= other._value + + def __gt__(self, other): + return self._value > other._value + + def __le__(self, other): + return self._value <= other._value + + def __lt__(self, other): + return self._value < other._value + + def statement(self): + aliases = list(self.aliases()) + stmt = "sensitivity {0}".format(self) + if aliases: + if len(aliases) > 1: + stmt += " alias {{ {0} }}".format(' '.join(aliases)) + else: + stmt += " alias {0}".format(aliases[0]) + stmt += ";" + return stmt + + +class BaseMLSLevel(symbol.PolicySymbol): + + """Base class for MLS levels.""" + + def __str__(self): + lvl = str(self.sensitivity) + + # sort by policy declaration order + cats = sorted(self.categories(), key=lambda k: k._value) + + if cats: + # generate short category notation + shortlist = [] + for _, i in itertools.groupby(cats, key=lambda k, + c=itertools.count(): k._value - next(c)): + group = list(i) + if len(group) > 1: + shortlist.append("{0}.{1}".format(group[0], group[-1])) + else: + shortlist.append(str(group[0])) + + lvl += ":" + ','.join(shortlist) + + return lvl + + @property + def sensitivity(self): + raise NotImplementedError + + def categories(self): + """ + Generator that yields all individual categories for this level. + All categories are yielded, not a compact notation such as + c0.c255 + """ + + for cat in self.qpol_symbol.cat_iter(self.policy): + yield category_factory(self.policy, cat) + + +class LevelDecl(BaseMLSLevel): + + """ + The declaration statement for MLS levels, e.g: + + level s7:c0.c1023; + """ + # below comparisons are only based on sensitivity + # dominance since, in this context, the allowable + # category set is being defined for the level. + # object type is asserted here because this cannot + # be compared to a Level instance. + + def __eq__(self, other): + assert not isinstance(other, Level), "Levels cannot be compared to level declarations" + + try: + return self.sensitivity == other.sensitivity + except AttributeError: + return str(self) == str(other) + + def __ge__(self, other): + assert not isinstance(other, Level), "Levels cannot be compared to level declarations" + return self.sensitivity >= other.sensitivity + + def __gt__(self, other): + assert not isinstance(other, Level), "Levels cannot be compared to level declarations" + return self.sensitivity > other.sensitivity + + def __le__(self, other): + assert not isinstance(other, Level), "Levels cannot be compared to level declarations" + return self.sensitivity <= other.sensitivity + + def __lt__(self, other): + assert not isinstance(other, Level), "Levels cannot be compared to level declarations" + return self.sensitivity < other.sensitivity + + @property + def sensitivity(self): + """The sensitivity of the level.""" + # since the qpol symbol for levels is also used for + # MLSSensitivity objects, use self's qpol symbol + return sensitivity_factory(self.policy, self.qpol_symbol) + + def statement(self): + return "level {0};".format(self) + + +class Level(BaseMLSLevel): + + """An MLS level used in contexts.""" + + def __hash__(self): + return hash(str(self)) + + def __eq__(self, other): + try: + othercats = set(other.categories()) + except AttributeError: + return str(self) == str(other) + else: + selfcats = set(self.categories()) + return self.sensitivity == other.sensitivity and selfcats == othercats + + def __ge__(self, other): + """Dom operator.""" + selfcats = set(self.categories()) + othercats = set(other.categories()) + return self.sensitivity >= other.sensitivity and selfcats >= othercats + + def __gt__(self, other): + selfcats = set(self.categories()) + othercats = set(other.categories()) + return ((self.sensitivity > other.sensitivity and selfcats >= othercats) or + (self.sensitivity >= other.sensitivity and selfcats > othercats)) + + def __le__(self, other): + """Domby operator.""" + selfcats = set(self.categories()) + othercats = set(other.categories()) + return self.sensitivity <= other.sensitivity and selfcats <= othercats + + def __lt__(self, other): + selfcats = set(self.categories()) + othercats = set(other.categories()) + return ((self.sensitivity < other.sensitivity and selfcats <= othercats) or + (self.sensitivity <= other.sensitivity and selfcats < othercats)) + + def __xor__(self, other): + """Incomp operator.""" + return not (self >= other or self <= other) + + @property + def sensitivity(self): + """The sensitivity of the level.""" + return sensitivity_factory(self.policy, self.qpol_symbol.sens_name(self.policy)) + + def statement(self): + raise exception.NoStatement + + +class Range(symbol.PolicySymbol): + + """An MLS range""" + + def __str__(self): + high = self.high + low = self.low + if high == low: + return str(low) + + return "{0} - {1}".format(low, high) + + def __hash__(self): + return hash(str(self)) + + def __eq__(self, other): + try: + return self.low == other.low and self.high == other.high + except AttributeError: + # remove all spaces in the string representations + # to handle cases where the other object does not + # have spaces around the '-' + other_str = str(other).replace(" ", "") + self_str = str(self).replace(" ", "") + return self_str == other_str + + def __contains__(self, other): + return self.low <= other <= self.high + + @property + def high(self): + """The high end/clearance level of this range.""" + return level_factory(self.policy, self.qpol_symbol.high_level(self.policy)) + + @property + def low(self): + """The low end/current level of this range.""" + return level_factory(self.policy, self.qpol_symbol.low_level(self.policy)) + + def statement(self): + raise exception.NoStatement diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mlsrule.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mlsrule.py new file mode 100644 index 0000000..5c91c59 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/mlsrule.py @@ -0,0 +1,62 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import rule +from . import typeattr +from . import mls + + +def mls_rule_factory(policy, symbol): + """Factory function for creating MLS rule objects.""" + if not isinstance(symbol, qpol.qpol_range_trans_t): + raise TypeError("MLS rules cannot be looked-up.") + + return MLSRule(policy, symbol) + + +def validate_ruletype(types): + """Validate MLS rule types.""" + for t in types: + if t not in ["range_transition"]: + raise exception.InvalidMLSRuleType("{0} is not a valid MLS rule type.".format(t)) + + +class MLSRule(rule.PolicyRule): + + """An MLS rule.""" + + def __str__(self): + # TODO: If we ever get more MLS rules, fix this format. + return "range_transition {0.source} {0.target}:{0.tclass} {0.default};".format(self) + + @property + def source(self): + """The rule's source type/attribute.""" + return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.source_type(self.policy)) + + @property + def target(self): + """The rule's target type/attribute.""" + return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) + + @property + def default(self): + """The rule's default range.""" + return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/netcontext.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/netcontext.py new file mode 100644 index 0000000..5aeed5c --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/netcontext.py @@ -0,0 +1,167 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import socket +from collections import namedtuple + +from . import qpol +from . import symbol +from . import context + +port_range = namedtuple("port_range", ["low", "high"]) + + +def netifcon_factory(policy, name): + """Factory function for creating netifcon objects.""" + + if not isinstance(name, qpol.qpol_netifcon_t): + raise NotImplementedError + + return Netifcon(policy, name) + + +def nodecon_factory(policy, name): + """Factory function for creating nodecon objects.""" + + if not isinstance(name, qpol.qpol_nodecon_t): + raise NotImplementedError + + return Nodecon(policy, name) + + +def portcon_factory(policy, name): + """Factory function for creating portcon objects.""" + + if not isinstance(name, qpol.qpol_portcon_t): + raise NotImplementedError + + return Portcon(policy, name) + + +class NetContext(symbol.PolicySymbol): + + """Base class for in-policy network labeling rules.""" + + def __str__(self): + raise NotImplementedError + + @property + def context(self): + """The context for this statement.""" + return context.context_factory(self.policy, self.qpol_symbol.context(self.policy)) + + def statement(self): + return str(self) + + +class Netifcon(NetContext): + + """A netifcon statement.""" + + def __str__(self): + return "netifcon {0.netif} {0.context} {0.packet}".format(self) + + @property + def netif(self): + """The network interface name.""" + return self.qpol_symbol.name(self.policy) + + @property + def context(self): + """The context for the interface.""" + return context.context_factory(self.policy, self.qpol_symbol.if_con(self.policy)) + + @property + def packet(self): + """The context for the packets.""" + return context.context_factory(self.policy, self.qpol_symbol.msg_con(self.policy)) + + +class Nodecon(NetContext): + + """A nodecon statement.""" + + def __str__(self): + return "nodecon {0.address} {0.netmask} {0.context}".format(self) + + def __eq__(self, other): + # Libqpol allocates new C objects in the + # nodecons iterator, so pointer comparison + # in the PolicySymbol object doesn't work. + try: + return (self.address == other.address and + self.netmask == other.netmask and + self.context == other.context) + except AttributeError: + return (str(self) == str(other)) + + @property + def ip_version(self): + """ + The IP version for the nodecon (socket.AF_INET or + socket.AF_INET6). + """ + return self.qpol_symbol.protocol(self.policy) + + @property + def address(self): + """The network address for the nodecon.""" + return self.qpol_symbol.addr(self.policy) + + @property + def netmask(self): + """The network mask for the nodecon.""" + return self.qpol_symbol.mask(self.policy) + + +class Portcon(NetContext): + + """A portcon statement.""" + + _proto_to_text = {socket.IPPROTO_TCP: 'tcp', + socket.IPPROTO_UDP: 'udp'} + + def __str__(self): + low, high = self.ports + proto = self._proto_to_text[self.protocol] + + if low == high: + return "portcon {0} {1} {2}".format(proto, low, self.context) + else: + return "portcon {0} {1}-{2} {3}".format(proto, low, high, self.context) + + @property + def protocol(self): + """ + The protocol number for the portcon (socket.IPPROTO_TCP + or socket.IPPROTO_UDP). + """ + return self.qpol_symbol.protocol(self.policy) + + @property + def ports(self): + """ + The port range for this portcon. + + Return: Tuple(low, high) + low The low port of the range. + high The high port of the range. + """ + low = self.qpol_symbol.low_port(self.policy) + high = self.qpol_symbol.high_port(self.policy) + return port_range(low, high) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/objclass.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/objclass.py new file mode 100644 index 0000000..bf9a553 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/objclass.py @@ -0,0 +1,110 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import symbol +from . import qpol + + +def common_factory(policy, name): + """Factory function for creating common permission set objects.""" + + if isinstance(name, Common): + assert name.policy == policy + return name + elif isinstance(name, qpol.qpol_common_t): + return Common(policy, name) + + try: + return Common(policy, qpol.qpol_common_t(policy, str(name))) + except ValueError: + raise exception.InvalidCommon("{0} is not a valid common".format(name)) + + +def class_factory(policy, name): + """Factory function for creating object class objects.""" + + if isinstance(name, ObjClass): + assert name.policy == policy + return name + elif isinstance(name, qpol.qpol_class_t): + return ObjClass(policy, name) + + try: + return ObjClass(policy, qpol.qpol_class_t(policy, str(name))) + except ValueError: + raise exception.InvalidClass("{0} is not a valid object class".format(name)) + + +class Common(symbol.PolicySymbol): + + """A common permission set.""" + + def __contains__(self, other): + return other in self.perms + + @property + def perms(self): + """The list of the common's permissions.""" + return set(self.qpol_symbol.perm_iter(self.policy)) + + def statement(self): + return "common {0}\n{{\n\t{1}\n}}".format(self, '\n\t'.join(self.perms)) + + +class ObjClass(Common): + + """An object class.""" + + def __contains__(self, other): + try: + if other in self.common.perms: + return True + except exception.NoCommon: + pass + + return other in self.perms + + @property + def common(self): + """ + The common that the object class inherits. + + Exceptions: + NoCommon The object class does not inherit a common. + """ + + try: + return common_factory(self.policy, self.qpol_symbol.common(self.policy)) + except ValueError: + raise exception.NoCommon("{0} does not inherit a common.".format(self)) + + def statement(self): + stmt = "class {0}\n".format(self) + + try: + stmt += "inherits {0}\n".format(self.common) + except exception.NoCommon: + pass + + # a class that inherits may not have additional permissions + perms = self.perms + if len(perms) > 0: + stmt += "{{\n\t{0}\n}}".format('\n\t'.join(perms)) + + return stmt diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/polcap.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/polcap.py new file mode 100644 index 0000000..8ab164d --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/polcap.py @@ -0,0 +1,40 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import qpol +from . import symbol + + +def polcap_factory(policy, name): + """Factory function for creating policy capability objects.""" + + if isinstance(name, PolicyCapability): + assert name.policy == policy + return name + elif isinstance(name, qpol.qpol_polcap_t): + return PolicyCapability(policy, name) + else: + raise TypeError("Policy capabilities cannot be looked up.") + + +class PolicyCapability(symbol.PolicySymbol): + + """A policy capability.""" + + def statement(self): + return "policycap {0};".format(self) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/qpol.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/qpol.py new file mode 100644 index 0000000..97e602b --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/qpol.py @@ -0,0 +1,1114 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 2.0.11 +# +# Do not make changes to this file unless you know what you are doing--modify +# the SWIG interface file instead. + + + + + +from sys import version_info +if version_info >= (2,6,0): + def swig_import_helper(): + from os.path import dirname + import imp + fp = None + try: + fp, pathname, description = imp.find_module('_qpol', [dirname(__file__)]) + except ImportError: + import _qpol + return _qpol + if fp is not None: + try: + _mod = imp.load_module('_qpol', fp, pathname, description) + finally: + fp.close() + return _mod + _qpol = swig_import_helper() + del swig_import_helper +else: + import _qpol +del version_info +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'SwigPyObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError(name) + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +try: + _object = object + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 + + + +def to_str(*args): + return _qpol.to_str(*args) +to_str = _qpol.to_str +import logging +from functools import wraps + +def QpolGenerator(cast): + """ + A decorator which converts qpol iterators into Python generators. + + Qpol iterators use void* to be generic about their contents. + The purpose of the _from_void functions below is to wrap + the pointer casting, hence the "cast" variable name here. + + Decorator parameter: + cast A wrapper function which casts the qpol iterator return pointer + to the proper C data type pointer. The Python function + reference to the C Python extension is used, for example: + + @QpolGenerator(_qpol.qpol_type_from_void) + """ + + def decorate(func): + @wraps(func) + def wrapper(*args, **kwargs): + qpol_iter = func(*args) + while not qpol_iter.isend(): + yield cast(qpol_iter.item()) + qpol_iter.next_() + + return wrapper + return decorate + +def qpol_logger(level, msg): + """Log qpol messages via Python logging.""" + logging.getLogger("libqpol").debug(msg) + +def qpol_policy_factory(path): + """Factory function for qpol policy objects.""" + # The main purpose here is to hook in the + # above logger callback. + return qpol_policy_t(path, 0, qpol_logger) + +QPOL_POLICY_OPTION_NO_NEVERALLOWS = _qpol.QPOL_POLICY_OPTION_NO_NEVERALLOWS +QPOL_POLICY_OPTION_NO_RULES = _qpol.QPOL_POLICY_OPTION_NO_RULES +QPOL_POLICY_OPTION_MATCH_SYSTEM = _qpol.QPOL_POLICY_OPTION_MATCH_SYSTEM +QPOL_POLICY_MAX_VERSION = _qpol.QPOL_POLICY_MAX_VERSION +QPOL_POLICY_MIN_VERSION = _qpol.QPOL_POLICY_MIN_VERSION +class qpol_policy_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_policy_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_policy_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_policy_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_policy_t + __del__ = lambda self : None; + def version(self): return _qpol.qpol_policy_t_version(self) + def handle_unknown(self): return _qpol.qpol_policy_t_handle_unknown(self) + def capability(self, *args): return _qpol.qpol_policy_t_capability(self, *args) + @QpolGenerator(_qpol.qpol_type_from_void) + def type_iter(self): return _qpol.qpol_policy_t_type_iter(self) + def type_count(self): return _qpol.qpol_policy_t_type_count(self) + @QpolGenerator(_qpol.qpol_role_from_void) + def role_iter(self): return _qpol.qpol_policy_t_role_iter(self) + def role_count(self): return _qpol.qpol_policy_t_role_count(self) + @QpolGenerator(_qpol.qpol_level_from_void) + def level_iter(self): return _qpol.qpol_policy_t_level_iter(self) + def level_count(self): return _qpol.qpol_policy_t_level_count(self) + @QpolGenerator(_qpol.qpol_cat_from_void) + def cat_iter(self): return _qpol.qpol_policy_t_cat_iter(self) + def cat_count(self): return _qpol.qpol_policy_t_cat_count(self) + @QpolGenerator(_qpol.qpol_user_from_void) + def user_iter(self): return _qpol.qpol_policy_t_user_iter(self) + def user_count(self): return _qpol.qpol_policy_t_user_count(self) + @QpolGenerator(_qpol.qpol_bool_from_void) + def bool_iter(self): return _qpol.qpol_policy_t_bool_iter(self) + def bool_count(self): return _qpol.qpol_policy_t_bool_count(self) + @QpolGenerator(_qpol.qpol_class_from_void) + def class_iter(self, perm=None): return _qpol.qpol_policy_t_class_iter(self, perm) + def class_count(self): return _qpol.qpol_policy_t_class_count(self) + @QpolGenerator(_qpol.qpol_common_from_void) + def common_iter(self, perm=None): return _qpol.qpol_policy_t_common_iter(self, perm) + def common_count(self): return _qpol.qpol_policy_t_common_count(self) + @QpolGenerator(_qpol.qpol_fs_use_from_void) + def fs_use_iter(self): return _qpol.qpol_policy_t_fs_use_iter(self) + def fs_use_count(self): return _qpol.qpol_policy_t_fs_use_count(self) + @QpolGenerator(_qpol.qpol_genfscon_from_void) + def genfscon_iter(self): return _qpol.qpol_policy_t_genfscon_iter(self) + def genfscon_count(self): return _qpol.qpol_policy_t_genfscon_count(self) + @QpolGenerator(_qpol.qpol_isid_from_void) + def isid_iter(self): return _qpol.qpol_policy_t_isid_iter(self) + def isid_count(self): return _qpol.qpol_policy_t_isid_count(self) + @QpolGenerator(_qpol.qpol_netifcon_from_void) + def netifcon_iter(self): return _qpol.qpol_policy_t_netifcon_iter(self) + def netifcon_count(self): return _qpol.qpol_policy_t_netifcon_count(self) + @QpolGenerator(_qpol.qpol_nodecon_from_void) + def nodecon_iter(self): return _qpol.qpol_policy_t_nodecon_iter(self) + def nodecon_count(self): return _qpol.qpol_policy_t_nodecon_count(self) + @QpolGenerator(_qpol.qpol_portcon_from_void) + def portcon_iter(self): return _qpol.qpol_policy_t_portcon_iter(self) + def portcon_count(self): return _qpol.qpol_policy_t_portcon_count(self) + @QpolGenerator(_qpol.qpol_constraint_from_void) + def constraint_iter(self): return _qpol.qpol_policy_t_constraint_iter(self) + def constraint_count(self): return _qpol.qpol_policy_t_constraint_count(self) + @QpolGenerator(_qpol.qpol_validatetrans_from_void) + def validatetrans_iter(self): return _qpol.qpol_policy_t_validatetrans_iter(self) + def validatetrans_count(self): return _qpol.qpol_policy_t_validatetrans_count(self) + @QpolGenerator(_qpol.qpol_role_allow_from_void) + def role_allow_iter(self): return _qpol.qpol_policy_t_role_allow_iter(self) + def role_allow_count(self): return _qpol.qpol_policy_t_role_allow_count(self) + @QpolGenerator(_qpol.qpol_role_trans_from_void) + def role_trans_iter(self): return _qpol.qpol_policy_t_role_trans_iter(self) + def role_trans_count(self): return _qpol.qpol_policy_t_role_trans_count(self) + @QpolGenerator(_qpol.qpol_range_trans_from_void) + def range_trans_iter(self): return _qpol.qpol_policy_t_range_trans_iter(self) + def range_trans_count(self): return _qpol.qpol_policy_t_range_trans_count(self) + @QpolGenerator(_qpol.qpol_avrule_from_void) + def avrule_iter(self): return _qpol.qpol_policy_t_avrule_iter(self) + def avrule_allow_count(self): return _qpol.qpol_policy_t_avrule_allow_count(self) + def avrule_auditallow_count(self): return _qpol.qpol_policy_t_avrule_auditallow_count(self) + def avrule_neverallow_count(self): return _qpol.qpol_policy_t_avrule_neverallow_count(self) + def avrule_dontaudit_count(self): return _qpol.qpol_policy_t_avrule_dontaudit_count(self) + @QpolGenerator(_qpol.qpol_terule_from_void) + def terule_iter(self): return _qpol.qpol_policy_t_terule_iter(self) + def terule_trans_count(self): return _qpol.qpol_policy_t_terule_trans_count(self) + def terule_change_count(self): return _qpol.qpol_policy_t_terule_change_count(self) + def terule_member_count(self): return _qpol.qpol_policy_t_terule_member_count(self) + def cond_iter(self): return _qpol.qpol_policy_t_cond_iter(self) + def cond_count(self): return _qpol.qpol_policy_t_cond_count(self) + @QpolGenerator(_qpol.qpol_filename_trans_from_void) + def filename_trans_iter(self): return _qpol.qpol_policy_t_filename_trans_iter(self) + def filename_trans_count(self): return _qpol.qpol_policy_t_filename_trans_count(self) + @QpolGenerator(_qpol.qpol_type_from_void) + def permissive_iter(self): return _qpol.qpol_policy_t_permissive_iter(self) + def permissive_count(self): return _qpol.qpol_policy_t_permissive_count(self) + def typebounds_iter(self): return _qpol.qpol_policy_t_typebounds_iter(self) + def typebounds_count(self): return _qpol.qpol_policy_t_typebounds_count(self) + @QpolGenerator(_qpol.qpol_polcap_from_void) + def polcap_iter(self): return _qpol.qpol_policy_t_polcap_iter(self) + def polcap_count(self): return _qpol.qpol_policy_t_polcap_count(self) + @QpolGenerator(_qpol.qpol_default_object_from_void) + def default_iter(self): return _qpol.qpol_policy_t_default_iter(self) +qpol_policy_t_swigregister = _qpol.qpol_policy_t_swigregister +qpol_policy_t_swigregister(qpol_policy_t) + +QPOL_CAP_ATTRIB_NAMES = _qpol.QPOL_CAP_ATTRIB_NAMES +QPOL_CAP_SYN_RULES = _qpol.QPOL_CAP_SYN_RULES +QPOL_CAP_LINE_NUMBERS = _qpol.QPOL_CAP_LINE_NUMBERS +QPOL_CAP_CONDITIONALS = _qpol.QPOL_CAP_CONDITIONALS +QPOL_CAP_MLS = _qpol.QPOL_CAP_MLS +QPOL_CAP_MODULES = _qpol.QPOL_CAP_MODULES +QPOL_CAP_RULES_LOADED = _qpol.QPOL_CAP_RULES_LOADED +QPOL_CAP_SOURCE = _qpol.QPOL_CAP_SOURCE +QPOL_CAP_NEVERALLOW = _qpol.QPOL_CAP_NEVERALLOW +QPOL_CAP_POLCAPS = _qpol.QPOL_CAP_POLCAPS +QPOL_CAP_BOUNDS = _qpol.QPOL_CAP_BOUNDS +QPOL_CAP_DEFAULT_OBJECTS = _qpol.QPOL_CAP_DEFAULT_OBJECTS +QPOL_CAP_DEFAULT_TYPE = _qpol.QPOL_CAP_DEFAULT_TYPE +QPOL_CAP_PERMISSIVE = _qpol.QPOL_CAP_PERMISSIVE +QPOL_CAP_FILENAME_TRANS = _qpol.QPOL_CAP_FILENAME_TRANS +QPOL_CAP_ROLETRANS = _qpol.QPOL_CAP_ROLETRANS +class qpol_iterator_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_iterator_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_iterator_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_iterator_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_iterator_t + __del__ = lambda self : None; + def item(self): return _qpol.qpol_iterator_t_item(self) + def next_(self): return _qpol.qpol_iterator_t_next_(self) + def isend(self): return _qpol.qpol_iterator_t_isend(self) + def size(self): return _qpol.qpol_iterator_t_size(self) +qpol_iterator_t_swigregister = _qpol.qpol_iterator_t_swigregister +qpol_iterator_t_swigregister(qpol_iterator_t) + +class qpol_type_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_type_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_type_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_type_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_type_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_type_t_name(self, *args) + def value(self, *args): return _qpol.qpol_type_t_value(self, *args) + def isalias(self, *args): return _qpol.qpol_type_t_isalias(self, *args) + def isattr(self, *args): return _qpol.qpol_type_t_isattr(self, *args) + def ispermissive(self, *args): return _qpol.qpol_type_t_ispermissive(self, *args) + @QpolGenerator(_qpol.qpol_type_from_void) + def type_iter(self, *args): return _qpol.qpol_type_t_type_iter(self, *args) + @QpolGenerator(_qpol.qpol_type_from_void) + def attr_iter(self, *args): return _qpol.qpol_type_t_attr_iter(self, *args) + @QpolGenerator(_qpol.to_str) + def alias_iter(self, *args): return _qpol.qpol_type_t_alias_iter(self, *args) +qpol_type_t_swigregister = _qpol.qpol_type_t_swigregister +qpol_type_t_swigregister(qpol_type_t) + + +def qpol_type_from_void(*args): + return _qpol.qpol_type_from_void(*args) +qpol_type_from_void = _qpol.qpol_type_from_void +class qpol_role_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_role_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_role_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_role_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_role_t + __del__ = lambda self : None; + def value(self, *args): return _qpol.qpol_role_t_value(self, *args) + def name(self, *args): return _qpol.qpol_role_t_name(self, *args) + @QpolGenerator(_qpol.qpol_type_from_void) + def type_iter(self, *args): return _qpol.qpol_role_t_type_iter(self, *args) + def dominate_iter(self, *args): return _qpol.qpol_role_t_dominate_iter(self, *args) +qpol_role_t_swigregister = _qpol.qpol_role_t_swigregister +qpol_role_t_swigregister(qpol_role_t) + + +def qpol_role_from_void(*args): + return _qpol.qpol_role_from_void(*args) +qpol_role_from_void = _qpol.qpol_role_from_void +class qpol_level_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_level_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_level_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_level_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_level_t + __del__ = lambda self : None; + def isalias(self, *args): return _qpol.qpol_level_t_isalias(self, *args) + def value(self, *args): return _qpol.qpol_level_t_value(self, *args) + def name(self, *args): return _qpol.qpol_level_t_name(self, *args) + @QpolGenerator(_qpol.qpol_cat_from_void) + def cat_iter(self, *args): return _qpol.qpol_level_t_cat_iter(self, *args) + @QpolGenerator(_qpol.to_str) + def alias_iter(self, *args): return _qpol.qpol_level_t_alias_iter(self, *args) +qpol_level_t_swigregister = _qpol.qpol_level_t_swigregister +qpol_level_t_swigregister(qpol_level_t) + + +def qpol_level_from_void(*args): + return _qpol.qpol_level_from_void(*args) +qpol_level_from_void = _qpol.qpol_level_from_void +class qpol_cat_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_cat_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_cat_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_cat_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_cat_t + __del__ = lambda self : None; + def isalias(self, *args): return _qpol.qpol_cat_t_isalias(self, *args) + def value(self, *args): return _qpol.qpol_cat_t_value(self, *args) + def name(self, *args): return _qpol.qpol_cat_t_name(self, *args) + @QpolGenerator(_qpol.to_str) + def alias_iter(self, *args): return _qpol.qpol_cat_t_alias_iter(self, *args) +qpol_cat_t_swigregister = _qpol.qpol_cat_t_swigregister +qpol_cat_t_swigregister(qpol_cat_t) + + +def qpol_cat_from_void(*args): + return _qpol.qpol_cat_from_void(*args) +qpol_cat_from_void = _qpol.qpol_cat_from_void +class qpol_mls_range_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_mls_range_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_mls_range_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_mls_range_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_mls_range_t + __del__ = lambda self : None; + def high_level(self, *args): return _qpol.qpol_mls_range_t_high_level(self, *args) + def low_level(self, *args): return _qpol.qpol_mls_range_t_low_level(self, *args) +qpol_mls_range_t_swigregister = _qpol.qpol_mls_range_t_swigregister +qpol_mls_range_t_swigregister(qpol_mls_range_t) + + +def qpol_mls_range_from_void(*args): + return _qpol.qpol_mls_range_from_void(*args) +qpol_mls_range_from_void = _qpol.qpol_mls_range_from_void +class qpol_semantic_level_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_semantic_level_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_semantic_level_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_semantic_level_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_semantic_level_t + __del__ = lambda self : None; + def add_cats(self, *args): return _qpol.qpol_semantic_level_t_add_cats(self, *args) +qpol_semantic_level_t_swigregister = _qpol.qpol_semantic_level_t_swigregister +qpol_semantic_level_t_swigregister(qpol_semantic_level_t) + +class qpol_mls_level_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_mls_level_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_mls_level_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_mls_level_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_mls_level_t + __del__ = lambda self : None; + def sens_name(self, *args): return _qpol.qpol_mls_level_t_sens_name(self, *args) + @QpolGenerator(_qpol.qpol_cat_from_void) + def cat_iter(self, *args): return _qpol.qpol_mls_level_t_cat_iter(self, *args) +qpol_mls_level_t_swigregister = _qpol.qpol_mls_level_t_swigregister +qpol_mls_level_t_swigregister(qpol_mls_level_t) + + +def qpol_mls_level_from_void(*args): + return _qpol.qpol_mls_level_from_void(*args) +qpol_mls_level_from_void = _qpol.qpol_mls_level_from_void +class qpol_user_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_user_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_user_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_user_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_user_t + __del__ = lambda self : None; + def value(self, *args): return _qpol.qpol_user_t_value(self, *args) + @QpolGenerator(_qpol.qpol_role_from_void) + def role_iter(self, *args): return _qpol.qpol_user_t_role_iter(self, *args) + def range(self, *args): return _qpol.qpol_user_t_range(self, *args) + def name(self, *args): return _qpol.qpol_user_t_name(self, *args) + def dfltlevel(self, *args): return _qpol.qpol_user_t_dfltlevel(self, *args) +qpol_user_t_swigregister = _qpol.qpol_user_t_swigregister +qpol_user_t_swigregister(qpol_user_t) + + +def qpol_user_from_void(*args): + return _qpol.qpol_user_from_void(*args) +qpol_user_from_void = _qpol.qpol_user_from_void +class qpol_bool_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_bool_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_bool_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_bool_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_bool_t + __del__ = lambda self : None; + def value(self, *args): return _qpol.qpol_bool_t_value(self, *args) + def state(self, *args): return _qpol.qpol_bool_t_state(self, *args) + def name(self, *args): return _qpol.qpol_bool_t_name(self, *args) +qpol_bool_t_swigregister = _qpol.qpol_bool_t_swigregister +qpol_bool_t_swigregister(qpol_bool_t) + + +def qpol_bool_from_void(*args): + return _qpol.qpol_bool_from_void(*args) +qpol_bool_from_void = _qpol.qpol_bool_from_void +class qpol_context_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_context_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_context_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_context_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_context_t + __del__ = lambda self : None; + def user(self, *args): return _qpol.qpol_context_t_user(self, *args) + def role(self, *args): return _qpol.qpol_context_t_role(self, *args) + def type_(self, *args): return _qpol.qpol_context_t_type_(self, *args) + def range(self, *args): return _qpol.qpol_context_t_range(self, *args) +qpol_context_t_swigregister = _qpol.qpol_context_t_swigregister +qpol_context_t_swigregister(qpol_context_t) + + +def qpol_context_from_void(*args): + return _qpol.qpol_context_from_void(*args) +qpol_context_from_void = _qpol.qpol_context_from_void +class qpol_class_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_class_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_class_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_class_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_class_t + __del__ = lambda self : None; + def value(self, *args): return _qpol.qpol_class_t_value(self, *args) + def common(self, *args): return _qpol.qpol_class_t_common(self, *args) + @QpolGenerator(_qpol.to_str) + def perm_iter(self, *args): return _qpol.qpol_class_t_perm_iter(self, *args) + @QpolGenerator(_qpol.qpol_constraint_from_void) + def constraint_iter(self, *args): return _qpol.qpol_class_t_constraint_iter(self, *args) + @QpolGenerator(_qpol.qpol_validatetrans_from_void) + def validatetrans_iter(self, *args): return _qpol.qpol_class_t_validatetrans_iter(self, *args) + def name(self, *args): return _qpol.qpol_class_t_name(self, *args) +qpol_class_t_swigregister = _qpol.qpol_class_t_swigregister +qpol_class_t_swigregister(qpol_class_t) + + +def qpol_class_from_void(*args): + return _qpol.qpol_class_from_void(*args) +qpol_class_from_void = _qpol.qpol_class_from_void +class qpol_common_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_common_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_common_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_common_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_common_t + __del__ = lambda self : None; + def value(self, *args): return _qpol.qpol_common_t_value(self, *args) + @QpolGenerator(_qpol.to_str) + def perm_iter(self, *args): return _qpol.qpol_common_t_perm_iter(self, *args) + def name(self, *args): return _qpol.qpol_common_t_name(self, *args) +qpol_common_t_swigregister = _qpol.qpol_common_t_swigregister +qpol_common_t_swigregister(qpol_common_t) + + +def qpol_common_from_void(*args): + return _qpol.qpol_common_from_void(*args) +qpol_common_from_void = _qpol.qpol_common_from_void +QPOL_FS_USE_XATTR = _qpol.QPOL_FS_USE_XATTR +QPOL_FS_USE_TRANS = _qpol.QPOL_FS_USE_TRANS +QPOL_FS_USE_TASK = _qpol.QPOL_FS_USE_TASK +QPOL_FS_USE_GENFS = _qpol.QPOL_FS_USE_GENFS +QPOL_FS_USE_NONE = _qpol.QPOL_FS_USE_NONE +QPOL_FS_USE_PSID = _qpol.QPOL_FS_USE_PSID +class qpol_fs_use_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_fs_use_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_fs_use_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_fs_use_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_fs_use_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_fs_use_t_name(self, *args) + def behavior(self, *args): return _qpol.qpol_fs_use_t_behavior(self, *args) + def context(self, *args): return _qpol.qpol_fs_use_t_context(self, *args) +qpol_fs_use_t_swigregister = _qpol.qpol_fs_use_t_swigregister +qpol_fs_use_t_swigregister(qpol_fs_use_t) + + +def qpol_fs_use_from_void(*args): + return _qpol.qpol_fs_use_from_void(*args) +qpol_fs_use_from_void = _qpol.qpol_fs_use_from_void +QPOL_CLASS_ALL = _qpol.QPOL_CLASS_ALL +QPOL_CLASS_BLK_FILE = _qpol.QPOL_CLASS_BLK_FILE +QPOL_CLASS_CHR_FILE = _qpol.QPOL_CLASS_CHR_FILE +QPOL_CLASS_DIR = _qpol.QPOL_CLASS_DIR +QPOL_CLASS_FIFO_FILE = _qpol.QPOL_CLASS_FIFO_FILE +QPOL_CLASS_FILE = _qpol.QPOL_CLASS_FILE +QPOL_CLASS_LNK_FILE = _qpol.QPOL_CLASS_LNK_FILE +QPOL_CLASS_SOCK_FILE = _qpol.QPOL_CLASS_SOCK_FILE +class qpol_genfscon_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_genfscon_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_genfscon_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_genfscon_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_genfscon_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_genfscon_t_name(self, *args) + def path(self, *args): return _qpol.qpol_genfscon_t_path(self, *args) + def object_class(self, *args): return _qpol.qpol_genfscon_t_object_class(self, *args) + def context(self, *args): return _qpol.qpol_genfscon_t_context(self, *args) +qpol_genfscon_t_swigregister = _qpol.qpol_genfscon_t_swigregister +qpol_genfscon_t_swigregister(qpol_genfscon_t) + + +def qpol_genfscon_from_void(*args): + return _qpol.qpol_genfscon_from_void(*args) +qpol_genfscon_from_void = _qpol.qpol_genfscon_from_void +class qpol_isid_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_isid_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_isid_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_isid_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_isid_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_isid_t_name(self, *args) + def context(self, *args): return _qpol.qpol_isid_t_context(self, *args) +qpol_isid_t_swigregister = _qpol.qpol_isid_t_swigregister +qpol_isid_t_swigregister(qpol_isid_t) + + +def qpol_isid_from_void(*args): + return _qpol.qpol_isid_from_void(*args) +qpol_isid_from_void = _qpol.qpol_isid_from_void +class qpol_netifcon_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_netifcon_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_netifcon_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_netifcon_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_netifcon_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_netifcon_t_name(self, *args) + def msg_con(self, *args): return _qpol.qpol_netifcon_t_msg_con(self, *args) + def if_con(self, *args): return _qpol.qpol_netifcon_t_if_con(self, *args) +qpol_netifcon_t_swigregister = _qpol.qpol_netifcon_t_swigregister +qpol_netifcon_t_swigregister(qpol_netifcon_t) + + +def qpol_netifcon_from_void(*args): + return _qpol.qpol_netifcon_from_void(*args) +qpol_netifcon_from_void = _qpol.qpol_netifcon_from_void +QPOL_IPV4 = _qpol.QPOL_IPV4 +QPOL_IPV6 = _qpol.QPOL_IPV6 +class qpol_nodecon_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_nodecon_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_nodecon_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_nodecon_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_nodecon_t + __del__ = lambda self : None; + def addr(self, *args): return _qpol.qpol_nodecon_t_addr(self, *args) + def mask(self, *args): return _qpol.qpol_nodecon_t_mask(self, *args) + def protocol(self, *args): return _qpol.qpol_nodecon_t_protocol(self, *args) + def context(self, *args): return _qpol.qpol_nodecon_t_context(self, *args) +qpol_nodecon_t_swigregister = _qpol.qpol_nodecon_t_swigregister +qpol_nodecon_t_swigregister(qpol_nodecon_t) + + +def qpol_nodecon_from_void(*args): + return _qpol.qpol_nodecon_from_void(*args) +qpol_nodecon_from_void = _qpol.qpol_nodecon_from_void +IPPROTO_TCP = _qpol.IPPROTO_TCP +IPPROTO_UDP = _qpol.IPPROTO_UDP +class qpol_portcon_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_portcon_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_portcon_t, name) + __repr__ = _swig_repr + def __init__(self, *args): + this = _qpol.new_qpol_portcon_t(*args) + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_portcon_t + __del__ = lambda self : None; + def low_port(self, *args): return _qpol.qpol_portcon_t_low_port(self, *args) + def high_port(self, *args): return _qpol.qpol_portcon_t_high_port(self, *args) + def protocol(self, *args): return _qpol.qpol_portcon_t_protocol(self, *args) + def context(self, *args): return _qpol.qpol_portcon_t_context(self, *args) +qpol_portcon_t_swigregister = _qpol.qpol_portcon_t_swigregister +qpol_portcon_t_swigregister(qpol_portcon_t) + + +def qpol_portcon_from_void(*args): + return _qpol.qpol_portcon_from_void(*args) +qpol_portcon_from_void = _qpol.qpol_portcon_from_void +class qpol_constraint_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_constraint_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_constraint_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_constraint_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_constraint_t + __del__ = lambda self : None; + def object_class(self, *args): return _qpol.qpol_constraint_t_object_class(self, *args) + @QpolGenerator(_qpol.to_str) + def perm_iter(self, *args): return _qpol.qpol_constraint_t_perm_iter(self, *args) + @QpolGenerator(_qpol.qpol_constraint_expr_node_from_void) + def expr_iter(self, *args): return _qpol.qpol_constraint_t_expr_iter(self, *args) +qpol_constraint_t_swigregister = _qpol.qpol_constraint_t_swigregister +qpol_constraint_t_swigregister(qpol_constraint_t) + + +def qpol_constraint_from_void(*args): + return _qpol.qpol_constraint_from_void(*args) +qpol_constraint_from_void = _qpol.qpol_constraint_from_void +class qpol_validatetrans_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_validatetrans_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_validatetrans_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_validatetrans_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_validatetrans_t + __del__ = lambda self : None; + def object_class(self, *args): return _qpol.qpol_validatetrans_t_object_class(self, *args) + @QpolGenerator(_qpol.qpol_constraint_expr_node_from_void) + def expr_iter(self, *args): return _qpol.qpol_validatetrans_t_expr_iter(self, *args) +qpol_validatetrans_t_swigregister = _qpol.qpol_validatetrans_t_swigregister +qpol_validatetrans_t_swigregister(qpol_validatetrans_t) + + +def qpol_validatetrans_from_void(*args): + return _qpol.qpol_validatetrans_from_void(*args) +qpol_validatetrans_from_void = _qpol.qpol_validatetrans_from_void +QPOL_CEXPR_TYPE_NOT = _qpol.QPOL_CEXPR_TYPE_NOT +QPOL_CEXPR_TYPE_AND = _qpol.QPOL_CEXPR_TYPE_AND +QPOL_CEXPR_TYPE_OR = _qpol.QPOL_CEXPR_TYPE_OR +QPOL_CEXPR_TYPE_ATTR = _qpol.QPOL_CEXPR_TYPE_ATTR +QPOL_CEXPR_TYPE_NAMES = _qpol.QPOL_CEXPR_TYPE_NAMES +QPOL_CEXPR_SYM_USER = _qpol.QPOL_CEXPR_SYM_USER +QPOL_CEXPR_SYM_ROLE = _qpol.QPOL_CEXPR_SYM_ROLE +QPOL_CEXPR_SYM_TYPE = _qpol.QPOL_CEXPR_SYM_TYPE +QPOL_CEXPR_SYM_TARGET = _qpol.QPOL_CEXPR_SYM_TARGET +QPOL_CEXPR_SYM_XTARGET = _qpol.QPOL_CEXPR_SYM_XTARGET +QPOL_CEXPR_SYM_L1L2 = _qpol.QPOL_CEXPR_SYM_L1L2 +QPOL_CEXPR_SYM_L1H2 = _qpol.QPOL_CEXPR_SYM_L1H2 +QPOL_CEXPR_SYM_H1L2 = _qpol.QPOL_CEXPR_SYM_H1L2 +QPOL_CEXPR_SYM_H1H2 = _qpol.QPOL_CEXPR_SYM_H1H2 +QPOL_CEXPR_SYM_L1H1 = _qpol.QPOL_CEXPR_SYM_L1H1 +QPOL_CEXPR_SYM_L2H2 = _qpol.QPOL_CEXPR_SYM_L2H2 +QPOL_CEXPR_OP_EQ = _qpol.QPOL_CEXPR_OP_EQ +QPOL_CEXPR_OP_NEQ = _qpol.QPOL_CEXPR_OP_NEQ +QPOL_CEXPR_OP_DOM = _qpol.QPOL_CEXPR_OP_DOM +QPOL_CEXPR_OP_DOMBY = _qpol.QPOL_CEXPR_OP_DOMBY +QPOL_CEXPR_OP_INCOMP = _qpol.QPOL_CEXPR_OP_INCOMP +class qpol_constraint_expr_node_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_constraint_expr_node_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_constraint_expr_node_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_constraint_expr_node_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_constraint_expr_node_t + __del__ = lambda self : None; + def expr_type(self, *args): return _qpol.qpol_constraint_expr_node_t_expr_type(self, *args) + def sym_type(self, *args): return _qpol.qpol_constraint_expr_node_t_sym_type(self, *args) + def op(self, *args): return _qpol.qpol_constraint_expr_node_t_op(self, *args) + @QpolGenerator(_qpol.to_str) + def names_iter(self, *args): return _qpol.qpol_constraint_expr_node_t_names_iter(self, *args) +qpol_constraint_expr_node_t_swigregister = _qpol.qpol_constraint_expr_node_t_swigregister +qpol_constraint_expr_node_t_swigregister(qpol_constraint_expr_node_t) + + +def qpol_constraint_expr_node_from_void(*args): + return _qpol.qpol_constraint_expr_node_from_void(*args) +qpol_constraint_expr_node_from_void = _qpol.qpol_constraint_expr_node_from_void +class qpol_role_allow_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_role_allow_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_role_allow_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_role_allow_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_role_allow_t + __del__ = lambda self : None; + def rule_type(self,policy): + return "allow" + + def source_role(self, *args): return _qpol.qpol_role_allow_t_source_role(self, *args) + def target_role(self, *args): return _qpol.qpol_role_allow_t_target_role(self, *args) +qpol_role_allow_t_swigregister = _qpol.qpol_role_allow_t_swigregister +qpol_role_allow_t_swigregister(qpol_role_allow_t) + + +def qpol_role_allow_from_void(*args): + return _qpol.qpol_role_allow_from_void(*args) +qpol_role_allow_from_void = _qpol.qpol_role_allow_from_void +class qpol_role_trans_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_role_trans_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_role_trans_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_role_trans_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_role_trans_t + __del__ = lambda self : None; + def rule_type(self,policy): + return "role_transition" + + def source_role(self, *args): return _qpol.qpol_role_trans_t_source_role(self, *args) + def target_type(self, *args): return _qpol.qpol_role_trans_t_target_type(self, *args) + def object_class(self, *args): return _qpol.qpol_role_trans_t_object_class(self, *args) + def default_role(self, *args): return _qpol.qpol_role_trans_t_default_role(self, *args) +qpol_role_trans_t_swigregister = _qpol.qpol_role_trans_t_swigregister +qpol_role_trans_t_swigregister(qpol_role_trans_t) + + +def qpol_role_trans_from_void(*args): + return _qpol.qpol_role_trans_from_void(*args) +qpol_role_trans_from_void = _qpol.qpol_role_trans_from_void +class qpol_range_trans_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_range_trans_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_range_trans_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_range_trans_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_range_trans_t + __del__ = lambda self : None; + def rule_type(self,policy): + return "range_transition" + + def source_type(self, *args): return _qpol.qpol_range_trans_t_source_type(self, *args) + def target_type(self, *args): return _qpol.qpol_range_trans_t_target_type(self, *args) + def object_class(self, *args): return _qpol.qpol_range_trans_t_object_class(self, *args) + def range(self, *args): return _qpol.qpol_range_trans_t_range(self, *args) +qpol_range_trans_t_swigregister = _qpol.qpol_range_trans_t_swigregister +qpol_range_trans_t_swigregister(qpol_range_trans_t) + + +def qpol_range_trans_from_void(*args): + return _qpol.qpol_range_trans_from_void(*args) +qpol_range_trans_from_void = _qpol.qpol_range_trans_from_void +QPOL_RULE_ALLOW = _qpol.QPOL_RULE_ALLOW +QPOL_RULE_NEVERALLOW = _qpol.QPOL_RULE_NEVERALLOW +QPOL_RULE_AUDITALLOW = _qpol.QPOL_RULE_AUDITALLOW +QPOL_RULE_DONTAUDIT = _qpol.QPOL_RULE_DONTAUDIT +class qpol_avrule_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_avrule_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_avrule_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_avrule_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_avrule_t + __del__ = lambda self : None; + def rule_type(self, *args): return _qpol.qpol_avrule_t_rule_type(self, *args) + def source_type(self, *args): return _qpol.qpol_avrule_t_source_type(self, *args) + def target_type(self, *args): return _qpol.qpol_avrule_t_target_type(self, *args) + def object_class(self, *args): return _qpol.qpol_avrule_t_object_class(self, *args) + @QpolGenerator(_qpol.to_str) + def perm_iter(self, *args): return _qpol.qpol_avrule_t_perm_iter(self, *args) + def cond(self, *args): return _qpol.qpol_avrule_t_cond(self, *args) + def is_enabled(self, *args): return _qpol.qpol_avrule_t_is_enabled(self, *args) + def which_list(self, *args): return _qpol.qpol_avrule_t_which_list(self, *args) + def syn_avrule_iter(self, *args): return _qpol.qpol_avrule_t_syn_avrule_iter(self, *args) +qpol_avrule_t_swigregister = _qpol.qpol_avrule_t_swigregister +qpol_avrule_t_swigregister(qpol_avrule_t) + + +def qpol_avrule_from_void(*args): + return _qpol.qpol_avrule_from_void(*args) +qpol_avrule_from_void = _qpol.qpol_avrule_from_void +QPOL_RULE_TYPE_TRANS = _qpol.QPOL_RULE_TYPE_TRANS +QPOL_RULE_TYPE_CHANGE = _qpol.QPOL_RULE_TYPE_CHANGE +QPOL_RULE_TYPE_MEMBER = _qpol.QPOL_RULE_TYPE_MEMBER +class qpol_terule_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_terule_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_terule_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_terule_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_terule_t + __del__ = lambda self : None; + def rule_type(self, *args): return _qpol.qpol_terule_t_rule_type(self, *args) + def source_type(self, *args): return _qpol.qpol_terule_t_source_type(self, *args) + def target_type(self, *args): return _qpol.qpol_terule_t_target_type(self, *args) + def object_class(self, *args): return _qpol.qpol_terule_t_object_class(self, *args) + def default_type(self, *args): return _qpol.qpol_terule_t_default_type(self, *args) + def cond(self, *args): return _qpol.qpol_terule_t_cond(self, *args) + def is_enabled(self, *args): return _qpol.qpol_terule_t_is_enabled(self, *args) + def which_list(self, *args): return _qpol.qpol_terule_t_which_list(self, *args) + def syn_terule_iter(self, *args): return _qpol.qpol_terule_t_syn_terule_iter(self, *args) +qpol_terule_t_swigregister = _qpol.qpol_terule_t_swigregister +qpol_terule_t_swigregister(qpol_terule_t) + + +def qpol_terule_from_void(*args): + return _qpol.qpol_terule_from_void(*args) +qpol_terule_from_void = _qpol.qpol_terule_from_void +class qpol_cond_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_cond_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_cond_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_cond_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_cond_t + __del__ = lambda self : None; + @QpolGenerator(_qpol.qpol_cond_expr_node_from_void) + def expr_node_iter(self, *args): return _qpol.qpol_cond_t_expr_node_iter(self, *args) + def av_true_iter(self, *args): return _qpol.qpol_cond_t_av_true_iter(self, *args) + def av_false_iter(self, *args): return _qpol.qpol_cond_t_av_false_iter(self, *args) + def te_true_iter(self, *args): return _qpol.qpol_cond_t_te_true_iter(self, *args) + def te_false_iter(self, *args): return _qpol.qpol_cond_t_te_false_iter(self, *args) + def evaluate(self, *args): return _qpol.qpol_cond_t_evaluate(self, *args) +qpol_cond_t_swigregister = _qpol.qpol_cond_t_swigregister +qpol_cond_t_swigregister(qpol_cond_t) + + +def qpol_cond_from_void(*args): + return _qpol.qpol_cond_from_void(*args) +qpol_cond_from_void = _qpol.qpol_cond_from_void +QPOL_COND_EXPR_BOOL = _qpol.QPOL_COND_EXPR_BOOL +QPOL_COND_EXPR_NOT = _qpol.QPOL_COND_EXPR_NOT +QPOL_COND_EXPR_OR = _qpol.QPOL_COND_EXPR_OR +QPOL_COND_EXPR_AND = _qpol.QPOL_COND_EXPR_AND +QPOL_COND_EXPR_XOR = _qpol.QPOL_COND_EXPR_XOR +QPOL_COND_EXPR_EQ = _qpol.QPOL_COND_EXPR_EQ +QPOL_COND_EXPR_NEQ = _qpol.QPOL_COND_EXPR_NEQ +class qpol_cond_expr_node_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_cond_expr_node_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_cond_expr_node_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_cond_expr_node_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_cond_expr_node_t + __del__ = lambda self : None; + def expr_type(self, *args): return _qpol.qpol_cond_expr_node_t_expr_type(self, *args) + def get_boolean(self, *args): return _qpol.qpol_cond_expr_node_t_get_boolean(self, *args) +qpol_cond_expr_node_t_swigregister = _qpol.qpol_cond_expr_node_t_swigregister +qpol_cond_expr_node_t_swigregister(qpol_cond_expr_node_t) + + +def qpol_cond_expr_node_from_void(*args): + return _qpol.qpol_cond_expr_node_from_void(*args) +qpol_cond_expr_node_from_void = _qpol.qpol_cond_expr_node_from_void +class qpol_filename_trans_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_filename_trans_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_filename_trans_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_filename_trans_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_filename_trans_t + __del__ = lambda self : None; + def rule_type(self,policy): + return "type_transition" + + def source_type(self, *args): return _qpol.qpol_filename_trans_t_source_type(self, *args) + def target_type(self, *args): return _qpol.qpol_filename_trans_t_target_type(self, *args) + def object_class(self, *args): return _qpol.qpol_filename_trans_t_object_class(self, *args) + def default_type(self, *args): return _qpol.qpol_filename_trans_t_default_type(self, *args) + def filename(self, *args): return _qpol.qpol_filename_trans_t_filename(self, *args) +qpol_filename_trans_t_swigregister = _qpol.qpol_filename_trans_t_swigregister +qpol_filename_trans_t_swigregister(qpol_filename_trans_t) + + +def qpol_filename_trans_from_void(*args): + return _qpol.qpol_filename_trans_from_void(*args) +qpol_filename_trans_from_void = _qpol.qpol_filename_trans_from_void +class qpol_polcap_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_polcap_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_polcap_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_polcap_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_polcap_t + __del__ = lambda self : None; + def name(self, *args): return _qpol.qpol_polcap_t_name(self, *args) +qpol_polcap_t_swigregister = _qpol.qpol_polcap_t_swigregister +qpol_polcap_t_swigregister(qpol_polcap_t) + + +def qpol_polcap_from_void(*args): + return _qpol.qpol_polcap_from_void(*args) +qpol_polcap_from_void = _qpol.qpol_polcap_from_void +class qpol_typebounds_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_typebounds_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_typebounds_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_typebounds_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_typebounds_t + __del__ = lambda self : None; + def parent_name(self, *args): return _qpol.qpol_typebounds_t_parent_name(self, *args) + def child_name(self, *args): return _qpol.qpol_typebounds_t_child_name(self, *args) +qpol_typebounds_t_swigregister = _qpol.qpol_typebounds_t_swigregister +qpol_typebounds_t_swigregister(qpol_typebounds_t) + + +def qpol_typebounds_from_void(*args): + return _qpol.qpol_typebounds_from_void(*args) +qpol_typebounds_from_void = _qpol.qpol_typebounds_from_void +class qpol_rolebounds_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_rolebounds_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_rolebounds_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_rolebounds_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_rolebounds_t + __del__ = lambda self : None; + def parent_name(self, *args): return _qpol.qpol_rolebounds_t_parent_name(self, *args) + def child_name(self, *args): return _qpol.qpol_rolebounds_t_child_name(self, *args) +qpol_rolebounds_t_swigregister = _qpol.qpol_rolebounds_t_swigregister +qpol_rolebounds_t_swigregister(qpol_rolebounds_t) + + +def qpol_rolebounds_from_void(*args): + return _qpol.qpol_rolebounds_from_void(*args) +qpol_rolebounds_from_void = _qpol.qpol_rolebounds_from_void +class qpol_userbounds_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_userbounds_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_userbounds_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_userbounds_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_userbounds_t + __del__ = lambda self : None; + def parent_name(self, *args): return _qpol.qpol_userbounds_t_parent_name(self, *args) + def child_name(self, *args): return _qpol.qpol_userbounds_t_child_name(self, *args) +qpol_userbounds_t_swigregister = _qpol.qpol_userbounds_t_swigregister +qpol_userbounds_t_swigregister(qpol_userbounds_t) + + +def qpol_userbounds_from_void(*args): + return _qpol.qpol_userbounds_from_void(*args) +qpol_userbounds_from_void = _qpol.qpol_userbounds_from_void +class qpol_default_object_t(_object): + __swig_setmethods__ = {} + __setattr__ = lambda self, name, value: _swig_setattr(self, qpol_default_object_t, name, value) + __swig_getmethods__ = {} + __getattr__ = lambda self, name: _swig_getattr(self, qpol_default_object_t, name) + __repr__ = _swig_repr + def __init__(self): + this = _qpol.new_qpol_default_object_t() + try: self.this.append(this) + except: self.this = this + __swig_destroy__ = _qpol.delete_qpol_default_object_t + __del__ = lambda self : None; + def object_class(self, *args): return _qpol.qpol_default_object_t_object_class(self, *args) + def user_default(self, *args): return _qpol.qpol_default_object_t_user_default(self, *args) + def role_default(self, *args): return _qpol.qpol_default_object_t_role_default(self, *args) + def type_default(self, *args): return _qpol.qpol_default_object_t_type_default(self, *args) + def range_default(self, *args): return _qpol.qpol_default_object_t_range_default(self, *args) +qpol_default_object_t_swigregister = _qpol.qpol_default_object_t_swigregister +qpol_default_object_t_swigregister(qpol_default_object_t) + + +def qpol_default_object_from_void(*args): + return _qpol.qpol_default_object_from_void(*args) +qpol_default_object_from_void = _qpol.qpol_default_object_from_void +# This file is compatible with both classic and new-style classes. + + diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rbacrule.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rbacrule.py new file mode 100644 index 0000000..aa6a0d0 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rbacrule.py @@ -0,0 +1,92 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import rule +from . import role +from . import typeattr + + +def rbac_rule_factory(policy, name): + """Factory function for creating RBAC rule objects.""" + + if isinstance(name, qpol.qpol_role_allow_t): + return RoleAllow(policy, name) + elif isinstance(name, qpol.qpol_role_trans_t): + return RoleTransition(policy, name) + else: + raise TypeError("RBAC rules cannot be looked up.") + + +def validate_ruletype(types): + """Validate RBAC rule types.""" + for t in types: + if t not in ["allow", "role_transition"]: + raise exception.InvalidRBACRuleType("{0} is not a valid RBAC rule type.".format(t)) + + +class RoleAllow(rule.PolicyRule): + + """A role allow rule.""" + + def __str__(self): + return "allow {0.source} {0.target};".format(self) + + @property + def source(self): + """The rule's source role.""" + return role.role_factory(self.policy, self.qpol_symbol.source_role(self.policy)) + + @property + def target(self): + """The rule's target role.""" + return role.role_factory(self.policy, self.qpol_symbol.target_role(self.policy)) + + @property + def tclass(self): + """The rule's object class.""" + raise exception.RuleUseError("Role allow rules do not have an object class.") + + @property + def default(self): + """The rule's default role.""" + raise exception.RuleUseError("Role allow rules do not have a default role.") + + +class RoleTransition(rule.PolicyRule): + + """A role_transition rule.""" + + def __str__(self): + return "role_transition {0.source} {0.target}:{0.tclass} {0.default};".format(self) + + @property + def source(self): + """The rule's source role.""" + return role.role_factory(self.policy, self.qpol_symbol.source_role(self.policy)) + + @property + def target(self): + """The rule's target type/attribute.""" + return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) + + @property + def default(self): + """The rule's default role.""" + return role.role_factory(self.policy, self.qpol_symbol.default_role(self.policy)) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/role.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/role.py new file mode 100644 index 0000000..1d9fbe1 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/role.py @@ -0,0 +1,81 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import symbol +from . import typeattr + + +def role_factory(qpol_policy, name): + """Factory function for creating Role objects.""" + + if isinstance(name, Role): + assert name.policy == qpol_policy + return name + elif isinstance(name, qpol.qpol_role_t): + return Role(qpol_policy, name) + + try: + return Role(qpol_policy, qpol.qpol_role_t(qpol_policy, str(name))) + except ValueError: + raise exception.InvalidRole("{0} is not a valid role".format(name)) + + +class BaseRole(symbol.PolicySymbol): + + """Role/role attribute base class.""" + + def expand(self): + raise NotImplementedError + + def types(self): + raise NotImplementedError + + +class Role(BaseRole): + + """A role.""" + + def expand(self): + """Generator that expands this into its member roles.""" + yield self + + def types(self): + """Generator which yields the role's set of types.""" + + for type_ in self.qpol_symbol.type_iter(self.policy): + yield typeattr.type_or_attr_factory(self.policy, type_) + + def statement(self): + types = list(str(t) for t in self.types()) + stmt = "role {0}".format(self) + if types: + if (len(types) > 1): + stmt += " types {{ {0} }}".format(' '.join(types)) + else: + stmt += " types {0}".format(types[0]) + stmt += ";" + return stmt + + +class RoleAttribute(BaseRole): + + """A role attribute.""" + + pass diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rule.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rule.py new file mode 100644 index 0000000..73fc812 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/rule.py @@ -0,0 +1,72 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import symbol +from . import objclass + + +class PolicyRule(symbol.PolicySymbol): + + """This is base class for policy rules.""" + + def __str__(self): + raise NotImplementedError + + @property + def ruletype(self): + """The rule type for the rule.""" + return self.qpol_symbol.rule_type(self.policy) + + @property + def source(self): + """ + The source for the rule. This should be overridden by + subclasses. + """ + raise NotImplementedError + + @property + def target(self): + """ + The target for the rule. This should be overridden by + subclasses. + """ + raise NotImplementedError + + @property + def tclass(self): + """The object class for the rule.""" + return objclass.class_factory(self.policy, self.qpol_symbol.object_class(self.policy)) + + @property + def default(self): + """ + The default for the rule. This should be overridden by + subclasses. + """ + raise NotImplementedError + + @property + def conditional(self): + """The conditional expression for this rule.""" + # Most rules cannot be conditional. + raise exception.RuleNotConditional + + def statement(self): + return str(self) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/symbol.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/symbol.py new file mode 100644 index 0000000..4712d7f --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/symbol.py @@ -0,0 +1,74 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# + + +class PolicySymbol(object): + + """This is a base class for all policy objects.""" + + def __init__(self, policy, qpol_symbol): + """ + Parameters: + policy The low-level policy object. + qpol_symbol The low-level policy symbol object. + """ + + assert qpol_symbol + + self.policy = policy + self.qpol_symbol = qpol_symbol + + def __str__(self): + return self.qpol_symbol.name(self.policy) + + def __hash__(self): + return hash(self.qpol_symbol.name(self.policy)) + + def __eq__(self, other): + try: + return self.qpol_symbol.this == other.qpol_symbol.this + except AttributeError: + return str(self) == str(other) + + def __ne__(self, other): + return not self == other + + def __lt__(self, other): + """Comparison used by Python sorting functions.""" + return str(self) < str(other) + + def __repr__(self): + return "<{0.__class__.__name__}(<qpol_policy_t id={1}>,\"{0}\")>".format( + self, id(self.policy)) + + def __deepcopy__(self, memo): + # shallow copy as all of the members are immutable + cls = self.__class__ + newobj = cls.__new__(cls) + newobj.policy = self.policy + newobj.qpol_symbol = self.qpol_symbol + memo[id(self)] = newobj + return newobj + + def statement(self): + """ + A rendering of the policy statement. This should be + overridden by subclasses. + """ + raise NotImplementedError diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/terule.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/terule.py new file mode 100644 index 0000000..d8a9e94 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/terule.py @@ -0,0 +1,155 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import rule +from . import typeattr +from . import boolcond + + +def te_rule_factory(policy, symbol): + """Factory function for creating TE rule objects.""" + + if isinstance(symbol, qpol.qpol_avrule_t): + return AVRule(policy, symbol) + elif isinstance(symbol, (qpol.qpol_terule_t, qpol.qpol_filename_trans_t)): + return TERule(policy, symbol) + else: + raise TypeError("TE rules cannot be looked-up.") + + +def validate_ruletype(types): + """Validate TE Rule types.""" + for t in types: + if t not in ["allow", "auditallow", "dontaudit", "neverallow", + "type_transition", "type_member", "type_change"]: + raise exception.InvalidTERuleType("{0} is not a valid TE rule type.".format(t)) + + +class BaseTERule(rule.PolicyRule): + + """A type enforcement rule.""" + + @property + def source(self): + """The rule's source type/attribute.""" + return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.source_type(self.policy)) + + @property + def target(self): + """The rule's target type/attribute.""" + return typeattr.type_or_attr_factory(self.policy, self.qpol_symbol.target_type(self.policy)) + + @property + def filename(self): + raise NotImplementedError + + @property + def conditional(self): + """The rule's conditional expression.""" + try: + return boolcond.condexpr_factory(self.policy, self.qpol_symbol.cond(self.policy)) + except (AttributeError, ValueError): + # AttributeError: name filetrans rules cannot be conditional + # so no member function + # ValueError: The rule is not conditional + raise exception.RuleNotConditional + + +class AVRule(BaseTERule): + + """An access vector type enforcement rule.""" + + def __str__(self): + rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} ".format( + self) + + perms = self.perms + + # allow/dontaudit/auditallow/neverallow rules + if len(perms) > 1: + rule_string += "{{ {0} }};".format(' '.join(perms)) + else: + # convert to list since sets cannot be indexed + rule_string += "{0};".format(list(perms)[0]) + + try: + rule_string += " [ {0} ]".format(self.conditional) + except exception.RuleNotConditional: + pass + + return rule_string + + @property + def perms(self): + """The rule's permission set.""" + return set(self.qpol_symbol.perm_iter(self.policy)) + + @property + def default(self): + """The rule's default type.""" + raise exception.RuleUseError("{0} rules do not have a default type.".format(self.ruletype)) + + @property + def filename(self): + raise exception.RuleUseError("{0} rules do not have file names".format(self.ruletype)) + + +class TERule(BaseTERule): + + """A type_* type enforcement rule.""" + + def __str__(self): + rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default}".format(self) + + try: + rule_string += " \"{0}\";".format(self.filename) + except (exception.TERuleNoFilename, exception.RuleUseError): + # invalid use for type_change/member + rule_string += ";" + + try: + rule_string += " [ {0} ]".format(self.conditional) + except exception.RuleNotConditional: + pass + + return rule_string + + @property + def perms(self): + """The rule's permission set.""" + raise exception.RuleUseError( + "{0} rules do not have a permission set.".format(self.ruletype)) + + @property + def default(self): + """The rule's default type.""" + return typeattr.type_factory(self.policy, self.qpol_symbol.default_type(self.policy)) + + @property + def filename(self): + """The type_transition rule's file name.""" + try: + return self.qpol_symbol.filename(self.policy) + except AttributeError: + if self.ruletype == "type_transition": + raise exception.TERuleNoFilename + else: + raise exception.RuleUseError("{0} rules do not have file names". + format(self.ruletype)) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/typeattr.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/typeattr.py new file mode 100644 index 0000000..a52c69a --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/typeattr.py @@ -0,0 +1,174 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import symbol + + +def _symbol_lookup(qpol_policy, name): + """Look up the low-level qpol policy reference""" + if isinstance(name, qpol.qpol_type_t): + return name + + try: + return qpol.qpol_type_t(qpol_policy, str(name)) + except ValueError: + raise exception.InvalidType("{0} is not a valid type/attribute".format(name)) + + +def attribute_factory(qpol_policy, name): + """Factory function for creating attribute objects.""" + + if isinstance(name, TypeAttribute): + assert name.policy == qpol_policy + return name + + qpol_symbol = _symbol_lookup(qpol_policy, name) + + if not qpol_symbol.isattr(qpol_policy): + raise TypeError("{0} is a type".format(qpol_symbol.name(qpol_policy))) + + return TypeAttribute(qpol_policy, qpol_symbol) + + +def type_factory(qpol_policy, name, deref=False): + """Factory function for creating type objects.""" + + if isinstance(name, Type): + assert name.policy == qpol_policy + return name + + qpol_symbol = _symbol_lookup(qpol_policy, name) + + if qpol_symbol.isattr(qpol_policy): + raise TypeError("{0} is an attribute".format(qpol_symbol.name(qpol_policy))) + elif qpol_symbol.isalias(qpol_policy) and not deref: + raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) + + return Type(qpol_policy, qpol_symbol) + + +def type_or_attr_factory(qpol_policy, name, deref=False): + """Factory function for creating type or attribute objects.""" + + if isinstance(name, (Type, TypeAttribute)): + assert name.policy == qpol_policy + return name + + qpol_symbol = _symbol_lookup(qpol_policy, name) + + if qpol_symbol.isalias(qpol_policy) and not deref: + raise TypeError("{0} is an alias.".format(qpol_symbol.name(qpol_policy))) + + if qpol_symbol.isattr(qpol_policy): + return TypeAttribute(qpol_policy, qpol_symbol) + else: + return Type(qpol_policy, qpol_symbol) + + +class BaseType(symbol.PolicySymbol): + + """Type/attribute base class.""" + + @property + def ispermissive(self): + raise NotImplementedError + + def expand(self): + """Generator that expands this attribute into its member types.""" + raise NotImplementedError + + def attributes(self): + """Generator that yields all attributes for this type.""" + raise NotImplementedError + + def aliases(self): + """Generator that yields all aliases for this type.""" + raise NotImplementedError + + +class Type(BaseType): + + """A type.""" + + @property + def ispermissive(self): + """(T/F) the type is permissive.""" + return self.qpol_symbol.ispermissive(self.policy) + + def expand(self): + """Generator that expands this into its member types.""" + yield self + + def attributes(self): + """Generator that yields all attributes for this type.""" + for attr in self.qpol_symbol.attr_iter(self.policy): + yield attribute_factory(self.policy, attr) + + def aliases(self): + """Generator that yields all aliases for this type.""" + for alias in self.qpol_symbol.alias_iter(self.policy): + yield alias + + def statement(self): + attrs = list(self.attributes()) + aliases = list(self.aliases()) + stmt = "type {0}".format(self) + if aliases: + if len(aliases) > 1: + stmt += " alias {{ {0} }}".format(' '.join(aliases)) + else: + stmt += " alias {0}".format(aliases[0]) + for attr in attrs: + stmt += ", {0}".format(attr) + stmt += ";" + return stmt + + +class TypeAttribute(BaseType): + + """An attribute.""" + + def __contains__(self, other): + for type_ in self.expand(): + if other == type_: + return True + + return False + + def expand(self): + """Generator that expands this attribute into its member types.""" + for type_ in self.qpol_symbol.type_iter(self.policy): + yield type_factory(self.policy, type_) + + def attributes(self): + """Generator that yields all attributes for this type.""" + raise TypeError("{0} is an attribute, thus does not have attributes.".format(self)) + + def aliases(self): + """Generator that yields all aliases for this type.""" + raise TypeError("{0} is an attribute, thus does not have aliases.".format(self)) + + @property + def ispermissive(self): + """(T/F) the type is permissive.""" + raise TypeError("{0} is an attribute, thus cannot be permissive.".format(self)) + + def statement(self): + return "attribute {0};".format(self) diff --git a/lib/python2.7/site-packages/setoolsgui/setools/policyrep/user.py b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/user.py new file mode 100644 index 0000000..94f81bc --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/policyrep/user.py @@ -0,0 +1,86 @@ +# Copyright 2014, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +from . import exception +from . import qpol +from . import role +from . import mls +from . import symbol + + +def user_factory(qpol_policy, name): + """Factory function for creating User objects.""" + + if isinstance(name, User): + assert name.policy == qpol_policy + return name + elif isinstance(name, qpol.qpol_user_t): + return User(qpol_policy, name) + + try: + return User(qpol_policy, qpol.qpol_user_t(qpol_policy, str(name))) + except ValueError: + raise exception.InvalidUser("{0} is not a valid user".format(name)) + + +class User(symbol.PolicySymbol): + + """A user.""" + + @property + def roles(self): + """The user's set of roles.""" + + roleset = set() + + for role_ in self.qpol_symbol.role_iter(self.policy): + item = role.role_factory(self.policy, role_) + + # object_r is implicitly added to all roles by the compiler. + # technically it is incorrect to skip it, but policy writers + # and analysts don't expect to see it in results, and it + # will confuse, especially for role set equality user queries. + if item != "object_r": + roleset.add(item) + + return roleset + + @property + def mls_level(self): + """The user's default MLS level.""" + return mls.level_factory(self.policy, self.qpol_symbol.dfltlevel(self.policy)) + + @property + def mls_range(self): + """The user's MLS range.""" + return mls.range_factory(self.policy, self.qpol_symbol.range(self.policy)) + + def statement(self): + roles = list(str(r) for r in self.roles) + stmt = "user {0} roles ".format(self) + if len(roles) > 1: + stmt += "{{ {0} }}".format(' '.join(roles)) + else: + stmt += roles[0] + + try: + stmt += " level {0.mls_level} range {0.mls_range};".format(self) + except exception.MLSDisabled: + stmt += ";" + + return stmt diff --git a/lib/python2.7/site-packages/setoolsgui/setools/portconquery.py b/lib/python2.7/site-packages/setoolsgui/setools/portconquery.py new file mode 100644 index 0000000..798a828 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/portconquery.py @@ -0,0 +1,146 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +from socket import IPPROTO_TCP, IPPROTO_UDP + +from . import contextquery +from .policyrep.netcontext import port_range + + +class PortconQuery(contextquery.ContextQuery): + + """ + Port context query. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + protocol The protocol to match (socket.IPPROTO_TCP for + TCP or socket.IPPROTO_UDP for UDP) + + ports A 2-tuple of the port range to match. (Set both to + the same value for a single port) + ports_subset If true, the criteria will match if it is a subset + of the portcon's range. + ports_overlap If true, the criteria will match if it overlaps + any of the portcon's range. + ports_superset If true, the criteria will match if it is a superset + of the portcon's range. + ports_proper If true, use proper superset/subset operations. + No effect if not using set operations. + + user The criteria to match the context's user. + user_regex If true, regular expression matching + will be used on the user. + + role The criteria to match the context's role. + role_regex If true, regular expression matching + will be used on the role. + + type_ The criteria to match the context's type. + type_regex If true, regular expression matching + will be used on the type. + + range_ The criteria to match the context's range. + range_subset If true, the criteria will match if it is a subset + of the context's range. + range_overlap If true, the criteria will match if it overlaps + any of the context's range. + range_superset If true, the criteria will match if it is a superset + of the context's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + _protocol = None + _ports = None + ports_subset = False + ports_overlap = False + ports_superset = False + ports_proper = False + + @property + def ports(self): + return self._ports + + @ports.setter + def ports(self, value): + pending_ports = port_range(*value) + + if all(pending_ports): + if pending_ports.low < 1 or pending_ports.high < 1: + raise ValueError("Port numbers must be positive: {0.low}-{0.high}". + format(pending_ports)) + + if pending_ports.low > pending_ports.high: + raise ValueError( + "The low port must be smaller than the high port: {0.low}-{0.high}". + format(pending_ports)) + + self._ports = pending_ports + else: + self._ports = None + + @property + def protocol(self): + return self._protocol + + @protocol.setter + def protocol(self, value): + if value: + if not (value == IPPROTO_TCP or value == IPPROTO_UDP): + raise ValueError( + "The protocol must be {0} for TCP or {1} for UDP.". + format(IPPROTO_TCP, IPPROTO_UDP)) + + self._protocol = value + else: + self._protocol = None + + def results(self): + """Generator which yields all matching portcons.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ports: {0.ports}, overlap: {0.ports_overlap}, " + "subset: {0.ports_subset}, superset: {0.ports_superset}, " + "proper: {0.ports_proper}".format(self)) + self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) + self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) + self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for portcon in self.policy.portcons(): + + if self.ports and not self._match_range( + portcon.ports, + self.ports, + self.ports_subset, + self.ports_overlap, + self.ports_superset, + self.ports_proper): + continue + + if self.protocol and self.protocol != portcon.protocol: + continue + + if not self._match_context(portcon.context): + continue + + yield portcon diff --git a/lib/python2.7/site-packages/setoolsgui/setools/query.py b/lib/python2.7/site-packages/setoolsgui/setools/query.py new file mode 100644 index 0000000..358a095 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/query.py @@ -0,0 +1,192 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + + +class PolicyQuery(object): + + """Base class for SELinux policy queries.""" + + def __init__(self, policy, **kwargs): + self.log = logging.getLogger(self.__class__.__name__) + + self.policy = policy + + # keys are sorted in reverse order so regex settings + # are set before the criteria, e.g. name_regex + # is set before name. This ensures correct behavior + # since the criteria descriptors are sensitve to + # regex settings. + for name in sorted(kwargs.keys(), reverse=True): + attr = getattr(self, name, None) # None is not callable + if callable(attr): + raise ValueError("Keyword parameter {0} conflicts with a callable.".format(name)) + + setattr(self, name, kwargs[name]) + + @staticmethod + def _match_regex(obj, criteria, regex): + """ + Match the object with optional regular expression. + + Parameters: + obj The object to match. + criteria The criteria to match. + regex If regular expression matching should be used. + """ + + if regex: + return bool(criteria.search(str(obj))) + else: + return obj == criteria + + @staticmethod + def _match_set(obj, criteria, equal): + """ + Match the object (a set) with optional set equality. + + Parameters: + obj The object to match. (a set) + criteria The criteria to match. (a set) + equal If set equality should be used. Otherwise + any set intersection will match. + """ + + if equal: + return obj == criteria + else: + return bool(obj.intersection(criteria)) + + @staticmethod + def _match_in_set(obj, criteria, regex): + """ + Match if the criteria is in the list, with optional + regular expression matching. + + Parameters: + obj The object to match. + criteria The criteria to match. + regex If regular expression matching should be used. + """ + + if regex: + return [m for m in obj if criteria.search(str(m))] + else: + return criteria in obj + + @staticmethod + def _match_indirect_regex(obj, criteria, indirect, regex): + """ + Match the object with optional regular expression and indirection. + + Parameters: + obj The object to match. + criteria The criteria to match. + regex If regular expression matching should be used. + indirect If object indirection should be used, e.g. + expanding an attribute. + """ + + if indirect: + return PolicyQuery._match_in_set((obj.expand()), criteria, regex) + else: + return PolicyQuery._match_regex(obj, criteria, regex) + + @staticmethod + def _match_regex_or_set(obj, criteria, equal, regex): + """ + Match the object (a set) with either set comparisons + (equality or intersection) or by regex matching of the + set members. Regular expression matching will override + the set equality option. + + Parameters: + obj The object to match. (a set) + criteria The criteria to match. + equal If set equality should be used. Otherwise + any set intersection will match. Ignored + if regular expression matching is used. + regex If regular expression matching should be used. + """ + + if regex: + return [m for m in obj if criteria.search(str(m))] + else: + return PolicyQuery._match_set(obj, set(criteria), equal) + + @staticmethod + def _match_range(obj, criteria, subset, overlap, superset, proper): + """ + Match ranges of objects. + + obj An object with attributes named "low" and "high", representing the range. + criteria An object with attributes named "low" and "high", representing the criteria. + subset If true, the criteria will match if it is a subset obj's range. + overlap If true, the criteria will match if it overlaps any of the obj's range. + superset If true, the criteria will match if it is a superset of the obj's range. + proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + if overlap: + return ((obj.low <= criteria.low <= obj.high) or ( + obj.low <= criteria.high <= obj.high) or ( + criteria.low <= obj.low and obj.high <= criteria.high)) + elif subset: + if proper: + return ((obj.low < criteria.low and criteria.high <= obj.high) or ( + obj.low <= criteria.low and criteria.high < obj.high)) + else: + return obj.low <= criteria.low and criteria.high <= obj.high + elif superset: + if proper: + return ((criteria.low < obj.low and obj.high <= criteria.high) or ( + criteria.low <= obj.low and obj.high < criteria.high)) + else: + return (criteria.low <= obj.low and obj.high <= criteria.high) + else: + return criteria.low == obj.low and obj.high == criteria.high + + @staticmethod + def _match_level(obj, criteria, dom, domby, incomp): + """ + Match the an MLS level. + + obj The level to match. + criteria The criteria to match. (a level) + dom If true, the criteria will match if it dominates obj. + domby If true, the criteria will match if it is dominated by obj. + incomp If true, the criteria will match if it is incomparable to obj. + """ + + if dom: + return (criteria >= obj) + elif domby: + return (criteria <= obj) + elif incomp: + return (criteria ^ obj) + else: + return (criteria == obj) + + def results(self): + """ + Generator which returns the matches for the query. This method + should be overridden by subclasses. + """ + raise NotImplementedError diff --git a/lib/python2.7/site-packages/setoolsgui/setools/rbacrulequery.py b/lib/python2.7/site-packages/setoolsgui/setools/rbacrulequery.py new file mode 100644 index 0000000..240b921 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/rbacrulequery.py @@ -0,0 +1,147 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import mixins, query +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, RuletypeDescriptor +from .policyrep.exception import InvalidType, RuleUseError + + +class RBACRuleQuery(mixins.MatchObjClass, query.PolicyQuery): + + """ + Query the RBAC rules. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The list of rule type(s) to match. + source The name of the source role/attribute to match. + source_indirect If true, members of an attribute will be + matched rather than the attribute itself. + source_regex If true, regular expression matching will + be used on the source role/attribute. + Obeys the source_indirect option. + target The name of the target role/attribute to match. + target_indirect If true, members of an attribute will be + matched rather than the attribute itself. + target_regex If true, regular expression matching will + be used on the target role/attribute. + Obeys target_indirect option. + tclass The object class(es) to match. + tclass_regex If true, use a regular expression for + matching the rule's object class. + default The name of the default role to match. + default_regex If true, regular expression matching will + be used on the default role. + """ + + ruletype = RuletypeDescriptor("validate_rbac_ruletype") + source = CriteriaDescriptor("source_regex", "lookup_role") + source_regex = False + source_indirect = True + _target = None + target_regex = False + target_indirect = True + tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") + tclass_regex = False + default = CriteriaDescriptor("default_regex", "lookup_role") + default_regex = False + + @property + def target(self): + return self._target + + @target.setter + def target(self, value): + if not value: + self._target = None + elif self.target_regex: + self._target = re.compile(value) + else: + try: + self._target = self.policy.lookup_type_or_attr(value) + except InvalidType: + self._target = self.policy.lookup_role(value) + + def results(self): + """Generator which yields all matching RBAC rules.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " + "regex: {0.source_regex}".format(self)) + self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " + "regex: {0.target_regex}".format(self)) + self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) + self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) + + for rule in self.policy.rbacrules(): + # + # Matching on rule type + # + if self.ruletype: + if rule.ruletype not in self.ruletype: + continue + + # + # Matching on source role + # + if self.source and not self._match_indirect_regex( + rule.source, + self.source, + self.source_indirect, + self.source_regex): + continue + + # + # Matching on target type (role_transition)/role(allow) + # + if self.target and not self._match_indirect_regex( + rule.target, + self.target, + self.target_indirect, + self.target_regex): + continue + + # + # Matching on object class + # + try: + if not self._match_object_class(rule): + continue + except RuleUseError: + continue + + # + # Matching on default role + # + if self.default: + try: + if not self._match_regex( + rule.default, + self.default, + self.default_regex): + continue + except RuleUseError: + continue + + # if we get here, we have matched all available criteria + yield rule diff --git a/lib/python2.7/site-packages/setoolsgui/setools/rolequery.py b/lib/python2.7/site-packages/setoolsgui/setools/rolequery.py new file mode 100644 index 0000000..e95dfa6 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/rolequery.py @@ -0,0 +1,77 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery +from .descriptors import CriteriaSetDescriptor + + +class RoleQuery(compquery.ComponentQuery): + + """ + Query SELinux policy roles. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The role name to match. + name_regex If true, regular expression matching + will be used on the role names. + types The type to match. + types_equal If true, only roles with type sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + types_regex If true, regular expression matching + will be used on the type names instead + of set logic. + """ + + types = CriteriaSetDescriptor("types_regex", "lookup_type") + types_equal = False + types_regex = False + + def results(self): + """Generator which yields all matching roles.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " + "eq: {0.types_equal}".format(self)) + + for r in self.policy.roles(): + if r == "object_r": + # all types are implicitly added to object_r by the compiler. + # technically it is incorrect to skip it, but policy writers + # and analysts don't expect to see it in results, and it + # will confuse, especially for set equality type queries. + continue + + if not self._match_name(r): + continue + + if self.types and not self._match_regex_or_set( + set(r.types()), + self.types, + self.types_equal, + self.types_regex): + continue + + yield r diff --git a/lib/python2.7/site-packages/setoolsgui/setools/sensitivityquery.py b/lib/python2.7/site-packages/setoolsgui/setools/sensitivityquery.py new file mode 100644 index 0000000..a102836 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/sensitivityquery.py @@ -0,0 +1,74 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging + +from . import compquery +from . import mixins +from .descriptors import CriteriaDescriptor + + +class SensitivityQuery(mixins.MatchAlias, compquery.ComponentQuery): + + """ + Query MLS Sensitivities + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The name of the category to match. + name_regex If true, regular expression matching will + be used for matching the name. + alias The alias name to match. + alias_regex If true, regular expression matching + will be used on the alias names. + sens The criteria to match the sensitivity by dominance. + sens_dom If true, the criteria will match if it dominates + the sensitivity. + sens_domby If true, the criteria will match if it is dominated + by the sensitivity. + """ + + sens = CriteriaDescriptor(lookup_function="lookup_sensitivity") + sens_dom = False + sens_domby = False + + def results(self): + """Generator which yields all matching sensitivities.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self)) + self.log.debug("Sens: {0.sens!r}, dom: {0.sens_dom}, domby: {0.sens_domby}".format(self)) + + for s in self.policy.sensitivities(): + if not self._match_name(s): + continue + + if not self._match_alias(s): + continue + + if self.sens and not self._match_level( + s, + self.sens, + self.sens_dom, + self.sens_domby, + False): + continue + + yield s diff --git a/lib/python2.7/site-packages/setoolsgui/setools/terulequery.py b/lib/python2.7/site-packages/setoolsgui/setools/terulequery.py new file mode 100644 index 0000000..7f3eccf --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/terulequery.py @@ -0,0 +1,178 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import mixins, query +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, RuletypeDescriptor +from .policyrep.exception import RuleUseError, RuleNotConditional + + +class TERuleQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery): + + """ + Query the Type Enforcement rules. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The list of rule type(s) to match. + source The name of the source type/attribute to match. + source_indirect If true, members of an attribute will be + matched rather than the attribute itself. + Default is true. + source_regex If true, regular expression matching will + be used on the source type/attribute. + Obeys the source_indirect option. + Default is false. + target The name of the target type/attribute to match. + target_indirect If true, members of an attribute will be + matched rather than the attribute itself. + Default is true. + target_regex If true, regular expression matching will + be used on the target type/attribute. + Obeys target_indirect option. + Default is false. + tclass The object class(es) to match. + tclass_regex If true, use a regular expression for + matching the rule's object class. + Default is false. + perms The set of permission(s) to match. + perms_equal If true, the permission set of the rule + must exactly match the permissions + criteria. If false, any set intersection + will match. + Default is false. + perms_regex If true, regular expression matching will be used + on the permission names instead of set logic. + default The name of the default type to match. + default_regex If true, regular expression matching will be + used on the default type. + Default is false. + boolean The set of boolean(s) to match. + boolean_regex If true, regular expression matching will be + used on the booleans. + Default is false. + boolean_equal If true, the booleans in the conditional + expression of the rule must exactly match the + criteria. If false, any set intersection + will match. Default is false. + """ + + ruletype = RuletypeDescriptor("validate_te_ruletype") + source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") + source_regex = False + source_indirect = True + target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") + target_regex = False + target_indirect = True + default = CriteriaDescriptor("default_regex", "lookup_type") + default_regex = False + boolean = CriteriaSetDescriptor("boolean_regex", "lookup_boolean") + boolean_regex = False + boolean_equal = False + + def results(self): + """Generator which yields all matching TE rules.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " + "regex: {0.source_regex}".format(self)) + self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " + "regex: {0.target_regex}".format(self)) + self.log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) + self.log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}". + format(self)) + self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) + self.log.debug("Boolean: {0.boolean!r}, eq: {0.boolean_equal}, " + "regex: {0.boolean_regex}".format(self)) + + for rule in self.policy.terules(): + # + # Matching on rule type + # + if self.ruletype: + if rule.ruletype not in self.ruletype: + continue + + # + # Matching on source type + # + if self.source and not self._match_indirect_regex( + rule.source, + self.source, + self.source_indirect, + self.source_regex): + continue + + # + # Matching on target type + # + if self.target and not self._match_indirect_regex( + rule.target, + self.target, + self.target_indirect, + self.target_regex): + continue + + # + # Matching on object class + # + if not self._match_object_class(rule): + continue + + # + # Matching on permission set + # + try: + if not self._match_perms(rule): + continue + except RuleUseError: + continue + + # + # Matching on default type + # + if self.default: + try: + if not self._match_regex( + rule.default, + self.default, + self.default_regex): + continue + except RuleUseError: + continue + + # + # Match on Boolean in conditional expression + # + if self.boolean: + try: + if not self._match_regex_or_set( + rule.conditional.booleans, + self.boolean, + self.boolean_equal, + self.boolean_regex): + continue + except RuleNotConditional: + continue + + # if we get here, we have matched all available criteria + yield rule diff --git a/lib/python2.7/site-packages/setoolsgui/setools/typeattrquery.py b/lib/python2.7/site-packages/setoolsgui/setools/typeattrquery.py new file mode 100644 index 0000000..a91026c --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/typeattrquery.py @@ -0,0 +1,70 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery +from .descriptors import CriteriaSetDescriptor + + +class TypeAttributeQuery(compquery.ComponentQuery): + + """ + Query SELinux policy type attributes. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The type name to match. + name_regex If true, regular expression matching + will be used on the type names. + types The type to match. + types_equal If true, only attributes with type sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + types_regex If true, regular expression matching + will be used on the type names instead + of set logic. + """ + + types = CriteriaSetDescriptor("types_regex", "lookup_type") + types_equal = False + types_regex = False + + def results(self): + """Generator which yields all matching types.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " + "eq: {0.types_equal}".format(self)) + + for attr in self.policy.typeattributes(): + if not self._match_name(attr): + continue + + if self.types and not self._match_regex_or_set( + set(attr.expand()), + self.types, + self.types_equal, + self.types_regex): + continue + + yield attr diff --git a/lib/python2.7/site-packages/setoolsgui/setools/typequery.py b/lib/python2.7/site-packages/setoolsgui/setools/typequery.py new file mode 100644 index 0000000..6634f76 --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/typequery.py @@ -0,0 +1,96 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery +from . import mixins +from .descriptors import CriteriaSetDescriptor + + +class TypeQuery(mixins.MatchAlias, compquery.ComponentQuery): + + """ + Query SELinux policy types. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The type name to match. + name_regex If true, regular expression matching + will be used on the type names. + alias The alias name to match. + alias_regex If true, regular expression matching + will be used on the alias names. + attrs The attribute to match. + attrs_equal If true, only types with attribute sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + attrs_regex If true, regular expression matching + will be used on the attribute names instead + of set logic. + permissive The permissive state to match. If this + is None, the state is not matched. + """ + + attrs = CriteriaSetDescriptor("attrs_regex", "lookup_typeattr") + attrs_regex = False + attrs_equal = False + _permissive = None + + @property + def permissive(self): + return self._permissive + + @permissive.setter + def permissive(self, value): + if value is None: + self._permissive = None + else: + self._permissive = bool(value) + + def results(self): + """Generator which yields all matching types.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self)) + self.log.debug("Attrs: {0.attrs!r}, regex: {0.attrs_regex}, " + "eq: {0.attrs_equal}".format(self)) + self.log.debug("Permissive: {0.permissive}".format(self)) + + for t in self.policy.types(): + if not self._match_name(t): + continue + + if not self._match_alias(t): + continue + + if self.attrs and not self._match_regex_or_set( + set(t.attributes()), + self.attrs, + self.attrs_equal, + self.attrs_regex): + continue + + if self.permissive is not None and t.ispermissive != self.permissive: + continue + + yield t diff --git a/lib/python2.7/site-packages/setoolsgui/setools/userquery.py b/lib/python2.7/site-packages/setoolsgui/setools/userquery.py new file mode 100644 index 0000000..00910cf --- /dev/null +++ b/lib/python2.7/site-packages/setoolsgui/setools/userquery.py @@ -0,0 +1,116 @@ +# Copyright 2014-2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# <http://www.gnu.org/licenses/>. +# +import logging +import re + +from . import compquery +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor + + +class UserQuery(compquery.ComponentQuery): + + """ + Query SELinux policy users. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The user name to match. + name_regex If true, regular expression matching + will be used on the user names. + roles The attribute to match. + roles_equal If true, only types with role sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + roles_regex If true, regular expression matching + will be used on the role names instead + of set logic. + level The criteria to match the user's default level. + level_dom If true, the criteria will match if it dominates + the user's default level. + level_domby If true, the criteria will match if it is dominated + by the user's default level. + level_incomp If true, the criteria will match if it is incomparable + to the user's default level. + range_ The criteria to match the user's range. + range_subset If true, the criteria will match if it is a subset + of the user's range. + range_overlap If true, the criteria will match if it overlaps + any of the user's range. + range_superset If true, the criteria will match if it is a superset + of the user's range. + range_proper If true, use proper superset/subset operations. + No effect if not using set operations. + """ + + level = CriteriaDescriptor(lookup_function="lookup_level") + level_dom = False + level_domby = False + level_incomp = False + range_ = CriteriaDescriptor(lookup_function="lookup_range") + range_overlap = False + range_subset = False + range_superset = False + range_proper = False + roles = CriteriaSetDescriptor("roles_regex", "lookup_role") + roles_equal = False + roles_regex = False + + def results(self): + """Generator which yields all matching users.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Name: {0.name!r}, regex: {0.name_regex}".format(self)) + self.log.debug("Roles: {0.roles!r}, regex: {0.roles_regex}, " + "eq: {0.roles_equal}".format(self)) + self.log.debug("Level: {0.level!r}, dom: {0.level_dom}, domby: {0.level_domby}, " + "incomp: {0.level_incomp}".format(self)) + self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " + "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) + + for user in self.policy.users(): + if not self._match_name(user): + continue + + if self.roles and not self._match_regex_or_set( + user.roles, + self.roles, + self.roles_equal, + self.roles_regex): + continue + + if self.level and not self._match_level( + user.mls_level, + self.level, + self.level_dom, + self.level_domby, + self.level_incomp): + continue + + if self.range_ and not self._match_range( + user.mls_range, + self.range_, + self.range_subset, + self.range_overlap, + self.range_superset, + self.range_proper): + continue + + yield user |