diff options
Diffstat (limited to 'debian/cryptdisks-functions')
-rw-r--r-- | debian/cryptdisks-functions | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/debian/cryptdisks-functions b/debian/cryptdisks-functions new file mode 100644 index 0000000..ce5e6f4 --- /dev/null +++ b/debian/cryptdisks-functions @@ -0,0 +1,286 @@ +# +# This file is for inclusion with +# . /lib/cryptsetup/cryptdisks-functions +# and should not be executed directly. + +PATH="/usr/sbin:/usr/bin:/sbin:/bin" +CRYPTDISKS_ENABLE="Yes" + +#set -x + +# Sanity check #1 +[ -x /sbin/cryptsetup ] || exit 0 + +. /lib/lsb/init-functions +. /lib/cryptsetup/functions + +if [ -r /etc/default/cryptdisks ]; then + . /etc/default/cryptdisks +fi + +MOUNT="$CRYPTDISKS_MOUNT" + + +# do_start() +# Unlock all devices in the crypttab(5) +do_start() { + [ -s "$TABFILE" ] || return 0 + + # Create locking directory before invoking cryptsetup(8) to avoid warnings + mkdir -pm0700 /run/cryptsetup + modprobe -qb dm-mod || true + modprobe -qb dm-crypt || true + dmsetup mknodes >/dev/null 2>&1 || true + + if [ "$INITSTATE" != "init" ]; then + log_action_begin_msg "Starting $INITSTATE crypto disks" + fi + mount_fs + + crypttab_foreach_entry _do_start_callback + + umount_fs + log_action_end_msg 0 +} +_do_start_callback() { + setup_mapping || log_action_end_msg $? +} + +# mount_fs() +# Premounts file systems +mount_fs() { + local point + MOUNTED="" + + for point in $MOUNT; do + if mount "$point" >/dev/null; then + MOUNTED="$MOUNTED $point" + fi + done +} + +# Postunmounts file systems +umount_fs() { + local point + + for point in $MOUNTED; do + umount "$point" >/dev/null + done +} + +# setup_mapping() +# Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME, +# $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS. +setup_mapping() { + if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then + device_msg "running" + return 0 + fi + + local loud="${DEFAULT_LOUD:-}" + crypttab_parse_options --export --missing-path=fail || return 1 + if [ -n "${CRYPTTAB_OPTION_quiet+x}" ]; then + loud="no" + elif [ -n "${CRYPTTAB_OPTION_loud+x}" ]; then + loud="yes" + fi + + if [ -z "${FORCE_START-}" ]; then + if [ "$INITSTATE" = "early" -a -n "${CRYPTTAB_OPTION_noearly+x}" ] || + [ "$INITSTATE" != "manual" -a -n "${CRYPTTAB_OPTION_noauto+x}" ]; then + device_msg "ignored" + return 0 + fi + fi + + if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then + if ! crypttab_key_check; then + device_msg "invalid key" + return 1 + fi + CRYPTTAB_OPTION_tries=1 + fi + + if ! crypttab_resolve_source; then + if [ "$loud" = "yes" ]; then + device_msg "skipped, device $CRYPTTAB_SOURCE does not exist" + fi + return 1 + fi + device_msg "starting" + + local offset_bytes="" + if [ -n "${CRYPTTAB_OPTION_offset+x}" ] && [ ${#CRYPTTAB_OPTION_offset} -le 7 ] && [ $CRYPTTAB_OPTION_offset -lt 4194304 ]; then + # silently ignore large offset values which might cause the multiplication to overflow... + offset_bytes=$((CRYPTTAB_OPTION_offset * 512)) + fi + + local out tmpdev + if [ "$CRYPTTAB_TYPE" != "luks" ] && [ "$CRYPTTAB_TYPE" != "bitlk" ]; then + # fail if the device has a filesystem and the disk encryption format doesn't + # verify the key digest (unlike LUKS); unless it's swap, otherwise people can't + # easily convert an existing plainttext swap partition to an encrypted one + if ! out="$(/lib/cryptsetup/checks/un_blkid "$CRYPTTAB_SOURCE" "" ${CRYPTTAB_OPTION_offset+"$offset_bytes"} 2>/dev/null)" && + ! /lib/cryptsetup/checks/blkid "$CRYPTTAB_SOURCE" swap ${CRYPTTAB_OPTION_offset+"$offset_bytes"} >/dev/null; then + log_warning_msg "$CRYPTTAB_NAME: the precheck for '$CRYPTTAB_SOURCE' failed: $out" + return 1 + fi + fi + + local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype rv + local target="$CRYPTTAB_NAME" + CRYPTTAB_NAME="${CRYPTTAB_NAME}_unformatted" # XXX potential conflict + while [ $maxtries -le 0 ] || [ $count -lt $maxtries ]; do + if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then + # unlock via keyfile + unlock_mapping "$CRYPTTAB_KEY" + else + # unlock interactively or via keyscript + CRYPTTAB_NAME="$target" run_keyscript "$count" | unlock_mapping + fi + rv=$? + count=$(( $count + 1 )) + + if [ $rv -ne 0 ] || ! tmpdev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then + continue + fi + if [ -n "${CRYPTTAB_OPTION_check+x}" ] && \ + ! "$CRYPTTAB_OPTION_check" "$tmpdev" ${CRYPTTAB_OPTION_checkargs+"$CRYPTTAB_OPTION_checkargs"}; then + log_warning_msg "$target: the check for '$CRYPTTAB_NAME' failed" + cryptsetup remove -- "$CRYPTTAB_NAME" + continue + fi + if [ "${CRYPTTAB_OPTION_swap+x}" ]; then + if out="$(/lib/cryptsetup/checks/un_blkid "$tmpdev" "" ${CRYPTTAB_OPTION_offset+"$offset_bytes"} 2>/dev/null)" || + /lib/cryptsetup/checks/blkid "$tmpdev" swap ${CRYPTTAB_OPTION_offset+"$offset_bytes"} >/dev/null 2>&1; then + mkswap "$tmpdev" >/dev/null 2>&1 + else + log_warning_msg "$target: the check for '$CRYPTTAB_NAME' failed. $CRYPTTAB_NAME contains data: $out" + cryptsetup remove -- "$CRYPTTAB_NAME" + return 1 + fi + elif [ "${CRYPTTAB_OPTION_tmp+x}" ]; then + local tmpdir="$(mktemp --tmpdir="/run/cryptsetup" --directory)" rv=0 + if ! mkfs -t "$CRYPTTAB_OPTION_tmp" -q "$tmpdev" >/dev/null 2>&1 || + ! mount -t "$CRYPTTAB_OPTION_tmp" "$tmpdev" "$tmpdir" || + ! chmod 1777 "$tmpdir"; then + rv=1 + fi + umount "$tmpdir" || true + rmdir "$tmpdir" || true + [ $rv -eq 0 ] || return $rv + fi + if command -v udevadm >/dev/null 2>&1; then + udevadm settle + fi + dmsetup rename -- "$CRYPTTAB_NAME" "$target" + device_msg "$target" "started" + return 0 + done + device_msg "$target" "failed" + return 1 +} + +# Removes all mappings in crypttab, except the ones holding the root +# file system or /usr +do_stop() { + local devno_rootfs devno_usr + dmsetup mknodes + log_action_begin_msg "Stopping $INITSTATE crypto disks" + + devno_rootfs="$(get_mnt_devno /)" || devno_rootfs="" + devno_usr="$(get_mnt_devno /usr)" || devno_usr="" + + crypttab_foreach_entry _do_stop_callback + log_action_end_msg 0 +} +_do_stop_callback() { + local skip="n" devno rv=0 + + # traverse the device tree for each crypttab(5) entry and mark / and + # /usr holders as skipped. that's suboptimal but we can't use + # mapped device names as they might contain any character other than + # NUL. shouldn't be much overhead anyway as the device tree is + # likely not that long + foreach_cryptdev _do_stop_skipped $devno_rootfs $devno_usr + [ "$skip" = "n" ] || return $rv + + if devno="$(dmsetup info -c --noheadings -o devno -- "$CRYPTTAB_NAME" 2>/dev/null)" && [ -n "$devno" ]; then + foreach_cryptdev --reverse _do_stop_remove "$devno" || rv=$? # try to remove slave devices first + fi + return $rv +} +_do_stop_skipped() { + if [ "$1" = "$CRYPTTAB_NAME" ]; then + skip="y" + fi +} +_do_stop_remove() { + local name="$1" i rv=0 + for i in 1 2 4 8 16 32; do + remove_mapping "$name" 3<&- && break || rv=$? + if [ $rv -eq 1 ] || [ $rv -eq 2 -a $i -gt 16 ]; then + log_action_end_msg $rv + break + fi + log_action_cont_msg "$name busy..." + sleep $i + done +} + +# device_msg([$name], $message) +# Convenience function to handle $VERBOSE +device_msg() { + local name message + if [ $# -eq 1 ]; then + name="$CRYPTTAB_NAME" + message="$1" + else + name="$1" + message="$2" + fi + + if [ "$VERBOSE" != "no" ]; then + log_action_cont_msg "$name ($message)" + fi +} + +# remove_mapping($target) +# Remove mapping $target +remove_mapping() { + local CRYPTTAB_NAME="$1" + + if ! dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then + device_msg "stopped" + return 0 + fi + + if [ "$(dmsetup info --noheadings -c -o subsystem -- "$CRYPTTAB_NAME")" != "CRYPT" ]; then + device_msg "error" + return 1 + fi + + local opencount="$(dmsetup info -c --noheadings -o open -- "$CRYPTTAB_NAME" 2>/dev/null || true)" + if [ -z "$opencount" ]; then + device_msg "error" + return 1 + elif [ "$opencount" != "0" ]; then + device_msg "busy" + if [ "$INITSTATE" = "early" ] || [ "$INITSTATE" = "manual" ]; then + return 1 + elif [ "$INITSTATE" = "remaining" ]; then + return 2 + fi + return 0 + fi + + if cryptsetup remove -- "$CRYPTTAB_NAME"; then + device_msg "stopping" + return 0 + else + device_msg "error" + return 1 + fi +} + +# vim: set filetype=sh : |