1#!/bin/sh
2#
3# Copyright (c) 2000 Alexandre Peixoto
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD: src/share/examples/ipfw/change_rules.sh,v 1.2.2.4 2003/02/16 10:02:42 brueffer Exp $
28# $DragonFly: src/share/examples/ipfw/change_rules.sh,v 1.2 2003/06/17 04:36:57 dillon Exp $
29
30# Change ipfw(8) rules with safety guarantees for remote operation
31#
32# Invoke this script to edit ${firewall_script}. It will call ${EDITOR},
33# or vi(1) if the environment variable is not set, for you to edit
34# ${firewall_script}, ask for confirmation, and then run
35# ${firewall_script}. You can then examine the output of ipfw list and
36# confirm whether you want the new version or not.
37#
38# If no answer is received in 30 seconds, the previous
39# ${firewall_script} is run, restoring the old rules (this assumes ipfw
40# flush is present in it).
41#
42# If the new rules are confirmed, they'll replace ${firewall_script} and
43# the previous ones will be copied to ${firewall_script}.{date}. Mail
44# will also be sent to root with a unified diff of the rule change.
45#
46# Unapproved rules are kept in ${firewall_script}.new, and you are
47# offered the option of changing them instead of the present rules when
48# you call this script.
49#
50# This script could be improved by using version control
51# software.
52
53if [ -r /etc/defaults/rc.conf ]; then
54	. /etc/defaults/rc.conf
55	source_rc_confs
56elif [ -r /etc/rc.conf ]; then
57	. /etc/rc.conf
58fi
59
60EDITOR=${EDITOR:-/usr/bin/vi}
61PAGER=${PAGER:-/usr/bin/more}
62
63tempfoo=`basename $0`
64TMPFILE=`mktemp -t ${tempfoo}` || exit 1
65
66get_yes_no() {
67	while true
68	do
69		echo -n "$1 (Y/N) ? "
70		read -t 30 a
71		if [ $? != 0 ]; then
72			a="No";
73		        return;
74		fi
75		case $a in
76			[Yy]) a="Yes";
77			      return;;
78			[Nn]) a="No";
79			      return;;
80			*);;
81		esac
82	done
83}
84
85restore_rules() {
86	nohup sh ${firewall_script} >/dev/null 2>&1
87	rm ${TMPFILE}
88	exit 1
89}
90
91case "${firewall_type}" in
92[Cc][Ll][Ii][Ee][Nn][Tt]|\
93[Cc][Ll][Oo][Ss][Ee][Dd]|\
94[Oo][Pp][Ee][Nn]|\
95[Ss][Ii][Mm][Pp][Ll][Ee]|\
96[Uu][Nn][Kk][Nn][Oo][Ww][Nn])
97	edit_file="${firewall_script}"
98	rules_edit=no
99	;;
100*)
101	if [ -r "${firewall_type}" ]; then
102		edit_file="${firewall_type}"
103		rules_edit=yes
104	fi
105	;;
106esac
107
108if [ -f ${edit_file}.new ]; then
109	get_yes_no "A new rules file already exists, do you want to use it"
110	[ $a = 'No' ] && cp ${edit_file} ${edit_file}.new
111else
112	cp ${edit_file} ${edit_file}.new
113fi
114
115trap restore_rules SIGHUP
116
117${EDITOR} ${edit_file}.new
118
119get_yes_no "Do you want to install the new rules"
120
121[ $a = 'No' ] && exit 1
122
123cat <<!
124The rules will be changed now. If the message 'Type y to keep the new
125rules' does not appear on the screen or the y key is not pressed in 30
126seconds, the original rules will be restored.
127The TCP/IP connections might be broken during the change. If so, restore
128the ssh/telnet connection being used.
129!
130
131if [ ${rules_edit} = yes ]; then
132	nohup sh ${firewall_script} ${firewall_type}.new \
133	    > ${TMPFILE} 2>&1
134else
135	nohup sh ${firewall_script}.new \
136	    > ${TMPFILE} 2>&1
137fi
138sleep 2;
139get_yes_no "Would you like to see the resulting new rules"
140[ $a = 'Yes' ] && ${PAGER} ${TMPFILE}
141get_yes_no "Type y to keep the new rules"
142[ $a != 'Yes' ] && restore_rules
143
144DATE=`date "+%Y%m%d%H%M"`
145cp ${edit_file} ${edit_file}.$DATE
146mv ${edit_file}.new ${edit_file}
147cat <<!
148The new rules are now installed. The previous rules have been preserved in
149the file ${edit_file}.$DATE
150!
151diff -F "^# .*[A-Za-z]" -u ${edit_file}.$DATE ${edit_file} \
152    | mail -s "`hostname` Firewall rule change" root
153rm ${TMPFILE}
154exit 0
155