#!/bin/sh
# simple setup script for cryptmount
# $Revision: 176 $, $Date: 2007-08-04 14:01:08 +0100 (Sat, 04 Aug 2007) $
# RW Penney, May 2007

# This file is part of 'cryptmount' and is therefore
# supplied with NO WARRANTY of any form.
# Please see the file 'COPYING' in the main cryptmount source directory
# for further information.

CM_BINEXE="/usr/bin/cryptmount"
CM_CFGDIR="/etc/cryptmount"


TrapCleanup() {
    # try to mitigate any damage if terminated prematurely
    echo "abandoning $0 ..."
    exit 2
}


CheckPrivileges() {
    if [ "`whoami`" != "root" ]; then
        echo ""
        echo "This script must be run with superuser privileges"
        echo "Please try again, e.g. using one of the following:"
        echo "    sudo $0"
        echo "    su -c $0"
        echo ""
        exit 1
    fi
}


SectionBreak() {
    echo ""
    if [ "$1" != "minor" ]; then
        echo ""
    fi
}


GetResponse() {
    # Issue prompt string & await response from user
    # syntax: GetResponse <prompt> <default_val> <variable>
    echo ""
    echo "  $1"
    echo -n "  [$2]: "
    read resp
    if [ -z "${resp}" ]; then
        resp="$2"
    fi
    eval "$3=\"${resp}\""
}


GuessHome() {
    # try to guess user's home-directory, even after su/sudo
    guessed_home="${HOME}"
    if [ "${user_owner}" != "" ]; then
        eval "guessed_home=~${user_owner}"
    fi
    for tgt in "${guessed_home}" "${HOME}" "`pwd`" "/home"; do
        hm="`echo ${tgt}/ | sed -n -e 's%^\(/.*home/[^/]*\).*$%\1%p'`"
        if [ "${hm}" != "" -a -d "${hm}" ]; then
            guessed_home="`echo ${hm} | sed 's%/$%%'`"
            break
        fi
    done
}


CanonVars() {
    # canonicalize string variables
    for var in $@; do
        eval "val=\"\$${var}\""
        eval "$var=\"`echo \"${val}\" | sed 's, ,\\\\ ,g'`\""
    done
}


GetTargetName() {
    cat <<EOF
Each cryptmount filesystem is identifed by a short name which is used
when mounting or configuring that filesystem.
This name should be a single word (without spaces), such as "opaque".
EOF
    echo "The following target names have already been used:"
    echo -n "    "
    tgts=`${CM_BINEXE} --list | awk '{printf"%s ", $1}'`
    if [ ! -z "${tgts}" ]; then echo "${tgts}"; else echo "(NONE)"; fi
    echo ""

    target_name=""
    while [ -z "${target_name}" ]; do
        GetResponse "Please enter a target name for your filesystem" "opaque" "target_name"

        if ${CM_BINEXE} --list "${target_name}" >/dev/null 2>&1; then
            echo "The target-name \"${target_name}\" has already been used"
            target_name=""
        fi
    done
}


GetUser() {
    cat <<EOF
The "${target_name}" filesystem can be configured to be owned by
a nominated user, who will be able to create top-level files & directories
without needing to involve the superuser.
EOF

    GetResponse "Which user should own the filesystem (leave blank for "root")" "" "user_owner"
}


GetMountPoint() {
    cat <<EOF
In order to access the "${target_name}" filesystem,
it must be mounted on top of an empty directory.
EOF

    mount_dir=""
    while [ -z "${mount_dir}" ]; do
        GetResponse "Please specify where \"${target_name}\" should be mounted" "${guessed_home}/crypt" "mount_dir"

        if [ -e "${mount_dir}" -a ! -d "${mount_dir}" ]; then
            echo "${mount_dir} is not a valid directory name"
            mount_dir=""
        fi
    done
}


GetContainerInfo() {
    cat <<EOF
The maximum available size of your filesystem needs to be chosen so that
enough space can be reserved on your disk.
EOF

    fs_size=""
    while [ -z "${fs_size}" ]; do
        GetResponse "Enter the filesystem size (in MB)" "64" "fs_size"
        if [ "${fs_size}" -gt 0 ] 2>/dev/null; then
            true
        else
            echo "Invalid number"
            fs_size=""
        fi
    done

    SectionBreak
    cat <<EOF
The actual encrypted filesystem will be stored in a special file, which
needs to be large enough to contain your entire encrypted filesystem.
EOF

    crypto_dev=""
    while [ -z "${crypto_dev}" ]; do
        GetResponse "Enter a filename for your encrypted container" "${guessed_home}/crypto.fs" "crypto_dev"

        if [ -e "${crypto_dev}" ]; then
            echo "WARNING: ${crypto_dev} already exists"
            crypto_dev=""
        fi
    done
}


GetKeyInfo() {
    cat <<EOF
Access to your encrypted filesystem is protected by a key that is kept
in a separate small file. The key is locked by a password that you must
enter whenever you mount the filesystem.
EOF

    key_file=""
    while [ -z "${key_file}" ]; do
        GetResponse "Enter a location for the keyfile" "${CM_CFGDIR}/${target_name}.key" "key_file"

        if [ -e "${key_file}" ]; then
            echo "WARNING: ${key_file} already exists"
            key_file=""
        fi
    done
}


BuildFS() {
    bckp_cmtab="${CM_CFGDIR}/cmtab.bckp-setup"

    cat <<EOF

************************
* Your filing system is now ready to be built.
* This will involve:
    Creating the directory "${mount_dir}"
    Creating a ${fs_size}MB file, "${crypto_dev}"
    Adding an extra entry ("${target_name}") in "${CM_CFGDIR}/cmtab"
    Creating a key-file ("${key_file}")
    Creating an ext3 filingsystem on "${crypto_dev}"
EOF
    if [ -f "${bckp_cmtab}" ]; then
        echo "    Overwriting the backup configuration-file \"${bckp_cmtab}\""
    fi
    echo "* If you do not wish to proceed, no changes will be made to your system."
    GetResponse "Please confirm that you want to proceed (enter \"yes\")" "No" "confirm"
    if [ "`echo ${confirm} | tr 'A-Z' 'a-z'`" != "yes" ]; then
        echo "Installation abandoned"
        exit 1
    fi

    set -e
    echo -n "Making mount-point (${mount_dir})..."
    mkdir -p "${mount_dir}"
    echo " done"
    echo -n "Creating filesystem container (${crypto_dev})..."
    pfx=`dirname "${crypto_dev}"`
    test -d "${pfx}" || mkdir -p "${pfx}"
    dd if=/dev/zero of="${crypto_dev}" bs=1M count="${fs_size}" >/dev/null 2>&1
    echo " done"
    echo -n "Taking backup of cryptmount master config-file (${bckp_cmtab})..."
    mv "${CM_CFGDIR}/cmtab" "${bckp_cmtab}"
    echo " done"
    cat "${bckp_cmtab}" > "${CM_CFGDIR}/cmtab"
    cat <<EOF >> "${CM_CFGDIR}/cmtab"

# entry automatically generated by setup-script:
`echo "${target_name}" | sed 's, ,\\\\ ,g'` {
    dev=`echo "${crypto_dev}" | sed 's, ,\\\\ ,g'`
    dir=`echo "${mount_dir}" | sed 's, ,\\\\ ,g'`
    fstype=ext3
    fsoptions=defaults
    cipher=aes
    keyformat=builtin
    keyfile=`echo "${key_file}" | sed 's, ,\\\\ ,g'`
}
EOF
    echo "Generating filesystem access key (${key_file})..."
    ${CM_BINEXE} --generate-key 32 "${target_name}"
    echo "Formatting encrypted filesystem..."
    ${CM_BINEXE} --prepare "${target_name}"
    mke2fs -j "/dev/mapper/${target_name}" >/dev/null 2>&1
    if [ "${user_owner}" != "" ]; then
	chown "${user_owner}" "${mount_dir}" "${crypto_dev}"
	chmod 0500 "${mount_dir}"
	chmod 0600 "${crypto_dev}"
        mount "/dev/mapper/${target_name}" "${mount_dir}"
        chown "${user_owner}" "${mount_dir}"
        chmod 0700 "${mount_dir}"
        umount "${mount_dir}"
    fi
    ${CM_BINEXE} --release "${target_name}"
}



#
# main program
#

cat <<EOF
********************************
* cryptmount setup script
*
* This program will allow you to setup a secure filing-system that will
* be managed by "cryptmount". You will be able to select basic features
* such as the location and size of the filesystem - if you want more
* advanced features, you should consult the cryptmount manual page.
*
* cryptmount version 2.1, Copyright (C) 2007 RW Penney
* cryptmount comes with ABSOLUTELY NO WARRANTY.
* This is free software, and you are welcome to redistribute it under
* certain conditions - see the file 'COPYING' in the source directory.

EOF


CheckPrivileges
modprobe -q -a dm-mod dm-crypt || true
trap TrapCleanup INT QUIT HUP


# interactively gather configuration information from user:
GetTargetName
SectionBreak
GetUser
GuessHome
SectionBreak
GetMountPoint
SectionBreak
GetContainerInfo
SectionBreak
GetKeyInfo

# build filesystem:
BuildFS

cat <<EOF

Your new encrypted filesystem is now ready for use.
To access, try:
    cryptmount ${target_name}
    cd ${mount_dir}
After you have finished using the filesystem, try:
    cd
    cryptmount --unmount ${target_name}
EOF

exit 0
