blob: 7a83aee407cfc4345ac4f7289705a605e3dd146b [file] [log] [blame]
Jeff Vander Stoep74e4f932016-02-08 15:27:10 -08001# 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