#!/bin/sh # # this script does EVERYTHING # all other scripts are only frontends :) # # called by: # - some rc-scripts # - the web frontend cgi # set -eu # parse config file . /etc/cryptobox/cryptobox.conf ## configuration CONFIG_MARKER="$CONFIG_DIR/cryptobox.marker" CERT_TEMP=/tmp/stunnel.pem ##### log_msg() { # the log file is not writable during boot - try before writing ... [ -w "$LOG_FILE" ] || return 0 echo >>"$LOG_FILE" echo "################ `date` ####################" >>"$LOG_FILE" echo "$1" >>"$LOG_FILE" } function error_msg() # parameters: ExitCode ErrorMessage { echo "[`date`] - $2" | tee -a "$LOG_FILE" >&2 # print the execution stack - not usable with busybox #caller | sed 's/^/\t/' >&2 exit "$1" } function initial_checks() # Parameter: device { local device="$1" [ ! -b "$device" ] && log_msg "blockdevice $device does not exist" && return 1 ## check if we have an existing configpartition ## TODO: why this config_mount_test? # config_mount_test "$device" [ ! -x "$WIPE" ] && log_msg "$WIPE not found" && return 1 [ ! -x "$SFDISK" ] && log_msg "$SFDISK not found" && return 1 for a in $ALGO $HASH do grep -q "^name *: $a$" /proc/crypto || modprobe "$a" grep -q "^name *: $a$" /proc/crypto || { log_msg "$a is not supported by kernel" && return 1; } done log_msg "inital checks successful" return 0 } function create_partitions() # Parameter: device { local device="$1" # first partition size is 1 sector, second goes til end # sfdisk -n doesn't actually write (for testing purpose) echo -e "0,1,L \n,,L\n" | $SFDISK "$device" } function config_set_value() # parameters: SettingName SettingValue { mount -o rw,remount "$CONFIG_DIR" echo -n "$2" > "$CONFIG_DIR/$1" mount -o ro,remount "$CONFIG_DIR" } function config_get_value() # parameters: SettingName { # use mounted config, if it exists - otherwise use defaults local conf_dir if is_config_mounted then conf_dir=$CONFIG_DIR else conf_dir=$CONFIG_DEFAULTS_DIR fi [ -z "$1" ] && error_msg 1 "empty setting name" [ ! -e "$conf_dir/$1" ] && error_msg 2 "unknown configuration value ($1)" # remove trailing line break echo -n $(cat "$conf_dir/$1") } function create_config() # Parameter: device { local device="${1}1" log_msg "Creating config filesystem ..." $MKFS_CONFIG "$device" # mount the config partition rw log_msg "Mounting config partition ..." mount "$device" "$CONFIG_DIR" # create a marker to recognize a cryptobox partition date -I >"$CONFIG_MARKER" log_msg "Copying configuration defaults ..." cp -a "$CONFIG_DEFAULTS_DIR/." "$CONFIG_DIR" log_msg "Copying temporary cerificate file to config filesystem ..." cp -p "$CERT_TEMP" "$CERT_FILE" log_msg "Setting inital values ..." # beware: config_set_value remounts the config partition read-only config_set_value "device" "$1" config_set_value "ip" "$(get_current_ip)" # reinitialise configuration log_msg "Unmounting config partition ..." umount "$CONFIG_DIR" log_msg "Reload configuration ..." mount_config } function get_current_ip() # not necessarily the same as configured (necessary for validation) { # filter the output of ifconfig and remove trailing line break echo -n $(ifconfig $NET_IFACE | grep "inet" | cut -d ":" -f2 | cut -d " " -f1) } function create_crypto() # Parameter: device { local device="$1" # flood the crypto partition with noise # - not needed - #$WIPE -kq -R /dev/urandom "${device}2" # passphrase may be passed via command line $CRYPTSETUP -h "$HASH" -c "$ALGO" create "`basename $CRYPTMAPPER_DEV`" "${device}2" } function mkfs_crypto() # split from create_crypto to allow background execution via web interface { $MKFS_DATA "$CRYPTMAPPER_DEV" } function config_mount_test() # Parameter: device { local device="${1}" local STATUS=0 mount "${device}1" "$CONFIG_DIR" &>/dev/null || true is_config_mounted && STATUS=1 umount "$CONFIG_DIR" &>/dev/null || true # return code is the result of this expression [ 1 -eq "$STATUS" ] && return 0 return 1 } function is_config_mounted() { mount | grep -q " ${CONFIG_DIR} " && [ -f "$CONFIG_MARKER" ] } function is_crypto_mounted() { mount | grep -q " ${CRYPTO_DIR} " } function is_init_running() { #ps -e | grep -q -E "$MKFS_DATA|$WIPE" # this line is good for the "at" stuff - see cryptobox.pl [ -n "$(at -l)" ] } function find_harddisk() # look for the harddisk to be partitioned { local dev=$( if is_config_mounted then config_get_value "device" else for a in $SCAN_DEVICES do grep -q " `basename $a`$" /proc/partitions && echo "$a" && break done fi ) [ -z "$dev" ] && echo "no valid partition for initialisation found!" >>"$LOG_FILE" echo -n "$dev" } function mount_config() { is_config_mounted && error_msg 3 "configuration directory ($CONFIG_DIR) is already mounted!" local device=$( for a in $SCAN_DEVICES do log_msg "Trying to load configuration from $a ..." config_mount_test "$a" && echo "$a" && break done ) if [ -n "$device" ] && mount "${device}1" "$CONFIG_DIR" then log_msg "configuraton found on $device" config_set_value "device" "$device" return 0 else log_msg "failed to locate harddisk" return 1 fi } function mount_crypto() { is_crypto_mounted && echo "Das Crypto-Dateisystem ist bereits aktiv!" && return local device=`find_harddisk` [ -z "$device" ] && error_msg 4 'no valid harddisk found!' # passphrase is read from stdin log_msg "Mounting crypto partition ..." $CRYPTSETUP -h "$HASH" -c "$ALGO" create "`basename $CRYPTMAPPER_DEV`" "${device}2" if mount "$CRYPTMAPPER_DEV" "$CRYPTO_DIR" then log_msg "Mount succeded - now starting samba ..." /etc/init.d/samba start else log_msg "Mount failed - removing dev-mapper ..." dmsetup remove $(basename $CRYPTMAPPER_DEV) return 1 fi } function umount_crypto() { # do not break on error set +e if ps -e | grep -q " [sn]mbd$" then log_msg "Stopping samba ..." /etc/init.d/samba stop ps -e | grep -q " smbd$" && killall smbd ps -e | grep -q " nmbd$" && killall nmbd ps -e | grep -q " smbd$" && killall -9 smbd ps -e | grep -q " nmbd$" && killall -9 nmbd fi if mount | grep -q " $CRYPTO_DIR " then log_msg "Unmounting crypto partition ..." umount "$CRYPTO_DIR" fi if [ -e "$CRYPTMAPPER_DEV" ] then log_msg "Removing dev-mapper ..." $CRYPTSETUP remove $(basename $CRYPTMAPPER_DEV) fi set -e } function init_cryptobox_part1() # this is only the first part of initialisation that takes no time - good for a smooth web interface { local device=`find_harddisk` [ -z "$device" ] && log_msg 'no valid harddisk found!' && return 1 ( log_msg "Initializing crypto partition on $device ..." umount_crypto || true mount | grep -q " $CONFIG_DIR " && umount "$CONFIG_DIR" || true initial_checks "$device" || return 1 create_partitions "$device" create_config "$device" ) >>"$LOG_FILE" 2>&1 # the output of create_crypto may NOT be redirected - this would prevent cryptsetup from # reading the passphrase from stdin log_msg "Creating the crypto partition ..." create_crypto "$device" } function init_cryptobox_part2() # some things to be done in the background # these are the final steps of initialisation # thuid must be changed at the first time, therfore it needs to be # mounted { mkfs_crypto mount "$CRYPTMAPPER_DEV" "$CRYPTO_DIR" chown $SAMBA_USER "$CRYPTO_DIR" umount_crypto } function init_cryptobox_complete() { init_cryptobox_part1 init_cryptobox_part2 } ### main ### # set PATH because thttpd removes /sbin and /usr/sbin for cgis export PATH=/usr/sbin:/usr/bin:/sbin:/bin ACTION=help [ $# -gt 0 ] && ACTION="$1" case "$ACTION" in config-up ) # die cruft option hilft vielleicht bei dem Fehler "interleaved files not (yet) supported" mount -o remount,cruft / if mount_config then echo "Cryptobox configuration successfully loaded" else error_msg 3 "Could not find a configuration partition!" fi ;; config-down ) mount | grep -q " $CONFIG_DIR" && umount "$CONFIG_DIR" ;; network-up ) kudzu -s -q --class network conf_ip=$(config_get_value "ip") ifconfig $NET_IFACE "$conf_ip" log_msg "Configured $NET_IFACE for $conf_ip ..." echo "Configured network interface for $NET_IFACE: $conf_ip" log_msg "Starting the firewall ..." $FIREWALL_SCRIPT start # start stunnel if [ -f "$CERT_FILE" ] then USE_CERT=$CERT_FILE else USE_CERT=$CERT_TEMP $MAKE_CERT_SCRIPT "$CERT_TEMP" >>"$LOG_FILE" 2>&1 fi log_msg "Starting stunnel ..." stunnel -p "$USE_CERT" -r localhost:80 -d 443 \ || echo "$USE_CERT not found - not starting stunnel" # this ping allows other hosts to get the IP of # the box, in case of misconfiguration ping -b -c 1 $(ifconfig $NET_IFACE | grep Bcast | cut -d ":" -f 3 | cut -d " " -f 1) &>/dev/null ;; network-down ) log_msg "Stopping the firewall ..." $FIREWALL_SCRIPT stop log_msg "Stopping stunnel ..." killall stunnel log_msg "Shutting the network interface down ..." ifconfig $NET_IFACE down ;; services-up ) /etc/init.d/thttpd start ;; services-down ) /etc/init.d/samba stop /etc/init.d/thttpd stop ;; box-init ) # this is good for commandline only, as it takes a lot of time init_cryptobox_complete >>"$LOG_FILE" 2>&1 ;; box-init-fg ) # only partitioning and configuration # this is nice for the web interface, as it is fast # output redirection does not work, as it prevents cryptsetup from asking # for a password init_cryptobox_part1 ;; box-init-bg ) # do it in the background to provide a smoother web interface # messages and errors get written to $LOG_FILE init_cryptobox_part2 >"$LOG_FILE" 2>&1 ;; is_crypto_mounted ) is_crypto_mounted ;; is_config_mounted ) is_config_mounted ;; is_init_running ) is_init_running ;; crypto-mount ) mount_crypto ;; crypto-umount ) umount_crypto ;; set_config ) [ $# -ne 3 ] && error_msg 7 "'set_config' requires two parameters" config_set_value "$2" "$3" ;; get_config ) [ $# -ne 2 ] && error_msg 6 "'get_config' requires exactly one parameter" config_get_value "$2" ;; diskinfo ) $SFDISK -L -q -l `find_harddisk` ;; get_current_ip ) get_current_ip ;; is_harddisk_available ) [ -z "$(find_harddisk)" ] && exit 1 exit 0 ;; * ) # TODO: update this! echo "Syntax: `basename $0` { mount_config | umount_config | init }" echo ;; esac