[X2Go-Dev] Bug#922: Avoiding X2GO Servers all using the same SSH_PORT - what conflicts when try to connect to different servers from one windows terminal (multiple sessions of x2go client)

Robert Nowotny rnowotny at rotek.at
Mon Aug 17 15:53:21 CEST 2015


Package: x2goagent
Version: 3.5.0.32


As discussed with IONIC, there is a problem when You try to connect to 
different servers from Windows at the same time, using multiple 
instances of x2go client.
The reason is, that the x2go servers are all using the same SSH_Port. 
That should not be a problem from my point of view, so that behaviour 
should be further investigated.

The problem was reported already a very long time ago, but still exists 
: https://www.mail-archive.com/x2go-user@lists.berlios.de/msg00547.html

In the meantime, here a small patch for x2gostartagent script:
That patch uses a different SSH_PORT for each Server, therefore try to 
avoid conflicts.

There are two methods implemented :

method one, suitable for Class "C" Networks, with no possible conflicts. 
The SSH Port is dependent on the last octet of the servers host adress.
method two, with randomized ports, what may lead to conflicts from case 
to case, but can handle networks were servers might have the same last 
octet of the host adress.

However, that patch enables to have multiple instances of x2goclients 
running on one windows machine, against different hosts.

please find attached the IRC conversation log with Ionic, as well as the 
patched script for x2gostartagent

I hove it can be committed, I am getting tired to patch my hosts on 
every x2go server update ;-)

yours sincerely

Robert Nowotny
Rotek GmbH

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.x2go.org/pipermail/x2go-dev/attachments/20150817/e631bb2f/attachment-0001.html>
-------------- next part --------------

Session Start: Mon Aug 17 12:51:17 2015
Session Ident: #x2go
03[12:51] * Now talking in #x2go
03[12:51] * Topic is 'X2Go is a suite to build Linux based terminal farms. The channel's language is English. For further info on X2Go please visit: http://www.x2go.org.'
03[12:51] * Set by MeinNameIstRetro on Wed Jun 24 22:59:11 2015
01[12:51] <rnowotny> good afternoon
01[12:57] <rnowotny> is there someone listening ?
[12:57] <Ionic> sometimes, yes...
01[12:57] <rnowotny> ;-)
01[12:58] <rnowotny> ok. first I have to say this is my first contact with x2go development. Althought I use x2go for a long time, and vefore I was using nx.
01[12:58] <rnowotny> so please be pationt with me.
01[12:59] <rnowotny> patient
[13:00] <Ionic> ok?
01[13:00] <rnowotny> as I read, it is neccessary to edit the x2gostartagent, SSH_Port=30000   parameter for each host on the network, in order to be able to connect to multiple hosts from one windows client (multiple instances of the X2go client) 
01[13:01] <rnowotny> I have written a small patch for the x2gostartagent, to set the SSH_Port depending on the last octet of the servers IP Adress.
01[13:01] <rnowotny> I konw that might not be perfect, but should avoid collisions on class C-Networks
[13:02] <Ionic> hum
[13:02] <Ionic> is it necessary to edit x2gostartagent? that sounds wierd
01[13:02] <rnowotny> I can provide the patch ( a few lines) - but I havent set up GIT, so maybe someone more experienced than me can review and possibly propose the patch on git.
[13:02] <Ionic> well we're probably using a fixed port number
01[13:03] <rnowotny> Ionic - yes
[13:03] <Ionic> but wouldn't the client also need a change?
01[13:03] <rnowotny> Port is fixed to 30001 - and is later checked in the script if it is free
01[13:03] <rnowotny> Ionic, no
01[13:03] <rnowotny> no, client dont need to change
[13:03] <Ionic> hmhmhm
01[13:04] <rnowotny> I tested (well, others tested that before)
01[13:04] <rnowotny> and its working
01[13:05] <rnowotny> althought I dont know if there will be any side - effects - but there should nor be some. Because the Script x2gostartagent try to find a free port beginning from port 30001
[13:05] <Ionic> so, why would you need to change that starting port in the first place?
01[13:06] <rnowotny> because You cant use multiple client sessions on windows if the servers use all the same port
[13:06] <Ionic> well each session must use a different port which is also registered in the DB, right?
01[13:06] <rnowotny> no
01[13:07] <rnowotny> it is the reverse port
01[13:08] <rnowotny> the problem is well aware, and already known and tested. But users have to edit x2gostartagent manually, after each update
[13:09] <Ionic> well I'm not aware of it, at least not until now
01[13:09] <rnowotny> so I suggest to start to search for a free port from 30.000 + last octet of the IP adress - to avoid possible conflicts in most cases.
01[13:10] <rnowotny> Ionic, one momet, I will give You the link to the post
[13:10] <Ionic> the last octet isn't really a good fingerprint
01[13:12] <rnowotny> https://www.mail-archive.com/x2go-user@lists.berlios.de/msg00547.html
01[13:12] <rnowotny> check this out
01[13:13] <rnowotny> I know, using the last octet is not perfect. 
[13:13] <Ionic> oh that's old
01[13:13] <rnowotny> But unless there is a better solution, it will avoid collisions in most cases
01[13:14] <rnowotny> but we only have lets say 40.000 Ports available, so it is not possible to map 256*256*256*256 IP4 Adresses to Ports ... 
01[13:14] <rnowotny> yes, it is old, but still true
[13:14] <Ionic> I still don't understand why that is, though
01[13:14] <rnowotny> me neither
[13:14] <Ionic> does the client connect back to the server?
[13:14] <Ionic> err
01[13:14] <rnowotny> because it should be able to handle the same port from different hosts
[13:14] <Ionic> other way around
[13:14] <Ionic> does the server connect back to the client?
01[13:15] <rnowotny> I dont know.
[13:15] <Ionic> AFAIK the client (nxproxy) connects to the server
[13:15] <Ionic> well, but naturally
[13:15] <Ionic> if you have two sessions on the same port, that won't work
01[13:15] <rnowotny> Well, it is like it is. I cant dig too deep, thats just my workaround, until something better comes up.
[13:15] <Ionic> there's a more subtle problem to that
01[13:15] <rnowotny> but it bores me, to apply my patch on each upgrade of x2go servewr
[13:16] <Ionic> I understand that, I'm just not sure that's the best way to go...
01[13:16] <rnowotny> hm. at least it is a bullet prooved solution in a class C net - what is the majority I guess
[13:16] <Ionic> the real culprit lies in forwarding fixed ports in the first part
01[13:16] <rnowotny> and it does not harm 
[13:17] <Ionic> that depends, your solution will also break easily
01[13:17] <rnowotny> not easily. It CAN break. But on the other hand, all Servers starting on 30000 will brake for sure.
[13:17] <Ionic> let's say you have a server with ending in .50, so the first port that gets used will be 30051 (or so)
01[13:18] <rnowotny> right
[13:18] <Ionic> the next one will be ending in .51 and thus start at 30052
01[13:18] <rnowotny> correct
[13:18] <Ionic> that'll work for the first session
01[13:18] <rnowotny> yes
01[13:18] <rnowotny> I know
[13:18] <Ionic> but if you start a second session on server1, you won't be able to use the first (and only) session on server2, because it uses 30052
01[13:18] <rnowotny> yes, I know
01[13:19] <rnowotny> but that problem cant be solved, since the servers dont know of each other
[13:19] <Ionic> your solution might be better than what we currently have
01[13:19] <rnowotny> if You come up with someting better - I would love it
[13:19] <Ionic> well, other than adding random data to the starting port number instead of a guessable last octet of the IPv4 address
[13:20] <Ionic> but I'm unhappy with both of them, because that shouldn't be a problem in the first place
01[13:20] <rnowotny> yeah, You can add a random data. Or multiply the last octet with 16, so You can be able to use at least 16 sessions per host, thats a good idea
[13:21] <Ionic> I would probably just a random integer between 1 and 500 or whatever
01[13:21] <rnowotny> I agree. But its a quick patch, until You come up with something better
[13:21] <Ionic> every time the script is ran
[13:21] <Ionic> or hell maybe even a higher number
01[13:22] <rnowotny> I have read the development issues - multiple windows sessions are #1 priority, so i guess my patch is only for the time beeing, until the perfect solution is available
01[13:22] <rnowotny> Ionic, yes, i will calculate - give me a minute
[13:22] <Ionic> weeeell, let's say it would be a great feature to have
01[13:23] <rnowotny> ok, we can multiply the last octet with 128
01[13:23] <rnowotny> 128 sessions per host should be enough ... 
01[13:23] <rnowotny> right ? 
[13:23] <Ionic> but I'm actually working on other stuff currently (or, sadly, for the most part nothing even x2go-related)
01[13:24] <rnowotny> I can send You the patch. Its very short. I dont want to install all the git stuff for that few lines.
[13:24] <Ionic> why would you think it's 128 sessions per host? :)
[13:24] <Ionic> it's just one again
01[13:24] <rnowotny> whatever - we have 128 ports
[13:24] <Ionic> oh, wait, multiplication
01[13:25] <rnowotny> yes. SSH_PORT = 30.000 + (128 x IP last octet)
[13:25] <Ionic> could actually become a problem
01[13:25] <rnowotny> why ?
[13:25] <Ionic> 32640 + 30000 = 62640
01[13:25] <rnowotny> right
01[13:25] <rnowotny> and we have 64000 ports available
[13:26] <Ionic> it's still below the 65535, so still working
01[13:26] <rnowotny> right. I calculated factor 128 to be well below 65535
[13:27] <Ionic> but at that point, why not adding a random number between 1 and 30000 each time?
[13:28] <Ionic> if you happen to be unfortunate enough to have to machines ending in the same octet, you'd be screwed with your approach
01[13:28] <rnowotny> because the poirts below 30.000 may be used by other services. 
01[13:28] <rnowotny> above 30.000 its free
[13:28] <Ionic> with randomization, you might be randomly screwed, but...
[13:28] <Ionic> huh?
01[13:28] <rnowotny> and a random number still can make collisions
[13:28] <Ionic> 30000 + [some random number from 1 to 30000]
01[13:28] <rnowotny> right. randomly screwed
[13:28] <Ionic> sure
[13:28] <Ionic> randomly screwed
01[13:29] <rnowotny> but in the case 30.000 + (128 x octet) we have at least 128 ports "distance" between each host 
01[13:29] <rnowotny> so collision is not very likely
[13:29] <Ionic> unless octet1 and octet2 is the same
[13:29] <Ionic> (for two given hosts)
01[13:29] <rnowotny> however - everything is better then all host using 30001 ;-)
[13:29] <Ionic> randomization would avoid that problem
01[13:30] <rnowotny> for class "C" nets, this will never happen.
[13:30] <Ionic> yeah, but it's still easy to run into it for anything bigger
[13:31] <Ionic> for instance, when working with VMs and internal networks, you typically assign a virtual network per machine and the ending octets will be the same
01[13:31] <rnowotny> ok, however - I propose a patch like that. And as You said before - it should be solved in some other place later anyway.
01[13:32] <rnowotny> I will finish the patch, with both varians : random and 128 ports "distance", and You can configure.
01[13:33] <rnowotny> Would You be so kind and issue the patch on git ? 
[13:33] <Ionic> just pointing out that I'm more inclined to do randomization than apply your patch as-is and I don't want you to get mad at that
[13:33] <Ionic> don't worry about the randomization part
01[13:33] <rnowotny> I can send to Your email adress if You want.
[13:33] <Ionic> sure, or to git-admin at x2go.org
01[13:33] <rnowotny> ok, I will send it later today
[13:33] <Ionic> preferably also CC'd to the mailing list
01[13:33] <rnowotny> Oh, I am not mad at all.
[13:33] <Ionic> actually, the "correct" way would to create a new bug report...
[13:34] <Ionic> and also use "Tag: patch"
01[13:34] <rnowotny> Yeah, I was afraid to "spam" the Bug & Mailinglist. So I politely ask before .... 
[13:35] <Ionic> nah, that's actually the prefered way
[13:35] <Ionic> (I don't keep IRC logs for instance)
01[13:36] <rnowotny> no problem. But our conversation was very productive, I haven thought of "more sessions to one host" . So the multiplier + randomisation is a good compromise
[13:39] <Ionic> my top priority for the client is something rather unimportant to most users
[13:39] <Ionic> getting PulseAudio support on OS X working and bundling the daemon with the client
[13:39] <Ionic> I'm still hanging at the bundling stage which is non-trivial
[13:40] <Ionic> and my top-top most priority is writing my bachelor's thesis, which doesn't leave me as much free time as I'd like...
01[13:42] <rnowotny> ok Ionic, I understand ;-) however, it would be nice if my patch can make it through 
[13:42] <Ionic> sure, although I will probably only do randomization
01[13:42] <rnowotny> I will give You both options, what can be configured.

-------------- next part --------------
#!/bin/bash

# Copyright (C) 2007-2015 X2Go Project - http://wiki.x2go.org
#
# 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.
#
# 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; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Copyright (C) 2007-2015 Oleksandr Shneyder <oleksandr.shneyder at obviously-nice.de>
# Copyright (C) 2007-2015 Heinz-Markus Graesing <heinz-m.graesing at obviously-nice.de>

# rnowotny, <rnowotny at rotek.at>
# patch for SSH_PORT, not to use the same SSH port on each Server, what
# is a problem if You want to connect to different servers at the same time with the windows client.
# the problem was reported already here :  https://www.mail-archive.com/x2go-user@lists.berlios.de/msg00547.html

# get my Ip Adress - also works on mac osx
get_my_ip() 		
	{
    local _ip _line
    while IFS=$': \t' read -a _line ;do
        [ -z "${_line%inet}" ] &&
           _ip=${_line[${#_line[1]}>4?1:2]} &&
           [ "${_ip#127.0.0.1}" ] && echo $_ip && return 0
      done< <(LANG=C /sbin/ifconfig)
	}
# /get my Ip Adress

# get random port 
get_random_port() 		
	{
	local n_random
	local n_port
	n_random=$RANDOM
	let "n_random %= 2200"
	n_port=$((30000 + $n_random*16))
	echo $n_port
	}
# /get random port 


b_randomize_ssh_port=0						# if You use hosts on a class C network, You should select "0" here.
											# each hosts SSH_PORT will be set to 30.000 + (128 x last octet of IP Adress)
											# this results in no collosions on a class C network with at least 128 ports for each host available for different sessions
											# if You select "1" here, the SSH_PORT will be set to 30.000 + random(0..2220 * 16)
											# the chance for a collision is n(Hosts) : 2220, with at least 16 ports for each host available for different sessions 		

if [ "$b_randomize_ssh_port" = "0" ]; then
	my_ip=$(get_my_ip)						# my IP Adress, for instance 192.168.0.105
	my_ip_last_octet="${my_ip##*.}"			# last octet of IP Adress, for instance 105
	SSH_PORT=$((30000+$my_ip_last_octet*128))  	# first ssh port = 30001 + last octet of IP Adress * 128 to avoid collisions on multiple windows clients
else
	SSH_PORT=$(get_random_port)
fi


X2GO_LIB_PATH="$(x2gopath libexec)";

$X2GO_LIB_PATH/x2gosyslog "$0" "info" "$(basename $0) called with options: $@"

X2GO_PORT=49 	#First port for X2GO=50
# patched out by rnowotny
# SSH_PORT=3000  	# first ssh port = 30001 + last octet of IP Adress to avoid collisions on multiple windows clients


# some sanity checks before session startup...
if egrep "^backend[ ]*=[ ]*postgres" /etc/x2go/x2gosql/sql 1>/dev/null 2>/dev/null && [ "x$USER" = "xroot" ]; then
	msg="The super-user \"root\" is not allowed to launch X2Go sessions."
	echo "$msg"
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "$msg"
	exit -1
elif [ -z "$USER" ]; then
	msg="The \$USER environment variable is not set. Aborting session startup."
	echo "$msg"
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "$msg"
	exit -2
elif [ -z "$HOME" ]; then
	msg="The \$HOME environment variable is not set. Aborting session startup."
	echo "$msg"
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "$msg"
	exit -4
elif ! echo $HOME | iconv -f ASCII -t ASCII 1>/dev/null 2>/dev/null; then
	msg="Your home directory path contains non-ASCII characters. Aborting session startup."
	echo "$msg"
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "$msg"
	exit -5
fi

X2GO_ROOT="${HOME}/.x2go"
export NX_ROOT=$X2GO_ROOT

X2GO_NXAGENT_DEFAULT_OPTIONS="-extension XFIXES -extension GLX -nolisten tcp"

if [ -r /etc/x2go/x2goagent.options ]; then
	source /etc/x2go/x2goagent.options
fi

if [ -z "$X2GO_NXAGENT_OPTIONS" ]; then
	X2GO_NXAGENT_OPTIONS="$X2GO_NXAGENT_DEFAULT_OPTIONS"
fi

REMOTE=localhost

# shadow sessions (via x2godesktopsharing) set the X2GO_CLIENT var in the process environment
# so either it is already set or we obtain it from SSH_CLIENT/SSH_CONNECTION
if [ -z "$X2GO_CLIENT" ] && [ -n "$SSH_CLIENT" ]; then
	X2GO_CLIENT=`echo $SSH_CLIENT | awk '{print $1}'`
elif [ -z "$X2GO_CLIENT" ] && [ -n "$SSH_CONNECTION" ]; then
	X2GO_CLIENT=`echo $SSH_CONNECTION | awk '{print $1}'`
fi
if [ -z "$X2GO_CLIENT" ]; then
	msg="The \$X2GO_CLIENT environment variable is not set. Possible reasons: \$SSH_CLIENT not set or \$SSH_CONNECTION not set. Or \$X2GO_CLIENT not set by ,,X2Go Desktop Sharing'' applet. Aborting session startup."
	echo "$msg"
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "$msg"
	exit -3
fi

$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "client announced itself as ,,$X2GO_CLIENT''"

X2GO_GEOMETRY="$1"; shift
X2GO_LINK="$1"; shift
X2GO_PACK="$1"; shift
X2GO_TYPE="$1"; shift
X2GO_KBD_LAYOUT="$1"; shift
X2GO_KBD_TYPE="$1"; shift
X2GO_SET_KBD="$1"; shift
X2GO_STYPE="$1"; shift
X2GO_CMD="$1"; shift
X2GO_RESIZE=1
X2GO_FULLSCREEN=0

X2GO_CLIPBOARD=""

XAUTHORITY=${XAUTHORITY:-"$HOME/.Xauthority"}


if [ "$X2GO_STYPE" == "S" ]; then

	SHADOW_MODE=`echo $X2GO_CMD |awk '{split($0,a,"XSHAD"); print a[1]}'`
	SHADOW_USER=`echo $X2GO_CMD |awk '{split($0,a,"XSHAD"); print a[2]}'`
	SHADOW_DESKTOP=`echo $X2GO_CMD |awk '{split($0,a,"XSHAD"); print a[3]}'`

	if [ -z "$1" ]; then

		# can this line be removed?
		#echo "suser $SHADOW_USER user $USER " >> /tmp/uagent

		$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "shadow session requested: mode $SHADOW_MODE, user: $SHADOW_USER, desktop: $SHADOW_DESKTOP"
	else
		SHADREQ_USER="$1"; shift
		$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "preparing shadow session request for user $SHADREQ_USER, agent starts for user ${USER}"
	fi

	if [ "$SHADOW_USER" != "$USER" ]; then

		$X2GO_LIB_PATH/x2gosyslog "$0" "notice" "user ,,$USER'' requests desktop sharing from user ,,$SHADOW_USER'' for desktop ,,$SHADOW_DESKTOP''"
		$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "executing command: x2godesktopsharing client $X2GO_CLIENT $X2GO_GEOMETRY $X2GO_LINK $X2GO_PACK $X2GO_TYPE $X2GO_KBD_LAYOUT $X2GO_KBD_TYPE $X2GO_SET_KBD $X2GO_STYPE $X2GO_CMD $USER"
		OUTPUT=`x2godesktopsharing client "$X2GO_CLIENT" "$X2GO_GEOMETRY" "$X2GO_LINK" "$X2GO_PACK" "$X2GO_TYPE" "$X2GO_KBD_LAYOUT" "$X2GO_KBD_TYPE" "$X2GO_SET_KBD" "$X2GO_STYPE" "$X2GO_CMD" "$USER"`
		$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "command result is: $OUTPUT"
		if [ "${OUTPUT:0:4}" == "DENY" ]; then
			echo "ACCESS DENIED" 1>&2
			DENIAL_REASON="${OUTPUT:5}"
			if [ -z "$DENIAL_REASON" ]; then
				DENIAL_REASON="the user ,,$SHADOW_USER'' does not seem to have desktop sharing activated"
			fi
			$X2GO_LIB_PATH/x2gosyslog "$0" "err" "ERROR: user $SHADOW_USER denied desktop sharing session"
			$X2GO_LIB_PATH/x2gosyslog "$0" "err" "ERROR: reason: for desktop sharing denial ${DENIAL_REASON}"
			exit -1
		fi
		X2GO_COOKIE=`echo $OUTPUT | awk '{print $2}'`
		X2GO_PORT=`echo $OUTPUT | awk '{print $1}'`

		$X2GO_LIB_PATH/x2gosyslog "$0" "debug" "received shadow session information: cookie: $X2GO_COOKIE, port: $X2GO_PORT"
		xauth -f "$XAUTHORITY" add "${HOSTNAME}/unix:${X2GO_PORT}" MIT-MAGIC-COOKIE-1 "${X2GO_COOKIE}"
		xauth -f "$XAUTHORITY" add "${HOSTNAME}:${X2GO_PORT}" MIT-MAGIC-COOKIE-1 "${X2GO_COOKIE}"

		echo $X2GO_PORT
		echo $X2GO_COOKIE
		echo $OUTPUT | awk '{print $3}'
		echo $OUTPUT | awk '{print $4}'
		echo $OUTPUT | awk '{print $5}'
		echo $OUTPUT | awk '{print $6}'
		echo $OUTPUT | awk '{print $7}'
		exit 0
	else
		X2GO_CLIPBOARD="$1"; shift
	fi
fi

LIMIT=`x2gosessionlimit`
LWORD=`echo $LIMIT | awk '{print $1}'`

if [ "$LWORD" == "LIMIT" ]; then
	echo  $LIMIT 1>&2
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "session limit has been reached for user ,,$USER'', cannot start new session"
	exit -1
fi

export NX_CLIENT="$X2GO_LIB_PATH/x2gosuspend-agent"

COLORDEPTH=`echo $X2GO_TYPE | awk '{split($0,a,"-depth_"); print a[2]}'`

SESSION_TYPE="D"
NOEXITPARAM=""

if [ "$X2GO_STYPE" == "R" ]; then
	SESSION_TYPE="R"
elif  [ "$X2GO_STYPE" == "P" ]; then
	SESSION_TYPE="R"
	NOEXITPARAM="-norootlessexit"
elif  [ "$X2GO_STYPE" == "S" ]; then
	SESSION_TYPE="S"
fi

if [ "$X2GO_CLIENT" == "" ]; then
	X2GO_CLIENT="$HOSTNAME"
fi

# define the full path to the ss utility
ss=$(PATH="$PATH:/usr/sbin:/sbin" type -P ss);

while [ "$OUTPUT"  != "inserted" ]; do

	USED_DISPLAYS=`$X2GO_LIB_PATH/x2gogetdisplays $HOSTNAME`

	#Get all used in system ports from X2Go database and ss output
	USED_PORTS=$(
	    "$X2GO_LIB_PATH/x2gogetports" "$HOSTNAME";
	    "$ss" -nt -all |
	    awk '{ n=split($0,lines,"\n"); for(i=1;i<=n;i++){split (lines[i],words," ");delim=split(words[4],ports,":"); if(delim>1)printf ("|%s|\n",ports[delim])} }';
	);

	X2GO_PORT=$(($X2GO_PORT + 1))
	X2GO_PORT=`echo "for(\\$i=$X2GO_PORT;\\$br ne \"true\";\\$i++){ if(\"$USED_DISPLAYS\" =~ m/\\|\\$i\\|/){\\$br=\"false\";}else{\\$br=\"true\";print \\$i;}}"|perl`
	
	#Test if the session is already in use. nxagent uses 6000+DISPLAY to open a port. Therefore this must be tested, too.
	NX_PORT=$(($X2GO_PORT + 6000))
	if $ss -lxs 2>/dev/null | egrep "(@|)/tmp/.X11-unix/X${X2GO_PORT}(|-lock) " 1>/dev/null ||
		grep -q "|${NX_PORT}|" <<<$USED_PORTS ; then
		OUTPUT="XXX"
	else
		SESSION_NAME="${USER}-${X2GO_PORT}-`date +\"%s\"`"
		if [ "$COLORDEPTH" != "" ]; then
			SESSION_NAME="${SESSION_NAME}_st${SESSION_TYPE}${X2GO_CMD}_dp${COLORDEPTH}"
			SESSION_NAME=`echo "$SESSION_NAME" | perl -pe  "s/:/PP/g"`
		fi
		# sanitize session name
		SESSION_NAME=`echo "$SESSION_NAME" | perl -pe  "s/[^a-zA-Z0-9\.\_\-\@]//g"`

		OUTPUT=`$X2GO_LIB_PATH/x2goinsertsession "$X2GO_PORT" "$HOSTNAME" "$SESSION_NAME"`
	fi 
done


while [ "$GR_PORT" == "" ] || [ "$SOUND_PORT" == "" ] || [ "$FS_PORT" == "" ]; do
	OUTPUT=""
	while [ "$OUTPUT"  != "inserted" ]; do
		SSH_PORT=$(($SSH_PORT + 1))

		#Get all used in system ports from X2Go database and ss output
		USED_PORTS=$(
		    "$X2GO_LIB_PATH/x2gogetports" "$HOSTNAME";
		    "$ss" -nt -all |
		    awk '{ n=split($0,lines,"\n"); for(i=1;i<=n;i++){split (lines[i],words," ");delim=split(words[4],ports,":"); if(delim>1)printf ("|%s|\n",ports[delim])} }';
		);

		#get free port
		SSH_PORT=`echo "for(\\$i=$SSH_PORT;\\$br ne \"true\";\\$i++){ if(\"$USED_PORTS\" =~ m/\\|\\$i\\|/){\\$br=\"false\";}else{\\$br=\"true\";print \\$i;}}"|perl`

		#check if port in /etc/services
		SERV=`grep $SSH_PORT /etc/services`
		if [ "$SERV" == "" ]; then
			OUTPUT=`$X2GO_LIB_PATH/x2goinsertport "$HOSTNAME" "$SESSION_NAME" "$SSH_PORT"`
		fi
	done

	if [ "$GR_PORT" == "" ]; then
		GR_PORT="$SSH_PORT"
	elif [ "$SOUND_PORT" == "" ]; then
		SOUND_PORT="$SSH_PORT"
	else
		FS_PORT="$SSH_PORT"
	fi
done

# rootless sessions of geometry fullscreen are invalid
if [ "$X2GO_GEOMETRY" == "fullscreen" ] && [ "$SESSION_TYPE" == "R" ]; then
	X2GO_GEOMETRY=""
fi

# no geometry for desktop sessions shall result in fullscreen desktop sessions
if [ "$X2GO_GEOMETRY" == "" ] && [ "$SESSION_TYPE" == "D" ]; then
	X2GO_GEOMETRY="fullscreen"
fi
if [ "$X2GO_GEOMETRY" == "fullscreen" ]; then
	X2GO_FULLSCREEN=1
fi

# shadow sessions are never fullscreen session and adopt the original session's geometry
if [ "$X2GO_STYPE" == "S" ]; then
	X2GO_GEOMETRY=`DISPLAY="$SHADOW_DESKTOP" xwininfo -root | grep geometry`
	X2GO_GEOMETRY=`echo "$X2GO_GEOMETRY" | sed  -e  "s/ //g"`
	X2GO_GEOMETRY=`echo "$X2GO_GEOMETRY" | sed  -e  "s/-geometry//"`
fi


if [ ! -d "$X2GO_ROOT" ]; then
	mkdir "$X2GO_ROOT"
fi

X2GO_TMP_ROOT="/tmp/.x2go-${USER}"
if [ ! -d "$X2GO_TMP_ROOT" ]; then
    mkdir "$X2GO_TMP_ROOT"
fi

SESSION_DIR="${X2GO_TMP_ROOT}/C-${SESSION_NAME}"
STATE_FILE="${X2GO_ROOT}/C-${SESSION_NAME}/state"

# do not use $TMP or $TEMP here, the session.log file location has to be accessible by root
SESSION_LOG="${SESSION_DIR}/session.log"
mkdir -p "${SESSION_DIR}"
if [ "x$X2GO_STYPE" = "xS" ]; then
	chmod -f 0710 "${SESSION_DIR}"
	if groups "$USER" | grep x2godesktopsharing 1>/dev/null 2>/dev/null; then
		$X2GO_LIB_PATH/x2gosyslog "$0" "info" "user ,,$USER'' grants access to ${SESSION_DIR} for group ,,x2godesktopsharing''"
		chown :x2godesktopsharing "${SESSION_DIR}"
	fi
else
	chmod -f 0700 "${SESSION_DIR}"
fi
touch "${SESSION_LOG}"
chmod -f 0600 "${SESSION_LOG}"


if [ ! -d "$X2GO_ROOT/ssh" ]; then
    mkdir "$X2GO_ROOT/ssh"
fi

grep PPid /proc/$PPID/status > ${SESSION_DIR}/sshd.pid



X2GO_COOKIE=`mcookie`


PATH="${PATH}:${X2GO_BIN}/"
export PATH


xauth -f "$XAUTHORITY" add "${HOSTNAME}/unix:${X2GO_PORT}" MIT-MAGIC-COOKIE-1 "${X2GO_COOKIE}"
xauth -f "$XAUTHORITY" add "${HOSTNAME}:${X2GO_PORT}" MIT-MAGIC-COOKIE-1 "${X2GO_COOKIE}"


option_geometry=""
if [ -n "$X2GO_GEOMETRY" ] && [ "$X2GO_GEOMETRY" != "fullscreen" ]; then
	option_geometry="geometry=${X2GO_GEOMETRY},"
fi

if [ -n "$X2GO_CLIPBOARD" ] && [ -z "`echo $X2GO_CLIPBOARD | sed -re 's/(0|none|client|server|both|1)//'`" ]; then
	clipboard=",clipboard=$X2GO_CLIPBOARD"
else
	clipboard=",clipboard=both"
fi

if [ "$X2GO_SET_KBD" == "0" ] || [ "$X2GO_KBD_TYPE" == "auto" ];then
    X2GO_HOST="nx/nx,link=${X2GO_LINK},pack=${X2GO_PACK},limit=0,root=${SESSION_DIR},cache=8M,images=32M,type=${X2GO_TYPE},id=${SESSION_NAME},cookie=$X2GO_COOKIE,errors=${SESSION_LOG},kbtype=null/null,${option_geometry}resize=${X2GO_RESIZE},fullscreen=${X2GO_FULLSCREEN},accept=${REMOTE},listen=${GR_PORT}${clipboard},client=linux,menu=0,state=${STATE_FILE}"
else
    X2GO_HOST="nx/nx,link=${X2GO_LINK},pack=${X2GO_PACK},limit=0,root=${SESSION_DIR},cache=8M,images=32M,type=${X2GO_TYPE},id=${SESSION_NAME},cookie=$X2GO_COOKIE,errors=${SESSION_LOG},kbtype=${X2GO_KBD_TYPE},${option_geometry}resize=${X2GO_RESIZE},fullscreen=${X2GO_FULLSCREEN},accept=${REMOTE},listen=${GR_PORT}${clipboard},client=linux,menu=0,state=${STATE_FILE}"
fi


echo "${X2GO_HOST}:${X2GO_PORT}" >"${SESSION_DIR}/options"

NX_AGENT=":${X2GO_PORT}"
SAVED_DISPLAY="$DISPLAY"
DISPLAY="nx/nx,options=${SESSION_DIR}/options:${X2GO_PORT}"
export DISPLAY


if [ "$X2GODPI" == "" ]; then
	X2GODPIOPTION_=""
else
	X2GODPIOPTION_="-dpi $X2GODPI"
fi

NOLISTOPT=""
if [ "$X2GOXDMCP" == "" ] ;then
	XDMCPOPT=""
	if [ "x${X2GO_NXAGENT_OPTIONS}" != "x${X2GO_NXAGENT_OPTIONS/' -nolisten tcp'/''}" ]; then
		NOLISTOPT="-nolisten tcp"
	fi
else
	XDMCPOPT="-query $X2GOXDMCP"
fi

# run x2goserver-extensions for pre-start
x2gofeature X2GO_RUN_EXTENSIONS &>/dev/null && x2goserver-run-extensions "$SESSION_NAME" pre-start || true

SESSION_WINDOW_TITLE="X2GO-${SESSION_NAME}"
agent_geometry=""
if [ -n "$X2GO_GEOMETRY" ] && [ "$X2GO_GEOMETRY" != "fullscreen" ]; then
	agent_geometry="-geometry ${X2GO_GEOMETRY}"
fi

if  [ "$X2GO_STYPE" == "S" ]; then
	# set NX_TEMP to /tmp, make sure x2goagent starts when pam_tmpdir.so is in use
	NX_TEMP=/tmp x2goagent $X2GO_NXAGENT_OPTIONS $NOLISTOPT $X2GODPIOPTION_ -$SESSION_TYPE -auth "$XAUTHORITY" -shadow $SHADOW_DESKTOP -shadowmode $SHADOW_MODE $agent_geometry -name "${SESSION_WINDOW_TITLE}"  "${NX_AGENT}" 2>"${SESSION_LOG}" &
else
	# set NX_TEMP to /tmp, make sure x2goagent starts when pam_tmpdir.so is in use
	NX_TEMP=/tmp x2goagent $X2GO_NXAGENT_OPTIONS $NOLISTOPT $X2GODPIOPTION_ $XDMCPOPT -$SESSION_TYPE $NOEXITPARAM -auth "$XAUTHORITY" $agent_geometry -name "${SESSION_WINDOW_TITLE}"  "${NX_AGENT}" 2>"${SESSION_LOG}" &
fi

ln -s "${SESSION_DIR}" "${X2GO_ROOT}/C-${SESSION_NAME}"

X2GO_AGENT_PID=$!
X2GO_AGENT_RETVAL=$?
test $X2GO_AGENT_RETVAL && {
	$X2GO_LIB_PATH/x2gosyslog "$0" "notice" "successfully started X2Go agent session with ID $SESSION_NAME"

	# run x2goserver-extensions for post-start
	x2gofeature X2GO_RUN_EXTENSIONS &>/dev/null && x2goserver-run-extensions "$SESSION_NAME" post-start || true

} || {
	$X2GO_LIB_PATH/x2gosyslog "$0" "err" "ERROR: failed to start X2Go agent session with ID $SESSION_NAME"

	# run x2goserver-extensions for fail-start
	x2gofeature X2GO_RUN_EXTENSIONS &>/dev/null && x2goserver-run-extensions "$SESSION_NAME" fail-start || true

}

X2GO_SND_PORT=1024

$X2GO_LIB_PATH/x2gocreatesession "$X2GO_COOKIE" "$X2GO_AGENT_PID" "$X2GO_CLIENT" "$GR_PORT" "$SOUND_PORT" "$FS_PORT" "$SESSION_NAME" > /dev/null

if [ "$X2GO_SET_KBD" == "0" ] || [ "$X2GO_KBD_TYPE" != "auto" ]; then
	$X2GO_LIB_PATH/x2gosyslog "$0" "info" "blocking creation of agent's keyboard file ${SESSION_DIR}/keyboard as requested by session startup command"
	mkdir -p ${SESSION_DIR}/keyboard
fi

echo $X2GO_PORT
echo $X2GO_COOKIE
echo $X2GO_AGENT_PID
echo $SESSION_NAME
echo $GR_PORT
echo $SOUND_PORT
echo $FS_PORT


More information about the x2go-dev mailing list