summaryrefslogtreecommitdiffstats
path: root/core/modules/remote-access/data/opt/openslx/scripts/remoteaccess-launch_vnc_server
blob: 892bcf2a915b1a0778a5a00996fcc2e8012c64f2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/bash

t="/tmp/remote-access-$DISPLAY"
mkdir -p "$t"
modmap="$t/modmap.want"
tmpmap="$t/modmap.have"
(
	sleep 1
	setxkbmap de
	xmodmap -e "keycode 92 ="
	xmodmap -e "keycode 187 ="
	xmodmap -e "keycode 188 ="
	xmodmap -e "keycode 26 = e E e E U20AC U20AC U20AC"
	xmodmap -pke > "$modmap"
) &
. /opt/openslx/config
# TODO If we support multiple parallel sessions in the future, we need dedicated
# ports for each session for both, the VNC and the RPC port.
vnc_port="${SLX_REMOTE_VNC_PORT:-5900}"
if ! [ "$vnc_port" -gt 0 ] || ! [ "$vnc_port" -lt 65535 ]; then
	vnc_port=5900
fi
srchost="$SLX_REMOTE_HOST_ACCESS"
if [ -n "$srchost" ]; then
	# IPTABLES
	rule="/opt/openslx/iptables/rules.d/80-remote-access"
	if ! [ -e "$rule" ]; then
		(
			echo "#!/bin/sh"
			echo "iptables -A INPUT -s "'"'"$srchost"'"'" -p tcp --dport $vnc_port -j ACCEPT"
			echo "iptables -A INPUT -s "'"'"$srchost"'"'" -p tcp --dport 7551 -j ACCEPT"
			echo "iptables -A INPUT -p tcp --dport $vnc_port -j DROP"
			echo "iptables -A INPUT -p tcp --dport 7551 -j DROP"
		) > "$rule"
		chmod +x "$rule"
	fi
fi
#set -x
#exec &> /tmp/fooooooooooooo
# dd since busybox head doesn't know -c
passwd="$( < /dev/urandom  tr -c -d 'a-zA-Z0-9#&/=()[]{}' | dd bs=8 count=1 status=none )"
printf "%s" "$passwd" > "$t/vnc-passwd"
[ "$SLX_REMOTE_VNC" = "x11vnc" ] && chmod 0600 "$t/vnc-passwd"
(
	# Make a copy of xauth, so if the xserver restarts, we'll use the old one and fail to connect
	if [ -n "$XAUTHORITY" ]; then
		copy="$( mktemp )"
		cat "$XAUTHORITY" > "$copy"
		export XAUTHORITY="$copy"
		trap 'exit 1' INT TERM
		trap 'rm -f -- "$copy"' EXIT
	fi
	< "$t/vnc-passwd"  tigervncpasswd -f  > "$t/tigervnc-passwd"
	fails=0
	while true; do
		s="$( date +%s )"
		x0vncserver -fg -SecurityTypes VncAuth,TLSvnc -rfbauth "$t/tigervnc-passwd" -rfbport "$vnc_port" -localhost no -Log "*:stdout:100" \
			-AlwaysShared=true -DisconnectClients=false -MaxConnectionTime=0 -MaxDisconnectionTime=0 -MaxIdleTime=0
		e="$( date +%s )"
		d="$(( e - s ))"
		if [ "$d" -gt 5 ]; then
			fails=0
		else
			fails="$(( fails + 1 ))"
			[ "$fails" -gt 10 ] && break
			[ "$fails" -gt 3 ] && usleep 333333
		fi
	done
) &> "$t/x11vnc-log-$$" &
vncpid=$!
# Delay this a bit until x11vnc is ready, and since we might potentially have had a race
# with the ~poweron event, which would reset the password in the database.
(
	if [ -n "$SLX_REMOTE_LOG" ]; then
		url="${SLX_REMOTE_LOG//=clientlog/=remoteaccess}"
	elif [ -n "$SLX_PVS_CONFIG_URL" ]; then
		url="${SLX_PVS_CONFIG_URL//=roomplanner/=remoteaccess}"
	else
		url="http://${SLX_PXE_SERVER_IP}/slx-admin/api.php?do=remoteaccess"
	fi
	for _ in {1..20}; do
		sleep 1
		[ -e "/etc/cron.d/usage_stats" ] && break
	done
	[ -d "/proc/${vncpid}" ] || exit 1 # Something is wrong, bail
	curl -s -S -L --retry 4 --retry-connrefused --max-time 3 --retry-max-time 10 \
		--data-urlencode "password=$passwd" \
		--data-urlencode "vncport=$vnc_port" \
		"$url" > /dev/null
) &
gotone=false
vmvnc=false
idle=0
stepcount=0
# In case of stale entry
# TODO: This sucks anyways performance-wise for VMware, maybe remove?
iptables -t nat -D PREROUTING -p tcp --dport "$vnc_port" -j REDIRECT --to-ports 5901
while [ -d "/proc/${vncpid}" ]; do
	sleep 5
	if netstat -tn | awk 'BEGIN{ e=1 } { if ($4 ~ /:('"$vnc_port"'|5901)$/) e=0 } END{ exit e }'; then
		gotone=true
		idle=0
	else
		idle=$(( idle + 1 ))
	fi
	if $gotone; then
		# As soon as someone is connected, "blank" the screen by setting brightness to zero.
		# This doesn't seem to affect the framebuffer, luckily
		# Let's see how well this works in practice. :-(
		if (( stepcount == 0 )); then
			declare -a args
			args=()
			for o in $( xrandr | grep -E '^[A-Z0-9-]+ connected.*[0-9]+x[0-9]+' | awk '{print $1}' ); do
				args+=( "--output" "$o" "--brightness" "0" )
			done
			xrandr "${args[@]}"
		fi
		if (( stepcount++ > 3 )); then
			stepcount=0
		fi
	fi
	if $gotone && [ "$idle" -gt 120 ]; then # 120 * 5 = 10 mins
		kill "$vncpid"
		break
	fi
	# In case we access vmplayer via x11vnc; vmplayer won't leave the keymap alone >:(
	xmodmap -pke > "$tmpmap"
	if ! cmp -s "$tmpmap" "$modmap"; then
		echo "$( date ) Reloading modmap" >> "$t/reload-log"
		xmodmap "$modmap"
	fi

	# Check if we should redirect to vmware
	if [ "$SLX_REMOTE_VNC" != 'x11vnc' ]; then
		if netstat -tnl | awk 'BEGIN{ e=1 } { if ($4 ~ /:5901$/) e=0 } END{ exit e }'; then
			#enable
			if ! $vmvnc; then
				killall x0vncserver
				usleep 10000
				iptables -t nat -I PREROUTING 1 -p tcp --dport "$vnc_port" -j REDIRECT --to-ports 5901
			fi
			vmvnc=true
		else
			# disable
			if $vmvnc; then
				iptables -t nat -D PREROUTING -p tcp --dport "$vnc_port" -j REDIRECT --to-ports 5901
			fi
			vmvnc=false
		fi
	fi
done
systemctl restart lightdm