286 lines
8.7 KiB
Bash
286 lines
8.7 KiB
Bash
#
|
|
# 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 :
|