• 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
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