diff --git a/INSTALL.md b/INSTALL.md index 996ada3..e25e7a0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -66,6 +66,7 @@ Tomb can use some optional tools to extend its functionalities: executable | function ---------- | --------------------------------------------------- + lsof | slam a tomb (close even if open programs) dcfldd | show progress while digging tombs and keys steghide | bury and exhume keys inside images resizefs | extend the size of existing tomb volumes diff --git a/doc/tomb.1 b/doc/tomb.1 index 0e91112..f04dfa3 100644 --- a/doc/tomb.1 +++ b/doc/tomb.1 @@ -1,4 +1,4 @@ -.TH tomb 1 "November 26, 2014" "tomb" +.TH tomb 1 "February 05, 2017" "tomb" .SH NAME Tomb \- the Crypto Undertaker @@ -114,9 +114,9 @@ the tomb is in use by running processes (to force close, see .IP "slam" Closes a tomb like the command \fIclose\fR does, but it doesn't fail even if the tomb is in use by other application processes: it looks -for and violently kills \-9 each of them. This command may +for and closes each of them (in order: TERM, HUP, KILL). This command may provoke unsaved data loss, but assists users to face surprise -situations. +situations. It requires \fIlsof\fR else it falls back to \fIclose\fR. .B diff --git a/doc/tomb_manpage.pdf b/doc/tomb_manpage.pdf index 55aa72d..d2bcad2 100644 Binary files a/doc/tomb_manpage.pdf and b/doc/tomb_manpage.pdf differ diff --git a/extras/test/runtests b/extras/test/runtests index 4847f45..6560358 100755 --- a/extras/test/runtests +++ b/extras/test/runtests @@ -56,9 +56,11 @@ command -v qrencode > /dev/null || QRENCODE=0 typeset -A results + tests=(dig forge lock badpass open close passwd chksum bind setkey recip-dig -recip-forge recip-lock recip-open recip-close recip-passwd recip-resize -recip-setkey shared shared-passwd shared-setkey) + recip-forge recip-lock recip-open recip-close recip-passwd recip-resize + recip-setkey shared shared-passwd shared-setkey) + { test $RESIZER = 1 } && { tests+=(resize) } { test $KDF = 1 } && { tests+=(kdforge kdfpass kdflock kdfopen) } { test $STEGHIDE = 1 } && { tests+=(stgin stgout stgopen stgpipe stgimpl @@ -322,7 +324,32 @@ test-regression() { } +test-open-read-only() { + notice "wiping all testro.tomb* in /tmp" + sudo rm -f /tmp/testro.tomb{,.key,.new.key} + + # Create new + tt dig -s 20 /tmp/testro.tomb + tt forge /tmp/testro.tomb.key \ + --ignore-swap --unsafe --tomb-pwd ${dummypass} --use-urandom + tt lock /tmp/testro.tomb -k /tmp/testro.tomb.key \ + --ignore-swap --unsafe --tomb-pwd ${dummypass} + + notice "Testing open read only" + + # Remove write privilege on test.tomb + chmod -w /tmp/testro.tomb + + # Attempt to open the unwritable tomb with the read-only mount option + tt open /tmp/testro.tomb -k /tmp/testro.tomb.key \ + --ignore-swap --unsafe --tomb-pwd ${dummypass} -o ro,noatime,nodev + + { test $? = 0 } && { + results+=(openro SUCCESS) + tt close testro + } +} startloops=(`sudo losetup -a |cut -d: -f1`) @@ -357,8 +384,8 @@ tt close test { test $? = 0 } && { results+=(close SUCCESS) } - - +# isolated function +test-open-read-only notice "Testing changing tomb password" diff --git a/tomb b/tomb index 8f171d5..5f34d11 100755 --- a/tomb +++ b/tomb @@ -242,9 +242,9 @@ _plot() { TOMBFILE=$(basename $TOMBPATH) - # The tomb name is TOMBFILE without an extension. - # It can start with dots: ..foo.tomb -> ..foo - TOMBNAME="${TOMBFILE%\.[^\.]*}" + # The tomb name is TOMBFILE without an extension and underscores instead of spaces (for mount and cryptsetup) + # It can start with dots: ..foo bar baz.tomb -> ..foo_bar_baz + TOMBNAME=${${TOMBFILE// /_}%.*} [[ -z $TOMBNAME ]] && { _failure "Tomb won't work without a TOMBNAME." } @@ -507,7 +507,8 @@ is_valid_tomb() { _fail=0 # Tomb file must be a readable, writable, non-empty regular file. - [[ ! -w "$1" ]] && { + # If passed the "ro" mount option, the writable check is skipped. + [[ ! -w "$1" ]] && [[ $(option_value -o) != *"ro"* ]] && { _warning "Tomb file is not writable: ::1 tomb file::" $1 _fail=1 } @@ -812,6 +813,8 @@ _ensure_dependencies() { # Which wipe command to use command -v wipe 1>/dev/null 2>/dev/null && WIPE=(wipe -f -s) + # Check for lsof for slamming tombs + command -v lsof 1>/dev/null 2>/dev/null || LSOF=0 # Check for steghide command -v steghide 1>/dev/null 2>/dev/null || STEGHIDE=0 # Check for resize @@ -1159,7 +1162,7 @@ ask_key_password() { # call cryptsetup with arguments using the currently known secret # echo flags eliminate newline and disable escape (BSD_ECHO) _cryptsetup() { - print -R -n - "$TOMBSECRET" | _sudo cryptsetup --key-file - ${=@} + print -R -n - "$TOMBSECRET" | _sudo cryptsetup --key-file - ${@} return $? } @@ -2488,7 +2491,7 @@ search_tombs() { # Use swish-e to search over contents [[ $SWISH == 1 && -r $tombmount/.swish ]] && { _message "Searching contents in tomb ::1 tomb name::" $tombname - swish-e -w ${=@} -f $tombmount/.swish -H0 } + swish-e -w ${@} -f $tombmount/.swish -H0 } } || { _warning "Skipping tomb ::1 tomb name::: not indexed." $tombname _warning "Run 'tomb index' to create indexes." } @@ -2690,20 +2693,20 @@ umount_tomb() { # Kill all processes using the tomb slam_tomb() { # $1 = tomb mount point - if [[ -z `fuser -m "$1" 2>/dev/null` ]]; then + if [[ -z `lsof -t +D "$1" 2>/dev/null` ]]; then return 0 fi #Note: shells are NOT killed by INT or TERM, but they are killed by HUP for s in TERM HUP KILL; do _verbose "Sending ::1:: to processes inside the tomb:" $s if option_is_set -D; then - ps -fp `fuser -m /media/a.tomb 2>/dev/null`| + ps -fp `lsof -t +D "$1" 2>/dev/null`| while read line; do _verbose $line done fi - fuser -s -m "$1" -k -M -$s - if [[ -z `fuser -m "$1" 2>/dev/null` ]]; then + kill -$s `lsof -t +D "$1"` + if [[ -z `lsof -t +D "$1" 2>/dev/null` ]]; then return 0 fi if ! option_is_set -f; then @@ -2893,28 +2896,33 @@ main() { # CREATE Step 1: dig -s NN file.tomb dig) - dig_tomb ${=PARAM} + dig_tomb $PARAM ;; # CREATE Step 2: forge file.tomb.key forge) - forge_key ${=PARAM} + forge_key $PARAM ;; # CREATE Step 2: lock -k file.tomb.key file.tomb lock) - lock_tomb_with_key ${=PARAM} + lock_tomb_with_key $PARAM ;; # Open the tomb mount|open) - mount_tomb ${=PARAM} + mount_tomb $PARAM ;; # Close the tomb # `slam` is used to force closing. umount|close|slam) - [[ "$subcommand" == "slam" ]] && SLAM=1 + [[ "$subcommand" == "slam" ]] && { + SLAM=1 + [[ $LSOF == 0 ]] && { + unset SLAM + _warning "lsof not installed: cannot slam tombs." + _warning "Trying a regular close." }} umount_tomb $PARAM[1] ;; @@ -2939,7 +2947,7 @@ main() { # Search tomb contents search) - search_tombs ${=PARAM} + search_tombs $PARAM ;; ## Locking operations @@ -2948,7 +2956,7 @@ main() { engrave) [[ $QRENCODE == 0 ]] && { _failure "QREncode not installed: cannot engrave keys on paper." } - engrave_key ${=PARAM} + engrave_key $PARAM ;; # Change password on existing key @@ -2958,7 +2966,7 @@ main() { # Change tomb key setkey) - change_tomb_key ${=PARAM} + change_tomb_key $PARAM ;; # STEGANOGRAPHY: hide key inside an image