#!/bin/sh
#
#     tiger - A UN*X security checking system
#     Copyright (C) 2000, 2001 Javier Fernandez-Sanguino Peña
#
#    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.
#
#     Please see the file `COPYING' for the complete copyright notice.
#
# Linux/deb_checkmd5sums - 24/08/2001
#
# 01/23/2014 - jfs - Fix the location of dpkg-divert (Debian bug #732936 and #735102)
# 12/19/2013 - jfs - Do not use dpkg-divert if not available
# 09/09/2008 - jfs - Use prelink to calculate checksums if present (Debian bug #445531)
# 06/22/2007 - jfs - Fix Debian bug 50611 by properly reading md5sum's output
# 08/17/2006 - jfs - Fix Ubuntu bug 50611 by excluding dev/ and 
#        lib/udev/devices/ from the md5sum test, thanks to Richard Laager 
#        for the patch (also Debian bug #383400)
# 04/29/2005 - jfs - Prevent issues with /usr/bin/[ by adjusting GREP calls
#        (Debian bug #305484)
# 03/21/2005 - jfs - Do not warn if the md5 file is not present in the list file
#       (Debian bug #299935)
# 09/13/2004 - jfs - Exclude usr/share/doc better (Debian bug 264111)
# 05/01/2004 - jfs - Fixed previous patch.
# 02/26/2004 - jfs - Included patch from Chung-chieh Shan which avoids failure
#       on packages whose names contain "."
#       (Debian bug 234811)
# 12/20/2003 - jfs - Included patch from Nicholas François which makes 
#       Tiger not warn on manpage files purged through localepurge 
#       (Debian bug 219728)
# 11/16/2003 - jfs - Applied patch from Philipp Weis to avoid giving
#       warnings for /usr/bin/[ by using the -F switch (Debian bug 220946)
# 11/09/2003 - jfs - Avoid running into problems if the GREP calls to
#       diversions or conffiles return more than one line.
#       Also detect local diversion (Debian bug 219727)
# 10/15/2003 - jfs - Modify ERROR to FAIL
# 09/19/2003 - jfs - Add patches provided by Nicolas François to 
#      greatly improve the speed and add support for diversions 
#      (Debian Bug #162589).
#      Also added some minor changes so the package in question
#      is printed when files don't match and avoid printing
#      errors related to conffiles (Debian Bug #211329)
# 02/04/2018 - jfs - Do not call prelink with '-c' when using it
#      (Savannah bug #52087)
# 02/10/2018 - jfs - Excude additional directories in /usr/share
#       which contain many files but do not pose a huge security
#       risk if changed: /usr/share/help, /usr/share/icons,
#       /usr/share/fonts, /usr/share/locale, /usr/share/games
#       /usr/share/i18n
#       Since we do not check locale anymore, remove the code that
#       used the infomation from locale puge
#
# TODO:
# - Consider using a single file instead of calling MD5sum
#   each time.
# - Add an option to Tiger so some directories might be excluded from this
#   check.
#
#-----------------------------------------------------------------------------
TigerInstallDir="/usr/share/tiger"


#
# Set default base directory.
# Order or preference:
#      -B option
#      TIGERHOMEDIR environment variable
#      TigerInstallDir installed location
#
basedir=${TIGERHOMEDIR:=$TigerInstallDir}

for parm
do
   case $parm in
   -B) basedir=$2; break;;
   esac
done

#
# Verify that a config file exists there, and if it does
# source it.
#
[ ! -r $basedir/config ] && {
  echo "--ERROR-- [init002e] No 'config' file in \`$basedir'."
  exit 1
}

. $basedir/config

. $BASEDIR/initdefs

#
# If run in test mode (-t) this will verify that all required
# elements are set.
#
[ "$Tiger_TESTMODE" = 'Y' ] && {
  haveallcmds MD5SUM CAT CUT SED GREP EGREP BASENAME || exit 1
  haveallfiles BASEDIR WORKDIR || exit 1
  haveallvars TESTLINK HOSTNAME
  
  message CONFIG init003c "" "$0: Configuration ok..."
  exit 0
}

#------------------------------------------------------------------------
echo
echo "# Checking md5sums of installed files"

haveallcmds MD5SUM CAT CUT SED GREP EGREP BASENAME || exit 1

# Prelink
PRELINK=/usr/sbin/prelink
if [ -x "$PRELINK" ] ; then
    MD5SUM="$PRELINK -y --md5"
    MD5SUM_CALL="$MD5SUM"
else
    MD5SUM_CALL="$MD5SUM -c"
fi

DIVERSIONS="/var/lib/dpkg/diversions"

if [ -d /var/lib/dpkg/info ] 
then
ls /var/lib/dpkg/info/*.md5sums | 
while read md5file; do
    [ -f $md5file ] && [ ! -L $md5file  ] && {
# Note: We  do not check things in some /usr/share/ directories to speed things up
# TODO
# - This could be user defined, as some systems might have more files in 
#   /usr/share/ depending on installed applications
# - Alternatively we could let the use configure so only binary directories
#   are reviewed (i.e. /bin, /usr/bin, /sbin, /usr/sbin..) or those in PATH
#   but this would still leave some areas that could potentially load
#   malicious code (e.g. interpreter scripts in /usr/share/perl, /usr/share/go...
#
# The list of excluded directories below can be reviewed to obtain the number of
# files per directory by using the following:
# { ls -d /usr/share/* |while read dir; do [ -d "$dir" ] && { echo -n "$dir:" ; find "$dir" -type f  | wc -l  ; } ; done ; } | awk -F : '{print $2" "$1;}' | sort -n |less
#
	$CAT "$md5file" |
	$EGREP -v "usr/share/[doc|help|man|icons|pixmaps|i18n|locale|mime|games]/" |
	$GREP -v " dev/" |
	$GREP -v " lib/udev/devices/" |
	$SED -e "s/^\(.*\)  \(.*\)/\1  \/\2/" |
	$MD5SUM_CALL -c 2>&1 | $SED -e "s/^.*md5sum: MD5 check failed for '\(.*\)'/DIFF \1/; s/^.*md5sum: can't open \(.*\)/ERR \1/" | {
		while read file err
		do
			package=`$BASENAME "$md5file" ".md5sums"`
                        file=`echo $file | sed -e "s/:$//"`
                        echo "DEBUG: Checking file $file of $package ($err)" >&2
			case $err in
			DIFF|FAILED)
				# don't check diverted now
				[ -z "`$GREP -sxF \"$file\" $DIVERSIONS`" ] &&
				# and conffiles should not be checked either
				[ -z "`$GREP -sxF \"$file\" /var/lib/dpkg/info/$package.conffiles`" ] &&
 				[ -n "`$GREP -sxF \"$file\" /var/lib/dpkg/info/$package.list`" ] &&
					message FAIL lin005f "" "Installed file \`$file' checksum differs from installed package '$package'."
# TODO: Consider including the MD5sum to this message
# notice that some integrity checkers might do this already too.
				;;
			ERR)
# Check if this package 
 				if $GREP -sqxF \"$file\" /var/lib/dpkg/info/$package.list ; then

					message FAIL lin006f "" "Cannot check file \"$file\" provided by \"$package\" since it does not exist"
				fi
				;;
			esac
		done 
	}
    }
done
# check diversions


if [ -x /usr/bin/dpkg-divert ]; then
/usr/bin/dpkg-divert --list |
# extract the file diverted, the backup file and the diverter package
$SED -e 's/diversion of \(\/.*\) to \(\/.*\) by \(.*\)$/\1;\2;\3/' \
     -e 's/local diversion of \(\/.*\) to \(\/.*\)$/\1;\2;LOCAL/' | {
  saveIFS=$IFS
  IFS=";"
  while read file tofile bypackage
  do
    IFS=":" ; set X `$DPKG -S "$file" | $GREP -v "^diversion by "`
    IFS=", " ; set X $2
    while [ "$2" != "" ]
    do
      if [ "$2" = "$bypackage" ]
      then
        currentfile=$file
      else
        currentfile=$tofile
      fi
      [ -f "/var/lib/dpkg/info/$2.md5sums" ] && {
        md5pck=`$GREP "$(echo "$file\$"|$CUT -c2-)" /var/lib/dpkg/info/$2.md5sums | $CUT -f 1 -d " "`
        [ -n "$md5pck" ] && {
          if [ -f "$currentfile" ]
          then
            md5sum=`$MD5SUM "$currentfile" | $CUT -f 1 -d " "`
            [ "$md5pck" != "$md5sum" ] &&
              message FAIL lin005f "" "Installed file \`$currentfile' checksum differs from installed packages."
          else
            message FAIL lin006f "" "Cannot check file \"$currentfile\" provided by \"$2\" since it does not exist"
          fi
        }
      }
      shift
    done
    IFS=";"
  done

  # restore IFS
  IFS=$saveIFS
}
fi

else
	message WARN lin006w "" "This check cannot be done since we seem not to be running on a Debian GNU/Linux system"
fi
