diff --git a/seinfo b/seinfo
index 77aa105..ac8ea32 100755
--- a/seinfo
+++ b/seinfo
@@ -97,6 +97,13 @@ try:
q = setools.objclassquery.ObjClassQuery(p)
components.append(("Classes", q))
+ if args.constraintquery or args.all:
+ if isinstance(args.constraintquery, str):
+ q = setools.constraintquery.ConstraintQuery(p, tclass=args.constraintquery)
+ else:
+ q = setools.constraintquery.ConstraintQuery(p)
+ components.append(("Constraints", q))
+
if args.fsusequery or args.all:
if isinstance(args.fsusequery, str):
q = setools.fsusequery.FSUseQuery(p, fs=args.fsusequery)
diff --git a/setools/__init__.py b/setools/__init__.py
index 3e12e09..79dd9d6 100644
--- a/setools/__init__.py
+++ b/setools/__init__.py
@@ -43,6 +43,9 @@ from . import mlsrulequery
from . import rbacrulequery
from . import terulequery
+# Constraint queries
+from . import constraintquery
+
# In-policy Context Queries
from . import fsusequery
from . import genfsconquery
diff --git a/setools/constraintquery.py b/setools/constraintquery.py
new file mode 100644
index 0000000..c94aaed
--- /dev/null
+++ b/setools/constraintquery.py
@@ -0,0 +1,78 @@
+# 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
+# .
+#
+import re
+
+from . import mixins
+from .query import PolicyQuery
+
+
+class ConstraintQuery(mixins.MatchObjClass, mixins.MatchPermission, PolicyQuery):
+
+ """Query constraint rules (constraint/mlsconstraint)."""
+
+ def __init__(self, policy,
+ ruletype=[],
+ tclass="", tclass_regex=False,
+ perms=set(), perms_equal=False):
+
+ """
+ Parameter:
+ policy The policy to query.
+ ruletype The 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.
+ """
+
+ self.policy = policy
+
+ self.set_ruletype(ruletype)
+ self.set_tclass(tclass, regex=tclass_regex)
+ self.set_perms(perms, equal=perms_equal)
+
+ def results(self):
+ """Generator which yields all matching constraints rules."""
+
+ for c in self.policy.constraints():
+ if self.ruletype:
+ if c.ruletype not in self.ruletype:
+ continue
+
+ if self.tclass and not self._match_object_class(c.tclass):
+ continue
+
+ if self.perms and not self._match_perms(c.perms):
+ continue
+
+ yield c
+
+ def set_ruletype(self, ruletype):
+ """
+ Set the rule types for the rule query.
+
+ Parameter:
+ ruletype The rule types to match.
+ """
+
+ self.ruletype = ruletype
diff --git a/setools/policyrep/__init__.py b/setools/policyrep/__init__.py
index 1e33b7a..e8dc474 100644
--- a/setools/policyrep/__init__.py
+++ b/setools/policyrep/__init__.py
@@ -143,7 +143,7 @@ class SELinuxPolicy(object):
@property
def constraint_count(self):
"""The number of standard constraints."""
- return sum(1 for _ in self.constraints())
+ return sum(1 for c in self.constraints() if c.ruletype == "constrain")
@property
def dontaudit_count(self):
@@ -173,12 +173,12 @@ class SELinuxPolicy(object):
@property
def mlsconstraint_count(self):
"""The number of MLS constraints."""
- return sum(1 for _ in self.mlsconstraints())
+ 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 _ in self.mlsvalidatetrans())
+ return sum(1 for v in self.validatetrans() if v.ruletype == "mlsvalidatetrans")
@property
def netifcon_count(self):
@@ -263,12 +263,11 @@ class SELinuxPolicy(object):
@property
def validatetrans_count(self):
"""The number of validatetrans."""
- return sum(1 for _ in self.validatetrans())
+ return sum(1 for v in self.validatetrans() if v.ruletype == "validatetrans")
#
# Policy components lookup functions
#
-
def lookup_attribute(self, name):
"""Look up an attribute by name."""
return typeattr.attribute_factory(self.policy, name)
@@ -446,40 +445,16 @@ class SELinuxPolicy(object):
#
def constraints(self):
- """Generator which yields all constraints."""
+ """Generator which yields all constraints (regular and MLS)."""
for constraint_ in self.policy.constraint_iter():
- try:
- yield constraint.constraint_factory(self.policy, constraint_)
- except TypeError:
- pass
-
- def mlsconstraints(self):
- """Generator which yields all MLS constraints."""
-
- for constraint_ in self.policy.constraint_iter():
- try:
- yield constraint.mlsconstraint_factory(self.policy, constraint_)
- except TypeError:
- pass
-
- def mlsvalidatetrans(self):
- """Generator which yields all mlsvalidatetrans."""
-
- for validatetrans in self.policy.validatetrans_iter():
- try:
- yield constraint.mlsvalidatetrans_factory(self.policy, validatetrans)
- except TypeError:
- pass
+ yield constraint.constraint_factory(self.policy, constraint_)
def validatetrans(self):
- """Generator which yields all validatetrans."""
+ """Generator which yields all validatetrans (regular and MLS)."""
for validatetrans in self.policy.validatetrans_iter():
- try:
- yield constraint.validatetrans_factory(self.policy, validatetrans)
- except TypeError:
- pass
+ yield constraint.validatetrans_factory(self.policy, validatetrans)
#
# In-policy Labeling statement generators
diff --git a/setools/policyrep/constraint.py b/setools/policyrep/constraint.py
index d2fead7..ede8781 100644
--- a/setools/policyrep/constraint.py
+++ b/setools/policyrep/constraint.py
@@ -35,52 +35,30 @@ def _is_mls(policy, symbol):
def constraint_factory(policy, symbol):
- """Factory function for creating regular constraint objects."""
+ """Factory function for creating constraint objects."""
try:
if _is_mls(policy, symbol):
- raise TypeError("Symbol is not a constrain.")
+ return Constraint(policy, symbol, "mlsconstrain")
+ else:
+ return Constraint(policy, symbol, "constrain")
+
except AttributeError:
raise TypeError("Constraints cannot be looked-up.")
- return Constraint(policy, symbol, "constrain")
-
-
-def mlsconstraint_factory(policy, symbol):
- """Factory function for creating MLS constraint objects."""
-
- try:
- if not _is_mls(policy, symbol):
- raise TypeError("Symbol is not a mlsconstrain.")
- except AttributeError:
- raise TypeError("mlsconstrain cannot be looked-up.")
-
- return Constraint(policy, symbol, "mlsconstrain")
-
def validatetrans_factory(policy, symbol):
- """Factory function for creating regular validatetrans objects."""
+ """Factory function for creating validatetrans objects."""
try:
if _is_mls(policy, symbol):
- raise TypeError("Symbol is not a validatetrans.")
+ return Validatetrans(policy, symbol, "mlsvalidatetrans")
+ else:
+ return Validatetrans(policy, symbol, "validatetrans")
+
except AttributeError:
raise TypeError("validatetrans cannot be looked-up.")
- return Validatetrans(policy, symbol, "validatetrans")
-
-
-def mlsvalidatetrans_factory(policy, symbol):
- """Factory function for creating MLS validatetrans objects."""
-
- try:
- if not _is_mls(policy, symbol):
- raise TypeError("Symbol is not a mlsvalidatetrans.")
- except AttributeError:
- raise TypeError("mlsvalidatetrans cannot be looked-up.")
-
- return Validatetrans(policy, symbol, "mlsvalidatetrans")
-
class BaseConstraint(symbol.PolicySymbol):
diff --git a/tests/constraintquery.conf b/tests/constraintquery.conf
new file mode 100644
index 0000000..5187ee3
--- /dev/null
+++ b/tests/constraintquery.conf
@@ -0,0 +1,176 @@
+class test1
+class test10
+class test11a
+class test11b
+class test11c
+class test12a
+class test12b
+class test12c
+class test20a
+class test20b
+class test20c
+class test21a
+class test21b
+class test21c
+
+sid kernel
+sid security
+
+common test
+{
+ low_w
+ med_w
+ hi_w
+ low_r
+ med_r
+ hi_r
+}
+
+
+class test1
+inherits test
+
+class test10
+inherits test
+
+class test11a
+inherits test
+
+class test11b
+inherits test
+
+class test11c
+inherits test
+
+class test12a
+inherits test
+
+class test12b
+inherits test
+
+class test12c
+inherits test
+
+class test20a
+{
+ test20ap
+ test20bp
+}
+
+class test20b
+{
+ test20ap
+ test20bp
+}
+
+class test20c
+{
+ test20ap
+ test20bp
+}
+
+class test21a
+{
+ test21ap
+ test21bp
+}
+
+class test21b
+{
+ test21ap
+ test21bp
+}
+
+class test21c
+{
+ test21ap
+ test21bp
+}
+
+
+sensitivity low_s;
+sensitivity medium_s alias med;
+sensitivity high_s;
+
+dominance { low_s med high_s }
+
+category here;
+category there;
+category elsewhere alias lost;
+
+level low_s:here.there;
+level med:here, elsewhere;
+level high_s:here.lost;
+
+# test 1:
+# ruletype: mlsconstrain
+# tclass: unset
+# perms: unset
+mlsconstrain test1 hi_r ((l1 dom l2) or (t1 == mls_exempt));
+
+attribute mls_exempt;
+
+type system;
+role system;
+role system types system;
+
+user system roles system level med range low_s - high_s:here.lost;
+
+# test 10:
+# ruletype: unset
+# tclass: test10
+# perms: unset
+constrain test10 hi_w (u1 == u2);
+
+# test 11:
+# ruletype: unset
+# tclass: test11a, test11b
+# perms: unset
+constrain test11a hi_w (u1 == u2);
+constrain test11b hi_w (u1 == u2);
+constrain test11c hi_w (u1 == u2);
+
+# test 12:
+# ruletype: unset
+# tclass: intoflow12(a|c), regex
+# perms: unset
+constrain test12a hi_w (u1 == u2);
+constrain test12b hi_w (u1 == u2);
+constrain test12c hi_w (u1 == u2);
+
+# test 20:
+# ruletype: unset
+# tclass: unset
+# perms: test20ap, test20bp
+constrain test20a test20ap (u1 == u2);
+constrain test20b test20bp (u1 == u2);
+
+# test 21:
+# ruletype: unset
+# tclass: unset
+# perms: test21ap, test21bp, equal
+constrain test21a test21ap (u1 == u2);
+constrain test21b test21bp (u1 == u2);
+constrain test21c { test21bp test21ap } (u1 == u2);
+
+#isids
+sid kernel system:system:system:medium_s:here
+sid security system:system:system:high_s:lost
+
+#fs_use
+fs_use_trans devpts system:object_r:system:low_s;
+fs_use_xattr ext3 system:object_r:system:low_s;
+fs_use_task pipefs system:object_r:system:low_s;
+
+#genfscon
+genfscon proc / system:object_r:system:med
+genfscon proc /sys system:object_r:system:low_s
+genfscon selinuxfs / system:object_r:system:high_s:here.there
+
+portcon tcp 80 system:object_r:system:low_s
+
+netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s
+
+nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here
+nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here
+
diff --git a/tests/constraintquery.py b/tests/constraintquery.py
new file mode 100644
index 0000000..9ed73ed
--- /dev/null
+++ b/tests/constraintquery.py
@@ -0,0 +1,78 @@
+# 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 General Public License as published by
+# the Free Software Foundation, either version 2 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with SETools. If not, see .
+#
+import unittest
+
+from setools import SELinuxPolicy
+from setools.constraintquery import ConstraintQuery
+
+
+class ConstraintQueryTest(unittest.TestCase):
+
+ def setUp(self):
+ self.p = SELinuxPolicy("tests/constraintquery.conf")
+
+ def test_000_unset(self):
+ """Constraint query with no criteria."""
+ allconstraint = sorted(c.tclass for c in self.p.constraints())
+
+ q = ConstraintQuery(self.p)
+ qconstraint = sorted(c.tclass for c in q.results())
+
+ self.assertListEqual(allconstraint, qconstraint)
+
+ def test_001_ruletype(self):
+ """Constraint query with rule type match."""
+ q = ConstraintQuery(self.p, ruletype=["mlsconstrain"])
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test1"], constraint)
+
+ def test_010_class_exact(self):
+ """Constraint query with exact object class match."""
+ q = ConstraintQuery(self.p, tclass="test10")
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test10"], constraint)
+
+ def test_011_class_list(self):
+ """Constraint query with object class list match."""
+ q = ConstraintQuery(self.p, tclass=["test11a", "test11b"])
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test11a", "test11b"], constraint)
+
+ def test_012_class_list(self):
+ """Constraint query with object class list match."""
+ q = ConstraintQuery(self.p, tclass="test12(a|c)", tclass_regex=True)
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test12a", "test12c"], constraint)
+
+ def test_020_perms_any(self):
+ """Constraint query with permission set intersection match."""
+ q = ConstraintQuery(self.p, perms=["test20ap", "test20bp"])
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test20a", "test20b"], constraint)
+
+ def test_020_perms_equal(self):
+ """Constraint query with permission set equality match."""
+ q = ConstraintQuery(self.p, perms=["test21ap", "test21bp"], perms_equal=True)
+
+ constraint = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["test21c"], constraint)