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