#!/bin/sh # # Copyright (c) 02005 sense.lab # # License: This script is distributed under the terms of version 2 # of the GNU GPL. See the LICENSE file included with the package. # # $Id$ # # this script is responsible for all dangerous actions, that require root privileges # every action should be checked at least TWICE a day for open holes :) # usually will get call via sudo # # called by: # - cbox-manage.sh # set -eu LIB_DIR=$(dirname "$0") LIB_DIR=$(cd "$LIB_DIR"; pwd) test "$(id -u)" -ne 0 && echo "$(basename $0) - only root may call this script" >&2 && exit 100 # read the default setting file, if it exists test -e /etc/default/cryptobox && . /etc/default/cryptobox # set CONF_FILE to default value, if not configured in /etc/default/cryptobox CONF_FILE=${CONF_FILE:-/etc/cryptobox/cryptobox.conf} # parse config file . "$CONF_FILE" # parse distribution specific file . "$DISTRIBUTION_CONF" CB_SCRIPT="$LIB_DIR/cbox-manage.sh" CONFIG_MARKER=cryptobox.marker ############ some useful functions ############### # check if the given device is part of the SCAN_DEVICE list # every entry in SCAN_DEVICES is matched as "^/dev/${SCAN_DEVICE}[^/]*$" against # the given device # other devices may not be touched function is_device_allowed() # parameter: device { for a in $SCAN_DEVICES do echo "$1" | grep -q "^/dev/${a}[^/]*$" && return 0 done return 1 } # return the uuid of the partition (if possible) # this works at least for luks, ext2/3 and vfat partitions function get_device_uuid() { local UUID # check for luksUUID or ext2/3-uuid if is_luks_device "$1" then UUID=$("$CRYPTSETUP" luksUUID "$1") else test -x "$BLKID" && UUID=$("$BLKID" -s UUID -o value -c /dev/null -w /dev/null "$1" 2>/dev/null) fi if test -z "$UUID" then get_device_flat_name "$1" else echo "$UUID" fi return 0 } # the device name is "flattened" function get_device_flat_name() { echo "$1" | sed 's#/#_#g' } # the basename of the mountpoint for this device - should be somehow human_readable function get_device_mnt_name() { "$CB_SCRIPT" get_device_name "$1" } # every devmapper name should look like a UUID function is_uuid_valid() { local hex=[0-9a-f] echo "$1" | grep -q "^$hex\{8\}-$hex\{4\}-$hex\{4\}-$hex\{4\}-$hex\{12\}$" } # parameter ExitCode ErrorMessage function error_msg() { echo "CBOX-ERROR: [$(basename $0) - $ACTION] - $2" >&2 exit $1 } # parameter: device sfdisk_layout_setup # e.g.: /dev/hda "0,1,L \n,,L\n" function partition_device() { # TODO: allow different layouts # TODO: skip config partition if a configuration is already active # sfdisk -n doesn't actually write (for testing purpose) if echo -e "$2" | "$SFDISK" -n "$1" then echo -e "$2" | "$SFDISK" "$1" || return 1 else return 2 fi true } function is_luks_device() # parameter: device { "$CRYPTSETUP" isLuks "$1" 2>/dev/null } ################ main #################### ACTION=unknown test $# -gt 0 && ACTION=$1 && shift case "$ACTION" in partition_disk ) test $# -ne 2 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" partition_device "$1" "$2" || \ error_msg 2 "failed to create new partition table on device $1" ;; mount ) # parameters: device # returns the relative name of the mointpoint for success test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" mnt_name=$(get_device_mnt_name "$1") mountpoint -q "$MNT_PARENT/$mnt_name" && \ error_msg 5 "a device with the same name ($mnt_name) is already mounted" mkdir -p "$MNT_PARENT/$mnt_name" if is_luks_device "$1" then "$CRYPTSETUP" luksOpen "$1" "$mnt_name" || \ error_msg 6 "could not open encrypted device $1" if mount "$DEV_MAPPER_DIR/$mnt_name" "$MNT_PARENT/$mnt_name" then true else "$CRYPTSETUP" luksClose "$mnt_name" || true error_msg 7 "wrong password for $1 supplied" fi else mount "$1" "$MNT_PARENT/$mnt_name" || \ error_msg 8 "invalid filesystem on device $1" fi # just in case, that there is no ext2/3 filesystem: # set uid option (will fail silently for ext2/3) # TODO: there is no FILE_USER setting anymore - do we still need it? #mount -o remount,uid="$FILE_USER" "$MNT_PARENT/$name" 2>/dev/null || true # adapt top-level permission to current setup - again: may fail silently #chown "$FILE_USER" "$MNT_PARENT/$name" 2>/dev/null || true true ;; umount ) #parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" mnt_name=$(get_device_mnt_name "$1") mountpoint -q "$MNT_PARENT/$mnt_name" || \ error_msg 9 "the device ($1) is not mounted as '$mnt_name'" # try to unmount - do it in lazy mode umount -l "$MNT_PARENT/$mnt_name" # TODO: check, what happens, if there are open files - does the device gets mapping removed? # remove (if necessary) the device mapping if test -e "$DEV_MAPPER_DIR/$mnt_name" then "$CRYPTSETUP" luksClose "$mnt_name" || \ error_msg 11 "could not remove the device mapper ($mnt_name) for device $1" fi # try to remove the mountpoint - a failure is not important rmdir "$MNT_PARENT/$mnt_name" || true # set exitcode mountpoint -q "$MNT_PARENT/$mnt_name" && exit 1 true ;; create_crypto ) # parameter: device keyfile test $# -ne 2 && error_msg 1 "wrong number of parameters" keyfile=$2 test -e "$keyfile" || error_msg 2 "keyfile ($keyfile) not found" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" # read the passphrase from stdin # the iter-time is in milliseconds - keep it low for fast mounting cat "$keyfile" | \ "$CRYPTSETUP" --cipher "$DEFAULT_CIPHER" --iter-time 2000 --batch-mode luksFormat "$1" || \ error_msg 11 "failed to create the encrypted partition" name=$(get_device_mnt_name "$1") cat "$keyfile" | "$CRYPTSETUP" --batch-mode luksOpen "$1" "$name" || \ error_msg 12 "failed to open the encrypted partition" # trash the passphrase in keyfile echo "0123456789abcdefghijklmnopqrstuvwxyz" > "$keyfile" # the disk cache surely prevents the previous line from being written, but we do it anyway ... echo "zyxwvutsrqponmlkjihgfedcba9876543210" > "$keyfile" rm "$keyfile" # complete in background ( "$MKFS_DATA" "$DEV_MAPPER_DIR/$name" || \ error_msg 13 "failed to create the encrypted filesystem" "$CRYPTSETUP" --batch-mode luksClose "$name" || \ error_msg 14 "failed to close the encrypted mapped device" ) /dev/null 2>/dev/null & true ;; create_plain ) # parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters for 'create_plain'" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" # complete in background ( "$MKFS_DATA" "$1" || \ error_msg 15 "failed to create the plaintext filesystem" ) /dev/null 2>/dev/null & true ;; get_device_mnt_name ) # parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" get_device_mnt_name "$1" ;; get_device_uuid ) # parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" get_device_uuid "$1" ;; is_config_partition ) # parameter: device # returns exitcode 0 if the device contains a configuration test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" is_config=0 tmp_dir=/tmp/$(basename $0)-$$-mnt mkdir -p "$tmp_dir" # error means "no config partition" if mount "$1" "$CONFIG_DIR" then test -e "$CONFIG_DIR/$CONFIG_MARKER" && is_config=1 umount "$CONFIG_DIR" || \ error_msg 14 "unable to unmount configation partition after probing" fi rmdir "$tmp_dir" || true # return 0 if $device is a config partition test "$is_config" -eq 1 && exit 0 exit 1 ;; is_crypto_partition ) # parameter: device # returns exitcode 0 if the device contains a luks header test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" is_luks_device "$1" ;; is_plain_partition ) # parameter: device # returns exitcode 0 if the device contains a readable filesystem test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" status=0 tmp_dir=/tmp/$(basename $0)-$$-mnt mkdir -p "$tmp_dir" if mount "$1" "$tmp_dir" >/dev/null 2>/dev/null then test ! -e "$tmp_dir/$CONFIG_MARKER" && status=1 umount "$tmp_dir" fi rmdir "$tmp_dir" || true test "$status" -eq 1 && exit 0 exit 1 ;; trash_device ) # parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" dd if=/dev/urandom of="$1" bs=512 count=1 2>/dev/null ;; diskinfo ) # parameter: device test $# -ne 1 && error_msg 1 "wrong number of parameters" is_device_allowed "$1" || \ error_msg 3 "this device ($1) is not listed in SCAN_DEVICES (see $CONF_FILE)" "$SFDISK" -L -q -l "$1" ;; update_network ) # parameter: none ip= # TODO: can we avoid to hard-code the filename ($CONFIG_DIR/ip) here? test -e "$CONFIG_DIR/ip" && ip=$(<"$CONFIG_DIR/ip") test -n "$z" && ifconfig "$NET_IFACE" "$ip" ;; poweroff ) # TODO: check configuration setting before "$POWEROFF" ;; reboot ) # TODO: check configuration setting before "$REBOOT" ;; * ) echo "[$(basename $0)] - unknown action: $ACTION" >&2 echo "Syntax: $(basename $0) ACTION PARAMETERS" echo ' partition_disk $device $disk_layout' echo ' get_device_name $device' echo ' get_device_uuid $device' echo ' create_crypto $device' echo ' mount $device' echo ' umount $name' echo ' create_config $device' echo ' mount_config $device' echo ' remount_config { ro | rw }' echo ' umount_config' echo ' is_config_partition $device' echo ' is_plain_partition $device' echo ' is_crypto_partition $device' echo ' trash_device $device' echo ' diskinfo $device' echo ' update_network' echo ' poweroff' echo ' reboot' echo ' help' echo test "$ACTION" = "help" && exit 0 # return error for any unknown/unspecified action exit 1 ;; esac