From c419b9c3f0846e86afdb60f70c12c08511037596 Mon Sep 17 00:00:00 2001
From: Chris PeBenito <cpebenito@tresys.com>
Date: Thu, 24 Jul 2014 09:37:30 -0400
Subject: [PATCH] Implement ObjClass and Common classes.

---
 libapol/policyrep/__init__.py | 17 ++++++++
 libapol/policyrep/objclass.py | 79 ++++++++++++++++++++++++++++++++++-
 2 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/libapol/policyrep/__init__.py b/libapol/policyrep/__init__.py
index 8b1b755..ae0e66f 100644
--- a/libapol/policyrep/__init__.py
+++ b/libapol/policyrep/__init__.py
@@ -79,6 +79,23 @@ class SELinuxPolicy(object):
     #
     # Policy components generators
     #
+
+    def classes(self):
+        """Generator which yields all object classes."""
+
+        qiter = self.policy.get_class_iter()
+        while not qiter.end():
+            yield objclass.ObjClass(self.policy, qpol.qpol_class_from_void(qiter.get_item()))
+            qiter.next()
+
+    def commons(self):
+        """Generator which yields all commons."""
+
+        qiter = self.policy.get_common_iter()
+        while not qiter.end():
+            yield objclass.Common(self.policy, qpol.qpol_common_from_void(qiter.get_item()))
+            qiter.next()
+
     def types(self):
         """Generator which yields all types."""
 
diff --git a/libapol/policyrep/objclass.py b/libapol/policyrep/objclass.py
index 0d8ed10..f9e2dab 100644
--- a/libapol/policyrep/objclass.py
+++ b/libapol/policyrep/objclass.py
@@ -23,10 +23,85 @@ import setools.qpol as qpol
 class Common(symbol.PolicySymbol):
 
     """A common permission set."""
+
+    def __contains__(self, other):
+        piter = self.qpol_symbol.get_perm_iter(self.policy)
+
+        while not piter.end():
+            if other == qpol.to_str(piter.get_item()):
+                return True
+
+            piter.next()
+
+        return False
+
+    @property
+    def perms(self):
+        """The list of the common's permissions."""
+
+        piter = self.qpol_symbol.get_perm_iter(self.policy)
+        p = []
+
+        while not piter.end():
+            p.append(qpol.to_str(piter.get_item()))
+            piter.next()
+
+        return p
+
+    def statement(self):
+        return "common {0}\n{{\n\t{1}\n}}".format(self, '\n\t'.join(self.perms))
+
+    @property
+    def value(self):
+        """
+        The value of the common.
+
+        This is a low-level policy detail exposed so that commons can
+        be sorted based on their policy declaration order instead of
+        by their name.  This has no other use.
+
+        Example usage: sorted(policy.commons(), key=lambda k: k.value)
+        """
+        return self.qpol_symbol.get_value(self.policy)
+
+
+class NoCommon(symbol.InvalidSymbol):
+
+    """
+    Exception when a class does not inherit a common permission set.
+    """
     pass
 
 
-class ObjClass(symbol.PolicySymbol):
+class ObjClass(Common):
 
     """An object class."""
-    pass
+
+    @property
+    def common(self):
+        """
+        The common that the object class inherits.
+
+        Exceptions:
+        NoCommon    The object class does not inherit a common.
+        """
+
+        try:
+            return Common(self.policy, self.qpol_symbol.get_common(self.policy))
+        except symbol.InvalidSymbol:
+            raise 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 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