diff --git a/defaults/initrd.d/00-crypt.sh b/defaults/initrd.d/00-crypt.sh index 745b9c1..dfebeb7 100755 --- a/defaults/initrd.d/00-crypt.sh +++ b/defaults/initrd.d/00-crypt.sh @@ -14,15 +14,17 @@ _bootstrap_key() { } _crypt_exec() { + local luks_dev="${1}" + local cmd="${2}" # TODO(lxnay): this fugly crypt_silent should really go away if [ "${CRYPT_SILENT}" = "1" ]; then - eval ${1} >/dev/null 2>/dev/null + eval ${cmd} >/dev/null 2>/dev/null else ask_for_password --ply-tries 5 \ - --ply-cmd "${1}" \ - --ply-prompt "Encryption password (${LUKS_DEVICE}): " \ + --ply-cmd "${cmd}" \ + --ply-prompt "Encryption password (${luks_dev}): " \ --tty-tries 5 \ - --tty-cmd "${1}" || return 1 + --tty-cmd "${cmd}" || return 1 return 0 fi } @@ -30,19 +32,22 @@ _crypt_exec() { _open_luks() { case ${1} in root) + local ltypes=ROOTS local ltype=ROOT ;; swap) + local ltypes=SWAPS local ltype=SWAP ;; esac - eval local LUKS_DEVICE='"${CRYPT_'${ltype}'}"' - eval local LUKS_KEY='"${CRYPT_'${ltype}'_KEY}"' - eval local LUKS_KEYDEV='"${CRYPT_'${ltype}'_KEYDEV}"' - eval local LUKS_TRIM='"${CRYPT_'${ltype}'_TRIM}"' + eval local luks_devices='"${CRYPT_'${ltypes}'}"' + eval local luks_key='"${CRYPT_'${ltype}'_KEY}"' + eval local luks_keydev='"${CRYPT_'${ltype}'_KEYDEV}"' + eval local luks_trim='"${CRYPT_'${ltype}'_TRIM}"' + + local luks_name="${1}" - local LUKS_NAME="${1}" local dev_error=0 key_error=0 keydev_error=0 local mntkey="/mnt/key/" cryptsetup_opts="" @@ -51,187 +56,204 @@ _open_luks() { return 1 fi - local exit_st= - - while true; do - local gpg_cmd="" - exit_st=1 - - # do not force the link to /dev/mapper/root - # but rather use the value from root=, which is - # in ${REAL_ROOT} - local luks_dev_name=$(basename "${LUKS_DEVICE}") - local real_dev= - local luks_name_prefix= - if [ "${ltype}" = "ROOT" ]; then - real_dev="${REAL_ROOT}" - elif [ "${ltype}" = "SWAP" ]; then - real_dev="${REAL_RESUME}" - fi - if echo "${real_dev}" | grep -q "^/dev/mapper/"; then - # If we use LVM + cryptsetup, we may have collisions between - # the two inside /dev/mapper. So, make up a way to avoid them. - LUKS_NAME="${LUKS_NAME}_${luks_dev_name}-$(basename ${real_dev})" - fi + local real_dev= + if [ "${ltype}" = "ROOT" ]; then + real_dev="${REAL_ROOT}" + elif [ "${ltype}" = "SWAP" ]; then + real_dev="${REAL_RESUME}" + fi - # if crypt_silent=1 and some error occurs, bail out. - local any_error= - [ "${dev_error}" = "1" ] && any_error=1 - [ "${key_error}" = "1" ] && any_error=1 - [ "${keydev_error}" = "1" ] && any_error=1 - if [ "${CRYPT_SILENT}" = "1" ] && [ -n "${any_error}" ]; then - bad_msg "Failed to setup the LUKS device" - exit_st=1 - break - fi + local exit_st= luks_device= + for luks_device in ${luks_devices}; do - if [ "${dev_error}" = "1" ]; then - prompt_user "LUKS_DEVICE" "${LUKS_NAME}" - dev_error=0 - continue - fi + good_msg "Working on device ${luks_device}..." - if [ "${key_error}" = "1" ]; then - prompt_user "LUKS_KEY" "${LUKS_NAME} key" - key_error=0 - continue - fi + while true; do - if [ "${keydev_error}" = "1" ]; then - prompt_user "LUKS_KEYDEV" "${LUKS_NAME} key device" - keydev_error=0 - continue - fi + local gpg_cmd="" + exit_st=1 - local luks_dev=$(find_real_device "${LUKS_DEVICE}") - [ -n "${luks_dev}" ] && LUKS_DEVICE="${luks_dev}" # otherwise hope... + # do not force the link to /dev/mapper/root + # but rather use the value from root=, which is + # in ${REAL_ROOT} + local luks_dev_name=$(basename "${luks_device}") + local luks_name_prefix= - setup_md_device "${LUKS_DEVICE}" - cryptsetup isLuks "${LUKS_DEVICE}" || { - bad_msg "${LUKS_DEVICE} does not contain a LUKS header" - dev_error=1 - continue; - } + if echo "${real_dev}" | grep -q "^/dev/mapper/"; then + local real_dev_bn=$(basename "${real_dev}") + # If we use LVM + cryptsetup, we may have collisions between + # the two inside /dev/mapper. So, make up a way to avoid them. + luks_dev_name="${luks_name}_${luks_dev_name}-${real_dev_bn}" + fi - # Handle keys - if [ "${LUKS_TRIM}" = "yes" ]; then - good_msg "Enabling TRIM support for ${LUKS_NAME}." - cryptsetup_opts="${cryptsetup_opts} --allow-discards" - fi + # if crypt_silent=1 and some error occurs, bail out. + local any_error= + [ "${dev_error}" = "1" ] && any_error=1 + [ "${key_error}" = "1" ] && any_error=1 + [ "${keydev_error}" = "1" ] && any_error=1 + if [ "${CRYPT_SILENT}" = "1" ] && [ -n "${any_error}" ]; then + bad_msg "Failed to setup the LUKS device" + exit_st=1 + break + fi + + if [ "${dev_error}" = "1" ]; then + prompt_user "luks_device" "${luks_dev_name}" + dev_error=0 + continue + fi - if [ -n "${LUKS_KEY}" ]; then - local real_luks_keydev="${LUKS_KEYDEV}" + if [ "${key_error}" = "1" ]; then + prompt_user "luks_key" "${luks_dev_name} key" + key_error=0 + continue + fi - if [ ! -e "${mntkey}${LUKS_KEY}" ]; then - real_luks_keydev=$(find_real_device "${LUKS_KEYDEV}") - good_msg "Using key device ${real_luks_keydev}." + if [ "${keydev_error}" = "1" ]; then + prompt_user "luks_keydev" "${luks_dev_name} key device" + keydev_error=0 + continue + fi - if [ ! -b "${real_luks_keydev}" ]; then - bad_msg "Insert device ${LUKS_KEYDEV} for ${LUKS_NAME}" - bad_msg "You have 10 seconds..." - local count=10 - while [ ${count} -gt 0 ]; do - count=$((count-1)) - sleep 1 + local luks_dev=$(find_real_device "${luks_device}") + [ -n "${luks_dev}" ] && \ + luks_device="${luks_dev}" # otherwise hope... + + setup_md_device "${luks_device}" + cryptsetup isLuks "${luks_device}" || { + bad_msg "${luks_device} does not contain a LUKS header" + dev_error=1 + continue; + } + + # Handle keys + if [ "${luks_trim}" = "yes" ]; then + good_msg "Enabling TRIM support for ${luks_dev_name}." + cryptsetup_opts="${cryptsetup_opts} --allow-discards" + fi - real_luks_keydev=$(find_real_device "${LUKS_KEYDEV}") - [ ! -b "${real_luks_keydev}" ] || { - good_msg "Device ${real_luks_keydev} detected." - break; - } - done + if [ -n "${luks_key}" ]; then + local real_luks_keydev="${luks_keydev}" + + if [ ! -e "${mntkey}${luks_key}" ]; then + real_luks_keydev=$(find_real_device "${luks_keydev}") + good_msg "Using key device ${real_luks_keydev}." if [ ! -b "${real_luks_keydev}" ]; then - eval CRYPT_${ltype}_KEY=${LUKS_KEY} - _bootstrap_key ${ltype} - eval LUKS_KEYDEV='"${CRYPT_'${ltype}'_KEYDEV}"' + bad_msg "Insert device ${luks_keydev} for ${luks_dev_name}" + bad_msg "You have 10 seconds..." + local count=10 + while [ ${count} -gt 0 ]; do + count=$((count-1)) + sleep 1 + + real_luks_keydev=$(find_real_device "${luks_keydev}") + [ ! -b "${real_luks_keydev}" ] || { + good_msg "Device ${real_luks_keydev} detected." + break; + } + done - real_luks_keydev=$(find_real_device "${LUKS_KEYDEV}") if [ ! -b "${real_luks_keydev}" ]; then - keydev_error=1 - bad_msg "Removable device ${LUKS_KEYDEV} not found." + eval CRYPT_${ltype}_KEY=${luks_key} + _bootstrap_key ${ltype} + eval luks_keydev='"${CRYPT_'${ltype}'_KEYDEV}"' + + real_luks_keydev=$(find_real_device "${luks_keydev}") + if [ ! -b "${real_luks_keydev}" ]; then + keydev_error=1 + bad_msg "Device ${luks_keydev} not found." + continue + fi + + # continue otherwise will mount keydev which is + # mounted by bootstrap continue fi + fi - # continue otherwise will mount keydev which is - # mounted by bootstrap + # At this point a device was recognized, now let's see + # if the key is there + mkdir -p "${mntkey}" # ignore + + mount -n -o ro "${real_luks_keydev}" \ + "${mntkey}" || { + keydev_error=1 + bad_msg "Mounting of device ${real_luks_keydev} failed." + continue; + } + + good_msg "Removable device ${real_luks_keydev} mounted." + + if [ ! -e "${mntkey}${luks_key}" ]; then + umount -n "${mntkey}" + key_error=1 + keydev_error=1 + bad_msg "{luks_key} on ${real_luks_keydev} not found." continue fi fi - # At this point a device was recognized, now let's see - # if the key is there - mkdir -p "${mntkey}" # ignore - - mount -n -o ro "${real_luks_keydev}" \ - "${mntkey}" || { - keydev_error=1 - bad_msg "Mounting of device ${real_luks_keydev} failed." - continue; - } - - good_msg "Removable device ${real_luks_keydev} mounted." - - if [ ! -e "${mntkey}${LUKS_KEY}" ]; then - umount -n "${mntkey}" - key_error=1 - keydev_error=1 - bad_msg "{LUKS_KEY} on ${real_luks_keydev} not found." - continue + # At this point a candidate key exists + # (either mounted before or not) + good_msg "${luks_key} on device ${real_luks_keydev} found" + if [ "$(echo ${luks_key} | grep -o '.gpg$')" = ".gpg" ] && \ + [ -e /usr/bin/gpg ]; then + + # TODO(lxnay): WTF is this? + [ -e /dev/tty ] && mv /dev/tty /dev/tty.org + mknod /dev/tty c 5 1 + + cryptsetup_opts="${cryptsetup_opts} -d -" + gpg_cmd="/usr/bin/gpg --logger-file /dev/null" + gpg_cmd="${gpg_cmd} --quiet --decrypt ${mntkey}${luks_key} | " + else + cryptsetup_opts="${cryptsetup_opts} -d ${mntkey}${luks_key}" fi fi - # At this point a candidate key exists - # (either mounted before or not) - good_msg "${LUKS_KEY} on device ${real_luks_keydev} found" - if [ "$(echo ${LUKS_KEY} | grep -o '.gpg$')" = ".gpg" ] && \ - [ -e /usr/bin/gpg ]; then - - # TODO(lxnay): WTF is this? - [ -e /dev/tty ] && mv /dev/tty /dev/tty.org - mknod /dev/tty c 5 1 - - cryptsetup_opts="${cryptsetup_opts} -d -" - gpg_cmd="/usr/bin/gpg --logger-file /dev/null" - gpg_cmd="${gpg_cmd} --quiet --decrypt ${mntkey}${LUKS_KEY} | " - else - cryptsetup_opts="${cryptsetup_opts} -d ${mntkey}${LUKS_KEY}" - fi - fi - - # At this point, keyfile or not, we're ready! - local cmd="${gpg_cmd}/sbin/cryptsetup" - cmd="${cmd} ${cryptsetup_opts} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}" - _crypt_exec "${cmd}" - local ret="${?}" - - # TODO(lxnay): WTF is this? - [ -e /dev/tty.org ] \ - && rm -f /dev/tty \ - && mv /dev/tty.org /dev/tty - - if [ "${ret}" = "0" ]; then - exit_st=0 - good_msg "LUKS device ${LUKS_DEVICE} opened" - - # This is fine if the crypt device is a physical device - # like /dev/sdaX, however, if we have cryptsetup inside - # LVM, we must tweak REAL_ROOT if there is no device node. - start_volumes # this should create /dev/mapper links - if echo "${real_dev}" | grep -q "^/dev/mapper/"; then - if [ ! -e "${real_dev}" ]; then - good_msg "Creating symlink for ${LUKS_NAME} to ${real_dev}" - ln -s "${LUKS_NAME}" "${real_dev}" || exit_st=1 + # At this point, keyfile or not, we're ready! + local cmd="${gpg_cmd}/sbin/cryptsetup" + cmd="${cmd} ${cryptsetup_opts} open ${luks_device} ${luks_dev_name}" + _crypt_exec "${luks_device}" "${cmd}" + local ret="${?}" + + # TODO(lxnay): WTF is this? + [ -e /dev/tty.org ] \ + && rm -f /dev/tty \ + && mv /dev/tty.org /dev/tty + + if [ "${ret}" = "0" ]; then + exit_st=0 + good_msg "LUKS device ${luks_device} opened" + + # This is fine if the crypt device is a physical device + # like /dev/sdaX, however, if we have cryptsetup inside + # LVM, we must tweak REAL_ROOT if there is no device node. + start_volumes # this should create /dev/mapper links + if echo "${real_dev}" | grep -q "^/dev/mapper/"; then + if [ ! -e "${real_dev}" ]; then + # WARN: while for ltype=SWAP this may not be a problem, + # for ltype=ROOT this may render the system unbootable + # because lvm can get angry to see a symlink where it's + # not supposed to be or we may fail to create the proper + # link (due to the if above), however, reordering the + # cmdline entries may solve this. + good_msg "Creating symlink ${luks_dev_name} -> ${real_dev}" + ln -s "${luks_dev_name}" "${real_dev}" || exit_st=1 + fi fi + + break fi - break - fi + bad_msg "Failed to open LUKS device ${luks_device}" + dev_error=1 + key_error=1 + keydev_error=1 + + done - bad_msg "Failed to open LUKS device ${LUKS_DEVICE}" - dev_error=1 - key_error=1 - keydev_error=1 done umount -l "${mntkey}" 2>/dev/null >/dev/null @@ -246,7 +268,7 @@ start_luks() { [ -n "${CRYPT_ROOT_KEY}" ] && [ -z "${CRYPT_ROOT_KEYDEV}" ] \ && sleep 6 && _bootstrap_key "ROOT" - if [ -n "${CRYPT_ROOT}" ]; then + if [ -n "${CRYPT_ROOTS}" ]; then if _open_luks "root"; then # force REAL_ROOT= to some value if not set # this is mainly for backward compatibility, @@ -259,9 +281,9 @@ start_luks() { # TODO(lxnay): this sleep 6 thing is hurting my eyes sooooo much. # same for swap, but no need to sleep if root was unencrypted [ -n "${CRYPT_SWAP_KEY}" ] && [ -z "${CRYPT_SWAP_KEYDEV}" ] \ - && { [ -z "${CRYPT_ROOT}" ] && sleep 6; _bootstrap_key "SWAP"; } + && { [ -z "${CRYPT_ROOTS}" ] && sleep 6; _bootstrap_key "SWAP"; } - if [ -n "${CRYPT_SWAP}" ]; then + if [ -n "${CRYPT_SWAPS}" ]; then if _open_luks "swap"; then # force REAL_RESUME= to some value if not set [ -z "${REAL_RESUME}" ] && REAL_RESUME="/dev/mapper/swap" diff --git a/defaults/initrd.d/00-livecd.sh b/defaults/initrd.d/00-livecd.sh index f483071..350267e 100755 --- a/defaults/initrd.d/00-livecd.sh +++ b/defaults/initrd.d/00-livecd.sh @@ -360,12 +360,12 @@ livecd_mount() { _cache_cd_contents # If encrypted, find key and mount, otherwise mount as usual - if [ -n "${CRYPT_ROOT}" ]; then + if [ -n "${CRYPT_ROOTS}" ]; then CRYPT_ROOT_KEY=$(head -n 1 "${CDROOT_PATH}/${CDROOT_MARKER}") - CRYPT_ROOT="$(losetup -f)" + CRYPT_ROOTS="$(losetup -f)" # support only one value for livecd good_msg "You booted an encrypted livecd" - losetup "${CRYPT_ROOT}" "${CDROOT_PATH}/${LOOPEXT}${LOOP}" + losetup "${CRYPT_ROOTS}" "${CDROOT_PATH}/${LOOPEXT}${LOOP}" test_success "Preparing loop filesystem" start_luks diff --git a/defaults/initrd.d/00-zfs.sh b/defaults/initrd.d/00-zfs.sh index 7df7056..7c9acc4 100755 --- a/defaults/initrd.d/00-zfs.sh +++ b/defaults/initrd.d/00-zfs.sh @@ -86,7 +86,7 @@ zfs_start_volumes() { if [ "${pools}" = "${ZFS_POOL}" ]; then good_msg "ZFS pool ${ZFS_POOL} already imported." - if [ -n "${CRYPT_ROOT}" ] || [ -n "${CRYPT_SWAP}" ]; then + if [ -n "${CRYPT_ROOTS}" ] || [ -n "${CRYPT_SWAPS}" ]; then good_msg "LUKS detected. Reimporting ${ZFS_POOL}" zpool export -f "${ZFS_POOL}" zpool import -N ${ZPOOL_FORCE} "${ZFS_POOL}" diff --git a/defaults/linuxrc b/defaults/linuxrc index eb7e14b..d690114 100755 --- a/defaults/linuxrc +++ b/defaults/linuxrc @@ -195,11 +195,26 @@ for x in ${CMDLINE}; do ;; crypt_root=*) - CRYPT_ROOT=${x#*=} + # kept for backward compatibility + CRYPT_ROOTS=${x#*=} ;; crypt_swap=*) - CRYPT_SWAP=${x#*=} + # kept for backward compatibility + CRYPT_SWAPS=${x#*=} ;; + + crypt_roots=*) + # The first entry will be the one that + # is going to be mapped to ${REAL_ROOT}. + # Multiple "roots" devices are needed + # in order to support multiple dmcrypts + # aggregated through software raid arrays. + CRYPT_ROOTS="${CRYPT_ROOTS} ${x#*=}" + ;; + crypt_swaps=*) + CRYPT_SWAPS="${CRYPT_SWAPS} ${x#*=}" + ;; + root_key=*) CRYPT_ROOT_KEY=${x#*=} ;; diff --git a/doc/genkernel.8.txt b/doc/genkernel.8.txt index 5fbfff0..2d6b988 100644 --- a/doc/genkernel.8.txt +++ b/doc/genkernel.8.txt @@ -398,10 +398,33 @@ which the ramdisk scripts would recognize. *crypt_root*=<...>:: This specifies the device encrypted by Luks, which contains the - root filesystem to mount. + root filesystem to mount. If you intend to use multiple devices + cooperating in the building of a single root device node (like + for instance in the case of dmcrypts -> software raid), please + use crypt_roots= instead. + +*crypt_roots*=<...>:: + This specifies the devices encrypted by Luks, which concur in + the availability of a device node used for the root filesystem. + For instance, you could have two separately encrypted partitions + on separate disks that are part of a software raid setup. You just + need to declare multiple crypt_roots= statements each one containing + one device path. Please keep in mind that the entries will be processed + in the order they are declared. If you use crypt_roots=, remember to + remove any reference to crypt_root=. They all share the same root_key= + and root_keydev=. *crypt_swap*=<...>:: - This specifies the swap device encrypted by Luks. + This specifies the swap device encrypted by Luks. If you have more than + one encrypted swap, please use crypt_swaps= instead. + +*crypt_swaps*=<...>:: + This specifies the swap devices encrypted by Luks. You just + need to declare multiple crypt_swaps= statements each one containing + one device path. Please keep in mind that the entries will be processed + in the order they are declared. If you use crypt_swaps=, remember to + remove any reference to crypt_swap=. They all share the same root_key= + and root_keydev=. *root_key*=<...>:: In case your root is encrypted with a key, you can use a device