This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goserver. commit eef6425c59110df81d2134dcf30f1649154ac6d3 Author: Mihai Moldovan <ionic@ionic.de> Date: Mon Jan 8 04:55:59 2018 +0100 x2goserver/lib: new script x2gocheckport, containing common functionality for port checking. Duplicated code will be deleted next. Cherry-picked from release/4.0.1.x branch. --- debian/changelog | 2 + x2goserver/lib/x2gocheckport | 280 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8bad925..7efec84 100644 --- a/debian/changelog +++ b/debian/changelog @@ -327,6 +327,8 @@ x2goserver (4.0.1.23-0x2go1) UNRELEASED; urgency=medium - x2goserver/lib/x2gogetfreeport: use single quotes for literal strings. - x2goserver/lib/x2gogetfreeport: use error code 1 for general failure, shift parameter sanitization failure codes up. + - x2goserver/lib: new script x2gocheckport, containing common + functionality for port checking. Duplicated code will be deleted next. * x2goserver.spec: - RPMify x2goserver-xsession description. - Remove qt4 stuff, we're not using the framework here. diff --git a/x2goserver/lib/x2gocheckport b/x2goserver/lib/x2gocheckport new file mode 100644 index 0000000..110766c --- /dev/null +++ b/x2goserver/lib/x2gocheckport @@ -0,0 +1,280 @@ +#!/bin/bash + +# Copyright (C) 2017-2018 X2Go Project - https://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. + +[[ -z "${X2GO_INTERNAL_SOURCE}" ]] && exit '2' + +# Variables used for caching. +# We do not want to fetch the whole list for every +# single port check. +typeset -a used_x2go_ports +typeset -a used_system_ports +typeset -a used_display_ports +used_x2go_ports=() +used_system_ports=() +used_display_ports=() + +# Initializes used_x2go_ports array. +# Internal use only. +# Takes the current hostname as a parameter. +# Returns 0 on success or non-0 on failure. +initialize_x2go_ports() { + typeset current_host_name="${1}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${current_host_name}" ]] || [[ "${current_host_name}" =~ ${empty_regex} ]] || [[ "${current_host_name}" = '(none)' ]] || [[ "${current_host_name}" = 'localhost' ]]; then + return '1' + fi + + # Get all used ports from the X2Go database + # What this does is very unobvious, so here's how that works: + # The -d parameter with an empty string as its argument makes + # the read utility process a "line" until the first such delimiter + # is found. Since an empty string in C is terminated by a NULL + # character, the delimiter will be set to this NULL character. + # Hence, assuming that the input string does not contain any + # NULL characters, the whole input string will be treated as + # one big line. + # Then, normal word splitting kicks in and the -a flag tells + # read to put all words into elements of the provided array + # variable. + typeset -a used_x2go_ports_work + used_x2go_ports_work=() + IFS="${IFS}|" read -r -d '' -a 'used_x2go_ports_work' < <("${X2GO_LIB_PATH}/x2gogetports" "${current_host_name}") + + # Filter out any empty or invalid values. + typeset -i item_i='0' + typeset item='' + for item in "${used_x2go_ports_work[@]}"; do + item_i="${item}" + + [[ -n "${item}" ]] && [[ "${item}" -eq "${item_i}" ]] && [[ "${item}" = "${item_i}" ]] && used_x2go_ports+=( "${item}" ) + done + + return '0' +} + +# Initializes used_system_ports array. +# Internal use only. +# Takes a command for ss as a parameter. +# If an ss command is not given, a default of "ss" is assumed. +# Returns 0 on success or non-0 on failure. +initialize_system_ports() { + typeset ss="${1:-'ss'}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${ss}" ]] || [[ "${ss}" =~ ${empty_regex} ]]; then + return '1' + fi + + typeset -a used_system_ports_work + used_system_ports_work=() + IFS="${IFS}|" read -r -d '' -a 'used_system_ports_work' < <("${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 ("\n%d\n", ports[delim]) + } + } + }') + + # Filter out any empty or invalid values. + typeset -i item_i='0' + typeset item='' + for item in "${used_system_ports_work[@]}"; do + item_i="${item}" + + [[ -n "${item}" ]] && [[ "${item}" -eq "${item_i}" ]] && [[ "${item}" = "${item_i}" ]] && used_system_ports+=( "${item}" ) + done + + return '0' +} + +# Initializes used_display_ports array. +# Internal use only. +# Takes the current hostname as a parameter. +# Returns 0 on success or non-0 on failure. +initialize_display_ports() { + typeset current_host_name="${1}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${current_host_name}" ]] || [[ "${current_host_name}" =~ ${empty_regex} ]] || [[ "${current_host_name}" = '(none)' ]] || [[ "${current_host_name}" = 'localhost' ]]; then + return '1' + fi + + typeset -a used_display_ports_work + used_display_ports_work=() + IFS="${IFS}|" read -r -d '' -a 'used_display_ports_work' < <("${X2GO_LIB_PATH}/x2gogetdisplays" "${current_host_name}") + + # Filter out any empty or invalid values. + typeset -i item_i='0' + typeset item='' + for item in "${used_display_ports_work[@]}"; do + item_i="${item}" + + [[ -n "${item}" ]] && [[ "${item}" -eq "${item_i}" ]] && [[ "${item}" = "${item_i}" ]] && used_display_ports+=( "${item}" ) + done + + return '0' +} + +# Checks if a port is registered as in use by X2Go. +# Takes the current hostname and a port value as parameters. +# Returns 0 if the port is free, or non-0 if it already +# in use or on failure. +check_x2go_port() { + typeset current_host_name="${1}" + typeset port="${2}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${current_host_name}" ]] || [[ "${current_host_name}" =~ ${empty_regex} ]] || [[ "${current_host_name}" = '(none)' ]] || [[ "${current_host_name}" = 'localhost' ]]; then + return '2' + fi + + typeset -i port_i="${port}" + if [[ -z "${port}" ]] || [[ "${port}" != "${port_i}" ]] || [[ "${port}" -ne "${port_i}" ]] || [[ "${port_i}" -lt '1' ]] || [[ "${port_i}" -gt '65535' ]]; then + return '3' + fi + + typeset -i ret='0' + + # If cache is empty, initialize it. + if [[ "${#used_x2go_ports[@]}" -eq '0' ]]; then + initialize_x2go_ports "${current_host_name}" || ret='4' + fi + + if [[ "${ret}" -eq '0' ]]; then + typeset -i i='0' + for ((i = 0; i < ${#used_x2go_ports[@]}; ++i)); do + if [[ "${used_x2go_ports[i]}" = "${port}" ]]; then + ret='1' + break + fi + done + fi + + return "${ret}" +} + +# Checks if a port is registered as in use by the system. +# Takes a command for ss and a port value as parameters. +# If an ss command is not given, a default of "ss" is assumed. +# Returns 0 if the port is free, or non-0 if it already +# in use or on failure. +check_system_port() { + typeset ss="${1:-'ss'}" + typeset port="${2}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${ss}" ]] || [[ "${ss}" =~ ${empty_regex} ]]; then + return '2' + fi + + typeset -i port_i="${port}" + if [[ -z "${port}" ]] || [[ "${port}" != "${port_i}" ]] || [[ "${port}" -ne "${port_i}" ]] || [[ "${port_i}" -lt '1' ]] || [[ "${port_i}" -gt '65535' ]]; then + return '3' + fi + + typeset -i ret='0' + + # If the port is a well-known one, don't block it. + grep -qs "[[:space:]]\+${port}/" '/etc/services' &>'/dev/null' && ret='1' + + if [[ "${ret}" -eq '0' ]]; then + # If cache is empty, initialize it. + if [[ "${#used_system_ports[@]}" -eq '0' ]]; then + initialize_system_ports "${ss}" || ret='4' + fi + fi + + if [[ "${ret}" -eq '0' ]]; then + typeset -i i='0' + for ((i = 0; i < ${#used_system_ports[@]}; ++i)); do + if [[ "${used_system_ports[i]}" = "${port}" ]]; then + ret='1' + break + fi + done + fi + + return "${ret}" +} + +# Checks if a port is registered as in use by the system. +# Takes the current host name, a command for ss and a port value as parameters. +# If an ss command is not given, a default of "ss" is assumed. +# Returns 0 if the port is free, or non-0 if it already +# in use or on failure. +check_display_port() { + typeset current_host_name="${1}" + typeset ss="${2:-'ss'}" + typeset port="${3}" + + typeset empty_regex='^[[:space:]]*$' + if [[ -z "${current_host_name}" ]] || [[ "${current_host_name}" =~ ${empty_regex} ]] || [[ "${current_host_name}" = '(none)' ]] || [[ "${current_host_name}" = 'localhost' ]]; then + return '2' + fi + + if [[ -z "${ss}" ]] || [[ "${ss}" =~ ${empty_regex} ]]; then + return '3' + fi + + typeset -i port_i="${port}" + if [[ -z "${port}" ]] || [[ "${port}" != "${port_i}" ]] || [[ "${port}" -ne "${port_i}" ]] || [[ "${port_i}" -lt '0' ]] || [[ "${port_i}" -gt '59535' ]]; then + return '4' + fi + + typeset -i ret='0' + + # If cache is empty, initialize it. + if [[ "${#used_display_ports[@]}" -eq '0' ]]; then + initialize_display_ports "${current_host_name}" || ret='5' + fi + + if [[ "${ret}" -eq '0' ]]; then + typeset -i i='0' + for ((i = 0; i < ${#used_display_ports[@]}; ++i)); do + if [[ "${used_display_ports[i]}" = "${port}" ]]; then + ret='1' + break + fi + done + fi + + if [[ "${ret}" -eq '0' ]]; then + # Looks free, check system sockets. + if "${ss}" -lxs 2>'/dev/null' | grep -Eqs "(@|)/tmp/.X11-unix/X${port}(|-lock) " >'/dev/null'; then + ret='1' + fi + fi + + if [[ "${ret}" -eq '0' ]]; then + # Still looks free, check X2Go database. + check_x2go_port "${current_host_name}" "$((port + 6000))" || ret='1' + fi + + if [[ "${ret}" -eq '0' ]]; then + # Still looks free, check system state. + check_system_port "${ss}" "$((port + 6000))" || ret='1' + fi + + return "${ret}" +} -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2goserver.git