diff --git a/src/tomb b/src/tomb index 38bfd04..7e141a4 100755 --- a/src/tomb +++ b/src/tomb @@ -4,7 +4,7 @@ # # a tool to easily operate file encryption of private and secret data # -# Copyleft (C) 2007-2011 Denis Roio +# {{{ Copyleft (C) 2007-2011 Denis Roio # # This source code is free software; you can redistribute it and/or # modify it under the terms of the GNU Public License as published by @@ -19,7 +19,8 @@ # You should have received a copy of the GNU Public License along with # this source code; if not, write to: # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - +# }}} +# {{{ GLOBAL VARIABLES VERSION=1.2 DATE=Nov/2011 TOMBEXEC=$0 @@ -37,8 +38,9 @@ typeset -A global_opts typeset -A opts # PATH=/usr/bin:/usr/sbin:/bin:/sbin - -# standard output message routines +# }}} +# {{{ HELPER FUNCTIONS +# {{{ - Standard output message routines # it's always useful to wrap them, in case we change behaviour later notice() { if [[ $QUIET == 0 ]]; then print "$fg_bold[green][*]$fg_no_bold[white] $1" >&2; fi } error() { if [[ $QUIET == 0 ]]; then print "$fg[red][!]$fg[white] $1" >&2; fi } @@ -52,7 +54,8 @@ act() { fi fi } - +# }}} +# {{{ - CHECK BINARY DEPENDENCIES check_bin() { # which dd command to use which dcfldd > /dev/null @@ -102,12 +105,12 @@ check_bin() { error "Cannot find pinentry. Please install it." exit 1 fi - + which mktemp > /dev/null if [ $?! = 0 ]; then MKTEMP=0 fi - + # check for tomb-open script if [ "$0" = "./tomb" ]; then TOMBOPENEXEC="./tomb-open" @@ -115,8 +118,9 @@ check_bin() { TOMBOPENEXEC="`dirname $0`/tomb-open" fi } - -# safe dir creation function +# }}} +# {{{ - "SAFE" FUNCTIONS +# {{{ - Create a directory with caution safe_dir() { which mktemp &> /dev/null if [[ $? = 0 ]]; then @@ -127,21 +131,21 @@ safe_dir() { (umask 077 && mkdir "$dir") || print "-1" print "$dir" } - - +# }}} +# {{{ - Create a file with caution safe_file() { local tmpdir tmpfile - + if [ "$MKTEMP" = "1" ]; then mktemp -u /dev/shm/$1.$$.XXXXXXX # this return needs to output ONLY the file - else + else tmpfile="/dev/shm/$1.$$.$RANDOM.$RANDOM" print $tmpfile fi } - -#check if there is swap activated +# }}} +# {{{ - Check if swap is activated check_swap() { # Return 0 if NO swap is used, 1 if swap is used # TODO: it should return 2 if swap is used, but encrypted @@ -157,7 +161,8 @@ check_swap() { fi return $r; } - +# }}} +# {{{ - Ask user for a password # we use pinentry now # comes from gpg project and is much more secure # it also conveniently uses the right toolkit @@ -184,8 +189,8 @@ GETPIN EOF } - -# drop privileges +# }}} +# {{{ - Drop privileges exec_as_user() { if ! [ $SUDO_USER ]; then exec $@[@] @@ -196,9 +201,8 @@ exec_as_user() { sudo -u $SUDO_USER "${@[@]}" return $? } - - -# escalate privileges +# }}} +# {{{ - Escalate privileges check_priv() { if [ $UID != 0 ]; then func "Using sudo for root execution of 'tomb ${(f)OLDARGS}'" @@ -220,9 +224,11 @@ EOF fi # are we root already return 0 } - +# }}} +# }}} +# {{{ - TOMB USAGE usage() { - cat <. EOF } - +# }}} +# {{{ - I18N FUNCTIONS generate_translatable_strings() { cat < /dev/null + if [ $? != 0 ]; then + error "encode failed: $tombkey is not a tomb key" + return 1 + fi + file $imagefile | grep JPEG > /dev/null + if [ $? != 0 ]; then + error "encode failed: $imagefile is not a jpeg image" + return 1 + fi + + notice "Encoding key $tombkey inside image $imagefile" + act "please choose a password for the encoding" + + # 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 ${TOMBEXEC} askpass "Steg password for ${tombkey}"` + tombpasstmp=$tombpass + tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${tombkey} (again)"` + if [ "$tombpasstmp" = "$tombpass" ]; then + break; + fi + unset tombpasstmp + unset tombpass + done + + if [ -z $tombpass ]; then + error "passwords don't match, aborting operation." + return 1 + fi + + awk ' +/^-----/ {next} +/^Version/ {next} +{print $0}' ${tombkey} \ + | steghide embed --embedfile - --coverfile ${imagefile} \ + -p ${tombpass} -z 9 -e serpent cbc + if [ $? != 0 ]; then + error "encoding error: steghide reports problems" + res=1 + else + notice "tomb key encoded succesfully into image ${imagefile}" + res=0 + fi + + unset tombpass + + return $res +} +# }}} +# {{{ - Decode Key +decode_key() { + tombname=$CMD2 + imagefile=$CMD3 + res=1 + + file $imagefile | grep JPEG > /dev/null + if [ $? != 0 ]; then + error "encode failed: $imagefile is not a jpeg image" + return 1 + fi + + keyfile=${tombname%%\.*}.tomb.key + if [[ -e "$keyfile" ]]; then + error "Key file $keyfile already exist." + return 1 + fi + 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 ${TOMBEXEC} askpass "Steg password for ${keyfile}"` + else + tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for $keyfile (retry $c)"` + fi + steghide extract -sf ${imagefile} -p ${tombpass} -xf - \ + | awk ' +BEGIN { +print "-----BEGIN PGP MESSAGE-----" +} +{ print $0 } +END { +print "-----END PGP MESSAGE-----" +}' > ${keyfile} + + if [ "`cat ${keyfile} | wc -l`" != "3" ]; then + act "${keyfile} succesfully decoded" + res=0 + break; + fi + done + + unset tombpass + + if [ $res != 0 ]; then + error "nothing found." + fi + + return $res +} +# }}} +# }}} +# {{{ - HOOK HELPERS +# {{{ - Execute Bind Hooks +exec_safe_bind_hooks() { + if [[ -n ${(k)opts[-o]} ]]; then + MOUNTOPTS=${opts[-o]} + fi + local MOUNTPOINT="${1}" + local ME=${SUDO_USER:-$(whoami)} + local HOME=$(awk -v a="$ME" -F ':' '{if ($1 == a) print $6}' /etc/passwd 2>/dev/null) + if [ $? -ne 0 ]; then + error "how pitiful! A tomb, and no HOME" + return 1 + fi + if [ -z "$MOUNTPOINT" -o ! -d "$MOUNTPOINT" ]; then + error "cannot exec bind hooks without a mounted tomb." + return 1 + fi + if ! [ -r "$MOUNTPOINT/bind-hooks" ]; then + func "bind-hooks not found in $MOUNTPOINT" + return 1 + fi + typeset -al mounted + typeset -Al maps + maps=($(<"$MOUNTPOINT/bind-hooks")) + for dir in ${(k)maps}; do + if [ "${dir[1]}" = "/" -o "${dir[1,2]}" = ".." ]; then + error "bind-hooks map format: local/to/tomb local/to/\$HOME" + continue + fi + if [ "${${maps[$dir]}[1]}" = "/" -o "${${maps[$dir]}[1,2]}" = ".." ]; then + error "bind-hooks map format: local/to/tomb local/to/\$HOME. Rolling back" + for dir in ${mounted}; do umount $dir; done + return 1 + fi + if [ ! -r "$HOME/${maps[$dir]}" ]; then + error "bind-hook target not existent, skipping $HOME/${maps[$dir]}" + elif [ ! -r "$MOUNTPOINT/$dir" ]; then + error "bind-hook source not found in tomb, skipping ${MOUNTPOINT}/${dir}" + else + mount -o bind,$MOUNTOPTS $MOUNTPOINT/$dir $HOME/${maps[$dir]} + mounted+=("$HOME/${maps[$dir]}") + fi + done +} +# }}} +# {{{ - POST-MOUNT HOOKS +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 + # security on what is being run, however we expect you know well + # what is inside your tomb. this feature opens the possibility to + # make encrypted executables. + cat ${mnt}/post-hooks | head -n1 | grep '^#!/' + if [ $? = 0 ]; then + act "post hooks found, executing as user $SUDO_USER" + exec_as_user ${mnt}/post-hooks $2 + fi +} +# }}} +# }}} +# }}} +# {{{ TOMB SUB-COMMANDS +# {{{ - Create create_tomb() { if ! option_is_set --ignore-swap && [[ `check_swap out` == 1 ]]; then error "You have swap activated; use --ignore-swap if you want to skip this check" @@ -328,19 +509,19 @@ create_tomb() { # make sure the file has a .tomb extension tombname=${tombfile%%\.*} tombfile=${tombname}.tomb - tombsize=$opts[-s] - + tombsize=$opts[-s] + if [[ $tombsize != <-> ]]; then error "Size is not an integer" return 1 fi - + if [ -e ${tombdir}/${tombfile} ]; then - error "tomb exists already. I'm not digging here:" - ls -lh ${tombdir}/${tombfile} - return 1 + error "tomb exists already. I'm not digging here:" + ls -lh ${tombdir}/${tombfile} + return 1 fi - + if option_is_set -k; then tombkey="`option_value -k`.tomb.key" else @@ -489,7 +670,8 @@ create_tomb() { notice "Your tomb is ready in ${tombdir}/${tombfile} and secured with key ${tombkey}" } - +# }}} +# {{{ - Open mount_tomb() { notice "Commanded to open tomb $CMD2" if ! option_is_set --ignore-swap && [[ `check_swap out` == 1 ]]; then @@ -552,7 +734,7 @@ mount_tomb() { else tombmount=${CMD3} fi - + # check if its already open mount -l | grep "${tombfile}.*\[$tombname\]$" 2>&1 > /dev/null if [ $? = 0 ]; then @@ -561,7 +743,7 @@ mount_tomb() { list_tombs ${tombname} return 1 fi - + notice "mounting $tombfile on mountpoint $tombmount" # we need root from here on @@ -596,9 +778,9 @@ mount_tomb() { else tombpass=`exec_as_user ${TOMBEXEC} askpass "Open tomb $keyname (retry $c)"` fi - (gpg --batch --passphrase-fd 0 --no-tty --no-options \ - -d "${tombkey}" 2> /dev/null <<< ${tombpass} ) \ - | cryptsetup --key-file - luksOpen ${nstloop} ${mapper} + (gpg --batch --passphrase-fd 0 --no-tty --no-options \ + -d "${tombkey}" 2> /dev/null <<< ${tombpass} ) \ + | cryptsetup --key-file - luksOpen ${nstloop} ${mapper} unset tombpass # if key was from stdin delete temp file and dir @@ -638,171 +820,9 @@ mount_tomb() { fi return 0 } - -encode_key() { - tombkey=$CMD2 - imagefile=$CMD3 - - file $tombkey | grep PGP > /dev/null - if [ $? != 0 ]; then - error "encode failed: $tombkey is not a tomb key" - return 1 - fi - file $imagefile | grep JPEG > /dev/null - if [ $? != 0 ]; then - error "encode failed: $imagefile is not a jpeg image" - return 1 - fi - - notice "Encoding key $tombkey inside image $imagefile" - act "please choose a password for the encoding" - - # 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 ${TOMBEXEC} askpass "Steg password for ${tombkey}"` - tombpasstmp=$tombpass - tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${tombkey} (again)"` - if [ "$tombpasstmp" = "$tombpass" ]; then - break; - fi - unset tombpasstmp - unset tombpass - done - - if [ -z $tombpass ]; then - error "passwords don't match, aborting operation." - return 1 - fi - - awk ' -/^-----/ {next} -/^Version/ {next} -{print $0}' ${tombkey} \ - | steghide embed --embedfile - --coverfile ${imagefile} \ - -p ${tombpass} -z 9 -e serpent cbc - if [ $? != 0 ]; then - error "encoding error: steghide reports problems" - res=1 - else - notice "tomb key encoded succesfully into image ${imagefile}" - res=0 - fi - - unset tombpass - - return $res -} - -decode_key() { - tombname=$CMD2 - imagefile=$CMD3 - res=1 - - file $imagefile | grep JPEG > /dev/null - if [ $? != 0 ]; then - error "encode failed: $imagefile is not a jpeg image" - return 1 - fi - - keyfile=${tombname%%\.*}.tomb.key - if [[ -e "$keyfile" ]]; then - error "Key file $keyfile already exist." - return 1 - fi - 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 ${TOMBEXEC} askpass "Steg password for ${keyfile}"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for $keyfile (retry $c)"` - fi - steghide extract -sf ${imagefile} -p ${tombpass} -xf - \ - | awk ' -BEGIN { -print "-----BEGIN PGP MESSAGE-----" -} -{ print $0 } -END { -print "-----END PGP MESSAGE-----" -}' > ${keyfile} - - if [ "`cat ${keyfile} | wc -l`" != "3" ]; then - act "${keyfile} succesfully decoded" - res=0 - break; - fi - done - - unset tombpass - - if [ $res != 0 ]; then - error "nothing found." - fi - - return $res -} - -exec_safe_bind_hooks() { - if [[ -n ${(k)opts[-o]} ]]; then - MOUNTOPTS=${opts[-o]} - fi - local MOUNTPOINT="${1}" - local ME=${SUDO_USER:-$(whoami)} - local HOME=$(awk -v a="$ME" -F ':' '{if ($1 == a) print $6}' /etc/passwd 2>/dev/null) - if [ $? -ne 0 ]; then - error "how pitiful! A tomb, and no HOME" - return 1 - fi - if [ -z "$MOUNTPOINT" -o ! -d "$MOUNTPOINT" ]; then - error "cannot exec bind hooks without a mounted tomb." - return 1 - fi - if ! [ -r "$MOUNTPOINT/bind-hooks" ]; then - func "bind-hooks not found in $MOUNTPOINT" - return 1 - fi - typeset -al mounted - typeset -Al maps - maps=($(<"$MOUNTPOINT/bind-hooks")) - for dir in ${(k)maps}; do - if [ "${dir[1]}" = "/" -o "${dir[1,2]}" = ".." ]; then - error "bind-hooks map format: local/to/tomb local/to/\$HOME" - continue - fi - if [ "${${maps[$dir]}[1]}" = "/" -o "${${maps[$dir]}[1,2]}" = ".." ]; then - error "bind-hooks map format: local/to/tomb local/to/\$HOME. Rolling back" - for dir in ${mounted}; do umount $dir; done - return 1 - fi - if [ ! -r "$HOME/${maps[$dir]}" ]; then - error "bind-hook target not existent, skipping $HOME/${maps[$dir]}" - elif [ ! -r "$MOUNTPOINT/$dir" ]; then - error "bind-hook source not found in tomb, skipping ${MOUNTPOINT}/${dir}" - else - mount -o bind,$MOUNTOPTS $MOUNTPOINT/$dir $HOME/${maps[$dir]} - mounted+=("$HOME/${maps[$dir]}") - fi - done -} - -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 - # security on what is being run, however we expect you know well - # what is inside your tomb. this feature opens the possibility to - # make encrypted executables. - cat ${mnt}/post-hooks | head -n1 | grep '^#!/' - if [ $? = 0 ]; then - act "post hooks found, executing as user $SUDO_USER" - exec_as_user ${mnt}/post-hooks $2 - fi -} - -# {{{ slam_tomb +# }}} +# {{{ - Close +# {{{ - Slam the door # Kill all processes using the tomb slam_tomb() { # $1 = tomb mount point @@ -813,62 +833,61 @@ slam_tomb() { return 1 } # }}} - +# {{{ - Unmount Tomb umount_tomb() { local tombs how_many_tombs local pathmap mapper tombname tombmount loopdev local ans pidk pname if ! [ $1 ]; then - 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.*'` - func "closing mapper $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 + 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.*'` + func "closing mapper $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 - tombs=`find /dev/mapper -name 'tomb.*'` - if ! [ $tombs ]; then - notice "Tombs are all closed, cemetery is quiet." - return 0 - fi - for t in ${(f)tombs}; do - umount_tomb ${t} - done + tombs=`find /dev/mapper -name 'tomb.*'` + if ! [ $tombs ]; then + notice "Tombs are all closed, cemetery is quiet." return 0 + fi + for t in ${(f)tombs}; do + umount_tomb ${t} + done + return 0 fi - # tomb close argument deduction pathmap=`dirname "$1"` if [ "${pathmap}" = "/dev/mapper" ]; then - mapper="$1" # argument is the mapper (or none which autofills mapper) - tombname="`print $mapper | cut -d. -f2`" - tombmount=`mount -l | \ + mapper="$1" # argument is the mapper (or none which autofills mapper) + tombname="`print $mapper | cut -d. -f2`" + tombmount=`mount -l | \ awk -vtomb="[$tombname]" '/^\/dev\/mapper\/tomb/ { if($7==tomb) print $3 } '` elif [ "$pathmap" = "." ]; then - tombname="$1" # argument is the name - mapper=`mount -l | \ + tombname="$1" # argument is the name + mapper=`mount -l | \ awk -vtomb="[$tombname]" '/^\/dev\/mapper\/tomb/ { if($7==tomb) print $1 } '` - tombmount=`mount -l | \ + tombmount=`mount -l | \ awk -vtomb="[$tombname]" '/^\/dev\/mapper\/tomb/ { if($7==tomb) print $3 } '` else - tombmount="$1" # argument should be the mount + tombmount="$1" # argument should be the mount mapper=`mount | awk -vmnt="$tombmount" '/^\/dev\/mapper\/tomb/ { if($3==mnt) print $1 }'` - tombname="`print $mapper | cut -d. -f2`" + tombname="`print $mapper | cut -d. -f2`" fi # avoid block when the same tomb is mounted, take only the first @@ -886,43 +905,43 @@ umount_tomb() { fi if [ $SLAM ]; then - notice "Slamming tomb $tombname mounted on $tombmount" - act "Kill all processes busy inside the tomb" + notice "Slamming tomb $tombname mounted on $tombmount" + act "Kill all processes busy inside the tomb" slam_tomb "$tombmount" if [[ $? == 1 ]]; then error "Cannot slam the tomb $tombname" return 1 fi else - notice "Closing tomb $tombname mounted on $tombmount" + notice "Closing tomb $tombname mounted on $tombmount" fi # check if there are binded dirs and close them tombmount_esc=`sed 's:\/:\\\/:g' <<< $tombmount ` unbind=`mount | awk "/^$tombmount_esc.*bind/"' { print $3 }'` for b in ${(f)unbind}; do - hook="`basename $b`" - act "closing tomb hook: $hook" - umount $b - if [[ $? != 0 ]]; then - if [ $SLAM ]; then - notice "Slamming tomb: killing all processes using this hook" + hook="`basename $b`" + act "closing tomb hook: $hook" + umount $b + if [[ $? != 0 ]]; then + if [ $SLAM ]; then + notice "Slamming tomb: killing all processes using this hook" slam_tomb "$b" if [[ $? == 1 ]]; then error "Cannot slam the tomb $b" return 1 fi - umount $b + umount $b else - error "Tomb hook is busy, cannot close tomb." - return 1 - fi + error "Tomb hook is busy, cannot close tomb." + return 1 fi + fi done # Execute post-hooks for eventual cleanup if ! option_is_set -n ; then - exec_safe_post_hooks ${tombmount%%/} close + exec_safe_post_hooks ${tombmount%%/} close fi if [ $tombmount ]; then # tomb is actively mounted @@ -930,11 +949,11 @@ umount_tomb() { umount ${tombmount} if ! [ $? = 0 ]; then error "Tomb is busy, cannot umount!" - else + else # this means we used a "default" mount point - if [ "${tombmount}" = "/media/${tombname}.tomb" ]; then + if [ "${tombmount}" = "/media/${tombname}.tomb" ]; then rmdir ${tombmount} - fi + fi fi fi @@ -958,7 +977,9 @@ umount_tomb() { notice "Tomb $tombname closed: your bones will rest in peace." return 0 } - +# }}} +# }}} +# {{{ - Change Password # change tomb key password change_passwd() { if ! option_is_set --ignore-swap && [[ `check_swap out` == 1 ]]; then @@ -973,31 +994,30 @@ change_passwd() { # check the keyfile if ! [ -r $keyfile ]; then - error "key not found: $keyfile" - return 1 + error "key not found: $keyfile" + return 1 fi - + file $keyfile | grep PGP > /dev/null if [ $? != 0 ]; then - error "file doesn't seems to be a tomb key: $keyfile" - error "operation aborted." - return 1 + error "file doesn't seems to be a tomb key: $keyfile" + error "operation aborted." + return 1 fi local tmpnewkey tmpoldkey c tombpass tombpasstmp - + tmpnewkey=`safe_file tomb` tmpoldkey=`safe_file tomb` - notice "Changing password for $keyfile" keyname=`basename $keyfile` for c in 1 2 3; do - if [ $c = 1 ]; then - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname}" "Change tomb key password"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname} (retry $c)" "Change tomb key password"` - fi + if [ $c = 1 ]; then + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname}" "Change tomb key password"` + else + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname} (retry $c)" "Change tomb key password"` + fi gpg --batch --no-options --no-tty --passphrase-fd 0 -o "${tmpoldkey}" -d $keyfile <<< "$tombpass" &> /dev/null if [ $? = 0 ]; then tombpass="ok" @@ -1014,27 +1034,27 @@ change_passwd() { fi for c in 1 2 3; do - # 3 tries to write two times a matching password - if [ $c = 1 ]; then - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname}" "Change tomb key password"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname} (retry $c)" "Change tomb key password"` - fi - tombpasstmp=$tombpass - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password again" "Change tomb key password"` - if [ "$tombpasstmp" = "$tombpass" ]; then - break; - fi - unset tombpasstmp - unset tombpass + # 3 tries to write two times a matching password + if [ $c = 1 ]; then + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname}" "Change tomb key password"` + else + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname} (retry $c)" "Change tomb key password"` + fi + tombpasstmp=$tombpass + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password again" "Change tomb key password"` + if [ "$tombpasstmp" = "$tombpass" ]; then + break; + fi + unset tombpasstmp + unset tombpass done if [ -z $tombpass ]; then - error "You mistyped the new password. Operation aborted." + error "You mistyped the new password. Operation aborted." # /dev/null because the file cannot exists ${WIPE[@]} "${tmpnewkey}" 2> /dev/null ${WIPE[@]} "${tmpoldkey}" 2> /dev/null - return 1 + return 1 fi gpg \ @@ -1063,7 +1083,8 @@ change_passwd() { return 0 } - +# }}} +# {{{ - List # list all tombs mounted in a readable format list_tombs() { if [ $1 ]; then @@ -1090,10 +1111,8 @@ list_tombs() { exit 1 fi - for t in ${(f)mounted_tombs}; do mapper=`basename ${t[(ws:;:)1]}` - tombname=${t[(ws:;:)5]} tombmount=${t[(ws:;:)2]} tombfs=${t[(ws:;:)3]} @@ -1130,12 +1149,11 @@ list_tombs() { print -n "$fg_no_bold[white] free (" print -n "$fg_bold[white]$tombpercent" print "$fg_no_bold[white] full)" - + if [[ ${tombp} -ge 90 ]]; then print -n "$fg_no_bold[green]$tombname" print "$fg_bold[red] Your tomb is almost full!" fi - # now check hooks mtomb=`sed 's:\/:\\\/:g' <<< $tombmount` @@ -1149,7 +1167,8 @@ list_tombs() { done done } - +# }}} +# {{{ - Status launch_status() { # calculates the correct arguments to launch tomb-status tray # applet; it takes the tomb name as an argument and can be @@ -1176,7 +1195,7 @@ launch_status() { error "There is no open tomb, status cannot be launched" return 1 elif [[ "$how_many_tombs" == "1" ]]; then - #mapper=`find /dev/mapper -name 'tomb.*'` + #mapper=`find /dev/mapper -name 'tomb.*'` tombname=`find /dev/mapper -name "tomb.*"` tombname=`basename $tombname | cut -d. -f2` notice "launching status for tomb $tombname" @@ -1201,7 +1220,8 @@ launch_status() { tomb-status $tombmap $tombname $tombmount &! return 0 } - +# }}} +# {{{ - Install GUI # install mime-types, bells and whistles for the desktop # see http://developers.sun.com/solaris/articles/integrating_gnome.html # and freedesktop specs @@ -1245,7 +1265,7 @@ Categories=Utility;Security;Archiving;Filesystem; MimeType=application/x-tomb-volume; X-AppInstall-Package=tomb EOF - update-desktop-database + update-desktop-database act "updating menus..." cat < /etc/menu/tomb @@ -1290,7 +1310,10 @@ tomb EOF act "Tomb is now installed." } - +# }}} +# }}} +# {{{ OPTION PARSING +# {{{ - Check an option option_is_set() { #First argument, the option (something like "-s") #Second (optional) argument: if it's "out", command will print it out 'set'/'unset' @@ -1307,11 +1330,15 @@ option_is_set() { fi return $r; } +# }}} +# {{{ - Get an option value option_value() { #First argument, the option (something like "-s") <<< ${opts[$1]} } - +# }}} +# }}} +# {{{ MAIN COMMAND main() { local -A subcommands_opts ### Options configuration @@ -1367,100 +1394,125 @@ main() { argv=(${oldstar}) unset oldstar - ### Parsing global + command-specific options - # zsh magic: ${=string} will split to multiple arguments when spaces occur - set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]} - if [[ -n $cmd_opts ]]; then #if there is no option, we don't need parsing - zparseopts -M -E -D -Aopts ${cmd_opts} + ### Parsing global + command-specific options + # zsh magic: ${=string} will split to multiple arguments when spaces occur + set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]} + # if there is no option, we don't need parsing + if [[ -n $cmd_opts ]]; then + zparseopts -M -E -D -Aopts ${cmd_opts} if [[ $? != 0 ]]; then - error "Some error occurred during option processing. See \"tomb help\" for more info" - exit 127 + error "Some error occurred during option processing. See \"tomb help\" for more info" + exit 127 fi - fi - #build PARAM (array of arguments) and check if there are unrecognized options - ok=0 - PARAM=() - for arg in $*; do + fi + #build PARAM (array of arguments) and check if there are unrecognized options + ok=0 + PARAM=() + for arg in $*; do if [[ $arg == '--' || $arg == '-' ]]; then - ok=1 - continue #it shouldnt be appended to PARAM + ok=1 + continue #it shouldnt be appended to PARAM elif [[ $arg[1] == '-' ]]; then - if [[ $ok == 0 ]]; then + if [[ $ok == 0 ]]; then error "unrecognized option $arg" exit 127 - fi + fi fi PARAM+=$arg - done - #first parameter actually is the subcommand: delete it and shift - if [[ $subcommand != '__default' ]]; then - PARAM[1]=() - shift - fi - ### End parsing command-specific options + done + #first parameter actually is the subcommand: delete it and shift + if [[ $subcommand != '__default' ]]; then + PARAM[1]=() + shift + fi + ### End parsing command-specific options if ! option_is_set --no-color; then autoload colors; colors fi - ### Set global options (useless, but for code retro-compatibility) - for opt in ${(k)global_opts}; do + ### Set global options (useless, but for code retro-compatibility) + for opt in ${(k)global_opts}; do if [[ $opt == '-q' ]]; then - QUIET=1 + QUIET=1 elif [[ $opt == '-D' ]]; then - DEBUG=1 + DEBUG=1 fi - done + done - CMD=$subcommand - CMD2=$PARAM[1] - CMD3=$PARAM[2] + CMD=$subcommand + CMD2=$PARAM[1] + CMD3=$PARAM[2] func "Tomb command: $CMD $CMD2 $CMD3" case "$subcommand" in - create) check_priv ; create_tomb ;; - mount) check_priv ; mount_tomb ;; - open) check_priv ; mount_tomb ;; - umount) check_priv ; umount_tomb ${CMD2} ;; - close) check_priv ; umount_tomb ${CMD2} ;; - slam) check_priv ; SLAM=1; umount_tomb ${CMD2} ;; - passwd) check_priv ; change_passwd ${CMD2} ;; - list) list_tombs ${CMD2} ;; - status) launch_status ${CMD2} ;; - help) usage ;; - 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} ;; + create) + check_priv + create_tomb + ;; + mount|open) + check_priv + mount_tomb + ;; + umount|close|slam) + check_priv + [ "$subcommand" = "slam" ] && SLAM=1 + umount_tomb ${CMD2} + ;; + passwd) + check_priv + change_passwd ${CMD2} + ;; + list) + list_tombs ${CMD2} + ;; + status) + launch_status ${CMD2} + ;; + help) + usage + ;; + 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} + ;; # internal commands useful to developers - 'source') return 0 ;; - install) check_priv ; install_tomb ;; - askpass) ask_password ${CMD2} ${CMD3} ;; - mktemp) safe_dir ${CMD2} ;; - translate) generate_translatable_strings ;; - __default) - if option_is_set -v; then - echo Tomb - $VERSION - else - usage - fi;; - *) error "command \"$CMD\" not recognized" - act "try -h for help" - return 1 - ;; + 'source') return 0 ;; + install) check_priv ; install_tomb ;; + askpass) ask_password ${CMD2} ${CMD3} ;; + mktemp) safe_dir ${CMD2} ;; + translate) generate_translatable_strings ;; + __default) + if option_is_set -v; then + echo Tomb - $VERSION + else + usage + fi + ;; + *) + error "command \"$CMD\" not recognized" + act "try -h for help" + return 1 + ;; esac return $? } - +# }}} +# {{{ RUNTIME check_bin main $@ if [[ $? != 0 ]]; then #this "if" seems useless, but avoid source tomb source from exiting exit $? fi +# }}}