#!/bin/sh

# PROVIDE: openssh
# REQUIRE: DAEMON
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable openssh:
#
# openssh_enable (bool):	Set it to "YES" to enable openssh.
#				Default is "NO".
# openssh_flags (flags):	Set extra flags to openssh.
#				Default is "". see sshd(1).
# openssh_pidfile (file):	Set full path to pid file.

. /etc/rc.subr

name="openssh"
rcvar=openssh_enable

load_rc_config ${name}

: ${openssh_enable:="NO"}
: ${openssh_skipportscheck="NO"}

# These only control ssh-keygen automatically generating host keys.
: ${openssh_dsa_enable="YES"}
: ${openssh_dsa_flags=""}
: ${openssh_rsa_enable="YES"}
: ${openssh_rsa_flags=""}
: ${openssh_ecdsa_enable="YES"}
: ${openssh_ecdsa_flags=""}
: ${openssh_ed25519_enable="YES"}
: ${openssh_ed25519_flags=""}

command=%%PREFIX%%/sbin/sshd
extra_commands="configtest reload keygen"
start_precmd="${name}_checks"
reload_precmd="${name}_checks"
restart_precmd="${name}_checks"
configtest_cmd="${name}_configtest"
keygen_cmd="${name}_keygen"
pidfile=${openssh_pidfile:="/var/run/sshd.pid"}

openssh_keygen()
{
	local skip_dsa= skip_rsa= skip_ecdsa= skip_ed25519=
	checkyesno openssh_dsa_enable || skip_dsa=y
	checkyesno openssh_rsa_enable || skip_rsa=y
	checkyesno openssh_ecdsa_enable || skip_ecdsa=y
	checkyesno openssh_ed25519_enable || skip_ed25519=y

	if [ \( -n "$skip_dsa" -o -f %%ETCDIR%%/ssh_host_dsa_key \) -a \
	    \( -n "$skip_rsa" -o -f %%ETCDIR%%/ssh_host_rsa_key \) -a \
	    \( -n "$skip_ecdsa" -o -f %%ETCDIR%%/ssh_host_ecdsa_key \) -a \
	    \( -n "$skip_ed25519" -o -f %%ETCDIR%%/ssh_host_ed25519_key \) ]; then
		return 0
	fi

	umask 022

	# Can't do anything if ssh is not installed
	[ -x %%PREFIX%%/bin/ssh-keygen ] ||
		err 1 "%%PREFIX%%/bin/ssh-keygen does not exist."

	if [ -f %%ETCDIR%%/ssh_host_dsa_key ]; then
		echo "You already have a DSA host key" \
			"in %%ETCDIR%%/ssh_host_dsa_key"
		echo "Skipping protocol version 2 DSA Key Generation"
	elif checkyesno openssh_dsa_enable; then
		%%PREFIX%%/bin/ssh-keygen -t dsa $openssh_dsa_flags \
			-f %%ETCDIR%%/ssh_host_dsa_key -N ''
	fi

	if [ -f %%ETCDIR%%/ssh_host_rsa_key ]; then
		echo "You already have a RSA host key" \
			"in %%ETCDIR%%/ssh_host_rsa_key"
		echo "Skipping protocol version 2 RSA Key Generation"
	elif checkyesno openssh_rsa_enable; then
		%%PREFIX%%/bin/ssh-keygen -t rsa $openssh_rsa_flags \
			-f %%ETCDIR%%/ssh_host_rsa_key -N ''
	fi

	if [ -f %%ETCDIR%%/ssh_host_ecdsa_key ]; then
		echo "You already have a Elliptic Curve DSA host key" \
			"in %%ETCDIR%%/ssh_host_ecdsa_key"
		echo "Skipping protocol version 2 Elliptic Curve DSA Key Generation"
	elif checkyesno openssh_ecdsa_enable; then
		%%PREFIX%%/bin/ssh-keygen -t ecdsa $openssh_ecdsa_flags \
			-f %%ETCDIR%%/ssh_host_ecdsa_key -N ''
	fi

	if [ -f %%ETCDIR%%/ssh_host_ed25519_key ]; then
		echo "You already have a Elliptic Curve ED25519 host key" \
			"in %%ETCDIR%%/ssh_host_ed25519_key"
		echo "Skipping protocol version 2 Elliptic Curve ED25519 Key Generation"
	elif checkyesno openssh_ed25519_enable; then
		%%PREFIX%%/bin/ssh-keygen -t ed25519 $openssh_ed22519_flags \
			-f %%ETCDIR%%/ssh_host_ed25519_key -N ''
	fi
}

openssh_check_same_ports(){
    # check if opensshd don't use base system sshd's port
    #
    # openssh binds ports in priority (lowest first):
    # Port from sshd_config
    # -p option from command line
    # ListenAddress addr:port from sshd_config


    #check if opensshd-portable installed in replacement of base sshd
    if [ "%%ETCDIR%%" = "/etc/ssh" ]; then
        return 1
    fi

    self_port=$(awk '$1~/^ListenAddress/ \
        {mlen=match($0,":[0-9]*$"); print \
        substr($0,mlen+1,length($0)-mlen)}' %%ETCDIR%%/sshd_config)
    if [ -z "$self_port" ]; then
        self_port=$(echo $openssh_flags | awk \
            '{for (i = 1; i <= NF; i++) if ($i == "-p") \
            {i++; printf "%s", $i; break; }; }')
        if [ -z "$self_port" ]; then
            self_port=$(awk '$1~/^Port/ {print $2}' \
                %%ETCDIR%%/sshd_config)
        fi
    fi
    # assume default 22 port
    if [ -z "$self_port" ]; then
        self_port=22
    fi

    load_rc_config "sshd"

    base_sshd_port=$(awk '$1~/^ListenAddress/ \
        {mlen=match($0,":[0-9]*$"); print \
        substr($0,mlen+1,length($0)-mlen)}' /etc/ssh/sshd_config)
    if [ -z "$base_sshd_port" ]; then
        base_sshd_port=$(echo $sshd_flags | awk \
            '{for (i = 1; i <= NF; i++) if ($i == "-p") \
            {i++; printf "%s", $i; break; }; }')
        if [ -z "$base_sshd_port" ]; then
            base_sshd_port=$(awk '$1~/^Port/ {print $2}' \
                /etc/ssh/sshd_config)
        fi
    fi
    if [ -z "$base_sshd_port" ]; then
        base_sshd_port=22
    fi

    # self_port and base_sshd_port may have multiple values. Compare them all
    for sport in ${self_port}; do
	    for bport in ${base_sshd_port}; do
		    [ ${sport} -eq ${bport} ] && return 0
	    done
    done

    return 1
}

openssh_configtest()
{
	echo "Performing sanity check on ${name} configuration."
	eval ${command} ${openssh_flags} -t
}

openssh_checks()
{
	if checkyesno sshd_enable ; then
      if openssh_check_same_ports && ! checkyesno openssh_skipportscheck; then
          err 1 "sshd_enable is set, but $name and /usr/sbin/sshd use the same port"
      fi
	fi

	openssh_keygen
	openssh_configtest
}

run_rc_command "$1"
