[Bug 55159] Re: usplash prevents passwords from being not echoed on the console

Luke lukekuhn at hotmail.com
Thu Apr 9 14:26:37 UTC 2009


FIX FOR BOTH HARDY AND JAUNTY:

Some time back, I modified /lib/cnryptsetup/cryptdisks.functions to make
Usplash work to mount a non-root LUKS partition in Hardy. The working
principle is this: On b oth my AMD 64 single core and my Intel Atom, if
you type the passphrase with Usplash running while cryptsetup is waiting
for it, it goes right to cryptsetup same as if the console was showing,
though there would be no prompt to tell you  when to type it!

This altered code drops the usplash_write "quit" line from Hardy's
version, and uses Usplash_write's VERBOSE and TEXT functions to prompt
just before cryptsetup runs-but does NOT try to use anything like
askpass or usplash_write_inputquiet due to bugs.

Since the Jaunty version leaves the password on the console, I must
assume it would be easier for an attacker to scan all memory and
recognize the password than it would be to recognize the actual key.
This is unacceptable, so I have rolled back to my own code.


Here's the new cryptdisks.functions  Cut and paste into gedit, etc and save as /lib/cryptdisks.functions as root after backing up the original file: 
##########################################################


#
# This file is for inclusion with
#	. /lib/cryptsetup/cryptdisks.functions
# and should not be executed directly.

PATH="/sbin:/bin"
TABFILE=/etc/crypttab
CRYPTDISKS_ENABLE="Yes"

#set -x

# Sanity checks
[ -x /sbin/cryptsetup ] || exit 0
[ -f "$TABFILE"       ] || exit 0

. /lib/lsb/init-functions

if [ -r /etc/default/cryptdisks ]; then
	. /etc/default/cryptdisks
fi

MOUNT="$CRYPTDISKS_MOUNT"

case "$CRYPTDISKS_ENABLE" in
[Nn]*)
	exit 0
	;;
esac

# Always output to console
stdin=`readlink /proc/self/fd/0`
if [ "${stdin#/dev/null}" != "$stdin" ] && [ "$ON_VT" != "yes" ]; then
    exec env ON_VT=yes /usr/bin/openvt -f -c `fgconsole` -w $0 "$@"
fi

# Parses the option field from the crypttab file
parse_opts () {
	local opts opt IFS PARAM VALUE

	opts="$1"
	LOUD=""
	PARAMS=""
	CHECK=""
	CHECKARGS=""
	PRECHECK=""
	TRIES="3"
	MAKETMP=""
	MAKESWAP=""
	USELUKS=""
	TIMEOUT=""
	KEYSCRIPT=""

	# Parse the options field, convert to cryptsetup parameters
	# and construct the command line
	IFS=','
	for opt in $opts; do
		PARAM=$(echo "$opt" | sed 's/=.*//')
		VALUE=$(echo "$opt" | sed '/=/!d;s/^.*=//')
		
		case "$PARAM" in 
		readonly)
			PARAMS="$PARAMS -r"
			;;
		cipher)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for cipher option, skipping"
				return 1
			fi
			PARAMS="$PARAMS -c $VALUE"
			;;
		size)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for size option, skipping"
				return 1
			fi
			PARAMS="$PARAMS -s $VALUE"
			;;
		hash)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for hash option, skipping"
				return 1
			fi
			PARAMS="$PARAMS -h $VALUE"
			;;
		verify)
			PARAMS="$PARAMS -y"
			;;
		check)
			if [ -z "$VALUE" ]; then
				VALUE="$CRYPTDISKS_CHECK"
			fi
			if [ -x "$VALUE" ]; then
				CHECK="$VALUE"
			elif [ -x "/lib/cryptsetup/checks/$VALUE" ]; then
				CHECK="/lib/cryptsetup/checks/$VALUE"
			else
				log_warning_msg "check $VALUE is not an executable script, skipping"
				return 1
			fi
			;;
		checkargs)
			if [ -n "$VALUE" ]; then
				CHECKARGS="$VALUE"
			fi
			;;
		precheck)
			if [ -z "$VALUE" ]; then
				VALUE="$CRYPTDISKS_PRECHECK"
			fi
			if [ -x "$VALUE" ]; then
				PRECHECK="$VALUE"
			elif [ -x "/lib/cryptsetup/checks/$VALUE" ]; then
				PRECHECK="/lib/cryptsetup/checks/$VALUE"
			else
				log_warning_msg "precheck $VALUE is not an executable script, skipping"
				return 1
			fi
			;;
		tries)
			if echo "$VALUE" | grep -q "^[[:digit:]]\+$" && [ "$VALUE" -gt 0 ]; then
				TRIES="$VALUE"
			else
				log_warning_msg "$dst: option tries used with an incorrect argument - forced to $TRIES"
			fi
			PARAMS="$PARAMS --tries=$TRIES"
			;;
		timeout)
			if [ -z "$VALUE" ]; then
				TIMEOUT="$CRYPTDISKS_TIMEOUT"
			elif echo "$VALUE" | grep -q "^[[:digit:]]\+$"; then
				TIMEOUT="$VALUE"
			else
				log_warning_msg "$dst: option timeout used with an incorrect argument - forced to '$TIMEOUT'"
			fi
			PARAMS="$PARAMS --timeout=$TIMEOUT"
			;;
		swap)
			MAKESWAP=yes
			SWCHECK="/lib/cryptsetup/checks/un_vol_id"
			SWCHECKARGS="swap"
			;;
		tmp)
			MAKETMP=yes
			;;
		luks)
			USELUKS=yes
			;;
		loud)
			LOUD=yes
			;;
		keyscript)
			if [ -n "$KEYSCRIPT" ]; then
				log_warning_msg "$dst: multiple key decryption options are not allowed together, skipping"
				return 1
			elif [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for keyscript option, skipping"
				return 1
			fi
			KEYSCRIPT="$VALUE"
			;;
		esac
	done

	return 0
}

# Set up loopback devices
lo_setup () {
	local loopdev

	if [ ! -f "$src" ]; then
		return 0
	fi

	if [ ! -x /sbin/losetup ]; then
		return 1
	fi

	if ! grep -q "[[:space:]]loop$" /proc/devices; then
		modprobe -qb loop > /dev/null 2>&1 || return 1
	fi

        loopdev=$(losetup -f 2> /dev/null) || return 1

	losetup "$loopdev" "$src" || return 1
	src="$loopdev"
	return 0
}

# Sanity check for keys
check_key () {
	local GMODE OMODE OWNER GROUP

	# If the keyscript option is set, the "key" is just an argument to
	# the keyscript and not necessarily a file
	if [ -n "$KEYSCRIPT" ]; then
		return 0
	fi

	if [ -z "$key" ] || [ "$key" = "none" ]; then
		INTERACTIVE="yes"
		return 0
	fi
	INTERACTIVE="no"

	if [ ! -e "$key" ]; then
		log_warning_msg "$dst: keyfile not found"
		return 1
	fi

	# stat is unfortunately in /usr/bin...
	OMODE=$(ls -l "$key" | sed 's/[[:space:]].*//;s/^.\{7\}//')
	GMODE=$(ls -l "$key" | sed 's/[[:space:]].*//;s/^.\{4\}\(.\{3\}\).*/\1/')
	GROUP=$(ls -l "$key" | sed 's/^.\{11\}[^[:space:]]* [^[:space:]]* \([^[:space:]]*\).*/\1/')
	OWNER=$( ls -l "$key" | sed 's/^.\{11\}[^[:space:]]* \([^[:space:]]*\).*/\1/')

	# LUKS requires a persistent key, /dev/*random is not supported
	if [ "$USELUKS" = "yes" ] && [ "$key" != "${key%random}" ]; then
		log_warning_msg "$dst: LUKS does not work with random data as key"
		return 1
	fi

	# Check owner
	if [ "$OWNER" != "root" ]; then
		log_warning_msg "$dst: INSECURE OWNER FOR $key, see /usr/share/doc/cryptsetup/README.Debian."
	fi

	# If key is random, we're done
	if [ "$key" != "${key%random}" ]; then
		return 0
	fi

	# Check group and other permissions
	if [ "$OMODE" != "---" ] || [ "$GROUP" != "root" ] && [ "$GMODE" != "---" ]; then
		log_warning_msg "$dst: INSECURE MODE FOR $key, see /usr/share/doc/cryptsetup/README.Debian."
	fi

	return 0
}

# Setup a luks mapping
do_luks () {
	local tried
	tried=0

	if ! cryptsetup isLuks "$src" >/dev/null 2>&1; then
		log_warning_msg "$dst: device '$src' is not a LUKS partition, skipping"
		return 1
	fi

	if [ -n "$KEYSCRIPT" ]; then
		PARAMS="$PARAMS --key-file=-"
		while [ "$tried" -lt "$TRIES" ]; do
			if "$KEYSCRIPT" "$key" <&1 | cryptsetup $PARAMS luksOpen "$src" "$dst"; then
				break
			fi
			tried=$(( $tried + 1 ))
		done
	elif [ "$INTERACTIVE" != "yes" ]; then
		PARAMS="$PARAMS --key-file=$key"
		while [ "$tried" -lt "$TRIES" ]; do
			if cryptsetup $PARAMS luksOpen "$src" "$dst" <&1; then
				break
			fi
			tried=$(( $tried + 1 ))
		done
	else
		if test "x$INTERACTIVE" != "xyes" ; then
			PARAMS="$PARAMS --key-file=$key"
			cryptsetup $PARAMS luksOpen $src $dst <&1
		else
#####  # BEGIN LOCAL CHANGE########################################################################
			#if [ -x /sbin/usplash_write -a -p /dev/.initramfs/usplash_outfifo ]; then
			#     	/sbin/usplash_write "QUIT"
			#	# saftey sleep !
			#	sleep 2
			#fi
                        ## prompt through Usplash for password
                        usplash_write "VERBOSE on"
                        usplash_write "CLEAR"
                        usplash_write "TIMEOUT 0"
                        usplash_write "TEXT Enter LUKS Passphrase,Ret 3x to ignore encrypted volume"
			cryptsetup $PARAMS luksOpen $src $dst <&1  ##This line from original scritp###
                        usplash_write "SUCCESS OK"
                        usplash_write "TEXT key slot 0 unlocked: Encrypted Filesystem in us"
                        usplash_write "VERBOSE default"
#####  # END LOCAL CHANGE ###########################################################################

		fi
	fi

	if [ "$tried" -ge "$TRIES" ]; then
		return 1
	fi

	if [ -n "$CHECK" ] && ! "$CHECK" "/dev/mapper/$dst" $CHECKARGS; then
		log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed"
		cryptsetup luksClose $dst
		return 1
	fi

	return 0
}

# Setup a regular mapping
do_noluks () {
	local pre_out tried
	tried=0

	if [ -z "$PRECHECK" ]; then
		PRECHECK="/lib/cryptsetup/checks/un_vol_id"
	fi

	if ! pre_out=$("$PRECHECK" "$src" 2> /dev/null) && \
	   [ "$MAKESWAP" != "yes" ] && \
	   ! /lib/cryptsetup/checks/vol_id "$src" swap >/dev/null; then
		log_warning_msg "$dst: the precheck for '$src' failed: $pre_out"
		return 1
	fi

	if [ -n "$KEYSCRIPT" ]; then
		PARAMS="$PARAMS --key-file=-"
	elif [ "$INTERACTIVE" != "yes" ]; then
		PARAMS="$PARAMS --key-file=$key"
	fi

	while [ "$tried" -lt "$TRIES" ]; do
		if [ -n "$KEYSCRIPT" ]; then
			"$KEYSCRIPT" "$key" <&1 | cryptsetup $PARAMS create "$dst" "$src"
		else
			cryptsetup $PARAMS create "$dst" "$src" <&1
		fi

		if [ -z "$CHECK" ] || "$CHECK" "/dev/mapper/$dst" $CHECKARGS; then
			break
		else
			log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed - maybe the password is wrong"
			cryptsetup remove "$dst"
		fi
		tried=$(( $tried + 1 ))
	done

	if [ "$tried" -ge "$TRIES" ]; then
		return 1
	fi

	return 0
}

# Premounts file systems
mount_fs () {
	local point
	MOUNTED=""

	for point in $MOUNT; do
		if mount "$point" >/dev/null; then
			MOUNTED="$MOUNTED $point"
		fi
	done
}

# Postunmounts file systems
umount_fs () {
	local point

	for point in $MOUNTED; do
		umount "$point" >/dev/null
	done
}

# Prepares swap partitions using random keys
do_swap () {
	local swap_out

	if [ "$MAKESWAP" != "yes" ] || [ ! -b "/dev/mapper/$dst" ]; then
		return 0
	fi

	if swap_out=$(/lib/cryptsetup/checks/un_vol_id "/dev/mapper/$dst" 2> /dev/null) || \
	   /lib/cryptsetup/checks/vol_id "/dev/mapper/$dst" swap > /dev/null 2>&1; then
		mkswap "/dev/mapper/$dst" > /dev/null 2>&1
	else
		log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed. /dev/mapper/$dst contains data: $swap_out"
		do_close
		return 1
	fi

	return 0
}

# Prepares tmp partitions using random keys
do_tmp () {
	if [ "$MAKETMP" != "yes" ] || [ ! -b "/dev/mapper/$dst" ]; then
		return 0
	fi

	mke2fs "/dev/mapper/$dst" > /dev/null 2>&1 || return 1
	mount -t ext2 "/dev/mapper/$dst" /tmp || return 1
	chmod 1777 /tmp
	umount /tmp
	return 0
}

# Removes a mapping
do_close () {
	local found IFS opt

	found="no"
	IFS=','
	for opt in $opts; do
		if [ "$opt" = "luks" ]; then
			found="yes"
			break
		fi
	done

	if [ "$found" = "yes" ]; then
		cryptsetup luksClose "$dst"
	else
		cryptsetup remove "$dst"
	fi
	return $?
}

load_optimized_aes_module () {
        local asm_module modulesdir

        # find directory with kernel modules
        modulesdir="/lib/modules/`uname -r`"
        # Add assembly optimized AES module if it exists
        asm_module=`ls -1 "$modulesdir"/kernel/arch/*/*/aes*.ko`
        if [ $asm_module ];then
           insmod $asm_module 2>/dev/null || true
        fi
}

# Sets up all entries in crypttab
do_start () {
	local dst src key opts result

	modprobe -qb dm-mod || true
	modprobe -qb dm-crypt || true
	dmsetup mknodes > /dev/null 2>&1 || true
	log_action_begin_msg "Starting $INITSTATE crypto disks"
	load_optimized_aes_module
	mount_fs

        egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src
key opts; do

		# Make sure that all fields are present
		if [ -z "$dst" ]; then
			continue
		elif [ -z "$src" ] || [ -z "$key" ] || [ -z "$opts" ]; then
			device_msg "$dst" "skipped, missing parameters"
			continue
		fi

		# parse UUID= symlinks
		if [ ${src#UUID=} != $src ]; then
			src="/dev/disk/by-uuid/${src#UUID=}"
		elif [ ${src#LABEL=} != $src ]; then
			src="/dev/disk/by-label/${src#LABEL=}"
		fi

		# Make sure source device exists
		if [ ! -r "$src" ]; then
			if [ "$LOUD" = "yes" ]; then
				device_msg "$dst" "skipped, device $src does not exist"
			fi
			continue
		fi

		# Make sure that target device doesn't exist
		if [ -b "/dev/mapper/$dst" ]; then
			device_msg "$dst" "running"
			continue
		fi

		# All checks passed, do the preparatory steps
		if ! parse_opts "$opts"; then
			device_msg "$dst" "invalid opts"
			continue
		elif ! check_key; then
			device_msg "$dst" "invalid key"
			continue
		elif ! lo_setup; then
			device_msg "$dst" "loopback failed"
		fi

		# Do the real setup
		log_progress_msg "$dst (starting)"
		result="ok"
		if [ "$USELUKS" = "yes" ]; then
			do_luks || result="fail"
		else
			do_noluks || result="fail"
		fi

		# Finish up
		if [ "$result" != "ok" ]; then
			log_progress_msg "$dst (failed)"
		else
			do_swap
			do_tmp
			log_progress_msg "$dst (started)"
		fi
	done

	umount_fs
	log_action_end_msg 0
}

# Removes all mappings in crypttab
do_stop () {
	local dst src key opts opencount major minor loopmajor

	dmsetup mknodes
	log_action_begin_msg "Stopping $INITSTATE crypto disks"
	loopmajor=$(grep "[[:space:]]*loop$" /proc/devices | sed 's/^[[:space:]]*//;s/[[:space:]].*//')

	egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src key opts; do
		if [ ! -b "/dev/mapper/$dst" ]; then
			device_msg "$dst" "stopped"
			continue
		fi

		opencount=$(dmsetup info -c --noheadings -o open "$dst" 2> /dev/null)
		if [ -z "$opencount" ]; then
			device_msg "$dst" "error"
			continue
		elif [ "$opencount" != "0" ]; then
			device_msg "$dst" "busy"
			continue
		fi

		major=$(dmsetup info -c --noheadings -o major "$dst" 2> /dev/null)
		minor=$(dmsetup info -c --noheadings -o minor "$dst" 2> /dev/null)

		if [ -z "$major" ] || [ -z "$minor" ]; then
			device_msg "$dst" "error"
			continue
		fi

		do_close
		log_action_cont_msg "$dst (stopping)"

		# Detach loopback device, if attached
		if [ -f "$src" ] && [ -n "$loopmajor" ] && [ "$loopmajor" = "$major" ]; then 
			losetup -d "/dev/loop$minor" > /dev/null 2>&1 || true
		fi
	done

	log_action_end_msg 0
}

# Convenience function to handle $VERBOSE
device_msg () {
	local dst msg
	dst="$1"
	msg="$2"

	if [ "$VERBOSE" != "no" ]; then
		log_action_cont_msg "$dst ($msg)"
	fi
}

** Attachment added: "Alternate /lib/cryptsetup/cryptdisks.functions"
   http://launchpadlibrarian.net/25113038/cryptdisks.functions

-- 
usplash prevents passwords from being not echoed on the console
https://bugs.launchpad.net/bugs/55159
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.

-- 
ubuntu-bugs mailing list
ubuntu-bugs at lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs




More information about the universe-bugs mailing list