chiark / gitweb /
Directory claiming and ephemeral filesystems.
[distorted-keys] / mount-ephemeral
diff --git a/mount-ephemeral b/mount-ephemeral
new file mode 100755 (executable)
index 0000000..3641e2a
--- /dev/null
@@ -0,0 +1,196 @@
+#! /bin/sh
+###
+### Mount an ephemeral filesystem
+###
+### (c) 2012 Mark Wooding
+###
+
+###----- Licensing notice ---------------------------------------------------
+###
+### This file is part of the distorted.org.uk key management suite.
+###
+### distorted-keys is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License as published by
+### the Free Software Foundation; either version 2 of the License, or
+### (at your option) any later version.
+###
+### distorted-keys is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with distorted-keys; if not, write to the Free Software Foundation,
+### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+set -e
+
+QUIS=${0##*/}
+VERSION=1.0.0
+USAGE="usage: $QUIS [-u] [-R RANDOM] [-n BYTES] [-C CIPHER] [-H HASH]
+       [-l LABEL] [-t FSTYPE] [-b BACKING-FILE] MOUNTPOINT [SIZE]"
+
+###--------------------------------------------------------------------------
+### Parse the command line.
+
+## Set initial defaults.
+mode=mount
+cipher=aes-xts-plain
+hash=sha256
+random=/dev/random
+randbytes=512
+fail=nil
+backing=/tmp
+unset label
+
+## Report version number.
+version () { echo "$QUIS, version $VERSION"; }
+
+## Report help text.
+help () {
+  version
+  cat <<EOF
+$USAGE
+
+Options:
+  -h           Show this help text.
+  -v           Show the program's version number.
+  -C CIPHER    Cipher to use to encrypt the filesystem [$cipher].
+  -H HASH      Hash function for hashing the random data [$hash].
+  -R RANDOM    Source of random bytes for key material [$random].
+  -b BACKING   Where to store the ciphertext [$backing].
+  -l LABEL     Device mapper label [basename of MOUNTPOINT].
+  -n RANDBYTES Number of random bytes to read for the key [$randbytes].
+  -u           Unmount the filesystem, destroying all data in it.
+EOF
+}
+
+## Loop over the options.
+while getopts "C:H:R:b:hl:n:t:uv" opt; do
+  case $opt in
+    h) help; exit 0 ;;
+    v) echo "$VERSION"; exit 0 ;;
+    C) cipher=$OPTARG ;;
+    H) hash=$OPTARG ;;
+    R) random=$OPTARG ;;
+    n) randbytes=$OPTARG ;;
+    b) backing=$OPTARG ;;
+    l) label=$OPTARG ;;
+    u) mode=umount ;;
+    *) fail=t ;;
+  esac
+done
+shift $(( $OPTIND - 1 ))
+case $fail,$mode,$# in
+  nil,mount,2) mntpt=$1 size=$2 ;;
+  nil,umount,1) mntpt=$1 ;;
+  *) echo >&2 "$USAGE"; exit 1 ;;
+esac
+
+## Default omitted arguments.
+case "${label+t}" in t) ;; *) label=${mntpt##*/} ;; esac
+
+###--------------------------------------------------------------------------
+### Do the job.
+
+case $mode in
+
+  mount)
+    ## Mount the filesystem.
+
+    ## Determine a name for the backing file.  If BACKING is a directory then
+    ## we should make a file there and delete it once we've created a
+    ## mapping.  The directory may be a shared bit of filesystem, so we must
+    ## be very careful.
+    rmbacking=nil
+    if [ -d "$backing" ]; then
+      i=0
+      while :; do
+       gorp=$(openssl rand -base64 6)
+       bkdir=$backing/mnteph.$$.$gorp
+       if mkdir >/dev/null 2>&1 -m700 "$bkdir"; then break; fi
+       i=$(( $i + 1 ))
+       if [ $i -ge 100 ]; then
+         echo >&2 "$QUIS: failed to create backing directory"
+         exit 1
+       fi
+      done
+      backing=$bkdir/fs
+      trap 'rc=$?; rm "$backing"; rmdir "$bkdir"; exit $rc' EXIT
+      trap 'exit 127' INT TERM
+      rmbacking=t
+    fi
+
+    ## Create the backing file.
+    truncate -s"$size" "$backing"
+    loop=$(losetup -f --show "$backing")
+
+    ## Attach a device-mapper entry to the file.
+    dd 2>/dev/null if="$random" bs=1 count="$randbytes" |
+    cryptsetup \
+      --cipher="$cipher" --hash="$hash" \
+      --key-file=- \
+      create "$label" "$loop"
+
+    ## Create the filesystem.
+    if spew=$(mkfs 2>&1 "/dev/mapper/$label"); then
+      :
+    else
+      rc=$?
+      echo >&2 "$QUIS: mkfs failed (rc = $rc)"
+      echo "$spew" | sed >&2 's/^/| /'
+      exit $rc
+    fi
+
+    ## Mount.
+    mount "/dev/mapper/$label" "$mntpt"
+    ;;
+
+  umount)
+    ## Unmount a filesystem.
+
+    ## Find the numbers of the loopback device.
+    deps=$(dmsetup deps "/dev/mapper/$label")
+    set -- $(echo "$deps" |
+      sed 's!^.*:.*(\([0-9]\+\),[[:space:]]*\([0-9]\+\)).*$!\1 \2!')
+    case "$#" in
+      2) ;;
+      *)
+       echo >&2 "$QUIS: unexpected answer from \`dmsetup deps'"
+       echo "$deps" | sed >&2 's/^/| /'
+       exit 1
+       ;;
+    esac
+    maj=$1 min=$2
+
+    ## Convert that into a name.
+    dev=$(readlink /sys/dev/block/$maj:$min)
+    dev=${dev##*/}
+    case "$dev" in
+      loop*) ;;
+      *)
+       echo >&2 "$QUIS: expected a loopback device; found \`$dev'"
+       exit 1
+       ;;
+    esac
+
+    ## Unmount the filesystem.
+    umount "$mntpt"
+
+    ## Remove the cryptoloop mapping.
+    if spew=$(cryptsetup 2>&1 remove "$label"); then
+      :
+    else
+      rc=$?
+      echo >&2 "$QUIS: cryptsetup failed (rc = $rc)"
+      echo "$spew" | sed >&2 's/^/| /'
+      exit $rc
+    fi
+
+    ## Disconnect the loopback device.
+    losetup -d "/dev/$dev"
+    ;;
+
+esac
+
+###----- That's all, folks --------------------------------------------------