[Pkg-cryptsetup-devel] Bug#358452: cryptsetup: new version of scripts

David Härdeman david at 2gen.com
Sat Apr 8 23:29:25 UTC 2006


Hey,

this is an updated version of the hook and script for adding cryptoroot 
functionality to cryptsetup/initramfs.

The script has seen minor changes to address the issues raised by 
Maximilian, while the hook script has undergone some major changes.

It now expects the root volume to be present in /etc/crypttab, and if it 
is, the modules to include in the initramfs are decided by looking at 
the /etc/crypttab options.

The settings are then automatically added to the generated initramfs 
image.

As for compability with the (old) initrd ways of doing thing, as far as 
I could tell, initrd simply deduced at build time whether or not root 
was encrypted and then hardcoded that knowledge within the initrd, so 
there is no mismatch in options between the two as initrd had none...

Regards,
David

PS
This should of course still not be applied until after 348147 is fixed.

-------------- next part --------------
#!/bin/sh

PREREQ=""

prereqs()
{
	echo "$PREREQ"
}

case $1 in
prereqs)
	prereqs
	exit 0
	;;
esac

. /usr/share/initramfs-tools/hook-functions

find_root_device() {
	[ -r /etc/fstab ] || return

	grep '^[^#]' /etc/fstab | ( \
	while read device mount type options dump pass; do
		if [ "$mount" = "/" ]; then
			echo "$device"
			return
		fi
	done )
}

get_root_opts() {
	local node rootopts
	node=$1

	[ -z $node ] && return
	[ -r /etc/crypttab ] || return

	rootopts=$( grep ^$node /etc/crypttab | \
		    head -1 | sed 's/[[:space:]]+*/ /g' | cut -d " " -f 4-)
	echo "$rootopts"
	[ ! -z $rootopts ] || return 1
	return 0
}

get_root_modules() {
	local rootopts
	rootopts=$1

	[ ! -z $rootopts ] || return

	echo "dm_mod"
	echo "dm_crypt"
	local IFS=", "
	for opt in $rootopts; do
		# Does option start with cipher=?
		value=${opt#cipher=}
		[ $value != $opt ] || continue

		# Add the cipher to the list of modules
		cipher=${value%%-*}
		echo $cipher

		# Possibly add a hash as well
		hash=${value##*:}
		[ ! -z $hash -o $hash != $value ] || continue
		echo $hash
	done
}

get_root_initramfsopts() {
	local rootnode rootopts
	rootnode=$1
	rootopts=$2

	[ ! -z $rootnode ] || return
	[ ! -z $rootopts ] || return

	echo -n "node=$rootnode"
	local IFS=", "
	for opt in $rootopts; do
		case $opt in
			cipher=*)
				echo -n ",$opt"
				;;
			hash=*)
				echo -n ",$opt"
				;;
			size=*)
				echo -n ",$opt"
				;;
			*)
				# Presumably a non-supported option
				;;
		esac
	done
	echo ""
}

# Find out which device root is on
rootdev=$(find_root_device)
[ ! -z $rootdev ] || exit 0

# Check that it is a node under /dev/mapper/
node=${rootdev#/dev/mapper/}
[ "$node" != $rootdev ] || exit 0

# Get crypttab root options
rootopts=$(get_root_opts $node $opts)
[ ! -z $rootopts ] || exit 0

# Calculate needed modules
modules=$(get_root_modules $rootopts | sort | uniq)
for x in $modules; do
	manual_add_modules ${x}
done

# Check the root options to write to the initramfs
initramfsopts=$(get_root_initramfsopts $node $rootopts)
echo "CRYPTOPTS=\"$initramfsopts\"" > ${DESTDIR}/conf/conf.d/cryptroot

copy_exec /sbin/cryptsetup /sbin
copy_exec /sbin/dmsetup /sbin
[ -x "/etc/mkinitramfs/cryptgetpw" ] && copy_exec /etc/mkinitramfs/cryptgetpw /sbin

exit 0
-------------- next part --------------
#!/bin/sh

PREREQ=""

prereqs()
{
	echo "$PREREQ"
}

case $1 in
# get pre-requisites
prereqs)
	prereqs
	exit 0
	;;
esac

# Do we have any settings from the /conf/conf.d/cryptroot file?
[ -r /conf/conf.d/cryptroot ] && . /conf/conf.d/cryptroot
cryptopts="${CRYPTOPTS}"

# Does the kernel boot command line override them?
for x in $(cat /proc/cmdline); do
	case $x in
	cryptopts=*)
		cryptopts=${x#cryptopts=}
		;;
	esac
done

# Sanity checks
eval $(fstype < ${ROOT})
if [ "$FSTYPE" != "luks" -a -z "$cryptopts" ]; then
	# Apparently the root partition isn't encrypted
	echo "No cryptoroot configured or detected"
	exit 0
fi

# There are two possible scenarios here:
#
# 1) The fstype of the root device has been identified as "luks"
# 2) The fstype is not "luks" but cryptopts has been set
#
# The former means that we use the luks functionality of cryptsetup, the
# latter means that we do it the old-fashioned way.

# Start by parsing some options, all options are relevant to regular cryptsetup
# but only cryptnode is relevant to luks which picks up the rest of the 
# parameters by reading the partition header
cryptcipher=aes-cbc-essiv:sha256
cryptsize=256
crypthash=sha256
cryptnode=cryptroot
if [ -n "$cryptopts" ]; then
	IFS=" ,"
	for x in $cryptopts; do
		case $x in
		hash=*)
			crypthash=${x#hash=}
			;;
		size=*)
			cryptsize=${x#size=}
			;;
		cipher=*)
			cryptcipher=${x#cipher=}
			;;
		node=*)
			cryptnode=${x#node=}
			;;
		esac
	done
	unset IFS
fi
NEWROOT="/dev/mapper/$cryptnode"

# Check which cryptosolution we want
if [ "$FSTYPE" = "luks" ]; then
	# 1) The fstype of the root device has been identified as "luks"
	cryptcreate="/sbin/cryptsetup luksOpen $ROOT $cryptnode"
	cryptremove=""
else
	# 2) The fstype is not "luks" but cryptopts have been set
	cryptcreate="/sbin/cryptsetup -c $cryptcipher -s $cryptsize -h $crypthash create $cryptnode $ROOT"
	cryptremove="/sbin/cryptsetup remove $cryptnode"
fi

# Loop until we have a satisfactory password
while [ 1 ]; do
	if [ -x "/sbin/cryptgetpw" ]; then
		/sbin/cryptgetpw | $cryptcreate
	else
		$cryptcreate
	fi

	if [ $? -eq 0 ]; then
		fstype < "$NEWROOT" > /dev/.initramfs/source.me
		if [ $? -eq 0 ]; then
			. /dev/.initramfs/source.me
			if [ "$FSTYPE" != "unknown" ]; then
				break
			fi
		fi
	fi

	echo "$0: cryptsetup failed or fstype not recognized, bad password or options?"
	$cryptremove
	sleep 3
done

# init can now pick up new FSTYPE, FSSIZE and ROOT
echo "ROOT=\"$NEWROOT\"" >> /dev/.initramfs/source.me

exit 0


More information about the Pkg-cryptsetup-devel mailing list