huge cleanup

tomb shell command doesn't depends from X,
 all GUI notifications are moved into tomb-open including USB key handling,
 gksu has been dropped completely as a method to gain privileges,
 there is a new -n flag to avoid processing hooks,
 variable names have been sanitized, duplicate code eliminated,
 documentation has been updated and the code cleaned up

we are very close to the 1.0 now
This commit is contained in:
Jaromil 2011-02-20 14:59:30 +01:00
parent fd8df548f4
commit b521e32110
4 changed files with 423 additions and 403 deletions

View File

@ -92,6 +92,10 @@ file adding a '.gpg' suffix, but can be later renamed and transported
on other media. When a key is not found, the program asks to insert a on other media. When a key is not found, the program asks to insert a
USB storage device and it will look for the key file inside it. USB storage device and it will look for the key file inside it.
.B .B
.IP "-n"
Skip processing of post-hooks and bind-hooks if found inside the tomb.
See the \fIHOOKS\fR section in this manual for more information.
.B
.IP "-h" .IP "-h"
Display a help text and quit Display a help text and quit
.B .B

563
src/tomb
View File

@ -20,7 +20,7 @@
# this source code; if not, write to: # this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
VERSION=0.9.2 VERSION=0.9.3
DATE=Feb/2011 DATE=Feb/2011
# PATH=/usr/bin:/usr/sbin:/bin:/sbin # PATH=/usr/bin:/usr/sbin:/bin:/sbin
@ -48,114 +48,6 @@ else
WIPE=(rm -f) WIPE=(rm -f)
fi 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 "
exec_as_user notify-send -i monmort \
-u normal -h string:App:Tomb \
-h double:Version:${VERSION} \
-t 60 \
"Insert your USB KEY" \
"Tomb is waiting 1 minute for you to insert an external key."
plugged=false
c=0
while [ "$plugged" != "true" ]; do
dmesg | tail -n 12 | grep -q 'new.*USB device'
if [ $? = 0 ]; then plugged=true; fi
echo -n "."
sleep .5
c=`expr $c + 1`
if [ $c -gt 15 ]; then
echo
error "timeout."
export usbkey_mount=none
return 1;
fi
done
echo
echo -n " . usb key inserted, attaching "
c=0
attached=false
while [ "$attached" != "true" ]; do
dmesg | tail -n 12| grep -q 'Attached.*removable disk'
if [ $? = 0 ]; then attached=true; fi
echo -n "."
sleep 1
c=`expr $c + 1`
if [ $c -gt 15 ]; then
echo
error "timeout."
export usbkey_mount=none
return 1;
fi
done
echo
echo -n " . usb attached, opening "
# get the first partition
# usbpart=`dmesg |tail -n 12 | grep ' sd.:' |cut -d: -f2 |tr -d ' '`
for i in $(seq 1 10); do
usbpart=$(dmesg | tail -n 12 | sed '/ sd.:/!d;s/^.*: \(sd.[0-9]*\)/\1/')
if [ -n "$usbpart" ]; then
break
elif [ $i -eq 10 ]; then
error "timeout."
return 1
else
echo -n .
sleep 1
fi
done
# # wait that is mounted (it automount is on)
# c=0
# mounted=false
# while [ "$mounted" != "true" ]; do
# cat /proc/mounts | tail -n 2 | grep -q $usbpart
# if [ $? = 0 ]; then mounted=true; fi
# echo -n "."
# sleep .5
# c=`expr $c + 1`
# if [ $c -gt 30 ]; then
# echo
# error "timeout."
# export usbkey_mount=none
# return 1;
# fi
# done
# # check where it is mounted
# usbmount=`cat /proc/mounts | awk -v p=$usbpart '{ if( $1 == "/dev/" p) print $2 }'`
# sleep 1
# mount the first partition on the usb key
# mtmp=`tempfile -p tomb`
# rm -f $mtmp
# mkdir -p $mtmp
mtmp=$(/bin/mktemp -d --tmpdir tomb.XXXXXXXXXXXX)
mount /dev/$usbpart $mtmp
if [ $? = 0 ]; then
usbmount=$mtmp
else
error "cannot mount usbkey partition $usbmount"
return 1
fi
echo
act "usb key mounted on $usbmount"
export usbkey_mount=$usbmount
return 0
}
# we use pinentry now # we use pinentry now
# comes from gpg project and is much more secure # comes from gpg project and is much more secure
@ -166,7 +58,10 @@ ask_password() {
# so we need to temporary modify the gtk theme # so we need to temporary modify the gtk theme
if [ -r ~/.gtkrc-2.0 ]; then if [ -r ~/.gtkrc-2.0 ]; then
cp ~/.gtkrc-2.0 ~/.gtkrc-2.0.tomb.bak cp ~/.gtkrc-2.0 ~/.gtkrc-2.0.tomb.bak
else
touch ~/.gtkrc-2.0
fi fi
cat <<EOF >> ~/.gtkrc-2.0 cat <<EOF >> ~/.gtkrc-2.0
pixmap_path "/usr/local/share/pixmaps" pixmap_path "/usr/local/share/pixmaps"
style "normal" { stock["gtk-dialog-authentication"] = {{"monmort.xpm"}} } style "normal" { stock["gtk-dialog-authentication"] = {{"monmort.xpm"}} }
@ -174,8 +69,8 @@ ask_password() {
EOF EOF
cat <<EOF | pinentry | awk '/^D/ { print $2 }' cat <<EOF | pinentry | awk '/^D/ { print $2 }'
SETTITLE Opening Tomb $1 SETTITLE Insert tomb password
SETDESC You need a password to use its key SETDESC Open tomb: $1
SETPROMPT Password: SETPROMPT Password:
GETPIN GETPIN
EOF EOF
@ -184,33 +79,12 @@ EOF
if [ -r ~/.gtkrc-2.0.tomb.bak ]; then if [ -r ~/.gtkrc-2.0.tomb.bak ]; then
cp ~/.gtkrc-2.0.tomb.bak ~/.gtkrc-2.0 cp ~/.gtkrc-2.0.tomb.bak ~/.gtkrc-2.0
rm ~/.gtkrc-2.0.tomb.bak rm ~/.gtkrc-2.0.tomb.bak
fi
}
# 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 $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 else
exec_as_user notify-send -i $icon ${@} rm -f ~/.gtkrc-2.0
fi fi
} }
# drop privileges # drop privileges
exec_as_user() { exec_as_user() {
@ -235,77 +109,127 @@ exec_as_user() {
check_priv() { check_priv() {
id | grep root > /dev/null id | grep root > /dev/null
if [ $? != 0 ]; then if [ $? != 0 ]; then
which gksu > /dev/null
if [ $? = 0 ]; then
func "Using gksu for root execution of 'tomb ${(f)ARGS}'"
gksudo "tomb ${ARGS[@]}"
exit $?
fi
which sudo > /dev/null which sudo > /dev/null
if [ $? = 0 ]; then if [ $? != 0 ]; then
func "Using sudo for root execution of 'tomb ${(f)ARGS}'" error "Tomb requires sudo. please install it."
exit 1
fi
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 tomb 2> /dev/null sudo -n tomb 2> /dev/null
if [ $? != 0 ]; then # if not then ask a password if [ $? != 0 ]; then # if not then ask a password
cat <<EOF | pinentry | awk '/^D/ { print $2 }' | sudo -S -v cat <<EOF | pinentry | awk '/^D/ { print $2 }' | sudo -S -v
SETTITLE Super user privileges required SETTITLE Super user privileges required
SETDESC Sudo execution of Tomb ${ARGS[@]} SETDESC Sudo execution of Tomb ${ARGS[@]}
SETPROMPT Insert your USER password: SETPROMPT Insert your USER password:
GETPIN GETPIN
EOF EOF
fi fi
sudo "tomb" ${(s: :)ARGS} sudo "tomb" ${(s: :)ARGS}
exit $? exit $?
fi # have sudo
return 1
fi # are we root already fi # are we root already
return 0 return 0
} }
get_arg_tomb() {
# set up variables to be used by caller:
# tombfile - filename without path
# tombdir - directory where the tomb is
# tombname - name of the tomb (filename without extension)
# the full path is made with $tombdir/$tombfile
if [ -z $1 ]; then
error "internal: get_arg_tomb called without argument"
return 1
fi
arg=${1}
if ! [ -r ${arg} ]; then
error "file not found: $arg"
return 1
fi
tombfile=`basename $arg`
tombdir=`dirname $arg`
file ${tombdir}/${tombfile} | grep -i 'luks encrypted file' 2>&1 >/dev/null
if [ $? != 0 ]; then
error "$arg is not a valid tomb file, operation aborted"
return 1
fi
tombname=${tombfile%%\.*}
act "tomb found: ${tombdir}/${tombfile}"
# now check if the key is kept beside or in args
# we use the extension .key
# the problem with .tomb.gpg is that decoding by hand using gpg it
# can override the tomb contents if the key is in the same
# directory than the tomb
if [ $KEY ]; then
tombkey=$KEY # commandline -k flag
act "tomb key specified manually: $tombkey"
elif [ -r ${tombdir}/${tombname}.key ]; then
tombkey=${tombdir}/${tombname}.key
act "key found for tomb '${tombname}': ${tombkey}"
else
error "key not found for tomb '${tombname}'"
return 1
fi
return 0
}
############################ ############################
### main() ### main()
### ###
echo $@ | grep '\-q' 2>&1 > /dev/null
if [ $? != 0 ]; then
notice "Tomb - simple commandline tool for encrypted storage"
act "version $VERSION ($DATE) by Jaromil @ dyne.org"
fi
echo $@ | grep '\-D' 2>&1 > /dev/null echo $@ | grep '\-D' 2>&1 > /dev/null
if [ $? = 0 ]; then if [ $? = 0 ]; then
echo "[D] invoked with args \"${(f)@}\" "
echo "[D] running on `date`"
fi fi
ARGS=$@[@] ARGS=$@[@]
OPTS=`getopt -o hvqDs:k: -n 'tomb' -- "$@"` OPTS=`getopt -o hvqDs:k:n -n 'tomb' -- "$@"`
while true; do while true; do
case "$1" in case "$1" in
-h) -h)
act "" cat <<EOF
notice "Syntax: tomb [options] command [file] [mountpoint]" Tomb $VERSION - a strong and gentle undertaker for your secrets
act ""
notice "Commands:"
act "create create a new encrypted storage FILE and keys"
act "open open an existing tomb FILE on MOUNTPOINT"
act "close closes the tomb on MOUNTPOINT"
act "bury hide a tomb key inside a jpeg image"
act "exhume extract an hidden tomb key from a jpeg image"
act "" Copyright (C) 2007-2011 Dyne.org Foundation, License GNU GPL v3+
notice "Options:" This is free software: you are free to change and redistribute it
act "-s size of the storage file when creating one (MB)" The latest Tomb sourcecode is published on <http://tomb.dyne.org>
act "-k path to the key to use for decryption"
act "" Syntax: tomb [options] command [file] [place]
act "-h print this help"
act "-v version information for this tool" Commands:
act "-q run quietly without printing informations"
act "-D print debugging information at runtime" create create a new tomb FILE and its keys
echo; exit 2 ;; open open an existing tomb FILE on PLACE
close closes the tomb open on PLACE
bury hide a tomb key FILE inside a jpeg PLACE
exhume extract a tomb key FILE from a jpeg PLACE
Options:
-s size of the tomb file when creating one (in MB)
-k path to the key to use for opening a tomb
-n don't process the hooks found in tomb
-h print this help
-v version information for this tool
-q run quietly without printing informations
-D print debugging information at runtime
For more informations on Tomb read the manual: man tomb
Please report bugs on <http://bugs.dyne.org>.
EOF
exit 0 ;;
-v) -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 # print out the GPL license in this file
act "" act ""
cat $0 | awk ' cat $0 | awk '
@ -317,9 +241,13 @@ BEGIN { license=0 }
act "" act ""
exit 0 ;; exit 0 ;;
-q) QUIET=1; shift 1 ;; -q) QUIET=1; shift 1 ;;
-D) DEBUG=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 ;; -s) SIZE=$2; shift 2 ;;
-k) KEY=$2; shift 2 ;; -k) KEY=$2; shift 2 ;;
-b) NOBIND=1; shift 1 ;;
--) shift; break ;; --) shift; break ;;
*) CMD=$1; *) CMD=$1;
FILE=$2; MOUNT=$3; # compat with old args FILE=$2; MOUNT=$3; # compat with old args
@ -331,44 +259,52 @@ done
if ! [ $CMD ]; then if ! [ $CMD ]; then
error "first argument missing, use -h for help" error "first argument missing, use -h for help"
tomb-notify
exit 0 exit 0
fi fi
func "Tomb command: $CMD $CMD2 $CMD3"
func "Tomb called: $CMD $CMD2 $CMD3"
create_tomb() { create_tomb() {
# make sure the file has a .tomb extension if ! [ ${CMD2} ]; then
FILE="${FILE%\.*}.tomb" error "no tomb name specified for creation"
return 1
fi
if [ -e "$FILE" ]; then tombfile=`basename ${CMD2}`
error "$FILE exists already. I'm not digging here." tombdir=`dirname ${CMD2}`
# make sure the file has a .tomb extension
tombname=${tombfile%%\.*}
tombfile=${tombname}.tomb
if [ -e ${tombdir}/${tombfile} ]; then
error "tomb exists already. I'm not digging here:"
ls -lh ${tombdir}/${tombfile}
return 1 return 1
fi fi
notice "Creating a new tomb" notice "Creating a new tomb in ${tombdir}/${tombfile}"
if [ -z $SIZE ]; then if [ -z $SIZE ]; then
if [ $MOUNT ]; then if [ $CMD3 ]; then
SIZE=$MOUNT tombsize=${CMD3}
else else
act "No size specified, summoning the Tomb Undertaker to guide us in the creation." act "No size specified, summoning the Tomb Undertaker to guide us in the creation."
tomb-open &! tomb-open &!
return 0 return 0
fi fi
else
tombsize=${SIZE}
fi fi
SIZE_4k=`expr $SIZE \* 1000 / 4` tombsize_4k=`expr $tombsize \* 1000 / 4`
act "Generating ${FILE} of ${SIZE}Mb (${SIZE_4k} blocks of 4Kb)" act "Generating ${tombfile} of ${tombsize}Mb (${tombsize_4k} blocks of 4Kb)"
$DD if=/dev/urandom bs=4k count=${SIZE_4k} of=${FILE} $DD if=/dev/urandom bs=4k count=${tombsize_4k} of=${tombdir}/${tombfile}
if [ $? = 0 -a -e ${FILE} ]; then if [ $? = 0 -a -e ${tombdir}/${tombfile} ]; then
act "OK: `ls -lh ${FILE}`" act "OK: `ls -lh ${tombdir}/${tombfile}`"
else else
error "Error creating the tomb ${FILE}, operation aborted." error "Error creating the tomb ${tombdir}/${tombfile}, operation aborted."
exit 1 exit 1
fi fi
@ -376,7 +312,7 @@ create_tomb() {
modprobe aes-i586 modprobe aes-i586
nstloop=`losetup -f` # get the number for next loopback device nstloop=`losetup -f` # get the number for next loopback device
losetup -f ${FILE} # allocates the next loopback for our file losetup -f ${tombdir}/${tombfile} # allocates the next loopback for our file
# create the keyfile in tmpfs so that we leave less traces in RAM # create the keyfile in tmpfs so that we leave less traces in RAM
keytmp=`tempfile -p tomb` keytmp=`tempfile -p tomb`
@ -404,15 +340,14 @@ create_tomb() {
exit 1 exit 1
fi fi
notice "Setup your secret key file ${FILE}.gpg" notice "Setup your secret key file ${tombname}.key"
tomb-notify "The Tomb key is being forged:" "please set your password."
# 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 -q askpass ${FILE}` tombpass=`exec_as_user tomb askpass ${tombname}`
tombpasstmp=$tombpass tombpasstmp=$tombpass
tombpass=`exec_as_user tomb -q askpass "${FILE} (again)"` tombpass=`exec_as_user tomb askpass "${tombname} (again)"`
if [ "$tombpasstmp" = "$tombpass" ]; then if [ "$tombpasstmp" = "$tombpass" ]; then
break; break;
fi fi
@ -428,8 +363,9 @@ create_tomb() {
exit 1 exit 1
fi fi
echo "${tombpass}" | gpg --batch --no-options --no-tty --passphrase-fd 0 \ echo "${tombpass}" | gpg \
-o "${FILE}.gpg" -c -a ${keytmp}/tomb.tmp --openpgp --batch --no-options --no-tty --passphrase-fd 0 \
-o "${tombdir}/${tombname}.key" -c -a ${keytmp}/tomb.tmp
if [ $? = 2 ]; then if [ $? = 2 ]; then
error "setting password failed: gnupg returns 2" error "setting password failed: gnupg returns 2"
@ -460,12 +396,11 @@ create_tomb() {
act "formatting your Tomb with Ext4 filesystem" act "formatting your Tomb with Ext4 filesystem"
mkfs.ext4 -q -F -j -L "${FILE%%.*}" /dev/mapper/tomb.tmp mkfs.ext4 -q -F -j -L ${tombname} /dev/mapper/tomb.tmp
if [ $? = 0 ]; then if [ $? != 0 ]; then
act "OK, encrypted storage succesfully formatted" error "Tomb format returns error"
else error "your tomb ${tombfile} maybe corrupt"
act "error formatting Tomb"
fi fi
sync sync
@ -473,101 +408,19 @@ create_tomb() {
cryptsetup luksClose tomb.tmp cryptsetup luksClose tomb.tmp
losetup -d ${nstloop} losetup -d ${nstloop}
notice "done creating $FILE encrypted storage (using Luks dm-crypt AES/SHA256)" act "done creating $tombname encrypted storage (using Luks dm-crypt AES/SHA256)"
tomb-notify "The Tomb is ready!" "We will now open your new Tomb for the first time." notice "Your tomb is ready in ${tombdir}/${tombfile} and secured with key ${tombname}.key"
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?"
act "This is recommended for safety:"
act "Always keep the key in a different place than the door!"
act "If you answer yes, you'll need a USB KEY now: (y/n)"
tomb-notify "Tomb has forged a key." "Would you like to save it on USB?"
echo -n " > "
read -q
if [ $? = 0 ]; then
ask_usbkey
if ! [ -e ${usbkey_mount} ]; then
error "cannot save the key in a separate place, move it yourself later."
else
mkdir -m 0700 -p ${usbkey_mount}/.tomb
cp -v ${FILE}.gpg ${usbkey_mount}/.tomb/
chmod -R go-rwx ${usbkey_mount}/.tomb
umount ${usbkey_mount}
unset usbkey_mount
notice "Key ${FILE}.gpg succesfully saved on your USB"
act "now we proceed opening your new tomb"
KEY=${FILE}.gpg
CMD2=${FILE}
CMD3=/media/${FILE}
mount_tomb ${FILE}
${WIPE[@]} ${FILE}.gpg
fi
else # kept besides (deprecated behaviour)
act "now we proceed opening your new tomb"
KEY=${FILE}.gpg
unset CMD2
unset CMD3
mount_tomb ${FILE}
fi
} }
mount_tomb() { mount_tomb() {
if ! [ $CMD2 ]; then get_arg_tomb $CMD2
error "need an argument, operation aborted."
return 1
elif [ -r $CMD2 ]; then
tombfile=`basename $CMD2`
else
# try also adding a .tomb extension
tombfile=${tombfile%%\.*}.tomb
if ! [ -r $tombfile ]; then
error "cannot find a tomb named $CMD2"
return 1
fi
fi
tombdir=`dirname $CMD2`
file ${tombdir}/${tombfile} | grep -i 'luks encrypted.*cbc-essiv' 2>&1 >/dev/null
if [ $? != 0 ]; then if [ $? != 0 ]; then
error "$CMD2 is not a valid tomb file, operation aborted" error "operation aborted."
tomb-notify "Not a tomb." "$CMD2 doesn't seems a real tomb."
return 1 return 1
fi fi
tombname=${tombfile%%\.*}
act "mounting tomb named $tombname"
if [ $KEY ]; then
tombkey="`basename $KEY`"
tombkeypath="$KEY"
act "tomb key specified manually, using: $tombkeypath"
else
tombkey=${tombfile}.gpg
if [ -r $tombkey ]; then
tombkeypath=$tombkey
elif [ -r "$tombdir/$tombkey" ]; then
tombkeypath="$tombdir/$tombkey"
else
error "encryption key ${enc_key} not found on disk"
error "use -k option to specify which key to use"
error "provide a usb key now, or press ctrl-c to abort"
notice "please insert your USB KEY"
ask_usbkey
# returns usbkey_mount, now check if the key is there
if [ -r ${usbkey_mount}/.tomb/${tombkey} ]; then
tombkeypath=${usbkey_mount}/.tomb/${tombkey}
notice "key found on ${tombkeypath}"
else
error "key is missing, try to locate $tombkey in your files."
error "operation aborted"
return 1
fi
fi
fi
if ! [ $CMD3 ]; then if ! [ $CMD3 ]; then
tombmount=/media/${tombfile} tombmount=/media/${tombfile}
act "mountpoint not specified, using default: $tombmount" act "mountpoint not specified, using default: $tombmount"
@ -610,19 +463,19 @@ 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`"
notice "Password is required for key ${tombkey}" keyname=`basename $tombkey | cut -d. -f1`
keyname=`basename $tombkey | cut -d. -f1` 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 tomb -q askpass ${keyname}` tombpass=`exec_as_user tomb askpass ${keyname}`
else else
tombpass=`exec_as_user tomb -q askpass "$keyname (retry $c)"` tombpass=`exec_as_user tomb askpass "$keyname (retry $c)"`
fi fi
echo "${tombpass}" \ echo "${tombpass}" \
| gpg --batch --passphrase-fd 0 --no-tty --no-options \ | gpg --batch --passphrase-fd 0 --no-tty --no-options \
-d "${tombkeypath}" \ -d "${tombkey}" \
| cryptsetup --key-file - luksOpen ${nstloop} ${mapper} | cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
unset tombpass unset tombpass
@ -632,12 +485,6 @@ mount_tomb() {
fi fi
done done
if [ -r ${usbkey_mount}/.tomb/${tombkey} ]; then
umount ${usbkey_mount}
rmdir ${usbkey_mount}
unset usbkey_mount
fi
if ! [ -r /dev/mapper/${mapper} ]; then if ! [ -r /dev/mapper/${mapper} ]; then
error "failure mounting the encrypted file" error "failure mounting the encrypted file"
@ -660,8 +507,10 @@ mount_tomb() {
notice "encrypted storage $tombfile succesfully mounted on $tombmount" notice "encrypted storage $tombfile succesfully mounted on $tombmount"
# exec_bind_hooks ${tombmount} # exec_bind_hooks ${tombmount}
exec_safe_bind_hooks ${tombmount} if ! [ $NOBIND ]; then
exec_post_hooks ${tombmount} open exec_safe_bind_hooks ${tombmount}
exec_post_hooks ${tombmount} open
fi
return 0 return 0
} }
@ -686,9 +535,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 -q askpass ${FILE}` tombpass=`exec_as_user tomb askpass ${tombkey}`
tombpasstmp=$tombpass tombpasstmp=$tombpass
tombpass=`exec_as_user tomb -q askpass "${FILE} (again)"` tombpass=`exec_as_user tomb askpass "${tombkey} (again)"`
if [ "$tombpasstmp" = "$tombpass" ]; then if [ "$tombpasstmp" = "$tombpass" ]; then
break; break;
fi fi
@ -704,7 +553,6 @@ encode_key() {
awk ' awk '
/^-----/ {next} /^-----/ {next}
/^Version/ {next} /^Version/ {next}
/^Comment/ {next}
{print $0}' ${tombkey} \ {print $0}' ${tombkey} \
| steghide embed --embedfile - --coverfile ${imagefile} \ | steghide embed --embedfile - --coverfile ${imagefile} \
-p ${tombpass} -z 9 -e serpent cbc -p ${tombpass} -z 9 -e serpent cbc
@ -732,27 +580,26 @@ decode_key() {
return 1 return 1
fi fi
tombfile=${tombname%%\.*}.tomb.gpg keyfile=${tombname%%\.*}.key
notice "Decoding 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 -q askpass ${keyname}` tombpass=`exec_as_user tomb askpass ${keyfile}`
else else
tombpass=`exec_as_user tomb -q askpass "$keyname (retry $c)"` tombpass=`exec_as_user tomb askpass "$keyfile (retry $c)"`
fi fi
steghide extract -sf ${imagefile} -p ${tombpass} -xf - \ steghide extract -sf ${imagefile} -p ${tombpass} -xf - \
| awk ' | awk '
BEGIN { BEGIN {
print "-----BEGIN PGP MESSAGE-----" print "-----BEGIN PGP MESSAGE-----"
print "Version: GnuPG v1.4.10 (GNU/Linux)"
} }
{ print $0 } { print $0 }
END { END {
print "-----END PGP MESSAGE-----" print "-----END PGP MESSAGE-----"
}' > ${tombfile} }' > ${keyfile}
if [ "`cat ${tombfile} | wc -l`" != "3" ]; then if [ "`cat ${keyfile} | wc -l`" != "3" ]; then
act "${tombfile} succesfully decoded" act "${keyfile} succesfully decoded"
res=0 res=0
break; break;
fi fi
@ -780,7 +627,8 @@ exec_bind_hooks() {
{ if($1 && $2) print "mount -o bind \${mnt}/" $1 " " $2 "; " } { if($1 && $2) print "mount -o bind \${mnt}/" $1 " " $2 "; " }
'` '`
# restore $HOME for the calling user # restore $HOME for the calling user
HOME=/home/${SUDO_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" act "bind hooks found, mounting directories as requested"
# execute the mount commands # execute the mount commands
@ -800,9 +648,9 @@ exec_safe_bind_hooks() {
error "cannot exec bind hooks without a mounted tomb." error "cannot exec bind hooks without a mounted tomb."
return 1 return 1
fi fi
if [ ! -r "$MOUNTPOINT/bind-hooks" ]; then if ! [ -r "$MOUNTPOINT/bind-hooks" ]; then
func "cannot read bind-hooks." func "bind-hooks not found in $MOUNTPOINT"
return return 1
fi fi
typeset -al created typeset -al created
typeset -al mounted typeset -al mounted
@ -820,7 +668,7 @@ exec_safe_bind_hooks() {
return 1 return 1
fi fi
if [ ! -d "$HOME/${maps[$dir]}" ]; then if [ ! -d "$HOME/${maps[$dir]}" ]; then
notice "creating $HOME/${maps[$dir]}" act "creating $HOME/${maps[$dir]}"
mkdir -p $HOME/${maps[$dir]} mkdir -p $HOME/${maps[$dir]}
created+=("$HOME/${maps[$dir]}") created+=("$HOME/${maps[$dir]}")
fi fi
@ -844,38 +692,6 @@ exec_post_hooks() {
fi fi
} }
get_arg_tomb() {
# set up variables to be used by caller:
# tombfile - filename without path
# tombdir - directory where the tomb is
# tombname - name of the tomb (filename without extension)
# the full path is made with $tombdir/$tombfile
if [ -z $1 ]; then
error "internal: get_arg_tomb called without argument"
return 1
fi
# make sure there is a .tomb extension
arg=${1%%\.*}.tomb
if ! [ -r ${arg} ]; then
error "file not found: $arg"
return 1
fi
tombfile=`basename $arg`
tombdir=`dirname $arg`
file ${tombdir}/${tombfile} | grep -i 'luks encrypted file' 2>&1 >/dev/null
if [ $? != 0 ]; then
error "$arg is not a valid tomb file, operation aborted"
tomb-notify "Not a tomb." "$arg doesn't seems a real tomb."
return 1
fi
tombname=${tombfile%%\.*}
return 0
}
backup_tomb() { # FIXME - duplicity asks passwords too often backup_tomb() { # FIXME - duplicity asks passwords too often
# using duplicity # using duplicity
@ -913,10 +729,10 @@ backup_tomb() { # FIXME - duplicity asks passwords too often
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 tomb 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
# i.e. try ssh true to sshurl="`echo $bckurl | sed -e 's/ssh:\/\///'`" # i.e. try ssh true to sshurl="`echo $bckurl | sed -e 's/ssh:\/\///'`"
# --no-print-statistics # --no-print-statistics
fi fi
# duplicity works only on directories # duplicity works only on directories
@ -984,8 +800,8 @@ umount_tomb() {
if [ "$1" = "all" ]; then if [ "$1" = "all" ]; then
tombs=`find /dev/mapper -name 'tomb.*'` tombs=`find /dev/mapper -name 'tomb.*'`
if ! [ $tombs ]; then if ! [ $tombs ]; then
error "Tombs are all closed, cemetery is quiet." notice "Tombs are all closed, cemetery is quiet."
return 1 return 0
fi fi
for t in ${(f)tombs}; do for t in ${(f)tombs}; do
umount_tomb ${t} umount_tomb ${t}
@ -1000,7 +816,6 @@ umount_tomb() {
else else
error "tomb not found: $1" error "tomb not found: $1"
error "please specify an existing /dev/mapper/tomb.*" error "please specify an existing /dev/mapper/tomb.*"
tomb-notify "Tomb was already closed." "Undertaker will rest in peace."
return 0 return 0
fi fi
@ -1021,15 +836,17 @@ umount_tomb() {
fi fi
# Execute post-hooks for eventual cleanup # Execute post-hooks for eventual cleanup
exec_post_hooks ${tombmount} close if ! [ $NOBIND ]; then
exec_post_hooks ${tombmount} close
fi
act "closing tomb $tombname on dm-crypt $basemap" act "closing tomb $tombname on dm-crypt $basemap"
mount | grep $mapper 2>&1 >/dev/null mount | grep $mapper 2>&1 >/dev/null
if [ $? = 0 ]; then # still mounted if [ $? = 0 ]; then # still mounted
umount ${mapper} umount ${mapper}
if ! [ $? = 0 ]; then if ! [ $? = 0 ]; then
tomb-notify "Tomb '$tombname' is too busy." \ # TODO: ask user if wanting to SLAM the tomb closed
"Close all applications and file managers, then try again." # then kill all processes found using it with fuser and lsof
return 1 return 1
fi fi
fi fi
@ -1042,8 +859,7 @@ umount_tomb() {
losetup -d "/dev/`echo $basemap | cut -d. -f4`" losetup -d "/dev/`echo $basemap | cut -d. -f4`"
notice "crypt storage ${mapper} unmounted" notice "Tomb $tombname closed: your bones will rest in peace."
tomb-notify "Tomb closed: $tombname" "Your bones will Rest In Peace."
return 0 return 0
} }
@ -1053,7 +869,7 @@ umount_tomb() {
install_tomb() { install_tomb() {
# TODO: distro package deps (for binary) # TODO: distro package deps (for binary)
# debian: zsh, cryptsetup, libgtk2.0-0, libnotify-bin # debian: zsh, cryptsetup, sudo
act "updating mimetypes..." act "updating mimetypes..."
cat <<EOF > /tmp/dyne-tomb.xml cat <<EOF > /tmp/dyne-tomb.xml
<?xml version="1.0"?> <?xml version="1.0"?>
@ -1064,7 +880,7 @@ install_tomb() {
</mime-type> </mime-type>
<mime-type type="application/x-tomb-key"> <mime-type type="application/x-tomb-key">
<comment>Tomb crypto key</comment> <comment>Tomb crypto key</comment>
<glob pattern="*.tomb.gpg"/> <glob pattern="*.key"/>
</mime-type> </mime-type>
</mime-info> </mime-info>
EOF EOF
@ -1115,7 +931,7 @@ application/x-tomb-volume
ext: tomb ext: tomb
application/x-tomb-key application/x-tomb-key
ext: tomb.gpg ext: key
EOF EOF
cat <<EOF > /usr/lib/mime/packages/tomb cat <<EOF > /usr/lib/mime/packages/tomb
application/x-tomb-volume; tomb-open '%s'; priority=8 application/x-tomb-volume; tomb-open '%s'; priority=8
@ -1155,9 +971,8 @@ case "$CMD" in
install) check_priv ; install_tomb ;; install) check_priv ; install_tomb ;;
askpass) ask_password $CMD2 $CMD3 ;; askpass) ask_password $CMD2 ;;
status) tomb-status ;; status) tomb-status ;;
notify) tomb-notify $CMD2 $CMD3 ;;
*) error "command \"$CMD\" not recognized" *) error "command \"$CMD\" not recognized"
act "try -h for help" act "try -h for help"

View File

@ -31,35 +31,188 @@ try() {
else return -1; fi else return -1; fi
} }
tombdir=`dirname $1` # popup notification
tombfile=`basename $1` tomb-notify() {
tombname=${tombfile%%\.*}
which notify-send > /dev/null
if [ $? != 0 ]; then return 1; fi
# 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
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
notify-send -i $icon ${@}
fi
}
# USB plug auto detect using dmesg
# tested on ubuntu 10.04 and debian 6.0
# please test and patch on other systems if you can.
# TODO: use udev rules, see how archlinux folks document it:
# 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() {
unset usbkey_mount
echo "Waiting 1 minute for a usb key to connect"
echo -n " . please insert your usb key "
tomb-notify "Insert your USB KEY" \
"Tomb is waiting 30 seconds for you to insert an external key."
plugged=false
c=0
while [ "$plugged" != "true" ]; do
dmesg | tail -n 12 | grep -q 'new.*USB device'
if [ $? = 0 ]; then plugged=true; fi
echo -n "."
sleep .5
c=`expr $c + 1`
if [ $c -gt 60 ]; then
echo
echo "[!] timeout."
return 1;
fi
done
echo
echo -n " . usb key inserted, attaching "
c=0
attached=false
while [ "$attached" != "true" ]; do
dmesg | tail -n 12| grep -q 'Attached.*removable disk'
if [ $? = 0 ]; then attached=true; fi
echo -n "."
sleep .5
c=`expr $c + 1`
if [ $c -gt 30 ]; then
echo
echo "[!] timeout."
export usbkey_mount=none
return 1;
fi
done
echo
echo -n " . usb attached, opening "
# get the first partition
# usbpart=`dmesg |tail -n 12 | grep ' sd.:' |cut -d: -f2 |tr -d ' '`
for i in $(seq 1 10); do
usbpart=$(dmesg | tail -n 12 | sed '/ sd.:/!d;s/^.*: \(sd.[0-9]*\)/\1/')
if [ -n "$usbpart" ]; then
break
elif [ $i -eq 10 ]; then
echo "[!] timeout."
return 1
else
echo -n .
sleep 1
fi
done
mtmp=$(/bin/mktemp -d --tmpdir tomb.XXXXXXXXXXXX)
sudo mount /dev/$usbpart $mtmp
if [ $? = 0 ]; then
usbmount=$mtmp
else
echo "[!] cannot mount usbkey partition $usbmount"
return 1
fi
echo
echo " . usb key mounted on $usbmount"
usbkey_mount=$usbmount
return 0
}
launch_status() {
# calculates the correct arguments to launch tomb-status tray
# applet; it takes the tomb name as an argument and should be
# launched after a successful tomb mount.
if ! [ $1 ]; then
echo "[!] cannot launch status tray applet: we don't even know the name of our tomb."
exit 1
fi
tombname=${1}
tombmap=`mount -l | awk "/\[${tombname}\]$/"' { print $1 } '`
tombmount=`mount -l | awk "/\[${tombname}\]$/"' { print $3 } '`
tomb-status $tombmap $tombname $tombmount &!
}
# got an argument # got an argument
if [ $1 ]; then # is it a file? if [ $1 ]; then # is it a file?
tombdir=`dirname $1`
tombfile=`basename $1`
tombname=${tombfile%%\.*}
if [ -f ${tombdir}/${tombfile} ]; then if [ -f ${tombdir}/${tombfile} ]; then
# is it a luks partition # is it a luks partition
file ${tombdir}/${tombfile} | grep LUKS file ${tombdir}/${tombfile} | grep -i LUKS > /dev/null
if [ $? = 0 ]; then # tomb is a valid LUKS file if [ $? = 0 ]; then # tomb is a valid LUKS file
if [ -r ${tombdir}/${tombname}.key ]; then
tombkey=${tombdir}/${tombname}.key
else
ask_usbkey
if ! [ $usbkey_mount ]; then # no usb key was mounted
echo "key not provided for tomb: $tombname"
echo "operation aborted." # TODO: dialog with pinentry
exit 1
else # usb mounted, check key presence
if [ -r ${usbkey_mount}/.tomb/${tombname}.key ]; then
tombkey=${usbkey_mount}/.tomb/${tombname}.key
elif [ -r ${usbkey_mount}/.tomb ]; then
echo "we can't find the right key, have a look yourself:"
ls -lha ${usbkey_mount}/.tomb
exit 1
else
echo "there are no keys stored in your usb"
exit 1
fi
fi
fi
if ! [ ${tombkey} ]; then # just to be sure
echo "key not found, operation aborted."
exit 1
else
tomb -k ${tombkey} mount ${tombdir}/${tombfile}
success=$?
fi
tomb mount ${tombdir}/${tombfile} if [ $usbkey_mount ]; then
sudo umount ${usbkey_mount}
rmdir ${usbkey_mount}
unset usbkey_mount
fi
if [ $? = 0 ]; then # mount was succesfull (with password and all) if [ $success = 0 ]; then # mount was succesfull (with password and all)
# strip extension if there launch_status ${tombname}
tombmap=`mount -l | awk "/\[${tombname}\]$/"' { print $1 } '`
tombmount=`mount -l | awk "/\[${tombname}\]$/"' { print $3 } '`
echo "tomb-status $tombmap $tombname $tombmount"
tomb-status $tombmap $tombname $tombmount &!
exit 0 exit 0
else else
tomb notify "Tomb cannot open." "Are you knocking the wrong door?" tomb-notify "Tomb cannot open." "Are you knocking the wrong door?"
exit 1 exit 1
fi fi
else else
tomb notify "Not a real Tomb." "We found no real bones in there." tomb-notify "Not a real Tomb." "We found no real bones in there."
exit 1 exit 1
fi fi
@ -74,7 +227,7 @@ if [ $1 ]; then # is it a file?
try rox; if [ $? = 0 ]; then rox ${1}; exit 0; fi try rox; if [ $? = 0 ]; then rox ${1}; exit 0; fi
try fsviewer; if [ $? = 0 ]; then fsviewer ${1}; exit 0; fi try fsviewer; if [ $? = 0 ]; then fsviewer ${1}; exit 0; fi
# try xnc; if [ $? = 0 ]; then xnc ${1}; exit 0; fi # try xnc; if [ $? = 0 ]; then xnc ${1}; exit 0; fi
tomb notify "File manager not found." "Tomb cannot guess which filemanager you are using" tomb-notify "File manager not found." "Tomb cannot guess which filemanager you are using"
exit 1 exit 1
fi fi
fi fi
@ -88,7 +241,13 @@ if [ -z $DISPLAY ]; then
fi fi
# no arguments: start guided tomb creation # no arguments: start guided tomb creation
tomb notify tomb-notify
# we do it on the desktop by default
if [ -r $HOME/Desktop ]; then
cd $HOME/Desktop;
# or inside HOME
else cd $HOME; fi
cat <<EOF cat <<EOF
Create a new Tomb Create a new Tomb
================= =================
@ -115,13 +274,14 @@ fi
# let's proceed # let's proceed
echo " Please type in the name for your new tomb file:" echo " Please type in the name for your new tomb file:"
echo -n "> " echo -n "> "
read filename read tombname
echo " How big you want the Tomb to be?" echo " How big you want the Tomb to be?"
echo " Type a size number in Megabytes:" echo " Type a size number in Megabytes:"
echo -n "> " echo -n "> "
read size read tombsize
clear
echo " You have commanded the creation of this Tomb:" echo " You have commanded the creation of this Tomb:"
echo " $filename ( $size MBytes )"; echo " $tombname ( $tombsize MBytes )";
echo echo
cat <<EOF cat <<EOF
Please confirm if you want to proceed now: Please confirm if you want to proceed now:
@ -146,22 +306,60 @@ cat <<EOF
password: password:
EOF EOF
tomb create ${filename}.tomb $size tombfile=${tombname}.tomb
tomb -s $tombsize create ${tombfile}
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "An error occurred creating tomb, operation aborted." echo "An error occurred creating tomb, operation aborted."
exit 1 exit 1
else
tombname="${filename%%.*}"
tombmap=`mount -l | awk "/\[${tombname}\]$/"' { print $1 } '`
tombmount=`mount -l | awk "/\[${tombname}\]$/"' { print $3 } '`
tomb-status $tombmap $tombname $tombmount &!
fi fi
tomb-notify "The Tomb is ready!" "We will now open your new Tomb for the first time."
cat <<EOF
Would you like to save the key on an external usb device?"
This is recommended for safety:"
Always keep the key in a different place than the door!"
If you answer yes, you'll need a USB KEY now: (y/n)"
EOF
# tomb-notify "Tomb has forged a key." "Would you like to save it on USB?"
echo -n " > "
read -q
if [ $? = 0 ]; then
ask_usbkey
if [ ${usbkey_mount} ]; then
# if ! [ -r /usr/share/applications/tomb.desktop ]; then sudo mkdir -m 0700 -p ${usbkey_mount}/.tomb
# echo " Well done!" sudo cp -v ${tombname}.key ${usbkey_mount}/.tomb/
# echo " Now the last thing to do is to install Tomb on your desktop:" sudo chmod -R go-rwx ${usbkey_mount}/.tomb
# sudo tomb install
# fi
echo "${tombname}.key succesfully saved on your USB"
echo "now we'll proceed opening your brand new tomb"
tomb -k ${tombname}.key open ${tombfile}
if [ $? = 0 ]; then
launch_status ${tombname}
fi
rm -f ${tombname}.key
sudo umount ${usbkey_mount}
rmdir ${usbkey_mount}
unset usbkey_mount
exit 0
fi
fi
cat <<EOF
Impossible to save the key on USB.
We recommend to preserve the key in a separate place!
You can move it yourself later, place it in a hidden directory
named .tomb inside the first partition of an usb key.
EOF
tomb -k ${tombname}.key open ${tombfile}
if [ $? = 0 ]; then
launch_status ${tombname}
fi
exit 0

View File

@ -215,6 +215,9 @@ gboolean cb_close(GtkWidget *w, GdkEvent *e) {
notify_uninit(); notify_uninit();
exit(0); exit(0);
} }
/* tomb-notify "Tomb '$tombname' is too busy." \
"Close all applications and file managers, then try again."
*/
return TRUE; return TRUE;
} }