#! @SH@
#
# $NetBSD: audit-system,v 1.5 2014/12/05 14:31:49 schmonz Exp $
#
# Copyright (c) 2008 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Alistair Crooks.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

AWK=@AWK@
CHMOD=@CHMOD@
CKSUM=@CKSUM@
MKDIR="@MKDIR@"
FIND=@FIND@
MV=@MV@
RM=@RM@

FORMAT_MAJOR=1
FORMAT_MINOR=0
FORMAT_TEENY=0

# print a usage message and then die
usage() {
        argv0="${1##*/}"
        cat <<EOF
$2
Usage: $argv0 [-duv]
    -d : Download the system-vulnerabilities file before anything else
    -u : Download the system-vulnerabilities file only
    -v : Verbose mode
EOF
        exit 1
}

# set some defaults
: ${SYSVULNDIR=@SYSVULNDIR@}
: ${FETCH_PROTO=ftp}
: ${FETCH_TOOL=@FETCH_TOOL@}
: ${FETCH_TOOL_ARGS="-o"}
scriptdir="@SCRIPT_DIR@"
download=no
download_only=no
verbose=no
neednew=no
tools="@STAT@ @OBJDUMP@ @CKSUM@ @FETCH_TOOL@ @IDENT@"

# check the integrity of a system-vulnerabilities file
check_integrity() 
{
	# see if the file got damaged while it was being downloaded
	recordedsum=$(${AWK} '$1 == "#CHECKSUM" { print $3 }' $1)
	recordedalg=$(${AWK} '$1 == "#CHECKSUM" { print $2 }' $1)

	if [ "x${recordedsum}" = "x" -o "x${recordedalg}" = "x" ]; then
		echo "ERROR: Error in downloading"
		${RM} -f "$1"
		exit 1
	fi
	
	calcsum=$(${AWK} '$1 == "#CHECKSUM" || /\$NetBSD.*/ { next } { print }' $1 | ${CKSUM} -a ${recordedalg})
	if [ "x${recordedsum}" != "x${calcsum}" ]; then
		echo "ERROR: Checksum mismatch"
		${RM} -f "$1"
		exit 1
	fi
}

# check all the tools we need are available
for t in ${tools} ; do
	if [ ! -x ${t} ]; then
		echo "ERROR: Required tools not found"
		exit 1
	fi
done

# process any command line arguments
while [ $# -gt 0 ]; do
        case "$1" in
        -d)     download=yes ;;
        -u)     download_only=yes ;;
        -v)     verbose=yes ;;
        *)	usage "$0" "Unknown option $1"
        esac
        shift
done

# check for incompatible command line options
if [ "x${download}" = "xyes" -a "x${download_only}" = "xyes" ]; then
	echo "ERROR: Invalid command line options specified"
	exit 1
fi

# if we have any configuration information, then read it
if [ -r @PKG_SYSCONFDIR@/audit-system.conf ]; then
	if [ "x${verbose}" = "xyes" ]; then
        	echo "Reading settings from @PKG_SYSCONFDIR@/audit-system.conf"
	fi
        . @PKG_SYSCONFDIR@/audit-system.conf
fi

# check FETCH_PROTO is sane
case ${FETCH_PROTO} in
http) 	;;
ftp)	;;
*)	echo "ERROR: Unsupported FETCH_PROTO specified"
	exit 1
	;;
esac

# setup what we know is sane so far
#vulsource="${FETCH_PROTO}://ftp.NetBSD.org/pub/NetBSD/misc/agc/audit-system/system-vulnerabilities"
vulsource="${FETCH_PROTO}://localhost/pub/NetBSD/system-vulnerabilities"
vuls="${SYSVULNDIR}/system-vulnerabilities"
newvullist="${SYSVULNDIR}/system-vulnerabilities.$$"

# try to download the system vulnerability list, as requested
# the integrity of the list is checked below
# so just issue a warning if there was a failure
if [ "x${download}" = "xyes" -o "x${download_only}" = "xyes" ]; then

	# check we can get to ${SYSVULNDIR}
	if [ ! -d ${SYSVULNDIR}/. ]; then
		echo "Creating ${SYSVULNDIR}"
		${MKDIR} ${SYSVULNDIR}
	fi
	echo audit-system > ${SYSVULNDIR}/.cookie
	if [ -f ${SYSVULNDIR}/.cookie ]; then
		${RM} ${SYSVULNDIR}/.cookie
	else
		echo "ERROR: Unable to write to ${SYSVULNDIR}"
		exit 1
	fi

	# get the file
	${FETCH_TOOL} ${FETCH_TOOL_ARGS} "${newvullist}" "${vulsource}"

	# see if we got a file
	if [ ! -f "${newvullist}" ]; then
		echo "ERROR: Download of vulnerabilities file failed"
		exit 1
	fi

	check_integrity "${newvullist}"

	# test to see if file has been changed
	if [ -f "${vuls}" ]; then
		oldsum=$(${AWK} '$1 == "#CHECKSUM" { print $3 }' "${vuls}")
		if [ "x${oldsum}" != "x${calcsum}" ]; then
			neednew=yes
		fi
	else
		neednew=yes
	fi

	# if we need the new file, move it into position
	if [ "x${neednew}" = "xyes" ]; then
		echo "System vulnerabilities file has been updated"
		${CHMOD} a+r "${newvullist}"
		${MV} -f "${newvullist}" "${vuls}"
	else
		echo "No change from existing system vulnerabilities file"
		${RM} -f "${newvullist}"
	fi
fi

# if download_only was specified then we end here
if [ "x${download_only}" = "xyes" ]; then
	exit 0
fi

# check for missing vulnerabilities file before we continue
if [ ! -f "${vuls}" ]; then
	echo "ERROR: Missing system vulnerabilities file"
	exit 1
fi

# check for old vulnerabilities file if we're being verbose
if [ "x${verbose}" = "xyes" ]; then
        if [ -n "$(${FIND} ${vuls} -ctime +7)" ]; then
		echo "WARNING: system vulnerabilities file is more than a week old"
	fi
fi

# check format version of vulnerabilities file
file_major=$(${AWK} '/^#[ \t]*FORMAT/ { split($NF, a, "\\."); print a[1]; exit; }' "${vuls}")
file_minor=$(${AWK} '/^#[ \t]*FORMAT/ { split($NF, a, "\\."); print a[2]; exit; }' "${vuls}")
file_teeny=$(${AWK} '/^#[ \t]*FORMAT/ { split($NF, a, "\\."); print a[3]; exit; }' "${vuls}")

if [ -z "${file_teeny}" ] ; then
	file_teeny=0
fi

if [ "x${file_major}" = "x" -o "x${file_minor}" = "x" ]; then
	echo "ERROR: Error in downloading"
	exit 1
fi

if [ "${file_major}" -gt "${FORMAT_MAJOR}" -o "${file_minor}" -gt "${FORMAT_MINOR}" ]; then
	echo "ERROR: Unsupported file format version"
	echo "Please ensure you are running the latest version of audit-system"
	exit 1
fi

if [ "${file_major}" -lt "${FORMAT_MAJOR}" -o "${file_minor}" -lt "${FORMAT_MINOR}" ]; then
	echo "ERROR: Old version of system-vulnerabilities file detected"
	exit 1
fi

# check integrity of vulnerabilities file
check_integrity "${vuls}"

${AWK} -v scriptdir="${scriptdir}" '
/^#.*/	{ next }
{
	cmd = sprintf("v=$(%s/audit-%s %s) && test -e %s && test $v -lt %s && echo %c%s (version $v before %s) could have a %s vulnerability (severity %s) - see %s%c",
		scriptdir, $2, $1,
		$1,
		$3,
		34, $1, $3, $4, $5, $6, 34);
	system(cmd);
}
' "$vuls"
