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