summaryrefslogtreecommitdiffstats
path: root/debian/initramfs/scripts/local-top/cryptroot
diff options
context:
space:
mode:
Diffstat (limited to 'debian/initramfs/scripts/local-top/cryptroot')
-rw-r--r--debian/initramfs/scripts/local-top/cryptroot239
1 files changed, 239 insertions, 0 deletions
diff --git a/debian/initramfs/scripts/local-top/cryptroot b/debian/initramfs/scripts/local-top/cryptroot
new file mode 100644
index 0000000..90b521b
--- /dev/null
+++ b/debian/initramfs/scripts/local-top/cryptroot
@@ -0,0 +1,239 @@
+#!/bin/sh
+
+PREREQ="cryptroot-prepare"
+
+#
+# Standard initramfs preamble
+#
+prereqs()
+{
+ # Make sure that cryptroot is run last in local-top
+ local req
+ for req in "${0%/*}"/*; do
+ script="${req##*/}"
+ if [ "$script" != "${0##*/}" ]; then
+ printf '%s\n' "$script"
+ fi
+ done
+}
+
+case $1 in
+prereqs)
+ prereqs
+ exit 0
+ ;;
+esac
+
+. /scripts/functions
+
+[ -f /lib/cryptsetup/functions ] || return 0
+. /lib/cryptsetup/functions
+
+
+# wait_for_source()
+# Wait for encrypted $CRYPTTAB_SOURCE . Set $CRYPTTAB_SOURCE
+# to its normalized device name when it shows up;
+# return 1 if timeout.
+wait_for_source() {
+ wait_for_udev 10
+
+ if crypttab_resolve_source; then
+ # the device is here already, no need to loop
+ return 0
+ fi
+
+ # If the source device hasn't shown up yet, give it a little while
+ # to allow for asynchronous device discovery (e.g. USB).
+ #
+ # We also need to take into account RAID or other devices that may
+ # only be available on local-block stage. So, wait 5 seconds upfront,
+ # in local-top; if that fails, end execution relying on local-block
+ # invocations. Allow $ROOTDELAY/4 invocations with 1s sleep times (with
+ # a minimum of 20 invocations), and if after that we still fail, then it's
+ # really time to give-up. Variable $initrd_cnt tracks the re-invocations.
+ #
+ # Part of the lines below has been taken from initramfs-tools
+ # scripts/local's local_device_setup(), as suggested per
+ # https://launchpad.net/bugs/164044 .
+
+ local slumber=5
+ if [ "${CRYPTROOT_STAGE-}" = "local-block" ]; then
+ slumber=1
+ fi
+
+ cryptsetup_message "Waiting for encrypted source device $CRYPTTAB_SOURCE..."
+
+ while [ $slumber -gt 0 ]; do
+ sleep 1
+
+ if crypttab_resolve_source; then
+ wait_for_udev 10
+ return 0
+ fi
+
+ slumber=$(( $slumber - 1 ))
+ done
+ return 1
+}
+
+# setup_mapping()
+# Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME,
+# $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS.
+setup_mapping() {
+ local dev initrd_cnt
+
+ # We control here the number of re-invocations of this script from
+ # local-block - the heuristic is $ROOTDELAY/4, with a minimum of 20.
+
+ if [ -f "$CRYPTROOT_COUNT_FILE" ]; then
+ initrd_cnt="$(cat <"$CRYPTROOT_COUNT_FILE")"
+ else
+ initrd_cnt="${ROOTDELAY:-180}"
+ initrd_cnt=$(( initrd_cnt/4 ))
+ if [ $initrd_cnt -lt 20 ]; then
+ initrd_cnt=20
+ fi
+ echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
+ fi
+
+ # The same target can be specified multiple times
+ # e.g. root and resume lvs-on-lvm-on-crypto
+ if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then
+ return 0
+ fi
+
+ crypttab_parse_options --export --missing-path=fail || return 1
+
+ if ! wait_for_source; then
+ if [ $initrd_cnt -eq 0 ]; then
+ # we've given up
+ if [ -n "$panic" ]; then
+ panic "ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
+ else
+ # let the user fix matters if they can
+ echo " ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
+ echo " Check cryptopts=source= bootarg: cat /proc/cmdline"
+ echo " or missing modules, devices: cat /proc/modules; ls /dev"
+ panic "Dropping to a shell."
+ fi
+ return 1 # can't continue because environment is lost
+ else
+ initrd_cnt=$(( initrd_cnt - 1 ))
+ echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
+ return 0 # allow some attempts on local-block stage
+ fi
+ fi
+
+ # our `cryptroot-unlock` script searches for cryptsetup processes
+ # with a given CRYPTTAB_NAME it their environment
+ export CRYPTTAB_NAME
+
+ if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ]; then
+ # no keyscript: interactive unlocking, or key file
+
+ if [ "${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}" != "$CRYPTTAB_KEY" ]; then
+ # skip the mapping for now if the root FS is not mounted yet
+ sed -rn 's/^\s*[^#[:blank:]]\S*\s+(\S+)\s.*/\1/p' /proc/mounts | grep -Fxq -- "$rootmnt" || return 1
+ # substitute the "/FIXME-initramfs-rootmnt/" prefix by the real root FS mountpoint otherwise
+ CRYPTTAB_KEY="$rootmnt/${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}"
+ fi
+
+ if [ "$CRYPTTAB_KEY" != "none" ]; then
+ if [ ! -e "$CRYPTTAB_KEY" ]; then
+ cryptsetup_message "ERROR: Skipping target $CRYPTTAB_NAME: non-existing key file $CRYPTTAB_KEY"
+ return 1
+ fi
+ # try only once if we have a key file
+ CRYPTTAB_OPTION_tries=1
+ fi
+ fi
+
+ local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype vg rv
+ 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
+ run_keyscript "$count" | unlock_mapping
+ fi
+ rv=$?
+ count=$(( $count + 1 ))
+
+ if [ $rv -ne 0 ]; then
+ cryptsetup_message "ERROR: $CRYPTTAB_NAME: cryptsetup failed, bad password or options?"
+ sleep 1
+ continue
+ elif ! dev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then
+ cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown error setting up device mapping"
+ return 1
+ fi
+
+ if ! fstype="$(get_fstype "$dev")" || [ "$fstype" = "unknown" ]; then
+ if [ "$CRYPTTAB_TYPE" != "luks" ]; then
+ # bad password for plain dm-crypt device? or mkfs not run yet?
+ cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown fstype, bad password or options?"
+ wait_for_udev 10
+ /sbin/cryptsetup remove -- "$CRYPTTAB_NAME"
+ sleep 1
+ continue
+ fi
+ fi
+
+ cryptsetup_message "$CRYPTTAB_NAME: set up successfully"
+ wait_for_udev 10
+ return 0
+ done
+
+ cryptsetup_message "ERROR: $CRYPTTAB_NAME: maximum number of tries exceeded"
+ exit 1
+}
+
+
+#######################################################################
+# Begin real processing
+
+mkdir -p /cryptroot # might not exist yet if the main system has no crypttab(5)
+
+# Do we have any kernel boot arguments?
+if ! grep -qE '^(.*\s)?cryptopts=' /proc/cmdline; then
+ # ensure $TABFILE exists and has a mtime greater than the boot time
+ # (existing $TABFILE is preserved)
+ touch -- "$TABFILE"
+else
+ # let the read builtin unescape the '\' as GRUB substitutes '\' by '\\' in the cmdline
+ tr ' ' '\n' </proc/cmdline | sed -n 's/^cryptopts=//p' | while IFS= read cryptopts; do
+ # skip empty values (which can be used to disable the initramfs
+ # scripts for a particular boot, cf. #873840)
+ [ -n "$cryptopts" ] || continue
+ unset -v target source key options
+
+ IFS=","
+ for x in $cryptopts; do
+ case "$x" in
+ target=*) target="${x#target=}";;
+ source=*) source="${x#source=}";;
+ key=*) key="${x#key=}";;
+ *) options="${options+$options,}$x";;
+ esac
+ done
+
+ if [ -z "${source:+x}" ]; then
+ cryptsetup_message "ERROR: Missing source= value in kernel parameter cryptopts=$cryptopts"
+ else
+ # preserve mangling
+ printf '%s %s %s %s\n' "${target:-cryptroot}" "$source" "${key:-none}" "${options-}"
+ fi
+ done >"$TABFILE"
+fi
+
+# Do we have any settings from the $TABFILE?
+if [ -s "$TABFILE" ]; then
+ # Create locking directory before invoking cryptsetup(8) to avoid warnings
+ mkdir -pm0700 /run/cryptsetup
+ modprobe -q dm_crypt
+
+ crypttab_foreach_entry setup_mapping
+fi
+
+exit 0