Home | History | Annotate | Download | only in sepolgen
      1 # Authors: Karl MacMillan <kmacmillan (at] mentalrootkit.com>
      2 #
      3 # Copyright (C) 2006 Red Hat
      4 # see file 'COPYING' for use and warranty information
      5 #
      6 # This program is free software; you can redistribute it and/or
      7 # modify it under the terms of the GNU General Public License as
      8 # published by the Free Software Foundation; version 2 only
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License
     16 # along with this program; if not, write to the Free Software
     17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     18 #
     19 
     20 import string
     21 import selinux
     22 
     23 # OVERVIEW
     24 #
     25 # This file contains objects and functions used to represent the reference
     26 # policy (including the headers, M4 macros, and policy language statements).
     27 #
     28 # This representation is very different from the semantic representation
     29 # used in libsepol. Instead, it is a more typical abstract representation
     30 # used by the first stage of compilers. It is basically a parse tree.
     31 #
     32 # This choice is intentional as it allows us to handle the unprocessed
     33 # M4 statements - including the $1 style arguments - and to more easily generate
     34 # the data structures that we need for policy generation.
     35 #
     36 
     37 # Constans for referring to fields
     38 SRC_TYPE  = 0
     39 TGT_TYPE  = 1
     40 OBJ_CLASS = 2
     41 PERMS     = 3
     42 ROLE      = 4
     43 DEST_TYPE = 5
     44 
     45 # String represenations of the above constants
     46 field_to_str = ["source", "target", "object", "permission", "role", "destination" ]
     47 str_to_field = { "source" : SRC_TYPE, "target" : TGT_TYPE, "object" : OBJ_CLASS,
     48                 "permission" : PERMS, "role" : ROLE, "destination" : DEST_TYPE }
     49 
     50 # Base Classes
     51 
     52 class PolicyBase:
     53     def __init__(self, parent=None):
     54         self.parent = None
     55         self.comment = None
     56 
     57 class Node(PolicyBase):
     58     """Base class objects produced from parsing the reference policy.
     59 
     60     The Node class is used as the base class for any non-leaf
     61     object produced by parsing the reference policy. This object
     62     should contain a reference to its parent (or None for a top-level
     63     object) and 0 or more children.
     64 
     65     The general idea here is to have a very simple tree structure. Children
     66     are not separated out by type. Instead the tree structure represents
     67     fairly closely the real structure of the policy statements.
     68 
     69     The object should be iterable - by default over all children but
     70     subclasses are free to provide additional iterators over a subset
     71     of their childre (see Interface for example).
     72     """
     73 
     74     def __init__(self, parent=None):
     75         PolicyBase.__init__(self, parent)
     76         self.children = []
     77 
     78     def __iter__(self):
     79         return iter(self.children)
     80 
     81     # Not all of the iterators will return something on all Nodes, but
     82     # they won't explode either. Putting them here is just easier.
     83 
     84     # Top level nodes
     85 
     86     def nodes(self):
     87         return filter(lambda x: isinstance(x, Node), walktree(self))
     88 
     89     def modules(self):
     90         return filter(lambda x: isinstance(x, Module), walktree(self))
     91 
     92     def interfaces(self):
     93         return filter(lambda x: isinstance(x, Interface), walktree(self))
     94 
     95     def templates(self):
     96         return filter(lambda x: isinstance(x, Template), walktree(self))
     97 
     98     def support_macros(self):
     99         return filter(lambda x: isinstance(x, SupportMacros), walktree(self))
    100 
    101     # Common policy statements
    102 
    103     def module_declarations(self):
    104         return filter(lambda x: isinstance(x, ModuleDeclaration), walktree(self))
    105 
    106     def interface_calls(self):
    107         return filter(lambda x: isinstance(x, InterfaceCall), walktree(self))
    108 
    109     def avrules(self):
    110         return filter(lambda x: isinstance(x, AVRule), walktree(self))
    111 
    112     def avextrules(self):
    113         return filter(lambda x: isinstance(x, AVExtRule), walktree(self))
    114 
    115     def typerules(self):
    116         return filter(lambda x: isinstance(x, TypeRule), walktree(self))
    117 
    118     def typebounds(self):
    119         return filter(lambda x: isinstance(x, TypeBound), walktree(self))
    120 
    121     def typeattributes(self):
    122         """Iterate over all of the TypeAttribute children of this Interface."""
    123         return filter(lambda x: isinstance(x, TypeAttribute), walktree(self))
    124 
    125     def roleattributes(self):
    126         """Iterate over all of the RoleAttribute children of this Interface."""
    127         return filter(lambda x: isinstance(x, RoleAttribute), walktree(self))
    128 
    129     def requires(self):
    130         return filter(lambda x: isinstance(x, Require), walktree(self))
    131 
    132     def roles(self):
    133         return filter(lambda x: isinstance(x, Role), walktree(self))
    134 
    135     def role_allows(self):
    136         return filter(lambda x: isinstance(x, RoleAllow), walktree(self))
    137 
    138     def role_types(self):
    139         return filter(lambda x: isinstance(x, RoleType), walktree(self))
    140 
    141     def __str__(self):
    142         if self.comment:
    143             return str(self.comment) + "\n" + self.to_string()
    144         else:
    145             return self.to_string()
    146 
    147     def __repr__(self):
    148         return "<%s(%s)>" % (self.__class__.__name__, self.to_string())
    149 
    150     def to_string(self):
    151         return ""
    152 
    153 
    154 class Leaf(PolicyBase):
    155     def __init__(self, parent=None):
    156         PolicyBase.__init__(self, parent)
    157 
    158     def __str__(self):
    159         if self.comment:
    160             return str(self.comment) + "\n" + self.to_string()
    161         else:
    162             return self.to_string()
    163 
    164     def __repr__(self):
    165         return "<%s(%s)>" % (self.__class__.__name__, self.to_string())
    166 
    167     def to_string(self):
    168         return ""
    169 
    170 
    171 
    172 # Utility functions
    173 
    174 def walktree(node, depthfirst=True, showdepth=False, type=None):
    175     """Iterate over a Node and its Children.
    176 
    177     The walktree function iterates over a tree containing Nodes and
    178     leaf objects. The iteration can perform a depth first or a breadth
    179     first traversal of the tree (controlled by the depthfirst
    180     paramater. The passed in node will be returned.
    181 
    182     This function will only work correctly for trees - arbitrary graphs
    183     will likely cause infinite looping.
    184     """
    185     # We control depth first / versus breadth first by
    186     # how we pop items off of the node stack.
    187     if depthfirst:
    188         index = -1
    189     else:
    190         index = 0
    191 
    192     stack = [(node, 0)]
    193     while len(stack) > 0:
    194         cur, depth = stack.pop(index)
    195         if showdepth:
    196             yield cur, depth
    197         else:
    198             yield cur
    199 
    200         # If the node is not a Node instance it must
    201         # be a leaf - so no need to add it to the stack
    202         if isinstance(cur, Node):
    203             items = []
    204             i = len(cur.children) - 1
    205             while i >= 0:
    206                 if type is None or isinstance(cur.children[i], type):
    207                     items.append((cur.children[i], depth + 1))
    208                 i -= 1
    209 
    210             stack.extend(items)
    211 
    212 def walknode(node, type=None):
    213     """Iterate over the direct children of a Node.
    214 
    215     The walktree function iterates over the children of a Node.
    216     Unlike walktree it does note return the passed in node or
    217     the children of any Node objects (that is, it does not go
    218     beyond the current level in the tree).
    219     """
    220     for x in node:
    221         if type is None or isinstance(x, type):
    222             yield x
    223 
    224 
    225 def list_to_space_str(s, cont=('{', '}')):
    226     """Convert a set (or any sequence type) into a string representation
    227     formatted to match SELinux space separated list conventions.
    228 
    229     For example the list ['read', 'write'] would be converted into:
    230     '{ read write }'
    231     """
    232     l = len(s)
    233     str = ""
    234     if l < 1:
    235         raise ValueError("cannot convert 0 len set to string")
    236     str = " ".join(s)
    237     if l == 1:
    238         return str
    239     else:
    240         return cont[0] + " " + str + " " + cont[1]
    241 
    242 def list_to_comma_str(s):
    243     l = len(s)
    244     if l < 1:
    245         raise ValueError("cannot conver 0 len set to comma string")
    246 
    247     return ", ".join(s)
    248 
    249 # Basic SELinux types
    250 
    251 class IdSet(set):
    252     def __init__(self, list=None):
    253         if list:
    254             set.__init__(self, list)
    255         else:
    256             set.__init__(self)
    257         self.compliment = False
    258 
    259     def to_space_str(self):
    260         return list_to_space_str(sorted(self))
    261 
    262     def to_comma_str(self):
    263         return list_to_comma_str(sorted(self))
    264 
    265 class SecurityContext(Leaf):
    266     """An SELinux security context with optional MCS / MLS fields."""
    267     def __init__(self, context=None, parent=None):
    268         """Create a SecurityContext object, optionally from a string.
    269 
    270         Parameters:
    271            [context] - string representing a security context. Same format
    272               as a string passed to the from_string method.
    273         """
    274         Leaf.__init__(self, parent)
    275         self.user = ""
    276         self.role = ""
    277         self.type = ""
    278         self.level = None
    279         if context is not None:
    280             self.from_string(context)
    281 
    282     def from_string(self, context):
    283         """Parse a string representing a context into a SecurityContext.
    284 
    285         The string should be in the standard format - e.g.,
    286         'user:role:type:level'.
    287 
    288         Raises ValueError if the string is not parsable as a security context.
    289         """
    290         # try to translate the context string to raw form
    291         raw = selinux.selinux_trans_to_raw_context(context)
    292         if raw[0] == 0:
    293             context = raw[1]
    294 
    295         fields = context.split(":")
    296         if len(fields) < 3:
    297             raise ValueError("context string [%s] not in a valid format" % context)
    298 
    299         self.user = fields[0]
    300         self.role = fields[1]
    301         self.type = fields[2]
    302         if len(fields) > 3:
    303             # FUTURE - normalize level fields to allow more comparisons to succeed.
    304             self.level = ':'.join(fields[3:])
    305         else:
    306             self.level = None
    307 
    308     def __eq__(self, other):
    309         """Compare two SecurityContext objects - all fields must be exactly the
    310         the same for the comparison to work. It is possible for the level fields
    311         to be semantically the same yet syntactically different - in this case
    312         this function will return false.
    313         """
    314         return self.user == other.user and \
    315                self.role == other.role and \
    316                self.type == other.type and \
    317                self.level == other.level
    318 
    319     def to_string(self, default_level=None):
    320         """Return a string representing this security context.
    321 
    322         By default, the string will contiain a MCS / MLS level
    323         potentially from the default which is passed in if none was
    324         set.
    325 
    326         Arguments:
    327            default_level - the default level to use if self.level is an
    328              empty string.
    329 
    330         Returns:
    331            A string represening the security context in the form
    332               'user:role:type:level'.
    333         """
    334         fields = [self.user, self.role, self.type]
    335         if self.level is None:
    336             if default_level is None:
    337                 if selinux.is_selinux_mls_enabled() == 1:
    338                     fields.append("s0")
    339             else:
    340                 fields.append(default_level)
    341         else:
    342             fields.append(self.level)
    343         return ":".join(fields)
    344 
    345 class ObjectClass(Leaf):
    346     """SELinux object class and permissions.
    347 
    348     This class is a basic representation of an SELinux object
    349     class - it does not represent separate common permissions -
    350     just the union of the common and class specific permissions.
    351     It is meant to be convenient for policy generation.
    352     """
    353     def __init__(self, name="", parent=None):
    354         Leaf.__init__(self, parent)
    355         self.name = name
    356         self.perms = IdSet()
    357 
    358 class XpermSet():
    359     """Extended permission set.
    360 
    361     This class represents one or more extended permissions
    362     represented by numeric values or ranges of values. The
    363     .complement attribute is used to specify all permission
    364     except those specified.
    365 
    366     Two xperm set can be merged using the .extend() method.
    367     """
    368     def __init__(self, complement=False):
    369         self.complement = complement
    370         self.ranges = []
    371 
    372     def __normalize_ranges(self):
    373         """Ensure that ranges are not overlapping.
    374         """
    375         self.ranges.sort()
    376 
    377         i = 0
    378         while i < len(self.ranges):
    379             while i + 1 < len(self.ranges):
    380                 if self.ranges[i + 1][0] <= self.ranges[i][1] + 1:
    381                     self.ranges[i] = (self.ranges[i][0], max(self.ranges[i][1],
    382                                                              self.ranges[i + 1][1]))
    383                     del self.ranges[i + 1]
    384                 else:
    385                     break
    386             i += 1
    387 
    388     def extend(self, s):
    389         """Add ranges from an xperm set
    390         """
    391         self.ranges.extend(s.ranges)
    392         self.__normalize_ranges()
    393 
    394     def add(self, minimum, maximum=None):
    395         """Add value of range of values to the xperm set.
    396         """
    397         if maximum is None:
    398             maximum = minimum
    399         self.ranges.append((minimum, maximum))
    400         self.__normalize_ranges()
    401 
    402     def to_string(self):
    403         if not self.ranges:
    404             return ""
    405 
    406         compl = "~ " if self.complement else ""
    407 
    408         # print single value without braces
    409         if len(self.ranges) == 1 and self.ranges[0][0] == self.ranges[0][1]:
    410             return compl + str(self.ranges[0][0])
    411 
    412         vals = map(lambda x: str(x[0]) if x[0] == x[1] else "%s-%s" % x,
    413                    self.ranges)
    414 
    415         return "%s{ %s }" % (compl, " ".join(vals))
    416 
    417 # Basic statements
    418 
    419 class TypeAttribute(Leaf):
    420     """SElinux typeattribute statement.
    421 
    422     This class represents a typeattribute statement.
    423     """
    424     def __init__(self, parent=None):
    425         Leaf.__init__(self, parent)
    426         self.type = ""
    427         self.attributes = IdSet()
    428 
    429     def to_string(self):
    430         return "typeattribute %s %s;" % (self.type, self.attributes.to_comma_str())
    431 
    432 class RoleAttribute(Leaf):
    433     """SElinux roleattribute statement.
    434 
    435     This class represents a roleattribute statement.
    436     """
    437     def __init__(self, parent=None):
    438         Leaf.__init__(self, parent)
    439         self.role = ""
    440         self.roleattributes = IdSet()
    441 
    442     def to_string(self):
    443         return "roleattribute %s %s;" % (self.role, self.roleattributes.to_comma_str())
    444 
    445 
    446 class Role(Leaf):
    447     def __init__(self, parent=None):
    448         Leaf.__init__(self, parent)
    449         self.role = ""
    450         self.types = IdSet()
    451 
    452     def to_string(self):
    453         s = ""
    454         for t in self.types:
    455             s += "role %s types %s;\n" % (self.role, t)
    456         return s
    457 
    458 class Type(Leaf):
    459     def __init__(self, name="", parent=None):
    460         Leaf.__init__(self, parent)
    461         self.name = name
    462         self.attributes = IdSet()
    463         self.aliases = IdSet()
    464 
    465     def to_string(self):
    466         s = "type %s" % self.name
    467         if len(self.aliases) > 0:
    468             s = s + "alias %s" % self.aliases.to_space_str()
    469         if len(self.attributes) > 0:
    470             s = s + ", %s" % self.attributes.to_comma_str()
    471         return s + ";"
    472 
    473 class TypeAlias(Leaf):
    474     def __init__(self, parent=None):
    475         Leaf.__init__(self, parent)
    476         self.type = ""
    477         self.aliases = IdSet()
    478 
    479     def to_string(self):
    480         return "typealias %s alias %s;" % (self.type, self.aliases.to_space_str())
    481 
    482 class Attribute(Leaf):
    483     def __init__(self, name="", parent=None):
    484         Leaf.__init__(self, parent)
    485         self.name = name
    486 
    487     def to_string(self):
    488         return "attribute %s;" % self.name
    489 
    490 class Attribute_Role(Leaf):
    491     def __init__(self, name="", parent=None):
    492         Leaf.__init__(self, parent)
    493         self.name = name
    494 
    495     def to_string(self):
    496         return "attribute_role %s;" % self.name
    497 
    498 
    499 # Classes representing rules
    500 
    501 class AVRule(Leaf):
    502     """SELinux access vector (AV) rule.
    503 
    504     The AVRule class represents all varieties of AV rules including
    505     allow, dontaudit, and auditallow (indicated by the flags self.ALLOW,
    506     self.DONTAUDIT, and self.AUDITALLOW respectively).
    507 
    508     The source and target types, object classes, and perms are all represented
    509     by sets containing strings. Sets are used to make it simple to add
    510     strings repeatedly while avoiding duplicates.
    511 
    512     No checking is done to make certain that the symbols are valid or
    513     consistent (e.g., perms that don't match the object classes). It is
    514     even possible to put invalid types like '$1' into the rules to allow
    515     storage of the reference policy interfaces.
    516     """
    517     ALLOW = 0
    518     DONTAUDIT = 1
    519     AUDITALLOW = 2
    520     NEVERALLOW = 3
    521 
    522     def __init__(self, av=None, parent=None):
    523         Leaf.__init__(self, parent)
    524         self.src_types = IdSet()
    525         self.tgt_types = IdSet()
    526         self.obj_classes = IdSet()
    527         self.perms = IdSet()
    528         self.rule_type = self.ALLOW
    529         if av:
    530             self.from_av(av)
    531 
    532     def __rule_type_str(self):
    533         if self.rule_type == self.ALLOW:
    534             return "allow"
    535         elif self.rule_type == self.DONTAUDIT:
    536             return "dontaudit"
    537         elif self.rule_type == self.AUDITALLOW:
    538             return "auditallow"
    539         elif self.rule_type == self.NEVERALLOW:
    540             return "neverallow"
    541 
    542     def from_av(self, av):
    543         """Add the access from an access vector to this allow
    544         rule.
    545         """
    546         self.src_types.add(av.src_type)
    547         if av.src_type == av.tgt_type:
    548             self.tgt_types.add("self")
    549         else:
    550             self.tgt_types.add(av.tgt_type)
    551         self.obj_classes.add(av.obj_class)
    552         self.perms.update(av.perms)
    553 
    554     def to_string(self):
    555         """Return a string representation of the rule
    556         that is a valid policy language representation (assuming
    557         that the types, object class, etc. are valie).
    558         """
    559         return "%s %s %s:%s %s;" % (self.__rule_type_str(),
    560                                      self.src_types.to_space_str(),
    561                                      self.tgt_types.to_space_str(),
    562                                      self.obj_classes.to_space_str(),
    563                                      self.perms.to_space_str())
    564 
    565 class AVExtRule(Leaf):
    566     """Extended permission access vector rule.
    567 
    568     The AVExtRule class represents allowxperm, dontauditxperm,
    569     auditallowxperm, and neverallowxperm rules.
    570 
    571     The source and target types, and object classes are represented
    572     by sets containing strings. The operation is a single string,
    573     e.g. 'ioctl'. Extended permissions are represented by an XpermSet.
    574     """
    575     ALLOWXPERM = 0
    576     DONTAUDITXPERM = 1
    577     AUDITALLOWXPERM = 2
    578     NEVERALLOWXPERM = 3
    579 
    580     def __init__(self, av=None, op=None, parent=None):
    581         Leaf.__init__(self, parent)
    582         self.src_types = IdSet()
    583         self.tgt_types = IdSet()
    584         self.obj_classes = IdSet()
    585         self.rule_type = self.ALLOWXPERM
    586         self.xperms = XpermSet()
    587         self.operation = op
    588         if av:
    589             self.from_av(av, op)
    590 
    591     def __rule_type_str(self):
    592         if self.rule_type == self.ALLOWXPERM:
    593             return "allowxperm"
    594         elif self.rule_type == self.DONTAUDITXPERM:
    595             return "dontauditxperm"
    596         elif self.rule_type == self.AUDITALLOWXPERM:
    597             return "auditallowxperm"
    598         elif self.rule_type == self.NEVERALLOWXPERM:
    599             return "neverallowxperm"
    600 
    601     def from_av(self, av, op):
    602         self.src_types.add(av.src_type)
    603         if av.src_type == av.tgt_type:
    604             self.tgt_types.add("self")
    605         else:
    606             self.tgt_types.add(av.tgt_type)
    607         self.obj_classes.add(av.obj_class)
    608         self.operation = op
    609         self.xperms = av.xperms[op]
    610 
    611     def to_string(self):
    612         """Return a string representation of the rule that is
    613         a valid policy language representation (assuming that
    614         the types, object class, etc. are valid).
    615         """
    616         return "%s %s %s:%s %s %s;" % (self.__rule_type_str(),
    617                                      self.src_types.to_space_str(),
    618                                      self.tgt_types.to_space_str(),
    619                                      self.obj_classes.to_space_str(),
    620                                      self.operation,
    621                                      self.xperms.to_string())
    622 
    623 class TypeRule(Leaf):
    624     """SELinux type rules.
    625 
    626     This class is very similar to the AVRule class, but is for representing
    627     the type rules (type_trans, type_change, and type_member). The major
    628     difference is the lack of perms and only and sing destination type.
    629     """
    630     TYPE_TRANSITION = 0
    631     TYPE_CHANGE = 1
    632     TYPE_MEMBER = 2
    633 
    634     def __init__(self, parent=None):
    635         Leaf.__init__(self, parent)
    636         self.src_types = IdSet()
    637         self.tgt_types = IdSet()
    638         self.obj_classes = IdSet()
    639         self.dest_type = ""
    640         self.rule_type = self.TYPE_TRANSITION
    641 
    642     def __rule_type_str(self):
    643         if self.rule_type == self.TYPE_TRANSITION:
    644             return "type_transition"
    645         elif self.rule_type == self.TYPE_CHANGE:
    646             return "type_change"
    647         else:
    648             return "type_member"
    649 
    650     def to_string(self):
    651         return "%s %s %s:%s %s;" % (self.__rule_type_str(),
    652                                      self.src_types.to_space_str(),
    653                                      self.tgt_types.to_space_str(),
    654                                      self.obj_classes.to_space_str(),
    655                                      self.dest_type)
    656 class TypeBound(Leaf):
    657     """SElinux typebound statement.
    658 
    659     This class represents a typebound statement.
    660     """
    661     def __init__(self, parent=None):
    662         Leaf.__init__(self, parent)
    663         self.type = ""
    664         self.tgt_types = IdSet()
    665 
    666     def to_string(self):
    667         return "typebounds %s %s;" % (self.type, self.tgt_types.to_comma_str())
    668 
    669 
    670 class RoleAllow(Leaf):
    671     def __init__(self, parent=None):
    672         Leaf.__init__(self, parent)
    673         self.src_roles = IdSet()
    674         self.tgt_roles = IdSet()
    675 
    676     def to_string(self):
    677         return "allow %s %s;" % (self.src_roles.to_comma_str(),
    678                                  self.tgt_roles.to_comma_str())
    679 
    680 class RoleType(Leaf):
    681     def __init__(self, parent=None):
    682         Leaf.__init__(self, parent)
    683         self.role = ""
    684         self.types = IdSet()
    685 
    686     def to_string(self):
    687         s = ""
    688         for t in self.types:
    689             s += "role %s types %s;\n" % (self.role, t)
    690         return s
    691 
    692 class ModuleDeclaration(Leaf):
    693     def __init__(self, parent=None):
    694         Leaf.__init__(self, parent)
    695         self.name = ""
    696         self.version = ""
    697         self.refpolicy = False
    698 
    699     def to_string(self):
    700         if self.refpolicy:
    701             return "policy_module(%s, %s)" % (self.name, self.version)
    702         else:
    703             return "module %s %s;" % (self.name, self.version)
    704 
    705 class Conditional(Node):
    706     def __init__(self, parent=None):
    707         Node.__init__(self, parent)
    708         self.cond_expr = []
    709 
    710     def to_string(self):
    711         return "[If %s]" % list_to_space_str(self.cond_expr, cont=("", ""))
    712 
    713 class Bool(Leaf):
    714     def __init__(self, parent=None):
    715         Leaf.__init__(self, parent)
    716         self.name = ""
    717         self.state = False
    718 
    719     def to_string(self):
    720         s = "bool %s " % self.name
    721         if s.state:
    722             return s + "true"
    723         else:
    724             return s + "false"
    725 
    726 class InitialSid(Leaf):
    727     def __init(self, parent=None):
    728         Leaf.__init__(self, parent)
    729         self.name = ""
    730         self.context = None
    731 
    732     def to_string(self):
    733         return "sid %s %s" % (self.name, str(self.context))
    734 
    735 class GenfsCon(Leaf):
    736     def __init__(self, parent=None):
    737         Leaf.__init__(self, parent)
    738         self.filesystem = ""
    739         self.path = ""
    740         self.context = None
    741 
    742     def to_string(self):
    743         return "genfscon %s %s %s" % (self.filesystem, self.path, str(self.context))
    744 
    745 class FilesystemUse(Leaf):
    746     XATTR = 1
    747     TRANS = 2
    748     TASK = 3
    749     
    750     def __init__(self, parent=None):
    751         Leaf.__init__(self, parent)
    752         self.type = self.XATTR
    753         self.filesystem = ""
    754         self.context = None
    755 
    756     def to_string(self):
    757         s = ""
    758         if self.type == self.XATTR:
    759             s = "fs_use_xattr "
    760         elif self.type == self.TRANS:
    761             s = "fs_use_trans "
    762         elif self.type == self.TASK:
    763             s = "fs_use_task "
    764 
    765         return "%s %s %s;" % (s, self.filesystem, str(self.context))
    766 
    767 class PortCon(Leaf):
    768     def __init__(self, parent=None):
    769         Leaf.__init__(self, parent)
    770         self.port_type = ""
    771         self.port_number = ""
    772         self.context = None
    773 
    774     def to_string(self):
    775         return "portcon %s %s %s" % (self.port_type, self.port_number, str(self.context))
    776 
    777 class NodeCon(Leaf):
    778     def __init__(self, parent=None):
    779         Leaf.__init__(self, parent)
    780         self.start = ""
    781         self.end = ""
    782         self.context = None
    783 
    784     def to_string(self):
    785         return "nodecon %s %s %s" % (self.start, self.end, str(self.context))
    786 
    787 class NetifCon(Leaf):
    788     def __init__(self, parent=None):
    789         Leaf.__init__(self, parent)
    790         self.interface = ""
    791         self.interface_context = None
    792         self.packet_context = None
    793 
    794     def to_string(self):
    795         return "netifcon %s %s %s" % (self.interface, str(self.interface_context),
    796                                    str(self.packet_context))
    797 class PirqCon(Leaf):
    798     def __init__(self, parent=None):
    799         Leaf.__init__(self, parent)
    800         self.pirq_number = ""
    801         self.context = None
    802 
    803     def to_string(self):
    804         return "pirqcon %s %s" % (self.pirq_number, str(self.context))
    805 
    806 class IomemCon(Leaf):
    807     def __init__(self, parent=None):
    808         Leaf.__init__(self, parent)
    809         self.device_mem = ""
    810         self.context = None
    811 
    812     def to_string(self):
    813         return "iomemcon %s %s" % (self.device_mem, str(self.context))
    814 
    815 class IoportCon(Leaf):
    816     def __init__(self, parent=None):
    817         Leaf.__init__(self, parent)
    818         self.ioport = ""
    819         self.context = None
    820 
    821     def to_string(self):
    822         return "ioportcon %s %s" % (self.ioport, str(self.context))
    823 
    824 class PciDeviceCon(Leaf):
    825     def __init__(self, parent=None):
    826         Leaf.__init__(self, parent)
    827         self.device = ""
    828         self.context = None
    829 
    830     def to_string(self):
    831         return "pcidevicecon %s %s" % (self.device, str(self.context))
    832 
    833 class DeviceTreeCon(Leaf):
    834     def __init__(self, parent=None):
    835         Leaf.__init__(self, parent)
    836         self.path = ""
    837         self.context = None
    838 
    839     def to_string(self):
    840         return "devicetreecon %s %s" % (self.path, str(self.context))
    841 
    842 # Reference policy specific types
    843 
    844 def print_tree(head):
    845     for node, depth in walktree(head, showdepth=True):
    846         s = ""
    847         for i in range(depth):
    848             s = s + "\t"
    849         print(s + str(node))
    850 
    851 
    852 class Headers(Node):
    853     def __init__(self, parent=None):
    854         Node.__init__(self, parent)
    855 
    856     def to_string(self):
    857         return "[Headers]"
    858 
    859 
    860 class Module(Node):
    861     def __init__(self, parent=None):
    862         Node.__init__(self, parent)
    863 
    864     def to_string(self):
    865         return ""
    866 
    867 class Interface(Node):
    868     """A reference policy interface definition.
    869 
    870     This class represents a reference policy interface definition.
    871     """
    872     def __init__(self, name="", parent=None):
    873         Node.__init__(self, parent)
    874         self.name = name
    875 
    876     def to_string(self):
    877         return "[Interface name: %s]" % self.name
    878 
    879 class TunablePolicy(Node):
    880     def __init__(self, parent=None):
    881         Node.__init__(self, parent)
    882         self.cond_expr = []
    883 
    884     def to_string(self):
    885         return "[Tunable Policy %s]" % list_to_space_str(self.cond_expr, cont=("", ""))
    886 
    887 class Template(Node):
    888     def __init__(self, name="", parent=None):
    889         Node.__init__(self, parent)
    890         self.name = name
    891 
    892     def to_string(self):
    893         return "[Template name: %s]" % self.name
    894 
    895 class IfDef(Node):
    896     def __init__(self, name="", parent=None):
    897         Node.__init__(self, parent)
    898         self.name = name
    899 
    900     def to_string(self):
    901         return "[Ifdef name: %s]" % self.name
    902 
    903 class InterfaceCall(Leaf):
    904     def __init__(self, ifname="", parent=None):
    905         Leaf.__init__(self, parent)
    906         self.ifname = ifname
    907         self.args = []
    908         self.comments = []
    909 
    910     def matches(self, other):
    911         if self.ifname != other.ifname:
    912             return False
    913         if len(self.args) != len(other.args):
    914             return False
    915         for a,b in zip(self.args, other.args):
    916             if a != b:
    917                 return False
    918         return True
    919 
    920     def to_string(self):
    921         s = "%s(" % self.ifname
    922         i = 0
    923         for a in self.args:
    924             if isinstance(a, list):
    925                 str = list_to_space_str(a)
    926             else:
    927                 str = a
    928                 
    929             if i != 0:
    930                 s = s + ", %s" % str
    931             else:
    932                 s = s + str
    933             i += 1
    934         return s + ")"
    935 
    936 class OptionalPolicy(Node):
    937     def __init__(self, parent=None):
    938         Node.__init__(self, parent)
    939 
    940     def to_string(self):
    941         return "[Optional Policy]"
    942 
    943 class SupportMacros(Node):
    944     def __init__(self, parent=None):
    945         Node.__init__(self, parent)
    946         self.map = None
    947 
    948     def to_string(self):
    949         return "[Support Macros]"
    950 
    951     def __expand_perm(self, perm):
    952         # Recursive expansion - the assumption is that these
    953         # are ordered correctly so that no macro is used before
    954         # it is defined
    955         s = set()
    956         if perm in self.map:
    957             for p in self.by_name(perm):
    958                 s.update(self.__expand_perm(p))
    959         else:
    960             s.add(perm)
    961         return s
    962 
    963     def __gen_map(self):
    964         self.map = {}
    965         for x in self:
    966             exp_perms = set()
    967             for perm in x.perms:
    968                 exp_perms.update(self.__expand_perm(perm))
    969             self.map[x.name] = exp_perms
    970 
    971     def by_name(self, name):
    972         if not self.map:
    973             self.__gen_map()
    974         return self.map[name]
    975 
    976     def has_key(self, name):
    977         if not self.map:
    978             self.__gen_map()
    979         return name in self.map
    980 
    981 class Require(Leaf):
    982     def __init__(self, parent=None):
    983         Leaf.__init__(self, parent)
    984         self.types = IdSet()
    985         self.obj_classes = { }
    986         self.roles = IdSet()
    987         self.data = IdSet()
    988         self.users = IdSet()
    989 
    990     def add_obj_class(self, obj_class, perms):
    991         p = self.obj_classes.setdefault(obj_class, IdSet())
    992         p.update(perms)
    993 
    994 
    995     def to_string(self):
    996         s = []
    997         s.append("require {")
    998         for type in self.types:
    999             s.append("\ttype %s;" % type)
   1000         for obj_class, perms in self.obj_classes.items():
   1001             s.append("\tclass %s %s;" % (obj_class, perms.to_space_str()))
   1002         for role in self.roles:
   1003             s.append("\trole %s;" % role)
   1004         for bool in self.data:
   1005             s.append("\tbool %s;" % bool)
   1006         for user in self.users:
   1007             s.append("\tuser %s;" % user)
   1008         s.append("}")
   1009 
   1010         # Handle empty requires
   1011         if len(s) == 2:
   1012             return ""
   1013 
   1014         return "\n".join(s)
   1015 
   1016 
   1017 class ObjPermSet:
   1018     def __init__(self, name):
   1019         self.name = name
   1020         self.perms = set()
   1021 
   1022     def to_string(self):
   1023         return "define(`%s', `%s')" % (self.name, self.perms.to_space_str())
   1024 
   1025 class ClassMap:
   1026     def __init__(self, obj_class, perms):
   1027         self.obj_class = obj_class
   1028         self.perms = perms
   1029 
   1030     def to_string(self):
   1031         return self.obj_class + ": " + self.perms
   1032 
   1033 class Comment:
   1034     def __init__(self, l=None):
   1035         if l:
   1036             self.lines = l
   1037         else:
   1038             self.lines = []
   1039 
   1040     def to_string(self):
   1041         # If there are no lines, treat this as a spacer between
   1042         # policy statements and return a new line.
   1043         if len(self.lines) == 0:
   1044             return ""
   1045         else:
   1046             out = []
   1047             for line in self.lines:
   1048                 out.append("#" + line)
   1049             return "\n".join(out)
   1050 
   1051     def merge(self, other):
   1052         if len(other.lines):
   1053             for line in other.lines:
   1054                 if line != "":
   1055                     self.lines.append(line)
   1056 
   1057     def __str__(self):
   1058         return self.to_string()
   1059 
   1060 
   1061