#!/bin/bash

#
# lxc: linux Container library

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

# Detect use under userns (unsupported)
for arg in "$@"; do
    [ "$arg" = "--" ] && break
    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
        echo "This template can't be used for unprivileged containers." 1>&2
        echo "You may want to try the \"download\" template instead." 1>&2
        exit 1
    fi
done

# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin

install_sshd()
{
    rootfs=$1

    tree="\
$rootfs/var/run/sshd \
$rootfs/var/empty/sshd \
$rootfs/var/lib/empty/sshd \
$rootfs/etc/init.d \
$rootfs/etc/rc.d \
$rootfs/etc/ssh \
$rootfs/etc/sysconfig/network-scripts \
$rootfs/dev/shm \
$rootfs/run/shm \
$rootfs/proc \
$rootfs/sys \
$rootfs/bin \
$rootfs/sbin \
$rootfs/usr \
$rootfs/tmp \
$rootfs/home \
$rootfs/root \
$rootfs/lib \
$rootfs/lib64"

    mkdir -p $tree
    if [ $? -ne 0 ]; then
        return 1
    fi

    return 0
}

configure_sshd()
{
    rootfs=$1

    cat <<EOF > $rootfs/etc/passwd
root:x:0:0:root:/root:/bin/bash
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
EOF

    cat <<EOF > $rootfs/etc/group
root:x:0:root
sshd:x:74:
EOF

ssh-keygen -t rsa -N "" -f $rootfs/etc/ssh/ssh_host_rsa_key
ssh-keygen -t dsa -N "" -f $rootfs/etc/ssh/ssh_host_dsa_key

    # by default setup root password with no password
    cat <<EOF > $rootfs/etc/ssh/sshd_config
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 768
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords yes
ChallengeResponseAuthentication no
EOF

    if [ -n "$auth_key" -a -f "$auth_key" ]; then
        u_path="/root/.ssh"
        root_u_path="$rootfs/$u_path"
        mkdir -p $root_u_path
        cp $auth_key "$root_u_path/authorized_keys"
        chown -R 0:0 "$rootfs/$u_path"
        chmod 700 "$rootfs/$u_path"
        echo "Inserted SSH public key from $auth_key into $rootfs/$u_path"
    fi

    return 0
}

copy_configuration()
{
    path=$1
    rootfs=$2
    name=$3

    init_path=$(realpath --relative-to=/ $(readlink -f /sbin/init))

    grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
cat <<EOF >> $path/config
lxc.utsname = $name
lxc.pts = 1024
lxc.cap.drop = sys_module mac_admin mac_override sys_time

# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.aa_profile = unconfined

lxc.mount.entry = /dev dev none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = tmpfs var/run/sshd tmpfs mode=0644 0 0
lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd $init_path none ro,bind 0 0
lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0

lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
EOF

    # Oracle Linux and Fedora need the following two bind mounted
    if [ -d /etc/sysconfig/network-scripts ]; then
        cat <<EOF >> $path/config
lxc.mount.entry = /etc/sysconfig/network-scripts etc/sysconfig/network-scripts none ro,bind 0 0
EOF
    fi

    if [ -d /etc/rc.d ]; then
        cat <<EOF >> $path/config
lxc.mount.entry = /etc/rc.d etc/rc.d none ro,bind 0 0
EOF
    fi

    # if no .ipv4 section in config, then have the container run dhcp
    grep -q "^lxc.network.ipv4" $path/config || touch $rootfs/run-dhcp

    if [ "$(uname -m)" = "x86_64" ]; then
        cat <<EOF >> $path/config
lxc.mount.entry = /lib64 lib64 none ro,bind 0 0
EOF
    fi
}

usage()
{
    cat <<EOF
$1 -h|--help -p|--path=<path> [--rootfs=<path>]
EOF
    return 0
}

check_for_cmd()
{
    cmd_path=`type $1`
    if [ $? -ne 0 ]; then
        echo "The command '$1' $cmd_path is not accessible on the system"
        exit 1
    fi
    # we use cut instead of awk because awk is alternatives symlink on ubuntu
    # and /etc/alternatives isn't bind mounted
    cmd_path=`echo $cmd_path |cut -d ' ' -f 3`
}

options=$(getopt -o hp:n:S: -l help,rootfs:,path:,name:,auth-key: -- "$@")
if [ $? -ne 0 ]; then
        usage $(basename $0)
    exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
        --rootfs)       rootfs=$2; shift 2;;
        -n|--name)      name=$2; shift 2;;
        -S|--auth-key)  auth_key=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi

if [ $0 = "/sbin/init" ]; then

    PATH="$PATH:/bin:/sbin:/usr/sbin"
    check_for_cmd @SBINDIR@/init.lxc
    check_for_cmd sshd
    sshd_path=$cmd_path

    # run dhcp?
    if [ -f /run-dhcp ]; then
        check_for_cmd dhclient
        check_for_cmd ifconfig
        touch /etc/fstab
        rm -f /dhclient.conf
        cat > /dhclient.conf << EOF
send host-name = gethostname();
EOF
        ifconfig eth0 up
        dhclient eth0 -cf /dhclient.conf
        echo "Container IP address:"
        ifconfig eth0 |grep inet
    fi

    exec @SBINDIR@/init.lxc -- $sshd_path
    exit 1
fi

if [ -z "$path" ]; then
    echo "'path' parameter is required"
    exit 1
fi

# detect rootfs
config="$path/config"
if [ -z "$rootfs" ]; then
    if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
        rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
    else
        rootfs=$path/rootfs
    fi
fi

install_sshd $rootfs
if [ $? -ne 0 ]; then
    echo "failed to install sshd's rootfs"
    exit 1
fi

configure_sshd $rootfs
if [ $? -ne 0 ]; then
    echo "failed to configure sshd template"
    exit 1
fi

copy_configuration $path $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed to write configuration file"
    exit 1
fi
