diff --git a/setools/__init__.py b/setools/__init__.py
index 5e936e8..a726dfb 100644
--- a/setools/__init__.py
+++ b/setools/__init__.py
@@ -51,6 +51,9 @@ from .terulequery import TERuleQuery
# Constraint queries
from .constraintquery import ConstraintQuery
+# Other queries
+from .defaultquery import DefaultQuery
+
# In-policy Context Queries
from .fsusequery import FSUseQuery
from .genfsconquery import GenfsconQuery
diff --git a/setools/defaultquery.py b/setools/defaultquery.py
new file mode 100644
index 0000000..dac93bc
--- /dev/null
+++ b/setools/defaultquery.py
@@ -0,0 +1,71 @@
+# 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
+# .
+#
+import logging
+import re
+
+from .query import PolicyQuery
+from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor
+from .mixins import MatchObjClass
+
+
+class DefaultQuery(MatchObjClass, PolicyQuery):
+
+ """
+ Query default_* statements.
+
+ Parameter:
+ policy The policy to query.
+
+ Keyword Parameters/Class attributes:
+ 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.
+ default The default to base new contexts (e.g. "source" or "target")
+ default_range The range to use on new context, default_range only
+ ("low", "high", "low_high")
+ """
+
+ ruletype = CriteriaSetDescriptor(lookup_function="validate_default_ruletype")
+ default = CriteriaDescriptor(lookup_function="validate_default_value")
+ default_range = CriteriaDescriptor(lookup_function="validate_default_range")
+
+ def results(self):
+ """Generator which yields all matching default_* statements."""
+ self.log.info("Generating results from {0.policy}".format(self))
+ self.log.debug("Ruletypes: {0.ruletype}".format(self))
+
+ for d in self.policy.defaults():
+ if self.ruletype and d.ruletype not in self.ruletype:
+ continue
+
+ if not self._match_object_class(d):
+ continue
+
+ if self.default and d.default != self.default:
+ continue
+
+ if self.default_range:
+ try:
+ if d.default_range != self.default_range:
+ continue
+ except AttributeError:
+ continue
+
+ yield d
diff --git a/tests/__init__.py b/tests/__init__.py
index 75bffe7..a7600da 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -19,6 +19,7 @@ from . import boolquery
from . import categoryquery
from . import constraintquery
from . import commonquery
+from . import defaultquery
from . import diff
from . import dta
from . import fsusequery
diff --git a/tests/defaultquery.conf b/tests/defaultquery.conf
new file mode 100644
index 0000000..772c167
--- /dev/null
+++ b/tests/defaultquery.conf
@@ -0,0 +1,125 @@
+class infoflow
+class infoflow2
+class infoflow3
+class infoflow4
+class infoflow5
+class infoflow6
+class infoflow7
+
+sid kernel
+sid security
+
+common infoflow
+{
+ low_w
+ med_w
+ hi_w
+ low_r
+ med_r
+ hi_r
+}
+
+class infoflow
+inherits infoflow
+
+class infoflow2
+inherits infoflow
+{
+ super_w
+ super_r
+}
+
+class infoflow3
+{
+ null
+}
+
+class infoflow4
+inherits infoflow
+
+class infoflow5
+inherits infoflow
+
+class infoflow6
+inherits infoflow
+
+class infoflow7
+inherits infoflow
+{
+ super_w
+ super_r
+ super_none
+ super_both
+ super_unmapped
+}
+
+########################################
+#
+# Default settings
+#
+
+default_user infoflow target;
+default_role { infoflow infoflow3 } source;
+default_type infoflow4 target;
+default_range infoflow5 target low;
+default_range infoflow7 target high;
+
+#########################################
+
+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 decl
+level low_s:here.there;
+level med:here, elsewhere;
+level high_s:here.lost;
+
+#some constraints
+mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt));
+
+attribute mls_exempt;
+
+type system;
+role system;
+role system types system;
+
+################################################################################
+# Type enforcement declarations and rules
+
+
+################################################################################
+
+#users
+user system roles system level med range low_s - high_s:here.lost;
+
+#normal constraints
+constrain infoflow hi_w (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/defaultquery.py b/tests/defaultquery.py
new file mode 100644
index 0000000..f19f5ea
--- /dev/null
+++ b/tests/defaultquery.py
@@ -0,0 +1,98 @@
+# Copyright 2016, 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, DefaultQuery
+from setools.policyrep.exception import InvalidDefaultType, InvalidClass, \
+ InvalidDefaultValue, InvalidDefaultRange
+
+
+class DefaultQueryTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.p = SELinuxPolicy("tests/defaultquery.conf")
+
+ def test_000_unset(self):
+ """Default query: no criteria."""
+ # query with no parameters gets all defaults
+ alldefaults = sorted(self.p.defaults())
+
+ q = DefaultQuery(self.p)
+ qdefaults = sorted(q.results())
+
+ self.assertListEqual(alldefaults, qdefaults)
+
+ def test_001_ruletype(self):
+ """Default query: ruletype criterion."""
+ q = DefaultQuery(self.p, ruletype=["default_user"])
+ defaults = list(q.results())
+ self.assertEqual(1, len(defaults))
+
+ d = defaults[0]
+ self.assertEqual("default_user", d.ruletype)
+ self.assertEqual("infoflow", d.tclass)
+ self.assertEqual("target", d.default)
+
+ def test_010_class_list(self):
+ """Default query: object class list match."""
+ q = DefaultQuery(self.p, tclass=["infoflow3", "infoflow4"])
+
+ defaults = sorted(d.tclass for d in q.results())
+ self.assertListEqual(["infoflow3", "infoflow4"], defaults)
+
+ def test_011_class_regex(self):
+ """Default query: object class regex match."""
+ q = DefaultQuery(self.p, tclass="infoflow(3|5)", tclass_regex=True)
+
+ defaults = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["infoflow3", "infoflow5"], defaults)
+
+ def test_020_default(self):
+ """Default query: default setting."""
+ q = DefaultQuery(self.p, default="source")
+
+ defaults = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["infoflow", "infoflow3"], defaults)
+
+ def test_030_default_range(self):
+ """Default query: default_range setting."""
+ q = DefaultQuery(self.p, default_range="high")
+
+ defaults = sorted(c.tclass for c in q.results())
+ self.assertListEqual(["infoflow7"], defaults)
+
+ def test_900_invalid_ruletype(self):
+ """Default query: invalid ruletype"""
+ with self.assertRaises(InvalidDefaultType):
+ q = DefaultQuery(self.p, ruletype=["INVALID"])
+
+ def test_901_invalid_class(self):
+ """Default query: invalid object class"""
+ with self.assertRaises(InvalidClass):
+ q = DefaultQuery(self.p, tclass=["INVALID"])
+
+ def test_902_invalid_default_value(self):
+ """Default query: invalid default value"""
+ with self.assertRaises(InvalidDefaultValue):
+ q = DefaultQuery(self.p, default="INVALID")
+
+ def test_903_invalid_default_range(self):
+ """Default query: invalid default range"""
+ with self.assertRaises(InvalidDefaultRange):
+ q = DefaultQuery(self.p, default_range="INVALID")