diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | cryptfs.bin.in | 236 | ||||
-rw-r--r-- | cryptfs.in | 150 | ||||
-rw-r--r-- | cryptfs.rc.in | 33 | ||||
-rw-r--r-- | cryptfs.service.in | 13 |
6 files changed, 304 insertions, 159 deletions
@@ -1 +1,3 @@ -cryptfs +cryptfs.bin +cryptfs.rc +cryptfs.service @@ -20,26 +20,37 @@ # DESTDIR = -ETCDIR = /etc +BINDIR = /usr/bin DEVDIR = /dev +ETCDIR = /etc UUIDDIR = $(DEVDIR)/disk/by-uuid MAPDIR = $(DEVDIR)/mapper RCDDIR = $(ETCDIR)/rc.d +SYSTEMDDIR = /usr/lib/systemd/system +CONF_PREFIXES = -VERSION = 0.3 +VERSION = 0.4 -all: cryptfs +all: cryptfs.bin cryptfs.rc cryptfs.service %: %.in - sed "s/#VERSION#/$(VERSION)/; s@#DEVDIR#@$(DEVDIR)@; s@#ETCDIR#@$(ETCDIR)@; s@#UUIDDIR#@$(UUIDDIR)@; s@#MAPDIR#@$(MAPDIR)@; s@#RCDDIR#@$(RCDDIR)@" $< > $@ + sed "s/#VERSION#/$(VERSION)/; s@#DEVDIR#@$(DEVDIR)@; s@#ETCDIR#@$(ETCDIR)@; s@#UUIDDIR#@$(UUIDDIR)@; s@#MAPDIR#@$(MAPDIR)@; s@#RCDDIR#@$(RCDDIR)@; s@#CONF_PREFIXES#@$(CONF_PREFIXES)@" $< > $@ + [ "$@" = "cryptfs.bin" ] && chmod +x "$@" || true + [ "$@" = "cryptfs.rc" ] && chmod +x "$@" || true + +.PHONY: install_bin install_systemd install_sysvinit dist clean + +install_bin: + install -D -m0755 cryptfs.bin $(DESTDIR)$(BINDIR)/cryptfs -.PHONY: install dist clean +install_systemd: install_bin + install -D -m0644 cryptfs.service $(DESTDIR)$(SYSTEMDDIR)/cryptfs -install: all - install -D -m0755 cryptfs $(DESTDIR)$(RCDDIR)/cryptfs +install_sysvinit: install_bin + install -D -m0755 cryptfs.rc $(DESTDIR)$(RCDDIR)/cryptfs clean: - rm -f cryptfs + rm -f cryptfs.bin cryptfs.rc cryptfs.service dist: clean git status --porcelain 2> /dev/null | grep -q "\S" && (git add .; git commit -m"neue Version: $(VERSION)") || true diff --git a/cryptfs.bin.in b/cryptfs.bin.in new file mode 100644 index 0000000..fde3bd0 --- /dev/null +++ b/cryptfs.bin.in @@ -0,0 +1,236 @@ +#!/bin/bash +# +# #BINDIR#/cryptfs: mount/umount encrypted partitions +# + +set -e + +if [ $# -eq 1 ] && [ "x$1" = 'x-u' ]; then + unmount=true +elif [ $# -eq 0 ]; then + unmount=false +else + >&2 printf 'Usage: %s [-u]\n' "$0" + exit 1 +fi + +give_all_parent_dirs() { + local odir + local dir + odir="$1" + odir="/${odir#/}" + dir="${odir%/*}" + while [ "${dir}" != '' ]; do + printf '%s %s\n' "${odir}" "${dir}" + dir="${dir%/*}" + done +} + +inner_fs_to_mountorder() { + { + echo "${fstab}" | \ + grep "^$1 " | \ + awk '{print "x " $3}' + echo "${fstab}" | \ + sed -n ' + s|^\(\S\+\) \S\+ \(\S\+\)\( .*\)\?$|\1 \2| + T + p + ' | \ + while read -r order dir; do + give_all_parent_dirs "${dir}" | \ + awk '{print "'"${order}"' " $1 " " $2}' + done | \ + sort -k3,3 -k2r,2 | \ + uniq -f2 | \ + cut -d' ' -f1,3 + } | \ + sort -k2r,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 +} + +mountpoint_to_file() { + { + echo "${fstab}" | \ + awk '{print $1 " " $3}' + give_all_parent_dirs "$1" | \ + awk '{print "x " $2}' + } | \ + sort -k2r,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 | \ + head -n1 +} + +mountorder_to_device() { + { + printf 'x %s\n' "$1" + echo "${fstab}" | \ + awk '{print $1 " " $2}' | \ + sort -k2,2 -u + } | \ + sort -k2,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 +} + +crypttab=$( + sed ' + s|^\s*#CONF_PREFIXES#\s*|| + /^\s*#/d + /^\s*$/d + s/\s\+/ /g + ' '#ETCDIR#/crypttab' | \ + sort -u | \ + sed ' + s|UUID=|#UUIDDIR#/| + s/\s\+/ /g + s/^ // + ' +) +fstab=$( + sed ' + s|^\s*#CONF_PREFIXES#\s*|| + /^\s*#/d + /^\s*\S\+\s\+[^\/[:space:]]/d + /^\s*$/d + s/\s\+/ /g + ' '#ETCDIR#/fstab' | \ + sort -u | \ + cat -n | \ + sed ' + s|UUID=|#UUIDDIR#/| + s/\s\+/ /g + s/^ // + s/ \+$// + ' +) + +mount_details() { + echo "${fstab}" | \ + grep "^$2 " | \ + while read -r _ source dest fs opts _; do + case "$1" in + 'mp') + printf '%s\n' "${dest}" + ;; + 'dev') + printf '%s\n' "${source}" + ;; + 'fs') + printf '%s\n' "${fs}" + ;; + 'all') + printf -- '-t %s ' "${fs}" + if [ -n "${opts}" ] && \ + [ "${opts}" != 'defaults' ]; then + printf -- '-o %s ' "${opts}" + fi + printf '%s %s\n' "${source}" "${dest}" + ;; + *) + >&2 printf 'unknown mount_details "%s"\n' "$1" + exit 42 + ;; + esac + done +} + +is_mounted() { + mountpoint -q "$(mount_details mp "$1")" +} + +is_unlocked() { + cryptsetup status "$1" >/dev/null 2>&1 +} + +do_mount() { + local inner_fs + if is_mounted "$1"; then + return + fi + inner_fs=$(inner_fs_to_mountorder "$1") + + case "$(mount_details fs "$1")" in + 'ext'*) + e2fsck $(mount_details dev "$1") + ;; + 'fuse.sshfs'|'fuse.ftps') + local max_wait + local host + max_wait=$(($(date +%s)+120)) + host=$( + mount_details dev "$1" | \ + sed 's>^\([^:@]*@\)\?\([^:@]\+\):\S*$>\2>" + ) + while [ $(date +%s) -lt ${max_wait} ] && \ + ! /bin/ping6 -c1 ${host} >/dev/null 2>&1 && \ + ! /bin/ping -c1 ${host} >/dev/null 2>&1; do + >&2 printf ',' + sleep 1 + done + ;; + esac + + if [ -n "${inner_fs}" ]; then + do_unmount -l "${inner_fs}" + fi + mount $(mount_details all "$1") + if [ -n "${inner_fs}" ]; then + do_mount "${inner_fs}" + fi +} + +do_unmount() { + local inner_fs + local lazy + if [ "x$1" = 'x-l' ]; then + lazy='-l' + shift + else + lazy='' + fi + if ! is_mounted "$1"; then + return + fi + inner_fs=$(inner_fs_to_mountorder "$1") + if [ -n "${inner_fs}" ]; then + do_unmount -l "${inner_fs}" + fi + umount ${lazy} $(mount_details mp "$1") + if [ -n "${inner_fs}" ]; then + do_mount "${inner_fs}" + fi +} + +do_crypt_close() { + if is_unlocked "$1"; then + cryptsetup luksClose "$1" + fi +} + +do_crypt_open() { + if ! is_unlocked "$1"; then + cryptsetup luksOpen "$1" "$2" --key-file="$3" + fi +} + +echo "${crypttab}" | \ + while read -r name raw key; do + key="${key%% *}" + key_mount=$(mountpoint_to_file "${key}") + mount_order=$(mountorder_to_device "#MAPDIR#/${name}") + + if ${unmount}; then + do_unmount "${mount_order}" + do_crypt_close "${name}" + else + do_mount "${key_mount}" + do_crypt_open "${name}" "${raw}" "${key}" + do_unmount -l "${key_mount}" + do_mount "${mount_order}" + fi + done + +# End of file diff --git a/cryptfs.in b/cryptfs.in deleted file mode 100644 index 8b5d1a8..0000000 --- a/cryptfs.in +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash -# -# #RCDDIR#/cryptfs: mount/umount encrypted partitions -# - -set -o pipefail - -cryptTab="$(grep -v "^\s*\(#\|\$\)" #ETCDIR#/crypttab | sed "s/^\s*//")" -fsTab="$(grep -v "^\s*\(#\|\$\)" #ETCDIR#/fstab | sed "s/^\s*//")" - -cryptedFss="$(echo "${cryptTab}" | awk '{print "#MAPDIR#/"$1}')" -neededKeyFss="$( - for fs in $(echo "${fsTab}" | awk '{print $2}' | grep "^/") - do - if echo "${cryptTab}" | grep -q "^\S\+\s\+\S\+\s\+${fs}\(/\|\s\)" - then - echo "${fs}" - fi - done -)" -innermostFss="$( - for fs in ${cryptedFss} - do - echo "${fsTab}" | \ - awk '{print $2}' | \ - grep "^$( - echo "${fsTab}" | \ - grep "^${fs}\s" | \ - awk '{print $2}' - )/" - done -)" - -case $1 in - -start) - - for neededKeyFs in ${neededKeyFss} - do - if ! mountpoint -q "${neededKeyFs}" - then - if echo "${fsTab}" | grep -q "^\S\+\s\+${neededKeyFs}\s\+fuse\.\(ssh\|ftp\)fs\s" - then - maxWait=120 - while [ ${maxWait} -gt 0 ] && ! /sbin/ip -o addr show scope global | grep -q '\S' - do - >&2 echo -ne "." - sleep 1 - maxWait=$[${maxWait}-1] - done - host="$( - echo "${fsTab}" | \ - grep -m1 "^\S\+\s\+${neededKeyFs}\s\+fuse\.\(ssh\|ftp\)fs\s" | \ - sed "s>^\([^ :@]*@\)\?\([^ :@]\+\)\(:\S\+\)\?\s\+${neededKeyFs}\s.*$>\2>" - )" - while [ ${maxWait} -gt 0 ] && ! /bin/ping6 -c1 ${host} &> /dev/null && ! /bin/ping -c1 ${host} &> /dev/null - do - >&2 echo -ne "," - sleep 1 - maxWait=$[${maxWait}-1] - done - fi - mount ${neededKeyFs} || exit $? - fi - done - - for ((cryptDeviceNum=0; cryptDeviceNum<$(echo "${cryptTab}" | wc -l); cryptDeviceNum++)) - do - zeile="$(echo "${cryptTab}" | head -n$[${cryptDeviceNum}+1] | tail -n1)" - name="$(echo "${zeile}" | awk '{print $1}')" - device="$(echo "${zeile}" | awk '{print $2}')" - if [[ "${device}" == "UUID="* ]] - then - device="#UUIDDIR#/${device#UUID=}" - fi - keyfile="$(echo "${zeile}" | awk '{print $3}')" - if [ ! -b "#MAPDIR#/${name}" ] - then - cryptsetup luksOpen "${device}" "${name}" --key-file="${keyfile}" || exit $? - fi - done - - for cryptedFs in ${cryptedFss} - do - if ! findmnt --source "${cryptedFs}" > /dev/null - then - e2fsck "${cryptedFs}" - mount "${cryptedFs}" || exit $? - fi - done - - for innermostFs in ${innermostFss} - do - if ! mountpoint -q "${innermostFs}" - then - mount "${innermostFs}" || exit $? - fi - done - - ;; - -stop) - - for innermostFs in ${innermostFss} - do - if mountpoint -q "${innermostFs}" - then - umount "${innermostFs}" || exit $? - fi - done - - for cryptedFs in ${cryptedFss} - do - if findmnt --source "${cryptedFs}" > /dev/null - then - umount "${cryptedFs}" || exit $? - fi - done - - for name in $(echo "${cryptTab}" | awk '{print $1}') - do - if [ -b "#MAPDIR#/${name}" ] - then - cryptsetup luksClose "${name}" || exit $? - fi - done - - for neededKeyFs in ${neededKeyFss} - do - if [ ! "${neededKeyFs}" == "/" ] && mountpoint -q "${neededKeyFs}" - then - umount ${neededKeyFs} || exit $? - fi - done - - ;; - - restart) - $0 stop - sleep 2 - $0 start - ;; - -*) - echo "usage: $0 [start|stop|restart]" - ;; - -esac - -# End of file diff --git a/cryptfs.rc.in b/cryptfs.rc.in new file mode 100644 index 0000000..bf52b9e --- /dev/null +++ b/cryptfs.rc.in @@ -0,0 +1,33 @@ +#!/bin/bash +# +# #RCDDIR#/cryptfs: mount/umount encrypted partitions +# + +case "$1" in + + start) + + cryptfs + + ;; + + stop) + + cryptfs -u + + ;; + + restart) + + "$0" stop + "$0" start + + *) + + echo "usage: $0 [start|stop|restart]" + + ;; + +esac + +# End of file diff --git a/cryptfs.service.in b/cryptfs.service.in new file mode 100644 index 0000000..be1003e --- /dev/null +++ b/cryptfs.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=Decrypt and mount encrypted partitions. +Requires=network-online.target local-fs.target +After=network-online.target local-fs.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=#BINDIR#/cryptfs +ExecStop=#BINDIR#/cryptfs -u + +[Install] +WantedBy=multi-user.target |