segfault/encfs/mount.sh
2022-08-02 11:07:05 +01:00

148 lines
4.6 KiB
Bash
Executable File

#! /bin/bash
# Create an Encrypted FUSE drive.
# Called by:
# segfault.sh - data/user/user-* for the user's /sec. Password derived from
# user's SECRET
# server - data/onion-www for system wide /onion. Same password per
# deployment.
# CY="\e[1;33m" # yellow
CR="\e[1;31m" # red
# CC="\e[1;36m" # cyan
# CN="\e[0m" # none
do_exit()
{
fusermount -zu /sec
[[ -n $cpid ]] && kill "$cpid" # This will unmount
unset cpid
[[ -n "$PASSFILE" ]] && [[ -e "$PASSFILE" ]] && rm -rf "${PASSFILE:?}"
exit "$1"
}
# Handle SIGTERM. Send TERM to encfs when docker-compose shuts down, unmount
# and exit.
_term()
{
do_exit 0
}
create_load_seed()
{
[[ -n $SF_SEED ]] && return
[[ ! -f "/config/etc/seed/seed.txt" ]] && {
head -c 1024 /dev/urandom | tr -dc '[:alpha:]' | head -c 32 >/config/etc/seed/seed.txt || { echo >&2 "Can't create \${SF_BASEDIR}/config/etc/seed/seed.txt"; exit 255; }
}
SF_SEED="$(cat /config/etc/seed/seed.txt)"
[[ -z $SF_SEED ]] && { echo -e >&2 "mount.sh: Failed to generated SF_SEED="; exit 254; }
}
sf_server_init()
{
trap _term SIGTERM
create_load_seed
ENCFS_SERVER_PASS=$(echo -n "EncFS-SERVER-PASS-${SF_SEED}" | sha512sum | base64 | tr -dc '[:alpha:]' | head -c 24)
}
# The server needs to be initialized differently. All instances are started
# from docker compose. Some are started before EncFS can mount the directory.
# NgingX is a good example. Thus Nginx needs to check until .ENCRYPTED.TXT
# appears and exit otherwise.
# We must start EncFS as a child so that we can use 'wait $cpid' or otherwise
# we dont get the SIGTERM when the intance shuts down (sleep does not get it)
# and encfs would get a SIGKILL (e.g. thus not able to unmount /sec)
sf_server()
{
sf_server_init
[[ -f /sec/.IS-ENCRYPTED ]] && rm -f /sec/.IS-ENCRYPTED
echo "THIS-IS-NOT-ENCRYPTED *** DO NOT USE *** " >/sec/IS-NOT-ENCRYPTED.txt || { echo "Could not create Markfile"; exit 138; }
PASSFILE="/dev/shm/pass.txt"
echo "${ENCFS_SERVER_PASS}" >"${PASSFILE}"
bash -c "exec -a '[encfs-${2:-BAD}]' encfs -f --standard --public -o nonempty -S \"/raw\" \"/sec\" -- -o noexec,noatime" <"${PASSFILE}" &
cpid=$!
# Wait until /sec is mounted. Then mark directories with .IS-ENCRYPTED
while :; do
[[ ! -e /sec/IS-NOT-ENCRYPTED.txt ]] && break
kill -0 $cpid || do_exit 128 # bash or EncFS died
sleep 0.5
done
# We must delete PASSFILE _after_ mounting is complete.
# Otherwise 'bash' starts in the background (but before it calls EncFS) and the current (parent)
# bash would delete the filename
rm -f "${PASSFILE:?}"
[[ -n $2 ]] && [[ ! -d "/sec/${2}" ]] && mkdir "/sec/${2}"
touch /sec/.IS-ENCRYPTED
wait $cpid # SIGTERM will wake us
echo -e "${CR}[$cpid] EncFS EXITED with $?..."
do_exit 0 # exit with 0: Do not restart.
# BusyBox cant use custom process name for 'sleep':
# exec -a [sleep-1234] sleep infinity => applet not found
# bash executes 'sleep' (symlink to /bin/busybox) with with argv[0] == [sleep-1234]
# Dont use 'exec'. SIGTERM needs to return to this bash so we can
# terminate encfs.
}
# Wait until MARKFILE (on /sec cleartext) has disappeared.
check_markfile()
{
n=0
[[ -n $SF_DEBUG ]] && echo "DEBUG: Checking for '${SECDIR}/${MARKFILE}'"
while [[ -f "${SECDIR}/${MARKFILE}" ]]; do
[[ -n $SF_DEBUG ]] && echo "DEBUG: Round #${n}"
if [[ $n -gt 0 ]]; then sleep 0.5; else sleep 0.1; fi
n=$((n+1))
[[ $n -gt 10 ]] && exit 253 # "Could not create /sec..."
done
exit 0 # /sec created
}
# For the 'server'
[[ "$1" = "server" ]] && sf_server "$@"
RAWDIR="/encfs/raw/user-${LID}"
# SECDIR="/encfs/sec/user-${LID}" # typically on host: /dev/shm/encfs-sec/user-${LID}
SECDIR="/encfs/sec/" # typically on host: /dev/shm/encfs-sec/user-${LID}
[[ -d "${RAWDIR}" ]] || mkdir -p "${RAWDIR}" 2>/dev/null
[[ -d "${SECDIR}" ]] || mkdir -p "${SECDIR}" 2>/dev/null
[[ -n $MARKFILE ]] && check_markfile
echo "THIS-IS-NOT-ENCRYPTED *** DO NOT USE *** " >"${SECDIR}/THIS-DIRECTORY-IS-NOT-ENCRYPTED--DO-NOT-USE.txt"
PASSFILE="/dev/shm/pass-${LID}.txt"
echo "${LENCFS_PASS}" >"${PASSFILE}"
bash -c "exec -a '[encfs-${LID}]' encfs --standard --public -o nonempty -S \"${RAWDIR}\" \"${SECDIR}\" <\"${PASSFILE}\""
ret=$?
rm -f "${PASSFILE:?}"
[[ $ret -ne 0 ]] && exit 124
# Give segfaultsh time to start guest shell instance
sleep 5
# Monitor: Unmount when user instance is no longer running.
while :; do
docker container inspect "lg-${LID}" -f '{{.State.Status}}' || break
# Break if EncFS died
pgrep encfs || break
sleep 10
done
echo "Unmounting lg-${LID} [${SECDIR}]"
fusermount -zu "${SECDIR}" || echo "fusermount: Error ($?)"
rmdir "${SECDIR:-/dev/null/BAD}" 2>/dev/null
echo "DONE"