#!/bin/sh
#
#     tiger - A UN*X security checking system
#     Copyright (C) 2000, 2001 Javier Fernandez-Sanguino Pea
#
#    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
#
# 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 Franois 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 Franois 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)
#      
#
# 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='.'


#
# 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 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 BASENAME || exit 1

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

# From the localepurge binary:
LOCALEDIR=/usr/share/locale
MANDIR=/usr/share/man
LOCALEPURGE=/etc/locale.nopurge
if [ -f "$LOCALEPURGE" ]
then
  LOCALENOPURGED=`for l in $($GREP ^[a-z] $LOCALEPURGE); do echo -n "$l\|"; done; echo -n "[^a-z].*"`
  SED_REMOVE_LOCALES_PURGED="/  usr\/share\/locale\/\($LOCALENOPURGED\)\//p;/  usr\/share\/locale\//d;/  usr\/share\/man\/\($LOCALENOPURGED\|man[1-9]\)\//p;/  usr\/share\/man\//d"
fi
DIVERSIONS="/var/lib/dpkg/diversions"

if [ -d /var/lib/dpkg/info ] 
then
for md5file in /var/lib/dpkg/info/*.md5sums
do
[ -f $md5file ] && [ ! -L $md5file  ] && {
# Note: We  do not check things in  /usr/share/doc
# to speed things up
	$GREP -v " usr/share/doc/" "$md5file" |
	$GREP -v " dev/" |
	$GREP -v " lib/udev/devices/" |
# Also don't check purged locales
        $SED -e "$SED_REMOVE_LOCALES_PURGED" |
	$SED -e "s/^\(.*\)  \(.*\)/\1  \/\2/" |
	$MD5SUM -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/:$//"`
			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
/usr/sbin/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
}

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