#!/bin/sh
#=============================================================================
# Cryptoswap space boot script
#
# Title:                kernel
# Description:          Setup and teardown crypto swap devices
# Programmed by:        Dale Amon <amon@islandone.org> 
# Revised by:           $Author: hvr $ 
# Date:                 $Date: 2002/04/22 13:56:41 $ 
# Version:              $Revision: 1.1 $
#
# NOTE:		* THIS IS NOT A RELEASABLE VERSION
#		* Something must be done to fill the entropy pool
#		* compatibility with modular kernel with devfs?
#		* what to do with a bad cipher name?
#		* what to do with non-crypto kernel?
#		* what to do with an as yet unloaded cipher module?
#
# HISTORY
# $Log: cryptoswap.sh,v $
# Revision 1.1  2002/04/22 13:56:41  hvr
# added dale amon's cryptoswap script
#
# 20020331	Dale Amon (amon@vnl.com) 
#		Created Debian init script to work with International 
#		patch set with loop-jari patch.
#
#================================================================================
. /etc/default/rcS

FADECNT=20		# Number of times to write zeroes over the data used
			# for initial entropy.

#=============================================================================
# Parse the options cryptoswap attributes and values.
# It is responsible for setting the global values of:
#
# Args:		A cryptoswap fstab option string, eg
#		swapfile=/dev/hda2,cipher=twofish,fallback
#
# Sets Globals:	swapfile
#		loopdev
#		fallback
#		cipher
#		keysize
#		wipe
#

function parse_cryptswap_options() {

	# Set the crypto options to default values
	swapfile=
	loopdev=
	fallback=
	cipher="aes"
	keysize=128
	wipe=

        ifssav=$IFS
	IFS=","
	for i in $1 ; do
	    IFS="="
	    case "$i" in
		swapfile*)
			a=($i)
	        	swapfile=${a[1]}
	        ;;
	        fallback*)
	        	fallback=1
	        ;;
	        cipher*)
	        	a=($i)
	        	cipher=${a[1]}
	        ;;
	        keysize*)
	        	a=($i)
	        	keysize=${a[1]}
	        ;;
	        loop*)
	        	a=($i)
	        	loopdev="/dev/loop${a[1]}"
	        ;;
	        wipe*)
	        	a=($i)
	        	wipe=${a[1]}
			if [ $wipe = 0 ]; then 
			   wipe=
			fi
	        ;;
	        *)    
	        ;;
	    esac  
	    IFS=$ifssav
	done

	# The swapfile *must* be either a block device or a normal file
        if [ $swapfile ] && [ -b $swapfile -o  -f $swapfile ]; then
		if [ $loopdev ]; then
		        # The loopdev must be an unused loop block device or we can't do cryptoswap
			if [ ! -b $loopdev ]; then
			   [ "$VERBOSE" != no ] && echo " Block device $loopdev not found";
			   loopdev=; cipher=; keysize=;
		        fi
		else
			# If no loop device name was given, we cannot do cryptoswap
			loopdev=; cipher=; keysize=;
		fi
	else
		# Ignore the entry if it isn't a block device or a file
		swapfile=; loopdev=; fallback=; cipher=; keysize=; wipe=
 	fi
}

#=============================================================================

case "$1" in
    start|"")
    [ "$VERBOSE" != no ] && echo "Securing swap devices"

    # This will happen again later, but we need /dev/random now
    if [ -f /var/lib/urandom/random-seed ]; then
	cat /var/lib/urandom/random-seed >/dev/urandom
    fi

    exec 9>&0 </etc/fstab
    while read fs mnt type opts dump pass junk; do
	swap=
	cswap=
	case "$type" in
	    ""|\#*)
	    	continue;
	    ;;
	    swap)
	    	swap=1
	    	if [ ${fs:0:9} == "/dev/swap" ]; then
			cswap=1
			parse_cryptswap_options $opts;
	    	fi
	    ;;
	esac

	if [ $cswap ]; then
                if [ $loopdev ] && /sbin/losetup ${loopdev} >& /dev/null; then 
	           [ "$VERBOSE" != no ] && echo " Block device $loopdev in use"
		   loopdev=; cipher=; keysize=;
                fi

		# echo "swapdev=$fs swap=$swapfile loopdev=$loopdev cipher=$cipher keysize=$keysize fallback=$fallback wipe=$wipe"

		# Remove the old link, if any.
		[ -L $fs ] && rm -f $fs;

		if [ $loopdev ]; then
		   [ "$VERBOSE" != no ] && echo -n " Cryptoswap setting up swap on $fs..."
		   ln -s $loopdev $fs

                   # This was Jaaru's idea, using first 40kb for initial entropy, however if we
                   # wipe on shutdown, this won't work.
                   MD=`dd if=${fs} bs=4096 count=10 2>/dev/null | md5sum`
                   for (( CNT=0 ; $CNT < ${FADECNT} ; CNT++ )); do
                       # dd if=/dev/zero of=${fs} bs=4096 count=10 conv=notrunc 2>/dev/null
                        sync;
                   done

                   UR=`dd if=/dev/urandom bs=18 count=1 2>/dev/null \
                       | uuencode -m - | tail -2 | head -1`
                   DT=`date '+%s'`
                   echo -n ${MD}${UR}${DT} | losetup -p 0 -e ${cipher} -k ${keysize} ${loopdev} ${swapfile}
                   MD=; UR=; DT=

                   # dd if=/dev/zero of=${loopdev} bs=4096 count=10 conv=notrunc 2>/dev/null
                   sync
                   mkswap $fs > /dev/null
		   [ "$VERBOSE" != no ] && echo "done."

		elif [ $fallback ]; then
		   [ "$VERBOSE" != no ] && echo -n " Cryptoswap falling back to unencrypted swap on $fs..."
	           mkswap $fs > /dev/null
		   [ "$VERBOSE" != no ] && echo "done."

		else
		   [ "$VERBOSE" != no ] && echo " Cryptoswap failed to initialize $fs"
		fi
	fi
    done
    ;;

    stop)
    [ "$VERBOSE" != no ] && echo "Clearing Swap"

    exec 9>&0 </etc/fstab
    while read fs mnt type opts dump pass junk; do
	swap=
	cswap=
	case "$type" in
	    ""|\#*)
	    	continue;
	    ;;
	    swap)
	    	swap=1
		parse_cryptswap_options $opts
	    	if [ ${fs:0:9} == "/dev/swap" ]; then
		   cswap=1
		   swapoff -a $fs >& /dev/null;
	    	elif [ $wipe ]; then
		     swapoff -a $fs >& /dev/null;
		fi
	    ;;
	esac

	if [ $swap ]; then
            # echo "swapdev=$fs swap=$swapfile loopdev=$loopdev cipher=$cipher keysize=$keysize fallback=$fallback wipe=$wipe"

	    # For the truly paranoid, scrub swap on shutdown
            if [ $wipe ]; then
	       [ "$VERBOSE" != no ] && echo -n " Clearing $fs..."
	       for (( CNT=0 ; CNT < $wipe ; CNT++ )) ; do
	           dd if=/dev/zero of=${fs} 2>/dev/null
	           sync
	       done
               [ "$VERBOSE" != no ] && echo "done."
	    fi

	    if [ $loopdev ] && /sbin/losetup ${loopdev} >& /dev/null; then 
	       [ "$VERBOSE" != no ] && echo -n " Detaching $fs from $loopdev..."
	       losetup -d $loopdev
               [ "$VERBOSE" != no ] && echo "done."
	    fi

	    if [ $cswap ]; then
	       rm -f $fs
	    fi
	fi
    done
    exec 0>&9 9>&-
    ;;

    *)
    echo "Usage: cryptoswap {start|stop}" >&2
    exit 1
    ;;
esac

exit 0

