#!/bin/bash

#	The RASServer for managing apf connections.
#	Copyright (C) 2011 Hauke Goos-Habermann (hhabermann@pc-kiel.de)
#
#	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 3 of the License, or any later version.
#
#	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.
#
#	You should have received a copy of the GNU General Public License along with this program;
#	see the file COPYING.  If not, write to the Free Software Foundation, Inc., 59 Temple
#	Place - Suite 330, Boston, MA 02111-1307, USA.





if [ -f ~/.RAS.config ]
then
	. ~/.RAS.config
else
	echo "~/.RAS.config not found"
	exit 1
fi





#####
# name helpPage
# description Generates a help page if RASClient is called with wrong parameters.
# parameter none
#####
helpPage()
{
	echo "This script manages the RASServer (m23 remote administration service).

Usage: $0 <action> <parameter 1> <parameter 2> <parameter ...>

Actions:"

	awk '

	BEGIN {
		show=1
	}

	/^# name / {
		gsub("^# name ","")
		l=l$0
	}

	/^# parameter / {
		gsub("^# parameter ","")
		l=l" <"$0">"
		show=1
	}

	/^# description / {
		gsub("^# description ","")
		d=""$0
	}

	/^#####/ {
		if (show == 1)
		{
			print(l""d)
			l=" * "
			show=0
		}
	}

	' $0 | sort | sed 's//\n   /g'
}





#####
# name helpPage
# description Check, if the account is given
# parameter Account name
#####
checkName()
{
	if [ -z "$1" ]
	then
		echo "Error: No account name given!"
		exit 1
	fi
}





#####
# name checkNameUnused
# description Check, if the account name is used and exitst, if the account is taken
# parameter Account name
#####
checkNameUnused()
{
	if [ $(grep "^realm $name$" $cfg -c) -ne 0 ]
	then
		echo "Error: Account name \"$name\" is used!"
		exit 1
	fi
}





#####
# name checkNameUsed
# description Check if a realm for the account exists and exists, if none is found.
# parameter Account name
#####
checkNameUsed()
{
	if [ $(grep "^realm $name$" $cfg -c) -eq 0 ]
	then
		echo "Error: Account name \"$name\" does not exist!"
		exit 1
	fi
}





#####
# name checkForConf
# description Checks if the config file is present and creates it, if not
# parameter none
#####
checkForConf()
{
	#Create the directory storing the config file
	mkdir -p $(dirname $cfg)

	#Write a basic config file, if it doesn't exists
	if [ ! -f $cfg ]
	then
cat >> $cfg << "EOFcfg"
cerfile server-cert.pem

keyfile         server.rsa

log           file,/home/ras/.apf/server.log,LOG_T_ALL,LOG_I_CRIT,LOG_I_ERR,LOG_I_WARNING
EOFcfg
		echo "Config file \"$cfg\" created!"
	fi
}





#####
# name getHighestPortNumber
# description Gets the highest used port number (or 20000, if no ports are found)
# parameter none
#####
getHighestPortNumber()
{
	port=$(grep ^listenport $cfg | tr -s '[:blank:]' | cut -d' ' -f2 | sort -n -r | head -1)
	if [ -z $port ]
	then
		echo 20000
	else
		echo $port
	fi
}





#####
# name stop
# description Stops the APF server
# parameter none
#####
stop()
{
	killall -9 afserver
	echo "afserver stopped"
}





#####
# name start
# description Starts the APF server and allows requests to the end points from localhost only
# parameter none
#####
start()
{
	#Remove al input filter rulbes
	sudo /sbin/iptables -F INPUT

	#-C 50: 50 afclients are allowed to connect to this server
	#-u 50: 50 users are allowed to connect to this server
	#-R 1: 1 afclients are allowed to remote administrate this server

	afserver -f $cfg -C 50 -u 50 -R 1
	echo "afserver started"

	#Get all listen ports (the ports normally open to the internet on the server)
	grep ^listenport $cfg | tr -s '[:blank:]' | cut -d' ' -f2 | while read port
	do
		#Accept only localhost (and not the internet) to access the port
		sudo /sbin/iptables -A INPUT -p tcp --dport $port -s 127.0.0.1 -j ACCEPT
		#Drop all other attempts to connect to the port
		sudo /sbin/iptables -A INPUT -p tcp --dport $port -j DROP
	done
	echo "Firewall rules set"
}





#####
# name restart
# description Restarts the APF server
# parameter none
#####
restart()
{
	stop
	start
}





#####
# name createNewAccountDo
# description Creats a new account
# parameter Name of the new account
#####
createNewAccountDo()
{
	name="$1"

	checkName $name
	checkNameUnused $name

	#Create values for the account
	pass=$(pwgen 30 1)
	port=$(getHighestPortNumber)
	manageport=$[$port + 1]
	listenport=$[$port + 2]

echo "
realm $name

listenport $listenport  #Port for connecting to the tunneled service
manageport $manageport  #Management port to connect to (with afclient)
pass       $pass        #Password for afclient
" >> $cfg
	echo "Account \"$name\" created!"
}





#####
# name createNewAccount
# description Creates a new account for SSH and WWW tunnels
# parameter Name of the new account
#####
createNewAccount()
{
	createNewAccountDo "$1-ssh"
	createNewAccountDo "$1-www"

	#Create the chat account
	$RASChatAccountManager createNewAccount "$1"

	restart
}





#####
# name enableAccount
# description Enables SSH and WWW tunnels for an account
# parameter Name of the account
#####
enableAccount()
{
	enableAccountDo "$1-ssh"
	enableAccountDo "$1-www"
	$RASChatAccountManager enable "$1"
	restart
}





#####
# name enableAccountDo
# description Enables an account
# parameter Name of the account
#####
enableAccountDo()
{
	name="$1"

	checkName "$name"
	
	tmp="/tmp/$$-disableAccountDo"

awk -vREALM="$name" '
BEGIN {
	copyLines=0
	regexp = "^#realm "REALM"$"
}

$0 ~ regexp {
	copyLines=5
}

{
	if (copyLines > 0)
		{
			gsub("^#","")
			print($0)
			copyLines--
		}
	else
		print($0)
}' $cfg >> $tmp

cat $tmp > $cfg

rm $tmp
}





#####
# name disableAccount
# description Disables SSH and WWW tunnels for an account
# parameter Name of the account
#####
disableAccount()
{
	disableAccountDo "$1-ssh"
	disableAccountDo "$1-www"
	$RASChatAccountManager disable "$1"
	restart
}





#####
# name disableAccountDo
# description Disables an account
# parameter Name of the account
#####
disableAccountDo()
{
	name="$1"

	checkName $name
	checkNameUsed $name
	
	tmp="/tmp/$$-disableAccountDo"

awk -vREALM="$name" '
BEGIN {
	copyLines=0
	regexp = "^realm "REALM"$"
}

$0 ~ regexp {
	copyLines=5
}

{
	if (copyLines > 0)
		{
			print("#"$0)
			copyLines--
		}
	else
		print($0)
}' $cfg >> $tmp

cat $tmp > $cfg

rm $tmp
}





#####
# name getAccountInfo
# description Shows information about an account
# parameter Name of the account
#####
getAccountInfo()
{
	name="$1"

	checkName $name
	checkNameUsed $name

# 	#Get the realm and the following 4 lines (containing ports and password)
	grep "^realm $name$" $cfg -A 4
}





#####
# name getAllAccounts
# description Shows a list of all accounts
# parameter none
#####
getAllAccounts()
{
	echo "Accounts:"
	grep "^realm" $cfg | cut -d' ' -f2

	if [ $(grep "^#realm" $cfg -c) -gt 0 ]
	then
		echo "Disabled accounts:"
		grep "^#realm" $cfg | cut -d' ' -f2
	fi
}





checkForConf

#Make sure, the action doesn't begin with one or more "-" (e.g. if the user decides to use --help)
action=`echo "$1" | sed 's/^-*//g'`

if [ `grep "$action()" $0 -c` -lt 1 ] || [ $# -eq 0 ]
then
	helpPage
else
	shift
	$action $@
fi