#!/bin/sh #/usr/local/sbin/bootkeyscript #https://doc.ubuntu-fr.org/tutoriel/securiser_ubuntu_avec_peripherique_externe#etape_3parametrer_le_demarrage # Swami Petaramesh, 2007/11/28 # Modified by Swami Petaramesh 2010/03/23 # Modified by malabarth 2013/09/26 # # Version 3.0 # # Copyright Swami Petaramesh 2007-2010 # Parts copied from "cryptroot" script from the "cryptsetup" # package, copyright cryptsetup authors. (Christophe Saout, # Clemens Fruhwirth). # This script allows using a key file stored on an external # device, which can be LUKS-encrypted or not. It can fallback # to using a manually input passphrase if the external device # is missing. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see # Additional boot params : cryptopts=key=: # Example : cryptopts=key=mmcblk0p1:mykeyfile # Will mount /dev/mmcblk0p1 and use "mykeyfile" on this device # # UUID=something:mykeyfile and LABEL=something:mykeyfile are also # supported. # # Helper functions # . /scripts/functions # debug=1 will print debug messages and echo typed password # debug=0 will be much more silent # It can be set using boot command line, i.e. cryptopts=target=,key=/dev/sdb1/.key,debug=1 debug=0 message() { if [ -x /bin/plymouth ] && plymouth --ping; then plymouth message --text="$@" elif [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TEXT-URGENT $@" else echo "$@" > /dev/console fi } parse_options() { local cryptopts cryptopts="$@" [ "${debug}" == "1" ] && message "(parse_options)" if [ -z "$cryptopts" ]; then message "(parse_options): Called without parameters. Nothing to do..." return 1 fi # Defaults crypttarget="filesystem" cryptkeydev="" dispkeydev="" cryptkey="" local IFS=" ," for x in $cryptopts; do case $x in target=*) crypttarget=${x#target=} ;; key=*) if [ "${x#key=}" != "none" ]; then cryptkey=${x#key=} fi ;; debug=*) if [ "${x#debug=}" == "1" ]; then debug=1 fi ;; esac done case ${cryptkey} in *:*) case ${cryptkey} in [Uu][Uu][Ii][Dd]=*) cryptkey="${cryptkey#[Uu][Uu][Ii][Dd]=}" cryptkeydev="/dev/disk/by-uuid/${cryptkey%%:*}" dispkeydev="${cryptkey%%:*}" dispkeydev="UUID:${dispkeydev##*-}" cryptkey="${cryptkey#*:}" ;; [Ll][Aa][Bb][Ee][Ll]=*) cryptkey="${cryptkey#[Ll][Aa][Bb][Ee][Ll]=}" cryptkeydev="/dev/disk/by-label/${cryptkey%%:*}" dispkeydev="${cryptkey%%:*}" cryptkey="${cryptkey#*:}" ;; *) cryptkeydev="/dev/${cryptkey%%:*}" dispkeydev="${cryptkey%%:*}" cryptkey="${cryptkey#*:}" ;; esac ;; *) cryptkeydev="/dev/${cryptkey%%/*}" dispkeydev="${cryptkey%%/*}" cryptkey="${cryptkey#*/}" ;; esac if [ "${debug}" == "1" ]; then message "target: ${crypttarget}; keydev: ${dispkeydev}; key: ${cryptkey}" fi } trymount() { local mtmsg mtresult [ "${debug}" == "1" ] && message "(trymount)" [ -d "/mnt/rootKey" ] || mkdir -p /mnt/rootKey >/dev/null 2>&1 FSTYPE='' eval $(fstype < "${cryptkeydev}") [ "${debug}" == "1" ] && message "${dispkeydev} filesystem is ${FSTYPE}" mtmsg="" mtresult=1 if [ -n "${FSTYPE}" -a "${FSTYPE}" != "unknown" -a "${FSTYPE}" != "Unknown" ]; then [ "${debug}" == "1" ] && message "Trying to mount $1 as ${FSTYPE}..." mtmsg="`mount -t ${FSTYPE} -o ro $1 /mnt/rootKey 2>&1`" mtresult="$?" fi if [ ${mtresult} -ne 0 ]; then [ "${debug}" == "1" ] && message "Trying to mount $1 as ext2..." mtmsg="`mount -t ext2 -o ro $1 /mnt/rootKey 2>&1`" mtresult="$?" fi if [ ${mtresult} -ne 0 ]; then [ "${debug}" == "1" ] && message "Trying to mount $1 as vfat..." mtmsg="`mount -t vfat -o ro $1 /mnt/rootKey 2>&1`" mtresult="$?" fi if [ ${mtresult} -ne 0 ]; then [ "${debug}" == "1" ] && message "Trying to mount $1 as ntfs..." mtmsg="`mount -t ntfs-3g -o ro $1 /mnt/rootKey 2>&1`" mtresult="$?" fi if [ "${debug}" == "1" ]; then if [ ${mtresult} -eq 0 ]; then message "Success !" else message "FAILED with message:" message "${mtmsg}" fi fi return ${mtresult} } type_key() { local PASS [ "${debug}" == "1" ] && { sleep 5 message "(type_key)" } if [ -x /bin/plymouth ] && plymouth --ping; then PASS="$(plymouth ask-for-password --prompt="${1:-Enter password:}")" elif [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 90" || true if [ "${debug}" == "1" ]; then /sbin/usplash_write "INPUT ${1:-Enter password:} " else /sbin/usplash_write "INPUTQUIET ${1:-Enter password:} " fi PASS="$(cat /dev/.initramfs/usplash_outfifo)" else [ "${debug}" != "1" ] && /bin/stty -F /dev/console -echo read -p "${1:-Enter password:} " PASS < /dev/console 2> /dev/console [ "${debug}" != "1" ] && /bin/stty -F /dev/console echo fi [ "${debug}" == "1" ] && message "Pwd: ${PASS}" echo -n "${PASS}" if [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then # clean the text /sbin/usplash_write "TIMEOUT 15" || true [ "${debug}" != "1" ] && /sbin/usplash_write "CLEAR" fi } fetch_key() { local opts count opts="$@" [ "${debug}" == "1" ] && message "(fetch_key)" if [ -z "$opts" ]; then message "(fetch_key): Called without parameters. Nothing to do..." return 1 fi parse_options "$opts" || { message "(fetch_key): ERROR: Could not parse options." return 1 } # If no key device and file specified, fallback to typing the passphrase if [ -z "${cryptkeydev}" -o -z "${cryptkey}" ]; then type_key "Enter password for ${crypttarget}:" else # Wait for udev to be ready, see https://launchpad.net/bugs/85640 if [ -x /sbin/udevsettle ]; then /sbin/udevsettle --timeout=30 fi # If the encrypted source device hasn't shown up yet, give it a little while # to deal with removable devices if [ ! -b "${cryptkeydev}" ] || ! /lib/udev/vol_id "${cryptkeydev}" >/dev/null 2>&1; then [ "${debug}" == "1" ] && message "Waiting for ${dispkeydev}..." # We'll wait for a maximum of 20 seconds : External key devices # such as solid-state USB keys or SD/MMC shouldn't take longer # to show up... slumber=20 if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 25" || true fi slumber=$(( ${slumber} * 10 )) while [ ! -b "${cryptkeydev}" ] || ! /lib/udev/vol_id "${cryptkeydev}" >/dev/null 2>&1; do /bin/sleep 0.1 slumber=$(( ${slumber} - 1 )) [ ${slumber} -gt 0 ] || break done if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 15" || true fi fi # Fallback to typing the passphrase if [ ! -b "${cryptkeydev}" ]; then type_key "Missing boot device ${dispkeydev}!" exit 0 fi [ "${debug}" == "1" ] && message "${dispkeydev} is available." # Now that we've found the key device, let's check if it is # itself LUKS-encrypted if /sbin/cryptsetup isLuks ${cryptkeydev} > /dev/null 2>&1; then [ "${debug}" == "1" ] && message "${dispkeydev} is LUKS encrypted." # Try to get a satisfactory password three times count=0 while [ $count -lt 3 ]; do count=$(( $count + 1 )) type_key "Enter password for ${dispkeydev}:" | /sbin/cryptsetup --readonly luksOpen ${cryptkeydev} rootKeyDev > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "cryptsetup: cryptsetup failed, bad password ?" > /dev/console sleep 2 continue elif [ ! -b "/dev/mapper/rootKeyDev" ]; then echo "cryptsetup: unknown error setting up device mapping" > /dev/console # Fallback to typing the passphrase type_key "Setup of ${dispkeydev} failed!" exit 0 fi break done if [ $count -ge 3 ]; then echo "cryptsetup: maximum number of tries exceeded" > /dev/console type_key "Failed opening ${dispkeydev}!" exit 0 fi # Now try to mount the encrypted key container trymount /dev/mapper/rootKeyDev else # Or try to mount the device trymount ${cryptkeydev} fi if [ $? -ne 0 ]; then type_key "Failed mounting ${dispkeydev}!" # echo the keyfile contents elif [ -r "/mnt/rootKey/${cryptkey}" -a -s "/mnt/rootKey/${cryptkey}" ]; then cat /mnt/rootKey/${cryptkey} else type_key "Could not find ${cryptkey} on ${dispkeydev}!" fi # Unmount the key device umount /mnt/rootKey > /dev/null 2>&1 # Wait for udev to be ready, see https://launchpad.net/bugs/85640 if [ -x /sbin/udevsettle ]; then /sbin/udevsettle --timeout=30 fi sleep 1 # Close the encrypted device if it has been used [ -b "/dev/mapper/rootKeyDev" ] && /sbin/cryptsetup luksClose rootKeyDev > /dev/null 2>&1 fi exit 0 } # # Begin real processing # # Do we have any kernel boot arguments? found='' for opt in $(cat /proc/cmdline); do case $opt in cryptdebug*) debug=1 ;; cryptopts=*) found=yes fetch_key "${opt#cryptopts=}" ;; esac done if [ -n "$found" ]; then if [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 60" || true fi exit 0 fi # Do we have any settings from the /conf/conf.d/cryptroot file? if [ -r /conf/conf.d/cryptroot ]; then while read mapping; do fetch_key "$mapping" done < /conf/conf.d/cryptroot fi if [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 60" || true fi exit 0