commit 465e2f63e5453b470dd605a46f3ff551fde07d23
parent 613fb37cc7cfcdd4274266be435e1d19d49397ee
Author: Jaromil <jaromil@dyne.org>
Date: Thu, 3 Feb 2011 17:11:08 +0100
relevant code cleanup
reenginered priviled escalation
fixed more test cases
Diffstat:
M | src/tomb | | | 294 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | src/tomb-open | | | 8 | +++++++- |
2 files changed, 205 insertions(+), 97 deletions(-)
diff --git a/src/tomb b/src/tomb
@@ -20,8 +20,8 @@
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-VERSION=0.9
-DATE=Jan/2011
+VERSION=0.9.1
+DATE=Feb/2011
# PATH=/usr/bin:/usr/sbin:/bin:/sbin
@@ -50,6 +50,10 @@ fi
# usb auto detect using dmesg
# tested on ubuntu 10.04 - please test and patch on other systems if you can
+# TODO: use udev rules, see how archlinux folks document it - arch rox 8)
+# https://wiki.archlinux.org/index.php/System_Encryption_with_LUKS_for_dm-crypt
+# here we could modularize the choice of methods using function pointers,
+# so that they are configurable when calling tomb.
ask_usbkey() {
notice "Waiting 1 minute for a usb key to connect"
echo -n " . please insert your usb key "
@@ -127,15 +131,16 @@ ask_usbkey() {
# user interface (just to ask the password)
ask_password() {
- exec_as_user xhost 2>/dev/null
+ exec_as_user xhost # 2&>1 >/dev/null
if [ $? = 0 ]; then # we have access to the X display
- exec_as_user which tomb-askpass
+ exec_as_user which tomb-askpass # 2&>1 > /dev/null
if [ $? = 0 ]; then
- keyname=`basename $enc_key | cut -d. -f1`
- export scolopendro="`exec_as_user tomb-askpass $keyname`"
+ export scolopendro="`exec_as_user tomb-askpass ${1} 2>/dev/null`"
return
- elif [ -x /usr/bin/ssh-askpass ]; then # debian has this
+ fi
+ exec_as_user which ssh-askpass # 2&>1 > /dev/null
+ if [ $? = 0 ]; then
export scolopendro="`exec_as_user ssh-askpass "Tomb: provide the password to unlock"`"
return
fi
@@ -146,6 +151,7 @@ ask_password() {
echo -n " > "
read -s scolopendro
export scolopendro
+
fi
# just in case we'd like to have dialog supported too:
@@ -157,22 +163,69 @@ ask_password() {
# popup notification
tomb-notify() {
+ # look for our icon in common prefixes
+ if [ -r /usr/share/pixmaps/monmort.xpm ]; then icon=/usr/share/pixmaps/monmort.xpm
+ elif [ -r /usr/share/icons/monmort.xpm ]; then icon=/usr/share/icons/monmort.xpm
+ elif [ -r /usr/local/share/pixmaps/monmort.xpm ]; then icon=/usr/local/share/pixmaps/monmort.xpm
+ elif [ -r /usr/local/share/icons/monmort.xpm ]; then icon=/usr/local/share/icons/monmort.xpm
+ elif [ -r /opt/share/pixmaps/monmort.xpm ]; then icon=/opt/share/pixmaps/monmort.xpm
+ elif [ -r /sw/share/pixmaps/monmort.xpm ]; then icon=/sw/share/pixmaps/monmort.xpm
+ fi
+
if [ -z $1 ]; then
- exec_as_user notify-send -i monmort \
+ exec_as_user notify-send -i $icon \
-u low -h string:App:Tomb \
-h double:Version:${VERSION} \
"Tomb version $VERSION" \
"Hi, I'm the Undertaker.
Let's start setting your Crypt?"
else
- exec_as_user notify-send -i monmort ${@}
+ exec_as_user notify-send -i $icon ${@}
fi
}
# drop privileges
exec_as_user() {
+
+ if ! [ $SUDO_USER ]; then
+ exec $@[@]
+ return $?
+ fi
+
func "executing as user '$SUDO_USER': ${(f)@}"
- sudo -u $SUDO_USER ${@}
+ which gksu > /dev/null
+ if [ $? = 0 ]; then
+ func "Using gksu for execution of '${(f)@}' as user $SUDO_USER"
+ gksu -u $SUDO_USER "${@[@]}"
+ return $?
+ fi
+ which sudo > /dev/null
+ if [ $? = 0 ]; then
+ func "Using sudo for execution of '${(f)@}' as user $SUDO_USER"
+ sudo -u $SUDO_USER "${@[@]}"
+ return $?
+ fi
+}
+
+
+# escalate privileges
+check_priv() {
+ id | grep root > /dev/null
+ if [ $? != 0 ]; then
+ which gksu > /dev/null
+ if [ $? = 0 ]; then
+ func "Using gksu for root execution of 'tomb ${(f)ARGS}'"
+ gksu "tomb ${ARGS[@]}"
+ exit $?
+ fi
+ which sudo > /dev/null
+ if [ $? = 0 ]; then
+ func "Using sudo for root execution of 'tomb ${(f)ARGS}'"
+ sudo "tomb ${ARGS[@]}"
+ exit $?
+ fi
+ exit 1
+ fi
}
@@ -184,9 +237,9 @@ notice "Tomb - simple commandline tool for encrypted storage"
act "version $VERSION ($DATE) by Jaromil @ dyne.org"
func "invoked with args \"${(f)@}\" "
func "running on `date`"
+ARGS=$@[@]
-
-OPTS=`getopt -o hvs:k:S -n 'tomb' -- "$@"`
+OPTS=`getopt -o hvDs:k: -n 'tomb' -- "$@"`
while true; do
case "$1" in
-h)
@@ -196,6 +249,7 @@ while true; do
notice "Options:"
act "-h print this help"
act "-v print out the version information for this tool"
+ act "-D print out debugging information at runtime"
act "-s size of the storage file when creating one (MB)"
act "-k path to the key to use for decryption"
act "-S acquire super user rights if possible"
@@ -216,37 +270,7 @@ BEGIN { license=0 }
'
act ""
exit 0 ;;
- -S) GETPRIV=true; shift 1 ;;
- *) break ;;
- esac
-done
-
-id | grep root > /dev/null
-if [ $? != 0 ]; then
- if [ "$GETPRIV" = "true" ]; then
- which gksu > /dev/null
- if [ $? = 0 ]; then
- act "Using gksu for root execution of 'tomb ${(f)@}'"
- gksu "tomb ${(f)@}"
- exit $?
- fi
- which sudo > /dev/null
- if [ $? = 0 ]; then
- act "Using sudo for root execution of 'tomb ${(f)@}'"
- sudo "tomb ${(f)@}"
- exit $?
- fi
- exit 1
- else
- error "This program must be run as root to produce results"
- exit 1
- fi
-fi
-
-# now process the real options
-OPTS=`getopt -o hvs:k:S -n 'tomb' -- "$@"`
-while true; do
- case "$1" in
+ -D) DEBUG=1; shift 1 ;;
-s) SIZE=$2; shift 2 ;;
-k) KEY=$2; shift 2 ;;
--) shift; break ;;
@@ -257,6 +281,7 @@ while true; do
done
+
if [ -z $CMD ]; then
error "first argument missing, use -h for help"
tomb-notify
@@ -279,11 +304,14 @@ fi
create_tomb() {
+# make sure the file has a .tomb extension
+ FILE="${FILE%\.*}.tomb"
+
if [ -e "$FILE" ]; then
error "$FILE exists already. I'm not digging here."
exit 1
fi
-
+
notice "Creating a new tomb"
if [ -z $SIZE ]; then
if [ $MOUNT ]; then
@@ -296,12 +324,8 @@ create_tomb() {
fi
fi
-# make sure the file has a .tomb extension
- FILE="${FILE%\.*}.tomb"
-
SIZE_4k=`expr $SIZE \* 1000 / 4`
act "Generating ${FILE} of ${SIZE}Mb (${SIZE_4k} blocks of 4Kb)"
-# TODO: use dd_rescue
$DD if=/dev/urandom bs=4k count=${SIZE_4k} of=${FILE}
if [ $? = 0 -a -e ${FILE} ]; then
@@ -311,34 +335,78 @@ create_tomb() {
exit 1
fi
- mkdir -p /tmp/tomb
-
modprobe dm-crypt
modprobe aes-i586
nstloop=`losetup -f` # get the number for next loopback device
losetup -f ${FILE} # allocates the next loopback for our file
- keytmp=`tempfile`
+
+ # create the keyfile in tmpfs so that we leave less traces in RAM
+ keytmp=`tempfile -p tomb`
+ rm -f $keytmp
+ mkdir -p $keytmp
+ mount tmpfs ${keytmp} -t tmpfs -o size=1m
+ if [ $? != 0 ]; then
+ error "cannot mount tmpfs filesystem in volatile memory"
+ error "operation aborted."
+ losetup -d $nstloop
+ rm -r $keytmp
+ exit 1
+ fi
act "Generating secret key..."
act "this operation takes time, keep using this computer on other tasks,"
act "once done you will be asked to choose a password for your tomb."
- cat /dev/urandom | dd bs=1 count=256 of=${keytmp}
-
+ touch ${keytmp}/tomb.tmp
+ chmod 0600 ${keytmp}/tomb.tmp
+ $DD bs=1 count=256 if=/dev/urandom of=${keytmp}/tomb.tmp
+ if ! [ -r ${keytmp}/tomb.tmp ]; then
+ error "cannot generate encryption key, operation aborted."
+ umount ${keytmp}
+ losetup -d $nstloop
+ rm -r $keytmp
+ exit 1
+ fi
+
notice "Setup your secret key file ${FILE}.gpg"
tomb-notify "The Tomb key is being forged:" "please set your password."
+
# here user is prompted for key password
- gpg -o "${FILE}.gpg" --no-options --openpgp -c -a ${keytmp}
- while [ $? = 2 ]; do
- gpg -o "${FILE}.gpg" --no-options --openpgp -c -a ${keytmp}
+ for c in 1 2 3; do
+ # 3 tries to write two times a matching password
+ ask_password ${FILE}
+ scolotemp=$scolopendro
+ ask_password "${FILE} (again)"
+ if [ "$scolotemp" = "$scolopendro" ]; then
+ break;
+ fi
+ unset $scolotemp
+ unset $scolopendro
done
+
+ if [ -z $scolopendro ]; then
+ error "passwords don't match, aborting operation"
+ umount ${keytmp}
+ losetup -d $nstloop
+ rm -r $keytmp
+ exit 1
+ fi
+
+ echo "${scolopendro}" | gpg --batch --no-options --no-tty --passphrase-fd 0 \
+ -o "${FILE}.gpg" -c -a ${keytmp}/tomb.tmp
+ if [ $? = 2 ]; then
+ error "setting password failed: gnupg returns 2"
+ umount ${keytmp}
+ losetup -d $nstloop
+ rm -r $keytmp
+ exit 1
+ fi
act "formatting Luks mapped device"
- # dm-crypt only supports sha1
- # but we can use aes-cbc-essiv with sha256 for better security
- # see http://clemens.endorphin.org/LinuxHDEncSettings
+ # we use aes-cbc-essiv with sha256
+ # for security, performance and compatibility
cryptsetup --batch-mode \
--cipher aes-cbc-essiv:sha256 --key-size 256 \
- luksFormat ${nstloop} ${keytmp}
+ luksFormat ${nstloop} ${keytmp}/tomb.tmp
if ! [ $? = 0 ]; then
act "operation aborted."
@@ -346,8 +414,10 @@ create_tomb() {
fi
- cryptsetup --key-file ${keytmp} --cipher aes luksOpen ${nstloop} tomb.tmp
- ${WIPE[@]} ${keytmp}
+ cryptsetup --key-file ${keytmp}/tomb.tmp --cipher aes luksOpen ${nstloop} tomb.tmp
+ ${WIPE[@]} ${keytmp}/tomb.tmp
+ umount ${keytmp}
+ rm -r ${keytmp}
notice "Your tomb is ready on ${FILE} and secured with key ${FILE}.gpg"
act "Would you like to save the key on an external usb device?"
@@ -393,12 +463,24 @@ create_tomb() {
mount_tomb() {
- if [ -z $KEY ]; then
+ if ! [ -r $FILE ]; then
+# try also adding a .tomb extension
+ FILEtomb="${FILE%\.*}.tomb"
+ if ! [ -r $FILEtomb ]; then
+ error "cannot find a tomb named $FILE"
+ exit 1
+ else
+ FILE=$FILEtomb
+ fi
+ fi
+
+ if ! [ $KEY ]; then
enc_key="`basename ${FILE}.gpg`"
else
enc_key="$KEY"
fi
+
notice "mounting $FILE on mountpoint $MOUNT"
if [ -z $MOUNT ]; then
MOUNT=/media/`basename ${FILE}`
@@ -447,13 +529,17 @@ mount_tomb() {
mapper="tomb.`basename $FILE | cut -d. -f1`.$mapdate.`basename $nstloop`"
notice "Password is required for key ${enc_key}"
+ keyname=`basename $enc_key | cut -d. -f1`
for c in 1 2 3; do
- ask_password
-
+ if [ $c = 1 ]; then
+ ask_password ${keyname}
+ else
+ ask_password "$keyname (retry $c)"
+ fi
echo "${scolopendro}" \
- | gpg --passphrase-fd 0 --no-tty --no-options \
- -d "${enc_key}" 2>/dev/null \
+ | gpg --batch --passphrase-fd 0 --no-tty --no-options \
+ -d "${enc_key}" 2>/dev/null \
| cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
unset scolopendro
@@ -475,7 +561,7 @@ mount_tomb() {
mount -o rw,noatime,nodev /dev/mapper/${mapper} ${MOUNT}
- # Ensure the user can write the disk
+ # Ensure the user can write the disk - 10x Hellekin :)
ME=${SUDO_USER:-$(whoami)}
chmod 0750 ${MOUNT}
chown $(id -u $ME):$(id -g $ME) ${MOUNT}
@@ -490,7 +576,7 @@ umount_tomb() {
if [ -z $FILE ]; then
- how_many_tombs=$(2>/dev/null (ls /dev/mapper/tomb.* | wc -w))
+ how_many_tombs=`ls /dev/mapper/tomb.* 2> /dev/null | wc -w`
if [ $how_many_tombs = 0 ]; then
error "there is no open tomb to be closed"
exit 0
@@ -503,21 +589,23 @@ umount_tomb() {
exit 1
fi
- else
-
- if [ -r $FILE ]; then
- mapper=$FILE
- elif [ -r /dev/mapper/${FILE} ]; then
- mapper=/dev/mapper/${FILE}
- else
- error "tomb not found: $FILE"
- error "please specify an existing /dev/mapper/tomb.*"
- ls /dev/mapper/tomb.*
- exit 1
- fi
-# FILE=`mount | grep $mapper | awk '{print $3}'`
+ fi
+ if [ -r $FILE ]; then # accepts relative and absolute path
+ mapper=$FILE
+ elif [ -r /dev/mapper/${FILE} ]; then
+ mapper=/dev/mapper/${FILE}
fi
+
+ if ! [ -r $mapper ]; then
+ error "tomb not found: $mapper"
+ error "please specify an existing /dev/mapper/tomb.*"
+ ls /dev/mapper/tomb.*
+ tomb-notify "My tomb vanished" "Crypto undertaker will rest in peace."
+ killall -e ${mapper}
+ exit 1
+ fi
+
# if [ "$mapper" = "" ]; then
# error "$FILE is not mounted"
@@ -535,11 +623,16 @@ umount_tomb() {
basemap=`basename $mapper`
tombname=`echo ${basemap} | cut -d. -f2`
- errno=`umount ${mapper}`
- if ! [ $? = 0 ]; then
- tomb-notify "Tomb '$tombname' is too busy." \
- "Close all applications and file managers, then try again."
- exit 1
+ act "closing tomb $tombname on dm-crypt $basemap"
+
+ mount | grep $mapper 2&>1 > /dev/null
+ if [ $? = 0 ]; then # still mounted
+ errno=`umount ${mapper}`
+ if ! [ $? = 0 ]; then
+ tomb-notify "Tomb '$tombname' is too busy." \
+ "Close all applications and file managers, then try again."
+ exit 1
+ fi
fi
cryptsetup luksClose $basemap
@@ -568,7 +661,7 @@ umount_tomb() {
# install mime-types, bells and whistles for the desktop
# see http://developers.sun.com/solaris/articles/integrating_gnome.html
# and freedesktop specs
-install() {
+install_tomb() {
# TODO: distro package deps (for binary)
# debian: zsh, cryptsetup, libgtk2.0-0, libnotify-bin
@@ -653,25 +746,34 @@ tomb
EOF
act "Tomb is now installed."
}
+
+kill_tomb() {
+ # TODO: fixME - should close all tombs
+ umount /tmp/tomb* 2&>1 > /dev/null
+ # todo check which are tomb loops
+ losetup -d /dev/loop* 2&>1 > /dev/null
+}
+
case "$CMD" in
- create) create_tomb ;;
+ create) check_priv ; create_tomb ;;
- mount) mount_tomb ;;
- open) mount_tomb ;;
+ mount) check_priv ; mount_tomb ;;
+ open) check_priv ; mount_tomb ;;
- umount) umount_tomb ;;
- unmount) umount_tomb ;;
- close) umount_tomb ;;
+ umount) check_priv ; umount_tomb ;;
+ unmount) check_priv ; umount_tomb ;;
+ close) check_priv ; umount_tomb ;;
- install) install ;;
+ install) check_priv ; install_tomb ;;
+ kill) check_priv ; kill_tomb ;;
status) tomb-status ;;
notify) tomb-notify $CMD2 $CMD3 ;;
*) error "command \"$CMD\" not recognized"
act "try -h for help"
- break
+ exit 1
;;
esac
diff --git a/src/tomb-open b/src/tomb-open
@@ -77,7 +77,7 @@ if [ "$1" != "create" ]; then
fi
# start guided tomb creation
-tomb -S notify
+tomb notify
cat <<EOF
Create a new Tomb
=================
@@ -128,6 +128,12 @@ cat <<EOF
password:
EOF
tomb -S create ${filename}.tomb $size
+if [ $? != 0 ]; then
+ echo "An error occurred creating tomb, operation aborted"
+ tomb -S kill
+ read -q
+ exit 1
+fi
if ! [ -r /usr/share/applications/tomb.desktop ]; then
echo " Well done!"
echo " Now the last thing to do is to install Tomb on your desktop:"