[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
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