de82d85
#! /usr/bin/env python
de82d85
# Copyright (C) 2006 Red Hat 
de82d85
# see file 'COPYING' for use and warranty information
de82d85
#
de82d85
# policygentool is a tool for the initial generation of SELinux policy
de82d85
#
de82d85
#    This program is free software; you can redistribute it and/or
de82d85
#    modify it under the terms of the GNU General Public License as
de82d85
#    published by the Free Software Foundation; either version 2 of
de82d85
#    the License, or (at your option) any later version.
de82d85
#
de82d85
#    This program is distributed in the hope that it will be useful,
de82d85
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
de82d85
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
de82d85
#    GNU General Public License for more details.
de82d85
#
de82d85
#    You should have received a copy of the GNU General Public License
de82d85
#    along with this program; if not, write to the Free Software
de82d85
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     
de82d85
#                                        02111-1307  USA
de82d85
#
de82d85
#  
de82d85
import os, sys, getopt
de82d85
import re
de82d85
de82d85
########################### Interface File #############################
575aa98
interface="""\
575aa98
## <summary>policy for TEMPLATETYPE</summary>
575aa98
575aa98
########################################
575aa98
## <summary>
575aa98
##	Execute a domain transition to run TEMPLATETYPE.
575aa98
## </summary>
575aa98
## <param name=\"domain\">
jantill eaccf7f
## <summary>
575aa98
##	Domain allowed to transition.
jantill eaccf7f
## </summary>
575aa98
## </param>
575aa98
#
575aa98
interface(`TEMPLATETYPE_domtrans',`
4ef386f
	gen_require(`
575aa98
		type TEMPLATETYPE_t, TEMPLATETYPE_exec_t;
575aa98
	')
575aa98
575aa98
	domain_auto_trans($1,TEMPLATETYPE_exec_t,TEMPLATETYPE_t)
575aa98
575aa98
	allow $1 TEMPLATETYPE_t:fd use;
575aa98
	allow TEMPLATETYPE_t $1:fd use;
cc073e7
	allow TEMPLATETYPE_t $1:fifo_file rw_file_perms;
575aa98
	allow TEMPLATETYPE_t $1:process sigchld;
575aa98
')
575aa98
"""
de82d85
de82d85
########################### Type Enforcement File #############################
575aa98
te="""\
575aa98
policy_module(TEMPLATETYPE,1.0.0)
575aa98
575aa98
########################################
575aa98
#
575aa98
# Declarations
575aa98
#
575aa98
575aa98
type TEMPLATETYPE_t;
575aa98
type TEMPLATETYPE_exec_t;
575aa98
domain_type(TEMPLATETYPE_t)
575aa98
init_daemon_domain(TEMPLATETYPE_t, TEMPLATETYPE_exec_t)
575aa98
"""
575aa98
te_pidfile="""
575aa98
# pid files
575aa98
type TEMPLATETYPE_var_run_t;
575aa98
files_pid_file(TEMPLATETYPE_var_run_t)
575aa98
"""
575aa98
te_logfile="""
575aa98
# log files
575aa98
type TEMPLATETYPE_var_log_t;
575aa98
logging_log_file(TEMPLATETYPE_var_log_t)
575aa98
"""
575aa98
te_libfile="""
575aa98
# var/lib files
575aa98
type TEMPLATETYPE_var_lib_t;
575aa98
files_type(TEMPLATETYPE_var_lib_t)
575aa98
"""
575aa98
te_sep="""
575aa98
########################################
575aa98
#
575aa98
# TEMPLATETYPE local policy
575aa98
#
575aa98
# Check in /etc/selinux/refpolicy/include for macros to use instead of allow rules.
575aa98
575aa98
# Some common macros (you might be able to remove some)
575aa98
files_read_etc_files(TEMPLATETYPE_t)
575aa98
libs_use_ld_so(TEMPLATETYPE_t)
575aa98
libs_use_shared_libs(TEMPLATETYPE_t)
575aa98
miscfiles_read_localization(TEMPLATETYPE_t)
575aa98
## internal communication is often done using fifo and unix sockets.
575aa98
allow TEMPLATETYPE_t self:fifo_file { read write };
575aa98
allow TEMPLATETYPE_t self:unix_stream_socket create_stream_socket_perms;
575aa98
"""
575aa98
te_pidfile2="""
575aa98
# pid file
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_run_t:file manage_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_run_t:sock_file manage_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_run_t:dir rw_dir_perms;
575aa98
files_pid_filetrans(TEMPLATETYPE_t,TEMPLATETYPE_var_run_t, { file sock_file })
575aa98
"""
575aa98
te_logfile2="""
575aa98
# log files
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_log_t:file create_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_log_t:sock_file create_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_log_t:dir { rw_dir_perms setattr };
575aa98
logging_log_filetrans(TEMPLATETYPE_t,TEMPLATETYPE_var_log_t,{ sock_file file dir })
575aa98
"""
575aa98
te_libfile2="""
575aa98
# var/lib files for TEMPLATETYPE
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_lib_t:file create_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_lib_t:sock_file create_file_perms;
575aa98
allow TEMPLATETYPE_t TEMPLATETYPE_var_lib_t:dir create_dir_perms;
539ba8a
files_var_lib_filetrans(TEMPLATETYPE_t,TEMPLATETYPE_var_lib_t, { file dir sock_file })
575aa98
"""
575aa98
te_network2="""
575aa98
## Networking basics (adjust to your needs!)
575aa98
sysnet_dns_name_resolve(TEMPLATETYPE_t)
575aa98
corenet_tcp_sendrecv_all_if(TEMPLATETYPE_t)
575aa98
corenet_tcp_sendrecv_all_nodes(TEMPLATETYPE_t)
575aa98
corenet_tcp_sendrecv_all_ports(TEMPLATETYPE_t)
575aa98
corenet_non_ipsec_sendrecv(TEMPLATETYPE_t)
575aa98
corenet_tcp_connect_http_port(TEMPLATETYPE_t)
575aa98
#corenet_tcp_connect_all_ports(TEMPLATETYPE_t)
575aa98
## if it is a network daemon, consider these:
575aa98
#corenet_tcp_bind_all_ports(TEMPLATETYPE_t)
575aa98
#corenet_tcp_bind_all_nodes(TEMPLATETYPE_t)
575aa98
allow TEMPLATETYPE_t self:tcp_socket { listen accept };
575aa98
"""
575aa98
te_initsc2="""
575aa98
# Init script handling
414d6d8
init_use_fds(TEMPLATETYPE_t)
575aa98
init_use_script_ptys(TEMPLATETYPE_t)
575aa98
domain_use_interactive_fds(TEMPLATETYPE_t)
575aa98
"""
de82d85
de82d85
########################### File Context ##################################
575aa98
fc="""\
575aa98
# TEMPLATETYPE executable will have:
575aa98
# label: system_u:object_r:TEMPLATETYPE_exec_t
575aa98
# MLS sensitivity: s0
575aa98
# MCS categories: <none>
575aa98
575aa98
EXECUTABLE		--	gen_context(system_u:object_r:TEMPLATETYPE_exec_t,s0)
575aa98
"""
575aa98
fc_pidfile="""\
575aa98
FILENAME			gen_context(system_u:object_r:TEMPLATETYPE_var_run_t,s0)
575aa98
"""
575aa98
fc_logfile="""\
575aa98
FILENAME			gen_context(system_u:object_r:TEMPLATETYPE_var_log_t,s0)
575aa98
"""
575aa98
fc_libfile="""\
575aa98
FILENAME			gen_context(system_u:object_r:TEMPLATETYPE_var_lib_t,s0)
575aa98
"""
de82d85
def errorExit(error):
de82d85
	sys.stderr.write("%s: " % sys.argv[0])
de82d85
	sys.stderr.write("%s\n" % error)
de82d85
	sys.stderr.flush()
de82d85
	sys.exit(1)
de82d85
de82d85
575aa98
def write_te_file(module, pidfile, logfile, libfile, network, initsc):
de82d85
	file="%s.te" % module
de82d85
	newte=re.sub("TEMPLATETYPE", module, te)
575aa98
	if pidfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_pidfile)
575aa98
	if logfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_logfile)
575aa98
	if libfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_libfile)
575aa98
	newte= newte + re.sub("TEMPLATETYPE", module, te_sep)
575aa98
	if pidfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_pidfile2)
575aa98
	if logfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_logfile2)
575aa98
	if libfile:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_libfile2)
575aa98
	if network:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_network2)
575aa98
	if initsc:
575aa98
		newte= newte + re.sub("TEMPLATETYPE", module, te_initsc2)
de82d85
	if os.path.exists(file):
de82d85
		errorExit("%s already exists" % file)
de82d85
	fd = open(file, 'w')
de82d85
	fd.write(newte)
de82d85
	fd.close()
de82d85
de82d85
def write_if_file(module):
de82d85
	file="%s.if" % module
de82d85
	newif=re.sub("TEMPLATETYPE", module, interface)
de82d85
	if os.path.exists(file):
de82d85
		errorExit("%s already exists" % file)
de82d85
	fd = open(file, 'w')
de82d85
	fd.write(newif)
de82d85
	fd.close()
de82d85
575aa98
def write_fc_file(module, executable, pidfile, logfile, libfile):
de82d85
	file="%s.fc" % module
575aa98
	temp=re.sub("TEMPLATETYPE", module, fc)
575aa98
	newfc=re.sub("EXECUTABLE", executable, temp)
575aa98
	if pidfile:
575aa98
		temp=re.sub("TEMPLATETYPE", module, fc_pidfile)
575aa98
		newfc=newfc + re.sub("FILENAME", pidfile, temp)
575aa98
	if logfile:
575aa98
		temp=re.sub("TEMPLATETYPE", module, fc_logfile)
575aa98
		newfc=newfc + re.sub("FILENAME", logfile, temp)
575aa98
	if libfile:
575aa98
		temp=re.sub("TEMPLATETYPE", module, fc_libfile)
575aa98
		newfc=newfc + re.sub("FILENAME", libfile, temp)
de82d85
	if os.path.exists(file):
de82d85
		errorExit("%s already exists" % file)
de82d85
	fd = open(file, 'w')
de82d85
	fd.write(newfc)
de82d85
	fd.close()
de82d85
575aa98
def gen_policy(module, executable, pidfile, logfile, libfile, initsc, network):
575aa98
	write_te_file(module, pidfile, logfile, libfile, initsc, network)
de82d85
	write_if_file(module)
575aa98
	write_fc_file(module, executable, pidfile, logfile, libfile)
de82d85
	
de82d85
if __name__ == '__main__':
de82d85
	def usage(message = ""):
de82d85
		print '%s ModuleName Executable' % sys.argv[0]
de82d85
		sys.exit(1)
de82d85
		
de82d85
	if len(sys.argv) != 3:
de82d85
		usage()
de82d85
575aa98
	print """\n
575aa98
This tool generate three files for policy development, A Type Enforcement (te)
575aa98
file, a File Context (fc), and a Interface File(if).  Most of the policy rules
575aa98
will be written in the te file.  Use the File Context file to associate file
575aa98
paths with security context.  Use the interface rules to allow other protected
575aa98
domains to interact with the newly defined domains.
575aa98
575aa98
After generating these files use the /usr/share/selinux/devel/Makefile to
575aa98
compile your policy package.  Then use the semodule tool to load it.
575aa98
575aa98
# /usr/share/selinux/devel/policygentool myapp /usr/bin/myapp
575aa98
# make -f /usr/share/selinux/devel/Makefile
575aa98
# semodule -l myapp.pp
575aa98
# restorecon -R -v /usr/bin/myapp "all files defined in myapp.fc"
575aa98
575aa98
Now you can turn on permissive mode, start your application and avc messages
575aa98
will be generated.  You can use audit2allow to help translate the avc messages
575aa98
into policy.
575aa98
575aa98
# setenforce 0
575aa98
# service myapp start
575aa98
# audit2allow -R -i /var/log/audit/audit.log
575aa98
575aa98
Return to continue:"""
575aa98
        sys.stdin.readline().rstrip()
575aa98
575aa98
	print 'If the module uses pidfiles, what is the pidfile called?'
575aa98
	pidfile = sys.stdin.readline().rstrip()
575aa98
	if pidfile == "":
575aa98
		pidfile = None
575aa98
	print 'If the module uses logfiles, where are they stored?'
575aa98
	logfile = sys.stdin.readline().rstrip()
575aa98
	if logfile == "":
575aa98
		logfile = None
575aa98
	print 'If the module has var/lib files, where are they stored?'
575aa98
	libfile = sys.stdin.readline().rstrip()
575aa98
	if libfile == "":
575aa98
		libfile = None
575aa98
	print 'Does the module have a init script? [yN]'
575aa98
	initsc = sys.stdin.readline().rstrip()
575aa98
	if initsc == "" or initsc == "n" or initsc == "N":
575aa98
		initsc = False
575aa98
	elif initsc == "y" or initsc == "Y":
575aa98
		initsc = True
575aa98
	else:
575aa98
		raise "Please answer with 'y' or 'n'!"
575aa98
	print 'Does the module use the network? [yN]'
575aa98
	network = sys.stdin.readline().rstrip()
575aa98
	if network == "" or network == "n" or network == "N":
575aa98
		network = False
575aa98
	elif network == "y" or network == "Y":
575aa98
		network = True
575aa98
	else:
575aa98
		raise "Please answer with 'y' or 'n'!"
575aa98
575aa98
	gen_policy(
575aa98
		module=sys.argv[1],
575aa98
		executable=sys.argv[2],
575aa98
		pidfile=pidfile,
575aa98
		logfile=logfile,
575aa98
		libfile=libfile,
575aa98
		initsc=initsc,
575aa98
		network=network
575aa98
	)
de82d85
de82d85