#!/bin/bash

#########################################

CHRDIR=/chroot

#########################################

PARTIAL=/var/cache/apt/archives/partial

FORCE=0
FIX=""
ONLY=""

if [ $# -lt 1 -o $# -gt 2 ]; then
	echo "usage: $0 all|root|chroot_name [FORCE|FIX]"
	exit 3
fi

ONLY=$1

if [ $# -eq 2 ]; then
	case $2 in
		"FORCE")
			FORCE=1
			;;
		"FIX")
			FIX="-f"
			;;
	esac
fi

initscripts=`find /etc/init.d/ -type f ! -name "*.*"`

#############################################################################

function grsec_chr_suspend()
{
		MODE=1
		if [ "$1" == "0" ]; then
			MODE=0
		fi
		CHROPTS=`sysctl -aN 2>/dev/null |grep "kernel.grsecurity.chroot"`
		for CHROPT in $CHROPTS; do
			if [ "$CHROPT" == "kernel.grsecurity.chroot_caps" ]; then
				sysctl -w $CHROPT=0
			elif [ "$CHROPT" == "kernel.grsecurity.chroot_deny_bad_rename" ]; then
				sysctl -w $CHROPT=0
			else
				sysctl -w $CHROPT=$MODE
			fi
		done
}

function preinst
{
	MCHR=
	if [ "x$1" != "x" ]; then
		MCHR=/chroot/$1
	fi

	if [ "x$MCHR" == "x/chroot/maild" ]; then
		chown debian-spamd:debian-spamd /chroot/maild/var/lib/spamassassin/compiled -R
	fi

}

function postinst
{
	MCHR=
	if [ "x$1" != "x" ]; then
		MCHR=/chroot/$1
	fi

	if [ "x$MCHR" == "x/chroot/maild" ]; then
		chown root:root /chroot/maild/var/lib/spamassassin/compiled -R
	fi

}

function privs
{
	MCHR=
	if [ "x$1" != "x" ]; then
		MCHR=/chroot/$1
	fi

	#grub
	pax mp $MCHR/usr/sbin/grub-mkdevicemap
	pax mp $MCHR/usr/sbin/grub-probe
	pax mp $MCHR/usr/sbin/grub-setup


	#clamav, clamscan, freshclam (root, chroot)
	if [ "x$MCHR" == "x" ]; then
		[ -f /etc/init.d/clamav-daemon ] && /etc/init.d/clamav-daemon stop
		[ -f /etc/init.d/clamav-freshclam ] && /etc/init.d/clamav-freshclam stop
		[ -f /etc/init.d/clamav-daemon ] && sleep 5
	fi
	pax m $MCHR/usr/sbin/clamd
	pax m $MCHR/usr/bin/clamscan
	pax m $MCHR/usr/bin/freshclam
	if [ "x$MCHR" == "x" ]; then
		[ -f /etc/init.d/clamav-daemon ] && /etc/init.d/clamav-daemon start
		[ -f /etc/init.d/clamav-freshclam ] && /etc/init.d/clamav-freshclam start
	fi

	#java
	pax m $MCHR/usr/bin/java

	# apache2-7x
	pax m $MCHR/usr/sbin/apache2-70
	pax m $MCHR/usr/sbin/apache2-71
	pax m $MCHR/usr/sbin/apache2-72
	pax m $MCHR/usr/sbin/apache2-73
	pax m $MCHR/usr/sbin/apache2-74
	pax m $MCHR/usr/sbin/apache2-80

	pax mp $MCHR/usr/bin/php7.0
	pax mp $MCHR/usr/bin/php7.1
	pax mp $MCHR/usr/bin/php7.2
	pax mp $MCHR/usr/bin/php7.3
	pax mp $MCHR/usr/bin/php7.4
	pax mp $MCHR/usr/bin/php8.0

	pax m $MCHR/usr/sbin/apache2-admin

}

function upgrade_head
{
	echo "-------------------------------------------------------------------------------"
	echo "*** Upgrading $1..."
	echo "-------------------------------------------------------------------------------"
}

function chr_daemon
{
	[ -d $1 ] || return 21

	for script in $initscripts; do

		if (grep -e "^CHRDIR="$1"$" $script >/dev/null); then
			echo "*** $script $2..."
			$script $2
		fi
	done
}

function pax
{
 if [ -f $2 ]; then
	echo "--- PAX flags change: $1 $2"
	if [ -x /sbin/chpax ]; then
		/sbin/chpax -$1 $2
	fi
	if [ -x /sbin/paxctl ]; then
		/sbin/paxctl -c$1 $2
	fi
 fi
}

############################################################################


# gather from all the chroots

if [ "$ONLY" == "all" ]; then
	if [ -d $CHRDIR ]; then
		CHROOTS=`ls $CHRDIR`
	else
		CHROOTS=""
	fi
elif [ "$ONLY" == "root" ]; then
		CHROOTS=""
else
	if [ -d $CHRDIR/$ONLY ]; then
		CHROOTS=$ONLY
	else
		echo "ERROR: no such chroot found: $ONLY"
		exit 34
	fi
fi

if [ "$ONLY" == "root" -o "$ONLY" == "all" ]; then
	# do it in /
	upgrade_head "root system"
	DMVER=`cat /etc/debian_version |head -c 1`
	WNP='--with-new-pkgs'
	if [ "$DMVER" -eq "$DMVER" ] 2>/dev/null; then
		if [ $DMVER -lt 8 ]; then
			WNP=''
		fi
	fi

	[ -d $PARTIAL ] || mkdir $PARTIAL
	UPG=$FORCE
	upstr=`apt-get $FIX $WNP upgrade -s`
	if (echo "$upstr" |grep "kept back" >/dev/null); then
		echo "WARNING: Packages kept back"
	fi
	if (echo "$upstr" |grep -E "(Inst|Conf)">/dev/null); then
		UPG=1
	fi
	if [ "$UPG" == "1" ]; then
		preinst
		apt-get $FIX $WNP upgrade -y
		privs
		postinst
	else
		echo "No need to upgrade root."
	fi
fi

if [ -n "$CHROOTS" ]; then

	# suspend chroot hardening
	echo "-------------------------------------------------------------------------------"
	grsec_chr_suspend 0
	echo "-------------------------------------------------------------------------------"

	for CHR in $CHROOTS; do

		if [ -d $CHRDIR/$CHR/etc/apt ]; then
			upgrade_head "$CHR chroot"

			DMVER=`cat $CHRDIR/$CHR/etc/debian_version |head -c 1`
			WNP='--with-new-pkgs'
			if [ "$DMVER" -eq "$DMVER" ] 2>/dev/null; then
				if [ $DMVER -lt 8 ]; then
					WNP=''
				fi
			fi

			[ -d $CHRDIR/$CHR$PARTIAL ] || mkdir $CHRDIR/$CHR$PARTIAL
			if ! [ -f $CHRDIR/$CHR/etc/apt/noautoupgrade ]; then
				UPG=$FORCE
				upstr=`chroot $CHRDIR/$CHR apt-get $FIX $WNP upgrade -s`
				if (echo "$upstr" |grep "kept back" >/dev/null); then
					echo "WARNING: Packages kept back"
				fi
				if (echo "$upstr" |grep -E "(Inst|Conf)">/dev/null); then
					UPG=1
				fi
				if [ "$UPG" == "1" ]; then
					preinst $CHR
					chroot $CHRDIR/$CHR apt-get $FIX $WNP upgrade -y
					chr_daemon $CHRDIR/$CHR stop
					sleep 4
					privs $CHR
					postinst $CHR
					sleep 2
					chr_daemon $CHRDIR/$CHR start
				else
					echo "No need to upgrade $CHR."
				fi
			else
				echo "WARNING: Automatic upgrade disabled in $CHR chroot !!!"
				echo "This can lead to a security risk."
				read -p "Press [enter] to continue: "
			fi
		fi

	done

	# reset chroot hardening
	echo "-------------------------------------------------------------------------------"
	grsec_chr_suspend 1

fi

echo "-------------------------------------------------------------------------------"
echo "Testing if all services are running..."
[ -f /etc/daemon-watchdog/daemon-watchdog ] && /etc/daemon-watchdog/daemon-watchdog test
echo "-------------------------------------------------------------------------------"

echo "Finished."
echo "Use FORCE as parameter if you want to run even if there is nothing to install."
