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 """
     21 Classes and functions for the output of reference policy modules.
     22 
     23 This module takes a refpolicy.Module object and formats it for
     24 output using the ModuleWriter object. By separating the output
     25 in this way the other parts of Madison can focus solely on
     26 generating policy. This keeps the semantic / syntactic issues
     27 cleanly separated from the formatting issues.
     28 """
     29 
     30 import refpolicy
     31 import util
     32 
     33 class ModuleWriter:
     34     def __init__(self):
     35         self.fd = None
     36         self.module = None
     37         self.sort = True
     38         self.requires = True
     39 
     40     def write(self, module, fd):
     41         self.module = module
     42 
     43         if self.sort:
     44             sort_filter(self.module)
     45 
     46         # FIXME - make this handle nesting
     47         for node, depth in refpolicy.walktree(self.module, showdepth=True):
     48             fd.write("%s\n" % str(node))
     49 
     50 # Helper functions for sort_filter - this is all done old school
     51 # C style rather than with polymorphic methods because this sorting
     52 # is specific to output. It is not necessarily the comparison you
     53 # want generally.
     54 
     55 # Compare two IdSets - we could probably do something clever
     56 # with different here, but this works.
     57 def id_set_cmp(x, y):
     58     xl = util.set_to_list(x)
     59     xl.sort()
     60     yl = util.set_to_list(y)
     61     yl.sort()
     62 
     63     if len(xl) != len(yl):
     64         return cmp(xl[0], yl[0])
     65     for v in zip(xl, yl):
     66         if v[0] != v[1]:
     67             return cmp(v[0], v[1])
     68     return 0
     69 
     70 # Compare two avrules
     71 def avrule_cmp(a, b):
     72     ret = id_set_cmp(a.src_types, b.src_types)
     73     if ret is not 0:
     74         return ret
     75     ret = id_set_cmp(a.tgt_types, b.tgt_types)
     76     if ret is not 0:
     77         return ret
     78     ret = id_set_cmp(a.obj_classes, b.obj_classes)
     79     if ret is not 0:
     80         return ret
     81 
     82     # At this point, who cares - just return something
     83     return cmp(len(a.perms), len(b.perms))
     84 
     85 # Compare two interface calls
     86 def ifcall_cmp(a, b):
     87     if a.args[0] != b.args[0]:
     88         return cmp(a.args[0], b.args[0])
     89     return cmp(a.ifname, b.ifname)
     90 
     91 # Compare an two avrules or interface calls
     92 def rule_cmp(a, b):
     93     if isinstance(a, refpolicy.InterfaceCall):
     94         if isinstance(b, refpolicy.InterfaceCall):
     95             return ifcall_cmp(a, b)
     96         else:
     97             return id_set_cmp([a.args[0]], b.src_types)
     98     else:
     99         if isinstance(b, refpolicy.AVRule):
    100             return avrule_cmp(a,b)
    101         else:
    102             return id_set_cmp(a.src_types, [b.args[0]])
    103                 
    104 def role_type_cmp(a, b):
    105     return cmp(a.role, b.role)
    106 
    107 def sort_filter(module):
    108     """Sort and group the output for readability.
    109     """
    110     def sort_node(node):
    111         c = []
    112 
    113         # Module statement
    114         for mod in node.module_declarations():
    115             c.append(mod)
    116             c.append(refpolicy.Comment())
    117 
    118         # Requires
    119         for require in node.requires():
    120             c.append(require)
    121         c.append(refpolicy.Comment())
    122 
    123         # Rules
    124         #
    125         # We are going to group output by source type (which
    126         # we assume is the first argument for interfaces).
    127         rules = []
    128         rules.extend(node.avrules())
    129         rules.extend(node.interface_calls())
    130         rules.sort(rule_cmp)
    131 
    132         cur = None
    133         sep_rules = []
    134         for rule in rules:
    135             if isinstance(rule, refpolicy.InterfaceCall):
    136                 x = rule.args[0]
    137             else:
    138                 x = util.first(rule.src_types)
    139 
    140             if cur != x:
    141                 if cur:
    142                     sep_rules.append(refpolicy.Comment())
    143                 cur = x
    144                 comment = refpolicy.Comment()
    145                 comment.lines.append("============= %s ==============" % cur)
    146                 sep_rules.append(comment)
    147             sep_rules.append(rule)
    148 
    149         c.extend(sep_rules)
    150 
    151 
    152         ras = []
    153         ras.extend(node.role_types())
    154         ras.sort(role_type_cmp)
    155         if len(ras):
    156             comment = refpolicy.Comment()
    157             comment.lines.append("============= ROLES ==============")
    158             c.append(comment)
    159         
    160 
    161         c.extend(ras)
    162 
    163         # Everything else
    164         for child in node.children:
    165             if child not in c:
    166                 c.append(child)
    167 
    168         node.children = c
    169 
    170     for node in module.nodes():
    171         sort_node(node)
    172 
    173 
    174