#!/bin/bash

# This file is part of the  X2Go Project - http://www.x2go.org
# Copyright (C) 2018-2020 by Stefan Baur <X2Go-ML-1@baur-itcs.de>
#
# X2Go Mini SSH Session Broker is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# X2Go Mini SSH Session Broker 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# Features and Limitations
# You can add sessions as for-everyone (defaultsessions), per-group, and per-user
# You cannot add sessions based on IP range
# You cannot deny sessions based on group, user, or IP range
# Checking for suspended sessions and resuming them only works if you are logged in
#   to the broker with the same credentials that you want to use to start/resume
#   the session AND
#   if broker and X2Go server are one and the same machine
#   (This could be expanded so it works with separate machines, as long as ssh
#   public/private key authentication and autologin is used.)

# Config goes here - always only one session per file!
# /etc/x2go/x2go-mini-sshbroker/defaultsessions/*.session
# /etc/x2go/x2go-mini-sshbroker/${USER}/*.session
# /etc/x2go/x2go-mini-sshbroker/groups/${GROUP}/*.session

### init ###
# make a list of the parameters we received on the command line
PARAMLIST=$(echo -e "$@" | sed -e 's/ --/\n--/g')

# make sure we have a directory to write our config file to
mkdir -p ~/.x2go

### main ###

# check if we were asked to list sessions
if (echo -e "$PARAMLIST" | grep -q -- '--task listsessions'); then

	# this is so we can request data for a username that is different from the one we used
	# to log in and run this script with
	REQUESTEDUSER=$(echo -e "$PARAMLIST" | awk '$1 == "--user" { print $2}')
	if [ -n "$REQUESTEDUSER" ]; then
		USER=$REQUESTEDUSER
	fi

	# fetch default sessions
	if [ -d /etc/x2go/x2go-mini-sshbroker/defaultsessions ]; then
		for SINGLESESSIONFILE in /etc/x2go/x2go-mini-sshbroker/defaultsessions/*.session ; do
			# add session file name to the list of sessionfiles
			SESSIONFILES+="$SINGLESESSIONFILE\n"
			# figure out what the name of the session should be, based on the filename
			SINGLESESSIONNAME=$(basename $SINGLESESSIONFILE | sed -e 's/\.session$//')
			# check if the session file already contains a proper header block
			if (grep -q "^\[$SINGLESESSIONNAME\]" $SINGLESESSIONFILE); then
				# if it does, all we do is replace the user name
				SESSIONLIST+="\n$(grep -v '^user=' $SINGLESESSIONFILE)\nuser=$USER\n"
			else
				# if it does not, we add a header based on the file name, and replace the user name
				SESSIONLIST+="\n[$SINGLESESSIONNAME]\n$(grep -v '^\[' $SINGLESESSIONFILE | grep -v '^user=')\nuser=$USER\n"
			fi
		done
	fi

	# fetch user-specific sessions
	if [ -d /etc/x2go/x2go-mini-sshbroker/$USER ]; then
		for SINGLESESSIONFILE in /etc/x2go/x2go-mini-sshbroker/$USER/*.session ; do
			# add session file name to the list of sessionfiles
			SESSIONFILES+="$SINGLESESSIONFILE\n"
			# figure out what the name of the session should be, based on the filename
			SINGLESESSIONNAME=$(basename $SINGLESESSIONFILE | sed -e 's/\.session$//')
			# check if the session file already contains a proper header block
			if (grep -q "^\[$SINGLESESSIONNAME\]" $SINGLESESSIONFILE); then
				# if it does, all we do is replace the user name
				SESSIONLIST+="\n$(grep -v '^user=' $SINGLESESSIONFILE)\nuser=$USER\n"
			else
				# if it does not, we add a header based on the file name, and replace the user name
				SESSIONLIST+="\n[$SINGLESESSIONNAME]\n$(grep -v '^\[' $SINGLESESSIONFILE | grep -v '^user=')\nuser=$USER\n"
			fi
		done
	fi

	# fetch group-specific sessions
	if [ -d /etc/x2go/x2go-mini-sshbroker/groups ]; then
		# determine groups for this user and work through the list
		for SINGLEGROUP in $(id -Gn $USER) ; do
			if [ -d /etc/x2go/x2go-mini-sshbroker/groups/$SINGLEGROUP ]; then
				for SINGLESESSIONFILE in /etc/x2go/x2go-mini-sshbroker/groups/$SINGLEGROUP/*.session ; do
					# add session file name to the list of sessionfiles
					SESSIONFILES+="$SINGLESESSIONFILE\n"
					# figure out what the name of the session should be, based on the filename
					SINGLESESSIONNAME=$(basename $SINGLESESSIONFILE | sed -e 's/\.session$//')
					# check if the session file already contains a proper header block
					if (grep -q "^\[$SINGLESESSIONNAME\]" $SINGLESESSIONFILE); then
						# if it does, all we do is replace the user name
						SESSIONLIST+="\n$(grep -v '^user=' $SINGLESESSIONFILE)\nuser=$USER\n"
					else
						# if it does not, we add a header based on the file name, and replace the user name
						SESSIONLIST+="\n[$SINGLESESSIONNAME]\n$(grep -v '^\[' $SINGLESESSIONFILE | grep -v '^user=')\nuser=$USER\n"
					fi
				done
			fi
		done
	fi

	# store list of session files
	TEMPBROKERSESSIONFILE=$(mktemp -p ~/.x2go)
	echo -e "$SESSIONFILES">$TEMPBROKERSESSIONFILE
	# atomic transaction, so it is always complete when accessed, even when multiple instances are run in parallel
	mv $TEMPBROKERSESSIONFILE ~/.x2go/brokersessionfile-${USER} # needs user name, in case we ssh'ed into the broker using different credentials

	# output all session data
	echo -e "Access granted"
	echo -e "START_USER_SESSIONS"
	echo -e "$SESSIONLIST"
	echo -e "END_USER_SESSIONS"

# check if we were asked to provide a server name/IP and port for a specific session
elif (echo -e "$PARAMLIST" | grep -q -- '--task selectsession'); then
		SESSIONID=$(echo -e "$PARAMLIST" | awk '$1 == "--sid" { print $2 }')
		# search for the line with the corresponding session file in our stored list of files
		SESSIONFILE=$(grep "$SESSIONID" ~/.x2go/brokersessionfile-${USER})
		# determine server name/IP and port from this file
		SERVER=$(awk -F '=' '$1 == "host" { print $2 }' $SESSIONFILE)
		PORT=$(awk -F '=' '$1 == "sshport" { print $2 }' $SESSIONFILE)
		# if this failed, set default values
		if [ -z "$SERVER" ] && [ -f /etc/x2go/x2go-mini-sshbroker/defaulthost ]; then
			# determine default hostname/IP
			read DEFAULTHOST </etc/x2go/x2go-mini-sshbroker/defaulthost
			SERVER=$DEFAULTHOST
		fi

		if [ -z "PORT" ]; then
			PORT=22
		fi

		# output all data
		echo -e "Access granted"
		echo -e "SERVER:$SERVER:$PORT"
		# check for suspended sessions
		SESSIONLIST=$(x2golistsessions)
		# NOTE: at present, this only checks for local sessions (X2GoBroker==X2GoServer)
		# to make this work with a separate X2GoServer, we would need something like
		#if [ -z "$SESSIONLIST" ] && [ -n "$SSH_AUTH_SOCK" ]; then
		#	# very hackish and not safe! Try to add hosts to a shared known_hosts file in advance, and place it in /etc/x2go/x2go-mini-sshbroker/
		#	# then point UserKnownHostsFile at that and get rid of the StrictHostKeyChecking=false
		#	SESSIONLIST=$(ssh -oStrictHostKeyChecking=false -oUserKnownHostsFile=/dev/null -p $PORT -A $USER@$SERVER x2golistsessions 2>/dev/null)
		#fi
		# but the problem is, that it seems SSH_AUTH_SOCK is not set by the broker when logging in
		# one way around this might be an ssh private key stored in /etc/x2go/x2go-mini-sshbroker/, that is added as a limited key with
		# "forced-command=x2golistsessions_root" to /root/.ssh/authorized_keys to all servers - the output would then have to be filtered for the
		# username in question, as _root shows the data of all users on that particular host
		if [ -n "$SESSIONLIST" ]; then
			echo "SESSION_INFO:$SESSIONLIST"
		fi
fi
# DEBUG echo "$@" >>/tmp/x2go-mini-sshbroker-commands
