#!/bin/sh
# -*- mode: sh; sh-shell: sh -*-
#
# IPsec startup and shutdown command
# Copyright (C) 2006 Michael Richardson <mcr@xelerance.com>
# Copyright (C) 2019 Paul Wouters <pwouters@redhat.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.  See <https://www.gnu.org/licenses/gpl2.txt>.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# WARNING: This script needs updating to use the new libreswan startup method

test $IPSEC_INIT_SCRIPT_DEBUG && set -v -x

LC_ALL=C export LC_ALL

me='ipsec setup'		# for messages

# Misc. paths (some of this should perhaps be overridable from ipsec.conf).
plutopid=/var/run/pluto/pluto.pid
plutoctl=/var/run/pluto/pluto.ctl
subsyslock=/var/lock/subsys/ipsec
lock=/var/run/pluto/ipsec_setup.pid

# defaults for "config setup" items
IPSECuniqueids=${IPSECuniqueids:-yes}
IPSECcrlcheckinterval=${IPSECcrlcheckinterval:-0}
IPSECprotostack=${IPSECprotostack:-bsdkame}
IPSECplutostderrlogtime=${IPSECplutostderrlogtime:-no}

# which kernel are we using?
case $IPSECprotostack in
bsdkame) ;;
*) echo "On FreeBSD the stack must be bsdkame (not $IPSECprotostack)";
	exit 1;;
esac

# Shall we trace?
execute="true"
display="false"
for i in $IPSEC_setupflags
do
	case "$i" in
	"--showonly")	execute="false" ; display=true ;;
	"--show")	display=true ;;
	esac
done

if $display
then
	echo "	" PATH="$PATH"
fi

perform() {
	if $display
	then
		echo "	" "$*"
	fi

	if $execute
	then
		eval "$*"
	fi
}


# for no-stdout logging:
LOGONLY="logger -p daemon.error -t ipsec_setup"

KILLKERNELSTATE='echo "Clearing out any lingering policy ";
           setkey -F;
           setkey -FP'

# do it
case "$1" in
  start|--start|_autostart)
	# First, does it seem to be going already?
	perform test ! -f $lock "||" "{" \
		echo "\"Libreswan IPsec apparently already running, start aborted\"" ";" \
		exit 1 ";" \
		"}"

	# announcement
	# (Warning, changes to this log message may affect barf.)
	version="$(ipsec --version | awk 'NR == 1 { print $(3) }' | sed -e 's/^U\(.*\)\/K(.*/\1/')"
	case "$1" in
	start|--start)	perform echo "\"Starting Libreswan IPsec $version...\""	;;
	_autostart)	perform echo "\"Restarting Libreswan IPsec $version...\""	;;
	esac

	# preliminaries
	perform rm -f $lock

	for f in /dev/random /dev/urandom
	do
		perform test -r $f "||" "{" \
			echo "\"...unable to start Libreswan IPsec, no $f!\"" ";" \
			exit 1 ";" \
			"}"
	done

	# the meaning of $$ at a different runtime is questionable!
	perform echo '$$' ">" $lock
	perform test -s $lock "||" "{" \
		echo "\"...unable to create $lock, aborting start!\"" ";" \
		rm -f $lock ";" \
		exit 1 ";" \
		"}"


	# misc pre-Pluto setup

	perform test -d $(dirname $subsyslock) "&&" touch $subsyslock

	# Pluto
	case "$1" in
	start|--start)	re=	;;
	_autostart)	re=--re	;;
	esac
		perform ipsec _plutorun $re \
			--debug "\"$IPSECplutodebug\"" \
			--uniqueids "\"$IPSECuniqueids\"" \
			--nocrsend "\"$IPSECnocrsend\"" \
			--strictcrlpolicy "\"$IPSECstrictcrlpolicy\"" \
			--keep_alive "\"$IPSECkeep_alive\"" \
			--protostack "\"$IPSECprotostack\"" \
			--virtual_private "\"$IPSECvirtual_private\"" \
			--crlcheckinterval "\"$IPSECcrlcheckinterval\"" \
			--nhelpers "\"$IPSECnhelpers\"" \
			--dump "\"$IPSECdumpdir\"" \
			--stderrlog "\"$IPSECplutostderrlog\"" \
			--plutostderrlogtime "\"$IPSECplutostderrlogtime\"" \
			--log daemon.error \
			--pid "\"$plutopid\"" "||" "{" \
	            $KILLKERNELSTATE ";" \
		    rm -f $lock ";" \
		    exit 1 ";" \
		    "}"

	# done!
	perform echo "\"...Libreswan IPsec started\"" "|" $LOGONLY
	;;

  stop|--stop|_autostop)		# _autostop is same as stop
	# Shut things down.
	perform echo "\"Stopping Libreswan IPsec...\""
	perform \
		if test -r $lock ";" \
		then \
			status=0 ";" \
		else \
			echo "\"stop ordered, but IPsec does not appear to be running!\"" ";" \
			echo "\"doing cleanup anyway...\"" ";" \
			status=1 ";" \
		fi

	perform test -f $plutopid "&&" "{" \
		if ps -p '`' cat $plutopid '`' ">" /dev/null ";" \
		then \
			ipsec whack --shutdown "|" grep -v "^002" ";" \
			sleep 1 ";" \
			if test -s $plutopid ";" \
			then \
				echo "\"Attempt to shut Pluto down failed!  Trying kill:\"" ";" \
				kill '`' cat $plutopid '`' ";" \
				sleep 5 ";" \
			fi ";" \
		else \
			echo "\"Removing orphaned $plutopid:\"" ";" \
		fi ";" \
		rm -f $plutopid ";" \
		"}"

	perform $KILLKERNELSTATE
	rm -f /var/run/pluto.pid

	perform test -d $(dirname $subsyslock) "&&" rm -f $subsyslock

	perform rm -f $lock $plutopid
	perform echo "...Libreswan IPsec stopped" "|" $LOGONLY
	perform exit \$status
	;;

  status|--status)
	if test " $IPSEC_setupflags" != " "
	then
		echo "$me $1 does not support $IPSEC_setupflags"
		exit 1
	fi

	if test -f $lock
	then
		haslock=yes
	fi

	if test -f $subsyslock
	then
		hassublock=yes
	fi

	if test -s $plutopid
	then
		if ps -p $(cat $plutopid) >/dev/null
		then
			plutokind=normal
		elif ps -C pluto >/dev/null
		then
			plutokind=illicit
		fi
	elif ps -C pluto >/dev/null
	then
		plutokind=orphaned
	else
		plutokind=no
	fi

	if test -r /proc/net/ipsec_eroute
	then
		if test " $(wc -l /proc/net/ipsec_eroute 2> /dev/null )" -gt 0
		then
			eroutes=$(wc -l /proc/net/ipsec_eroute 2> /dev/null | sed -e 's/ //g')
		fi
	else
		eroutes=$(ipsec eroute 2> /dev/null | wc -l | sed -e 's/\ //g')
	fi

	if test "$haslock"
	then
		echo "IPsec running"  " - pluto pid: $(cat $plutopid)"
		# might not be a subsystem lock dir, ignore that issue
		if test "$plutokind" = "normal" -a \( "$klips" = "yes" -o "$lk26sec" = "yes" \)
		then
			echo "pluto pid $(cat $plutopid)"
                        case "$eroutes" in
                        0)      echo "No tunnels up"    ;;
                        *)      echo "$eroutes tunnels up"      ;;
                        esac
			exit 0
		fi
		echo "but..."
		if test "$plutokind" != "normal"
		then
			echo "$plutokind Pluto running" " - pluto pid: $(cat $plutopid)"
		fi
		case $klips in
		maybe)	echo "KLIPS module is not loaded!"	;;
		none)	echo "no KLIPS in kernel!"		;;
		esac
		if test "$eroutes"
		then
			if test "$eroutes" -gt 0
			then
				echo "some eroutes exist"
			fi
		fi
	else
		echo "IPsec stopped"
		if test ! "$hassublock" -a "$plutokind" = "no" -a "$eroutes" -eq 0
		then
			exit 0
		fi
		echo "but..."
		if test "$hassublock"
		then
			echo "has subsystem lock ($subsyslock)!"
		fi
		if test "$plutokind" != "no"
		then
			echo "An ${plutokind} Pluto is running?"
		fi
		if test "$eroutes" -gt 0
		then
			echo "some (${eroutes}) eroutes exist!"
		fi
		exit 1
	fi
	# todo: ipsec verify --quiet that only shows problems
	/usr/sbin/ipsec verify;
	exit $?;
	;;

  --version)
	if test " $IPSEC_setupflags" != " "
	then
		echo "$me $1 does not support $IPSEC_setupflags"
		exit 1
	fi

	echo "$me $IPSEC_VERSION"
	exit 0
	;;

  --help)
	if test " $IPSEC_setupflags" != " "
	then
		echo "$me $1 does not support $IPSEC_setupflags"
		exit 1
	fi

	echo "Usage: $me {--start|--stop|--restart|--status}"
	exit 0
	;;

  *)
	echo "Usage: $me {--start|--stop|--restart|--status}" >&2
	exit 2
esac

exit 0
