diff --git a/libapol/__init__.py b/libapol/__init__.py index d84ff65..7235fd6 100644 --- a/libapol/__init__.py +++ b/libapol/__init__.py @@ -39,6 +39,9 @@ import terulequery import rbacrulequery import mlsrulequery +# In-policy Context Queries +import initsidquery + # Information Flow Analysis import infoflow import permmap diff --git a/libapol/contextquery.py b/libapol/contextquery.py new file mode 100644 index 0000000..237af30 --- /dev/null +++ b/libapol/contextquery.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 +# . +# +import re + +import query + + +class ContextQuery(query.PolicyQuery): + + """Abstract base class for SETools in-policy labeling/context queries.""" + + @staticmethod + def _match_context(context, + user, user_regex, user_recomp, + role, role_regex, role_recomp, + type_, type_regex, type_recomp, + range_): + """ + Match the context with optional regular expression. + + Parameters: + 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. + user_recomp The compiled user regular expression. + role The role to match in the context. + role_regex If true, regular expression matching + will be used on the role. + role_recomp The compiled role regular expression. + type_ The type to match in the context. + type_regex If true, regular expression matching + will be used on the type. + type_recomp The compiled type regular expression. + range_ The range to match in the context. + """ + + if user and not query.PolicyQuery._match_regex( + context.user, + user, + user_regex, + user_recomp): + return False + + if role and not query.PolicyQuery._match_regex( + context.role, + role, + role_regex, + role_recomp): + return False + + if type_ and not query.PolicyQuery._match_regex( + context.type_, + type_, + type_regex, + type_recomp): + return False + + if range_: + raise NotImplementedError( + "Context range queries are not yet implemented.") + + return True + + def set_user(self, user, **opts): + """ + Set the criteria for matching the context's user. + + Parameter: + user Name to match the context's user. + regex If true, regular expression matching will be used. + + Exceptions: + NameError Invalid keyword option. + """ + + self.user = str(user) + + for k in opts.keys(): + if k == "regex": + self.user_regex = opts[k] + else: + raise NameError("Invalid name option: {0}".format(k)) + + if self.user_regex: + self.user_cmp = re.compile(self.name) + else: + self.user_cmp = None + + def set_role(self, role, **opts): + """ + Set the criteria for matching the context's role. + + Parameter: + role Name to match the context's role. + regex If true, regular expression matching will be used. + + Exceptions: + NameError Invalid keyword option. + """ + + self.role = str(role) + + for k in opts.keys(): + if k == "regex": + self.role_regex = opts[k] + else: + raise NameError("Invalid name option: {0}".format(k)) + + if self.role_regex: + self.role_cmp = re.compile(self.name) + else: + self.role_cmp = None + + def set_type(self, type_, **opts): + """ + Set the criteria for matching the context's type. + + Parameter: + type_ Name to match the context's type. + regex If true, regular expression matching will be used. + + Exceptions: + NameError Invalid keyword option. + """ + + self.type_ = str(type_) + + for k in opts.keys(): + if k == "regex": + self.type_regex = opts[k] + else: + raise NameError("Invalid name option: {0}".format(k)) + + if self.type_regex: + self.type_cmp = re.compile(self.name) + else: + self.type_cmp = None + + def set_range(self, range_, **opts): + """ + Set the criteria for matching the context's range. + + Parameter: + range_ Range to match the context's range. + + Exceptions: + NameError Invalid keyword option. + """ + + self.range_ = range_ diff --git a/libapol/initsidquery.py b/libapol/initsidquery.py new file mode 100644 index 0000000..4b9ddf8 --- /dev/null +++ b/libapol/initsidquery.py @@ -0,0 +1,82 @@ +# 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 +# . +# +import compquery +import contextquery + + +class InitialSIDQuery(compquery.ComponentQuery, contextquery.ContextQuery): + + """Initial SID (context) query.""" + + def __init__(self, policy, + name="", name_regex=False, + user="", user_regex=False, + role="", role_regex=False, + type_="", type_regex=False, + range_=""): + """ + Parameters: + policy The policy to query. + + 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. + """ + + self.policy = policy + + self.set_name(name, regex=name_regex) + self.set_user(user, regex=user_regex) + self.set_role(role, regex=role_regex) + self.set_type(type_, regex=type_regex) + self.set_range(range_) + + def results(self): + """Generator which yields all matching initial SIDs.""" + + for i in self.policy.initialsids(): + if self.name and not self._match_regex( + i, + self.name, + self.name_regex, + self.name_cmp): + continue + + if not self._match_context( + i.context, + self.user, + self.user_regex, + self.user_cmp, + self.role, + self.role_regex, + self.role_cmp, + self.type_, + self.type_regex, + self.type_cmp, + self.range_): + continue + + yield i diff --git a/seinfo b/seinfo index b61dd85..d680223 100755 --- a/seinfo +++ b/seinfo @@ -144,3 +144,15 @@ if args.classquery: print(c.statement()) else: print(c) + +if args.initialsidquery: + if isinstance(args.initialsidquery, str): + q = libapol.initsidquery.InitialSIDQuery(p, args.initialsidquery) + else: + q = libapol.initsidquery.InitialSIDQuery(p) + + for i in sorted(q.results()): + if args.expand: + print(i.statement()) + else: + print(i)