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 30import refpolicy 31import util 32 33class 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. 57def 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 71def 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 86def 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 92def 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 104def role_type_cmp(a, b): 105 return cmp(a.role, b.role) 106 107def 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