#! /bin/sh -
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2021 Mateusz Piotrowski <0mp@FreeBSD.org>
#

# Usage: service openconnect COMMAND [SERVICE]
#
# COMMAND	The service script command. See the rc(8) manual page
#		for details. The non-standard service script commands are:
#
#		setpassword	Prompt the user for a password
#				and save it to the password file.
#
# SERVICE	The name of the OpenConnect service to apply the command to.
#		Default: "default".
#
# Add the following lines to rc.conf(5) to enable the OpenConnect VPN service:
#
# openconnect_SERVICE_enable (bool):
#				Set to "YES" to enable the OpenConnect service.
#				Please note that it does not make the service
#				start during boot (see the openconnect_services
#				service file if starting during boot is
#				desired).
#				Default: "NO".
# openconnect_SERVICE_args (string):
#				Append the specified string to the list of
#				command arguments.
#				Default: "NO".
# openconnect_SERVICE_server (string):
#				Set the VPN server to connect to.
#				Default: unset.
# openconnect_SERVICE_otp_cmd (string):
#				Provide a shell command to execute to obtain an
#				OTP token for authentication.
#				Default: "".
# openconnect_SERVICE_password_file (path):
#				Set a path to the file storing the VPN password.
#				Default: "/usr/local/etc/openconnect/passwords/SERVICE".
# openconnect_SERVICE_username (string):
#				Set the user and pass it as an argument to the
#				--user flag.
#				Default: unset, the flag is not passed.
#
# Note, that due to the use of daemon(8) some standard rc.subr(8) variables
# like openconnect_flags are not supported.

# PROVIDE: openconnect
# REQUIRE: NETWORKING
# KEYWORD: nostart

. /etc/rc.subr

_service="${2-default}"

name="openconnect_${_service}"
rcvar="openconnect_${_service}_enable"

load_rc_config "${name}"

_rundir="/var/run/openconnect"
_secrets="${_rundir}/${_service}.secrets"
pidfile="${_rundir}/${_service}.pid"

eval : "\${openconnect_${_service}_enable:=NO}"
eval : "\${openconnect_${_service}_password_file:=/usr/local/etc/openconnect/passwords/${_service}}"

eval _args=\$openconnect_${_service}_args
eval _server=\$openconnect_${_service}_server
eval _otp_cmd=\$openconnect_${_service}_otp_cmd
eval _password_file=\$openconnect_${_service}_password_file
eval _username=\$openconnect_${_service}_username

_username="${_username:+--user ${_username}}"

procname="/usr/local/sbin/openconnect"
command="/usr/sbin/daemon"
command_args="-o /var/log/${name}.log -p ${pidfile} -- ${procname}"
command_args="${command_args} --passwd-on-stdin < ${_secrets}"
command_args="${command_args} --non-inter"
command_args="${command_args} --quiet"
command_args="${command_args} ${_username}"
command_args="${command_args} ${_args}"
command_args="${command_args} ${_server}"
sig_reload="SIGUSR2"

required_files="$_password_file"

extra_commands="setpassword"

setpassword_cmd="openconnect_setpassword"
start_precmd="openconnect_prestart"
start_postcmd="rm -f ${_secrets}"

openconnect_setpassword()
{
	local _password

	if ! stty -echo; then
		err 1 "Failed to turn off echo"
	fi
	if ! mkdir -p /usr/local/etc/openconnect/passwords; then
		stty echo
		err 1 "Failed to create the passwords directory"
	fi
	if ! read -r -p "Password ($name): " _password; then
		stty echo
		err 1 "Failed read the password from standard input"
	fi
	echo ""
	if ! (umask 077 && echo "$_password" > ${_password_file}); then
		stty echo
		err 1 "Failed to save password to \"${_password_file}\""
	fi
	stty echo
}

openconnect_prestart()
{
	if ! mkdir -p "${_rundir}"; then
		err 1 "Unable to create a directory for PID and secrets files"
	fi

	if ! rm -f "${_secrets}"; then
		err 1 "Failed to clean up the old secrets file"
	fi

	if ! (umask 077; cat "${_password_file}" > "${_secrets}"); then
		err 1 "Failed to create a new secrets file"
	fi

	if [ "${_otp_cmd}" ]; then
		if ! eval ${_otp_cmd} >> "${_secrets}"; then
			err 1 "Failed to generate a token"
		fi
	fi
}

run_rc_command "$1"
