source: epoptes/trunk/fuentes/data/client-functions @ 295

Last change on this file since 295 was 295, checked in by mabarracus, 3 years ago

copy trusty epoptes code

File size: 10.1 KB
Line 
1###########################################################################
2# Implements the client side of the epoptes communications protocol.
3# The daemon reads this file when it starts, and sends it to clients when they
4# connect. The clients actually source it and then wait for further commands.
5#
6# Copyright (C) 2010, 2012 Alkis Georgopoulos <alkisg@gmail.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20#
21# On Debian GNU/Linux systems, the complete text of the GNU General
22# Public License can be found in `/usr/share/common-licenses/GPL'.
23###########################################################################
24
25# Output a message and exit with an error.
26# Parameters:
27# $1..$N = The message.
28die() {
29    echo "epoptes-client ERROR: $@" >&2
30    exit 1
31}
32
33# Calculate, export and return a collection of useful variables.
34info() {
35    local server_ip def_iface
36
37    if [ -z "$cached_info" ]; then
38        VERSION=${VERSION:-0.4.3} # Just in case the client wasn't updated
39        test -n "$USER" || USER=$(whoami)
40        NAME=$(getent passwd "$UID" | cut -d':' -f5 | cut -d',' -f1)
41        test -n "$HOME" || HOME=$(getent passwd "$UID" | cut -d: -f6)
42        if [ -n "$LTSP_CLIENT_HOSTNAME" ]; then
43            HOSTNAME="$LTSP_CLIENT_HOSTNAME"
44        else
45            HOSTNAME=$(hostname)
46            test -n "$HOSTNAME" || die "Empty hostname"
47        fi
48        if [ -n "$LTSP_CLIENT" ] && [ -n "$LTSP_CLIENT_MAC" ]; then
49            # LTSP exports those vars, use them if available.
50            MAC="$LTSP_CLIENT_MAC"
51            IP="$LTSP_CLIENT"
52        else
53            server_ip=$(getent hosts "$SERVER" | cut -d' ' -f1)
54            def_iface=$(ip -oneline -family inet route get "$server_ip" \
55                | sed -n '/.* dev \([^ ]*\).*/s//\1/p')
56            test "${def_iface:-lo}" = "lo" && def_iface=$(ip -oneline -family \
57                inet route show | sed -n '/^default .* dev \([^ ]*\).*/s//\1/p')
58            def_iface=${def_iface:-eth0}
59            MAC=$(ip -oneline -family inet link show dev "$def_iface" \
60                | sed "s/.*ether \([^ ]*\).*/\\1/")
61            MAC=$(echo "$MAC" | sed 'y/abcdef-/ABCDEF:/;s/[^A-F0-9:]//g')
62            test -n "$MAC" || die "Empty MAC"
63            IP=$(ip -oneline -family inet addr show dev "$def_iface" \
64                | sed "s/.* \([0-9.]*\)\/.*/\\1/")
65            test -n "$IP" || die "Empty IP"
66        fi
67        CPU=$(cat /proc/cpuinfo | grep "^model name" | head -n 1 | sed "s/.*: //")
68        RAM=$(free -m | grep "^Mem" | awk '{print $2}')
69        VGA=$(lspci -nn -m | sed -n -e '/"VGA/s/[^"]* "[^"]*" "[^"]*" "\([^"]*\)" .*/\1/p' | tr '\n' ' ')
70        OS=$(uname -o)
71
72        export VERSION USER NAME HOME HOSTNAME MAC IP CPU RAM VGA OS
73        cached_info=true
74    fi
75    cat <<EOF
76uid=$UID
77type=$TYPE
78version=$VERSION
79user=$USER
80name=$NAME
81home=$HOME
82hostname=$HOSTNAME
83mac=$MAC
84ip=$IP
85cpu=$CPU
86ram=$RAM
87vga=$VGA
88os=$OS
89EOF
90}
91
92# Execute a command in the background and optionally print its pid.
93# For internal use. Parameters:
94# [-p]   = print the pid.
95# $1..$N = the command and its parameters.
96background() {
97    local print_pid
98
99    if [ "$1" = "-p" ]; then
100        print_pid=true
101        shift
102    fi
103
104    # On root clients, try to get the active DISPLAY, the command may need it.
105    test "$UID" -eq 0 && export $(./get-display)
106
107    # The command is ran on a subshell with stdin and stdout redirected to
108    # /dev/null, so that it doesn't interfere with the output of other commands.
109    # stderr isn't changed, i.e. ~/.xsession-errors will be used.
110    ( "$@" 0</dev/null >/dev/null ) &
111
112    test -n "$print_pid" && echo $!
113}
114
115# Execute a command in the background.
116# Parameters:
117# $1 = the command.
118execute() {
119    local launcher
120
121    # Do some logging, either in ~/.xsession-errors or on the console.
122    echo "$(LANG=C date '+%c'), epoptes-client executing: $1" >&2
123
124    case "$1" in
125        '')
126            echo "Can't execute an empty command." >&2
127            ;;
128        www.*)
129            set "http://$1"
130            launcher="xdg-open"
131            ;;
132        http:*|https:*|ftp:*|file:*|mailto:*)
133            launcher="xdg-open"
134            ;;
135        *)
136            if [ -e "$1" ] && ( [ ! -x "$1" ] || [ -d "$1" ] ); then
137                launcher="xdg-open"
138            elif which -- "$1" >/dev/null; then
139                # Don't waste RAM for sh if it's just an executable.
140                launcher=""
141            fi
142    esac
143    # In all unhandled cases, run the command with sh -c.
144    launcher=${launcher-sh -c}
145    background $launcher "$1"
146}
147
148
149# Log out the connected user.
150logout() {
151    ./endsession --logout
152}
153
154# Reboot the client.
155reboot() {
156    ./endsession --reboot
157}
158
159# Shut down the client.
160shutdown() {
161    ./endsession --shutdown
162}
163
164# Create a thumbnail of the user screen.
165# Parameters:
166# $1 = thumbnail width.
167# $2 = thumbnail height.
168screenshot() {
169    if ./screenshot "$1" "$2"; then
170        BAD_SCREENSHOTS=0
171    elif [ "$BAD_SCREENSHOTS" -eq 3 ]; then
172        die "3 failed screenshots, exiting..."
173    else
174        BAD_SCREENSHOTS=$(($BAD_SCREENSHOTS+1))
175    fi
176}
177
178# Lock the screen.
179# Parameters:
180# $1 = seconds to keep screen locked, 0 means forever - currently ignored.
181# $2 = message to display to the user.
182lock_screen() {
183    test -n "$EPOPTES_LOCK_SCREEN_PID" && kill "$EPOPTES_LOCK_SCREEN_PID"
184    EPOPTES_LOCK_SCREEN_PID=$(background -p ./lock-screen "$2")
185}
186
187# Unlock a locked screen.
188unlock_screen() {
189    if [ -n "$EPOPTES_LOCK_SCREEN_PID" ]; then
190        kill "$EPOPTES_LOCK_SCREEN_PID"
191        unset EPOPTES_LOCK_SCREEN_PID
192    fi
193}
194
195# Mute the system sound.
196# Parameters:
197# $1 = seconds to keep sound muted, 0 means forever - currently ignored.
198mute_sound() {
199    if [ -x /usr/bin/pactl ]; then
200        background pactl set-sink-mute @DEFAULT_SINK@ 1
201    elif [ -x /usr/bin/amixer ]; then
202        background amixer -c 0 -q sset Master mute
203    fi
204}
205
206# Unute the system sound.
207unmute_sound() {
208    if [ -x /usr/bin/pactl ]; then
209        background pactl set-sink-mute @DEFAULT_SINK@ 0
210    elif [ -x /usr/bin/amixer ]; then
211        background amixer -c 0 -q sset Master unmute
212    fi
213}
214
215# Display some text to the user.
216# Parameters:
217# $1 = text.
218# $2 = title.
219# $3 = True/False, whether the text contains pango markup.
220message() {
221    background ./message "$1" "$2" "$3"
222}
223
224# Connect to the server to be monitored.
225# Parameters:
226# $1 = port.
227get_monitored() {
228    background x11vnc -noshm -24to32 -viewonly -connect_or_exit "$1"
229}
230
231# Connect to the server to get assistance.
232# Parameters:
233# $1 = port.
234# $2 = grab keyboard and mouse.
235get_assisted() {
236    background x11vnc -noshm -24to32 ${2:+-grabptr -grabkbd} -connect_or_exit "$1"
237}
238
239# Deactivate the screensaver, in order for the users to watch a broadcast.
240stop_screensaver() {
241    if [ -x /usr/bin/gnome-screensaver-command ]; then
242        gnome-screensaver-command -d
243    fi
244}
245
246# Receive a broadcasted screen from the server.
247# Parameters:
248# $1 = port.
249# $2 = password (encrypted as in ~/.vnc/passwd and octal-escaped).
250# $3 = fullscreen.
251receive_broadcast() {
252    stop_receptions
253    test "$UID" -eq 0 && export $(./get-display)
254    xset dpms force on
255    if [ -z "$VNCVIEWER" ]; then
256        # If the user installed ssvnc, prefer it over xvnc4viewer
257        if [ -x /usr/bin/ssvncviewer ]; then
258            VNCVIEWER=ssvncviewer
259        elif [ -x /usr/bin/xvnc4viewer ]; then
260            VNCVIEWER=xvnc4viewer
261        fi
262    fi
263    printf "$2" | {
264        sleep 0.$(($(hexdump -e \"%d\" -n 2 /dev/urandom) % 50 + 50))
265        if [ "$VNCVIEWER" = "ssvncviewer" ]; then
266            exec ssvncviewer -shared -viewonly -passwd /dev/stdin \
267                ${3:+-fullscreen} "$1"
268        elif [ "$VNCVIEWER" = "xvnc4viewer" ]; then
269            exec xvnc4viewer -Shared -ViewOnly -passwd /dev/stdin \
270                ${3:+-FullScreen -UseLocalCursor=0 -MenuKey F13} "$1"
271        else
272            exec vncviewer -shared -viewonly -passwd /dev/stdin \
273                ${3:+-fullscreen} "$1"
274        fi
275    } >/dev/null 2>&1 &
276    EPOPTES_VNCVIEWER_PID="$!"
277}
278
279# The vnc clients should automatically exit when the server is killed.
280# Unfortunately, that isn't always true, so try to kill them anyway.
281stop_receptions() {
282    if [ -n "$EPOPTES_VNCVIEWER_PID" ]; then
283        kill "$EPOPTES_VNCVIEWER_PID"
284        unset EPOPTES_VNCVIEWER_PID
285    fi
286}
287
288# Open a root terminal inside the X session.
289root_term() {
290    background xterm -e bash -l
291}
292
293# Send a screen session to the server using socat.
294# Parameters:
295# $1 = port.
296remote_term() {
297    local screen_params
298    REM=$1
299    if [ "$UID" -eq 0 ]; then
300        REM="$SERVER:${1#*:}"
301        screen_params="bash -l"
302    else
303        screen_params="-l"
304    fi
305    background sh -c "
306cd
307sleep 1
308TERM=xterm exec socat EXEC:'screen $screen_params',pty,stderr tcp:$REM"
309}
310
311# Ping is called every few seconds just to make sure the connection is alive.
312# But currently we use it as a workaround to kill stale clients too:
313# Epoptes-client isn't registered as an X session client, and it doesn't
314# exit automatically, so tell it to exit as soon as X is unavailable.
315ping() {
316    if [ "$UID" -gt 0 ]; then
317        xprop -root -f EPOPTES_CLIENT 32c -set EPOPTES_CLIENT $$ || exit
318    fi
319}
320
321# Display a message.
322# Parameters:
323# $1..$N = The message.
324# echo()
325# No need to implement it in the shell, it's embedded.
326
327# Main
328
329if [ -z "$UID" ] || [ -z "$TYPE" ] || [ -z "$SERVER" ]; then
330    die "Required environment variables are missing."
331fi
332
333# Source the lsb init functions, for log_end_msg.
334# Unfortunately it seems that Centos and Fedora don't have that file.
335if [ -f /lib/lsb/init-functions ]; then
336    ( # Use a subshell, we only need init-functions once
337    . /lib/lsb/init-functions
338    log_end_msg 0 >&5
339    )
340else
341    echo "[ OK ]" >&5
342fi
343
344info
Note: See TracBrowser for help on using the repository browser.