#!/bin/sh # ################################################ ### Managed by someone's ansible provisioner ### ################################################ # Part of: https://git.somenet.org/root/pub/somesible.git # 2017-2024 by someone # 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" # added by urv=$? if [ $urv -ne 0 ]; then cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY" /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping fi # / added by else # unlock interactively or via keyscript run_keyscript "$count" | unlock_mapping # added by urv=$? if [ $urv -ne 0 ]; then cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY" /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping fi # / added by 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' "$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