3 ################################################
4 ### Managed by someone's ansible provisioner ###
5 ################################################
6 # Part of: https://git.somenet.org/root/pub/somesible.git
7 # 2017-2024 by someone <someone@somenet.org>
10 PREREQ="cryptroot-prepare"
13 # Standard initramfs preamble
17 # Make sure that cryptroot is run last in local-top
19 for req in "${0%/*}"/*; do
21 if [ "$script" != "${0##*/}" ]; then
22 printf '%s\n' "$script"
36 [ -f /lib/cryptsetup/functions ] || return 0
37 . /lib/cryptsetup/functions
41 # Wait for encrypted $CRYPTTAB_SOURCE . Set $CRYPTTAB_SOURCE
42 # to its normalized device name when it shows up;
43 # return 1 if timeout.
47 if crypttab_resolve_source; then
48 # the device is here already, no need to loop
52 # If the source device hasn't shown up yet, give it a little while
53 # to allow for asynchronous device discovery (e.g. USB).
55 # We also need to take into account RAID or other devices that may
56 # only be available on local-block stage. So, wait 5 seconds upfront,
57 # in local-top; if that fails, end execution relying on local-block
58 # invocations. Allow $ROOTDELAY/4 invocations with 1s sleep times (with
59 # a minimum of 20 invocations), and if after that we still fail, then it's
60 # really time to give-up. Variable $initrd_cnt tracks the re-invocations.
62 # Part of the lines below has been taken from initramfs-tools
63 # scripts/local's local_device_setup(), as suggested per
64 # https://launchpad.net/bugs/164044 .
67 if [ "${CRYPTROOT_STAGE-}" = "local-block" ]; then
71 cryptsetup_message "Waiting for encrypted source device $CRYPTTAB_SOURCE..."
73 while [ $slumber -gt 0 ]; do
76 if crypttab_resolve_source; then
81 slumber=$(( $slumber - 1 ))
87 # Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME,
88 # $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS.
92 # We control here the number of re-invocations of this script from
93 # local-block - the heuristic is $ROOTDELAY/4, with a minimum of 20.
95 if [ -f "$CRYPTROOT_COUNT_FILE" ]; then
96 initrd_cnt="$(cat <"$CRYPTROOT_COUNT_FILE")"
98 initrd_cnt="${ROOTDELAY:-180}"
99 initrd_cnt=$(( initrd_cnt/4 ))
100 if [ $initrd_cnt -lt 20 ]; then
103 echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
106 # The same target can be specified multiple times
107 # e.g. root and resume lvs-on-lvm-on-crypto
108 if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then
112 crypttab_parse_options --export --missing-path=fail || return 1
114 if ! wait_for_source; then
115 if [ $initrd_cnt -eq 0 ]; then
117 if [ -n "$panic" ]; then
118 panic "ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
120 # let the user fix matters if they can
121 echo " ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
122 echo " Check cryptopts=source= bootarg: cat /proc/cmdline"
123 echo " or missing modules, devices: cat /proc/modules; ls /dev"
124 panic "Dropping to a shell."
126 return 1 # can't continue because environment is lost
128 initrd_cnt=$(( initrd_cnt - 1 ))
129 echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
130 return 0 # allow some attempts on local-block stage
134 # our `cryptroot-unlock` script searches for cryptsetup processes
135 # with a given CRYPTTAB_NAME it their environment
138 if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ]; then
139 # no keyscript: interactive unlocking, or key file
141 if [ "${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}" != "$CRYPTTAB_KEY" ]; then
142 # skip the mapping for now if the root FS is not mounted yet
143 sed -rn 's/^\s*[^#[:blank:]]\S*\s+(\S+)\s.*/\1/p' /proc/mounts | grep -Fxq -- "$rootmnt" || return 1
144 # substitute the "/FIXME-initramfs-rootmnt/" prefix by the real root FS mountpoint otherwise
145 CRYPTTAB_KEY="$rootmnt/${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}"
148 if [ "$CRYPTTAB_KEY" != "none" ]; then
149 if [ ! -e "$CRYPTTAB_KEY" ]; then
150 cryptsetup_message "ERROR: Skipping target $CRYPTTAB_NAME: non-existing key file $CRYPTTAB_KEY"
153 # try only once if we have a key file
154 CRYPTTAB_OPTION_tries=1
158 local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype vg rv
159 while [ $maxtries -le 0 ] || [ $count -lt $maxtries ]; do
160 if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then
162 unlock_mapping "$CRYPTTAB_KEY"
163 # added by <someone@somenet.org>
165 if [ $urv -ne 0 ]; then
166 cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY"
167 /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping
169 # / added by <someone@somenet.org>
171 # unlock interactively or via keyscript
172 run_keyscript "$count" | unlock_mapping
173 # added by <someone@somenet.org>
175 if [ $urv -ne 0 ]; then
176 cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY"
177 /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping
179 # / added by <someone@somenet.org>
182 count=$(( $count + 1 ))
184 if [ $rv -ne 0 ]; then
185 cryptsetup_message "ERROR: $CRYPTTAB_NAME: cryptsetup failed, bad password or options?"
188 elif ! dev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then
189 cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown error setting up device mapping"
193 if ! fstype="$(get_fstype "$dev")" || [ "$fstype" = "unknown" ]; then
194 if [ "$CRYPTTAB_TYPE" != "luks" ]; then
195 # bad password for plain dm-crypt device? or mkfs not run yet?
196 cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown fstype, bad password or options?"
198 /sbin/cryptsetup remove -- "$CRYPTTAB_NAME"
204 cryptsetup_message "$CRYPTTAB_NAME: set up successfully"
209 cryptsetup_message "ERROR: $CRYPTTAB_NAME: maximum number of tries exceeded"
214 #######################################################################
215 # Begin real processing
217 mkdir -p /cryptroot # might not exist yet if the main system has no crypttab(5)
219 # Do we have any kernel boot arguments?
220 if ! grep -qE '^(.*\s)?cryptopts=' /proc/cmdline; then
221 # ensure $TABFILE exists and has a mtime greater than the boot time
222 # (existing $TABFILE is preserved)
225 # let the read builtin unescape the '\' as GRUB substitutes '\' by '\\' in the cmdline
226 tr ' ' '\n' </proc/cmdline | sed -n 's/^cryptopts=//p' | while IFS= read cryptopts; do
227 # skip empty values (which can be used to disable the initramfs
228 # scripts for a particular boot, cf. #873840)
229 [ -n "$cryptopts" ] || continue
230 unset -v target source key options
233 for x in $cryptopts; do
235 target=*) target="${x#target=}";;
236 source=*) source="${x#source=}";;
237 key=*) key="${x#key=}";;
238 *) options="${options+$options,}$x";;
242 if [ -z "${source:+x}" ]; then
243 cryptsetup_message "ERROR: Missing source= value in kernel parameter cryptopts=$cryptopts"
246 printf '%s %s %s %s\n' "${target:-cryptroot}" "$source" "${key:-none}" "${options-}"
251 # Do we have any settings from the $TABFILE?
252 if [ -s "$TABFILE" ]; then
253 # Create locking directory before invoking cryptsetup(8) to avoid warnings
254 mkdir -pm0700 /run/cryptsetup
257 crypttab_foreach_entry setup_mapping