[PATCH] ecryptfs-setup-confidential: rework to use mount.ecryptfs_private

This patch reworks the ecryptfs-setup-confidential in order to use the
new functionality and methodology possible with the
mount.ecryptfs_private and umount.ecryptfs_private setuid binaries.

The goal is to make the ecryptfs-setup-confidential script completely
executable by non-privileged users.

This patch makes the following changes:

 * Remove support for specifying non-standard MOUNTPOINT and CRYPTDIR
directories.  Set PRIVATE_DIR="Private".  This is a temporary measure.
However, the setuid mount.ecryptfs_private program and this script need
to be in sync.  I think this should configurable by a system
administrator by setting something in /etc/ecryptfs.conf (or the like).

 * Create an error_testing() function that cleans up cruft created by
the test scenarios.

 * Put the interactive user name prompting in a loop until a good
username is received.

 * Check for active mount points in /proc/mounts.  Look for both the
MOUNTPOINT and CRYPTDIR.  Error out if either is mounted.

 * Put login and mount passphrase interactive prompting in a loop until
proper input is received.  Use "stty" to hide input while the user is
typing.

  * Remove the PAM library name detection.  That was a nasty hack to fix
a bug where the build system was producing the wrong PAM library name.
Good riddance!

 * Remove the modprobe of ecryptfs.  This should happen automatically,
or by the packing/installer if at all.  Another privileged operation
that does not belong in this script.

 * Remove all of the /etc/fstab munging.  This is completely avoidable
now with the mount.ecryptfs_private and the umount.ecryptfs_private
setuid executables.  The /etc/fstab munging was messy and required root
privileges.  Good riddance to this too!

* Remove the PAM configuration hack.  This is not permissible by Debian
policy, and requires system administrator privileges.  This only needs
to happen once per system, rather than every time a user sets up their
private directory.  This needs to be moved elsewhere.  Perhaps in a root
script, or perhaps in packaging.  But it does not belong here.

 * Remove the bash_proflie, bash_logout, and gnome autostart hacks.
These were temporary measures until we found better alternatives.  The
mount/unmount functionality will be handled by the ecryptfs PAM module.
That code is coming soon.  Stay tuned.

 * Backup both previous .ecryptfs/wrapped-passphrase
and .ecryptfs/Private.sig files.  Append the same timestamp to each (to
keep them paired for data recovery purposes).

 * Now call ecryptfs-wrap-passphrase and ecryptfs-add-passphrase
subsequently to write the wrapped passphrase to file, and add the
passphrase to the keyring in the current session.  We also grep/sed the
signature out of the ecryptfs-add-passphrase stdout and write that to
the .sig file.

 * Get rid of a bunch of various chown/chmod's that were necessary when
we were root running this on behalf of another user, or we were
sudo'ing.

 * Finally, we add a pretty rudimentary test scenario, wherein we:
  - mount the ecryptfs private directory we just created
  - grab roughly 16K (multiple pages) of random data
  - write that to a tempfile on the mountpoint
  - md5sum (read) that file, save to a variable
  - unmount
  - mount again
  - md5sum (read) that file again
  - compare the 2 different md5sums
  - error out if ANY of the above is not successful
 This test could be improved in various ways.  At some point, it should
probably be broken out to a script of its own.  For now, these
operations are very fast and perhaps can throw meaningful error messages
if the initial mount/write/unmount/read fail.

Signed-off-by: Dustin Kirkland <[EMAIL PROTECTED]>




-- 
:-Dustin

Dustin Kirkland
Ubuntu Server Developer
Canonical, LTD
[EMAIL PROTECTED]
GPG: 1024D/83A61194
diff --git a/src/utils/ecryptfs-setup-confidential b/src/utils/ecryptfs-setup-confidential
index df4e792..a6a21d7 100755
--- a/src/utils/ecryptfs-setup-confidential
+++ b/src/utils/ecryptfs-setup-confidential
@@ -1,6 +1,5 @@
 #!/bin/sh
-# This script sets up an ecryptfs mount in a user's ~/Private, configures
-# fstab, pam, and bash to attach and wrap on login.
+# This script sets up an ecryptfs mount in a user's ~/Private
 #
 # Originally ecryptfs-setup-pam-wrapped.sh by Michael Halcrow, IBM
 #
@@ -8,18 +7,19 @@
 # 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 "  [--mountpoint MOUNTPOINT] [--cryptdir CRYPTDIR]"
 	echo
-	echo " --username   Username for encrypted confidential mountpoint"
+	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 " --mountpoint Defaults to ~USER/Private, override here"
-	echo " --cryptdir   Defaults to ~USER/.Private, override here"
+	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"
@@ -27,12 +27,11 @@ usage() {
 	echo
 	echo "   Any of these parameters may be:"
 	echo "     1) exported as environment variables (USER, MOUNTPASS,"
-	echo "        LOGINPASS, MOUNTPOINT, CRYPTDIR)"
+	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, so be"
-	echo "   wary of shoulder surfers."
+	echo "   BEWARE: They will, however, be displayed on STDOUT"
 	echo
 	exit 1
 }
@@ -42,6 +41,13 @@ error() {
 	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
@@ -60,88 +66,105 @@ while [ ! -z "$1" ]; do
 			MOUNTPASS="$2"
 			shift 2
 		;;
-		--mountpoint)
-			MOUNTPOINT="$2"
-			shift 2
-		;;
-		--cryptdir)
-			CRYPTDIR="$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
-	read -p "Enter the username: " -r USER
-	if [ -z "$USER" ]; then
-		error "You must provide a username"
-	fi
-fi
-if ! grep "^$USER:" /etc/passwd >/dev/null; then
-	error "User [$USER] does not exist"
+	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
-	read -p "Enter your login passphrase: " -r LOGINPASS
-	if [ -z "$LOGINPASS" ]; then
-		error "You must provide the login passphrase"
-	fi
+	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
-	read -p "Enter your mount passphrase [leave blank to generate one]: " -r MOUNTPASS
-	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"`
-	fi
-fi
-
-if [ -z "$MOUNTPOINT" ]; then
-	read -p "Enter the confidential mountpoint [$HOME/Private]: " -r MOUNTPOINT
-	if [ -z "$MOUNTPOINT" ]; then
-		MOUNTPOINT="$HOME/Private"
-	fi
-fi
-
-if [ -z "$CRYPTDIR" ]; then
-	basename=`basename "$MOUNTPOINT"`
-	dir=`echo "$MOUNTPOINT" | sed "s/$basename$/\.$basename/"`
-	read -p "Enter the encrypted directory [$dir]: " -r CRYPTDIR
-	if [ -z "$CRYPTDIR" ]; then
-		CRYPTDIR="$dir"
-	fi
-fi
-
-if [ -f "/etc/pam.d/system-auth" ]; then
-	PAM_CONF=/etc/pam.d/system-auth
-elif [ -f "/etc/pam.d/common-auth" ]; then
-	PAM_CONF=/etc/pam.d/common-auth
-else
-	error "Cannot determine location of PAM system/common auth configuration"
+	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
 
-if [ -f "/lib/security/libpam_ecryptfs.so" ]; then
-	PAM_LIB=libpam_ecryptfs.so
-elif [ -f "/lib/security/pam_ecryptfs.so" ]; then
-	PAM_LIB=pam_ecryptfs.so
-else
-	error "Cannot find ecryptfs PAM library"
-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 "Using pam configuration file [$PAM_CONF]"
 echo
 echo "This script will attempt to set up your system to mount"
 echo "$MOUNTPOINT with eCryptfs automatically on login,"
@@ -156,95 +179,62 @@ echo
 
 ###############################################################################
 
-# Setup confidential directory in home
-sudo modprobe ecryptfs || error "Could not load ecryptfs driver"
-mkdir -m 500 -p "$CRYPTDIR" || error "Could not create crypt directory [$CRYPTDIR]"
+# 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]"
-chmod 700 "$MOUNTPOINT" || error "Could not change permissions on [$MOUNTPOINT]"
 touch "$MOUNTPOINT"/"NOT MOUNTED - Run ecryptfs-mount-confidential to mount this directory"
-chmod 500 "$MOUNTPOINT"
-
-# Check for an active mount
-sudo umount "$MOUNTPOINT" 2>/dev/null
-if mount | grep "$MOUNTPOINT type ecryptfs"; then
-	error "[$MOUNTPOINT] still mounted after umount"
-fi
-
-# Prune out of fstab
-tmpfile=`mktemp`
-grep -v "$MOUNTPOINT.*,ecryptfs_sig=.*" /etc/fstab > $tmpfile
-chmod --reference /etc/fstab $tmpfile
-sudo chown --reference /etc/fstab $tmpfile || error "Could not update /etc/fstab"
-sudo mv -f $tmpfile /etc/fstab || error "Could not update /etc/fstab"
-
-# Setup /etc/fstab
-# BUG: passwd will be momentarily visible in "ps -ef" output
-sudo mount -t ecryptfs "$CRYPTDIR" "$MOUNTPOINT" -o key=passphrase:passwd="$MOUNTPASS",ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_passthrough=n,no_sig_cache || error "Could not perform test ecryptfs mount"
-mtab=`cat /etc/mtab | grep "$CRYPTDIR $MOUNTPOINT ecryptfs rw,ecryptfs_sig=" | sed "s/\s0\s0$/,user,noauto 0 0/"`
-tmpfile1=`mktemp`
-cat /etc/fstab > $tmpfile1
-echo "$mtab" >> $tmpfile1
-chmod --reference /etc/fstab $tmpfile1
-sudo chown --reference /etc/fstab $tmpfile1
-sudo mv -f $tmpfile1 /etc/fstab || error "Could not append mount to /etc/fstab"
-sudo umount "$MOUNTPOINT" || error "Could not unmount [$MOUNTPOINT]"
-
-# Setup PAM
-tmpfile1=`mktemp`
-grep -v "pam_ecryptfs.so" $PAM_CONF > $tmpfile1
-tmpfile2=`mktemp`
-grep -B 100000 "auth\s.*pam_unix.so" $tmpfile1 | grep -v "auth\s.*pam_unix.so" > $tmpfile2
-echo "password required $PAM_LIB" >> $tmpfile2
-grep "auth\s.*pam_unix.so" $PAM_CONF >> $tmpfile2
-echo "auth required $PAM_LIB unwrap" >> $tmpfile2
-grep -A 100000 "auth\s.*pam_unix.so" $tmpfile1 | grep -v "auth\s.*pam_unix.so" >> $tmpfile2
-rm -f $tmpfile1
-chmod --reference $PAM_CONF $tmpfile2
-sudo chown --reference $PAM_CONF $tmpfile2 || error "Could not update PAM configuration"
-sudo mv -f $tmpfile2 $PAM_CONF || error "Could not update PAM configuration"
-
-# Setup bash profile
-if ! grep "ecryptfs-mount-confidential" $HOME/.bash_profile >/dev/null; then
-	echo "ecryptfs-mount-confidential" >> $HOME/.bash_profile || error "Could not configure bash profile"
-fi
-if ! grep "ecryptfs-umount-confidential" $HOME/.bash_logout >/dev/null; then
-	echo "ecryptfs-umount-confidential" >> $HOME/.bash_logout || error "Could not configure bash logout"
-fi
-
-# Setup gnome desktop autostart
-mkdir -p $HOME/.config/autostart/ 2>/dev/null
-echo "
-[Desktop Entry]
-Type=Application
-Name=Ecryptfs Mount Private
-Exec=/usr/bin/ecryptfs-mount-confidential
-X-GNOME-Autostart-enabled=true
-" > $HOME/.config/autostart/ecryptfs-mount-confidential.desktop || error "Could not create desktop autostart file"
 
 # Setup ~/.ecryptfs directory
 mkdir -m 700 $HOME/.ecryptfs 2>/dev/null
 touch $HOME/.ecryptfs/auto-mount || error "Could not setup ecryptfs auto-mount"
-# Backup any existing wrapped-passphrase
-if [ -z "$HOME/.ecryptfs/wrapped-passphrase" ]; then
-	timestamp=`date +%Y%m%d%H%M%S`
-	mv -f $HOME/.ecryptfs/wrapped-passphrase $HOME/.ecryptfs/wrapped-passphrase.$timestamp
+
+# 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
-# BUG: passphrases will be momentarily visible in "ps -ef" output
-ecryptfs-wrap-passphrase $HOME/.ecryptfs/wrapped-passphrase "$MOUNTPASS" "$LOGINPASS"
-chmod 400 $HOME/.ecryptfs/wrapped-passphrase
-chown $USERNAME:$USERNAME $HOME/.ecryptfs/wrapped-passphrase
-
-# Setup .ecryptfs/confidential to store the confidential mountpoint
-tmpfile1=`mktemp $HOME/.ecryptfs/confidential.XXXXXX`
-chmod 400 $tmpfile1
-chown $USERNAME:$USERNAME $tmpfile1
-grep -v "CONFIDENTIAL=" $HOME/.ecryptfs/confidential > $tmpfile1
-echo "CONFIDENTIAL=\"$MOUNTPOINT\"" >> $tmpfile1
-mv -f $tmpfile1 $HOME/.ecryptfs/confidential
+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."
+echo "Done configuring."
 echo
-echo "$USERNAME should log in and check the output of the 'mount' command."
+
+# 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

Attachment: signature.asc
Description: This is a digitally signed message part

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
eCryptfs-devel mailing list
eCryptfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ecryptfs-devel

Reply via email to