| #!/sbin/openrc-run |
| # Copyright 1999-2015 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| depend() { |
| before checkfs fsck |
| |
| if grep -qs ^swap= "${conf_file}" ; then |
| before swap |
| fi |
| } |
| |
| # We support multiple dmcrypt instances based on $SVCNAME |
| conf_file="/etc/conf.d/${SVCNAME}" |
| |
| # Get splash helpers if available. |
| if [ -e /sbin/splash-functions.sh ] ; then |
| . /sbin/splash-functions.sh |
| fi |
| |
| # Setup mappings for an individual target/swap |
| # Note: This relies on variables localized in the main body below. |
| dm_crypt_execute() { |
| local dev ret mode foo |
| |
| if [ -z "${target}" -a -z "${swap}" ] ; then |
| return |
| fi |
| |
| # Set up default values. |
| : ${dmcrypt_key_timeout:=1} |
| : ${dmcrypt_max_timeout:=300} |
| : ${dmcrypt_retries:=5} |
| |
| # Handle automatic look up of the source path. |
| if [ -z "${source}" -a -n "${loop_file}" ] ; then |
| source=$(losetup --show -f "${loop_file}") |
| fi |
| case ${source} in |
| *=*) |
| source=$(blkid -l -t "${source}" -o device) |
| ;; |
| esac |
| if [ -z "${source}" ] || [ ! -e "${source}" ] ; then |
| ewarn "source \"${source}\" for ${target} missing, skipping..." |
| return |
| fi |
| |
| if [ -n "${target}" ] ; then |
| # let user set options, otherwise leave empty |
| : ${options:=' '} |
| elif [ -n "${swap}" ] ; then |
| if cryptsetup isLuks ${source} 2>/dev/null ; then |
| ewarn "The swap you have defined is a LUKS partition. Aborting crypt-swap setup." |
| return |
| fi |
| target=${swap} |
| # swap contents do not need to be preserved between boots, luks not required. |
| # suspend2 users should have initramfs's init handling their swap partition either way. |
| : ${options:='-c aes -h sha1 -d /dev/urandom'} |
| : ${pre_mount:='mkswap ${dev}'} |
| fi |
| |
| if [ -n "${loop_file}" ] ; then |
| dev="/dev/mapper/${target}" |
| ebegin " Setting up loop device ${source}" |
| losetup ${source} ${loop_file} |
| fi |
| |
| # cryptsetup: |
| # open <device> <name> # <device> is $source |
| # create <name> <device> # <name> is $target |
| local arg1="create" arg2="${target}" arg3="${source}" |
| if cryptsetup isLuks ${source} 2>/dev/null ; then |
| arg1="open" |
| arg2="${source}" |
| arg3="${target}" |
| fi |
| |
| # Older versions reported: |
| # ${target} is active: |
| # Newer versions report: |
| # ${target} is active[ and is in use.] |
| if cryptsetup status ${target} | egrep -q ' is active' ; then |
| einfo "dm-crypt mapping ${target} is already configured" |
| return |
| fi |
| splash svc_input_begin ${SVCNAME} >/dev/null 2>&1 |
| |
| # Handle keys |
| if [ -n "${key}" ] ; then |
| read_abort() { |
| # some colors |
| local ans savetty resettty |
| [ -z "${NORMAL}" ] && eval $(eval_ecolors) |
| einfon " $1? (${WARN}yes${NORMAL}/${GOOD}No${NORMAL}) " |
| shift |
| # This is ugly as s**t. But POSIX doesn't provide `read -t`, so |
| # we end up having to implement our own crap with stty/etc... |
| savetty=$(stty -g) |
| resettty='stty ${savetty}; trap - EXIT HUP INT TERM' |
| trap 'eval "${resettty}"' EXIT HUP INT TERM |
| stty -icanon |
| stty min 0 time "$(( $2 * 10 ))" |
| ans=$(dd count=1 bs=1 2>/dev/null) || ans='' |
| eval "${resettty}" |
| if [ -z "${ans}" ] ; then |
| printf '\r' |
| else |
| echo |
| fi |
| case ${ans} in |
| [yY]) return 0;; |
| *) return 1;; |
| esac |
| } |
| |
| # Notes: sed not used to avoid case where /usr partition is encrypted. |
| mode=${key##*:} && ( [ "${mode}" = "${key}" ] || [ -z "${mode}" ] ) && mode=reg |
| key=${key%:*} |
| case "${mode}" in |
| gpg|reg) |
| # handle key on removable device |
| if [ -n "${remdev}" ] ; then |
| # temp directory to mount removable device |
| local mntrem="${RC_SVCDIR}/dm-crypt-remdev.$$" |
| if [ ! -d "${mntrem}" ] ; then |
| if ! mkdir -p "${mntrem}" ; then |
| ewarn "${source} will not be decrypted ..." |
| einfo "Reason: Unable to create temporary mount point '${mntrem}'" |
| return |
| fi |
| fi |
| i=0 |
| einfo "Please insert removable device for ${target}" |
| while [ ${i} -lt ${dmcrypt_max_timeout} ] ; do |
| foo="" |
| if mount -n -o ro "${remdev}" "${mntrem}" 2>/dev/null >/dev/null ; then |
| # keyfile exists? |
| if [ ! -e "${mntrem}${key}" ] ; then |
| umount -n "${mntrem}" |
| rmdir "${mntrem}" |
| einfo "Cannot find ${key} on removable media." |
| read_abort "Abort" ${dmcrypt_key_timeout} && return |
| else |
| key="${mntrem}${key}" |
| break |
| fi |
| else |
| [ -e "${remdev}" ] \ |
| && foo="mount failed" \ |
| || foo="mount source not found" |
| fi |
| : $((i += 1)) |
| read_abort "Stop waiting after $i attempts (${foo})" -t 1 && return |
| done |
| else # keyfile ! on removable device |
| if [ ! -e "${key}" ] ; then |
| ewarn "${source} will not be decrypted ..." |
| einfo "Reason: keyfile ${key} does not exist." |
| return |
| fi |
| fi |
| ;; |
| *) |
| ewarn "${source} will not be decrypted ..." |
| einfo "Reason: mode ${mode} is invalid." |
| return |
| ;; |
| esac |
| else |
| mode=none |
| fi |
| ebegin " ${target} using: ${options} ${arg1} ${arg2} ${arg3}" |
| if [ "${mode}" = "gpg" ] ; then |
| : ${gpg_options:='-q -d'} |
| # gpg available ? |
| if command -v gpg >/dev/null ; then |
| i=0 |
| while [ ${i} -lt ${dmcrypt_retries} ] ; do |
| # paranoid, don't store key in a variable, pipe it so it stays very little in ram unprotected. |
| # save stdin stdout stderr "values" |
| timeout ${dmcrypt_max_timeout} gpg ${gpg_options} ${key} 2>/dev/null | \ |
| cryptsetup --key-file - ${options} ${arg1} ${arg2} ${arg3} |
| ret=$? |
| # The timeout command exits 124 when it times out. |
| [ ${ret} -eq 0 -o ${ret} -eq 124 ] && break |
| : $(( i += 1 )) |
| done |
| eend ${ret} "failure running cryptsetup" |
| else |
| ewarn "${source} will not be decrypted ..." |
| einfo "Reason: cannot find gpg application." |
| einfo "You have to install app-crypt/gnupg first." |
| einfo "If you have /usr on its own partition, try copying gpg to /bin ." |
| fi |
| else |
| if [ "${mode}" = "reg" ] ; then |
| cryptsetup ${options} -d ${key} ${arg1} ${arg2} ${arg3} |
| ret=$? |
| eend ${ret} "failure running cryptsetup" |
| else |
| cryptsetup ${options} ${arg1} ${arg2} ${arg3} |
| ret=$? |
| eend ${ret} "failure running cryptsetup" |
| fi |
| fi |
| if [ -d "${mntrem}" ] ; then |
| umount -n ${mntrem} 2>/dev/null >/dev/null |
| rmdir ${mntrem} 2>/dev/null >/dev/null |
| fi |
| splash svc_input_end ${SVCNAME} >/dev/null 2>&1 |
| |
| if [ ${ret} -ne 0 ] ; then |
| cryptfs_status=1 |
| else |
| if [ -n "${pre_mount}" ] ; then |
| dev="/dev/mapper/${target}" |
| eval ebegin \"" pre_mount: ${pre_mount}"\" |
| eval "${pre_mount}" > /dev/null |
| ewend $? || cryptfs_status=1 |
| fi |
| fi |
| } |
| |
| # Lookup optional bootparams |
| get_bootparam_val() { |
| # We're given something like: |
| # foo=bar=cow |
| # Return the "bar=cow" part. |
| case $1 in |
| *=*) |
| echo "${1#*=}" |
| ;; |
| esac |
| } |
| |
| start() { |
| local header=true cryptfs_status=0 |
| local gpg_options key loop_file target targetline options pre_mount post_mount source swap remdev |
| |
| local x |
| for x in $(cat /proc/cmdline) ; do |
| case "${x}" in |
| key_timeout=*) |
| dmcrypt_key_timeout=$(get_bootparam_val "${x}") |
| ;; |
| esac |
| done |
| |
| while read targetline <&3 ; do |
| case ${targetline} in |
| # skip comments and blank lines |
| ""|"#"*) continue ;; |
| # skip service-specific openrc configs #377927 |
| rc_*) continue ;; |
| esac |
| |
| ${header} && ebegin "Setting up dm-crypt mappings" |
| header=false |
| |
| # check for the start of a new target/swap |
| case ${targetline} in |
| target=*|swap=*) |
| # If we have a target queued up, then execute it |
| dm_crypt_execute |
| |
| # Prepare for the next target/swap by resetting variables |
| unset gpg_options key loop_file target options pre_mount post_mount source swap remdev |
| ;; |
| |
| gpg_options=*|remdev=*|key=*|loop_file=*|options=*|pre_mount=*|post_mount=*|source=*) |
| if [ -z "${target}${swap}" ] ; then |
| ewarn "Ignoring setting outside target/swap section: ${targetline}" |
| continue |
| fi |
| ;; |
| |
| dmcrypt_*=*) |
| # ignore global options |
| continue |
| ;; |
| |
| *) |
| ewarn "Skipping invalid line in ${conf_file}: ${targetline}" |
| ;; |
| esac |
| |
| # Queue this setting for the next call to dm_crypt_execute |
| eval "${targetline}" |
| done 3< ${conf_file} |
| |
| # If we have a target queued up, then execute it |
| dm_crypt_execute |
| |
| ewend ${cryptfs_status} "Failed to setup dm-crypt devices" |
| } |
| |
| stop() { |
| local line header |
| |
| # Break down all mappings |
| header=true |
| egrep "^(target|swap)=" ${conf_file} | \ |
| while read line ; do |
| ${header} && einfo "Removing dm-crypt mappings" |
| header=false |
| |
| target= swap= |
| eval ${line} |
| |
| [ -n "${swap}" ] && target=${swap} |
| if [ -z "${target}" ] ; then |
| ewarn "invalid line in ${conf_file}: ${line}" |
| continue |
| fi |
| |
| ebegin " ${target}" |
| cryptsetup remove ${target} |
| eend $? |
| done |
| |
| # Break down loop devices |
| header=true |
| grep '^source=./dev/loop' ${conf_file} | \ |
| while read line ; do |
| ${header} && einfo "Detaching dm-crypt loop devices" |
| header=false |
| |
| source= |
| eval ${line} |
| |
| ebegin " ${source}" |
| losetup -d "${source}" |
| eend $? |
| done |
| |
| return 0 |
| } |