diff --git a/src/tomb b/src/tomb index 9c96de2..63227dd 100755 --- a/src/tomb +++ b/src/tomb @@ -23,6 +23,8 @@ VERSION=1.0 DATE=Feb/2011 TOMBEXEC=$0 +TOMBOPENEXEC="tomb-open" +STEGHIDE=1 # 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 } 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 -which wipe > /dev/null -if [ $? = 0 ]; then - WIPE=(wipe -f -s) -else - WIPE=(rm -f) -fi +check_bin() { + # which dd command to use + which dcfldd > /dev/null + if [ $? = 0 ]; then + DD="dcfldd" + else + DD=dd + fi -# check for filesystem creation progs -which mkfs.ext4 > /dev/null -if [ $? = 0 ]; then - MKFS=(mkfs.ext4 -q -F -j -L) -else - MKFS=(mkfs.ext3 -q -F -j -L) -fi + # which wipe command to use + which wipe > /dev/null + if [ $? = 0 ]; then + WIPE=(wipe -f -s) + else + WIPE=(rm -f) + fi -# check for sudo -which sudo > /dev/null -if [ $? != 0 ]; then - error "Cannot find sudo. Please install it" - exit 1 -fi + # check for filesystem creation progs + which mkfs.ext4 > /dev/null + if [ $? = 0 ]; then + MKFS=(mkfs.ext4 -q -F -j -L) + else + 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() { @@ -97,7 +115,6 @@ EOF # drop privileges exec_as_user() { - if ! [ $SUDO_USER ]; then exec $@[@] return $? @@ -111,10 +128,9 @@ exec_as_user() { # escalate privileges check_priv() { - id | grep root > /dev/null - if [ $? != 0 ]; then + if [ $UID != 0 ]; then 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 sudo -n ${TOMBEXEC} 2> /dev/null if [ $? != 0 ]; then # if not then ask a password @@ -214,59 +230,7 @@ Please report bugs on . 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() { - if ! [ ${CMD2} ]; then error "no tomb name specified for creation" return 1 @@ -397,10 +361,9 @@ create_tomb() { umount ${keytmp} rm -r ${keytmp} - # cryptsetup luksDump ${nstloop} + # cryptsetup luksDump ${nstloop} act "formatting your Tomb with Ext3/Ext4 filesystem" - ${MKFS} ${tombname} /dev/mapper/tomb.tmp if [ $? != 0 ]; then @@ -418,7 +381,6 @@ create_tomb() { } - mount_tomb() { get_arg_tomb $CMD2 if [ $? != 0 ]; then @@ -456,7 +418,7 @@ mount_tomb() { act "check for a valid LUKS encrypted device" cryptsetup isLuks ${nstloop} 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" $norm || rmdir $tombmount 2>/dev/null return 1 @@ -467,12 +429,10 @@ mount_tomb() { mapdate="`echo ${mapdate}/60 | bc -l | cut -d. -f1`" mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`" - keyname=`basename $tombkey | cut -d. -f1` notice "Password is required for key ${keyname}" for c in 1 2 3; do - if [ $c = 1 ]; then tombpass=`exec_as_user ${TOMBEXEC} askpass ${keyname}` else @@ -488,7 +448,6 @@ mount_tomb() { if [ -r /dev/mapper/${mapper} ]; then break; # password was correct fi - done if ! [ -r /dev/mapper/${mapper} ]; then @@ -511,10 +470,9 @@ mount_tomb() { chown $(id -u $ME):$(id -g $ME) ${tombmount} notice "encrypted storage $tombfile succesfully mounted on $tombmount" -# exec_bind_hooks ${tombmount} if ! [ $NOBIND ]; then exec_safe_bind_hooks ${tombmount} - exec_post_hooks ${tombmount} open + exec_safe_post_hooks ${tombmount} open fi return 0 } @@ -540,9 +498,9 @@ encode_key() { # here user is prompted for key password for c in 1 2 3; do # 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 - tombpass=`exec_as_user tomb askpass "${tombkey} (again)"` + tombpass=`exec_as_user ${TOMBEXEC} askpass "${tombkey} (again)"` if [ "$tombpasstmp" = "$tombpass" ]; then break; fi @@ -589,9 +547,9 @@ decode_key() { notice "Trying to exhume a key out of image $imagefile" for c in 1 2 3; do if [ $c = 1 ]; then - tombpass=`exec_as_user tomb askpass ${keyfile}` + tombpass=`exec_as_user ${TOMBEXEC} askpass ${keyfile}` else - tombpass=`exec_as_user tomb askpass "$keyfile (retry $c)"` + tombpass=`exec_as_user ${TOMBEXEC} askpass "$keyfile (retry $c)"` fi steghide extract -sf ${imagefile} -p ${tombpass} -xf - \ | awk ' @@ -619,28 +577,6 @@ print "-----END PGP MESSAGE-----" 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() { local MOUNTPOINT="${1}" local ME=${SUDO_USER:-$(whoami)} @@ -681,8 +617,9 @@ exec_safe_bind_hooks() { done } -exec_post_hooks() { - mnt=$1 # first argument is where the tomb is mounted +exec_safe_post_hooks() { + 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 '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 @@ -731,7 +668,7 @@ backup_tomb() { # FIXME - duplicity asks passwords too often act "backup over protocol $protocol" if [ "$protocol" = "ssh" ]; then 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" # TODO verify ssh access before duplicity does # 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() { + local tombs how_many_tombs + local pathmap mapper tombname tombmount loopdev + local ans pidk pname if ! [ $1 ]; then - - how_many_tombs="`find /dev/mapper -name 'tomb.*' | wc -w`" + tombs=`find /dev/mapper -name 'tomb.*'` + how_many_tombs=`wc -w <<< "$tombs"` if [ "$how_many_tombs" = "0" ]; then error "there is no open tomb to be closed" return 1 - elif [ "$how_many_tombs" = "1" ]; then - mapper=`find /dev/mapper -name 'tomb.*'` - notice "trying to close $mapper" - umount_tomb ${mapper} + #mapper=`find /dev/mapper -name 'tomb.*'` + notice "trying to close $tombs" + umount_tomb ${tombs} return 1 - else error "too many tombs mounted, please specify which to unmount:" ls /dev/mapper/tomb.* error "or issue the command 'tomb close all' to clos'em all." return 1 fi - fi if [ "$1" = "all" ]; then @@ -849,16 +786,28 @@ umount_tomb() { # Execute post-hooks for eventual cleanup if ! [ $NOBIND ]; then - exec_post_hooks ${tombmount%%/} close + exec_safe_post_hooks ${tombmount%%/} close fi act "closing tomb $tombname on dm-crypt $tombmount" - umount ${tombmount} + umount ${tombmount} 2> /dev/null if ! [ $? = 0 ]; then - # TODO: ask user if wanting to SLAM the tomb closed - # then kill all processes found using it with fuser and lsof - return 1 - fi + error "Tomb is busy, cannot umount!" + notice "Do you want to force umount? y/N: " + read ans + 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 if ! [ $? = 0 ]; then @@ -908,7 +857,7 @@ Type=Application Name=Tomb crypto undertaker GenericName=Crypto undertaker Comment=Keep your bones safe -Exec=tomb-open %U +Exec="${TOMBOPENEXEC}" %U TryExec=tomb-open Icon=monmort.xpm Terminal=true @@ -930,7 +879,7 @@ EOF cat < /usr/share/mime-info/tomb.keys # actions for encrypted tomb storage application/x-tomb-volume: - open=tomb-open %f + open="${TOMBOPENEXEC}" %f view=tomb-open %f icon-filename=monmort.xpm short_list_application_ids_for_novice_user_level=tomb @@ -962,32 +911,79 @@ EOF 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 - create) check_priv ; create_tomb ;; + case "$CMD" in + 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 ;; - open) check_priv ; mount_tomb ;; - - 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 $? +check_bin +main $@