# -*- sh -*-
#
#     tiger - A UN*X security checking system
#     Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford
#
#    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 1, 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.
#
#     Please see the file `COPYING' for the complete copyright notice.
#
#  config (top level) - 06/14/93
#
# 08/30/2006 jfs  Attempt to create working directory if it does not exist 
#                 (Debian bug #366919)
# 06/22/2005 jfs  Abort signature generation if the user does not 
#                 have permissions to change the directories signatures are
#                 stored in.
# 01/21/2005 jfs  Safer creation of $WORKDIR if undefined 
# 08/13/2004 jfs  Setup all locales as 'C' (Debian bug  #270108)
# 04/28/2004 jfs  Changed -f RCFILE check to -r to allow use through ssh
#                 as suggested by Falk Siemonsmeier:
#                  cat /etc/tiger/tigerrc | ssh tiger -c /dev/stdin
# 01/13/2004 jfs  Added check when running with -f since on some (unconfigured)
#		  systems this might fail.
# 08/19/2003 jfs  tara -> Tiger in the usage
# 08/13/2003 jfs  Added some of ARSC changes including:
#                 - support for signature generation (enhanced with also
#                   file_access_list generation and better error checking)
#                 - usage printing (but modified it to only exit with error
#                   if -h has not been issued)
#                 - Moved RCFILE check down so that RCFILEs can be used in 
#                   common locations if not specified
#                 Also removed CRACK, CRACKDIR and REPORTER exports since
#                 these can now be done from the configuration files
#                 (with the loc_override)
# 04/26/2003 jfs  Added a -q(uiet) option (to be used when using tigercron)
# 04/21/2003 jfs  Modified to only use hostname -f for Linux _and_
#		  moved hostname check after RCFILE parsing!
# 04/15/2003 jfs  Modified to support -B to work in the local dir 
# 04/29/93 dls  Added support for 'tigerrc' file.
#
#-----------------------------------------------------------------------------
#
# space, tab, newline

# Running on the dir defined by the tarball
# Comment this if you want to use Tiger defaults
TigerLogDir='log/'
TigerWorkDir='run/'
TigerConfigDir='.'

# This is important to avoid problems with commands that are
# dependant on the defined language environment
LANG="C"
LC_ALL="C"
export LANG LC_ALL
error_siggen()
{
  dir=$1
  file=$2
  tmpdir=$3
  echo "There is already a $file file in $tmpdir"
  echo "Please remove it and rerun Tiger"
  cd $dir
  exit 1
}

do_siggen()
{
  echo "  Generating new digital signatures for binaries"
  set X `$BASEDIR/util/gethostinfo` unknown unknown unknown
  OS=${OS:=$2}
  REV=${REV:=$3}
  ARCH=${ARCH:=$4}
  if [ ! -d "$BASEDIR/systems/$OS/$REV/$ARCH/" ] 
  then
        printf "Creating the directory $BASEDIR/systems/$OS/$REV/$ARCH/ where signatures will be stored..."
    	mkdir -p "$BASEDIR/systems/$OS/$REV/$ARCH/" || { echo "Cannot create directory '$BASEDIR/systems/$OS/$REV/$ARCH/'!" >&2; exit 1; }
	echo "...created"
  fi
# NOTE: I'm not sure it's ok to create the directory since
# if there are no config files in it or in it's parent the
# default might not apply
  PWD=`pwd`
  cd $WORKDIR
  if [ ! -f "signatures.$OS-$REV-$ARCH" ] 
  then
    printf "Generating and installing signatures..."
    $BASEDIR/util/mksig
    $BASEDIR/util/installsig "signatures.$OS-$REV-$ARCH"
    rm "signatures.$OS-$REV-$ARCH"
    echo "...done"
  else
    error_siggen "$PWD" "signatures.$OS-$REV-$ARCH" "$WORKDIR"
  fi
  if [ ! -f "file_access_list.$OS-$REV-$ARCH" ] 
  then
    printf "Generating and installing file access lists..."
    $BASEDIR/util/mkfilelst
    mv "file_access_list.$OS-$REV-$ARCH" $BASEDIR/systems/$OS/$REV/$ARCH/file_access_list || { echo "Cannot move files to '$BASEDIR/systems/$OS/$REV/$ARCH/'!" >&2; exit 1; }
    echo "...done"
  else
    error_siggen "$PWD" "file_access_list.$OS-$REV-$ARCH" "$WORKDIR"
  fi
  cd $PWD
  exit 0
}

do_usage()
{
echo "Tiger, version $TIGERVERSION"
echo "Usage: ./tiger [-vthqGSH]  [-B dir] [-l dir|@host] [-w dir] [-b dir] [-e|-E] [-c config] [-A arch] [-O os] [-R release]"
echo ""
echo "       -v     Show the Tiger version."
echo ""
echo "       -t     Run in test mode."
echo ""
echo "       -h     Show usage (this help)."
echo ""
echo "       -q     Supress messages to be as quiet as possible, only "
echo "              security messages will be shown."
echo ""
echo "       -B name"
echo "              Specify  the directory where tiger is installed.  If"
echo "              not specified, '$BASEDIR' is used."
echo ""
echo "       -l name"
echo "              Specify the name of the directory where Tiger  will"
echo "              write  the  security  report.  This defaults to    "
echo "              '$LOGDIR'. The filename  of  the report will be of "
echo "              the form 'security.report.host-name.date.time.'    "
echo "              If the directory  begins  with a "@", the name will"
echo "              be interpreted as a tiger logging server."
echo ""
echo "       -w name"
echo "              Specify a directory to  use  for  creating  scratch"
echo "              files.  This defaults to '$WORKDIR'."
echo ""
echo "       -b name"
echo "              Specify  the directory which contains (or will con-"
echo "              tain) the binaries generated from  the  C  modules."
echo "              If  the  systems  directories contain all the bina-"
echo "              ries, they will be used directly  from  there.   If"
echo "              not,  then  if  the  bindir  contains the binaries,"
echo "              these will be used.  If none are  found  in  either"
echo "              place,  then an attempt will be made to compile the"
echo "              C code and install the executables into the bindir."
echo ""
echo "       -c name"
echo "              Specify  an  alternate  name for the tigerrc control"
echo "              file.  The default is '$RCFILE'."
echo ""
echo "       -e     This option will cause explanations to be  inserted"
echo "              into  the  security  report following each message."
echo "              This can greatly increase the size of  the  report,"
echo "              as explanations may appear repeatedly."
echo ""
echo "       -E     This  option  indicates that a separate explanation"
echo "              report should be  created,  with  explanations  for"
echo "              each  type  of  message  only  appearing once.  The"
echo "              filename of the explanation report will be  of  the"
echo "              form 'explain.report.hostname.date.time.'"
echo ""
echo "       -G     Generate the signatures (MD5 hashes and file permissions)"
echo "              for system binary files."
echo ""
echo "       -H     This option will format the report into HTML creat-"
echo "              ing local links to the problem descriptions."
echo ""
echo "       -S     This option indicates that a surface level check of"
echo "              the  configuration  files  of  any diskless clients"
echo "              served by this machine should  be  checked  at  the"
echo "              same  time.   The checks will not be as in depth as"
echo "              they would be if run on the client itself."
echo ""
echo "Overrides for values detected  by the configuration system:"
echo "       -A arch"
echo "              Specify  an  alternate  architecture for tiger"
echo ""
echo "       -O os"
echo "              Specify  an  alternate  operating system for tiger"
echo ""
echo "       -R release"
echo "              Specify  an  alternate  operating system release  "
echo "              for tiger"
echo ""
echo "Report bugs at http://savannah.nongnu.org/projects/tiger"
}

checkfile()
{
  _rcfile=$1
  _rcpath=${2:=$1}
  _status=1
  
  if [ -d $_rcfile ]; then
    echo "--CONFIG-- [con001c] Ignoring config file $_rcpath, (directory)"
  elif [ -f $_rcfile ]; then
    _status=0
    _permit=`$LS $LSLINK -l $_rcfile |
             $AWK '{printf("%s%s", substr($1,6,1), substr($1,9,1));}'`
    [ "$_permit" != "--" ] && {
      echo "--CONFIG-- [con003c] Ignoring config file $_rcpath, (world and/or group writable)"
      _status=1
    }
  fi

  return $_status
}

[ "$CONFIGURED_ALREADY" != "YES" ] && {

  umask 077

  CONFIGURED_ALREADY=YES

  if [ -n "$TIGERHOMEDIR" -a "$TIGERHOMEDIR" != '.' ]; then
    BASEDIR="$TIGERHOMEDIR"
  elif [ -n "$TigerInstallDir" -a "$TigerInstallDir" != '.' ]; then
    BASEDIR="$TigerInstallDir"
  elif [ ! -d ./systems -a -d ../systems ]; then
    BASEDIR='..'
  else
    BASEDIR='.'
  fi

  LOGDIR=${TigerLogDir:=.}
  WORKDIR="$TigerWorkDir"
  RCFILE=${TigerConfigDir:=.}/tigerrc
  IGNORE_FILE=${TigerConfigDir:=.}/tiger.ignore
  TIGERHOMEDIR="$BASEDIR"
  EXPLAINREPORT=N
  SERVERCHECK=N
  Tiger_TESTMODE=N
  HTML=N
  export BASEDIR LOGDIR WORKDIR BINDIR EXPLAINREPORT SERVERCHECK 
  export TIGERHOMEDIR RCFILE IGNORE_FILE 
  export Tiger_TESTMODE TigerCleanup HTML
  doversion=0
  
  while [ $# != 0 ]
  do
    case $1 in
     -v) doversion=1;;
     -h) do_usage; exit 0;;
     -B) BASEDIR=$2; shift;;
     -l) LOGDIR=$2; shift;;
     -w) WORKDIR=$2; shift;;
     -b) BINDIR=$2; shift;;
     -c) RCFILE=$2; shift;;
     -e) EXPLAINREPORT=I;;
     -E) EXPLAINREPORT=Y;;
     -G) do_siggen;;
     -S) SERVERCHECK=Y;;
     -O) OS=$2; shift;;
     -A) ARCH=$2; shift;;
     -R) REV=$2; shift;;
     -t) Tiger_TESTMODE=Y;;
     -H) HTML=Y;;
     -q) QUIET=Y;;
      *) echo "--ERROR-- [con006e] Unknown option $1"; do_usage; exit 1;;
    esac
    shift;
  done

  TIGERVERSION="`/bin/cat $TIGERHOMEDIR/version.h 2>/dev/null`"
  [ ! -n "$TIGERVERSION" ] && TIGERVERSION="undetermined"
  export TIGERVERSION
  
  [ $doversion -eq 1 ] && {
    echo "tiger, version $TIGERVERSION"
    exit 0
  }

  if [ -z "$WORKDIR" ] ; then
	  WORKDIR=${TMPDIR:=/tmp}
	  ( umask 077; mkdir $WORKDIR/tiger.$$ ) || { echo "$0: Cannot create temporary directory" >&2; exit 1; }
	  WORKDIR="$WORKDIR/tiger.$$"
  fi
  # TODO: WORKDIR should be removed on exit if it is located in a temporary 
  # directory
  if [ ! -d "$WORKDIR" ] ; then
  	  echo "Configured working directory $WORKDIR does not exist" >&2
  	  if [ "$QUIET" != "Y" ] ; then
	  	echo "Creating working directory $WORKDIR"
		echo
	  fi
	  # TODO: -p switch is not portable
  	  if ! mkdir -p "$WORKDIR" >/dev/null 2>&1; then
	  	  echo "Configured working directory $WORKDIR cannot be created (should you use -w?)" >&2
		  exit 1
	  fi
  fi


  [ "$QUIET" != "Y" ] && echo "Configuring..."

  set X `$BASEDIR/util/gethostinfo` unknown unknown unknown
  OS=${OS:=$2}
  REV=${REV:=$3}
  ARCH=${ARCH:=$4}
  saveifs=$IFS
  IFS=.
  set X $REV
  IFS=$saveifs
  shift
  REL="$1"
  [ ! -n "$REL" ] && REL=$REV

  [ ! -n "$BINDIR" ] &&  eval BINDIR=${TigerBinDir:=$BASEDIR/bin}

  SCRIPTDIR=$BASEDIR/scripts
  export SCRIPTDIR

  [ "$QUIET" != "Y" ] &&  {
    echo " "
    echo "Will try to check using config for '$ARCH' running $OS $REV..."
  }

  CONFIG_LOC=${TIGERCONF:="$BASEDIR/systems"}

  if [ -f "$CONFIG_LOC/$OS/$REL/$REV/$ARCH/config" ]; then
    [ "$QUIET" != "Y" ] && echo "--CONFIG-- [con004c] Using configuration files for $OS $REV $ARCH."
    CONFIG_DIR="$CONFIG_LOC/$OS/$REL/$REV/$ARCH"
  elif [ -f "$CONFIG_LOC/$OS/$REL/$REV/config" ]; then
    [ "$QUIET" != "Y" ] && echo "--CONFIG-- [con004c] Using configuration files for $OS $REV."
    CONFIG_DIR="$CONFIG_LOC/$OS/$REL/$REV"
  elif [ -f "$CONFIG_LOC/$OS/$REL/config" ]; then
    [ "$QUIET" != "Y" ] &&  {
    echo "--CONFIG-- [con005c] Using configuration files for $OS $REV. Using"
    echo "           configuration files for generic $OS $REL."
    }
    CONFIG_DIR="$CONFIG_LOC/$OS/$REL"
  elif [ -f "$CONFIG_LOC/$OS/config" ]; then
    [ "$QUIET" != "Y" ] &&  {
    echo "--CONFIG-- [con005c] No configuration files for $OS $REV.  Using"
    echo "           configuration files for generic $OS."
    }
    CONFIG_DIR="$CONFIG_LOC/$OS"
  elif [ -f "$CONFIG_LOC/default/config" ]; then
    [ "$QUIET" != "Y" ] &&  {
    echo "--CONFIG-- [con007c] No configuration files for $OS.  Using default"
    echo "           configuration files.  Not all checks may be performed."
    CONFIG_DIR="$CONFIG_LOC/default"
    }
  else
    echo "--ERROR-- [con008e] No configuration files for $OS $REV and can't find the"
    echo "          default configuration files.  Terminating."
    exit 1
  fi
  CONFIG_FILE="$CONFIG_DIR/config"

  . $CONFIG_FILE

  [ ! -n "$TESTEXEC" ] && TESTEXEC="-f"
  [ ! -n "$TESTLINK" ] && TESTLINK="-h"

  OUTPUTMETHOD="$CAT"
  [ "$EXPLAINREPORT" != "N" ] && {
    OUTPUTMETHOD="$BASEDIR/tigexp -F"
  }
  export OUTPUTMETHOD
  
  #
  # If RCFILE is not defined consider using some sane defaults  
  #
  [ ! -n "$RCFILE" ] && {
    for file in '/etc/tiger/tigerrc' '/usr/local/etc/tigerrc' './.tigerrc' './tigerrc' '$BASEDIR/tigerrc' '$HOME/.tigerrc' 
  # TODO: Check with ARSC if there is a preference on their behalf
  # for this ordering since Tara 3.0.3 uses
  # for file in './.tigerrc' './tigerrc' '$HOME/.tigerrc' '$BASEDIR/tigerrc'
    do
      eval rc=$file
      if checkfile $rc $file; then
	RCFILE=$rc
	break
      fi
    done
  }

  [ -n "$RCFILE" -a ! -r "$RCFILE" ] && {
    echo "Control file "$RCFILE" not defined or not readable... exiting..."
    exit 1
  }

  #
  # Preprocess the RC file, to export variables to environment
  #

  [ -n "$RCFILE" -a -r $RCFILE ] && {
    tempfile=`tempfile -d $WORKDIR` || tempfile=$WORKDIR/rcfile.$$
    $GREP -v '^#' $RCFILE |
    $SED -e 's/^\(.*\)=/export \1; \1=/' > $tempfile
    . $tempfile
    $RM -f $tempfile
  }

  HOSTNAME=`$GETHOSTNAME`
  if [ "$Tiger_Output_FQDN" = 'Y' -a "$OS" = "Linux" ]
  then
  # Linux hostname has the -f option for FQDN... (jfs)
  # (others?)
	  HOSTNAME=`$GETHOSTNAME -f 2>/dev/null`
# But sometimes this will fail.... (if the system is not properly setup)
	  [ $? -ne 0 ] && HOSTNAME=`$GETHOSTNAME`
  fi

  for file in './site-$HOSTNAME' '$BASEDIR/site-$HOSTNAME' './site' '$BASEDIR/site'
  do
    eval rc=$file
    if checkfile $rc $file; then
      SITECONFIG=$rc
      break
    fi
  done

  [ -n "$SITECONFIG" -a -r "$SITECONFIG" ] && 
  {
    $GREP -v '^#' $SITECONFIG |
    $SED -e 's/^\(.*\)=/export \1; \1=/' > $WORKDIR/sitefile.$$
    . $WORKDIR/sitefile.$$
    $RM -f $WORKDIR/sitefile.$$
  }

  HOSTNAMESLIST=${HOSTNAMESLIST:=$HOSTNAME}

  export CONFIGURED_ALREADY OS REL REV ARCH HOSTNAME
  export CONFIG_DIR CONFIG_FILE HOSTNAMESLIST

  [ "$TigerNoBuild" != 'Y' ] && {
    > $WORKDIR/tigercmds.$$
    $BASEDIR/util/buildbins $WORKDIR/tigercmds.$$
    . $WORKDIR/tigercmds.$$
    $RM -f $WORKDIR/tigercmds.$$
  }

  # set the PATH 
  PATH=/sbin:/usr/sbin:/bin:/usr/bin
  export PATH
}
