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
}