#!/sbin/openrc-run

description="OpenBSD Secure Shell server"
description_checkconfig="Verify configuration file"
description_reload="Reload configuration"

extra_commands="checkconfig"
extra_started_commands="reload"

# NOTE: SSHD_* variables are deprecated and will be removed in future!
: "${sshd_disable_keygen:="${SSHD_DISABLE_KEYGEN:-"no"}"}"
: "${cfgfile:=${SSHD_CONFIG:-"${SSHD_CONFDIR:-"/etc/ssh"}/sshd_config"}}"

pidfile="${SSHD_PIDFILE:-"/run/$RC_SVCNAME.pid"}"
command="${SSHD_BINARY:-"/usr/sbin/sshd"}"
command_args="${command_args:-${SSHD_OPTS:-}}"

required_files="$cfgfile"

generate_host_key_type() {
	local bit_size key_type

	key_type=$1
	if [ ! -f /etc/ssh/ssh_host_"${key_type}"_key ]; then
		case $key_type in
			ecdsa)	bit_size="$ecdsa_bit_size";;
			rsa)	bit_size="$rsa_bit_size";;
		esac
		einfo "Generating $key_type SSH host key..."
		ssh-keygen \
			-q \
			-f /etc/ssh/ssh_host_"$key_type"_key \
			-N '' \
			-t "$key_type" \
			${bit_size:+ -b ${bit_size}} || return 1
	fi
}

generate_host_keys() {
	local type

	if [ -z "$key_types_to_generate" ] &&
	   [ -z "$ecdsa_bit_size" ] && [ -z "$rsa_bit_size" ]; then
		ssh-keygen -A
		return
	fi
	for type in ${key_types_to_generate:-dsa ecdsa ed25519 rsa}; do
		generate_host_key_type "$type" || return 1
	done
}

print_config() {
	"$command" -f "$cfgfile" -G 2>/dev/null
}

match_config() {
	print_config | grep -iqxE -e "$1"
}

print_listen_addresses() {
	print_config | awk '$1 == "listenaddress" && $2 !~ /^(0.0.0.0|\[::\])/ { print $2 }'
}

depend() {
	use logger dns
	after entropy

	if [ "${rc_need+set}" = "set" ] ; then
		: # Do nothing, the user has explicitly set rc_need
	else
		# shellcheck disable=SC2155
		local x addrs="$(print_listen_addresses)"
		if [ -n "$addrs" ] ; then
			need net
			ewarn "You are binding an interface in ListenAddress statement in your sshd_config!"
			ewarn "You must add rc_need=\"net.FOO\" to your /etc/conf.d/sshd"
			ewarn "where FOO is the interface(s) providing the following address(es):"
			for x in $addrs; do
				ewarn "  ${x%:*}"
			done
		fi
	fi
}

update_command() {
	if [ -x /usr/sbin/sshd.krb5 ] && command="/usr/sbin/sshd.krb5" \
	    match_config "(Kerberos|GSSAPI)Authentication yes"; then
		command="${SSHD_BINARY:-"/usr/sbin/sshd.krb5"}"
	elif [ -x /usr/sbin/sshd.pam ] && command="/usr/sbin/sshd.pam" \
	    match_config "UsePAM yes"; then
		command="${SSHD_BINARY:-"/usr/sbin/sshd.pam"}"
	fi
}

checkconfig() {
	update_command
	warn_deprecated_var SSHD_BINARY
	warn_deprecated_var SSHD_CONFDIR
	warn_deprecated_var SSHD_CONFIG cfgfile
	warn_deprecated_var SSHD_DISABLE_KEYGEN sshd_disable_keygen
	warn_deprecated_var SSHD_OPTS command_args
	warn_deprecated_var SSHD_PIDFILE

	if [ ! -d /var/empty ] ; then
		mkdir -p /var/empty || return 1
	fi

	if ! yesno "$sshd_disable_keygen"; then
		generate_host_keys || return 1
	fi

	[ "$pidfile" != "/run/sshd.pid" ] \
		&& command_args="$command_args -o PidFile=$pidfile"

	[ "$cfgfile" != "/etc/ssh/sshd_config" ] \
		&& command_args="$command_args -f $cfgfile"

	# shellcheck disable=SC2086
	"$command" -t $command_args || return 1
}

start_pre() {
	checkconfig
}

stop_pre() {
	update_command
	if [ "${RC_CMD}" = "restart" ] ; then
		checkconfig || return 1
	fi
}

stop_post() {
	if [ "$RC_RUNLEVEL" = "shutdown" ]; then
		_sshd_pids=$(pgrep "sshd-session:")
		if [ -n "$_sshd_pids" ]; then
			ebegin "Shutting down ssh connections"
			# shellcheck disable=SC2086
			kill -TERM $_sshd_pids >/dev/null 2>&1
			eend 0
		fi
	fi
}

reload() {
	checkconfig || return 1

	ebegin "Reloading $RC_SVCNAME"
	start-stop-daemon --signal HUP \
		--exec "$command" --pidfile "$pidfile"
	eend $?
}

warn_deprecated_var() {
	local varname="$1"
	local replacement="${2:-}"

	eval "test -n \"\$$varname\"" || return 0

	ewarn "Variable \$$varname is deprecated and will be removed in the future!"
	# shellcheck disable=SC2015
	[ "$replacement" ] && ewarn "Use \$$replacement instead of \$$varname." ||:
}
