summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/sepolgen/refpolicy.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/sepolgen/refpolicy.py')
-rw-r--r--lib/python2.7/site-packages/sepolgen/refpolicy.py916
1 files changed, 916 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/sepolgen/refpolicy.py b/lib/python2.7/site-packages/sepolgen/refpolicy.py
new file mode 100644
index 0000000..31b40d8
--- /dev/null
+++ b/lib/python2.7/site-packages/sepolgen/refpolicy.py
@@ -0,0 +1,916 @@
+# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+#
+# Copyright (C) 2006 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program 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; version 2 only
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+import string
+import selinux
+
+# OVERVIEW
+#
+# This file contains objects and functions used to represent the reference
+# policy (including the headers, M4 macros, and policy language statements).
+#
+# This representation is very different from the semantic representation
+# used in libsepol. Instead, it is a more typical abstract representation
+# used by the first stage of compilers. It is basically a parse tree.
+#
+# This choice is intentional as it allows us to handle the unprocessed
+# M4 statements - including the $1 style arguments - and to more easily generate
+# the data structures that we need for policy generation.
+#
+
+# Constans for referring to fields
+SRC_TYPE = 0
+TGT_TYPE = 1
+OBJ_CLASS = 2
+PERMS = 3
+ROLE = 4
+DEST_TYPE = 5
+
+# String represenations of the above constants
+field_to_str = ["source", "target", "object", "permission", "role", "destination" ]
+str_to_field = { "source" : SRC_TYPE, "target" : TGT_TYPE, "object" : OBJ_CLASS,
+ "permission" : PERMS, "role" : ROLE, "destination" : DEST_TYPE }
+
+# Base Classes
+
+class PolicyBase:
+ def __init__(self, parent=None):
+ self.parent = None
+ self.comment = None
+
+class Node(PolicyBase):
+ """Base class objects produced from parsing the reference policy.
+
+ The Node class is used as the base class for any non-leaf
+ object produced by parsing the reference policy. This object
+ should contain a reference to its parent (or None for a top-level
+ object) and 0 or more children.
+
+ The general idea here is to have a very simple tree structure. Children
+ are not separated out by type. Instead the tree structure represents
+ fairly closely the real structure of the policy statements.
+
+ The object should be iterable - by default over all children but
+ subclasses are free to provide additional iterators over a subset
+ of their childre (see Interface for example).
+ """
+
+ def __init__(self, parent=None):
+ PolicyBase.__init__(self, parent)
+ self.children = []
+
+ def __iter__(self):
+ return iter(self.children)
+
+ # Not all of the iterators will return something on all Nodes, but
+ # they won't explode either. Putting them here is just easier.
+
+ # Top level nodes
+
+ def nodes(self):
+ return filter(lambda x: isinstance(x, Node), walktree(self))
+
+ def modules(self):
+ return filter(lambda x: isinstance(x, Module), walktree(self))
+
+ def interfaces(self):
+ return filter(lambda x: isinstance(x, Interface), walktree(self))
+
+ def templates(self):
+ return filter(lambda x: isinstance(x, Template), walktree(self))
+
+ def support_macros(self):
+ return filter(lambda x: isinstance(x, SupportMacros), walktree(self))
+
+ # Common policy statements
+
+ def module_declarations(self):
+ return filter(lambda x: isinstance(x, ModuleDeclaration), walktree(self))
+
+ def interface_calls(self):
+ return filter(lambda x: isinstance(x, InterfaceCall), walktree(self))
+
+ def avrules(self):
+ return filter(lambda x: isinstance(x, AVRule), walktree(self))
+
+ def typerules(self):
+ return filter(lambda x: isinstance(x, TypeRule), walktree(self))
+
+ def typeattributes(self):
+ """Iterate over all of the TypeAttribute children of this Interface."""
+ return filter(lambda x: isinstance(x, TypeAttribute), walktree(self))
+
+ def roleattributes(self):
+ """Iterate over all of the RoleAttribute children of this Interface."""
+ return filter(lambda x: isinstance(x, RoleAttribute), walktree(self))
+
+ def requires(self):
+ return filter(lambda x: isinstance(x, Require), walktree(self))
+
+ def roles(self):
+ return filter(lambda x: isinstance(x, Role), walktree(self))
+
+ def role_allows(self):
+ return filter(lambda x: isinstance(x, RoleAllow), walktree(self))
+
+ def role_types(self):
+ return filter(lambda x: isinstance(x, RoleType), walktree(self))
+
+ def __str__(self):
+ if self.comment:
+ return str(self.comment) + "\n" + self.to_string()
+ else:
+ return self.to_string()
+
+ def __repr__(self):
+ return "<%s(%s)>" % (self.__class__.__name__, self.to_string())
+
+ def to_string(self):
+ return ""
+
+
+class Leaf(PolicyBase):
+ def __init__(self, parent=None):
+ PolicyBase.__init__(self, parent)
+
+ def __str__(self):
+ if self.comment:
+ return str(self.comment) + "\n" + self.to_string()
+ else:
+ return self.to_string()
+
+ def __repr__(self):
+ return "<%s(%s)>" % (self.__class__.__name__, self.to_string())
+
+ def to_string(self):
+ return ""
+
+
+
+# Utility functions
+
+def walktree(node, depthfirst=True, showdepth=False, type=None):
+ """Iterate over a Node and its Children.
+
+ The walktree function iterates over a tree containing Nodes and
+ leaf objects. The iteration can perform a depth first or a breadth
+ first traversal of the tree (controlled by the depthfirst
+ paramater. The passed in node will be returned.
+
+ This function will only work correctly for trees - arbitrary graphs
+ will likely cause infinite looping.
+ """
+ # We control depth first / versus breadth first by
+ # how we pop items off of the node stack.
+ if depthfirst:
+ index = -1
+ else:
+ index = 0
+
+ stack = [(node, 0)]
+ while len(stack) > 0:
+ cur, depth = stack.pop(index)
+ if showdepth:
+ yield cur, depth
+ else:
+ yield cur
+
+ # If the node is not a Node instance it must
+ # be a leaf - so no need to add it to the stack
+ if isinstance(cur, Node):
+ items = []
+ i = len(cur.children) - 1
+ while i >= 0:
+ if type is None or isinstance(cur.children[i], type):
+ items.append((cur.children[i], depth + 1))
+ i -= 1
+
+ stack.extend(items)
+
+def walknode(node, type=None):
+ """Iterate over the direct children of a Node.
+
+ The walktree function iterates over the children of a Node.
+ Unlike walktree it does note return the passed in node or
+ the children of any Node objects (that is, it does not go
+ beyond the current level in the tree).
+ """
+ for x in node:
+ if type is None or isinstance(x, type):
+ yield x
+
+
+def list_to_space_str(s, cont=('{', '}')):
+ """Convert a set (or any sequence type) into a string representation
+ formatted to match SELinux space separated list conventions.
+
+ For example the list ['read', 'write'] would be converted into:
+ '{ read write }'
+ """
+ l = len(s)
+ str = ""
+ if l < 1:
+ raise ValueError("cannot convert 0 len set to string")
+ str = " ".join(s)
+ if l == 1:
+ return str
+ else:
+ return cont[0] + " " + str + " " + cont[1]
+
+def list_to_comma_str(s):
+ l = len(s)
+ if l < 1:
+ raise ValueError("cannot conver 0 len set to comma string")
+
+ return ", ".join(s)
+
+# Basic SELinux types
+
+class IdSet(set):
+ def __init__(self, list=None):
+ if list:
+ set.__init__(self, list)
+ else:
+ set.__init__(self)
+ self.compliment = False
+
+ def to_space_str(self):
+ return list_to_space_str(sorted(self))
+
+ def to_comma_str(self):
+ return list_to_comma_str(sorted(self))
+
+class SecurityContext(Leaf):
+ """An SELinux security context with optional MCS / MLS fields."""
+ def __init__(self, context=None, parent=None):
+ """Create a SecurityContext object, optionally from a string.
+
+ Parameters:
+ [context] - string representing a security context. Same format
+ as a string passed to the from_string method.
+ """
+ Leaf.__init__(self, parent)
+ self.user = ""
+ self.role = ""
+ self.type = ""
+ self.level = None
+ if context is not None:
+ self.from_string(context)
+
+ def from_string(self, context):
+ """Parse a string representing a context into a SecurityContext.
+
+ The string should be in the standard format - e.g.,
+ 'user:role:type:level'.
+
+ Raises ValueError if the string is not parsable as a security context.
+ """
+ fields = context.split(":")
+ if len(fields) < 3:
+ raise ValueError("context string [%s] not in a valid format" % context)
+
+ self.user = fields[0]
+ self.role = fields[1]
+ self.type = fields[2]
+ if len(fields) > 3:
+ # FUTURE - normalize level fields to allow more comparisons to succeed.
+ self.level = ':'.join(fields[3:])
+ else:
+ self.level = None
+
+ def __eq__(self, other):
+ """Compare two SecurityContext objects - all fields must be exactly the
+ the same for the comparison to work. It is possible for the level fields
+ to be semantically the same yet syntactically different - in this case
+ this function will return false.
+ """
+ return self.user == other.user and \
+ self.role == other.role and \
+ self.type == other.type and \
+ self.level == other.level
+
+ def to_string(self, default_level=None):
+ """Return a string representing this security context.
+
+ By default, the string will contiain a MCS / MLS level
+ potentially from the default which is passed in if none was
+ set.
+
+ Arguments:
+ default_level - the default level to use if self.level is an
+ empty string.
+
+ Returns:
+ A string represening the security context in the form
+ 'user:role:type:level'.
+ """
+ fields = [self.user, self.role, self.type]
+ if self.level is None:
+ if default_level is None:
+ if selinux.is_selinux_mls_enabled() == 1:
+ fields.append("s0")
+ else:
+ fields.append(default_level)
+ else:
+ fields.append(self.level)
+ return ":".join(fields)
+
+class ObjectClass(Leaf):
+ """SELinux object class and permissions.
+
+ This class is a basic representation of an SELinux object
+ class - it does not represent separate common permissions -
+ just the union of the common and class specific permissions.
+ It is meant to be convenient for policy generation.
+ """
+ def __init__(self, name="", parent=None):
+ Leaf.__init__(self, parent)
+ self.name = name
+ self.perms = IdSet()
+
+# Basic statements
+
+class TypeAttribute(Leaf):
+ """SElinux typeattribute statement.
+
+ This class represents a typeattribute statement.
+ """
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.type = ""
+ self.attributes = IdSet()
+
+ def to_string(self):
+ return "typeattribute %s %s;" % (self.type, self.attributes.to_comma_str())
+
+class RoleAttribute(Leaf):
+ """SElinux roleattribute statement.
+
+ This class represents a roleattribute statement.
+ """
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.role = ""
+ self.roleattributes = IdSet()
+
+ def to_string(self):
+ return "roleattribute %s %s;" % (self.role, self.roleattributes.to_comma_str())
+
+
+class Role(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.role = ""
+ self.types = IdSet()
+
+ def to_string(self):
+ s = ""
+ for t in self.types:
+ s += "role %s types %s;\n" % (self.role, t)
+ return s
+
+class Type(Leaf):
+ def __init__(self, name="", parent=None):
+ Leaf.__init__(self, parent)
+ self.name = name
+ self.attributes = IdSet()
+ self.aliases = IdSet()
+
+ def to_string(self):
+ s = "type %s" % self.name
+ if len(self.aliases) > 0:
+ s = s + "alias %s" % self.aliases.to_space_str()
+ if len(self.attributes) > 0:
+ s = s + ", %s" % self.attributes.to_comma_str()
+ return s + ";"
+
+class TypeAlias(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.type = ""
+ self.aliases = IdSet()
+
+ def to_string(self):
+ return "typealias %s alias %s;" % (self.type, self.aliases.to_space_str())
+
+class Attribute(Leaf):
+ def __init__(self, name="", parent=None):
+ Leaf.__init__(self, parent)
+ self.name = name
+
+ def to_string(self):
+ return "attribute %s;" % self.name
+
+class Attribute_Role(Leaf):
+ def __init__(self, name="", parent=None):
+ Leaf.__init__(self, parent)
+ self.name = name
+
+ def to_string(self):
+ return "attribute_role %s;" % self.name
+
+
+# Classes representing rules
+
+class AVRule(Leaf):
+ """SELinux access vector (AV) rule.
+
+ The AVRule class represents all varieties of AV rules including
+ allow, dontaudit, and auditallow (indicated by the flags self.ALLOW,
+ self.DONTAUDIT, and self.AUDITALLOW respectively).
+
+ The source and target types, object classes, and perms are all represented
+ by sets containing strings. Sets are used to make it simple to add
+ strings repeatedly while avoiding duplicates.
+
+ No checking is done to make certain that the symbols are valid or
+ consistent (e.g., perms that don't match the object classes). It is
+ even possible to put invalid types like '$1' into the rules to allow
+ storage of the reference policy interfaces.
+ """
+ ALLOW = 0
+ DONTAUDIT = 1
+ AUDITALLOW = 2
+ NEVERALLOW = 3
+
+ def __init__(self, av=None, parent=None):
+ Leaf.__init__(self, parent)
+ self.src_types = IdSet()
+ self.tgt_types = IdSet()
+ self.obj_classes = IdSet()
+ self.perms = IdSet()
+ self.rule_type = self.ALLOW
+ if av:
+ self.from_av(av)
+
+ def __rule_type_str(self):
+ if self.rule_type == self.ALLOW:
+ return "allow"
+ elif self.rule_type == self.DONTAUDIT:
+ return "dontaudit"
+ else:
+ return "auditallow"
+
+ def from_av(self, av):
+ """Add the access from an access vector to this allow
+ rule.
+ """
+ self.src_types.add(av.src_type)
+ if av.src_type == av.tgt_type:
+ self.tgt_types.add("self")
+ else:
+ self.tgt_types.add(av.tgt_type)
+ self.obj_classes.add(av.obj_class)
+ self.perms.update(av.perms)
+
+ def to_string(self):
+ """Return a string representation of the rule
+ that is a valid policy language representation (assuming
+ that the types, object class, etc. are valie).
+ """
+ return "%s %s %s:%s %s;" % (self.__rule_type_str(),
+ self.src_types.to_space_str(),
+ self.tgt_types.to_space_str(),
+ self.obj_classes.to_space_str(),
+ self.perms.to_space_str())
+class TypeRule(Leaf):
+ """SELinux type rules.
+
+ This class is very similar to the AVRule class, but is for representing
+ the type rules (type_trans, type_change, and type_member). The major
+ difference is the lack of perms and only and sing destination type.
+ """
+ TYPE_TRANSITION = 0
+ TYPE_CHANGE = 1
+ TYPE_MEMBER = 2
+
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.src_types = IdSet()
+ self.tgt_types = IdSet()
+ self.obj_classes = IdSet()
+ self.dest_type = ""
+ self.rule_type = self.TYPE_TRANSITION
+
+ def __rule_type_str(self):
+ if self.rule_type == self.TYPE_TRANSITION:
+ return "type_transition"
+ elif self.rule_type == self.TYPE_CHANGE:
+ return "type_change"
+ else:
+ return "type_member"
+
+ def to_string(self):
+ return "%s %s %s:%s %s;" % (self.__rule_type_str(),
+ self.src_types.to_space_str(),
+ self.tgt_types.to_space_str(),
+ self.obj_classes.to_space_str(),
+ self.dest_type)
+
+class RoleAllow(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.src_roles = IdSet()
+ self.tgt_roles = IdSet()
+
+ def to_string(self):
+ return "allow %s %s;" % (self.src_roles.to_comma_str(),
+ self.tgt_roles.to_comma_str())
+
+class RoleType(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.role = ""
+ self.types = IdSet()
+
+ def to_string(self):
+ s = ""
+ for t in self.types:
+ s += "role %s types %s;\n" % (self.role, t)
+ return s
+
+class ModuleDeclaration(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.name = ""
+ self.version = ""
+ self.refpolicy = False
+
+ def to_string(self):
+ if self.refpolicy:
+ return "policy_module(%s, %s)" % (self.name, self.version)
+ else:
+ return "module %s %s;" % (self.name, self.version)
+
+class Conditional(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+ self.cond_expr = []
+
+ def to_string(self):
+ return "[If %s]" % list_to_space_str(self.cond_expr, cont=("", ""))
+
+class Bool(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.name = ""
+ self.state = False
+
+ def to_string(self):
+ s = "bool %s " % self.name
+ if s.state:
+ return s + "true"
+ else:
+ return s + "false"
+
+class InitialSid(Leaf):
+ def __init(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.name = ""
+ self.context = None
+
+ def to_string(self):
+ return "sid %s %s" % (self.name, str(self.context))
+
+class GenfsCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.filesystem = ""
+ self.path = ""
+ self.context = None
+
+ def to_string(self):
+ return "genfscon %s %s %s" % (self.filesystem, self.path, str(self.context))
+
+class FilesystemUse(Leaf):
+ XATTR = 1
+ TRANS = 2
+ TASK = 3
+
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.type = self.XATTR
+ self.filesystem = ""
+ self.context = None
+
+ def to_string(self):
+ s = ""
+ if self.type == XATTR:
+ s = "fs_use_xattr "
+ elif self.type == TRANS:
+ s = "fs_use_trans "
+ elif self.type == TASK:
+ s = "fs_use_task "
+
+ return "%s %s %s;" % (s, self.filesystem, str(self.context))
+
+class PortCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.port_type = ""
+ self.port_number = ""
+ self.context = None
+
+ def to_string(self):
+ return "portcon %s %s %s" % (self.port_type, self.port_number, str(self.context))
+
+class NodeCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.start = ""
+ self.end = ""
+ self.context = None
+
+ def to_string(self):
+ return "nodecon %s %s %s" % (self.start, self.end, str(self.context))
+
+class NetifCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.interface = ""
+ self.interface_context = None
+ self.packet_context = None
+
+ def to_string(self):
+ return "netifcon %s %s %s" % (self.interface, str(self.interface_context),
+ str(self.packet_context))
+class PirqCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.pirq_number = ""
+ self.context = None
+
+ def to_string(self):
+ return "pirqcon %s %s" % (self.pirq_number, str(self.context))
+
+class IomemCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.device_mem = ""
+ self.context = None
+
+ def to_string(self):
+ return "iomemcon %s %s" % (self.device_mem, str(self.context))
+
+class IoportCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.ioport = ""
+ self.context = None
+
+ def to_string(self):
+ return "ioportcon %s %s" % (self.ioport, str(self.context))
+
+class PciDeviceCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.device = ""
+ self.context = None
+
+ def to_string(self):
+ return "pcidevicecon %s %s" % (self.device, str(self.context))
+
+class DeviceTreeCon(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.path = ""
+ self.context = None
+
+ def to_string(self):
+ return "devicetreecon %s %s" % (self.path, str(self.context))
+
+# Reference policy specific types
+
+def print_tree(head):
+ for node, depth in walktree(head, showdepth=True):
+ s = ""
+ for i in range(depth):
+ s = s + "\t"
+ print(s + str(node))
+
+
+class Headers(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+
+ def to_string(self):
+ return "[Headers]"
+
+
+class Module(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+
+ def to_string(self):
+ return ""
+
+class Interface(Node):
+ """A reference policy interface definition.
+
+ This class represents a reference policy interface definition.
+ """
+ def __init__(self, name="", parent=None):
+ Node.__init__(self, parent)
+ self.name = name
+
+ def to_string(self):
+ return "[Interface name: %s]" % self.name
+
+class TunablePolicy(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+ self.cond_expr = []
+
+ def to_string(self):
+ return "[Tunable Policy %s]" % list_to_space_str(self.cond_expr, cont=("", ""))
+
+class Template(Node):
+ def __init__(self, name="", parent=None):
+ Node.__init__(self, parent)
+ self.name = name
+
+ def to_string(self):
+ return "[Template name: %s]" % self.name
+
+class IfDef(Node):
+ def __init__(self, name="", parent=None):
+ Node.__init__(self, parent)
+ self.name = name
+
+ def to_string(self):
+ return "[Ifdef name: %s]" % self.name
+
+class InterfaceCall(Leaf):
+ def __init__(self, ifname="", parent=None):
+ Leaf.__init__(self, parent)
+ self.ifname = ifname
+ self.args = []
+ self.comments = []
+
+ def matches(self, other):
+ if self.ifname != other.ifname:
+ return False
+ if len(self.args) != len(other.args):
+ return False
+ for a,b in zip(self.args, other.args):
+ if a != b:
+ return False
+ return True
+
+ def to_string(self):
+ s = "%s(" % self.ifname
+ i = 0
+ for a in self.args:
+ if isinstance(a, list):
+ str = list_to_space_str(a)
+ else:
+ str = a
+
+ if i != 0:
+ s = s + ", %s" % str
+ else:
+ s = s + str
+ i += 1
+ return s + ")"
+
+class OptionalPolicy(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+
+ def to_string(self):
+ return "[Optional Policy]"
+
+class SupportMacros(Node):
+ def __init__(self, parent=None):
+ Node.__init__(self, parent)
+ self.map = None
+
+ def to_string(self):
+ return "[Support Macros]"
+
+ def __expand_perm(self, perm):
+ # Recursive expansion - the assumption is that these
+ # are ordered correctly so that no macro is used before
+ # it is defined
+ s = set()
+ if perm in self.map:
+ for p in self.by_name(perm):
+ s.update(self.__expand_perm(p))
+ else:
+ s.add(perm)
+ return s
+
+ def __gen_map(self):
+ self.map = {}
+ for x in self:
+ exp_perms = set()
+ for perm in x.perms:
+ exp_perms.update(self.__expand_perm(perm))
+ self.map[x.name] = exp_perms
+
+ def by_name(self, name):
+ if not self.map:
+ self.__gen_map()
+ return self.map[name]
+
+ def has_key(self, name):
+ if not self.map:
+ self.__gen_map()
+ return name in self.map
+
+class Require(Leaf):
+ def __init__(self, parent=None):
+ Leaf.__init__(self, parent)
+ self.types = IdSet()
+ self.obj_classes = { }
+ self.roles = IdSet()
+ self.data = IdSet()
+ self.users = IdSet()
+
+ def add_obj_class(self, obj_class, perms):
+ p = self.obj_classes.setdefault(obj_class, IdSet())
+ p.update(perms)
+
+
+ def to_string(self):
+ s = []
+ s.append("require {")
+ for type in self.types:
+ s.append("\ttype %s;" % type)
+ for obj_class, perms in self.obj_classes.items():
+ s.append("\tclass %s %s;" % (obj_class, perms.to_space_str()))
+ for role in self.roles:
+ s.append("\trole %s;" % role)
+ for bool in self.data:
+ s.append("\tbool %s;" % bool)
+ for user in self.users:
+ s.append("\tuser %s;" % user)
+ s.append("}")
+
+ # Handle empty requires
+ if len(s) == 2:
+ return ""
+
+ return "\n".join(s)
+
+
+class ObjPermSet:
+ def __init__(self, name):
+ self.name = name
+ self.perms = set()
+
+ def to_string(self):
+ return "define(`%s', `%s')" % (self.name, self.perms.to_space_str())
+
+class ClassMap:
+ def __init__(self, obj_class, perms):
+ self.obj_class = obj_class
+ self.perms = perms
+
+ def to_string(self):
+ return self.obj_class + ": " + self.perms
+
+class Comment:
+ def __init__(self, l=None):
+ if l:
+ self.lines = l
+ else:
+ self.lines = []
+
+ def to_string(self):
+ # If there are no lines, treat this as a spacer between
+ # policy statements and return a new line.
+ if len(self.lines) == 0:
+ return ""
+ else:
+ out = []
+ for line in self.lines:
+ out.append("#" + line)
+ return "\n".join(out)
+
+ def merge(self, other):
+ if len(other.lines):
+ for line in other.lines:
+ if line != "":
+ self.lines.append(line)
+
+ def __str__(self):
+ return self.to_string()
+
+