chiark / gitweb /
cryptop.list: List other users' keys correctly.
[distorted-keys] / mount-ephemeral
1 #! /bin/sh
2 ###
3 ### Mount an ephemeral filesystem
4 ###
5 ### (c) 2012 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the distorted.org.uk key management suite.
11 ###
12 ### distorted-keys is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU General Public License as published by
14 ### the Free Software Foundation; either version 2 of the License, or
15 ### (at your option) any later version.
16 ###
17 ### distorted-keys is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ### GNU General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU General Public License
23 ### along with distorted-keys; if not, write to the Free Software Foundation,
24 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 set -e
27
28 QUIS=${0##*/}
29 VERSION=1.0.0
30 USAGE="usage: $QUIS [-u] [-R RANDOM] [-n BYTES] [-C CIPHER] [-H HASH]
31         [-l LABEL] [-t FSTYPE] [-b BACKING-FILE] MOUNTPOINT [SIZE]"
32
33 ###--------------------------------------------------------------------------
34 ### Parse the command line.
35
36 ## Set initial defaults.
37 mode=mount
38 cipher=aes-xts-plain
39 hash=sha256
40 random=/dev/random
41 randbytes=512
42 fail=nil
43 backing=/tmp
44 unset label
45
46 ## Report version number.
47 version () { echo "$QUIS, version $VERSION"; }
48
49 ## Report help text.
50 help () {
51   version
52   cat <<EOF
53 $USAGE
54
55 Options:
56   -h            Show this help text.
57   -v            Show the program's version number.
58   -C CIPHER     Cipher to use to encrypt the filesystem [$cipher].
59   -H HASH       Hash function for hashing the random data [$hash].
60   -R RANDOM     Source of random bytes for key material [$random].
61   -b BACKING    Where to store the ciphertext [$backing].
62   -l LABEL      Device mapper label [basename of MOUNTPOINT].
63   -n RANDBYTES  Number of random bytes to read for the key [$randbytes].
64   -u            Unmount the filesystem, destroying all data in it.
65 EOF
66 }
67
68 ## Loop over the options.
69 while getopts "C:H:R:b:hl:n:t:uv" opt; do
70   case $opt in
71     h) help; exit 0 ;;
72     v) echo "$VERSION"; exit 0 ;;
73     C) cipher=$OPTARG ;;
74     H) hash=$OPTARG ;;
75     R) random=$OPTARG ;;
76     n) randbytes=$OPTARG ;;
77     b) backing=$OPTARG ;;
78     l) label=$OPTARG ;;
79     u) mode=umount ;;
80     *) fail=t ;;
81   esac
82 done
83 shift $(( $OPTIND - 1 ))
84 case $fail,$mode,$# in
85   nil,mount,2) mntpt=$1 size=$2 ;;
86   nil,umount,1) mntpt=$1 ;;
87   *) echo >&2 "$USAGE"; exit 1 ;;
88 esac
89
90 ## Default omitted arguments.
91 case "${label+t}" in t) ;; *) label=${mntpt##*/} ;; esac
92
93 ###--------------------------------------------------------------------------
94 ### Do the job.
95
96 case $mode in
97
98   mount)
99     ## Mount the filesystem.
100
101     ## Determine a name for the backing file.  If BACKING is a directory then
102     ## we should make a file there and delete it once we've created a
103     ## mapping.  The directory may be a shared bit of filesystem, so we must
104     ## be very careful.
105     rmbacking=nil
106     if [ -d "$backing" ]; then
107       i=0
108       while :; do
109         gorp=$(openssl rand -base64 6)
110         bkdir=$backing/mnteph.$$.$gorp
111         if mkdir >/dev/null 2>&1 -m700 "$bkdir"; then break; fi
112         i=$(( $i + 1 ))
113         if [ $i -ge 100 ]; then
114           echo >&2 "$QUIS: failed to create backing directory"
115           exit 1
116         fi
117       done
118       backing=$bkdir/fs
119       trap 'rc=$?; rm "$backing"; rmdir "$bkdir"; exit $rc' EXIT
120       trap 'exit 127' INT TERM
121       rmbacking=t
122     fi
123
124     ## Create the backing file.
125     truncate -s"$size" "$backing"
126     loop=$(losetup -f --show "$backing")
127
128     ## Attach a device-mapper entry to the file.
129     dd 2>/dev/null if="$random" bs=1 count="$randbytes" |
130     cryptsetup \
131       --cipher="$cipher" --hash="$hash" \
132       --key-file=- \
133       create "$label" "$loop"
134
135     ## Create the filesystem.
136     if spew=$(mkfs 2>&1 "/dev/mapper/$label"); then
137       :
138     else
139       rc=$?
140       echo >&2 "$QUIS: mkfs failed (rc = $rc)"
141       echo "$spew" | sed >&2 's/^/| /'
142       exit $rc
143     fi
144
145     ## Mount.
146     mount "/dev/mapper/$label" "$mntpt"
147     ;;
148
149   umount)
150     ## Unmount a filesystem.
151
152     ## Find the numbers of the loopback device.
153     deps=$(dmsetup deps "/dev/mapper/$label")
154     set -- $(echo "$deps" |
155       sed 's!^.*:.*(\([0-9]\+\),[[:space:]]*\([0-9]\+\)).*$!\1 \2!')
156     case "$#" in
157       2) ;;
158       *)
159         echo >&2 "$QUIS: unexpected answer from \`dmsetup deps'"
160         echo "$deps" | sed >&2 's/^/| /'
161         exit 1
162         ;;
163     esac
164     maj=$1 min=$2
165
166     ## Convert that into a name.
167     dev=$(readlink /sys/dev/block/$maj:$min)
168     dev=${dev##*/}
169     case "$dev" in
170       loop*) ;;
171       *)
172         echo >&2 "$QUIS: expected a loopback device; found \`$dev'"
173         exit 1
174         ;;
175     esac
176
177     ## Unmount the filesystem.
178     umount "$mntpt"
179
180     ## Remove the cryptoloop mapping.
181     if spew=$(cryptsetup 2>&1 remove "$label"); then
182       :
183     else
184       rc=$?
185       echo >&2 "$QUIS: cryptsetup failed (rc = $rc)"
186       echo "$spew" | sed >&2 's/^/| /'
187       exit $rc
188     fi
189
190     ## Disconnect the loopback device.
191     losetup -d "/dev/$dev"
192     ;;
193
194 esac
195
196 ###----- That's all, folks --------------------------------------------------