Viewing file: ecryptfs-setup-private (15.02 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) | #!/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
# Copyright (C) 2008 Canonical Ltd.
# Copyright (C) 2007-2008 International Business Machines
PRIVATE_DIR="Private"
WRAPPING_PASS="LOGIN"
PW_ATTEMPTS=3
MESSAGE="Enter your login passphrase"
CIPHER="aes"
KEYBYTES="16"
FNEK=
# Zero out user-defined GREP_OPTIONS, such as --line-number
GREP_OPTIONS=
usage() {
echo
echo "Usage:"
echo " $0 [-f|--force] [-w|--wrapping] [--nopwcheck] [-n|--no-fnek]"
echo " [-u|--username USER] [-l|--loginpass LOGINPASS]"
echo " [-m|--mountpass MOUNTPASS]"
echo
echo " -f, --force Force overwriting of an existing setup"
echo " -w, --wrapping Use an independent wrapping passphrase,"
echo " different from the login passphrase"
echo " -n, --no-fnek Do not encrypt filenames; If this flag is"
echo " omitted, and the kernel supports filename"
echo " encryption, then filenames will be encrypted"
echo " -u, --username Username for encrypted private mountpoint,"
echo " defaults to yourself"
echo " -l, --loginpass Login/Wrapping passphrase for USER,"
echo " used to wrap MOUNTPASS"
echo " --nopwcheck Do not check the validity of the specified"
echo " login password (useful for LDAP user accounts)"
echo " --noautomount Setup this user such that the encrypted private"
echo " directory is not automatically mounted on login"
echo " --noautoumount Setup this user such that the encrypted private"
echo " directory is not automatically unmounted at"
echo " logout"
echo " -m, --mountpass Passphrase for mounting the ecryptfs directory,"
echo " defaults to randomly generated $KEYBYTES bytes"
echo " -b, --bootstrap Bootstrap a new user's entire home directory"
echo " Generates a random mount passphrase, which"
echo " will be wrapped when the new login passphrase"
echo " is set. SHOULD ONLY BE CALLED FROM 'adduser'."
echo " --undo Provide instructions on how to undo an"
echo " encrypted private setup"
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
exit 1
}
undo_msg() {
echo "
In the event that you want to remove your eCryptfs Private Directory setup,
you will need to very carefully perform the following actions manually:
1. Obtain your Private directory mountpoint
$ PRIVATE=\`cat ~/.ecryptfs/Private.mnt 2>/dev/null || echo \$HOME/Private\`
2. Ensure that you have moved all relevant data out of your \$PRIVATE directory
3. Unmount your encrypted private directory
$ ecryptfs-umount-private
4. Make your Private directory writable again
$ chmod 700 \$PRIVATE
5. Remove \$PRIVATE, ~/.Private, ~/.ecryptfs
Note: THIS IS VERY PERMANENT, BE VERY CAREFUL
$ rm -rf \$PRIVATE ~/.Private ~/.ecryptfs
6. Uninstall the utilities (this is specific to your Linux distribution)
$ sudo apt-get remove ecryptfs-utils libecryptfs0
"
}
error() {
echo "ERROR: $1" 1>&2
exit 1
}
error_testing() {
rm -f "$1" >/dev/null
/sbin/umount.ecryptfs_private >/dev/null
error "$2"
exit 1
}
random_passphrase () {
bytes=$1
# Pull $1 of random data from /dev/urandom,
# and convert to a string of hex digits
od -x -N $bytes --width=$bytes /dev/urandom | head -n 1 | sed "s/^0000000//" | sed "s/\s*//g"
}
filename_encryption_available() {
version=$(cat /sys/fs/ecryptfs/version 2>/dev/null)
[ -z "$version" ] && error "Can't get ecryptfs version, ecryptfs kernel module not loaded?"
[ $(($version & 0x100)) -eq 0 ] && return 1
return 0
}
filename_encryption_available && FNEK="--fnek"
if [ ! -z "$SUDO_USER" ]; then
USER="$SUDO_USER"
fi
while [ ! -z "$1" ]; do
case "$1" in
-u|--username)
USER="$2"
shift 2
;;
-l|--loginpass)
LOGINPASS="$2"
shift 2
;;
-m|--mountpass)
MOUNTPASS="$2"
shift 2
;;
-w|--wrapping)
WRAPPING_PASS="INDEPENDENT"
MESSAGE="Enter your wrapping passphrase"
shift 1
;;
-f|--force)
FORCE=1
shift 1
;;
--nopwcheck)
NOPWCHECK=1
shift 1
;;
--noautomount)
NOAUTOMOUNT=1
shift 1
;;
--noautoumount)
NOAUTOUMOUNT=1
shift 1
;;
--undo)
undo_msg
exit 0
;;
-b|--bootstrap)
[ `whoami` = "root" ] || error "You must be root to bootstrap encrypt a home directory"
BOOTSTRAP=1
MOUNTPASS=`random_passphrase $KEYBYTES`
RANDOM_MOUNTPASS=1
shift 1
;;
-n|--no-fnek)
FNEK=
shift 1
;;
*)
usage
;;
esac
done
# Prompt for the USER name, if not on the command line and not in the env
if [ -z "$USER" ]; then
while [ true ]; do
echo -n "Enter the username: "
USER=`head -n1`
echo
if [ -z "$USER" ]; then
echo "ERROR: You must provide a username"
continue
else
# Verify that the user exists
if ! id "$USER" >/dev/null; then
echo "ERROR: User [$USER] does not exist"
continue
fi
break
fi
done
else
# Verify that the user exists
id "$USER" >/dev/null || error "User [$USER] does not exist"
fi
# Check if user is member of ecryptfs group
if ! groups "$USER" | sed -e 's| |\n|g' | grep -q '^ecryptfs$'; then
error "User needs to be a member of ecryptfs group"
fi
# Obtain the user's home directory
HOME=`getent passwd "$USER" | awk -F: '{print $6}'`
if [ ! -d "$HOME" ]; then
error "User home directory [$HOME] does not exist"
fi
if [ "$BOOTSTRAP" = "1" ]; then
# If we want to encrypt the entire homedir, we need the .ecryptfs
# config dir elsewhere, but linked into the homedir
mkdir -p -m 700 /var/lib/ecryptfs/$USER
ln -sf /var/lib/ecryptfs/$USER $HOME/.ecryptfs
MOUNTPOINT="$HOME"
else
mkdir -m 700 $HOME/.ecryptfs
MOUNTPOINT="$HOME/$PRIVATE_DIR"
fi
# Check for previously setup private directory
if [ -s "$HOME/.ecryptfs/wrapped-passphrase" -a "$FORCE" != "1" ]; then
error "wrapped-passphrase file already exists, use --force to overwrite."
fi
if [ -s "$HOME/.ecryptfs/$PRIVATE_DIR.sig" -a "$FORCE" != "1" ]; then
error "$PRIVATE_DIR.sig file already exists, use --force to overwrite."
fi
# Check for active mounts
CRYPTDIR="$HOME/.$PRIVATE_DIR"
grep -qs "$MOUNTPOINT " /proc/mounts && error "[$MOUNTPOINT] is already mounted"
grep -qs "$CRYPTDIR " /proc/mounts && error "[$CRYPTDIR] is already mounted"
# Check that the mount point and encrypted directory are empty (skip symlinks).
# Perhaps one day we could provide a migration mode (using rsync or something),
# but this would be VERY hard to do safely.
count=`ls -Al "$MOUNTPOINT" 2>/dev/null | egrep -c "^[drwx-]{10}"`
if [ "$count" != "0" ]; then
error "$MOUNTPOINT must be empty before proceeding"
fi
count=`ls -Al "$CRYPTDIR" 2>/dev/null | egrep -c "^[dlrwx-]{10}"`
if [ "$count" != "0" ]; then
error "$CRYPTDIR must be empty before proceeding"
fi
stty_orig=`stty -g`
# Prompt for the LOGINPASS, if not on the command line and not in the env
if [ -z "$LOGINPASS" ] && [ "$BOOTSTRAP" != "1" ]; then
tries=0
while [ $tries -lt $PW_ATTEMPTS ]; do
stty -echo
echo -n "$MESSAGE: "
LOGINPASS=`head -n1`
stty $stty_orig
echo
if [ $WRAPPING_PASS != "LOGIN" -o ! -x /sbin/unix_chkpwd ]; then
# If we can't check the accuracy of the user's entered
# passphrase, force them to type it twice (matching)
stty -echo
echo -n "$MESSAGE (again): "
LOGINPASS2=`head -n1`
stty $stty_orig
echo
if [ "$LOGINPASS" != "$LOGINPASS2" ]; then
echo "ERROR: Wrapping passphrases must match"
else
break
fi
tries=$(($tries + 1))
continue
fi
if [ -z "$LOGINPASS" ]; then
echo "ERROR: You must provide a login passphrase"
tries=$(($tries + 1))
else
if [ "$NOPWCHECK" = "1" ]; then
echo "INFO: Skipping password verification"
break
else
if printf "%s\0" "$LOGINPASS" | /sbin/unix_chkpwd "$USER" nullok; then
break
else
echo "ERROR: Your login passphrase is incorrect"
tries=$(($tries + 1))
fi
fi
fi
done
if [ $tries -ge $PW_ATTEMPTS ]; then
echo "ERROR: Too many incorrect password attempts, exiting"
exit 1
fi
fi
# Prompt for the MOUNTPASS, if not on the command line and not in the env
if [ -z "$MOUNTPASS" ]; then
tries=0
while [ $tries -lt $PW_ATTEMPTS ]; do
stty -echo
echo -n "Enter your mount passphrase [leave blank to generate one]: "
MOUNTPASS=`head -n1`
stty $stty_orig
echo
if [ -z "$MOUNTPASS" ]; then
MOUNTPASS=`random_passphrase $KEYBYTES`
RANDOM_MOUNTPASS=1
break
else
stty -echo
echo -n "Enter your mount passphrase (again): "
MOUNTPASS2=`head -n1`
stty $stty_orig
echo
if [ "$MOUNTPASS" != "$MOUNTPASS2" ]; then
echo "ERROR: Mount passphrases do not match"
tries=$(($tries + 1))
else
break
fi
fi
done
if [ $tries -ge $PW_ATTEMPTS ]; then
echo "ERROR: Too many incorrect passphrase attempts, exiting"
exit 1
fi
fi
#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 "************************************************************************"
if [ "$RANDOM_MOUNTPASS" = "1" ]; then
echo "YOU SHOULD RECORD THIS MOUNT PASSPHRASE AND STORE IN A SAFE LOCATION:"
echo "$MOUNTPASS"
else
echo "YOU SHOULD RECORD YOUR MOUNT PASSPHRASE AND STORE IN A SAFE LOCATION:"
fi
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 -sf /usr/share/ecryptfs-utils/ecryptfs-mount-private.txt "$MOUNTPOINT"/README.txt
ln -sf /usr/share/ecryptfs-utils/ecryptfs-mount-private.desktop "$MOUNTPOINT"/Access-Your-Private-Data.desktop
chmod 500 "$MOUNTPOINT"
# Setup ~/.ecryptfs directory
if [ "$NOAUTOMOUNT" = "1" ]; then
echo "INFO: $HOME/$PRIVATE_DIR will not be mounted on login"
else
touch $HOME/.ecryptfs/auto-mount || error "Could not setup ecryptfs auto-mount"
fi
if [ "$NOAUTOUMOUNT" = "1" ]; then
echo "INFO: $HOME/$PRIVATE_DIR will not be unmounted on logout"
else
touch $HOME/.ecryptfs/auto-umount || error "Could not setup ecryptfs auto-umount"
fi
if [ "$WRAPPING_PASS" = "LOGIN" ]; then
rm -f $HOME/.ecryptfs/wrapping-independent || error "Could not remove ecryptfs wrapping-independent"
else
touch $HOME/.ecryptfs/wrapping-independent || error "Could not setup ecryptfs wrapping-independent"
fi
# 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
if [ "$BOOTSTRAP" = "1" ]; then
# This will be wrapped by pam_ecryptfs's chauthtok as soon as the user
# chooses a password. Until that happens (hopefully soon), standard
# file permissions (600) are all that's protecting it. Write it to
# ramdisk, to keep it from leaking to the hard-drive.
temp=`mktemp /dev/shm/.ecryptfs-XXXXXX`
printf "%s" "$MOUNTPASS" > "$temp"
mv "$temp" "/dev/shm/.ecryptfs-$USER"
else
printf "%s\n%s" "$MOUNTPASS" "$LOGINPASS" | ecryptfs-wrap-passphrase "$HOME/.ecryptfs/wrapped-passphrase" - || error "Could not wrap passphrase"
fi
umask $u
# Add the passphrase to current keyring
# On subsequent logins, this should be handled by "pam_ecryptfs.so unwrap"
response=`printf "%s" "$MOUNTPASS" | ecryptfs-add-passphrase $FNEK -`
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]{$KEYBYTES,$KEYBYTES}$"; then
error "Could not obtain the key signature"
fi
temp=`mktemp`
echo "$sig" > "$temp" || error "Could not create signature file [$HOME/.ecryptfs/$PRIVATE_DIR.sig]"
mv "$temp" "$HOME/.ecryptfs/$PRIVATE_DIR.sig"
temp=`mktemp`
echo "$MOUNTPOINT" > "$temp" || error "Could not create mountpoint file [$HOME/.ecryptfs/$PRIVATE_DIR.mnt]"
mv "$temp" "$HOME/.ecryptfs/$PRIVATE_DIR.mnt"
echo
echo "Done configuring."
echo
# Skip the tests if we're in bootstrap mode, but exit with the encrypted
# homedir mounted
if [ "$BOOTSTRAP" = "1" ]; then
# Force the mount here, since the root user has the key loaded,
# and the calling 'adduser' is about to copy over /etc/skel
# NOTE: it is the responsibility of 'adduser' to unmount!
# And ensure that $USER owns the files/dirs we've created as root
chown $USER:$USER "$CRYPTDIR" /dev/shm/.ecryptfs-$USER
if [ "$FNEK" = "--fnek" ]; then
fnek_sig=`tail -n 1 "$HOME/.ecryptfs/$PRIVATE_DIR.sig"`
sig=`head -n 1 "$HOME/.ecryptfs/$PRIVATE_DIR.sig"`
sig_opt="ecryptfs_sig=$sig,ecryptfs_fnek_sig=$fnek_sig"
else
sig_opt="ecryptfs_sig=$sig"
fi
mount -i -t ecryptfs -o "rw,$sig_opt,ecryptfs_cipher=$CIPHER,ecryptfs_key_bytes=$KEYBYTES" "$CRYPTDIR" "$MOUNTPOINT" || error "Could not mount"
ln -sf /var/lib/ecryptfs/$USER $MOUNTPOINT/.ecryptfs
for i in auto-mount \
auto-umount \
$PRIVATE_DIR.mnt \
$PRIVATE_DIR.sig \
wrapped-passphrase;
do
[ -e $HOME/.ecryptfs/$i ] && chown $USER:$USER $MOUNTPOINT/.ecryptfs/$i
done
chown $USER:$USER /var/lib/ecryptfs/$USER
chown -h $USER:$USER $MOUNTPOINT/.ecryptfs
exit 0
fi
# Now let's perform some basic mount/write/umount/read sanity testing...
echo "Testing mount/write/umount/read..."
/sbin/mount.ecryptfs_private || error "Could not mount private ecryptfs directory"
temp=`mktemp "$MOUNTPOINT/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"
/sbin/umount.ecryptfs_private || error_testing "$temp" "Could not unmount private ecryptfs directory"
/sbin/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"
# Use ecryptfs-umount-private on the final run, to clear the used keys
# out of the keyring
ecryptfs-umount-private || error_testing "$temp" "Could not unmount private ecryptfs directory (2)"
if [ "$md5sum1" != "$md5sum2" ]; then
error "Testing failed."
else
echo "Testing succeeded."
fi
echo
echo "Logout, and log back in to begin using your encrypted directory."
echo
exit 0
|