#!/bin/sh
# This script sets up an ecryptfs mount in a user's ~/Private
#
# Originally ecryptfs-setup-pam-wrapped.sh by Michael Halcrow, IBM
#
# Ported for use on Ubuntu by Dustin Kirkland <kirkland@canonical.com>
# Copyright (C) 2008 Canonical Ltd.
# Copyright (C) 2007-2008 International Business Machines

PRIVATE_DIR="Private"

usage() {
	echo 
	echo "Usage:"
	echo "# $0 [--username USER]"
	echo "  [--loginpass LOGINPASS] [--mountpass MOUNTPASS]"
	echo
	echo " --username   Username for encrypted private mountpoint,"
	echo "              defaults to yourself"
	echo " --loginpass  System passphrase for USER, used to wrap MOUNTPASS"
	echo " --mountpass  Passphrase for mounting the ecryptfs directory,"
	echo "              defaults to a randomly generated 16 bytes"
	echo
	echo "   Be sure to properly escape your parameters according to your"
	echo "   shell's special character nuances, and also surround the"
	echo "   parameters by double quotes, if necessary."
	echo
	echo "   Any of these parameters may be:"
	echo "     1) exported as environment variables (USER, MOUNTPASS,"
	echo "        LOGINPASS)"
	echo "     2) specified on the command line"
	echo "     3) left empty and interactively prompted"
	echo
	echo "   BEWARE: They will, however, be displayed on STDOUT"
	echo
	exit 1
}

error() {
	echo "ERROR: $1"
	exit 1
}

error_testing() {
	rm -f "$1" >/dev/null
	umount.ecryptfs_private >/dev/null
	error "$2"
	exit 1
}

if [ ! -z "$SUDO_USER" ]; then
	USER="$SUDO_USER"
fi

while [ ! -z "$1" ]; do
	case "$1" in
		--username)
                        USER="$2"
			shift 2
		;;
		--loginpass)
			LOGINPASS="$2"
			shift 2
		;;
		--mountpass)
			MOUNTPASS="$2"
			shift 2
		;;
		*)
			usage
		;;
	esac
done

# Prompt for the USER name, if not on the command line and not in the environment
if [ -z "$USER" ]; then
	while [ true ]; do
		read -p "Enter the username: " -r USER
		if [ -z "$USER" ]; then
			echo "ERROR: You must provide a username"
			continue
		else
			# Verify the USER name is in /etc/passwd
			if ! grep "^$USER:" /etc/passwd >/dev/null; then
				echo "ERROR: User [$USER] does not exist"
				continue
			fi
			break
		fi
	done
else
	# Verify the USER name is in /etc/passwd
	grep "^$USER:" /etc/passwd >/dev/null || error "User [$USER] does not exist"
fi

# Obtain the user's home directory from /etc/passwd
HOME=`grep "^$USER:" /etc/passwd | awk -F: '{print $6}'`
if [ ! -d "$HOME" ]; then
	error "User home directory [$HOME] does not exist"
fi

# Check for active mounts
MOUNTPOINT="$HOME/$PRIVATE_DIR"
CRYPTDIR="$HOME/.$PRIVATE_DIR"
grep -qs "$MOUNTPOINT " /proc/mounts && error "[$MOUNTPOINT] is already mounted"
grep -qs "$CRYPTDIR " /proc/mounts && error "[$CRYPTDIR] is already mounted"

stty_orig=`stty -g`
# Prompt for the LOGINPASS, if not on the command line and not in the environment
if [ -z "$LOGINPASS" ]; then
	while [ true ]; do
		stty -echo
		read -p "Enter your login passphrase: " -r LOGINPASS
		stty $stty_orig
		echo
		if [ -z "$LOGINPASS" ]; then
			echo "ERROR: You must provide a login passphrase"
			continue
		else 
			stty -echo
			read -p "Enter your login passphrase (again): " -r LOGINPASS2
			stty $stty_orig
			echo
			if [ "$LOGINPASS" != "$LOGINPASS2" ]; then
				echo "ERROR: Login passphrases do not match"
				continue
			else
				break
			fi
		fi
	done
fi

# Prompt for the MOUNTPASS, if not on the command line and not in the environment
if [ -z "$MOUNTPASS" ]; then
	while [ true ]; do
		stty -echo
		read -p "Enter your mount passphrase [leave blank to generate one]: " -r MOUNTPASS
		stty $stty_orig
		echo
		if [ -z "$MOUNTPASS" ]; then
			# Pull 128 bits of random data from /dev/urandom, and convert
			# to a string of 32 hex digits
			MOUNTPASS=`head -c 16 /dev/urandom | od -x | head -n 1 |sed "s/^0000000//" | sed "s/\s*//g"`
			break
		else
			stty -echo
			read -p "Enter your mount passphrase (again): " -r MOUNTPASS2
			stty $stty_orig
			echo
			if [ "$MOUNTPASS" != "$MOUNTPASS2" ]; then
				echo "ERROR: Mount passphrases do not match"
				continue
			else
				break
			fi
		fi
	done
fi

echo
echo
echo "Using username [$USER]"
echo "Using mount passphrase [$MOUNTPASS]"
echo "Using login passphrase [$LOGINPASS]"
echo "Using mount point [$MOUNTPOINT]"
echo "Using encrypted dir [$CRYPTDIR]"
echo
echo "This script will attempt to set up your system to mount"
echo "$MOUNTPOINT with eCryptfs automatically on login,"
echo "using your login passphrase."
echo
echo "************************************************************************"
echo "YOU SHOULD RECORD THIS MOUNT PASSPHRASE AND STORE IN A SAFE LOCATION:"
echo "$MOUNTPASS"
echo "THIS WILL BE REQUIRED IF YOU NEED TO RECOVER YOUR DATA AT A LATER TIME."
echo "************************************************************************"
echo

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

# Setup private directory in home
mkdir -m 700 -p "$CRYPTDIR" || error "Could not create crypt directory [$CRYPTDIR]"
mkdir -m 700 -p "$MOUNTPOINT" || error "Could not create mount directory [$MOUNTPOINT]"
ln -s /sbin/mount.ecryptfs_private "$MOUNTPOINT"/"THIS DIRECTORY HAS BEEN UNMOUNTED TO PROTECT YOUR DATA --  Run mount.ecryptfs_private to mount again"
chmod 500 "$MOUNTPOINT"

# Setup ~/.ecryptfs directory
mkdir -m 700 $HOME/.ecryptfs 2>/dev/null
touch $HOME/.ecryptfs/auto-mount || error "Could not setup ecryptfs auto-mount"
touch $HOME/.ecryptfs/auto-umount || error "Could not setup ecryptfs auto-umount"

# Backup any existing wrapped-passphrase or sig files; we DO NOT destroy this
timestamp=`date +%Y%m%d%H%M%S`
for i in "$HOME/.ecryptfs/wrapped-passphrase" "$HOME/.ecryptfs/$PRIVATE_DIR.sig"; do
	if [ -s "$i" ]; then
		mv -f "$i" "$i.$timestamp" || error "Could not backup existing data [$i]"
	fi
done

# Setup wrapped-passphrase file
u=`umask`
umask 377
ecryptfs-wrap-passphrase "$HOME/.ecryptfs/wrapped-passphrase" "$MOUNTPASS" "$LOGINPASS" || error "Could not wrap passphrase"
umask $u

# Add the passphrase to current keyring
# On subsequent logins, this should be handled by "pam_ecryptfs.so unwrap"
response=`ecryptfs-add-passphrase "$MOUNTPASS"`
if [ $? -ne 0 ]; then
	error "Could not add passphrase to the current keyring"
fi
sig=`echo "$response" | grep "Inserted auth tok" | sed "s/^.*\[//" | sed "s/\].*$//"`
if ! echo "$sig" | egrep -qs "^[0-9a-fA-F]{16,16}$"; then
	error "Could not obtain the key signature"
fi
echo "$sig" > "$HOME/.ecryptfs/$PRIVATE_DIR.sig" || error "Could not create signature file [$HOME/.ecryptfs/$PRIVATE_DIR.sig]"

echo
echo "Done configuring."
echo

# Now let's perform some basic mount/write/umount/read sanity testing...
echo "Testing mount/write/umount/read..."
mount.ecryptfs_private || error "Could not mount private ecryptfs directory"
temp=`mktemp "$HOME/$PRIVATE_DIR/ecryptfs.test.XXXXXX"` || error_testing "$temp" "Could not create empty file"
random_data=`head -c 16000 /dev/urandom | od -x` || error_testing "$temp" "Could not generate random data"
echo "$random_data" > "$temp" || error_testing "$temp" "Could not write encrypted file"
md5sum1=`md5sum "$temp"` || error_testing "$temp" "Could not read encrypted file"
umount.ecryptfs_private || error_testing "$temp" "Could not unmount private ecryptfs directory"
mount.ecryptfs_private || error_testing "$temp" "Could not mount private ecryptfs directory (2)"
md5sum2=`md5sum "$temp"` || error_testing "$temp" "Could not read encrypted file (2)"
rm -f "$temp"
umount.ecryptfs_private || error_testing "$temp" "Could not unmount private ecryptfs directory (2)"
if [ "$md5sum1" != "$md5sum2" ]; then
	error "Testing failed."
else
	echo "Testing succeeded."
fi

echo
exit 0
