Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / tools / linesync / linesync.sh
1 #!/bin/sh
2 # linesync.sh, Copyright (c) 2002 Arjen Wolfs
3 # 20020604, sengaia@undernet.org
4 #
5 # The code contained is in this file is licenced under the terms
6 # and conditions as specified in the GNU General Public License.
7 #
8 # linesync.sh - centralized ircd.conf updates.
9 # The purpose of this little shell script is to allow a section of an ircd.conf to be 
10 # updated from a central location. Hence it is intended to facilitate the automated 
11 # distribution of k, K, Q, and U lines; or any other .conf lines you may wish to keep
12 # synchronized accross all servers on a network.
13 #
14 # This script will download a file called linesync from a specified web server (see 
15 # below for configuration), and calculate an md5sum from it. It will then download
16 # a file called linesync.sum from a configurable number of other web servers and
17 # compare the contents of these files against the checksum calculated. If any of the
18 # downloaded checksums mismatch, the program will abort. This provides security to
19 # the centralized update mechanism - in order for it to be compromised, multiple
20 # web servers would have to compromised.
21 #
22 # If all checksums match, the script inspects the .conf lines contained within the 
23 # downloaded file. If any .conf lines are found that are not specifically allowed,
24 # the program will abort. This will prevent malicious/dangerous .conf lines (such as
25 # O: or C: lines) from being inserted into ircd.conf.
26 #
27 # If all the checks mentioned above are passed, the script checks ircd.conf for a section
28 # that begins with "# BEGIN LINESYNC", and ends with "# END LINESYNC". The section contained
29 # between these two comments is the section maintained by this program. If these lines are not
30 # found in the ircd.conf, they will be appended to it.
31 # Next, the script will build a new ircd.conf by removing all lines present between the two
32 # commented lines mentioned above, and replace them with the contents of the file downloaded.
33
34 # Once this has been completed, ircd.conf is backed up and replaced with the newly built version,
35 # and ircd will be rehashed. 
36 #
37 # Configuration: This script requires two parameters - the full path to your ircd.conf, and the
38 # full path to your ircd.pid. It will look for a configuration file called linesync.conf in the
39 # same directory as ircd.conf. See the included sample linesync.conf for information on how to
40 # set it up. Obviously, you will need to have web server(s) to use for the distribution of your
41 # .conf update and checksums. This script requires the presence of wget and md5sum, and various
42 # other programs that should be present by default on any Unix system. 
43 #
44 # This program should be run from crontab, i.e something like:
45 # 0 0 * * * /home/irc/bin/linesync.sh /home/irc/lib/ircd.conf /home/irc/lib/ircd.pid
46 #
47 # This program has been tested on and works on FreeBSD, Solaris, and Linux.
48 # md5sum is included in GNU textutils.
49 #
50 #       Good Luck!
51 #       Arjen Wolfs (sengaia@undernet.org), June 9 2002.
52 #
53
54 # This checks for the presence of an executable file in $PATH
55 locate_program() {
56         if [ ! -x "`which $1 2>&1`" ]; then
57                 echo "You don't seem to have $1. Sorry."
58                 exit 1
59         fi
60 }
61
62 # This checks for the presence of any file
63 check_file() {
64         if [ ! -f "$1" ]; then
65                 echo "There doesn't appear to be a $1. Sorry."
66                 exit 1
67         fi
68 }
69
70 # Try to find programs we will need
71 locate_program wget && locate_program egrep
72
73 # try to find GNU awk
74 awk_cmd=`which gawk`
75 if [ $? -ne 0 ]; then
76         awk_cmd=""
77 fi
78
79 # try to find an appropriate md5 program
80 # BSD md5 capability courtesy of spale
81 md5_cmd=`which md5sum`
82 if [ -z "$md5_cmd" ]; then
83         md5_cmd=`which md5`
84         if [ -z "$md5_cmd" ]; then
85                 echo "No MD5 capable programs found (I looked for md5sum and md5)."
86                 exit
87         else
88                 md5_cmd="$md5_cmd -q"
89         fi
90 fi
91
92 if [ -z "$awk_cmd" ]; then
93         locate_program awk
94         is_gawk=`echo | awk --version | head -1 | egrep '^GNU.+$'`
95         if [ -z "$is_gawk" ]; then
96                 echo "Your version of awk is not GNU awk. Sorry."
97                 exit 1
98         fi
99         awk_cmd="awk"   
100 fi
101
102 # Check for required command line parameters
103 if [ -z "$1" -o -z "$2" ]; then
104         echo "Usage: $0 <conf_path> <pid_path>"
105         echo "      <conf_path>     Full path to ircd.conf (/home/irc/lib/ircd.conf)"
106         echo "      <pid_path>      Full path to ircd.pid (/home/irc/lib/ircd.pid)"
107         exit 1
108 fi
109
110 # check and set up stuff
111 cpath=$1
112 ppath=$2
113 check_file $cpath
114 dpath=`dirname $cpath`
115 lpath="$dpath/linesync.conf"
116 check_file $lpath
117 save_dir=$PWD; cd $dpath
118 tpath=$PWD; cd $save_dir
119 tmp_path="$dpath/tmp"
120 mkdir $tmp_path > /dev/null 2>&1
121
122 # load and check configuration
123 . $lpath
124 if [ -z "$LINE_SERVER" -o -z "$LINE_CHECK" -o -z "$ALLOWED_LINES" ]; then
125         echo "Please setup $lpath correctly."
126         exit 1
127 fi
128
129 # Not all versions of date support %s, work around it
130 TS=`date +%Y%m%d%H%M%S`
131 TMPFILE="$tmp_path/linesync.$TS"
132 LSFILE="$LINE_SERVER""linesync"
133 # Attempt to download our .conf update
134 wget --cache=off --quiet --output-document=$TMPFILE $LSFILE > /dev/null 2>&1
135 if [ ! -s "$TMPFILE" ]; then
136         echo "Unable to retrieve $LSFILE. Sorry."
137         rm $TMPFILE > /dev/null 2>&1
138         exit 1
139 fi
140
141 # Check wether the file contains any disallowed .conf lines
142 bad_lines=`egrep '^[^'$ALLOWED_LINES'#]+' $TMPFILE`
143 if [ ! -z "$bad_lines" ]; then
144         echo "The file downloaded in $TMPFILE contains the following disallowed line(s):"
145         echo $bad_lines
146         exit 1
147 fi
148
149 # check our ircd.conf
150 ircd_setup=`egrep '^# (BEGIN|END) LINESYNC$' $cpath|wc -l`
151 if [ $ircd_setup != 2 ]; then
152         cp $cpath $cpath.orig
153         echo "Performing initial merge on $cpath, original file saved as $cpath.orig."
154         
155         echo "# Do NOT remove the following line, linesync.sh depends on it!" >> $cpath
156         echo "# BEGIN LINESYNC" >> $cpath
157         echo "# END LINESYNC" >> $cpath
158         echo "# Do not remove the previous line, linesync.sh depends on it!" >> $cpath
159
160         # Do an initial merge to remove duplicates
161         inpath="$tmp_path/linesync.tmp.$TS"
162         $awk_cmd '
163         {
164                 if (!loaded_template) {
165                         command="cat " tempfile; tlines=0;
166                         while ((command | getline avar) > 0) { template[tlines]=avar; tlines++ }
167                         close(command)
168                         loaded_template++
169                 }
170                 dup_line=0
171                 for (i=0; i<tlines; i++) {
172                         if (tolower($0)==tolower(template[i])) { dup_line++; break }
173                 }
174                 if (!dup_line) print $0
175         } ' tempfile=$TMPFILE < $cpath > $inpath
176 else
177         inpath=$cpath
178 fi
179
180 # Get the checksum
181 CKSUM=`$md5_cmd $TMPFILE|cut -d' ' -f1`
182
183 check_file="$tmp_path/linesync.sum.$TS"
184 for ck_server in $LINE_CHECK; do
185         sumfile="$ck_server""linesync.sum"
186         wget --cache=off --quiet --output-document=$check_file $sumfile > /dev/null 2>&1
187         if [ ! -s "$check_file" ]; then
188                 echo "Unable to retrieve checksum from $sumfile"
189                 exit 1  
190         fi
191         if [ "$CKSUM" != "`cat $check_file`" ]; then
192                 echo "Checksum retrieved from $sumfile does not match!"
193                 exit 1
194         fi
195         rm -f $check_file
196 done
197 # It all checks out, proceed...
198
199 # Replace the marked block in ircd.conf with the new version
200
201 $awk_cmd ' 
202 $0=="# BEGIN LINESYNC" { chop++; print; next }
203 $0=="# END LINESYNC" {
204         command="cat " syncfile
205         while ((command | getline avar) > 0) { print avar }
206         close(command)
207         chop--
208 }
209 { if (!chop) print $0 }
210 ' syncfile=$TMPFILE < $inpath > $tmp_path/linesync.new.$TS
211
212 # Back up the current ircd.conf and replace it with the new one
213 cp $cpath  $dpath/ircd.conf.bk
214 cp $tmp_path/linesync.new.$TS $cpath
215
216 # Rehash ircd (without caring wether or not it succeeds)
217 kill -HUP `cat $ppath 2>/dev/null` > /dev/null 2>&1
218
219 # (Try to) clean up
220 rm -rf $tmp_path > /dev/null 2>&1
221
222 # That's it...