• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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