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 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. 61def 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 75def 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 90def 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 96def 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 108def role_type_cmp(a, b): 109 return cmp(a.role, b.role) 110 111def 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