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