#!/bin/sh # # mount_encrypted [option] {label|device} # mount_encrypted -u {label|device} # # This is a user level script to mount (OR un-mount) an encrypted disks using # low level cryptsetup, or luks cryptsetup methods, via the linux dmsetup # mapper # # Options: # -u Unmount the Filesystem and Encryption then exit # -f Run fsck on filesystem before final mount # -m Just map the filesystem, don't try to mount it (future creation) # -x Force the use on X windows for password and Errors # -s Read password from stdin # -d debug output (non-X only) # # It reads password from the user via a TTY or X window display without # storing it, sets up the device mapper, and calls mount to mount the mapped # file system according to the "/etc/fstab" file. # # The script attempts to ensures things are setup right with a minimum of # errors, and provides both TTY and X window error reporting. On TTY's it # will report success or 'already done' non-errors on stdout, without # bothering the user if launched from non-TTY X window programs. # # Requirements... # * A properly defined and setup encrypted filesystem on some block device. # * "sudo cryptsetup" must be runable without a password, by the user. # * "/etc/fstab" entry to define user-level mount of the mapped device. # # See Script header for more details of setting up these requirements # # Anthony Thyssen July 2004 # ### # -------------------------------------------------------------------------- # Setup for Mounting Encrypted FS using this script... # # * Ensure the "cryptsetup" command is installed (part of redhat core) # # * Add "cryptsetup" to the sudo, to allow a user to run as root (no passwd) # visudo # anthony ALL=NOPASSWD:/sbin/cryptsetup # This appears to be quite safe, as this command does not provide users # direct access to the highly insecure "dmsetup table", which (for root) # can list the hashed encryption key of any currently mapped filesystem. # # * Create an empty disk partition, any filesystem type can be used. # This can be a local disk (hdaX), usb disk (sdaX), or loopback (loop1) # The device name is used (with '/' converted to '_' as the mapper label. # The mountpoint will be used as the name for the filesystem. # # * Fill the partition to encrypt with crap. # shred --verbose --iterations=1 /dev/sdb1 # or # dd if=/dev/urandom of=/dev/sdb1 # Make sure it is /dev/urandom not /dev/random which is slower # # * Create an Encrypted file system on a partition (for example on /dev/sdb1) # cryptsetup -c aes-cbc-essiv:sha256 -y -s 256 create luks-sdb1 /dev/sdb1 # password: ****** # password again: ****** # mkfs -j -m 0 -t ext3 /dev/mapper/luks-sdb1 # tune2fs -c 0 -i 0 -m 0 /dev/mapper/luks-sdb1 # cryptsetup remove luks-sdb1 # # Or a Luks Encrypted Partition (defined key encryption and multiple keys) # cryptsetup -y luksFormat /dev/sdb1 # Enter LUKS passphrase: ****** # Verify passphrase: ****** # cryptsetup isLuks /dev/sdb1 && echo YES # cryptsetup isLuks /dev/sdb1 && echo YES # cryptsetup luksOpen /dev/sdb1 sdb1 # password: ****** # mkfs -t ext3 /dev/mapper/luks-sdb1 # e2label /dev/mapper/luks-sdb1 crypted # tune2fs -c 0 -i 0 -m 0 /dev/mapper/luks-sdb1 # cryptsetup luksClose luks-sdb1 # # NOTE: The arguments for mapping the FS (luksOpen) are swapped! # # * Add a fstab entry defining the mappings device and mountpoint name. # /dev/mapper/luks-sdb1 /mnt/crypted ext3 noauto,noatime,user 0 0 # # The "luks-sdb1" is used to determine the physical partition that will be # used to set up the mapper file, as well as the encryption mapping. The # "luks-" prefix is optional, but recommented. You can also use "dev_" # instead. # # For VFAT file systems you may like to set owner, group and file/dir # permissions for the mounted filesystem appropriatally. # # * Create a mount point for the above fstab entry, for example... # mkdir /mnt/crypted # # * Mount it (The fstab ensures that root is not needed) # The given string is the name of the mountpoint directory # mount_encrypted crypted # password: ****** # or you can specify the full mountpoint path # mount_encrypted /mnt/crypted # password: ****** # # * Set up partition contents for ext2 or ext3 FS (once only as root) # so the user can write to partition as himself. # chown anthony.anthony /mnt/crypted # # * Unmount (when finished) # mount_encrypted -u crypted # # Luks Encrypted filesystem, Pros and Cons # * the mount parameters are swapped when compared to the lower level # encrypted mapping method. # * Multiple keys can be defined to mount the filesystem, which allows # for changing the password for a Luks encrypted file system without # reformating. # * The Password verify and mount is a good deal slower, but this is due to # "Key Strengthening" techniques used (see wikipedia). # * Luks filesystems are however easilly reconizable as a encrypted file # system, allowing more automated GUI mounting methods. A lower level # encryption however is not so easilly recognized, and could be varied. # # ------------------------------------------------------------------------- # PROGNAME=`type $0 | awk '{print $3}'` # search for executable on path PROGDIR=`dirname $PROGNAME` # extract directory of program PROGNAME=`basename $PROGNAME` # base name of program Usage() { # output the script comments as docs echo >&2 "$PROGNAME:" "$@" sed >&2 -n '/^###/q; /^#/!q; s/^#//; s/^ //; 3s/^/Usage: /; 2,$ p' \ "$PROGDIR/$PROGNAME" exit 10; } while [ $# -gt 0 ]; do case "$1" in --help|--doc*) Usage ;; -u) unmount=true ;; # Un-mount H-Drive only -f) fsck=true ;; # Run fsck before mounting -m) maponly=true ;; # Just map the filesystem, do not mount it -x) force_xwin=true ;; # Force use of X window popups (no tty) -s) force_stdin=true ;; # read password from stdin -d) DEBUG=true ;; # output the lower level commands used. --) shift; break ;; # end of user options -*) Usage "Unknown option \"$1\"" ;; *) break ;; # end of user options esac shift # next option done [ $# -eq 0 ] && Usage "Missing encrypted filesystem identifier" [ $# -gt 1 ] && Usage "Too many arguments: $@" # ---- Subroutines ---- cmd_found() { case "`type $1 2>&1`" in *'not found'*) return 1 ;; esac; return 0 } # STDERR Error message (output to tty or file) Tmessage() { echo >&2 "$PROGNAME:" "$@" } # X Windows Popup message Xmessage() { if cmd_found notify_message; then # personal message popups notify_message "$*" & elif cmd_found zenity; then zenity --info --title="$PROGNAME" --text="$*" & elif cmd_found xmessage; then xmessage -name "$PROGNAME" -center "$*" \ -xrm '*message.scrollVertical: false' \ >/dev/null /dev/null; then # tty is available Tmessage "$@" elif [ "$DISPLAY" ]; then # just do both Xmessage "$@" Tmessage "$@" else # doesn't look good, just output it Tmessage "No TTY or DISPLAY to notify user of error!" Tmessage "$@" fi exit 1 } # Is this device mapping label mounted? mounted() { mount | grep "^/dev/mapper/$1 on " >/dev/null } ASKPASS='' # The secure password asking program. # Fall back defaults... (these are unlikely to be needed) if cmd_found zenity; then ASKPASS="zenity --entry --hide-text --text" elif cmd_found pinentry; then ASKPASS=pin_entry pin_entry() { # wrapper for "pinentry" { echo "SETDESC $*" echo "GETPIN" } | pinentry | sed -n 's/^D //p' } fi # Figure out the best password entry method for X windows. # This needs to be re-done for i in ${X_ASKPASS:-not_found} \ /usr/libexec/openssh/x11-ssh-askpass \ /usr/libexec/openssh/ssh-askpass \ /usr/bin/ssh-askpass \ /usr/libexec/openssh/gnome-ssh-askpass \ /usr/lib/openssh/gnome-ssh-askpass ; do if [ -x "$i" ]; then ASKPASS="$i" break fi done # ---- Check Arguments - find file system details ---- if [ "$force_xwin" -a -z "$DISPLAY" ]; then Tmessage "Unable to force X windows, no DISPLAY set, continuing..." force_xwin='' fi if [ "$fsck" ]; then tty >/dev/null || ErrorExit "Unable to fsck without a TTY terminal" [ "$force_xwin" ] && ErrorExit "Unable to fsck using forced X Windows" [ "$unmount" ] && ErrorExit "Unable fsck encrypted mount, while unmounting it" fi # user supplied identifier or mountpoint of the encrypted filesystem fs=$(echo "$1" | sed 's/\/$//') # First try the filesystem as a mountpoint directory name (typical usage) # and lookup up the device filesystem name. case "$fs" in /*) mount_info=`awk '/^\/dev\/mapper\// && $2=="'"$fs"'"' /etc/fstab` ;; *) mount_info=`awk '/^\/dev\/mapper\// && $2 ~ /\/[^ ]*'"$fs"'/' /etc/fstab` ;; esac # Otherwise try the filesystem identifier as a device name in the fstab # Again look for it in the fstab if [ -z "$mount_info" ]; then case "$fs" in /dev/) label=`echo "$fs" | sed 's/^\/dev\///; s/\//_/g'` ;; *) label=`echo "$fs" | sed 's/\//_/g'` ;; esac mount_info=`grep "^/dev/mapper/$label" /etc/fstab` fi [ -z "$mount_info" ] && \ ErrorExit "Unable to find encrypted filesystem \"$fs\" in \"/etc/fstab\"" set -$- $mount_info label=`expr "$1" : '/dev/mapper/\(.*\)'` device="/dev/`echo $label | sed 's/luks-//; s/_/\//g; s/^dev\///'`" mountpoint="$2" [ "$DEBUG" ] && \ echo "fs=$fs label=$label device=$device mountpoint=$mountpoint" [ ! -b "$device" ] && ErrorExit "Filesystem "$fs" device \"$device\" is not a block device!" # what type of mount, dmcrypt, or luks? x_close=remove if sudo cryptsetup isLuks $device 2>/dev/null; then luks=Luks x_close=luksClose fi # --- Cleanup and Unmount --- # Unmount and unset any existing encrypted filesystem if mounted "$label"; then if [ -z "$unmount" ]; then # Already mounted! This is OK but if run from command line, report it OK "Encrypted FS \"$fs\" already mounted." exit 0 fi ( [ "$DEBUG" ] && set -x umount "/dev/mapper/$label" ) [ $? -ne 0 ] && ErrorExit "Umount of \"$fs\" Failed -- ABORTING" elif [ "$unmount" ]; then # Already unmounted! This is OK, but if run from command line, report it OK "Filesystem \"$fs\" already un-mounted." fi # Unmap any existing mapper device if [ -e "/dev/mapper/$label" ]; then [ "$DEBUG" ] && set -x sudo cryptsetup $x_close "$label" fi [ "$unmount" ] && exit 0 # --- Ensure we have a directory to mount to --- if [ ! -d "$mountpoint" ]; then # Mount point is not present - see if we can create one mkdir "$mountpoint" 2>/dev/null fi if [ ! -d "$mountpoint" ]; then # Mount point still not present ErrorExit "Directory for the mount \"$mountpoint\" is missing -- ABORTING" fi if [ -n "$(ls -A $mountpoint)" ]; then # Mount point still not present ErrorExit "Directory mount \"$mountpoint\" is not empty -- ABORTING" fi # --- Setup File System Encryption --- # Setup an encrypted file system mapper # Note that the arguments are swapped for cryptsetup, 'create' and 'luksOpen'! if tty >/dev/null || [ "$force_stdin" ] && [ -z "$force_xwin" ]; then # run from command line -- program asks direct from TTY or stdin tty >/dev/null && echo "Password for filesystem \"$fs\"" if [ "$luks" ]; then ( [ "$DEBUG" ] && set -x sudo cryptsetup luksOpen "$device" "$label" ) else ( [ "$DEBUG" ] && set -x sudo cryptsetup create "$label" "$device" ) fi elif [ "$DISPLAY" -a "$ASKPASS" ]; then # X windows available -- use graphical password reader if [ "$luks" ]; then ( [ "$DEBUG" ] && set -x $ASKPASS "Encrypted Luks FS \"$fs\"" |\ sudo cryptsetup luksOpen "$device" "$label" >/dev/null ) else ( [ "$DEBUG" ] && set -x $ASKPASS "Encrypted FS \"$fs\"" |\ sudo cryptsetup create "$label" "$device" ) fi else Tmessage "No TTY or DISPLAY to ask password for FS \"$fs\"" exit 1 fi if [ ! -e "/dev/mapper/$label" ]; then ErrorExit "Failed to setup mapping \"$label\" for \"$device\"! -- ABORTING" fi # --- Fsck Check --- (optional) [ "$fsck" ] && ( [ "$DEBUG" ] && set -x fsck -fCT "/dev/mapper/$label" ) if [ "$maponly" ]; then # If run from command line -- Report Success OK "Encrypted FS \"$fs\" mapped, but not mounted." exit 0 fi # --- Now Mount It --- error=`[ "$DEBUG" ] && set -x; mount "/dev/mapper/$label" 2>&1` # Clean up and report on failure if [ $? -ne 0 ]; then # remove mapper if it was created [ -e "/dev/mapper/$label" ] && ( [ "$DEBUG" ] && set -x sudo cryptsetup $x_close "$label" ) case "$error" in *'wrong fs type'*) ErrorExit "Failed to mount encrypted FS \"$fs\" from \"$device\" Wrong Password, or no Encrypted FS on device -- ABORTING" ;; *"/dev/mapper/$label does not exist"* |\ *"can't find /dev/mapper/$label "*) ErrorExit "Failed to mount encrypted FS \"$fs\" from \"$device\" Is the Mount point not setup correctly in \"/etc/fstab\"? -- ABORTING" ;; *) ErrorExit "Unknown failure to mount \"$fs\" from \"$device\" $error -- ABORTING" ;; esac exit 1 fi # Report Success OK "Encrypted FS \"$fs\" mounted." exit 0