#!/bin/bash
#
# Initialize ssh server for remote connections (option `--server ssh`)

if [ -z "${virtme_ssh_user}" ]; then
    echo "ssh: virtme_ssh_user is not defined" >&2
    exit 1
fi
if [ -z "${virtme_ssh_channel}" ]; then
    echo "ssh: virtme_ssh_channel is not defined" >&2
    exit 1
fi

rm -f /var/run/nologin

# use an ssh location OUTSIDE of the users home directory to enable sharing
# of host keys and authorized keys without dubious permission errors
SSH_DIR=/run/sshd

# use an ssh location INSIDE of the users home directory to communicate pre-
# created hostkeys and authorized keys
SSH_HOME="$(getent passwd "${virtme_ssh_user}" | cut -d: -f6)"
if [ ! -e "${SSH_HOME}" ]; then
    # Setup an arbitrary ssh location, just to be able to start sshd.
    SSH_HOME="${SSH_DIR}"
fi
SSH_CACHE="${SSH_HOME}"/.cache/virtme-ng/.ssh

# Generate ssh host keys (if they don't exist already).
mkdir -p "${SSH_CACHE}"/etc/ssh
ssh-keygen -A -f "${SSH_CACHE}"

# copy hostkeys to server location
mkdir -p "${SSH_DIR}"/etc/ssh
cp "${SSH_CACHE}"/etc/ssh/* "${SSH_DIR}"/etc/ssh

# Generate authorized_keys in the virtme-ng cache directory and add all
# current user's public keys.
SSH_AUTH_KEYS="${SSH_DIR}"/etc/ssh/authorized_keys
cat "${SSH_HOME}"/.ssh/id_*.pub >> "${SSH_AUTH_KEYS}" 2> /dev/null

# fixup permissions
chown -R root:root "${SSH_DIR}"/etc/ssh
chmod 600 "${SSH_DIR}"/etc/ssh/ssh_host_*_key
chmod 644 "${SSH_DIR}"/etc/ssh/ssh_host_*_key.pub "${SSH_AUTH_KEYS}"

# Determine sftp server (to support scp)
sftp_server=""
if [ -e /usr/lib/ssh/sftp-server ]; then
    sftp_server="Subsystem sftp /usr/lib/ssh/sftp-server"
elif [ -e /usr/lib/openssh/sftp-server ]; then
    sftp_server="Subsystem sftp /usr/lib/openssh/sftp-server"
fi

# Generate a minimal sshd config.
SSH_CONFIG="${SSH_DIR}"/etc/ssh/sshd_config
cat << EOF > "${SSH_CONFIG}"
# This file is automatically generated by virtme-ng.
Port 22
PermitRootLogin yes
AuthorizedKeysFile ${SSH_AUTH_KEYS}
PubkeyAuthentication yes
UsePAM yes
PrintMotd no
${sftp_server}
EOF

# Start sshd.
ARGS=(-f "${SSH_CONFIG}")
for key in "${SSH_DIR}"/etc/ssh/ssh_host_*_key; do
    ARGS+=(-h "${key}")
done

if [[ ${virtme_ssh_channel} == "vsock" ]]; then
    # Make sure vsock (module) is loaded and active, otherwise the '/dev/vsock' device
    # might not be available.
    if ! modprobe vsock &> /dev/null; then
        echo "ssh: vsock module could not be loaded. SSHD cannot be started. Use '--ssh-tcp' instead to fallback to SSH over TCP." >&2
        exit 1
    fi
    # 4294967295 == U32_MAX == -1
    declare -r VMADDR_CID_ANY=4294967295
    # TODO Use something like syslog or journal for the logging
    setsid --fork -- systemd-socket-activate --accept --listen="vsock:${VMADDR_CID_ANY}:22" --inetd -- /usr/sbin/sshd -i "${ARGS[@]}" &> /dev/null < /dev/null
else
    /usr/sbin/sshd "${ARGS[@]}"
fi
