123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #!/usr/bin/openrc-run
- # Copyright 1999-2015 Gentoo Foundation
- # Distributed under the terms of the GNU General Public License v2
- depend() {
- use modules
- 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 /usr/bin/splash-functions.sh ] ; then
- . /usr/bin/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 source_dev
- if [ -z "${target}" -a -z "${swap}" ] ; then
- return
- fi
- # Set up default values.
- : ${dmcrypt_key_timeout:=1}
- : ${dmcrypt_max_timeout:=300}
- : ${dmcrypt_retries:=5}
- : ${wait:=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
- *=*)
- i=0
- while [ ${i} -lt ${wait} ]; do
- if source_dev="$(blkid -l -t "${source}" -o device)"; then
- source="${source_dev}"
- break
- fi
- : $((i += 1))
- einfo "waiting for source \"${source}\" for ${target}..."
- sleep 1
- done
- ;;
- 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 wait
- ;;
- gpg_options=*|remdev=*|key=*|loop_file=*|options=*|pre_mount=*|post_mount=*|wait=*|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
- }
|