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

log() {
    if [[ -e /dev/kmsg ]]; then
        echo "<6>virtme-init: $*" > /dev/kmsg
    else
        echo "virtme-init: $*"
    fi
}

if [ -z "${virtme_ssh_cache}" ]; then
    log "ssh: virtme_ssh_cache is not defined"
    exit 1
fi
if [ -z "${virtme_ssh_channel}" ]; then
    log "ssh: virtme_ssh_channel is not defined"
    exit 1
fi
if [[ ! -f /usr/sbin/sshd ]]; then
    log "ssh: /usr/sbin/sshd does not exist."
    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
SSH_CACHE="${virtme_ssh_cache}"
if [[ "${SSH_CACHE}" == "/run/virtme/cache/.ssh" ]]; then
    SSH_HOME=/run/virtme/cache
else
    SSH_HOME="${SSH_CACHE%/.cache/virtme-ng/.ssh}"
fi

# 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 from the host user's public keys and id_virtme.
SSH_AUTH_KEYS="${SSH_DIR}"/etc/ssh/authorized_keys
: > "${SSH_AUTH_KEYS}"
if [[ ! -r "${SSH_CACHE}"/id_virtme.pub ]]; then
    log "ssh: missing ${SSH_CACHE}/id_virtme.pub"
    exit 1
fi
cat "${SSH_HOME}"/.ssh/id_*.pub >> "${SSH_AUTH_KEYS}" 2> /dev/null
cat "${SSH_CACHE}"/id_virtme.pub >> "${SSH_AUTH_KEYS}"

# 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
StrictModes 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
        log "ssh: vsock module could not be loaded. SSHD cannot be started. Use '--ssh-tcp' instead to fallback to SSH over TCP."
        exit 1
    fi

    if (("${virtme_empty_passwords:-0}" == 1)); then
        echo 'PermitEmptyPasswords yes' >> "${SSH_CONFIG}"
    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
    if (("${virtme_empty_passwords:-0}" == 1)); then
        log "Using TCP-based SSH together with empty passwords is insecure."
        exit 1
    fi

    /usr/sbin/sshd "${ARGS[@]}"
fi
