From b91573dde5003e06ac31e896adc80528241d88f5 Mon Sep 17 00:00:00 2001 From: hellekin Date: Thu, 23 Oct 2014 02:10:24 -0300 Subject: [PATCH] [cleanup] Introduce _plot --- tomb | 318 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 177 insertions(+), 141 deletions(-) diff --git a/tomb b/tomb index 50719a1..4de6c23 100755 --- a/tomb +++ b/tomb @@ -72,7 +72,11 @@ typeset -H _UID # Running user identifier typeset -H _GID # Running user group identifier typeset -H _TTY # Connected input terminal -typeset -H tomb_file +# Tomb context (see _plot()) +typeset -H TOMBPATH # Full path to the tomb +typeset -H TOMBDIR # Directory where the tomb is +typeset -H TOMBFILE # File name of the tomb +typeset -H TOMBNAME # Name of the tomb typeset -H tomb_key typeset -H tomb_key_file @@ -100,7 +104,10 @@ endgame() { while [[ ${#rr} -lt 500 ]]; do rr+="$RANDOM"; done # we make sure no info is left in unallocated mem - tomb_file="$rr"; unset tomb_file + TOMBPATH="$rr"; unset TOMBPATH + TOMBDIR="$rr"; unset TOMBDIR + TOMBFILE="$rr"; unset TOMBFILE + TOMBNAME="$rr"; unset TOMBNAME tomb_key="$rr"; unset tomb_key tomb_key_file="$rr"; unset tomb_key_file tomb_secret="$rr"; unset tomb_secret @@ -149,6 +156,35 @@ check_shm() { return 0 } +# Define sepulture's plot (setup tomb-related arguments) +# Synopsis: _plot "/path/to/the.tomb" +_plot() { + # We set global variables + typeset -g TOMBPATH TOMBDIR TOMBFILE TOMBNAME + + TOMBPATH="$1" + _verbose '_plot TOMBPATH = ::1 tomb path::' $TOMBPATH + + TOMBDIR=$(dirname $TOMBPATH) + _verbose '_plot TOMBDIR = ::1 tomb dir::' $TOMBDIR + + TOMBFILE=$(basename $TOMBPATH) + _verbose '_plot TOMBFILE = ::1 tomb file::' $TOMBFILE + + # The tomb name is TOMBFILE without an extension. + # It can start with dots: ..foo.tomb -> ..foo + TOMBNAME="${TOMBFILE%\.[^\.]*}" + _verbose '_plot TOMBNAME = ::1 tomb name::' $TOMBNAME + + # Normalize TOMBFILE name + TOMBFILE="${TOMBNAME}.tomb" + _verbose '_plot TOMBFILE = ::1 tomb file:: (normalized)' $TOMBFILE + + # Normalize TOMBPATH + TOMBPATH="${TOMBDIR}/${TOMBFILE}" + _verbose '_plot TOMBPATH = ::1 tomb path:: (normalized)' $TOMBPATH +} + # Provide a random filename in shared memory tmp_create() { local tfile="${TMPPREFIX}${RANDOM}" @@ -309,7 +345,7 @@ EOF return 0 } -# check if a filename is a valid tomb +# Check if a filename is a valid tomb is_valid_tomb() { _verbose "is_valid_tomb ::1 tomb file::" $1 # argument check @@ -329,13 +365,12 @@ is_valid_tomb() { file "$1" | grep -i "luks encrypted file" > /dev/null || { _warning "File is not yet a tomb: ::1 tomb file::" $1} - # check if its already open - tombfile=`basename $1` - tombname=${tombfile%%\.*} - mount -l | grep "${tombfile}.*\[$tombname\]$" > /dev/null + _plot $1 # Set TOMB{PATH,DIR,FILE,NAME} + + mount -l | grep "${TOMBFILE}.*\[$TOMBNAME\]$" > /dev/null { test $? = 0 } && { - _warning "Tomb is currently in use: ::1 tomb name::" $tombname; return 1 } - _message "Valid tomb file found: ::1 tomb file::" $1 + _warning "Tomb is currently in use: ::1 tomb name::" $TOMBNAME; return 1 } + _message "Valid tomb file found: ::1 tomb path::" $TOMBPATH return 0 } @@ -375,7 +410,8 @@ lo_preserve() { # eventually used for debugging dump_secrets() { - _verbose "tomb_file: ::1 tomb file::" $tomb_file + _verbose "TOMBFILE: ::1 tomb file::" $TOMBPATH + _verbose "TOMBFILE: ::1 tomb file::" $TOMBFILE _verbose "tomb_key: ::1 key:: chars long" ${#tomb_key} _verbose "tomb_key_file: ::1 key::" $tomb_key_file _verbose "tomb_secret: ::1 secret:: chars long" ${#tomb_secret} @@ -1122,7 +1158,7 @@ engrave_key() { # {{{ Create -# This is a new way to create tombs which dissects the whole create_tomb() into 3 clear steps: +# Since version 1.5.3, tomb creation is a three-step process that replaces create_tomb(): # # * dig a .tomb (the large file) using /dev/urandom (takes some minutes at least) # @@ -1130,6 +1166,64 @@ engrave_key() { # # * lock the .tomb file with the key, binding the key to the tomb (requires dm_crypt format) +# Step one - Dig a tomb +# +# Synopsis: dig_tomb /path/to/tomb -s sizemegabytes +# +# It will create an empty file to be formatted as a loopback +# filesystem. Initially the file is filled with random data taken +# from /dev/urandom to improve overall tomb's security and prevent +# some attacks aiming at detecting how much data is in the tomb, or +# which blocks in the filesystem contain that data. + +dig_tomb() { + local tombpath="$1" # Path to tomb + # Require the specification of the size of the tomb (-s) in MB + local -i tombsize=$(option_value -s) + + _message "Commanded to dig tomb ::1 tomb path::" $tombpath + + [[ -n "$tombpath" ]] || _failure "Missing path to tomb" + [[ -n "$tombsize" ]] || _failure "Size argument missing, use -s" + [[ $tombsize == <-> ]] || _failure "Size must be an integer (megabytes)" + [[ $tombsize -ge 10 ]] || _failure "Tombs can't be smaller than 10 megabytes" + + _check_swap # Ensure the available memory is safe to use + _plot $tombpath # Set TOMB{PATH,DIR,FILE,NAME} + + [[ -e $TOMBPATH ]] && { + _warning "A tomb exists already. I'm not digging here:" + _warning " $(ls -lh $TOMBPATH)" + return 1 + } + + _success "Creating a new tomb in ::1 tomb path::" $TOMBPATH + + _message "Generating ::1 tomb file:: of ::2 size::MiB" $TOMBFILE $tombsize + + # Ensure that file permissions are safe even if interrupted + touch $TOMBPATH + chmod 0600 $TOMBPATH + chown $_UID:$_GID $TOMBPATH + + _verbose "Data dump using ::1:: from /dev/urandom" ${DD[1]} + ${=DD} if=/dev/urandom bs=1048576 count=$tombsize of=$TOMBPATH + + [[ $? == 0 && -e $TOMBPATH ]] && { + _message " $(ls -lh $TOMBPATH)" + } || { + _warning "Error creating the tomb ::1 tomb path::" $TOMBPATH + _failure "Operation aborted." + } + + _success "Done digging ::1 tomb name::" $TOMBNAME + _message "Your tomb is not yet ready, you need to forge a key and lock it:" + _message "tomb forge ::1 tomb path::.key" $TOMBPATH + _message "tomb lock ::1 tomb path:: -k ::1 tomb path::.key" $TOMBPATH + + return 0 +} + forge_key() { # can be specified both as simple argument or using -k @@ -1213,88 +1307,34 @@ forge_key() { ls -lh ${tomb_key_file} } -# Dig a tomb, means that it will create an empty file to be formatted -# as a loopback filesystem. Initially the file is filled with random data -# taken from /dev/urandom which improves the tomb's overall security -dig_tomb() { - _message "Commanded to dig tomb ::1 tomb name::" $1 - if [ "$1" = "" ]; then - _warning "No tomb name specified for creation." - return 1 - fi +# Step three -- Lock tomb +# +# Synopsis: tomb_lock file.tomb file.tomb.key +# +# Lock the given tomb with the given key file, in fact formatting the +# loopback volume as a LUKS device. it take arguments as the LUKS +# cipher to be used - _check_swap - - tombfile=`basename $1` - tombdir=`dirname $1` - # make sure the file has a .tomb extension - tombname=${tombfile%%\.*} - tombfile=${tombname}.tomb - - # require the specification of the size of the tomb (-s) in MB - tombsize="`option_value -s`" - - [ $tombsize ] || _failure "Size argument missing, use -s" - - [[ $tombsize != <-> ]] && _failure "Size argument is not an integer." - - [[ $tombsize -lt 10 ]] && _failure "Tombs can't be smaller than 10 megabytes." - - if [ -e ${tombdir}/${tombfile} ]; then - _warning "A tomb exists already. I'm not digging here:" - _warning " `ls -lh ${tombdir}/${tombfile}`" - return 1 - fi - - _success "Creating a new tomb in ::1 tomb dir::/::2 tomb file::" $tombdir $tombfile - - _message "Generating ::1 tomb file:: of ::2 size::MiB" $tombfile $tombsize - # we will first touch the file and set permissions: this way, even if interrupted, permissions are right - touch ${tombdir}/${tombfile} - chmod 0600 "${tombdir}/${tombfile}" - chown $_UID:$_GID "${tombdir}/${tombfile}" - - _verbose "Data dump using ::1:: from /dev/urandom" ${DD[1]} - - ${=DD} if=/dev/urandom bs=1048576 count=${tombsize} of=${tombdir}/${tombfile} - - if [ $? = 0 -a -e ${tombdir}/${tombfile} ]; then - _message " `ls -lh ${tombdir}/${tombfile}`" - else - _failure "Error creating the tomb ::1 tomb dir::/::2 tomb file::, operation aborted." $tombdir $tombfile - fi - - _success "Done digging ::1 tomb name::" $tombname - _message "Your tomb is not yet ready, you need to forge a key and lock it:" - _message "tomb forge ::1 tomb name::.tomb.key" $tombname - _message "tomb lock ::1 tomb name::.tomb -k ::1 tomb name::.tomb.key" $tombname -} - - -# this function locks a tomb with a key file -# in fact LUKS formatting the loopback volume -# it take arguments as the LUKS cipher to be used lock_tomb_with_key() { - if ! [ $1 ]; then + local tombpath="$1" # First argument is the path to the tomb + local tombkey="$2" # Second argument is the path to the key file + + [[ -n $tombpath ]] || { _warning "No tomb specified for locking." _warning "Usage: tomb lock file.tomb file.tomb.key" return 1 - fi + } - tombpath="$1" - tombdir=`dirname "$tombpath"` - tombfile=`basename "$tombpath"` - tombname="${tombfile%%\.*}" + _plot $tombpath - _message "Commanded to lock tomb ::1 tomb file::" $tombfile + _message "Commanded to lock tomb ::1 tomb file::" $TOMBFILE - { test -f ${tombdir}/${tombfile} } || { - _failure "There is no tomb here. You have to it dig first." - return 1 } + [[ -f $TOMBPATH ]] || { + _failure "There is no tomb here. You have to it dig first." } - _verbose "Tomb found: ::1 tomb dir::/::2 tomb file::" $tombdir $tombfile + _verbose "Tomb found: ::1 tomb path::" $TOMBPATH - lo_mount "${tombdir}/${tombfile}" + lo_mount $TOMBPATH nstloop=`lo_new` _verbose "Loop mounted on ::1 mount point::" $nstloop @@ -1337,7 +1377,7 @@ lock_tomb_with_key() { { test $? = 0 } || { _failure "No valid password supplied." } - _success "Locking ::1 tomb file:: with ::2 tomb key::" $tombfile $tomb_key_file + _success "Locking ::1 tomb file:: with ::2 tomb key::" $TOMBFILE $tomb_key_file _message "Formatting Luks mapped device." print -n - "$tomb_secret" | \ @@ -1358,56 +1398,61 @@ lock_tomb_with_key() { fi _message "Formatting your Tomb with Ext3/Ext4 filesystem." - ${=MKFS} ${tombname} /dev/mapper/tomb.tmp + ${=MKFS} $TOMBNAME /dev/mapper/tomb.tmp if [ $? != 0 ]; then _warning "Tomb format returned an error." - _warning "Your tomb ::1 tomb file:: may be corrupted." $tombfile + _warning "Your tomb ::1 tomb file:: may be corrupted." $TOMBFILE fi # sync cryptsetup luksClose tomb.tmp - _message "Done locking ::1 tomb name:: using Luks dm-crypt ::2 cipher::" $tombname $cipher - _success "Your tomb is ready in ::1 tomb dir::/::2 tomb file:: and secured with key ::3 tomb key::" $tombdir $tombfile $tomb_key_file + _message "Done locking ::1 tomb name:: using Luks dm-crypt ::2 cipher::" $TOMBNAME $cipher + _success "Your tomb is ready in ::1 tomb path:: and secured with key ::3 tomb key::" \ + $TOMBPATH $tomb_key_file } # This function changes the key that locks a tomb change_tomb_key() { - _message "Commanded to reset key for tomb ::1 tomb name::" $2 + local tombkey="$1" # Path to the tomb's key file + local tombpath="$2" # Path to the tomb - _check_swap + _message "Commanded to reset key for tomb ::1 tomb path::" $tombpath - [[ "$2" = "" ]] && { + [[ -z "$tombpath" ]] && { _warning "Command 'setkey' needs two arguments: the old key file and the tomb." _warning "I.e: tomb -k new.tomb.key old.tomb.key secret.tomb" _failure "Execution aborted." } - lo_mount "$2" + _check_swap + _plot $tombpath + + lo_mount $TOMBPATH nstloop=`lo_new` cryptsetup isLuks ${nstloop} # is it a LUKS encrypted nest? we check one more time { test $? = 0 } || { - _failure "Not a valid LUKS encrypted volume: ::1 volume::" $2 } + _failure "Not a valid LUKS encrypted volume: ::1 volume::" $TOMBPATH } - load_key "$1" + load_key $tombkey { test $? = 0 } || { _failure "Aborting operations: error loading old key from arguments" } old_key="$tomb_key" old_key_file="$tomb_key_file" # we have everything, prepare to mount - _success "Changing lock on tomb ::1 tomb name::" $tombname + _success "Changing lock on tomb ::1 tomb name::" $TOMBNAME _message "Old key: ::1 old key::" $old_key # render the mapper mapdate=`date +%s` # save date of mount in minutes since 1970 - mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`" + mapper="tomb.$TOMBNAME.$mapdate.$(basename $nstloop)" # load the old key if option_is_set --tomb-old-pwd; then @@ -1461,7 +1506,7 @@ change_tomb_key() { { test $? = 0 } || { _failure "Unexpected error in luksClose." } - _success "Succesfully changed key for tomb: ::1 tomb file::" $2 + _success "Succesfully changed key for tomb: ::1 tomb file::" $TOMBFILE _message "The new key is: ::1 new key::" $new_key unset new_key @@ -1470,6 +1515,7 @@ change_tomb_key() { } # backward compatibility +# TODO DEPRECATED remove in 2.0 create_tomb() { _verbose "create_tomb(): ::1:: ::2::" ${=@} ${=OLDARGS} [[ "$1" = "" ]] && { @@ -1504,28 +1550,22 @@ create_tomb() { # $1 = tombfile $2(optional) = mountpoint mount_tomb() { + local tombpath="$1" # First argument is the path to the tomb + [[ -n "$tombpath" ]] || _failure "No tomb name specified for opening." + _message "Commanded to open tomb ::1 tomb name::" $1 - if [ "$1" = "" ]; then - _warning "No tomb name specified for opening." - return 1 - fi _check_swap + _plot $tombpath - # set up variables to be used - # the full path is made with $tombdir/$tombfile - - tombfile=`basename ${1}` - tombdir=`dirname ${1}` # check file type (if its a Luks fs) - file ${tombdir}/${tombfile} | \ - grep -i 'luks encrypted file' 2>&1 > /dev/null - if [ $? != 0 ]; then - _warning "::1 tomb file:: is not a valid tomb file, operation aborted." $1 - return 1 - fi - tombname=${tombfile%%\.*} - _verbose "Tomb found: ::1 tomb dir::/::2 tomb file::" $tombdir $tombfile + file $TOMBPATH | grep -i 'luks encrypted file' 2>&1 > /dev/null + [[ $? == 0 ]] || { + _warning "::1 tomb file:: is not a valid tomb file" $TOMBFILE + _failure "Operation aborted." + } + + _verbose "Tomb found: ::1 tomb path::" $TOMBPATH # load_key called here load_key @@ -1535,7 +1575,7 @@ mount_tomb() { _failure "Aborting operations: error loading key ::1 key::" $tombkey } if [ "$2" = "" ]; then - tombmount=/media/${tombfile} + tombmount=/media/$TOMBFILE _message "Mountpoint not specified, using default: ::1 mount point::" $tombmount else tombmount=$2 @@ -1544,21 +1584,21 @@ mount_tomb() { # check if its already open mount -l | grep "${tombfile}.*\[$tombname\]$" 2>&1 > /dev/null if [ $? = 0 ]; then - _warning "::1 tomb name:: is already open." $tombname + _warning "::1 tomb name:: is already open." $TOMBNAME _message "Here below its status is reported:" - list_tombs ${tombname} + list_tombs $TOMBNAME return 0 fi - _success "Opening ::1 tomb file:: on ::2 mount point::" $tombfile $tombmount + _success "Opening ::1 tomb file:: on ::2 mount point::" $TOMBFILE $tombmount - lo_mount "${tombdir}/${tombfile}" + lo_mount $TOMBPATH nstloop=`lo_new` cryptsetup isLuks ${nstloop} if [ $? != 0 ]; then # is it a LUKS encrypted nest? see cryptsetup(1) - _warning "::1 tomb file:: is not a valid Luks encrypted storage file." $tombfile + _warning "::1 tomb file:: is not a valid Luks encrypted storage file." $TOMBFILE return 1 fi _message "This tomb is a valid LUKS encrypted device." @@ -1585,7 +1625,7 @@ mount_tomb() { _verbose "Tomb key: ::1 key::" $tomb_key_file # take the name only, strip extensions - _verbose "Tomb name: ::1 tomb name:: (to be engraved)" $tombname + _verbose "Tomb name: ::1 tomb name:: (to be engraved)" $TOMBNAME if option_is_set --tomb-pwd; then tomb_pwd="`option_value --tomb-pwd`" @@ -1612,13 +1652,13 @@ mount_tomb() { /cipher:/ {print $2} /keysize:/ {print $2} /device:/ {print $2}'`) - _success "Success unlocking tomb ::1 tomb name::" $tombname + _success "Success unlocking tomb ::1 tomb name::" $TOMBNAME _verbose "Key size is ::1 size:: for cipher ::2 cipher::" $tombstat[2] $tombstat[1] _message "Checking filesystem via ::1::" $tombstat[3] fsck -p -C0 /dev/mapper/${mapper} - _verbose "Tomb engraved as ::1 tomb name::" $tombname - tune2fs -L ${tombname} /dev/mapper/${mapper} > /dev/null + _verbose "Tomb engraved as ::1 tomb name::" $TOMBNAME + tune2fs -L $TOMBNAME /dev/mapper/${mapper} > /dev/null # we need root from here on mkdir -p $tombmount @@ -1628,7 +1668,7 @@ mount_tomb() { chown $_UID:$_GID ${tombmount} chmod 0711 ${tombmount} - _success "Success opening ::1 tomb file:: on ::2 mount point::" $tombfile $tombmount + _success "Success opening ::1 tomb file:: on ::2 mount point::" $TOMBFILE $tombmount # print out when was opened the last time, by whom and where { test -r ${tombmount}/.last } && { @@ -2063,37 +2103,33 @@ search_tombs() { # resize tomb file size resize_tomb() { + local tombpath="$1" # First argument is the path to the tomb + _message "Commanded to resize tomb ::1 tomb name:: to ::2 size:: megabytes." $1 $OPTS[-s] - if ! [ $1 ]; then - _failure "No tomb name specified for resizing." - elif ! [ -r "$1" ]; then - _failure "Cannot find ::1::" $1 - fi - # $1 is the tomb file path + + [[ -z "$tombpath" ]] && _failure "No tomb name specified for resizing." + [[ ! -r $tombpath ]] && _failure "Cannot find ::1::" $tombpath newtombsize="`option_value -s`" { test "$newtombsize" = "" } && { _failure "Aborting operations: new size was not specified, use -s" } - - tombdir=`dirname $1` - tombfile=`basename $1` - tombname=${tombfile%%\.*} + _plot $tombpath # Set TOMB{PATH,DIR,FILE,NAME} # load key from options or file load_key ######## - local oldtombsize=$(( `stat -c %s "$1" 2>/dev/null` / 1048576 )) + local oldtombsize=$(( `stat -c %s "$TOMBPATH" 2>/dev/null` / 1048576 )) local mounted_tomb=`mount -l | - awk -vtomb="[$tombname]" '/^\/dev\/mapper\/tomb/ { if($7==tomb) print $1 }'` + awk -vtomb="[$TOMBNAME]" '/^\/dev\/mapper\/tomb/ { if($7==tomb) print $1 }'` if [ "$mounted_tomb" ]; then - _failure "The tomb ::1 tomb name:: is open, to resize it it needs to be closed." $tombname + _failure "Please close the tomb ::1 tomb name:: before trying to resize it." $TOMBNAME fi if ! [ "$newtombsize" ] ; then - _failure "You must specify the new size of ::1 tomb name::" $tombname + _failure "You must specify the new size of ::1 tomb name::" $TOMBNAME elif [[ $newtombsize != <-> ]]; then _failure "Size is not an integer." elif [ "$newtombsize" -le "$oldtombsize" ]; then @@ -2102,10 +2138,10 @@ resize_tomb() { delta="$(( $newtombsize - $oldtombsize ))" - _message "Generating ::1 tomb file:: of ::2 size::MiB" $tombfile $newtombsize + _message "Generating ::1 tomb file:: of ::2 size::MiB" $TOMBFILE $newtombsize _verbose "Data dump using ::1:: from /dev/urandom" ${DD[1]} - ${=DD} if=/dev/urandom bs=1048576 count=${delta} >> ${tombdir}/${tombfile} + ${=DD} if=/dev/urandom bs=1048576 count=${delta} >> $TOMBPATH { test $? = 0 } || { _failure "Error creating the extra resize ::1 size::, operation aborted." $tmp_resize }