1#!/usr/bin/python -Es
2#
3# Copyright (C) 2012 Red Hat
4# see file 'COPYING' for use and warranty information
5#
6# policygentool is a tool for the initial generation of SELinux policy
7#
8#    This program is free software; you can redistribute it and/or
9#    modify it under the terms of the GNU General Public License as
10#    published by the Free Software Foundation; either version 2 of
11#    the License, or (at your option) any later version.
12#
13#    This program is distributed in the hope that it will be useful,
14#    but WITHOUT ANY WARRANTY; without even the implied warranty of
15#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16#    GNU General Public License for more details.
17#
18#    You should have received a copy of the GNU General Public License
19#    along with this program; if not, write to the Free Software
20#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21#                                        02111-1307  USA
22#
23#
24import re, sys
25import sepolicy
26ADMIN_TRANSITION_INTERFACE = "_admin$"
27USER_TRANSITION_INTERFACE = "_role$"
28
29__all__ = [ 'get_all_interfaces', 'get_interfaces_from_xml', 'get_admin', 'get_user' ,'get_interface_dict', 'get_interface_format_text', 'get_interface_compile_format_text', 'get_xml_file', 'interface_compile_test' ]
30
31##
32## I18N
33##
34PROGNAME="policycoreutils"
35
36import gettext
37gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
38gettext.textdomain(PROGNAME)
39try:
40    gettext.install(PROGNAME,
41                    localedir="/usr/share/locale",
42                    unicode=False,
43                    codeset = 'utf-8')
44except IOError:
45    import __builtin__
46    __builtin__.__dict__['_'] = unicode
47
48def get_interfaces_from_xml(path):
49    """ Get all interfaces from given xml file"""
50    interfaces_list = []
51    idict = get_interface_dict(path)
52    for k in idict.keys():
53        interfaces_list.append(k)
54    return interfaces_list
55
56
57def get_all_interfaces(path=""):
58    from sepolicy import get_methods
59    all_interfaces = []
60    if not path:
61        all_interfaces = get_methods()
62    else:
63        xml_path = get_xml_file(path)
64        all_interfaces = get_interfaces_from_xml(xml_path)
65
66    return all_interfaces
67
68def get_admin(path=""):
69    """ Get all domains with an admin interface from installed policy."""
70    """ If xml_path is specified, func returns an admin interface from specified xml file"""
71    admin_list = []
72    if path:
73        try:
74            xml_path = get_xml_file(path)
75            idict = get_interface_dict(xml_path)
76            for k in idict.keys():
77                if k.endswith("_admin"):
78                    admin_list.append(k)
79        except IOError, e:
80            sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
81            sys.exit(1)
82    else:
83        for i in sepolicy.get_methods():
84            if i.endswith("_admin"):
85                admin_list.append(i.split("_admin")[0])
86
87    return admin_list
88
89def get_user(path=""):
90    """ Get all domains with SELinux user role interface"""
91    """ If xml_path is specified, func returns an user role interface from specified xml file"""
92    trans_list = []
93    if path:
94        try:
95            xml_path = get_xml_file(path)
96            idict = get_interface_dict(xml_path)
97            for k in idict.keys():
98                if k.endswith("_role"):
99                    if (("%s_exec_t" % k[:-5]) in sepolicy.get_all_types()):
100                        trans_list.append(k)
101        except IOError, e:
102            sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
103            sys.exit(1)
104    else:
105        for i in sepolicy.get_methods():
106            m = re.findall("(.*)%s" % USER_TRANSITION_INTERFACE, i)
107            if len(m) > 0:
108                if "%s_exec_t" % m[0] in sepolicy.get_all_types():
109                    trans_list.append(m[0])
110
111    return trans_list
112
113interface_dict = None
114def get_interface_dict(path="/usr/share/selinux/devel/policy.xml"):
115    global interface_dict
116    import os
117    import xml.etree.ElementTree
118    if interface_dict:
119        return interface_dict
120
121    interface_dict = {}
122    param_list = []
123
124    xml_path = """<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
125<policy>
126<layer name="admin">
127"""
128    xml_path += path
129    xml_path +="""
130</layer>
131</policy>
132"""
133
134    try:
135        if os.path.isfile(path):
136            tree = xml.etree.ElementTree.parse(path)
137        else:
138            tree = xml.etree.ElementTree.fromstring(xml_path)
139        for l in tree.findall("layer"):
140            for m in l.findall("module"):
141                for i in m.getiterator('interface'):
142                    for e in i.findall("param"):
143                        param_list.append(e.get('name'))
144                    interface_dict[(i.get("name"))] = [param_list,(i.find('summary').text),"interface"]
145                    param_list = []
146                for i in m.getiterator('template'):
147                    for e in i.findall("param"):
148                        param_list.append(e.get('name'))
149                    interface_dict[(i.get("name"))] = [param_list,(i.find('summary').text),"template"]
150                    param_list = []
151    except IOError, e:
152        pass
153    return interface_dict
154
155def get_interface_format_text(interface,path = "/usr/share/selinux/devel/policy.xml"):
156    idict = get_interface_dict(path)
157    interface_text = "%s(%s) %s" % (interface, ", ".join(idict[interface][0]), " ".join(idict[interface][1].split("\n")))
158
159    return interface_text
160
161def get_interface_compile_format_text(interfaces_dict, interface):
162    from templates import test_module
163    param_tmp = []
164    for i in interfaces_dict[interface][0]:
165        param_tmp.append(test_module.dict_values[i])
166        interface_text = "%s(%s)\n" % (interface, ", ".join(param_tmp))
167
168    return interface_text
169
170def generate_compile_te(interface, idict, name="compiletest"):
171    from templates import test_module
172    te = ""
173    te += re.sub("TEMPLATETYPE", name, test_module.te_test_module )
174    te += get_interface_compile_format_text(idict,interface)
175
176    return te
177
178def get_xml_file(if_file):
179    """ Returns xml format of interfaces for given .if policy file"""
180    import os, commands
181    basedir = os.path.dirname(if_file)+"/"
182    filename = os.path.basename(if_file).split(".")[0]
183    rc, output=commands.getstatusoutput("python /usr/share/selinux/devel/include/support/segenxml.py -w -m %s" % basedir+filename)
184    if rc != 0:
185        sys.stderr.write("\n Could not proceed selected interface file.\n")
186        sys.stderr.write("\n%s" % output)
187        sys.exit(1)
188    else:
189        return output
190
191def interface_compile_test(interface, path = "/usr/share/selinux/devel/policy.xml"):
192    exclude_interfaces = ["userdom","kernel","corenet","files", "dev"]
193    exclude_interface_type = ["template"]
194
195    import commands, os
196    policy_files = {'pp':"compiletest.pp", 'te':"compiletest.te", 'fc':"compiletest.fc", 'if':"compiletest.if"}
197    idict = get_interface_dict(path)
198
199    if not (interface.split("_")[0] in exclude_interfaces or idict[interface][2] in exclude_interface_type):
200        print(_("Compiling %s interface" % interface))
201        try:
202            fd = open(policy_files['te'], "w")
203            fd.write(generate_compile_te(interface, idict))
204            fd.close()
205            rc, output=commands.getstatusoutput("make -f /usr/share/selinux/devel/Makefile %s" % policy_files['pp'] )
206            if rc != 0:
207                sys.stderr.write(output)
208                sys.stderr.write(_("\nCompile test for %s failed.\n") % interface)
209
210        except EnvironmentError, e:
211            sys.stderr.write(_("\nCompile test for %s has not run. %s\n") % (interface, e))
212        for v in policy_files.values():
213            if os.path.exists(v):
214                os.remove(v)
215
216    else:
217        sys.stderr.write(_("\nCompiling of %s interface is not supported." % interface))
218