diff --git a/sediff b/sediff index 66e4b8c..cf5e04c 100755 --- a/sediff +++ b/sediff @@ -225,6 +225,36 @@ try: print() + if all_differences or args.attribute: + if diff.added_type_attributes or diff.removed_type_attributes or \ + diff.modified_type_attributes or args.attribute: + print("Type Attributes ({0} Added, {1} Removed, {2} Modified)".format( + len(diff.added_type_attributes), len(diff.removed_type_attributes), + len(diff.modified_type_attributes))) + if diff.added_type_attributes and not args.stats: + print(" Added Type Attributes: {0}".format(len(diff.added_type_attributes))) + for a in sorted(diff.added_type_attributes): + print(" + {0}".format(a)) + if diff.removed_type_attributes and not args.stats: + print(" Removed Type Attributes: {0}".format(len(diff.removed_type_attributes))) + for a in sorted(diff.removed_type_attributes): + print(" - {0}".format(a)) + if diff.modified_type_attributes and not args.stats: + print(" Modified Type Attributes: {0}".format(len(diff.modified_type_attributes))) + for name, mod in sorted(diff.modified_type_attributes.items()): + change = [] + if mod.added_types: + change.append("{0} Added types".format(len(mod.added_types))) + if mod.removed_types: + change.append("{0} Removed types".format(len(mod.removed_types))) + + print(" * {0} ({1})".format(name, ", ".join(change))) + for t in sorted(mod.added_types): + print(" + {0}".format(t)) + for t in sorted(mod.removed_types): + print(" - {0}".format(t)) + print() + if all_differences or args.user: if diff.added_users or diff.removed_users or diff.modified_users or args.user: print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users), diff --git a/setools/diff/__init__.py b/setools/diff/__init__.py index cbf2d10..3171f9e 100644 --- a/setools/diff/__init__.py +++ b/setools/diff/__init__.py @@ -22,6 +22,7 @@ from .objclass import ObjClassDifference from .rbacrules import RBACRulesDifference from .roles import RolesDifference from .terules import TERulesDifference +from .typeattr import TypeAttributesDifference from .types import TypesDifference from .users import UsersDifference @@ -34,6 +35,7 @@ class PolicyDifference(CommonDifference, RBACRulesDifference, RolesDifference, TERulesDifference, + TypeAttributesDifference, TypesDifference, UsersDifference): diff --git a/setools/diff/typeattr.py b/setools/diff/typeattr.py new file mode 100644 index 0000000..8c51832 --- /dev/null +++ b/setools/diff/typeattr.py @@ -0,0 +1,71 @@ +# 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 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 +# . +# +from collections import namedtuple + +from .descriptors import DiffResultDescriptor +from .difference import Difference, SymbolWrapper + + +modified_typeattr_record = namedtuple("modified_typeattr", ["added_types", + "removed_types", + "matched_types"]) + + +class TypeAttributesDifference(Difference): + + """Determine the difference in type attributes between two policies.""" + + added_type_attributes = DiffResultDescriptor("diff_type_attributes") + removed_type_attributes = DiffResultDescriptor("diff_type_attributes") + modified_type_attributes = DiffResultDescriptor("diff_type_attributes") + + def diff_type_attributes(self): + """Generate the difference in type attributes between the policies.""" + + self.log.info( + "Generating type attribute differences from {0.left_policy} to {0.right_policy}". + format(self)) + + self.added_type_attributes, self.removed_type_attributes, matched_attributes = \ + self._set_diff( + (SymbolWrapper(r) for r in self.left_policy.typeattributes()), + (SymbolWrapper(r) for r in self.right_policy.typeattributes())) + + self.modified_type_attributes = dict() + + for left_attribute, right_attribute in matched_attributes: + # Criteria for modified attributes + # 1. change to type set + added_types, removed_types, matched_types = self._set_diff( + (SymbolWrapper(t) for t in left_attribute.expand()), + (SymbolWrapper(t) for t in right_attribute.expand())) + + if added_types or removed_types: + self.modified_type_attributes[left_attribute] = modified_typeattr_record( + added_types, removed_types, matched_types) + + # + # Internal functions + # + def _reset_diff(self): + """Reset diff results on policy changes.""" + self.log.debug("Resetting type attribute differences") + self.added_type_attributes = None + self.removed_type_attributes = None + self.modified_type_attributes = None diff --git a/tests/diff.py b/tests/diff.py index bbd2bd2..69a65b0 100644 --- a/tests/diff.py +++ b/tests/diff.py @@ -892,6 +892,24 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase): self.assertEqual("s3:c1.c4", self.diff.modified_users["modified_change_range"].added_range) + # + # Type attributes + # + def test_added_type_attribute(self): + """Diff: added type attribute.""" + self.assertSetEqual(set(["added_attr"]), self.diff.added_type_attributes) + + def test_removed_type_attribute(self): + """Diff: removed type attribute.""" + self.assertSetEqual(set(["removed_attr"]), self.diff.removed_type_attributes) + + def test_modified_type_attribute(self): + """Diff: modified type attribute.""" + self.assertSetEqual(set(["modified_add_attr"]), + self.diff.modified_type_attributes["an_attr"].added_types) + self.assertSetEqual(set(["modified_remove_attr"]), + self.diff.modified_type_attributes["an_attr"].removed_types) + class PolicyDifferenceTestNoDiff(unittest.TestCase): @@ -1080,3 +1098,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase): def test_modified_users(self): """NoDiff: no modified user rules.""" self.assertFalse(self.diff.modified_users) + + def test_added_type_attributes(self): + """NoDiff: no added type attribute rules.""" + self.assertFalse(self.diff.added_type_attributes) + + def test_removed_type_attributes(self): + """NoDiff: no removed type attribute rules.""" + self.assertFalse(self.diff.removed_type_attributes) + + def test_modified_type_attributes(self): + """NoDiff: no modified type attribute rules.""" + self.assertFalse(self.diff.modified_type_attributes) diff --git a/tests/diff_left.conf b/tests/diff_left.conf index 08ef4d4..d4b9693 100644 --- a/tests/diff_left.conf +++ b/tests/diff_left.conf @@ -130,6 +130,7 @@ mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute an_attr; +attribute removed_attr; type system; role system; diff --git a/tests/diff_right.conf b/tests/diff_right.conf index cb9aee5..dae33ca 100644 --- a/tests/diff_right.conf +++ b/tests/diff_right.conf @@ -131,6 +131,7 @@ mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute an_attr; +attribute added_attr; type system; role system;