All pastes #350780 Raw Edit

Someone

public text v1 · immutable
·published 2007-02-11 18:29 UTC
rendered paste body
CRYPTCMD=/sbin/cryptsetup
DEVMAPCMD=/sbin/dmsetup
LOSETUP=/sbin/losetup
TABFILE=/etc/crypttab
MAPPER=/dev/mapper

MOUNT="${CRYPTDISKS_MOUNT}"

test -x $CRYPTCMD  || exit 0
test -x $DEVMAPCMD || exit 0
test -f $TABFILE   || exit 0


parse_opts () {
	local 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
	while test "x$opts" != "x" ; do
		ARG=`echo $opts | sed "s/,.*//"`
		opts=${opts##$ARG}
		opts=${opts##,}
		PARAM=`echo $ARG | sed "s/=.*//"`
		
		case "$ARG" in
		  *=*)
		  	PARAM=`echo $ARG | sed "s/=.*//"`
		  	VALUE=${ARG##$PARAM=}
		  	;;
		  *)
		  	PARAM=$ARG
		  	VALUE=""
			;;
		esac
		
		case "$PARAM" in 
		  readonly)
		  	PARAMS="$PARAMS -r"
		  	;;
		  cipher)
		  	PARAMS="$PARAMS -c $VALUE"
		  	if test "x$VALUE" = "x" ; then
		  		echo "no value for cipher option, skipping" >&2
		  		return 1
		  	fi
		  	;;
		  size)
		  	PARAMS="$PARAMS -s $VALUE"
		  	if test "x$VALUE" = "x" ; then
		  		echo "no value for size option, skipping" >&2
		  		return 1
		  	fi
		  	;;
		  hash)
		  	PARAMS="$PARAMS -h $VALUE"
		  	if test "x$VALUE" = "x" ; then
		  		echo "no value for hash option, skipping" >&2
		  		return 1
		  	fi
		  	;;
		  verify)
		  	PARAMS="$PARAMS -y"
		  	;;
		  check)
		  	if test "x$VALUE" = "x" ; then
				CHECK="${CRYPTDISKS_CHECK}"
			else
		  		CHECK="$VALUE"
		  	fi
		  	if [ "$CHECK" -a -x /lib/cryptsetup/checks/"$CHECK" ]; then
		   		CHECK="/lib/cryptsetup/checks/$CHECK"
		  	#else
		  	#	CHECK=""
		  	fi
		  	;;
		  checkargs)
		  	if test "x$VALUE" != "x"; then
				CHECKARGS="$VALUE"
			fi
			;;
		  precheck)
		  	if test "x$VALUE" = "x" ; then
				PRECHECK="${CRYPTDISKS_PRECHECK}"
			else
		  		PRECHECK="$VALUE"
		  	fi
		   	if [ "$PRECHECK" -a -x /lib/cryptsetup/checks/"$PRECHECK" ]; then
		  		PRECHECK="/lib/cryptsetup/checks/$PRECHECK"
		  	else
		  		PRECHECK=""
		  	fi
		  	;;
		  tries)
		  	if test "x$VALUE" != "x" ; then
		  		TRIES="$VALUE"
		  	fi
		  	case "$TRIES" in
		  	  [0-9]*)
		  	  	;;
		  	  *)
			  	echo "option TRIES is wrongly set to $TRIES - forced to '3' " >&2
			  	TRIES="3"
			  	;;
			esac
		  	PARAMS="$PARAMS --tries=$TRIES"
		  	;;
		  timeout)
		  	if test "x$VALUE" = "x" ; then
				TIMEOUT="${CRYPTDISKS_TIMEOUT}"
			else
		  		TIMEOUT="$VALUE"
		  	fi
			case "$TIMEOUT" in
			  [0-9]*)
			  	;;
			  *)
			  	echo "option TIMEOUT is wrongly set to $TIMEOUT - forced to '0' " >&2
				TIMEOUT="0"
				;;
			esac
		  	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
			;;
		  ssl)
			if [ -n "$KEYSCRIPT" ]; then
				echo "multiple key decryption options are not allowed together, skipping" >&2
				return 1
			fi
			KEYSCRIPT="/lib/cryptsetup/scripts/decrypt_old_ssl"
			;;
		  gpg)
			if [ -n "$KEYSCRIPT" ]; then
				echo "multiple key decryption options are not allowed together, skipping" >&2
				return 1
			fi
			KEYSCRIPT="/lib/cryptsetup/scripts/decrypt_gpg"
			;;
		  keyscript)
			if [ -n "$KEYSCRIPT" ]; then
				echo "multiple key decryption options are not allowed together, skipping" >&2
				return 1
			elif test "x$VALUE" = "x" ; then
		  		echo "no value for keyscript option, skipping" >&2
		  		return 1
		  	fi
			KEYSCRIPT="$VALUE"
		  	;;
		esac
	done

	return 0
}

lo_setup () {
	local LOOP_ID=""

	# Set up loopback devices
	if [ ! -f "$src" ]; then
		return 0
	fi

	if [ ! -d "/sys/block/loop0" ]; then
		modprobe loop || return 1
	fi

	for i in 0 1 2 3 4 5 6 7 ; do
		if [ "$(cat /sys/block/loop$i/size)" -eq 0 ]; then
			LOOP_ID=$i
			break
		fi
	done

	if [ -z "$LOOP_ID" ]; then
		return 1
	fi

	$LOSETUP /dev/loop$LOOP_ID $src || return 1
	src=/dev/loop$LOOP_ID
	return 0
}

check_key () {
	# 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"
		echo ""
		return 0
	fi

	if [ ! -e "$key" ]; then
		echo "Keyfile for '$dst' not found, skipping" >&2
		return 1
	fi

	# FIXME: Use stat here instead
	MODE=`ls -l $key | sed 's/^....\(......\).*/\1/'`
	OWNER=`ls -l $key | sed 's/^[^ ]* *[^ ]* *\([^ ]*\).*/\1/'`

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

	if [ "$key" = "${key%random}" ] && [ "$MODE" != "------" ]; then
		echo "INSECURE MODE FOR $key, see /usr/share/doc/cryptsetup/README.Debian." >&2
		# don't break here for now
		# return 1
	fi

	if [ "$OWNER" != "root" ]; then
		echo "INSECURE OWNER FOR $key, see /usr/share/doc/cryptsetup/README.Debian." >&2
		# don't break here for now
		# return 1
	fi

	INTERACTIVE="no"
	return 0
}

do_luks () {
	if ! $CRYPTCMD isLuks $src >/dev/null 2>&1; then
		echo "Device '$src' is not a LUKS partition, skipping" >&2
		return 1
	fi

	if test "x$KEYSCRIPT" != "x" ; then
		PARAMS="$PARAMS --key-file=-"
		$KEYSCRIPT $key <&1 | $CRYPTCMD $PARAMS luksOpen $src $dst
	else
		if test "x$INTERACTIVE" != "xyes" ; then
			PARAMS="$PARAMS --key-file=$key"
		fi
		$CRYPTCMD $PARAMS luksOpen $src $dst <&1
	fi

	if [ $? != 0 ]; then
		return 1
	fi

	if [ "$CHECK" != ""  ] && ! $CHECK $MAPPER/$dst $CHECKARGS; then
		echo "the check for '$MAPPER/$dst' failed" >&2
		echo "removing the crypto device $dst" >&2
		$CRYPTCMD luksClose $dst
		return 1
	fi

	return 0
}

do_noluks () {
	if [ "$PRECHECK" = "" ]; then
		PRECHECK="/lib/cryptsetup/checks/un_vol_id"
	fi

	if pre_out=$($PRECHECK $src); then
		run=1
	elif test "x$MAKESWAP" = "xyes" && /lib/cryptsetup/checks/vol_id $src swap>/dev/null; then
		run=1
	else
		run=0
		echo "$pre_out" >&2
		echo "the precheck for '$src' failed, skipping" >&2
		return 1
	fi
	
	if test "x$KEYSCRIPT" != "x" ; then
		PARAMS="$PARAMS --key-file=-"
		$KEYSCRIPT $key <&1 | $CRYPTCMD $PARAMS create $dst $src
	else
		if test "x$INTERACTIVE" != "xyes" ; then
			PARAMS="$PARAMS --key-file=$key"
		fi
		$CRYPTCMD $PARAMS create $dst $src <&1
	fi

	if [ $? != 0 ] ; then
		return 1
	fi


	if [ "$CHECK" != ""  ] && ! $CHECK $MAPPER/$dst $CHECKARGS; then
		echo "the check for '$MAPPER/$dst' failed - maybe the password is wrong" >&2
		echo "removing the crypto device $dst" >&2
		$CRYPTCMD remove $dst
		return 1
	fi

	return 0
}

mount_fs () {
	for point in $MOUNT; do
		MOUNT_YES="yes"
		echo "STICK!"
		read
		mount $point 2>/dev/null 1>&2 || MOUNT_YES="no"
	done
}

umount_fs () {
	if [ "x$MOUNT_YES" = "xyes" ]; then
		for point in $MOUNT; do
			umount $point
		done
	fi
}

do_swap () {
	if test "x$MAKESWAP" = "xyes" && test -b $MAPPER/$dst; then
		if swap_out=$(/lib/cryptsetup/checks/un_vol_id $MAPPER/$dst) || \
				/lib/cryptsetup/checks/vol_id $MAPPER/$dst swap>/dev/null; then
			mkswap $MAPPER/$dst 2>/dev/null >/dev/null
		else
			echo "$swap_out" >&2
			echo "the check for '$MAPPER/$dst' failed. $MAPPER/$dst contains data." >&2
			echo "removing the crypto device $dst" >&2
			do_close
		fi
	fi
}

do_tmp () {
	if test "x$MAKETMP" = "xyes" && test -b $MAPPER/$dst; then
		mke2fs $MAPPER/$dst >/dev/null
		mount -t ext2 $MAPPER/$dst /tmp
		chmod 1777 /tmp
		umount /tmp
	fi
}

do_close () {
	if echo $opts | grep -q "luks"; then
		$CRYPTCMD luksClose $dst
	else
		$CRYPTCMD remove $dst
	fi
}

do_start () {
	modprobe -q dm-crypt || true
	$DEVMAPCMD mknodes
	log_action_begin_msg "Starting $INITSTATE crypto disks"
	mount_fs
	egrep -v "^[[:space:]]*(#|$)" $TABFILE | while read dst src key opts; do

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

		# Make sure source device exists
		if [ ! -r "$src" ]; then
			if [ "x$LOUD" = "xyes" ]; then
				log_progress_msg "$dst(skipped, device $src does not exist)"
			fi
			continue
		fi

		# Make sure that target device doesn't exist
		if [ -b $MAPPER/$dst ]; then
			log_progress_msg "$dst(running)"
			continue
		fi

		# All checks passed, do the real setup
		log_progress_msg "$dst(starting)"

		parse_opts "$opts" || continue
		check_key || continue
		lo_setup || continue

		if test "x$USELUKS" = "xyes" ; then
			do_luks
		else
			do_noluks
		fi

		if [ $? -ne 0 ]; then
			log_progress_msg "$dst(failed)"
		else
			do_swap
			do_tmp
		fi
	done
	
	umount_fs
	log_action_end_msg 0
}

do_stop () {
	$DEVMAPCMD mknodes
	log_action_begin_msg "Stopping $INITSTATE crypto disks"
	egrep -v "^[[:space:]]*(#|$)" $TABFILE | while read dst src key opts; do
		if test -b $MAPPER/$dst; then
			if $DEVMAPCMD info $dst | grep -q '^Open count: *0$'; then
				dev=`$DEVMAPCMD table $dst | sed 's/^.* \([0-9]*:[0-9]*\) .*/\1/'`
				major=`echo $dev | sed 's/:.*//'`
				minor=`echo $dev | sed 's/.*://'`

				log_progress_msg "$dst(stopping)"
				do_close

				# Detach loopback device, if attached
				if test -f $src -a $major -eq 7; then
					$LOSETUP -d /dev/loop$minor
				fi
			else
				log_progress_msg "$dst(busy)"
			fi
		else
			log_progress_msg "$dst(stopped)"
		fi
	done

	log_action_end_msg 0
}

device_msg () {
	local dst msg
	dst="$1"
	msg="$2"

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