58fa663
#! /usr/bin/python -Es
58fa663
# Copyright (C) 2012 Red Hat 
58fa663
# AUTHOR: Dan Walsh <dwalsh@redhat.com>
58fa663
# see file 'COPYING' for use and warranty information
58fa663
#
58fa663
# semanage is a tool for managing SELinux configuration files
58fa663
#
58fa663
#    This program is free software; you can redistribute it and/or
58fa663
#    modify it under the terms of the GNU General Public License as
58fa663
#    published by the Free Software Foundation; either version 2 of
58fa663
#    the License, or (at your option) any later version.
58fa663
#
58fa663
#    This program is distributed in the hope that it will be useful,
58fa663
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
58fa663
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
58fa663
#    GNU General Public License for more details.
58fa663
#
58fa663
#    You should have received a copy of the GNU General Public License
58fa663
#    along with this program; if not, write to the Free Software
58fa663
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     
58fa663
#                                        02111-1307  USA
58fa663
#
58fa663
#  
58fa663
import seobject
58fa663
import selinux
58fa663
import datetime
58fa663
import setools
58fa663
import sys
58fa663
68f53e0
import xml.etree.ElementTree
68f53e0
modules_dict = {}
68f53e0
try:
68f53e0
	tree = xml.etree.ElementTree.parse("/usr/share/selinux/devel/policy.xml")
68f53e0
	for l in  tree.findall("layer"):
68f53e0
		for m in  l.findall("module"):
68f53e0
			name = m.get("name")
68f53e0
			if name == "apache":
68f53e0
				name = "httpd"
68f53e0
			if name == "zosremote":
68f53e0
				name = "zos"
68f53e0
			if name == "bind":
68f53e0
				name = "named"
68f53e0
			if name == "networkmanager":
68f53e0
				name = "NetworkManager"
68f53e0
			for b in  m.findall("summary"):
68f53e0
				modules_dict[name] = b.text[:-1]
68f53e0
                                if b.text[-1] != ".":
68f53e0
                                    modules_dict[name] += b.text[-1]
68f53e0
except IOError, e:
68f53e0
	pass
68f53e0
58fa663
entrypoints =  setools.seinfo(setools.ATTRIBUTE,"entry_type")[0]["types"]
58fa663
alldomains =  setools.seinfo(setools.ATTRIBUTE,"domain")[0]["types"]
58fa663
domains = []
58fa663
for d in alldomains:
58fa663
    found = False
58fa663
    if d[:-2] + "_exec_t" not in entrypoints:
58fa663
        continue
58fa663
    name = d.split("_")[0]
58fa663
    if name in domains or name == "pam":
58fa663
        continue
58fa663
    domains.append(name)
58fa663
58fa663
domains.sort()
58fa663
58fa663
file_types =  setools.seinfo(setools.ATTRIBUTE,"file_type")[0]["types"]
58fa663
file_types.sort()
58fa663
58fa663
port_types =  setools.seinfo(setools.ATTRIBUTE,"port_type")[0]["types"]
58fa663
port_types.sort()
58fa663
58fa663
portrecs = seobject.portRecords().get_all_by_type()
58fa663
filerecs = seobject.fcontextRecords()
58fa663
files_dict = {}
58fa663
fdict = filerecs.get_all()
58fa663
for i in fdict:
58fa663
    if fdict[i]:
58fa663
        if fdict[i][2] in files_dict:
58fa663
            files_dict[fdict[i][2]].append(i)
58fa663
        else:
58fa663
            files_dict[fdict[i][2]] = [i]
58fa663
boolrecs = seobject.booleanRecords()
58fa663
bools = seobject.booleans_dict.keys()
58fa663
58fa663
man = {}
58fa663
date = datetime.datetime.now().strftime("%d %b %Y")
58fa663
def prettyprint(f,trim):
58fa663
    return " ".join(f[:-len(trim)].split("_"))
58fa663
58fa663
class ManPage:
58fa663
    def __init__(self, domainname, path="/tmp"):
58fa663
        self.domainname = domainname
58fa663
        if self.domainname[-1]=='d':
58fa663
            self.short_name = self.domainname[:-1]
58fa663
        else:
58fa663
            self.short_name = domainname
58fa663
68f53e0
        try:
68f53e0
            self.desc = """
68f53e0
SELinux Linux secures
68f53e0
.B %s
68f53e0
(%s)
68f53e0
processes via flexible mandatory access
68f53e0
control.  
68f53e0
""" % (self.domainname, modules_dict[self.domainname])
68f53e0
        except KeyError:
68f53e0
            self.desc ="""
68f53e0
Security-Enhanced Linux secures the %s processes via flexible mandatory access
68f53e0
control.  
68f53e0
""" % self.domainname
68f53e0
            self.desc = ""
68f53e0
58fa663
        self.anon_list = []
58fa663
        self.fd = open("%s/%s_selinux.8" % (path, domainname), 'w')
58fa663
58fa663
        self.header()
58fa663
        self.booleans()
58fa663
        self.public_content()
58fa663
        self.file_context()
58fa663
        self.port_types()
58fa663
        self.process_types()
58fa663
        self.footer()
58fa663
        self.fd.close()
58fa663
58fa663
    def header(self):
58fa663
        self.fd.write('.TH  "%(domainname)s_selinux"  "8"  "%(domainname)s" "dwalsh@redhat.com" "%(domainname)s SELinux Policy documentation"'
58fa663
                 % {'domainname':self.domainname})
58fa663
        self.fd.write(r"""
58fa663
.SH "NAME"
58fa663
%(domainname)s_selinux \- Security Enhanced Linux Policy for the %(domainname)s processes
58fa663
.SH "DESCRIPTION"
58fa663
68f53e0
%(desc)s
58fa663
68f53e0
""" % {'desc':self.desc, 'domainname':self.domainname})
58fa663
58fa663
    def explain(self, f):
58fa663
        if f.endswith("_var_run_t"):
58fa663
            return "store the %s files under the /run directory." % prettyprint(f, "_var_run_t")
58fa663
        if f.endswith("_pid_t"):
58fa663
            return "store the %s files under the /run directory." % prettyprint(f, "_pid_t")
58fa663
        if f.endswith("_var_lib_t"):
58fa663
            return "store the %s files under the /var/lib directory."  % prettyprint(f, "_var_lib_t")
58fa663
        if f.endswith("_var_t"):
58fa663
            return "store the %s files under the /var directory."  % prettyprint(f, "_var_lib_t")
58fa663
        if f.endswith("_var_spool_t"):
58fa663
            return "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t")
58fa663
        if f.endswith("_spool_t"):
58fa663
            return "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t")
58fa663
        if f.endswith("_cache_t") or f.endswith("_var_cache_t"):
58fa663
            return "store the files under the /var/cache directory."
58fa663
        if f.endswith("_keytab_t"):
58fa663
            return "treat the files as kerberos keytab files."
58fa663
        if f.endswith("_lock_t"):
58fa663
            return "treat the files as %s lock data, stored under the /var/lock directory" % prettyprint(f,"_lock_t")
58fa663
        if f.endswith("_log_t"):
58fa663
            return "treat the data as %s log data, usually stored under the /var/log directory." % prettyprint(f,"_log_t")
58fa663
        if f.endswith("_config_t"):
58fa663
            return "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f,"_config_t")
58fa663
        if f.endswith("_conf_t"):
58fa663
            return "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f,"_conf_t")
58fa663
        if f.endswith("_exec_t"):
58fa663
            return "transition an executable to the %s_t domain." % f[:-len("_exec_t")]
58fa663
        if f.endswith("_cgi_content_t"):
58fa663
            return "treat the files as %s cgi content." % prettyprint(f, "_cgi_content_t")
58fa663
        if f.endswith("_rw_content_t"):
58fa663
            return "treat the files as %s read/write content." % prettyprint(f,"_rw_content_t")
58fa663
        if f.endswith("_rw_t"):
58fa663
            return "treat the files as %s read/write content." % prettyprint(f,"_rw_t")
58fa663
        if f.endswith("_write_t"):
58fa663
            return "treat the files as %s read/write content." % prettyprint(f,"_write_t")
58fa663
        if f.endswith("_db_t"):
58fa663
            return "treat the files as %s database content." % prettyprint(f,"_db_t")
58fa663
        if f.endswith("_ra_content_t"):
68f53e0
            return "treat the files as %s read/append content." % prettyprint(f,"_ra_content_t")
58fa663
        if f.endswith("_cert_t"):
58fa663
            return "treat the files as %s certificate data." % prettyprint(f,"_cert_t")
58fa663
        if f.endswith("_key_t"):
58fa663
            return "treat the files as %s key data." % prettyprint(f,"_key_t")
58fa663
58fa663
        if f.endswith("_secret_t"):
58fa663
            return "treat the files as %s secret data." % prettyprint(f,"_key_t")
58fa663
58fa663
        if f.endswith("_ra_t"):
58fa663
            return "treat the files as %s read/append content." % prettyprint(f,"_ra_t")
58fa663
58fa663
        if f.endswith("_ro_t"):
58fa663
            return "treat the files as %s read/only content." % prettyprint(f,"_ro_t")
58fa663
58fa663
        if f.endswith("_modules_t"):
58fa663
            return "treat the files as %s modules." % prettyprint(f, "_modules_t")
58fa663
58fa663
        if f.endswith("_content_t"):
58fa663
            return "treat the files as %s content." % prettyprint(f, "_content_t")
58fa663
58fa663
        if f.endswith("_state_t"):
58fa663
            return "treat the files as %s state data." % prettyprint(f, "_state_t")
58fa663
58fa663
        if f.endswith("_files_t"):
58fa663
            return "treat the files as %s content." % prettyprint(f, "_files_t")
58fa663
58fa663
        if f.endswith("_file_t"):
58fa663
            return "treat the files as %s content." % prettyprint(f, "_file_t")
58fa663
58fa663
        if f.endswith("_data_t"):
58fa663
            return "treat the files as %s content." % prettyprint(f, "_data_t")
58fa663
58fa663
        if f.endswith("_file_t"):
58fa663
            return "treat the data as %s content." % prettyprint(f, "_file_t")
58fa663
58fa663
        if f.endswith("_tmp_t"):
58fa663
            return "store %s temporary files in the /tmp directories." % prettyprint(f, "_tmp_t")
58fa663
        if f.endswith("_etc_t"):
58fa663
            return "store %s files in the /etc directories." % prettyprint(f, "_tmp_t")
58fa663
        if f.endswith("_home_t"):
58fa663
            return "store %s files in the users home directory." % prettyprint(f, "_home_t")
58fa663
        if f.endswith("_tmpfs_t"):
58fa663
            return "store %s files on a tmpfs file system." % prettyprint(f, "_tmpfs_t")
58fa663
        if f.endswith("_unit_file_t"):
58fa663
            return "treat files as a systemd unit file." 
58fa663
        if f.endswith("_htaccess_t"):
58fa663
            return "treat the file as a %s access file." % prettyprint(f, "_htaccess_t")
58fa663
58fa663
        return "treat the files as %s data." % prettyprint(f,"_t")
58fa663
58fa663
    def booleans(self):
58fa663
        self.booltext = ""
58fa663
        for b in bools:
58fa663
            if b.find(self.short_name) >= 0:
58fa663
                if b.endswith("anon_write"):
58fa663
                    self.anon_list.append(b)
58fa663
                else:
58fa663
                    desc = seobject.booleans_dict[b][2][0].lower() + seobject.booleans_dict[b][2][1:-1]
58fa663
                    self.booltext += """
58fa663
.PP
58fa663
If you want to %s, you must turn on the %s boolean.
58fa663
58fa663
.EX
58fa663
.B setsebool -P %s 1
58fa663
.EE
58fa663
""" % (desc, b, b)
58fa663
    
58fa663
        if self.booltext != "":        
58fa663
            self.fd.write("""
58fa663
.SH BOOLEANS
58fa663
SELinux policy is customizable based on least access required.  %s policy is extremely flexible and has several booleans that allow you to manipulate the policy and run %s with the tightest access possible.
58fa663
58fa663
""" % (self.domainname, self.domainname))
58fa663
58fa663
            self.fd.write(self.booltext)
58fa663
58fa663
    def process_types(self):
58fa663
        ptypes = []
58fa663
        for f in alldomains:
58fa663
            if f.startswith(self.short_name):
58fa663
                ptypes.append(f)
58fa663
        if len(ptypes) == 0:
58fa663
            return
58fa663
        self.fd.write(r"""
58fa663
.SH PROCESS TYPES
58fa663
SELinux defines process types (domains) for each process running on the system
58fa663
.PP
58fa663
You can see the context of a process using the \fB\-Z\fP option to \fBps\bP
58fa663
.PP
58fa663
Policy governs the access confined processes have to files. 
58fa663
SELinux %(domainname)s policy is very flexible allowing users to setup their %(domainname)s processes in as secure a method as possible.
58fa663
.PP 
58fa663
The following process types are defined for %(domainname)s:
58fa663
""" % {'domainname':self.domainname})
58fa663
        self.fd.write("""
58fa663
.EX
58fa663
.B %s 
58fa663
.EE""" % ", ".join(ptypes))
58fa663
        self.fd.write("""
58fa663
.PP
58fa663
Note: 
68f53e0
.B semanage permissive -a PROCESS_TYPE 
58fa663
can be used to make a process type permissive. Permissive process types are not denied access by SELinux. AVC messages will still be generated.
58fa663
""")
58fa663
58fa663
    def port_types(self):
58fa663
        self.ports = []
58fa663
        for f in port_types:
58fa663
            if f.startswith(self.short_name):
58fa663
                self.ports.append(f)
58fa663
58fa663
        if len(self.ports) == 0:
58fa663
            return
58fa663
        self.fd.write("""
58fa663
.SH PORT TYPES
58fa663
SELinux defines port types to represent TCP and UDP ports. 
58fa663
.PP
58fa663
You can see the types associated with a port by using the following command: 
58fa663
58fa663
.B semanage port -l
58fa663
58fa663
.PP
58fa663
Policy governs the access confined processes have to these ports. 
58fa663
SELinux %(domainname)s policy is very flexible allowing users to setup their %(domainname)s processes in as secure a method as possible.
58fa663
.PP 
58fa663
The following port types are defined for %(domainname)s:""" % {'domainname':self.domainname})
58fa663
58fa663
        for p in self.ports:
58fa663
            self.fd.write("""
58fa663
58fa663
.EX
58fa663
.TP 5
58fa663
.B %s 
58fa663
.TP 10
58fa663
.EE
58fa663
""" % p)
58fa663
            once = True
58fa663
            for p in ( "tcp", "udp" ):
58fa663
                if (f,p) in portrecs:
58fa663
                    if once:
58fa663
                        self.fd.write("""
58fa663
58fa663
Default Defined Ports:""")
58fa663
                    once = False
58fa663
                    self.fd.write(r"""
58fa663
%s %s
58fa663
.EE""" % (p, ",".join(portrecs[(f,p)])))
58fa663
58fa663
    def file_context(self):
58fa663
        self.fd.write(r"""
58fa663
.SH FILE CONTEXTS
58fa663
SELinux requires files to have an extended attribute to define the file type. 
58fa663
.PP
58fa663
You can see the context of a file using the \fB\-Z\fP option to \fBls\bP
58fa663
.PP
58fa663
Policy governs the access confined processes have to these files. 
58fa663
SELinux %(domainname)s policy is very flexible allowing users to setup their %(domainname)s processes in as secure a method as possible.
58fa663
.PP 
58fa663
The following file types are defined for %(domainname)s:
58fa663
""" % {'domainname':self.domainname})
58fa663
        for f in file_types:
58fa663
            if f.startswith(self.domainname):
58fa663
                self.fd.write("""
58fa663
58fa663
.EX
58fa663
.PP
58fa663
.B %s 
58fa663
.EE
58fa663
58fa663
- Set files with the %s type, if you want to %s
58fa663
""" % (f, f, self.explain(f)))
58fa663
58fa663
                if f in files_dict:
58fa663
                    plural = ""
58fa663
                    if len(files_dict[f]) > 1:
58fa663
                        plural = "s"
58fa663
                        self.fd.write("""
58fa663
.br
58fa663
.TP 5
58fa663
Path%s: 
58fa663
%s""" % (plural, files_dict[f][0][0]))
58fa663
                        for x in files_dict[f][1:]:
58fa663
                            self.fd.write(", %s" % x[0])
58fa663
58fa663
        self.fd.write("""
58fa663
58fa663
.PP
68f53e0
Note: File context can be temporarily modified with the chcon command.  If you want to permanently change the file context you need to use the
58fa663
.B semanage fcontext 
58fa663
command.  This will modify the SELinux labeling database.  You will need to use
58fa663
.B restorecon
58fa663
to apply the labels.
58fa663
""")
58fa663
58fa663
    def public_content(self):
58fa663
        if len(self.anon_list) > 0:
58fa663
            self.fd.write("""
58fa663
.SH SHARING FILES
58fa663
If you want to share files with multiple domains (Apache, FTP, rsync, Samba), you can set a file context of public_content_t and public_content_rw_t.  These context allow any of the above domains to read the content.  If you want a particular domain to write to the public_content_rw_t domain, you must set the appropriate boolean.
58fa663
.TP
58fa663
Allow %(domainname)s servers to read the /var/%(domainname)s directory by adding the public_content_t file type to the directory and by restoring the file type.
58fa663
.PP
58fa663
.B
58fa663
semanage fcontext -a -t public_content_t "/var/%(domainname)s(/.*)?"
58fa663
.br
58fa663
.B restorecon -F -R -v /var/%(domainname)s
58fa663
.pp
58fa663
.TP
68f53e0
Allow %(domainname)s servers to read and write /var/tmp/incoming by adding the public_content_rw_t type to the directory and by restoring the file type.  This also requires the allow_%(domainname)s_anon_write boolean to be set.
58fa663
.PP
58fa663
.B
58fa663
semanage fcontext -a -t public_content_rw_t "/var/%(domainname)s/incoming(/.*)?"
58fa663
.br
58fa663
.B restorecon -F -R -v /var/%(domainname)s/incoming
58fa663
58fa663
"""  % {'domainname':self.domainname})
58fa663
            for b in self.anon_list:
58fa663
                desc = seobject.booleans_dict[b][2][0].lower() + seobject.booleans_dict[b][2][1:]
58fa663
                self.fd.write("""
58fa663
.PP
58fa663
If you want to %s, you must turn on the %s boolean.
58fa663
58fa663
.EX
58fa663
.B setsebool -P %s 1
58fa663
.EE
58fa663
""" % (desc, b, b))
58fa663
58fa663
    def footer(self):
58fa663
        self.fd.write("""
58fa663
.SH "COMMANDS"
58fa663
.B semanage fcontext
58fa663
can also be used to manipulate default file context mappings.
58fa663
.PP
58fa663
.B semanage permissive
58fa663
can also be used to manipulate whether or not a process type is permissive.
58fa663
.PP
58fa663
.B semanage module
58fa663
can also be used to enable/disable/install/remove policy modules.
58fa663
""")
58fa663
58fa663
        if len(self.ports) > 0:
58fa663
            self.fd.write("""
58fa663
.B semanage port
58fa663
can also be used to manipulate the port definitions
58fa663
""")
58fa663
58fa663
        if self.booltext != "":        
58fa663
            self.fd.write("""
58fa663
.B semanage boolean
58fa663
can also be used to manipulate the booleans
58fa663
""")
58fa663
58fa663
        self.fd.write("""
58fa663
.PP
58fa663
.B system-config-selinux 
58fa663
is a GUI tool available to customize SELinux policy settings.
58fa663
58fa663
.SH AUTHOR	
58fa663
This manual page was autogenerated by genman.py.
58fa663
58fa663
.SH "SEE ALSO"
58fa663
selinux(8), %s(8), semanage(8), restorecon(8), chcon(1)
58fa663
""" % self.domainname)
58fa663
58fa663
        if self.booltext != "":        
58fa663
            self.fd.write(", setsebool(8)")
58fa663
58fa663
for domainname in domains:
68f53e0
    ManPage(domainname)