#!/bin/bash
#==============================================================================
# mkehd
#   Copyright (C) W. Michael Putello <mike@flyn.org>, 2002
#   Copyright © Jan Engelhardt <jengelh [at] gmx de>, 2005 - 2006
#
#   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 of
#   the License, 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.
#
#   You should have received a copy of the GNU General Public
#   License along with this program; if not, write to:
#   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
#   Boston, MA  02110-1301  USA
#
#   -- For details, see the file named "LICENSE.GPL2"
#==============================================================================

CONF=/etc/security/pam_mount.conf
CIPHER=aes
KEYBITS=256
SIZE=20
FSTYPE=ext2
_USER="$USER";

USAGE="[OPTION]...

  -h, -?      print this message
  -c cipher   set the cipher used in the filesystem [ $CIPHER ]
  -i cipher   set the fsk cipher                    [ from pam_mount.conf ]
  -f filename name of the disk image to generate    [ from pam_mount.conf ]
  -k keybits  set the number of bits in cipher key  [ $KEYBITS ]
  -p path     set the path to the efsk              [ from pam_mount.conf ]
  -s size     size in MB of generated filesystem    [ $SIZE ]
  -t fs type  type of filesystem to create          [ $FSTYPE ]
  -u user     name of user to create ehd for        [ $_USER ]"

while :; do
	case "$1" in
		-h | "-?" )
			echo -e usage: ${0##*/} "$USAGE" >&2
			exit 1 ;;
		-c )
			CIPHER="$2";
			shift ;;
		-f )
			FILENAME[0]="$2";
			shift ;;
		-i )
			FSK_CIPHER="$2";
			shift ;;
		-p )
			KEYPATH="$2";
			shift ;;
		-s )
			SIZE="$2";
			shift ;;
		-u )
			_USER="$2";
			shift ;;
		-?* )
			echo "${0##*/}: unrecognized option: $1" >&2;
			exit 1 ;;
		* )
			break ;;
	esac
	shift
done

if [ ! -f "$CONF" ]; then
	echo "${0##*/}: $CONF is missing"
	exit 1
fi

volcount=0
# if no image filename is specified then we grab all out of pam_mount.conf
if [ -z "${FILENAME[0]}" ]; then
	while read LINE; do
		if echo "$LINE" | grep -q "^volume $_USER "; then
			FILENAME[$volcount]=`echo "$LINE" | awk '{ print $5 }'`;
			FSK_CIPHER[$volcount]=`echo "$LINE" | awk '{ print $8 }'`;
			KEYPATH[$volcount]=`echo "$LINE" | awk '{ print $9 }'`;
			volcount=$[$volcount + 1];
		fi
	done <"$CONF";
	volcount=$[$volcount - 1];
fi

if [ -z "$PASSWORD" ]; then
	echo -n "(current) UNIX password: "
	stty -echo >/dev/tty;
	read PASSWORD </dev/tty; echo;
	echo -n "Retype UNIX password: "
	read VERIFY </dev/tty; echo;
	if [ "$PASSWORD" != "$VERIFY" ]; then
		echo "Sorry, passwords do not match"
		stty echo >/dev/tty;
		exit 1
	fi
	stty echo >/dev/tty;
fi

for((a=5; volcount >= 0; --volcount)); do
	if [ "${FSK_CIPHER[$volcount]}" != "-" ]; then
		echo "Using encrypted filesystem key...";
		if [ "${KEYPATH[$volcount]}" == "-" ]; then
			echo "${0##*/}: \"fs key path\" not defined in "
			echo "$CONF for user $_USER"
			echo
			echo "You need to edit $CONF correctly for efsk method."
			exit 1
		fi
		if [ -f "${KEYPATH[$volcount]}" ]; then
			echo "${0##*/}: ${KEYPATH[$volcount]} already exists: don't want to risk losing it"
			exit 1
		fi
		if [ -f "${FILENAME[$volcount]}" ]; then
			echo "${0##*/}: ${FILENAME[$volcount]} already exists: don't want to risk losing it"
			exit 1
		fi
		echo "Creating filesystem image using /dev/urandom (may take a LONG time)..."
		dd if=/dev/urandom of="${FILENAME[$volcount]}" bs=1M count="$SIZE" >/dev/null;
		# Use a named pipe because env. vars. are viewable by all
		# and random string is already being piped into openssl's
		# stdin
		SYS_PASS_PIPE=`mktemp -u /tmp/mkehd.XXXXXX`
		mkfifo -m 0600 "$SYS_PASS_PIPE";
		echo "$PASSWORD" >"$SYS_PASS_PIPE" &
		dd if=/dev/urandom bs=1c count=$[$KEYBITS/8] | \
                  openssl enc "-${FSK_CIPHER[$volcount]}" \
                  -pass file:"$SYS_PASS_PIPE" >"${KEYPATH[$volcount]}";

		echo "$PASSWORD" >"$SYS_PASS_PIPE" &
		openssl enc -d "-${FSK_CIPHER[$volcount]}" \
                  -in "${KEYPATH[$volcount]}" -pass file:"$SYS_PASS_PIPE" | \
                  losetup -e "$CIPHER" -k "$KEYBITS" -p0 /dev/loop1 \
                  "${FILENAME[$volcount]}";

		mkfs -t "$FSTYPE" /dev/loop1 >/dev/null;
		losetup -d /dev/loop1
		rm "$SYS_PASS_PIPE";
	else
		echo NOT using encrypted filesystem key...
		echo "Creating filesystem image using /dev/urandom (may take a LONG time)..."
		dd if=/dev/urandom of="${FILENAME[$volcount]}" bs=1M count="$SIZE";
		echo "$PASSWORD" | losetup -e "$CIPHER" -k "$KEYBITS" -p0 /dev/loop1 "${FILENAME[$volcount]}";
		mkfs -t "$FSTYPE" /dev/loop1 >/dev/null;
		losetup -d /dev/loop1
	fi
done
