
#-----------------------------------------------------------------------
# Copyright (C) 2000-2001, Jean-Sebastien Morisset <jsmoriss@mvlan.net>
#-----------------------------------------------------------------------
# $Id: config_modules.sh,v 1.5 2001/11/25 20:13:44 jsmoriss Exp $
#-----------------------------------------------------------------------
#  $RCSfile: config_modules.sh,v $
#   $Author: jsmoriss $
# $Revision: 1.5 $
#     $Date: 2001/11/25 20:13:44 $
#   $Locker:  $ 
#     $Name:  $
#-----------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation <http://www.gnu.org/copyleft/gpl.txt>.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License (LICENSE file in archive) for more details.
#
#-----------------------------------------------------------------------
# README
#-----------------------------------------------------------------------
#
# A bourne shell function used by rcf; a very secure, fast, and complete
# firewall for linux <http://jsmoriss.mvlan.net/linux/rcf.html>.
#
# Syntax: Config_Modules [public|private] {sub-dir}
#
#-----------------------------------------------------------------------
# FUNCTION
#-----------------------------------------------------------------------

Config_Modules () {
	ucase_1="`echo $1|To_Upper`"
	lcase_1="`echo $1|To_Lower`"
	lcase_2="`echo $2|To_Lower`"

	case "$lcase_2" in
		services)
			sort_offset="5"
			# Shell pattern match (not regex).
			module_files="[0-9][0-9][0-9]-[a-z]*"
			;;
		*)	sort_offset="1"
			module_files="*"
			;;
	esac

	# Find how far along the path string we have to sort.
	sort_pos="`Sed_Length ${MODULE_DIR}/${lcase_1}/${lcase_2}/`"
	sort_pos="`expr $sort_pos + $sort_offset`"

	# Include each module in the configuration file. We sort the list to
	# keep the options sorted within the configuration file. i.e. ssh
	# will be listed before telnet, etc.
	#
	for file in `find ${MODULE_DIR}/${lcase_1}/${lcase_2} \
		-name "${module_files}" -follow | \
		Chop_And_Swap $sort_pos | sort | Unchop_And_Swap $sort_pos`
	do
		# Just in case...
		[ -f "$file" ] || continue

		# Gather module configuration.
		       name="`sed -ne 's/^#[nN]#  *\([A-Za-z0-9]*\)$/\1/p'  $file|To_Lower`"
		    actions="`sed -ne 's/^#[aA]#  *\([A-Za-z0-9 ]*\)$/\1/p' $file|To_Lower`"
		       type="`sed -ne 's/^#[tT]#  *\([A-Za-z0-9]*\)$/\1/p'  $file|To_Lower`"
		module_mode="`sed -ne 's/^#[mM]#  *\([ 0-9]*\)/\1/p' $file`"

		# Skip this module if we don't have all the essential config values.
		[ "$name" -a "$actions" -a "$type" ] || continue
	
		# Determine if this module supports d/mz clusters.
	    [ "`grep '^#[iI]#.* cluster\( \|\$\)' $file`" ] && cluster_module="yes" || cluster_module="no"

		# Determine if this module supports virtual interfaces.
	    [ "`grep '^#[iI]#.* novirtual\( \|\$\)' $file`" ] && virtual_module="no" || virtual_module="yes"

		# Determine if this module supports ipsec interfaces.
	    [ "`grep '^#[iI]#.* noipsec\( \|\$\)' $file`" ] && ipsec_module="no" || ipsec_module="yes"

		# Pick-up all the interface names we'll be using for the options.
		eval interfaces=\"\$${ucase_1}_INTERFACES\"

		# Add d/mz interfaces names (if any).
		[ "$lcase_1" = "public" ] && interfaces="$interfaces $DMZ_INTERFACES"
		[ "$lcase_1" = "private" ] && interfaces="$interfaces $MZ_INTERFACES"

		# Create a temporary file to store the options.
		> ${CONF}.options.tmp
		chmod 600 ${CONF}.options.tmp

		# This variable will let us keep all the options flushed right.
		max_option_len="0"

		# For each public/private dmz/mz interface, start building the options.
		for interface in $interfaces
		do
			[ "`echo $interface|grep ':'`" -a "$virtual_module" = "no" ] && continue

			# If this is an ipsec interface, and the module excludes ipsec interfaces,
			# then continue to the next interface.
			[ -f /etc/ipsec.conf ] && [ "`grep -E \"interfaces=.*[\\" ]+${interface}=\" \
					/etc/ipsec.conf 2>/dev/null`" -a "$ipsec_module" = "no" ] && continue

			ucase_interface="`echo $interface|To_Upper_Fix`"

			# Check to see if cluster names have been defined for this interface.
			[ "$lcase_1" = "public" ] && eval cluster_names=\"\$DMZ_${ucase_interface}_CLUSTER_NAMES\"
			[ "$lcase_1" = "private" ] && eval cluster_names=\"\$MZ_${ucase_interface}_CLUSTER_NAMES\"

			# Construct an array for the interface section of the option name, and
			# add any clusters found to the array. An example would be "eth0:allservers".
			interface_fields="$interface"
			for cluster_name in $cluster_names
			do
				interface_fields="$interface_fields ${interface}:${cluster_name}"
			done

			for interface_field in $interface_fields
			do
				# For regular interfaces, the interface_fields variable contains only
				# a single interface name. For DMZs, the interface has been joined with
				# cluster names (i.e. "eth3:webservers eth0:1:ftpservers", etc.).
				# This test will tell us if the interface we're dealing with is an
				# interface:cluster_name combo.
				cluster_match="`echo \"$interface_field\"|grep \"^${interface}:.*\$\"`"

				# Set the compare_mode variable to the public/private/dmz/mz-interfaces-mode
				# or dmz/mz-clusters-mode (if it's a cluster). We can then see if this mode
				# number is included in the module_mode variable.
				compare_mode=""
				if [ "$cluster_match" ]
				then
					# Skip any module which doesn't support clusters. We have to test here,
					# since non-cluster interfaces have to be processed. This is where we know
					# if the interface_field contains a cluster_name, and the module supports
					# clusters.
					[ "$cluster_module" = "no" ] && continue
				
					case $lcase_1 in
						public)		compare_mode="$DMZ_CLUSTERS_MODE" ;;
						private)	compare_mode="$MZ_CLUSTERS_MODE" ;;
					esac
				else
					if [ "$cluster_names" ]
					then
						case $lcase_1 in
							public)		compare_mode="$DMZ_INTERFACES_MODE" ;;
							private)	compare_mode="$MZ_INTERFACES_MODE" ;;
						esac
					else
						case $lcase_1 in
							public)		compare_mode="$PUBLIC_INTERFACES_MODE" ;;
							private)	compare_mode="$PRIVATE_INTERFACES_MODE" ;;
						esac
					fi
				fi

				# If module_mode has been set (module had #m# field), check to see if
				# the compare_mode value is listed.
				[ "$module_mode" -a ! "`echo $module_mode|grep \"$compare_mode\"`" ] \
					&& continue

				# For each defined action (accept, deny, ignore, etc.) construct the option.
				for action in $actions
				do
					# Exclude forwarding modules for clusters
					[ "$cluster_match" -a "$action" = "forward" ] && continue

		  			default_value="`sed -ne \"s/^#[vV]#  *${action}  *\(.*\)\$/\1/p\" $file`"
					var="`echo ${action}-${interface_field}-${name}-${type}|To_Lower_Fix`"
					rec="`echo ${action}_${interface_field}_${name}_${type}|To_Upper_Fix`"
					
					if [ ! "`Defined $rec`" ]
					then
						eval : \${$rec:=\"$default_value\"}
					fi
					
					option_len="`Sed_Length $var`"
					[ "$option_len" -gt "$max_option_len" ] && max_option_len="$option_len"

					eval echo "${var}=\$${rec}" >> ${CONF}.options.tmp
				done
			done
			unset interface_fields interface_field compare_mode
		done

		unset default_value interfaces interface
		unset cluster_names cluster_name action var rec
		unset name actions type module_mode
		unset cluster_module virtual_module ipsec_module

		# Make sure we have some options before printing the description.
		if [ "$max_option_len" -gt "0" ]
		then
			{
	  			sed -ne 's/^#[dD]#\(.*\)$/#\1/p' $file
				[ "`grep '^#[dD]#' $file`" ] && echo "#"

				sed -ne '/=/{:a' -e "/^.\{${max_option_len}\}=/!s/^/ /;ta" -e '}' \
					-e 's/^\([^=]*\)=\([^=]*\)$/\1 = \2/p' ${CONF}.options.tmp
				echo ""

			} >> "${CONF}.tmp"
		fi
		rm -f ${CONF}.options.tmp
		unset max_option_len

		TOTAL_MODULES="`expr $TOTAL_MODULES + 1`"
		echo -n "."
	done

	unset ucase_1 lcase_1 lcase_2 module_files sort_pos
}

