#!/bin/tcsh -f
# JLdL 05Sep11.
#
# Copyright (C) 2008-2011 by Jorge L. deLyra <delyra@fma.if.usp.br>.
# This program may be copied and/or distributed freely. See the
# _ terms and conditions in /usr/share/doc/<package>/copyright.
#
# A script to be executed from a CGI form and allow users to
# _ register their home domains with dynamical addresses in
# _ their primary DNS server, which must be a machine within
# _ the local cluster of servers.
#
# Since this script is to be called from a CGI script,
# _ set the font size for the error messages.
echo '<body bgcolor="#e0d4c0" text="#000000"'
echo ' link="0000ff" vlink="0000aa" alink="ff0000">'
echo '<font size=4>'
#
# Wait for a random time between 0.1 sec and 1.0 sec,
# _ to ensure that the locking works even if the user
# _ submits several requests almost at the same time.
sleep 0.`rani`
#
# Record the name this script was called with.
set name = `basename $0`
#
# Record the short name of this host.
set shost = `hostname -s`
#
# Get the domain in which to act, from the configuration file;
# _ this is needed in case the host has two network interfaces
# _ to different domains, typically the internet and a private
# _ network, and we need to choose in which domain this remote
# _ authorization system will be active.
set dhost = `cat /etc/dynahost/defaultdomain`
#
# Record the full name of this host in that domain.
set fhost = $shost.$dhost
#
# Define also the localhost.
set lhost = "localhost"
#
# There may be more than one entry in the /etc/hosts file with
# _ the hostname and the same IP, so prevent any trouble with
# _ that here, simply using only the first entry.
set ihost = `hostname -i | cut -d' ' -f1`
#
# Check for a lock file.
set lockfile = /var/lock/$name
if ( -f $lockfile ) then
    echo "${name}: ERROR: this script is already running"
    echo '</font>'
    echo '</body>'
    exit 1
endif
#
# Make a lock file.
touch $lockfile
#
# Make sure the log file is there.
set logfile = /var/log/$name.log
touch $logfile
#
# Alias defining a macro for exiting cleanly.
alias cleanexit \
    "\rm -f $lockfile >& /dev/null ; echo '</font>\n</body>'; exit \!*"
#
# Define a variable with the TAB character.
set tab = "`echo '\t'`"
#
# Get the remote username from the command line.
set ruser = "$1"
#
# Get the remote IP address from the command line;
# _ filter out a possible "+" left when the user
# _ puts a trailing space in the CGI-script form
# _ entry for the address, which can happen when
# _ one uses cut-and-paste with the mouse.
set raddr = "`echo $2 | cut -d+ -f1`"
#
# Fix the variables to get fixed columns on the log file.
set nchar = `echo -n $ruser | wc -c`
if ( $nchar < 5 ) then
    set ru = "$ruser$tab"
else
    set ru = "$ruser"
endif
set nchar = `echo -n $raddr | wc -c`
if ( $nchar < 5 ) then
    set ra = "$raddr$tab$tab"
else if ( $nchar < 13 ) then
    set ra = "$raddr$tab"
else
    set ra = "$raddr"
endif
#
# Make sure the configuration file is there;
# _ first define the configuration file.
set conffile = /etc/dynahost/$name.conf
#
# If it is not, then exit in error.
if ( ! -f $conffile ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=NONE${tab}${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo \
    "${name}: INTERNAL ERROR: missing configuration file" | \
    tee -a $logfile
    cleanexit 1
endif
#
# Get the information from the configuration file.
#
# Get the record of the configuration file for this username.
set record = `grep "^[ $tab]*${ruser}[ $tab]" $conffile`
#
# If there is no such record, then exit in error.
if ( "$record" == "" ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=NONE${tab}${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo \
    "${name}: ERROR: user $ruser not registered for this service" | \
    tee -a $logfile
    cleanexit 1
endif
#
# If the record is incomplete, then exit in error.
if ( $#record < 2 ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=NONE${tab}${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo \
    "${name}: ERROR: record for user $ruser is incomplete" | \
    tee -a $logfile
    cleanexit 1
endif
#
# Extract the remote zonename from the record.
set rzone = $record[2]
#
# Fix the variables to get fixed columns on the log file.
set nchar = `echo -n $rzone | wc -c`
if ( $nchar < 5 ) then
    set rz = "$rzone$tab$tab"
else if ( $nchar < 13 ) then
    set rz = "$rzone$tab"
else
    set rz = "$rzone"
endif
#
# Extract the hostname of the primary DNS server
# _ from the record, if it is listed there.
if ( $#record > 2 ) then
    set pdnss = $record[3]
    #
    # Raise the remote-primary flag if needed.
    if ( "$pdnss" != "$shost" && \
	 "$pdnss" != "$fhost" && \
	 "$pdnss" != "$lhost" && \
	 "$pdnss" != "$ihost" ) then
	set rpflg = 1
    else
	set rpflg = 0
    endif
#
# By default the primary DNS server is the local host.
else
    set pdnss = "$shost"
    #
    # Lower the remote-primary flag.
    set rpflg = 0
    #
endif
#
# Extract the hostname of the secondary DNS server
# _ from the record, if it is listed there.
if ( $#record > 3 ) then
    set sdnss = $record[4]
    #
    # Raise the remote-secondary flag if needed.
    if ( "$sdnss" != "$shost" && \
	 "$sdnss" != "$fhost" && \
	 "$sdnss" != "$lhost" && \
	 "$sdnss" != "$ihost" ) then
	set rsflg = 1
    else
	set rsflg = 0
    endif
#
# There is no default for the secondary DNS server.
else
    set sdnss = ""
    #
    # Lower the remote-secondary flag.
    set rsflg = 0
    #
endif
#
# Check whether the zone file exists.
if ( $rpflg ) then
    set zstat = `ssh $pdnss "if ( -f /etc/bind/$rzone.zone ) echo OK"`
else
    set zstat = `if ( -f /etc/bind/$rzone.zone ) echo OK`
endif
#
# If it does not, then exit in error.
if ( $zstat != OK ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=$rz${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo "${name}: ERROR: unknown zone $rzone" | \
	tee -a $logfile
    cleanexit 1
endif
#
# Check whether the remote zone is registered.
grep -q "($rzone,-,`nisdomainname`)" /etc/netgroup
set error = $status
#
# If it is not, then exit in error.
if ( $error != 0 ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=$rz${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo \
	"${name}: ERROR: zone $rzone not registered for this service" | \
	tee -a $logfile
    cleanexit 1
endif
#
# Prevent the shell from interpreting any special
# _ characters contained within the grep targets.
set noglob
#
# Define a grep target to match a generic numerical IP address.
set iptrg = '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
#
# Check for the correctness of the IP address.
echo "$raddr" | grep -q "^$iptrg"'$'
set error = $status
#
# If it is wrong, then exit in error.
if ( $error != 0 ) then
    echo "${name}: ERROR:" >> $logfile
    echo -n "UN=$ru${tab}ZN=$rz${tab}IP=$ra$tab" >> $logfile
    date >> $logfile
    echo "${name}: ERROR: error in address $raddr" | \
	tee -a $logfile
    cleanexit 1
endif
#
# Restore the interpretation of special characters by the shell.
unset noglob
#
# Update the zone.
echo '</font>'
echo '<font size=3>'
echo '<pre>'
echo Updating the $rzone zone...
if ( $rpflg ) then
    ssh $pdnss /usr/lib/dynahost/update-dnszone "$rzone" "$raddr"
else
    /usr/lib/dynahost/update-dnszone "$rzone" "$raddr"
endif
#
# Verify whether a secondary DNS server is defined.
if ( "$sdnss" != "" ) then
    #
    # Update the secondary DNS server.
    echo Updating the secondary DNS server...
    if ( $rsflg ) then
	ssh $sdnss "rm -f /var/cache/bind/$rzone.zone"
	ssh $sdnss "rm -f /var/cache/bind/$rzone.revzone"
	#
	# Handling the migration from bind to bind9;
	# _ either one may exist, and bind9 requires
	# _ a restart rather than a reload; in order
	# _ to avoid the specificities of the root
	# _ shell on the remote machine, just run
	# _ both in sequence.
	ssh $sdnss /etc/init.d/bind reload
	ssh $sdnss /etc/init.d/bind9 restart
	#
    else
	rm -f "/var/cache/bind/$rzone.zone"
	rm -f "/var/cache/bind/$rzone.revzone"
	#
	# Handling the migration from bind to bind9;
	# _ either one may exist, and bind9 requires
	# _ a restart rather than a reload.
	if ( -x /etc/init.d/bind ) then
	    /etc/init.d/bind reload
	else if ( -x /etc/init.d/bind9 ) then
	    /etc/init.d/bind9 restart
	endif
	#
    endif
    #
endif
#
# The mail relay part of the update is only done if the remote
# _ zone is listed in the mail-relay configuration file.
#
# Only do this if the configuration file exists.
set mailfile = /etc/dynahost/mailrelaydns.conf
if ( -f $mailfile ) then
    #
    # Get the record of the configuration file for this zonename.
    set record = `grep "^[ $tab]*${rzone}[ $tab]" $mailfile`
    #
    # Only do this if the record exists.
    if ( "$record" != "" ) then
	#
	# Extract the hostname of the mail relay server
	# _ from the record, if it is listed there.
	if ( $#record > 1 ) then
	    set msrvr = $record[2]
	    #
	    # Raise the mail-server flag if needed.
	    if ( "$msrvr" != "$shost" && \
		 "$msrvr" != "$fhost" && \
		 "$msrvr" != "$lhost" && \
		 "$msrvr" != "$ihost" ) then
		set rmflg = 1
	    else
		set rmflg = 0
	    endif
	#
	# By default the mail relay server is the local host.
	else
	    set msrvr = "$shost"
	    #
	    # Lower the mail-server flag.
	    set rmflg = 0
	    #
	endif
	#
	# Update the mail client relay authorization.
	echo Updating the mail client relay authorization...
	if ( $rmflg ) then
	    ssh $msrvr /usr/lib/dynahost/update-dnsmailrelay "$rzone" "$raddr"
	else
	    /usr/lib/dynahost/update-dnsmailrelay "$rzone" "$raddr"
	endif
	#
    endif
    #
endif
echo '</pre>'
echo '</font>'
#
# Log the event.
echo -n "UN=$ru${tab}ZN=$rz${tab}IP=$ra$tab" >> $logfile
date >> $logfile
#
# Done.
echo '<font size=4>'
echo "${name}: done with address $raddr for zone $rzone"
cleanexit 0
