#!/sbin/runscript # Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/sys-fs/cryptsetup/files/1.5.1-dmcrypt.rc,v 1.1 2013/01/17 23:35:08 robbat2 Exp $ depend() { before checkfs fsck } # We support multiple dmcrypt instances based on $SVCNAME execute_hook="dm_crypt_execute_dmcrypt" # XXX: Should we drop this ? # execute_hook="dm_crypt_execute_localmount" 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_dmcrypt() { local dev ret mode foo 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}'} else return fi if [ "x${source#UUID}" != "x${source}" ]; then source=${source#UUID=} source="$(blkid -U ${source})" fi if [ -z "${source}" ] && [ ! -e "${source}" ] ; then ewarn "source \"${source}\" for ${target} missing, skipping..." return fi if [ -n "${loop_file}" ] ; then dev="/dev/mapper/${target}" ebegin " Setting up loop device ${source}" losetup ${source} ${loop_file} fi # cryptsetup: # luksOpen # is $source # create # is $target local arg1="create" arg2="${target}" arg3="${source}" luks=0 cryptsetup isLuks ${source} 2>/dev/null && { arg1="luksOpen"; arg2="${source}"; arg3="${target}"; luks=1; } # 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 [ "${1}" = -t ] && 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:-120} ] ; 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" ${read_timeout:--t 1} && 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 type -p gpg >/dev/null ; then for i in 0 1 2 ; do # paranoid, don't store key in a variable, pipe it so it stays very little in ram unprotected. # save stdin stdout stderr "values" gpg ${gpg_options} ${key} 2>/dev/null | cryptsetup ${options} ${arg1} ${arg2} ${arg3} ret=$? [ ${ret} -eq 0 ] && break 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}" ebegin " pre_mount: ${pre_mount}" eval "${pre_mount}" > /dev/null ewend $? || cryptfs_status=1 fi fi } # Run any post_mount commands for an individual mount # # Note: This relies on variables localized in the main body below. dm_crypt_execute_localmount() { local mount_point [ -z "${target}" ] && [ -z "${post_mount}" ] && return if ! cryptsetup status ${target} | egrep -q '\/dev/null eend $? || cryptfs_status=1 fi } # Lookup optional bootparams get_bootparam_val() { # We're given something like: # foo=bar=cow # Return the "bar=cow" part. case $1 in *\=*) local key=$(echo "$1" | cut -f1 -d=) echo "$1" | cut -c $(( ${#key} + 2 )) ;; 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\=*) local KEY_TIMEOUT=$(get_bootparam_val "${x}") if [ ${KEY_TIMEOUT} -gt 0 ] ; then read_timeout="-t ${KEY_TIMEOUT}" fi ;; esac done while read -u 3 targetline ; 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 ${execute_hook} # 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_max_timeout=*) # ignore global options continue ;; *) ewarn "Skipping invalid line in ${conf_file}: ${targetline}" ;; esac # Queue this setting for the next call to dm_crypt_execute_xxx eval "${targetline}" done 3< ${conf_file} # If we have a target queued up, then execute it ${execute_hook} 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 }