#!/bin/bash

# 		replaces: /etc/hotplug.d/block/cryptostick.hotplug
#            and: /etc/dev.d/block/usbcrypto.dev
#
#       depends on: udev, cryptsetup
#
#       description:
#       script is called by udev if a certain (like special name, size,
#       FS-ID etc.) usb-stick is plugged in. It loads and reconstructs
#       AES256 keys by xor and runs cryptsetup to setup a dm-crypt
#       device to decrypt an encrypted raw partition. 
#       It automatically mounts the dm-crypt device and runs exportfs if
#       needed.

# 		Something like this is needed somewhere in /etc/udev/rules for
# 		the script to run (You need to adjust it to your USB Stick (model, rev,
# 		ID_FS_UUID)):

# SUBSYSTEMS=="usb", BUS=="scsi", KERNEL=="sd*",  ATTRS{model}=="USB FLASH DRIVE", \
# ATTRS{rev}=="53CG", SYMLINK+="stick%n"
# SUBSYSTEMS=="usb", BUS=="scsi", KERNEL=="sd?2", \
# ATTRS{model}=="USB FLASH DRIVE", ATTRS{rev}=="53CG", \
# ACTION=="add",IMPORT{program}="vol_id --export $tempnode" \
# ENV{ID_FS_UUID}=="c3d9cb8e-1cb5-485c-9369-6404ec57b2c0" \
# ENV{ID_FS_TYPE}=="ext2" \
# RUN+="/usr/local/bin/mount_stuff_udev"
#                    ^^^^^^^^^^^^^^^^^^^ = this_script
#
#
#       Author: Volker Sauer <vsauer@dvs1.informatik.tu-darmstadt.de>
#       Version: 1.0
#       License: GPL


CRYPTRAWVOL=/dev/mapper/iata-rawstuff 	# RAW volume to be decrypted
CRYPTVOLMNT=/home/stuff 				# mountpoint the decrypted volume
CRYPTVOLNAME=stuff 						# name of decrypted volume (in /dev/mapper)
STICKKEYDIR=/keys 						# directory with the keys on the USB stick
HOSTKEYDIR=/etc/keys 					# directory with host keys of this computer
CRYPTSETUP=/sbin/cryptsetup 			# needed to setup dm-crypt (package cryptsetup)
MOUNT=/bin/mount 						# just in case you have your own mount program...
UMOUNT=/bin/umount 						# just in case you have your own mount program...
RUN_EXPORTFS=yes 						# run "exportfs -r" after successfull mount? 


# Check if RAW-Volume exists
if [ ! -b $CRYPTRAWVOL ]; then
	echo "(RAW) Volume $CRYPTRAWVOL does not exist or is not a block device"
	exit 0
fi

# Check if volume is already mounted
while read dev mntpath rest; do
	if [ "$mntpath" = "$CRYPTVOLMNT" ]; then
		echo "Volume $CRYPTVOLMNT is already mounted, exiting."
		exit 0
	fi
done < /proc/self/mounts

# Check if dm-crypt is already setup
if [ -b /dev/mapper/$CRYPTVOLNAME ]; then
        echo "/dev/mapper/$CRYPTVOLNAME already exists. Trying to mount...."
        $MOUNT /dev/mapper/$CRYPTVOLNAME $CRYPTVOLMNT
        if [ "$?" == "0" ]; then
                echo "/dev/mapper/$CRYPTVOLNAME successfully mounted in $CRYPTVOLMNT"
                exit 0
        else
                echo "($?) could not mount /dev/mapper/$CRYPTVOLNAME.  Exiting"
                exit 0
        fi
fi

STICKMNT=`mktemp -d`|| exit 0				# where to (temporarily) mount usb stick 
echo "Trying to get key from $DEVNAME. Mounting at $STICKMNT"
$MOUNT -o ro $DEVNAME $STICKMNT
if [ "$?" != "0" ]; then
	echo "Unable to mount $DEVNAME. Exiting"
	rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
	exit 0
fi
if [ ! -d $STICKMNT/$STICKKEYDIR ]; then
	echo "Directory $STICKMNT/$STICKKEYDIR does not exist. Unmounting $DEVNAME"
	$MOUNT $STICKMNT
	rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
	exit 0
fi
HOSTNAME=`hostname`
if [ ! -e $STICKMNT/$STICKKEYDIR/$HOSTNAME*.key ]; then
	echo "There is no key for $HOSTNAME in $STICKMNT/$STICKKEYDIR/. Unmounting $SYMLINK"
	$UMOUNT $STICKMNT
	rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
	exit 0
else
	COUNT=`ls $STICKMNT/$STICKKEYDIR/$HOSTNAME*.key|wc -w`
	if [ $COUNT -gt 1 ]; then
		echo "I found $COUNT keys for $HOSTNAME on $DEVNAME. Please provide only one key per host. Exiting"
		$UNMOUNT $STICKMNT
		rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
		exit 0
	else
		KEYNAME=`ls $STICKMNT/$STICKKEYDIR/$HOSTNAME*.key`
		KEYNAME=`basename $KEYNAME`
		echo "Using $DEVNAME/keys/$KEYNAME as userkey"
		HOSTKEY=`echo $KEYNAME|cut -d. -f1`.host
		if [ ! -e $HOSTKEYDIR/$HOSTKEY ]; then
			echo "Machtching hostkey $HOSTKEYDIR/$HOSTKEY. Exiting"
			rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
			exit 0
		else 
			echo "Using $HOSTKEYDIR/$HOSTKEY as hostkey"
		fi
		perl -e 'open(F2,@ARGV[0]) && open(F1,@ARGV[1]) or die "Usage: $0 <file1> <file2>\n"; print $buf1 ^ $buf2 while (read (F1,$buf1,65536) && read (F2,$buf2,65536));' -- $STICKMNT/$STICKKEYDIR/$KEYNAME $HOSTKEYDIR/$HOSTKEY | $CRYPTSETUP create $CRYPTVOLNAME $CRYPTRAWVOL
		if [ "$?" != "0" ]; then
			echo "($?) cryptsetup failed. This should not happen"
			rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
			exit 0
		fi

		echo "mount /dev/mapper/$CRYPTVOLNAME $CRYPTVOLMNT"
		$MOUNT /dev/mapper/$CRYPTVOLNAME $CRYPTVOLMNT
		if [ "$?" = "0" ]; then
			echo "/dev/mapper/$CRYPTVOLNAME successfully mounted at $CRYPTVOLMNT"
			if [ "$RUN_EXPORTFS" == "yes" ]; then
				if [ -x /usr/sbin/exportfs ]; then
					echo "Running exportfs -r"
					/usr/sbin/exportfs -r
					if [ "$?" != "0" ]; then
						echo "Could not run exportfs -r"
				fi
				else
					echo "/usr/sbin/exportfs does not exist on this computer. Maybe it isn't an NFS-Server?"
				fi
			fi
		else
			echo "($?) could not mount /dev/mapper/$CRYPTVOLNAME. Exiting"
			$UMOUNT $STICKMNT
			rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
			echo "Removing cryptsetup for $CRYPTVOLNAME"
			$CRYPTSETUP remove $CRYPTVOLNAME || echo "done"
			exit 0
		fi
		$UMOUNT $STICKMNT
		rmdir $STICKMNT || echo "Unable to remove temporary mountpoint $STICKMNT"
	fi
fi

# vim:set nospell:
