474 lines
13 KiB
Bash
Executable file
474 lines
13 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Copyright (c) 02005 sense.lab <senselab@systemausfall.org>
|
|
#
|
|
# 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 does EVERYTHING
|
|
# all other scripts are only frontends :)
|
|
#
|
|
# called by:
|
|
# - some rc-scripts
|
|
# - the web frontend cgi
|
|
#
|
|
|
|
# TODO: check permissions and owners of config files, directories and scripts before
|
|
# running cbox-root-actions.sh
|
|
|
|
set -eu
|
|
|
|
|
|
# default location of config file
|
|
CONF_FILE=/etc/cryptobox/cryptobox.conf
|
|
|
|
LIB_DIR=$(dirname "$0")
|
|
|
|
# to determine a nice default partition name
|
|
DEVICE_NAME_PREFIX="Disk #"
|
|
|
|
# read the default setting file, if it exists
|
|
test -e /etc/default/cryptobox && . /etc/default/cryptobox
|
|
|
|
test ! -e "$CONF_FILE" && echo "Could not find the configuration file: $CONF_FILE" >&2 && exit 1
|
|
|
|
# parse config file
|
|
. "$CONF_FILE"
|
|
|
|
test ! -e "$CONF_FILE" && echo "Could not find the distribution specific configuration file: $CONF_FILE" >&2 && exit 1
|
|
|
|
# parse the distribution specific file
|
|
. "$DISTRIBUTION_CONF"
|
|
|
|
# check for writable log file
|
|
test -w "$LOG_FILE" || LOG_FILE=/tmp/$(basename "$LOG_FILE")
|
|
|
|
# retrieve configuration directory
|
|
CONFIG_DIR="$(getent passwd $CRYPTOBOX_USER | cut -d ':' -f 6)/config"
|
|
CONFIG_MARKER=cryptobox.marker
|
|
|
|
## configuration
|
|
ROOT_PERM_SCRIPT="$LIB_DIR/cryptobox_root_wrapper"
|
|
# ROOT_PERM_SCRIPT needs the MNT_PARENT setting
|
|
export MNT_PARENT="$(cd ~; pwd)/mnt"
|
|
|
|
######## stuff ##########
|
|
|
|
# all partitions with a trailing number
|
|
ALL_PARTITIONS=$(cat /proc/partitions | sed '1,2d; s/ */ /g; s/^ *//' | cut -d " " -f 4 | grep '[0-9]$')
|
|
|
|
#########################
|
|
|
|
function log_msg()
|
|
{
|
|
# the log file is (maybe) not writable during boot - try
|
|
# before writing ...
|
|
test -w "$LOG_FILE" || return 0
|
|
echo >>"$LOG_FILE"
|
|
echo "##### `date` #####" >>"$LOG_FILE"
|
|
echo "$1" >>"$LOG_FILE"
|
|
}
|
|
|
|
|
|
function error_msg()
|
|
# parameters: ExitCode ErrorMessage
|
|
{
|
|
local all=$@
|
|
test $# -ne 2 && error_msg 1 "*** invalid call of error_msg *** $all"
|
|
echo "[`date`] - $2" | tee -a "$LOG_FILE" >&2
|
|
# print the execution stack - not usable with busybox
|
|
# caller | sed 's/^/\t/' >&2
|
|
exit "$1"
|
|
}
|
|
|
|
|
|
# Parameter: device
|
|
function is_device_allowed() {
|
|
# check for invalid characters and exit if one is found
|
|
local device=$(echo "$1" | sed 's#[^a-zA-Z0-9_\-\./]##g')
|
|
test "$1" = "$device" || return 1
|
|
# remove leading "/dev/"
|
|
device=$(echo "$device" | sed 's#^/dev/##')
|
|
# return for empty name
|
|
test -z "$device" && return 1
|
|
for a in $ALL_PARTITIONS
|
|
do echo "$device" | grep -q "^$a.*" && return 0
|
|
done
|
|
# no matching device found - exit with error
|
|
return 1
|
|
}
|
|
|
|
function config_set_value()
|
|
# parameters: SettingName [SettingValue]
|
|
# read from stdin if SettingValue is not defined
|
|
{
|
|
if test $# -gt 1
|
|
then echo "$2" > "$CONFIG_DIR/$1"
|
|
else cat - >"$CONFIG_DIR/$1"
|
|
fi
|
|
}
|
|
|
|
|
|
function config_get_value()
|
|
# parameters: SettingName
|
|
{
|
|
# use mounted config, if it exists - otherwise use defaults
|
|
local conf_dir
|
|
test -z "$1" && error_msg 1 "empty setting name"
|
|
# check for existence - maybe use default values (even for old
|
|
# releases that did not contain this setting)
|
|
if test -e "$CONFIG_DIR/$1"
|
|
then cat "$CONFIG_DIR/$1"
|
|
elif test -e "$CONFIG_DEFAULTS_DIR/$1"
|
|
then cat "$CONFIG_DEFAULTS_DIR/$1"
|
|
else case "$1" in
|
|
# you may place default values for older versions here
|
|
# for compatibility
|
|
* )
|
|
error_msg 2 "unknown configuration value ($1)"
|
|
;;
|
|
esac
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
|
|
function list_partitions_of_type()
|
|
# parameter: { config | crypto | plaindata | unused }
|
|
{
|
|
local config=
|
|
local crypto=
|
|
local plaindata=
|
|
local unused=
|
|
for a in $ALL_PARTITIONS
|
|
do if "$ROOT_PERM_SCRIPT" is_crypto_partition "/dev/$a"
|
|
then crypto="$crypto /dev/$a"
|
|
elif "$ROOT_PERM_SCRIPT" is_config_partition "/dev/$a"
|
|
then config="$config /dev/$a"
|
|
elif "$ROOT_PERM_SCRIPT" is_plaindata_partition "/dev/$a"
|
|
then plaindata="$plaindata /dev/$a"
|
|
else unused="$unused /dev/$a"
|
|
fi
|
|
done
|
|
case "$1" in
|
|
config )
|
|
echo "$config"
|
|
;;
|
|
crypto )
|
|
echo "$crypto"
|
|
;;
|
|
plaindata )
|
|
echo "$plaindata"
|
|
;;
|
|
unused )
|
|
echo "$unused"
|
|
;;
|
|
* )
|
|
error_msg 11 "wrong parameter ($1) for list_partition_types in $(basename $0)"
|
|
;;
|
|
esac | tr " " "\n" | grep -v '^$'
|
|
return 0
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function get_device_mnt_name() {
|
|
"$ROOT_PERM_SCRIPT" get_device_mnt_name "$1"
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function get_device_uuid() {
|
|
"$ROOT_PERM_SCRIPT" get_device_uuid "$1"
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
# return the readable name of the crypto container, if it is already defined
|
|
# if undefined - return the uuid
|
|
function get_device_name() {
|
|
local uuid=$(get_device_uuid "$1")
|
|
local dbname=$(config_get_value "names.db" | grep "^$uuid:" | cut -d ":" -f 2-)
|
|
# return dbname if it exists
|
|
test -n "$dbname" && echo "$dbname" && return 0
|
|
# find a nice name for the new partition
|
|
local counter=1
|
|
local test_name
|
|
local test_uuid
|
|
local test_result
|
|
# try to find a name with the defined "prefix" followed by a number ...
|
|
while true
|
|
do test_name="$DEVICE_NAME_PREFIX$counter"
|
|
if config_get_value "names.db" | grep -q ":$test_name$"
|
|
then counter=$((counter+1))
|
|
else # save it for next time
|
|
set_device_name "$1" "$test_name"
|
|
echo "$test_name"
|
|
return 0
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
function set_device_name()
|
|
# TODO: the implementation is quite ugly, but it works (tm)
|
|
# Parameter: DEVICE NAME
|
|
{
|
|
local uuid=$(get_device_uuid "$1")
|
|
# remove the old setting for this device and every possible entry with the same name
|
|
local new_config=$(config_get_value 'names.db' | sed "/^$uuid:/d; /^[^:]*:$2$/d"; echo "$uuid:$2")
|
|
echo "$new_config" | config_set_value "names.db"
|
|
}
|
|
|
|
|
|
function does_crypto_name_exist()
|
|
# Parameter: NAME
|
|
{
|
|
config_get_value 'names.db' | grep -q "^[^:]*:$1$"
|
|
}
|
|
|
|
|
|
function create_crypto()
|
|
# Parameter: DEVICE NAME KEYFILE
|
|
# keyfile is necessary, to allow background execution via 'at'
|
|
{
|
|
local device=$1
|
|
local name=$2
|
|
local keyfile=$3
|
|
# otherwise the web interface will hang
|
|
# passphrase may be passed via command line
|
|
local key=$(<"$keyfile")
|
|
# remove the passphrase-file as soon as possible
|
|
dd if=/dev/zero of="$keyfile" bs=512 count=1 2>/dev/null
|
|
rm "$keyfile"
|
|
|
|
log_msg "Creating crypto partition with the cipher $DEFAULT_CIPHER on $device"
|
|
echo "$key" | "$ROOT_PERM_SCRIPT" create_crypto "$device"
|
|
|
|
set_crypto_name "$device" "$name"
|
|
}
|
|
|
|
|
|
function is_config_active() {
|
|
test -f "$CONFIG_DIR/$CONFIG_MARKER"
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function is_mounted() {
|
|
local name=$(get_device_mnt_name "$1")
|
|
test -n "$name" && mountpoint -q "$MNT_PARENT/$name"
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function is_plain() {
|
|
"$ROOT_PERM_SCRIPT" is_plain_partition "$1"
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function is_encrypted() {
|
|
"$ROOT_PERM_SCRIPT" is_crypto_partition "$1"
|
|
}
|
|
|
|
|
|
# list which allowed disks are at the moment connected with the cbox
|
|
function get_available_disks() {
|
|
for scan in $SCAN_DEVICES
|
|
do for avail in $ALL_PARTITIONS
|
|
do echo "$avail" | grep -q "^$scan[^/]*" && echo "/dev/$avail"
|
|
done
|
|
done
|
|
return 0
|
|
}
|
|
|
|
|
|
# Parameter: DEVICE
|
|
function mount_crypto() {
|
|
local device=$1
|
|
test -z "$device" && error_msg 4 'No valid harddisk found!'
|
|
is_mounted "$device" && echo "The crypto filesystem is already active!" && return
|
|
# passphrase is read from stdin
|
|
log_msg "Mounting a crypto partition from $device"
|
|
"$ROOT_PERM_SCRIPT" mount "$device" >>"$LOG_FILE" 2>&1
|
|
}
|
|
|
|
|
|
function umount_partition() {
|
|
# Parameter: device
|
|
local container=$(get_device_name "$1")
|
|
"$ROOT_PERM_SCRIPT" umount "$1"
|
|
}
|
|
|
|
|
|
function box_purge()
|
|
# removing just the first bytes from the harddisk should be enough
|
|
# every harddisk will be overriden!
|
|
# this feature is only useful for validation
|
|
{
|
|
# TODO: not ALL harddisks, please!
|
|
get_available_disks | while read a
|
|
do log_msg "Purging $a ..."
|
|
"$ROOT_PERM_SCRIPT" trash_device "$a"
|
|
done
|
|
}
|
|
|
|
|
|
function turn_off_all_containers() {
|
|
# TODO - needs to be implemented
|
|
return 0
|
|
}
|
|
|
|
|
|
### main ###
|
|
|
|
# set PATH because thttpd removes /sbin and /usr/sbin for cgis
|
|
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
|
|
|
|
|
ACTION=help
|
|
test $# -gt 0 && ACTION=$1 && shift
|
|
|
|
case "$ACTION" in
|
|
crypto-up )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'crypto-up'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
mount_crypto "$1"
|
|
;;
|
|
crypto-down )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'crypto-down'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
umount_partition "$1"
|
|
;;
|
|
init )
|
|
init_cryptobox </dev/null >>"$LOG_FILE" 2>&1
|
|
;;
|
|
list_container )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'list_container'"
|
|
case "$1" in
|
|
config | unused | plaindata | crypto )
|
|
list_partitions_of_type "$1"
|
|
;;
|
|
* )
|
|
return 1
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
get_device_name )
|
|
# Parameter: DEVICE
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'get_device_name'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
get_device_name "$1"
|
|
;;
|
|
set_device_name )
|
|
# Parameter: DEVICE NAME
|
|
test $# -ne 2 && error_msg 10 "invalid number of parameters for 'set_device_name'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
set_device_name "$1" "$2"
|
|
;;
|
|
device_init )
|
|
# Parameter: DEVICE [KEYFILE]
|
|
test $# -lt 1 && error_msg 10 "invalid number of parameters for 'device_init' ($@)"
|
|
test $# -gt 2 && error_msg 10 "invalid number of parameters for 'device_init' ($@)"
|
|
if test $# -eq 2
|
|
then test -z "$2" -o ! -e "$2" && error_msg 11 "invalid keyfile ($2) given for 'device_init'"
|
|
fi
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
if test $# -eq 2
|
|
then "$ROOT_PERM_SCRIPT" create_crypto "$1" "$2"
|
|
else "$ROOT_PERM_SCRIPT" create_plain "$1"
|
|
fi
|
|
true
|
|
;;
|
|
is_mounted )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'is_mounted'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
is_mounted "$1"
|
|
;;
|
|
is_encrypted )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'is_encrypted'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
is_encrypted "$1"
|
|
;;
|
|
is_plain )
|
|
test $# -ne 1 && error_msg 10 "invalid number of parameters for 'is_plain'"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
is_plain "$1"
|
|
;;
|
|
check_config)
|
|
is_config_active
|
|
;;
|
|
get_available_disks )
|
|
get_available_disks
|
|
;;
|
|
set_config )
|
|
test $# -ne 2 && error_msg 7 "'set_config' requires two parameters"
|
|
config_set_value "$1" "$2"
|
|
;;
|
|
get_config )
|
|
test $# -ne 1 && error_msg 6 "'get_config' requires exactly one parameter"
|
|
config_get_value "$1"
|
|
;;
|
|
get_capacity_info )
|
|
test $# -ne 1 && error_msg 6 "'get_capacity_info' requires exactly one parameter"
|
|
is_device_allowed "$1" || error_msg 12 "invalid device: $1"
|
|
is_mounted "$1" || error_msg 13 "the device is not mounted: $1"
|
|
name=$(get_device_mnt_name "$1")
|
|
df -h "$MNT_PARENT/$name" | tail -1
|
|
;;
|
|
diskinfo )
|
|
get_available_disks | while read a
|
|
do "$ROOT_PERM_SCRIPT" diskinfo "$a"
|
|
done 2>/dev/null
|
|
;;
|
|
box-purge )
|
|
log_msg "Cleaning the CryptoBox ..."
|
|
turn_off_all_containers
|
|
"$0" config-down
|
|
box_purge >>"$LOG_FILE" 2>&1
|
|
;;
|
|
poweroff )
|
|
log_msg "Shutting down the Cryptobox ..."
|
|
turn_off_all_containers
|
|
"$ROOT_PERM_SCRIPT" poweroff
|
|
;;
|
|
reboot )
|
|
log_msg "Rebooting the Cryptobox ..."
|
|
turn_off_all_containers
|
|
"$ROOT_PERM_SCRIPT" reboot
|
|
;;
|
|
umount_all )
|
|
log_msg "Unmounting all volumes ..."
|
|
turn_off_all_containers
|
|
;;
|
|
* )
|
|
echo "[$(basename $0)] - unknown action: $ACTION" >&2
|
|
echo "Syntax: $(basename $0) ACTION [PARAMS]"
|
|
echo " crypto-up - mount crypto partition"
|
|
echo " crypto-down - unmount crypto partition"
|
|
echo " crypto-create - a wrapper for 'crypto-create-bg'"
|
|
echo " crypto-create-bg - create encrypted blockdevice and run mkfs"
|
|
echo " is_mounted - check, if crypto partition is mounted"
|
|
echo " check_config - check, if the configuration is usable"
|
|
echo " get_available_disks - shows all accessible disks"
|
|
echo " get_current_ip - get the current IP of the network interface"
|
|
echo " set_config NAME VALUE - change a configuration setting"
|
|
echo " get_config NAME - retrieve a configuration setting"
|
|
echo " get_device_name DEVICE - retrieve the human readable name of a partition"
|
|
echo " set_device_name DEVICE - set the human readable name of a partition"
|
|
echo " device_init DEVICE KEYFILE - initialize the filesystem of a partition (the keyfile just contains the passphrase)"
|
|
echo " get_capacity_info - print the output of 'df' for the (mounted) partition"
|
|
echo " diskinfo - show the partition table of the harddisk"
|
|
echo " box-purge - destroy the partition tables of all harddisks (delete everything)"
|
|
echo " poweroff - turn off the computer"
|
|
echo " reboot - reboot the computer"
|
|
echo
|
|
;;
|
|
esac
|
|
|
|
exit 0
|
|
|