improvements

This commit is contained in:
Anathema 2011-04-10 21:38:01 +02:00 committed by Jaromil
parent 1b38029474
commit 569a4d341f

324
src/tomb
View File

@ -23,6 +23,8 @@
VERSION=1.0 VERSION=1.0
DATE=Feb/2011 DATE=Feb/2011
TOMBEXEC=$0 TOMBEXEC=$0
TOMBOPENEXEC="tomb-open"
STEGHIDE=1
# PATH=/usr/bin:/usr/sbin:/bin:/sbin # PATH=/usr/bin:/usr/sbin:/bin:/sbin
@ -33,36 +35,52 @@ act() { if ! [ $QUIET ]; then echo " . $1" >&2; fi }
error() { if ! [ $QUIET ]; then echo "[!] $1" >&2; fi } error() { if ! [ $QUIET ]; then echo "[!] $1" >&2; fi }
func() { if [ $DEBUG ]; then echo "[D] $1" >&2; fi } func() { if [ $DEBUG ]; then echo "[D] $1" >&2; fi }
# which dd command to use
which dcfldd > /dev/null
if [ $? = 0 ]; then
DD="dcfldd"
else
DD=dd
fi
# which wipe command to use check_bin() {
which wipe > /dev/null # which dd command to use
if [ $? = 0 ]; then which dcfldd > /dev/null
WIPE=(wipe -f -s) if [ $? = 0 ]; then
else DD="dcfldd"
WIPE=(rm -f) else
fi DD=dd
fi
# check for filesystem creation progs # which wipe command to use
which mkfs.ext4 > /dev/null which wipe > /dev/null
if [ $? = 0 ]; then if [ $? = 0 ]; then
MKFS=(mkfs.ext4 -q -F -j -L) WIPE=(wipe -f -s)
else else
MKFS=(mkfs.ext3 -q -F -j -L) WIPE=(rm -f)
fi fi
# check for sudo # check for filesystem creation progs
which sudo > /dev/null which mkfs.ext4 > /dev/null
if [ $? != 0 ]; then if [ $? = 0 ]; then
error "Cannot find sudo. Please install it" MKFS=(mkfs.ext4 -q -F -j -L)
exit 1 else
fi MKFS=(mkfs.ext3 -q -F -j -L)
fi
# check for sudo
which sudo > /dev/null
if [ $? != 0 ]; then
error "Cannot find sudo. Please install it"
exit 1
fi
# check for steghide
which steghide > /dev/null
if [ $? != 0 ]; then
STEGHIDE=0
fi
# check for tomb-open script
if [ "$0" = "./tomb" ]; then
TOMBOPENEXEC="./tomb-open"
elif [ "$0" != "tomb" ]; then
TOMBOPENEXEC="`dirname $0`/tomb-open"
fi
}
# safe dir creation function # safe dir creation function
safe_dir() { safe_dir() {
@ -97,7 +115,6 @@ EOF
# drop privileges # drop privileges
exec_as_user() { exec_as_user() {
if ! [ $SUDO_USER ]; then if ! [ $SUDO_USER ]; then
exec $@[@] exec $@[@]
return $? return $?
@ -111,10 +128,9 @@ exec_as_user() {
# escalate privileges # escalate privileges
check_priv() { check_priv() {
id | grep root > /dev/null if [ $UID != 0 ]; then
if [ $? != 0 ]; then
func "Using sudo for root execution of 'tomb ${(f)ARGS}'" func "Using sudo for root execution of 'tomb ${(f)ARGS}'"
# check if sudo has a timestamp active # check if sudo has a timestamp active
sudok=false sudok=false
sudo -n ${TOMBEXEC} 2> /dev/null sudo -n ${TOMBEXEC} 2> /dev/null
if [ $? != 0 ]; then # if not then ask a password if [ $? != 0 ]; then # if not then ask a password
@ -214,59 +230,7 @@ Please report bugs on <http://bugs.dyne.org>.
EOF EOF
} }
############################
### main()
###
echo $@ | grep '\-D' 2>&1 > /dev/null
if [ $? = 0 ]; then
fi
ARGS=$@[@]
OPTS=`getopt -o hvqDs:k:n -n 'tomb' -- "$@"`
while true; do
case "$1" in
-h)
usage
exit 0 ;;
-v)
notice "Tomb - simple commandline tool for encrypted storage"
act "version $VERSION ($DATE) by Jaromil @ dyne.org"
# print out the GPL license in this file
act ""
cat $0 | awk '
BEGIN { license=0 }
/^# This source/ { license=1 }
{ if(license==1) print " " $0 }
/MA 02139, USA.$/ { license=0 }
'
act ""
exit 0 ;;
-q) QUIET=1; shift 1 ;;
-D)
echo "[D] Tomb invoked with args \"${(f)@}\" "
echo "[D] running on `date`"
DEBUG=1; shift 1 ;;
-s) SIZE=$2; shift 2 ;;
-k) KEY=$2; shift 2 ;;
-n) NOBIND=1; shift 1 ;;
--) shift; break ;;
*) CMD=$1;
FILE=$2; MOUNT=$3; # compat with old args
CMD2=${2}; CMD3=${3}; break ;;
esac
done
if ! [ $CMD ]; then
error "first argument missing, use -h for help"
exit 0
fi
func "Tomb command: $CMD $CMD2 $CMD3"
create_tomb() { create_tomb() {
if ! [ ${CMD2} ]; then if ! [ ${CMD2} ]; then
error "no tomb name specified for creation" error "no tomb name specified for creation"
return 1 return 1
@ -397,10 +361,9 @@ create_tomb() {
umount ${keytmp} umount ${keytmp}
rm -r ${keytmp} rm -r ${keytmp}
# cryptsetup luksDump ${nstloop} # cryptsetup luksDump ${nstloop}
act "formatting your Tomb with Ext3/Ext4 filesystem" act "formatting your Tomb with Ext3/Ext4 filesystem"
${MKFS} ${tombname} /dev/mapper/tomb.tmp ${MKFS} ${tombname} /dev/mapper/tomb.tmp
if [ $? != 0 ]; then if [ $? != 0 ]; then
@ -418,7 +381,6 @@ create_tomb() {
} }
mount_tomb() { mount_tomb() {
get_arg_tomb $CMD2 get_arg_tomb $CMD2
if [ $? != 0 ]; then if [ $? != 0 ]; then
@ -456,7 +418,7 @@ mount_tomb() {
act "check for a valid LUKS encrypted device" act "check for a valid LUKS encrypted device"
cryptsetup isLuks ${nstloop} cryptsetup isLuks ${nstloop}
if [ $? != 0 ]; then if [ $? != 0 ]; then
# is it a LUKS encrypted nest? see cryptsetup(1) # is it a LUKS encrypted nest? see cryptsetup(1)
error "$tombfile is not a valid Luks encrypted storage file" error "$tombfile is not a valid Luks encrypted storage file"
$norm || rmdir $tombmount 2>/dev/null $norm || rmdir $tombmount 2>/dev/null
return 1 return 1
@ -467,12 +429,10 @@ mount_tomb() {
mapdate="`echo ${mapdate}/60 | bc -l | cut -d. -f1`" mapdate="`echo ${mapdate}/60 | bc -l | cut -d. -f1`"
mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`" mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`"
keyname=`basename $tombkey | cut -d. -f1` keyname=`basename $tombkey | cut -d. -f1`
notice "Password is required for key ${keyname}" notice "Password is required for key ${keyname}"
for c in 1 2 3; do for c in 1 2 3; do
if [ $c = 1 ]; then if [ $c = 1 ]; then
tombpass=`exec_as_user ${TOMBEXEC} askpass ${keyname}` tombpass=`exec_as_user ${TOMBEXEC} askpass ${keyname}`
else else
@ -488,7 +448,6 @@ mount_tomb() {
if [ -r /dev/mapper/${mapper} ]; then if [ -r /dev/mapper/${mapper} ]; then
break; # password was correct break; # password was correct
fi fi
done done
if ! [ -r /dev/mapper/${mapper} ]; then if ! [ -r /dev/mapper/${mapper} ]; then
@ -511,10 +470,9 @@ mount_tomb() {
chown $(id -u $ME):$(id -g $ME) ${tombmount} chown $(id -u $ME):$(id -g $ME) ${tombmount}
notice "encrypted storage $tombfile succesfully mounted on $tombmount" notice "encrypted storage $tombfile succesfully mounted on $tombmount"
# exec_bind_hooks ${tombmount}
if ! [ $NOBIND ]; then if ! [ $NOBIND ]; then
exec_safe_bind_hooks ${tombmount} exec_safe_bind_hooks ${tombmount}
exec_post_hooks ${tombmount} open exec_safe_post_hooks ${tombmount} open
fi fi
return 0 return 0
} }
@ -540,9 +498,9 @@ encode_key() {
# here user is prompted for key password # here user is prompted for key password
for c in 1 2 3; do for c in 1 2 3; do
# 3 tries to write two times a matching password # 3 tries to write two times a matching password
tombpass=`exec_as_user tomb askpass ${tombkey}` tombpass=`exec_as_user ${TOMBEXEC} askpass ${tombkey}`
tombpasstmp=$tombpass tombpasstmp=$tombpass
tombpass=`exec_as_user tomb askpass "${tombkey} (again)"` tombpass=`exec_as_user ${TOMBEXEC} askpass "${tombkey} (again)"`
if [ "$tombpasstmp" = "$tombpass" ]; then if [ "$tombpasstmp" = "$tombpass" ]; then
break; break;
fi fi
@ -589,9 +547,9 @@ decode_key() {
notice "Trying to exhume a key out of image $imagefile" notice "Trying to exhume a key out of image $imagefile"
for c in 1 2 3; do for c in 1 2 3; do
if [ $c = 1 ]; then if [ $c = 1 ]; then
tombpass=`exec_as_user tomb askpass ${keyfile}` tombpass=`exec_as_user ${TOMBEXEC} askpass ${keyfile}`
else else
tombpass=`exec_as_user tomb askpass "$keyfile (retry $c)"` tombpass=`exec_as_user ${TOMBEXEC} askpass "$keyfile (retry $c)"`
fi fi
steghide extract -sf ${imagefile} -p ${tombpass} -xf - \ steghide extract -sf ${imagefile} -p ${tombpass} -xf - \
| awk ' | awk '
@ -619,28 +577,6 @@ print "-----END PGP MESSAGE-----"
return $res return $res
} }
exec_bind_hooks() {
mnt=$1 # first argument is where the tomb is mounted
if ! [ -r ${mnt}/bind-hooks ]; then return; fi
# if 'bind-hooks' is found inside the tomb, parse it
# every line contains two strings:
# the first is a directory existing inside the tomb
# the second is the place where it should be mounted (-o bind)
hook=`cat ${mnt}/bind-hooks | awk '
/^#/ { next }
{ if($1 && $2) print "mount -o bind \${mnt}/" $1 " " $2 "; " }
'`
# restore $HOME for the calling user
ME=${SUDO_USER:-$(whoami)}
HOME=$(grep $ME /etc/passwd | sed "s/^${ME}:.*:.*:.*:.*:\([\/a-z]*\):.*$/\1/" 2>/dev/null)
act "bind hooks found, mounting directories as requested"
# execute the mount commands
eval $hook
}
# FIXME: this should sanitize pathes!
exec_safe_bind_hooks() { exec_safe_bind_hooks() {
local MOUNTPOINT="${1}" local MOUNTPOINT="${1}"
local ME=${SUDO_USER:-$(whoami)} local ME=${SUDO_USER:-$(whoami)}
@ -681,8 +617,9 @@ exec_safe_bind_hooks() {
done done
} }
exec_post_hooks() { exec_safe_post_hooks() {
mnt=$1 # first argument is where the tomb is mounted local mnt=$1 # first argument is where the tomb is mounted
local ME=${SUDO_USER:-$(whoami)}
if ! [ -x ${mnt}/post-hooks ]; then return; fi if ! [ -x ${mnt}/post-hooks ]; then return; fi
# if 'post-hooks' is found inside the tomb, check it: if it is an # if 'post-hooks' is found inside the tomb, check it: if it is an
# executable, launch it as a user this might need a dialog for # executable, launch it as a user this might need a dialog for
@ -731,7 +668,7 @@ backup_tomb() { # FIXME - duplicity asks passwords too often
act "backup over protocol $protocol" act "backup over protocol $protocol"
if [ "$protocol" = "ssh" ]; then if [ "$protocol" = "ssh" ]; then
act "ssh connection requires a password" act "ssh connection requires a password"
FTP_PASSWORD="`exec_as_user tomb askpass $bckurl`" FTP_PASSWORD="`exec_as_user ${TOMBEXEC} askpass $bckurl`"
dupopts="--ssh-askpass" dupopts="--ssh-askpass"
# TODO verify ssh access before duplicity does # TODO verify ssh access before duplicity does
# since it blocks the thing retrying 5 times and such crap # since it blocks the thing retrying 5 times and such crap
@ -783,27 +720,27 @@ backup_tomb() { # FIXME - duplicity asks passwords too often
} }
umount_tomb() { umount_tomb() {
local tombs how_many_tombs
local pathmap mapper tombname tombmount loopdev
local ans pidk pname
if ! [ $1 ]; then if ! [ $1 ]; then
tombs=`find /dev/mapper -name 'tomb.*'`
how_many_tombs="`find /dev/mapper -name 'tomb.*' | wc -w`" how_many_tombs=`wc -w <<< "$tombs"`
if [ "$how_many_tombs" = "0" ]; then if [ "$how_many_tombs" = "0" ]; then
error "there is no open tomb to be closed" error "there is no open tomb to be closed"
return 1 return 1
elif [ "$how_many_tombs" = "1" ]; then elif [ "$how_many_tombs" = "1" ]; then
mapper=`find /dev/mapper -name 'tomb.*'` #mapper=`find /dev/mapper -name 'tomb.*'`
notice "trying to close $mapper" notice "trying to close $tombs"
umount_tomb ${mapper} umount_tomb ${tombs}
return 1 return 1
else else
error "too many tombs mounted, please specify which to unmount:" error "too many tombs mounted, please specify which to unmount:"
ls /dev/mapper/tomb.* ls /dev/mapper/tomb.*
error "or issue the command 'tomb close all' to clos'em all." error "or issue the command 'tomb close all' to clos'em all."
return 1 return 1
fi fi
fi fi
if [ "$1" = "all" ]; then if [ "$1" = "all" ]; then
@ -849,16 +786,28 @@ umount_tomb() {
# Execute post-hooks for eventual cleanup # Execute post-hooks for eventual cleanup
if ! [ $NOBIND ]; then if ! [ $NOBIND ]; then
exec_post_hooks ${tombmount%%/} close exec_safe_post_hooks ${tombmount%%/} close
fi fi
act "closing tomb $tombname on dm-crypt $tombmount" act "closing tomb $tombname on dm-crypt $tombmount"
umount ${tombmount} umount ${tombmount} 2> /dev/null
if ! [ $? = 0 ]; then if ! [ $? = 0 ]; then
# TODO: ask user if wanting to SLAM the tomb closed error "Tomb is busy, cannot umount!"
# then kill all processes found using it with fuser and lsof notice "Do you want to force umount? y/N: "
return 1 read ans
fi if [ "$ans" = "S" -o "$ans" = "s" -o "$ans" = "y" -o "$ans" = "Y" ]; then
pidk=`lsof -t "$tombmount"`
for p in "$pidk"; do
pname=`pidof $p`
func "killing PID $p of $pname..."
kill -9 $p
done
umount "${tombmount}"
else
error "Cannot umount $tombname on $tombmount"
return 1
fi
fi
cryptsetup luksClose $tombname cryptsetup luksClose $tombname
if ! [ $? = 0 ]; then if ! [ $? = 0 ]; then
@ -908,7 +857,7 @@ Type=Application
Name=Tomb crypto undertaker Name=Tomb crypto undertaker
GenericName=Crypto undertaker GenericName=Crypto undertaker
Comment=Keep your bones safe Comment=Keep your bones safe
Exec=tomb-open %U Exec="${TOMBOPENEXEC}" %U
TryExec=tomb-open TryExec=tomb-open
Icon=monmort.xpm Icon=monmort.xpm
Terminal=true Terminal=true
@ -930,7 +879,7 @@ EOF
cat <<EOF > /usr/share/mime-info/tomb.keys cat <<EOF > /usr/share/mime-info/tomb.keys
# actions for encrypted tomb storage # actions for encrypted tomb storage
application/x-tomb-volume: application/x-tomb-volume:
open=tomb-open %f open="${TOMBOPENEXEC}" %f
view=tomb-open %f view=tomb-open %f
icon-filename=monmort.xpm icon-filename=monmort.xpm
short_list_application_ids_for_novice_user_level=tomb short_list_application_ids_for_novice_user_level=tomb
@ -962,32 +911,79 @@ EOF
act "Tomb is now installed." act "Tomb is now installed."
} }
main () {
echo $@ | grep '\-D' 2>&1 > /dev/null
# ?????
if [ $? = 0 ]; then
fi
ARGS=$@[@]
OPTS=`getopt -o hvqDs:k:n -n 'tomb' -- "$@"`
while true; do
case "$1" in
-h)
usage
exit 0 ;;
-v)
notice "Tomb - simple commandline tool for encrypted storage"
act "version $VERSION ($DATE) by Jaromil @ dyne.org"
# print out the GPL license in this file
act ""
cat $0 | awk 'BEGIN { license=0 } /^# This source/ { license=1 } { if(license==1) print " " $0 }
/MA 02139, USA.$/ { license=0 }'
act ""
exit 0 ;;
-q) QUIET=1; shift 1 ;;
-D)
echo "[D] Tomb invoked with args \"${(f)@}\" "
echo "[D] running on `date`"
DEBUG=1; shift 1 ;;
-s) SIZE=$2; shift 2 ;;
-k) KEY=$2; shift 2 ;;
-n) NOBIND=1; shift 1 ;;
--) shift; break ;;
*) CMD=$1;
FILE=$2; MOUNT=$3; # compat with old args
CMD2=${2}; CMD3=${3}; break ;;
esac
done
if ! [ $CMD ]; then
error "first argument missing, use -h for help"
exit 0
fi
func "Tomb command: $CMD $CMD2 $CMD3"
case "$CMD" in
case "$CMD" in create) check_priv ; create_tomb ;;
create) check_priv ; create_tomb ;; mount) check_priv ; mount_tomb ;;
open) check_priv ; mount_tomb ;;
umount) check_priv ; umount_tomb ${CMD2} ;;
unmount) check_priv ; umount_tomb ${CMD2} ;;
close) check_priv ; umount_tomb ${CMD2} ;;
bury) if [ "$STEGHIDE" = 0 ]; then
error "steghide not installed. Cannot bury your key"
return 1
fi
encode_key ${CMD2} ${CMD3} ;;
exhume) if [ "$STEGHIDE" = 0 ]; then
error "steghide not installed. Cannot exhume your key"
return 1
fi
decode_key ${CMD2} ;;
backup) check_priv ; backup_tomb ${CMD2} ${CMD3} ;;
install) check_priv ; install_tomb ;;
askpass) ask_password $CMD2 ;;
status) tomb-status ;;
*) error "command \"$CMD\" not recognized"
act "try -h for help"
return 1
;;
esac
return 0
}
mount) check_priv ; mount_tomb ;; check_bin
open) check_priv ; mount_tomb ;; main $@
umount) check_priv ; umount_tomb ${CMD2} ;;
unmount) check_priv ; umount_tomb ${CMD2} ;;
close) check_priv ; umount_tomb ${CMD2} ;;
bury) encode_key ${CMD2} ${CMD3} ;;
exhume) decode_key ${CMD2} ;;
backup) check_priv ; backup_tomb ${CMD2} ${CMD3} ;;
install) check_priv ; install_tomb ;;
askpass) ask_password $CMD2 ;;
status) tomb-status ;;
*) error "command \"$CMD\" not recognized"
act "try -h for help"
return 1
;;
esac
# return codes from called functions
# return $?