This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goserver. commit 6cb9bb10b8d476572a7d47dc5e1b0987c49aaea8 Author: Mihai Moldovan <ionic@ionic.de> Date: Thu Jan 4 06:16:51 2018 +0100 x2goserver/bin/x2go{startagent,resume-session}: use x2gogetfreeport instead of duplicating the same code everywhere. Fixes: #1230. Also, rely on it returning a valid value and try at most 10 times to fetch a usable port value, then error out and make the session startup or resumption fail. Cherry-picked from release/4.0.1.x branch. --- debian/changelog | 5 ++ x2goserver/bin/x2goresume-session | 85 ++++++++++----------- x2goserver/bin/x2gostartagent | 151 +++++++++++++------------------------- 3 files changed, 99 insertions(+), 142 deletions(-) diff --git a/debian/changelog b/debian/changelog index f247d8e..55854d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -310,6 +310,11 @@ x2goserver (4.0.1.23-0x2go1) UNRELEASED; urgency=medium quotes on the lib path line. - x2goserver/bin/x2goresume-session: properly randomize first port, just like in x2gostartagent. + - x2goserver/bin/x2go{startagent,resume-session}: use x2gogetfreeport + instead of duplicating the same code everywhere. Fixes: #1230. Also, + rely on it returning a valid value and try at most 10 times to fetch a + usable port value, then error out and make the session startup or + resumption fail. * x2goserver.spec: - RPMify x2goserver-xsession description. - Remove qt4 stuff, we're not using the framework here. diff --git a/x2goserver/bin/x2goresume-session b/x2goserver/bin/x2goresume-session index 5cac4e1..b624c97 100755 --- a/x2goserver/bin/x2goresume-session +++ b/x2goserver/bin/x2goresume-session @@ -170,12 +170,6 @@ SERVER=`echo "$SESSIONINFO" | awk -F, {'print $4'}` "$X2GO_LIB_PATH/x2gosyslog" "$0" "debug" "old ports: $GR_PORT, $SOUND_PORT, $FS_PORT" -#Get all used in system ports from ss output -ss="$(PATH="$PATH:/usr/sbin:/sbin" type -P ss)"; -USED_PORTS=$( - "$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])} }'; -); #check if saved in DB ports free if grep -q "|${GR_PORT}|" <<<$SYSTEM_PORTS ; then @@ -223,44 +217,51 @@ if ! SSH_PORT="$("${X2GO_LIB_PATH}/x2gogetrandomport")"; then exit "1" fi -#Get all used in system ports from X2Go database and netstat output -USED_PORTS="$("${X2GO_LIB_PATH}/x2gogetports" "${current_host_name}"; netstat -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])} }')" - -while [ "$GR_PORT" == "" ] || [ "$SOUND_PORT" == "" ] || [ "$FS_PORT" == "" ] || [ "$TEKICTRL_PORT" == "" ] || [ "$TEKIDATA_PORT" == "" ]; do - OUTPUT="" - while [ "$OUTPUT" != "inserted" ]; do - SSH_PORT=$(($SSH_PORT + 1)) - - #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" "${current_host_name}" "$SESSION_NAME" "$SSH_PORT")" - - # Catching errors here would be nice, but the current layout doesn't allow this. - # Keep this in mind as a FIXME. - #if [[ "${?}" -ne "0" ]]; then - # typeset msg="Unable to insert new port into database; parameters: hostname (${current_host_name}), session name (${SESSION_NAME}) and port (${SSH_PORT})." - # "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" - # - # # Make x2goclient fail. - # echo "${msg}" >&2 - # exit 1 - #fi +# define the full path to the ss utility +typeset ss="$(PATH="${PATH}:/usr/sbin:/sbin" type -P 'ss')" + +typeset -i retry='0' +typeset -i max_retry='10' +typeset -i free_port='0' +typeset output='' +while [ -z "${GR_PORT}" ] || [ -z "${SOUND_PORT}" ] || [ -z "${FS_PORT}" ] || [ -z "${TEKICTRL_PORT}" ] || [ -z "${TEKIDATA_PORT}" ]; do + output='' + for ((retry = 0; retry < max_retry; ++retry)); do + free_port='0' + if free_port="$("${X2GO_LIB_PATH}/x2gogetfreeport" "${ss}" 'lowlevel' "${SSH_PORT}")"; then + SSH_PORT="${free_port}" + + output="$("${X2GO_LIB_PATH}/x2goinsertport" "${current_host_name}" "${SESSION_NAME}" "${SSH_PORT}")" + + if [[ "${output}" = "inserted" ]]; then + break + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "unable to insert port into database. Retrying (run $((retry + 1)))." + fi + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "no free port available, cannot start new session. Retrying (run $((retry + 1)))." fi done - if [ "$GR_PORT" == "" ]; then - GR_PORT="$SSH_PORT" - elif [ "$SOUND_PORT" == "" ]; then - SOUND_PORT="$SSH_PORT" - elif [ "$FS_PORT" == "" ]; then - FS_PORT="$SSH_PORT" - elif [ "$TEKICTRL_PORT" == "" ]; then - TEKICTRL_PORT="$SSH_PORT" - elif [ "$TEKIDATA_PORT" == "" ]; then - TEKIDATA_PORT="$SSH_PORT" + + if [[ "${output}" != "inserted" ]]; then + typeset msg="Unable to find free port or insert new session into database; parameters: hostname (${current_host_name}), session name (${SESSION_NAME}) and port (${SSH_PORT})." + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" + + # Make x2goclient fail. + echo "${msg}" >&2 + exit "12" + fi + + if [ -z "${GR_PORT}" ]; then + GR_PORT="${SSH_PORT}" + elif [ -z "${SOUND_PORT}" ]; then + SOUND_PORT="${SSH_PORT}" + elif [ -z "${FS_PORT}" ]; then + FS_PORT="${SSH_PORT}" + elif [ -z "${TEKICTRL_PORT}" ]; then + TEKICTRL_PORT="${SSH_PORT}" + elif [ -z "${TEKIDATA_PORT}" ]; then + TEKIDATA_PORT="${SSH_PORT}" fi done diff --git a/x2goserver/bin/x2gostartagent b/x2goserver/bin/x2gostartagent index bf9bf41..c209044 100755 --- a/x2goserver/bin/x2gostartagent +++ b/x2goserver/bin/x2gostartagent @@ -33,7 +33,7 @@ if ! SSH_PORT="$("${X2GO_LIB_PATH}/x2gogetrandomport")"; then exit "1" fi -X2GO_PORT="49" #First port for X2GO=50 +X2GO_PORT="50" # some sanity checks before session startup... if grep -E "^backend[ ]*=[ ]*postgres" "/etc/x2go/x2gosql/sql" 1>"/dev/null" 2>"/dev/null" && [ "x${USER}" = "xroot" ]; then @@ -216,53 +216,14 @@ fi # define the full path to the ss utility ss="$(PATH="${PATH}:/usr/sbin:/sbin" type -P "ss")" -while [ "${OUTPUT}" != "inserted" ]; do +typeset -i retry='0' +typeset -i max_retry='10' +typeset -i output='' +for ((retry = 0; retry < max_retry; ++retry)); do + typeset -i free_port="${X2GO_PORT}" + if free_port="$("${X2GO_LIB_PATH}/x2gogetfreeport" "${ss}" 'display' "${X2GO_PORT}")"; then + X2GO_PORT="${free_port}" - typeset -a used_displays - IFS='' read -ar used_displays < <("${X2GO_LIB_PATH}/x2gogetdisplays" "${current_host_name}") - - # Get all used in system ports from X2Go database and ss output - USED_PORTS="$( - "${X2GO_LIB_PATH}/x2gogetports" "${current_host_name}"; - "${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))" - - typeset -i search_x2go_port="0" - - # Find the next free port number. - for ((search_x2go_port = X2GO_PORT; i <= 59535; ++search_x2go_port)); do - typeset -i i="0" - typeset -i value_found="0" - - for ((i = 0; i < ${#used_displays[@]}; ++i)); do - if [[ "${used_displays[i]}" =~ /|${search_x2go_port}|/ ]]; then - # We need to continue with the next port number, - # this one is taken. - value_found="1" - break - fi - done - - # Searched the array and got nothing? Great, grab that port number! - [[ "${value_found}" -eq "0" ]] && break - done - - if [[ "${search_x2go_port}" -gt "59535" ]]; then - "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "no free display number available, cannot start new session" - exit "10" - fi - - X2GO_PORT="${search_x2go_port}" - - # 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" | grep -E "(@|)/tmp/.X11-unix/X${X2GO_PORT}(|-lock) " >"/dev/null" || - grep -q "|${NX_PORT}|" <<< "${USED_PORTS}"; then - OUTPUT="XXX" - else if [ -n "${SHADREQ_USER}" ]; then SESSION_NAME="${SHADREQ_USER}-${X2GO_PORT}-$(date "+%s")" else @@ -278,36 +239,31 @@ while [ "${OUTPUT}" != "inserted" ]; do if [ -n "${SHADREQ_USER}" ]; then "${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "initializing new shadow session with ID ${SESSION_NAME}" - OUTPUT="$("${X2GO_LIB_PATH}/x2goinsertshadowsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}" "${SHADREQ_USER}")" - - # Catching errors here would be nice, but the current layout doesn't allow this. - # Keep this in mind as a FIXME. - #if [[ "${?}" -ne "0" ]]; then - # typeset msg="Unable to insert new session into database; parameters: port (${X2GO_PORT}), hostname (${current_host_name}), session name (${SESSION_NAME}) and user requesting desktop sharing permissions (${SHADREQ_USER})." - # "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" - # - # # Make x2goclient fail. - # echo "${msg}" >&2 - # exit 1 - #fi + output="$("${X2GO_LIB_PATH}/x2goinsertshadowsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}" "${SHADREQ_USER}")" else "${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "initializing new session with ID ${SESSION_NAME}" - OUTPUT="$("${X2GO_LIB_PATH}/x2goinsertsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}")" - - # Catching errors here would be nice, but the current layout doesn't allow this. - # Keep this in mind as a FIXME. - #if [[ "${?}" -ne "0" ]]; then - # typeset msg="Unable to insert new session into database; parameters: port (${X2GO_PORT}), hostname (${current_host_name}) and session name (${SESSION_NAME})." - # "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" - # - # # Make x2goclient fail. - # echo "${msg}" >&2 - # exit 1 - #fi + output="$("${X2GO_LIB_PATH}/x2goinsertsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}")" + fi + + if [[ "${output}" = "inserted" ]]; then + break + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "unable to insert display port into database. Retrying (run $((retry + 1)))." fi + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "no free display number available, cannot start new session. Retrying (run $((retry + 1)))." fi done +if [[ "${output}" != "inserted" ]]; then + typeset msg="Unable to find free display port or insert new session into database; parameters: port (${X2GO_PORT}), hostname (${current_host_name}) and session name (${SESSION_NAME})." + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" + + # Make x2goclient fail. + echo "${msg}" >&2 + exit "11" +fi + if [ "x$X2GO_TELEKINESIS_ENABLED" == "x0" ] || [ "x$X2GO_STYPE" = "xS" ] || ! type -p telekinesis-server 1>/dev/null; then TEKICTRL_PORT="-1" TEKIDATA_PORT="-1" @@ -315,38 +271,33 @@ if [ "x$X2GO_TELEKINESIS_ENABLED" == "x0" ] || [ "x$X2GO_STYPE" = "xS" ] || ! ty fi while [ -z "${GR_PORT}" ] || [ -z "${SOUND_PORT}" ] || [ -z "${FS_PORT}" ] || [ -z "${TEKICTRL_PORT}" ] || [ -z "${TEKIDATA_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" "${current_host_name}"; - "${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" "${current_host_name}" "${SESSION_NAME}" "${SSH_PORT}")" - - # Catching errors here would be nice, but the current layout doesn't allow this. - # Keep this in mind as a FIXME. - #if [[ "${?}" -ne "0" ]]; then - # typeset msg="Unable to insert new port into database; parameters: hostname (${current_host_name}), session name (${SESSION_NAME}) and port (${SSH_PORT})." - # "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" - # - # # Make x2goclient fail. - # echo "${msg}" >&2 - # exit "12" - #fi + output='' + for ((retry = 0; retry < max_retry; ++retry)); do + free_port='0' + if free_port="$("${X2GO_LIB_PATH}/x2gogetfreeport" "${ss}" 'lowlevel' "${SSH_PORT}")"; then + SSH_PORT="${free_port}" + + output="$("${X2GO_LIB_PATH}/x2goinsertport" "${current_host_name}" "${SESSION_NAME}" "${SSH_PORT}")" + + if [[ "${output}" = "inserted" ]]; then + break + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "unable to insert port into database. Retrying (run $((retry + 1)))." + fi + else + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "warning" "no free port available, cannot start new session. Retrying (run $((retry + 1)))." fi done + if [[ "${output}" != "inserted" ]]; then + typeset msg="Unable to find free port or insert new session into database; parameters: hostname (${current_host_name}), session name (${SESSION_NAME}) and port (${SSH_PORT})." + "${X2GO_LIB_PATH}/x2gosyslog" "${0}" "err" "${msg}" + + # Make x2goclient fail. + echo "${msg}" >&2 + exit "12" + fi + if [ -z "${GR_PORT}" ]; then GR_PORT="${SSH_PORT}" elif [ -z "${SOUND_PORT}" ]; then -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2goserver.git