Cosmetic code cleanup: no functionality change.

This adds emacs folding-mode support to make it easier to find your way in the code.
In Emacs, try: M-x folding-mode, then: C-c @ C-q somewhere in the source.
This commit is contained in:
hellekin 2011-12-01 18:53:12 +01:00
parent dd3d5e6083
commit 0de65418da

490
src/tomb
View File

@ -4,7 +4,7 @@
#
# a tool to easily operate file encryption of private and secret data
#
# Copyleft (C) 2007-2011 Denis Roio <jaromil@dyne.org>
# {{{ Copyleft (C) 2007-2011 Denis Roio <jaromil@dyne.org>
#
# 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
@ -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,8 +131,8 @@ safe_dir() {
(umask 077 && mkdir "$dir") || print "-1"
print "$dir"
}
# }}}
# {{{ - Create a file with caution
safe_file() {
local tmpdir tmpfile
@ -140,8 +144,8 @@ safe_file() {
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,7 +224,9 @@ EOF
fi # are we root already
return 0
}
# }}}
# }}}
# {{{ - TOMB USAGE
usage() {
cat <<EOF
Tomb $VERSION - a strong and gentle undertaker for your secrets
@ -240,13 +246,13 @@ Commands:
slam close tomb FILE and kill all pids using it
passwd change the password of a tomb key FILE
EOF
if [ "$STEGHIDE" = 1 ]; then
if [ "$STEGHIDE" = 1 ]; then
cat <<EOF
bury hide a tomb key FILE inside a jpeg PLACE
exhume extract a tomb key FILE from a jpeg PLACE
EOF
fi
cat <<EOF
fi
cat <<EOF
Options:
@ -264,7 +270,8 @@ For more informations on Tomb read the manual: man tomb
Please report bugs on <http://bugs.dyne.org>.
EOF
}
# }}}
# {{{ - I18N FUNCTIONS
generate_translatable_strings() {
cat <<EOF
# Tomb - The Crypto Undertaker.
@ -291,7 +298,7 @@ EOF
usage | awk '
{ print "\"" $0 "\"" }'
cat <<EOF
cat <<EOF
msgstr ""
#
@ -308,7 +315,181 @@ EOF
print "#: act"; print "msgid " $0; print "msgstr \"\"\n" }
'
}
# }}}
# {{{ - HELPERS FOR KEYS
# {{{ - Encode Key
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
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"
@ -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
@ -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,7 +833,7 @@ slam_tomb() {
return 1
}
# }}}
# {{{ - Unmount Tomb
umount_tomb() {
local tombs how_many_tombs
local pathmap mapper tombname tombmount loopdev
@ -850,7 +870,6 @@ umount_tomb() {
return 0
fi
# tomb close argument deduction
pathmap=`dirname "$1"`
@ -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
@ -989,7 +1010,6 @@ change_passwd() {
tmpnewkey=`safe_file tomb`
tmpoldkey=`safe_file tomb`
notice "Changing password for $keyfile"
keyname=`basename $keyfile`
for c in 1 2 3; do
@ -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]}
@ -1136,7 +1155,6 @@ list_tombs() {
print "$fg_bold[red] Your tomb is almost full!"
fi
# now check hooks
mtomb=`sed 's:\/:\\\/:g' <<< $tombmount`
mounted_hooks=`mount | awk "/^$mtomb/"' {print $1 ";" $3}'`
@ -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
@ -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
@ -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
@ -1370,7 +1397,8 @@ main() {
### 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
# 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"
@ -1419,26 +1447,46 @@ main() {
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
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
encode_key ${CMD2} ${CMD3}
;;
exhume)
if [ "$STEGHIDE" = 0 ]; then
error "steghide not installed. Cannot exhume your key"
return 1
fi
decode_key ${CMD2} ;;
decode_key ${CMD2}
;;
# internal commands useful to developers
'source') return 0 ;;
install) check_priv ; install_tomb ;;
@ -1450,17 +1498,21 @@ main() {
echo Tomb - $VERSION
else
usage
fi;;
*) error "command \"$CMD\" not recognized"
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
# }}}