From 33aa94e8966d10478a2087a1c9dd445e92673933 Mon Sep 17 00:00:00 2001 Message-Id: <33aa94e8966d10478a2087a1c9dd445e92673933.1714851914.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sun, 12 Feb 2012 23:14:36 +0000 Subject: [PATCH] Directory claiming and ephemeral filesystems. Organization: Straylight/Edgeware From: Mark Wooding Two new related tools. * `mount-ephemeral' creates (and removes) a temporary filesystem, encrypted using a fresh random key so the contents are irretrievably lost when the host reboots or the power fails. * `claim-dir' is a `userv' service which allows users to claim directories in a shared filesystem without the hazardous free-for-all that results from world writability with a sticky bit. These go in their own separate Debian package. There's no direct link between the two, but bundling them together provides a hint regarding possible applications. --- Makefile.am | 24 ++++- claim-dir.tab | 21 ++++ debian/.gitignore | 2 + debian/claim-dir.install | 4 + debian/control | 20 ++++ debian/distorted-keys.install | 5 + mount-ephemeral | 196 ++++++++++++++++++++++++++++++++++ userv/claim-dir.in | 82 ++++++++++++++ 8 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 claim-dir.tab create mode 100644 debian/claim-dir.install create mode 100755 mount-ephemeral create mode 100644 userv/claim-dir.in diff --git a/Makefile.am b/Makefile.am index a356ec1..886e012 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,7 +49,7 @@ SUBSTVARS = \ PACKAGE="$(PACKAGE)" VERSION="$(VERSION)" \ PYTHON="$(PYTHON)" \ bindir="$(bindir)" sbindir="$(sbindir)" \ - pkgconfdir="$(pkgconfdir)" \ + sysconfdir="$(sysconfdir)" pkgconfdir="$(pkgconfdir)" \ pkgstatedir="$(localstatedir)/lib/$(PACKAGE)" \ pkglibdir="$(pkglibdir)" \ user="$(user)" @@ -153,6 +153,26 @@ userv/distorted-keys: userv/distorted-keys.in Makefile >userv/distorted-keys.new && \ mv userv/distorted-keys.new userv/distorted-keys +###-------------------------------------------------------------------------- +### Secure storage management. + +## Ephemeral filesystem construction. +sbin_SCRIPTS += mount-ephemeral +EXTRA_DIST += mount-ephemeral + +## Directory claiming service. +noinst_DATA += userv/claim-dir +EXTRA_DIST += userv/claim-dir.in +CLEANFILES += userv/claim-dir +userv/claim-dir: userv/claim-dir.in Makefile + $(AM_V_at)mkdir -p userv/ + $(SUBST) $(srcdir)/userv/claim-dir.in $(SUBSTVARS) \ + >userv/claim-dir.new && \ + mv userv/claim-dir.new userv/claim-dir + +## Configuration file. +EXTRA_DIST += claim-dir.tab + ###-------------------------------------------------------------------------- ### Configuration snippets. @@ -176,6 +196,8 @@ EXTRA_DIST += debian/rules debian/compat EXTRA_DIST += debian/distorted-keys.install EXTRA_DIST += debian/distorted-keys.postinst +EXTRA_DIST += debian/claim-dir.install + EXTRA_DIST += debian/admin.users debian/admin.groups ###----- That's all, folks -------------------------------------------------- diff --git a/claim-dir.tab b/claim-dir.tab new file mode 100644 index 0000000..f5ba774 --- /dev/null +++ b/claim-dir.tab @@ -0,0 +1,21 @@ +### -*-conf-*- +### +### This file lists the available filesystems which may be claimed by users. +### Each line has the form +### +### FS DIR [OPT=VALUE ...] +### +### The FS is a simple name for the filesystem, matched against the FILSYS +### argument to `claim-dir'. The DIR is the directory name in which to +### create user directories. The remaining options are as follows. +### +### acl=[-]{USER|%GROUP},... +### Access control list for this filesystem. Entries prefixed with `-' +### forbid access, other entries permit; the entries are glob patterns +### matched against the user's name or groups. The first match wins; if +### no entry matches, access is forbidden. Without this option, access +### is open to all. +### +### mount=SCRIPT +### If DIR is not a mount point already, run SCRIPT DIR. + diff --git a/debian/.gitignore b/debian/.gitignore index 4d91172..ddf56e8 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -1,5 +1,7 @@ build distorted-keys +claim-dir +tmp *.log *.substvars files diff --git a/debian/claim-dir.install b/debian/claim-dir.install new file mode 100644 index 0000000..202f94b --- /dev/null +++ b/debian/claim-dir.install @@ -0,0 +1,4 @@ +usr/sbin/mount-ephemeral + +debian/build/userv/claim-dir /etc/userv/default.d +claim-dir.tab /etc diff --git a/debian/control b/debian/control index 1de815e..7040f1b 100644 --- a/debian/control +++ b/debian/control @@ -23,3 +23,23 @@ Description: Basic key-management system with secure recovery features. This system doesn't actually do very much cryptography itself. Instead, it uses other existing implementations, such as GnuPG, OpenSSL, and Seccure. + +Package: claim-dir +Architecture: all +Depends: userv +Recommends: cryptsetup, dmsetup +Description: Allow users to claim directories on file systems + Machines sometimes have storage devices with useful special properties -- + such as high performance, or secure erasure on power failure. Rather than + set the root of such a filesystem world-writable and sticky, thereby making + another filesystem as hard to use safely as `/tmp', `claim-dir' lets users + claim directories on such filesystems via `userv'. A newly claimed + directory is named after the calling user, and created readable and writable + only by the calling user -- so he or she can relax the permissions later if + necessary. + . + A script `mount-ephemeral' is included which allows the construction of an + ephemeral filesystem -- one which is backed by normal storage (typically in + `/tmp'), but encrypted using a temporary key which will be lost at reboot. + This script can be used to build a safe place for the storage of + temporary secrets. diff --git a/debian/distorted-keys.install b/debian/distorted-keys.install index 83b30ea..8d09989 100644 --- a/debian/distorted-keys.install +++ b/debian/distorted-keys.install @@ -1,3 +1,8 @@ +usr/bin +usr/sbin/keys +usr/lib/distorted-keys +etc/distorted-keys + debian/build/userv/distorted-keys /etc/userv/default.d debian/admin.users /etc/distorted-keys debian/admin.groups /etc/distorted-keys diff --git a/mount-ephemeral b/mount-ephemeral new file mode 100755 index 0000000..3641e2a --- /dev/null +++ b/mount-ephemeral @@ -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 <&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 -------------------------------------------------- diff --git a/userv/claim-dir.in b/userv/claim-dir.in new file mode 100644 index 0000000..4cc6032 --- /dev/null +++ b/userv/claim-dir.in @@ -0,0 +1,82 @@ +### -*-conf-*- +### +### userv service for claiming a directory in a special filesystem + +if ( glob service claim-dir + & glob service-user root + & grep calling-user-shell /etc/shells + ) + no-suppress-args + null-fd 0 + require-fd 1-2 write + ignore-fd 3- + no-set-environment + execute sh -c "set -e; quis=$0; \ + case $# in \ + 1) filsys=$1 ;; \ + *) echo >&2 \"usage: $quis FILSYS\"; exit 1 ;; \ + esac; \ + foundp=nil; \ + while read fs dir opts; do \ + case \"$fs\" in \ + \\#* | \"\") continue ;; \ + \"$filsys\") foundp=t; break ;; \ + esac; \ + done <@sysconfdir@/claim-dir.tab; \ + case $foundp in \ + nil) \ + echo >&2 \"$quis: unknown filesystem \\`$filsys'\"; \ + exit 1 \ + ;; \ + esac; \ + for opt in $opts; do \ + arg=${opt#*=}; \ + case \"$opt\" in \ + acl=*) \ + verdict=forbid acl=$arg; \ + while :; do \ + case \"$acl\" in ?*) ;; *) break ;; esac; \ + case \"$acl\" in \ + *,*) word=${acl%%,*} acl=${acl#*,} ;; \ + *) word=$acl acl=\"\" ;; \ + esac; \ + case \"$word\" in \ + -*) sense=forbid word=${word#-} ;; \ + *) sense=allow word=$word ;; \ + esac; \ + case \"$word\" in \ + %*) pat=${word#%} list=\"$USERV_GROUP $USERV_GID\" ;; \ + *) pat=$word list=\"$USERV_USER $USERV_UID\" ;; \ + esac; \ + matchp=nil; \ + for i in $list; do \ + case \"$i\" in $pat) matchp=t; break ;; esac; \ + done; \ + case $matchp in t) verdict=$sense; break ;; esac; \ + done; \ + case $verdict in \ + forbid) \ + echo >&2 \"$quis: permission denied\"; \ + exit 1 \ + ;; \ + esac \ + ;; \ + mount=*) \ + if ! mountpoint -q \"$dir\"; then $arg \"$dir\"; fi \ + ;; \ + *) \ + echo >&2 \"$quis: unknown option \\`$opt'\"; \ + exit 1 \ + ;; \ + esac; \ + done; \ + set _ $USERV_USER; user=$2; \ + set _ $USERV_GROUP; group=$2; \ + cd \"$dir\"; \ + if [ ! -d \"$user\" ]; then \ + mkdir -m700 \"$user\"; \ + chown \"$user:$group\" \"$user\"; \ + fi; \ + echo \"$dir/$USERV_USER\" \ + " claim-dir +fi -- [mdw]