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