#!/bin/sh

# Shell script to collect and send configuration data for SCC.
# Copyright (C) 2001-2004 Open Challenge B.V.
# Copyright (C) 2004-2005 OpenEyeT Professional Services.
#
# 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; either version 2, or (at your option)
# any later version.
#
# 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 for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.
# If not, write to the Free Software Foundation,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Contact information: www.OpenEyeT.nl/scc/index.html 

# SCC-release:	1.6.26
# file-version:	$Revision: 1.68 $
 
 
ProgName=${0##*/};			export ProgName

SCC_BIN=/opt/scc/bin
SCC_TOP=/var/opt/scc
export SCC_BIN SCC_TOP

export SCC_DATA=${SCC_TOP}/data
export SCC_TMP=${SCC_TOP}/tmp
export SCC_CONF=/etc/opt/scc/conf

export TMPDIR=${SCC_TMP}
export TMP=${SCC_TMP}

export SHELL=/bin/sh
export LANG=C

umask 077

mkdir -p ${SCC_DATA} ${SCC_TMP} 2>/dev/null

PATH=${SCC_BIN}:/sbin:/usr/sbin:/usr/bin:/bin;	export PATH

# Use the following utilities for SunOS.
if [ -x /usr/ccs/bin/what ]
then
	alias what=/usr/ccs/bin/what
fi
if [ -x /usr/xpg4/bin/awk ]
then
	alias awk=/usr/xpg4/bin/awk
fi
if [ -x /usr/xpg4/bin/grep ]
then
	alias grep=/usr/xpg4/bin/grep
fi
if [ -x /usr/xpg4/bin/tr ]
then
	alias tr=/usr/xpg4/bin/tr
fi

test_dir="${SCC_TMP}/scc-d-$$"
TMP_FILE="${SCC_TMP}/scc-f-$$"
SCC_PSEUDO_ALTERNATE="${SCC_TMP}/scc-a-$$"

SYNTAX="Syntax error, use: ${ProgName} [ -a <alt> ] [ -c <remark> ] [ -d <delay> ] [ -e <mod> ] [ -f ] [ -i <smtp> ] [ -I <ident> ] [ -k <key> ] [ -m <max> ] [ -n ] [ -p <prog> ] [ -s <dest> ] [ -t ] [ -v <host> ] [ -V ]"

empty_files=0
prog=mail
max_interval=300
if tty -s
then
	# Waiting is meant for lots of jobs scheduled at the same time.
	max_interval=0			# Do not wait when interactive.
fi
alternate_dir=""
key_file=""
max_months=0
dest=""
mods=""
remark=""
fqdn=0
do_run=1
smtp_server=""
ssh_identity=""
virtual_host=""
virtual_host_opt=""
while [ $# -gt 0 ]
do
	case "${1}" in
	-a)	alternate_dir="${2}";
		if [ ! -d "${alternate_dir}" ]
		then
			echo "${ProgName}: cannot access ${alternate_dir}" >&2
			exit 2
		fi
		shift 2;;

	-c)	remark=$(echo "${2}" | tr -d "\012")	# be sure that the remark is single-line
		shift 2;;

	-d)	case "${2}" in
		[0-9]*)	max_interval=${2};;
		*)	echo "${ProgName}: non-numeric interval: ${2}" >&2
			exit 1;;
		esac
		shift 2;;

	-e)	mods="${2}";			# Pass on to scc-log
		shift 2;;

	-f)	fqdn=1
		shift 1;;

	-i)	smtp_server="${2}";
		prog=smtp;		# No need for -p smtp with -i option
		shift 2;;

	-I)	if [ ! -f "${2}" ]
		then
			echo "${ProgName}: cannot access identity_file ${2}" >&2
			exit 1;
		fi
		ssh_identity="-i ${2}"		# -i option for scp.
		prog=scp
		shift 2;;

	-k)	key_file="${2}";
		shift 2;;

	-m)	case "${2}" in
		[0-9]*)	max_months=${2};;
		*)	echo "${ProgName}: non-numeric argument for -m option: ${2}" >&2
			exit 1;
		esac
		shift 2;;

	-n)	do_run=0
		shift 1;;

	-p)	if [ -n "${dest}" ]
		then
			echo "${ProgName}: -p option must be used prior to -s option" >&2
			exit 2
		fi
		case "${2}" in
		cp|ftp|pull|rcp|scp|mail|smtp)	prog="${2}";;
		*)				echo "${ProgName}: unknown transfer-method: ${2}" >&2
						exit 2;;
		esac
		shift 2;;

	-s)	dest="${2}"
		shift 2;;

	-t)	empty_files=1
		shift 1;;

	-v)	virtual_host_opt=" -v ${2}";	# Pass on to scc-log
		virtual_host="${2}";
		shift 2;;

	-V)	echo "1.6.26"
		exit 0;;

	-*)	echo ${SYNTAX} >&2
		exit 1;;

	*)	break;;
	esac
done

if [ $# -ne 0 ]
then
	echo "${SYNTAX}" >&2
	exit 1
fi

if [ ${empty_files} -eq 1 -a "${alternate_dir}" ]
then
	echo "${ProgName}: cannot use -t option combined with -a option" >&2
	exit 2
fi

if [ "${prog}" = "pull" ]
then
	# scc executes and places the files in a directory that is inspected later by scc-srv.
	max_interval=0
	dest="${SCC_DATA}/transfer"
	mkdir -p "${dest}"
fi

our_name=$(hostname)
# Determine the domain.
if [ "${our_name}" = "${our_name%%.*}" ]
then
	# No domain available in hostname.
	DOMAIN=""
	if [ -x /bin/dnsdomainname ]
	then
		DOMAIN=$(/bin/dnsdomainname 2>/dev/null)
	fi
	if [ "${DOMAIN}" = "" ]
	then
		DOMAIN=$(awk '/^domain/ { print $2 }' /etc/resolv.conf 2>/dev/null | tail -1)
	fi
	if [ "${DOMAIN}" = "" ]
	then
		DOMAIN=$(nslookup ${our_name} 2>/dev/null | sed -n "s/^Name.*${our_name}\.//p")
	fi
	if [ "${DOMAIN}" = "" ]
	then
		DOMAIN=$(awk '/^search/ { print $2 }' /etc/resolv.conf 2>/dev/null | tail -1)
	fi
else
	DOMAIN=${our_name#*.}
fi
if [ -n "${virtual_host}" ]
then
	our_name="${virtual_host}"
fi
if [ ${fqdn} -gt 0 ]
then
	if [ -n "${DOMAIN}" ]
	then
		our_name="${our_name%%.*}.${DOMAIN}"
	else
		echo "${ProgName}: cannot determine domainname" >&2
		exit 2
	fi
else
	our_name=${our_name%%.*}	# Erase domain.
fi

MAIL_NAME=scc-transfer-data
PASSPHRASE="passphrase"

trap "rm -rf ${SCC_PSEUDO_ALTERNATE} ${TMP_FILE} ${SCC_TMP}/scc*tar ${SCC_TMP}/scc*signal ${SCC_TMP}/${MAIL_NAME}* ${SCC_TMP}/${PASSPHRASE}* ${test_dir}" 0
trap "exit 2" 1 2 3 15

if [ ${empty_files} -gt 0 ]
then
	# Create the empty test-files.
	mkdir ${test_dir}
	cd ${test_dir}
	for s in cur log log.html html
	do
		touch scc.${our_name}.${s}
	done
	max_interval=0			# do not wait when testing.
else
	if [ ${do_run} -eq 1 ]
	then
		if [ -z "${alternate_dir}" ]
		then
			# Produce new, real SCC-data
			nice ${SCC_BIN}/scc-log -c "${remark}" -e "${mods}" -m "${max_months}" ${virtual_host_opt}
			if [ $? -ne 0 ]
			then
				exit 1
			fi
		fi
	else
		max_interval=0		# do not wait when no run is required.
	fi

	cd ${SCC_DATA}
fi

# Only send the files when we have a destination.
if [ -z "${dest}" ]
then
	exit 0
fi

if [ ${max_interval} -gt 1 ]
then
	# Wait for a maximized, random interval
	if [ -z "${RANDOM}" ]
	then
		# No ${RANDOM}, use the seconds, minutes and hours. Add 10 to avoid multiplying with 0.
		RANDOM="$(date '+%H:%M:%S' | awk -F: '{ print ( 10 + $1 ) * ( 10 + $2 ) * ( 10 + $3 ) }' )"
		export RANDOM
	fi
	sleep $(( ${RANDOM} % ${max_interval} ))
fi

# Check whether data for pseudo hosts was split off from the main snapshot.
# Use the ${alternate_dir} for the temporary symbolic links to the files for the pseudo hosts.
# When ${alternate_dir} does not exist, we create a temporary directory (and remove it at the end of this script).
split_file=${SCC_CONF}/scc-split.conf
split_hosts=""
if [ -s "${split_file}" -a -z "${virtual_host}" ]
then
	split_hosts="$(awk -F"|" '/^host\|/ { print $2 }' ${split_file} | sort -u)"
fi
if [ "${split_hosts}" ]
then
	if [ -z "${alternate_dir}" ]
	then
		alternate_dir="${SCC_PSEUDO_ALTERNATE}"
		mkdir -p "${alternate_dir}"
	fi
	for host in ${our_name} ${split_hosts}
	do
		for e in cur log html log.html
		do
			ln -s ${SCC_DATA}/scc.${host}.${e} ${alternate_dir}/scc.${host}.${e}
		done
	done
fi

if [ "${alternate_dir}" ]
then
	cd "${alternate_dir}"
fi
start_dir="$(pwd)"

if [ "${alternate_dir}" ]
then
	# Check all snapshots.
	for f in scc.*.cur
	do
		host="${f%.cur}"
		echo "${host#scc.}"
	done
else
	if [ ${fqdn} -eq 1 ]
	then
		for s in cur html log log.html
		do
			ln -s scc.${our_name%%.*}.${s} scc.${our_name}.${s}
		done
		echo ${our_name}
	else
		echo ${our_name%%.*}
	fi
fi						|
while read host
do
	cd "${start_dir}"

	suffix=""
	p_exe="$(which gzip 2>/dev/null)"
	if [ -x "${p_exe}" ]
	then
		suffix=".gz";
	else
		p_exe="$(which compress 2>/dev/null)"
		if [ -x "${p_exe}" ]
		then
			suffix=".Z";
		else
			p_exe="cat"
		fi
	fi

	REMOTE_NAME=scc.${host}.tar
	REMOTE_SIGNAL=scc.${host}.signal

	if [ ! -f scc.${host}.cur ]
	then
		# Split hosts with remote compares can be absent.
		# Do not send any data in this case.
		cd ${SCC_TMP}
		continue
	fi

	# Pack the data in a single file, follow symbolic links.
	tar -chf - scc.${host}.cur scc.${host}.log scc.${host}.log.html scc.${host}.html	|
	"${p_exe}" >${SCC_TMP}/${REMOTE_NAME}${suffix}

	if [ "${alternate_dir}" -o ${fqdn} -eq 1 ]
	then
		# The alternate directory can contain symbolic links.
		# The FQDN files are symbolic links and no longer needed.
		for s in cur html log log.html
		do
			if [ -h scc.${host}.${s} ]
			then
				rm -f scc.${host}.${s}
			fi
		done
	fi

	cd ${SCC_TMP}

	case "${prog}" in
	mail|smtp)	which uuencode 2>/dev/null >/dev/null
		if [ $? -ne 0 ]
		then
			echo "${ProgName}: uuencode not found" >&2
			exit 2
		fi

		# Encryption required?
		if [ -n "${key_file}" ]
		then
			e_exe="$(which openssl 2>/dev/null)"
			if [ ! -x "${e_exe}" ]
			then
				echo "${ProgName}: openssl not found" >&2
				exit 2
			fi

			if [ ! -f ${PASSPHRASE} ]
			then
				# Generate a random passphrase.
				# Replace \0 and \n to avoid short (possibly empty) passwords.
				openssl rand 40			|
				tr -s "\012\000" "n0" > ${PASSPHRASE}
			fi

			# Encrypt the scc-data with triple DES, using the random passphrase.
			openssl	des3				\
				-in ${REMOTE_NAME}${suffix}	\
				-out ${MAIL_NAME}${suffix}.e	\
				-pass file:./${PASSPHRASE}	\
				-e				\
				-salt -S 83AF2E2D8BE716C2

			if [ ! -f ${PASSPHRASE}.e ]
			then
				# Encrypt the passphrase with the public key.
				openssl	rsautl			\
					-in ${PASSPHRASE}	\
					-out ${PASSPHRASE}.e	\
					-inkey "${key_file}"	\
					-pubin			\
					-encrypt 2>/dev/null
			fi

			# Combine the encrypted scc-data and the encrypted passphrase.
			# The scc-server has to:
			# - untar the combined, encrypted scc-data and passphrase
			# - decrypt the passphrase (using it's own private key)
			# - decrypt the scc-data with the decrypted passphrase
			tar cf ${REMOTE_NAME}${suffix}.e.tar ${PASSPHRASE}.e ${MAIL_NAME}${suffix}.e
			rm -f ${PASSPHRASE} ${PASSPHRASE}.e ${REMOTE_NAME}${suffix} ${REMOTE_NAME}${suffix}.e

			suffix="${suffix}.e.tar"
		fi

		if [ "${prog}" = "mail" ]
		then
			uuencode ${MAIL_NAME}${suffix} <${REMOTE_NAME}${suffix}		|
			mail "${dest}"
		else
			if [ -z "${smtp_server}" ]
			then
				# Split the email-address into host and account
				mail_account=${dest%%@*}
				smtp_server=${dest##*@}
			else
				mail_account=${dest}
			fi

			# Use smtp to transfer the data. 
			# Use sleep to avoid that our commands are sent too fast to the SMTP-server.
			(
				if [ -z "${DOMAIN}" ]
				then
					from_host="${our_name}"
				else
					from_host="${our_name%%.*}.${DOMAIN}"
				fi

				sleep 5
				echo "helo ${our_name}"
				sleep 5
				echo "mail from: root@${from_host}"
				sleep 5
				echo "rcpt to: ${mail_account}"
				sleep 5
				echo "data"
				sleep 5
				echo "to: ${mail_account}"
				echo ""
				sleep 5
				uuencode ${MAIL_NAME}${suffix} <${REMOTE_NAME}${suffix}
				echo "."
				sleep 5
				echo "quit"
				sleep 5
			)	|
			telnet ${smtp_server} 25 >/dev/null 2>&1
			# Remove the redirection of stdout and stderr to debug the communication with the smtp-server.
		fi
		;;

	rcp)	# Produce an empty signal-file to indicate that transfer is in progress.
		>${REMOTE_SIGNAL}
		rcp ${REMOTE_SIGNAL} ${dest}

		# Transfer the packed files.
		rcp ${REMOTE_NAME}${suffix} ${dest}

		# Replace the empty signal-file to indicate that transfer is complete.
		echo "done" >${REMOTE_SIGNAL}
		rcp ${REMOTE_SIGNAL} ${dest}
		;;

	pull)	# Produce an empty signal-file to indicate that transfer is in progress.
		>${dest}/${REMOTE_SIGNAL}

		# Transfer the packed files.
		cp ${REMOTE_NAME}${suffix} "${dest}"

		# Replace the empty signal-file to indicate that transfer is complete.
		echo "done" >"${dest}/${REMOTE_SIGNAL}"
		;;

	scp)	# Produce an empty signal-file to indicate that transfer is in progress.
		>${REMOTE_SIGNAL}
		scp -q ${ssh_identity} ${REMOTE_SIGNAL} ${dest} >/dev/null

		# Transfer the packed files.
		scp -q ${ssh_identity} ${REMOTE_NAME}${suffix} ${dest} >/dev/null

		# Replace the empty signal-file to indicate that transfer is complete.
		echo "done" >${REMOTE_SIGNAL}
		scp -q ${ssh_identity} ${REMOTE_SIGNAL} ${dest} >/dev/null
		;;

	cp)	if [ -d "${dest}" ]
		then
			# Produce an empty signal-file to indicate that transfer is in progress.
			>${dest}/${REMOTE_SIGNAL}

			# Move the packed files to the destination
			rm -f ${dest}/${REMOTE_NAME}*
			mv ${REMOTE_NAME}${suffix} ${dest}

			# Replace the empty signal-file to indicate that transfer is complete.
			echo "done" >>${dest}/${REMOTE_SIGNAL}
		else
			echo "${ProgName}: cannot access target directory: ${dest}" >&2
		fi
		;;

	ftp)	# ${dest} is <host>:<dir>
		host=${dest%:*}
		dir=${dest#*:}

		# Produce an empty signal-file to indicate that transfer is in progress.
		>${REMOTE_SIGNAL}
		ftp ${host} <<-_X_
			cd ${dir}
			bin
			put ${REMOTE_SIGNAL}
		_X_

		# Transfer the packed files to the destination
		ftp ${host} <<-_X_
			cd ${dir}
			bin
			put ${REMOTE_NAME}${suffix}
		_X_


		# Replace the empty signal-file to indicate that transfer is complete.
		echo "done" >${REMOTE_SIGNAL}
		ftp ${host} <<-_X_
			cd ${dir}
			bin
			put ${REMOTE_SIGNAL}
		_X_
		;;
	esac

	rm -f ${REMOTE_SIGNAL} ${REMOTE_NAME}${suffix}
done

exit 0
