#!/usr/local/bin/bash # Free implementation of nxserver components # # To use nxserver add the user "nx" # and use nxserver as default shell. # # Also make sure that hostkey based authentification works. # # Copyright (c) 2004 by Fabian Franz . # # License: GNU GPL, version 2 # # CVS: $Id: nxserver,v 1.75 2005/08/05 16:38:44 fabianx Exp $ # # Read the config file . $(PATH=$(cd $(dirname $0) && pwd):$PATH which nxloadconfig) -- # following two functions are Copyright by Klaus Knopper stringinstring(){ case "$2" in *$1*) return 0;; esac return 1 } # Reread boot command line; echo last parameter's argument or return false. getparam(){ stringinstring "&$1=" "$CMDLINE" || return 1 echo "$CMDLINE" | tr "&" "\n" | egrep "^"$1"=" | awk -F= '{ VAL=$2 } END { print VAL }' return 0 } ############### PACKAGE passdb.bm ####################### # # Library of passdb functions (outsource) # # Policy: Variable and function names _must_ start with passdb_ / PASSDB_ # Needed global vars: $NX_ETC_DIR, $PATH_BIN # Needed nonstd functions: md5sum passdb_get_crypt_pass() { echo "$@" | $COMMAND_MD5SUM | cut -d" " -f1 } passdb_get_pass() { PASSDB_CHUSER="$1" PASSDB_PASS=$(egrep "^$PASSDB_CHUSER:" $NX_ETC_DIR/passwords 2>/dev/null | cut -d":" -f2) if [ "$ENABLE_PASSDB_AUTHENTICATION" = "1" ] then egrep -q "^$PASSDB_CHUSER:" $NX_ETC_DIR/passwords 2>/dev/null && echo $PASSDB_PASS egrep -q "^$PASSDB_CHUSER:" $NX_ETC_DIR/passwords 2>/dev/null || echo "NOT_VALID" else echo "NOT_VALID" fi } passdb_chpass() { PASSDB_CHUSER="$1" PASSDB_ENC_PASS="$2" cp -f $NX_ETC_DIR/passwords $NX_ETC_DIR/passwords.orig perl -pi -e "s/$PASSDB_CHUSER:.*/$PASSDB_CHUSER:$PASSDB_ENC_PASS/g" $NX_ETC_DIR/passwords } passdb_user_exists() { PASSDB_CHUSER="$1" egrep -q "^$PASSDB_CHUSER:" $NX_ETC_DIR/passwords 2>/dev/null } passdb_remove_user() { PASSDB_CHUSER="$1" cp -f $NX_ETC_DIR/passwords $NX_ETC_DIR/passwords.orig perl -pi -e "s/$PASSDB_CHUSER:.*\n//g" $NX_ETC_DIR/passwords } passdb_add_user() { PASSDB_CHUSER="$1" cp -f $NX_ETC_DIR/passwords $NX_ETC_DIR/passwords.orig echo "$PASSDB_CHUSER:*" >> $NX_ETC_DIR/passwords # deactivated to avoid problems with comm-server su - $PASSDB_CHUSER -c "$PATH_BIN/nxnode --setkey" } passdb_list_user() { cat $NX_ETC_DIR/passwords | cut -d":" -f1 } # # End of passdb Library # ############### PACKAGE session.bm ####################### # # Library of session management functions # # Needed global vars: $NX_SESS_DIR session_list() { cat $NX_SESS_DIR/running/sessionId"{$1}" } # Find all running session-filenames session_find_all() { for i in $NX_SESS_DIR/running/* do [ -f $i ] || break echo $i done } # Find all running sessions of a id session_find_id() { [ -f $NX_SESS_DIR/running/sessionId"{$1}" ] && echo $NX_SESS_DIR/running/sessionId"{$1}" } # finds out if a session belongs to a user session_find_id_user() { [ -f $NX_SESS_DIR/running/sessionId"{$1}" ] && egrep -q "^userName=$2$" $NX_SESS_DIR/running/sessionId"{$1}" && return 0 return 1 } # Find all running sessions of a user session_find_user() { for i in $NX_SESS_DIR/running/* do [ -f $i ] || break egrep -q "^userName=$1$" $i && echo $i done } # Find all running sessions of a display session_find_display() { for i in $NX_SESS_DIR/running/* do [ -f $i ] || break egrep -q "^display=$1$" $i && echo $i done } # session_get_cmdline session_get_cmdline() { echo "a=b" | cat - $1 | tr '\n' '&' } # session_get session_get() { session_get_cmdline $NX_SESS_DIR/running/sessionId"{$1}" } # Get the first session, which can be resumed session_get_user_suspended() { for i in $NX_SESS_DIR/running/* do [ -f $i ] || break if egrep -q "^userName=$1$" $i && egrep -q "^status=$2$" $i then CMDLINE=$(session_get_cmdline $i) echo "$(getparam sessionId)" break fi done } # Count all sessions of a user # and save it in SESSION_COUNT and SESSION_COUNT_USER session_count_user() { SESSION_COUNT=0 SESSION_COUNT_USER=0 for i in $NX_SESS_DIR/running/* do [ -f $i ] || break let SESSION_COUNT=$SESSION_COUNT+1 egrep -q "^userName=$1$" $i && let SESSION_COUNT_USER=$SESSION_COUNT_USER+1 done } # List all sessions of a user session_list_user_suspended() { SESSION_COUNT=0 SESSION_COUNT_USER=0 TMPFILE=$(mktemp /tmp/nxserver_tmp.XXXXXXXXX) echo "NX> 127 Sessions list of user '$1' for reconnect:" > $TMPFILE echo >> $TMPFILE if [ -z "$4" ] then echo "Display Type Session ID Options Depth Screensize Available Session Name" >> $TMPFILE echo "------- ---------------- -------------------------------- -------- ----- -------------- --------- ----------------------" >> $TMPFILE else echo "Display Type Session ID Options Depth Screen Status Session Name" >> $TMPFILE echo "------- ---------------- -------------------------------- -------- ----- -------------- ----------- ------------------------------" >> $TMPFILE fi for i in $NX_SESS_DIR/running/* do [ -f $i ] || break let SESSION_COUNT=$SESSION_COUNT+1 if egrep -q "^userName=$1$" $i && egrep -q "^status=$2$" $i #&& grep -q "screeninfo=$3" $i then CMDLINE=$(session_get_cmdline $i) depth=$(getparam screeninfo | cut -d "x" -f3 | cut -d "+" -f1 ) geom=$(getparam screeninfo | cut -d "x" -f1,2) render=$(getparam screeninfo | cut -d "+" -f2 ) available="N/A" udepth=$(echo $3 | cut -d "x" -f3 | cut -d "+" -f1 ) urender=$(echo $3 | cut -d "+" -f2 ) options="-" stringinstring "fullscreen" "$3" && options="F" [ "$(getparam geometry)" = "fullscreen" ] || options="-" [ "$urender" = "render" ] && options="${options}R---PSA" [ "$urender" = "render" ] || options="${options}----PSA" [ "$udepth" = "$depth" -a "$urender" = "$render" ] && available=$(getparam status) # FIXME: HACK !!! to keep compatibility with old snapshot version (Knoppix 3.6 based for example) if [ -z "$4" -a "$available" != "N/A" ] then available="Yes" fi printf "%-7s %-16s %32s %8s %5s %-14s %-11s %s\n" "$(getparam display)" "$(getparam type)" "$(getparam sessionId)" "$options" "$depth" "$geom" "$available" "$(getparam sessionName)" >> $TMPFILE fi egrep -q "^userName=$1$" $i && let SESSION_COUNT_USER=$SESSION_COUNT_USER+1 done echo "" >> $TMPFILE echo "" >> $TMPFILE cat $TMPFILE rm -f $TMPFILE if [ "$SESSION_COUNT" -ge "$SESSION_LIMIT" -o "$SESSION_COUNT_USER" -ge "$SESSION_USER_LIMIT" ] then echo "NX> 147 Server capacity: reached for user: $1" else echo "NX> 148 Server capacity: not reached for user: $1" fi } session_list_user() { echo "NX> 127 Sessions list of user '$1'" echo echo "Display Username Remote IP Session ID" echo "------- --------------- --------------- --------------------------------" for i in $NX_SESS_DIR/running/* do [ -f $i ] || break if egrep -q "^userName=$1$" $i then CMDLINE=$(session_get_cmdline $i) echo -e "$(getparam display)\t$(getparam userName)\t$(getparam foreignAddress)\t$(getparam sessionId)" fi done } session_history() { userName=$1 sessionId=$2 echo "NX> 127 Session list:" echo echo "Display Username Remote IP Session ID Date Status" echo "------- --------------- --------------- -------------------------------- ------------------- -----------" for j in $(ls --time-style +%s -la "$NX_SESS_DIR"/{closed,failed,running} | awk '/sessionId/ { print $6 " " $7 }' | sort -n | cut -d" " -f2) do if [ -n "$sessionId" ] then [ "$j" = "sessionId{$sessionId}" ] || continue fi i="$NX_SESS_DIR"/*/"$j" [ -f $i ] || break CMDLINE=$(session_get_cmdline $i) if [ -n "$userName" ] then [ "$userName" = "$(getparam userName)" ] || continue fi echo -e "$(getparam display)\t$(getparam userName)\t$(getparam foreignAddress)\t$(getparam sessionId)\t$(ls --time-style="+%F %X" -l $i | awk '/sessionId/ { print $6 " " $7 }')\t$(getparam status)" done } # remove all sessions older than $SESSION_HISTORY seconds in failed/closed. session_cleanup() { [ "$SESSION_HISTORY" -gt "-1" ] || return let SESSION_HISTORY_MINUTES=$SESSION_HISTORY/60 find $NX_SESS_DIR/closed/ $NX_SESS_DIR/failed/ -type f -mmin +"$SESSION_HISTORY_MINUTES" -exec rm -f '{}' ';' } session_list_all() { echo "NX> 127 Sessions list:" echo echo "Display Username Remote IP Session ID" echo "------- --------------- --------------- --------------------------------" for i in $NX_SESS_DIR/running/* do [ -f $i ] || break CMDLINE=$(session_get_cmdline $i) echo -e "$(getparam display)\t$(getparam userName)\t$(getparam foreignAddress)\t$(getparam sessionId)" done } # session_add session_add() { id=$1 shift echo "$@" | tr '&' '\n' > $NX_SESS_DIR/running/sessionId'{'$id'}' } # session_change session_change() { [ -f $NX_SESS_DIR/running/sessionId'{'$1'}' ] && perl -pi -e "s/$2=.*/$2=$3/" $NX_SESS_DIR/running/sessionId'{'$1'}' } # session_id session_status() { session_change "$1" "status" "$2" } # session_close session_close() { perl -pi -e "s/startTime=\(.*\)/startTime=\1\nendTime=$(date +%s)/" $NX_SESS_DIR/running/sessionId'{'$1'}' session_status $1 "Finished" [ "$SESSION_HISTORY" = "0" ] && rm -f $NX_SESS_DIR/running/sessionId'{'$1'}' [ "$SESSION_HISTORY" = "0" ] || mv -f $NX_SESS_DIR/running/sessionId'{'$1'}' $NX_SESS_DIR/closed/sessionId'{'$1'}' } session_fail() { perl -pi -e "s/startTime=\(.*\)/startTime=\1\nendTime=$(date +%s)/" $NX_SESS_DIR/running/sessionId'{'$1'}' session_status $1 "Failed" [ "$SESSION_HISTORY" = "0" ] && rm -f $NX_SESS_DIR/running/sessionId'{'$1'}' [ "$SESSION_HISTORY" = "0" ] || mv -f $NX_SESS_DIR/running/sessionId'{'$1'}' $NX_SESS_DIR/failed/sessionId'{'$1'}' } session_suspend() { session_status $1 "Suspended" session_change $1 foreignAddress "-" } # # end of library # # # Main nxserver <-> nxclient communication module # if [ $USER = "nxfree" -o "$USER" = "nx" -o "$ENABLE_USERMODE_AUTHENTICATION" = "1" ] then setup_usermode_auth() { [ $USER = "nxfree" -o "$USER" = "nx" ] && ENABLE_USERMODE_AUTHENTICATION="0" if [ "$ENABLE_USERMODE_AUTHENTICATION" = "1" ] then export NX_SESS_DIR="$USER_FAKE_HOME/.nx/db/" export NX_LOGFILE="$USER_FAKE_HOME/.nx/temp/nxserver.log" mkdir -p $NX_SESS_DIR/{closed,running,failed} fi } setup_usermode_auth # Loglevels: # 1: Errors # 2: Warnings # 3: Important information # 4: Server - Client communication # 5: Information # 6: Debugging information # 7: stderror-channel of some applications log() { [ "$NX_LOG_LEVEL" -ge "$1" -a -w "$NX_LOGFILE" ] && shift && echo "$@" >> "$NX_LOGFILE" } # Log in a way that is secure for passwords / cookies / ... echo_secure() { echo "$@ " | perl -pi -e 's/--cookie=".+?"/--cookie="******"/g; s/--agent_password=".+?"/agent_password="******"/g; s/--password=".+?"/password="******"/g; s/cookie=.+?&/cookie=******&/g; s/agent_password=.+?&/agent_password=******&/g; s/password=.+?&/password=******&/g;' } log_secure() { if [ "$NX_LOG_SECURE" = "0" ] then log "$@" else [ "$NX_LOG_LEVEL" -ge "$1" -a -w "$NX_LOGFILE" ] && shift && echo_secure "$@" >> "$NX_LOGFILE" fi } log_tee() { [ "$NX_LOG_LEVEL" -ge "4" -a -w "$NX_LOGFILE" ] && exec tee -a "$NX_LOGFILE" [ "$NX_LOG_LEVEL" -ge "4" -a -w "$NX_LOGFILE" ] || exec cat - } log_error() { [ "$NX_LOG_LEVEL" -ge "7" -a -w "$NX_LOGFILE" ] && exec tee -a "$NX_LOGFILE" [ "$NX_LOG_LEVEL" -ge "7" -a -w "$NX_LOGFILE" ] || exec cat - } echo_x() { log "4" "$@" echo "$@" } # Start! [ "$NX_LOG_LEVEL" -ge "1" ] && touch "$NX_LOGFILE" >/dev/null 2>&1 log 3 "-- NX SERVER START: $@" if [ "$ENABLE_SERVER_FORWARD" = "1" -a -n "$SERVER_FORWARD_HOST" ] then log 3 "Info: Forwarding connection to $SERVER_FORWARD_HOST with secret key $SERVER_FORWARD_KEY." $COMMAND_SSH -i "$SERVER_FORWARD_KEY" "nx@$SERVER_FORWARD_HOST:$SERVER_FORWARD_PORT" exit 0 fi # forward the connection to commercial NoMachine server? if [ "$ENABLE_NOMACHINE_FORWARD_PORT" = "1" -a "$NOMACHINE_FORWARD_PORT" = "$(echo $SSH_CLIENT $SSH2_CLIENT| cut -d' ' -f3)" -a -n "$NOMACHINE_SERVER" ] then log 3 "Info: Detected SSH destination port $NOMACHINE_FORWARD_PORT. Forwarding connection to commercial NoMachine server." exec $NOMACHINE_SERVER log 1 "Error: Forwarding to NoMachine Server $NOMACHINE_SERVER failed. Using FreeNX server instead." fi echo_x "HELLO NXSERVER - Version $NX_VERSION $NX_LICENSE" # Login stage while true do echo_x -n "NX> 105 " read CMD # FIXME? [ "$CMD" = "" ] && CMD="quit" echo_x "$CMD" case "$CMD" in quit|QUIT) echo_x "Quit" echo_x "NX> 999 Bye" exit 0 ;; exit|EXIT) echo_x "Exit" echo_x "NX> 999 Bye" exit 0 ;; bye|BYE) echo_x "Bye" echo_x "NX> 999 Bye" exit 0 ;; hello*|HELLO*) PROTO=$(echo $CMD | sed 's/.*Version \(.*\)/\1/g') echo_x "NX> 134 Accepted protocol: $PROTO" if [ "$PROTO" = "1.3.0" -o "$PROTO" = "1.3.2" ] then [ "$ENABLE_AUTORECONNECT_BEFORE_140" = "1" ] && ENABLE_AUTORECONNECT="1" fi ;; "set auth_mode*"|"SET AUTH_MODE*") if [ "$CMD" = "set auth_mode password" -o "$CMD" = "SET AUTH_MODE PASSWORD" ] then echo_x "Set auth_mode: password" else echo_x "NX> 500 ERROR: unknown auth mode ''" fi ;; login|LOGIN) LOGIN_SUCCESS="0" echo_x -n "NX> 101 User: " read USER echo_x $USER echo_x -n "NX> 102 Password: " read -s PASS echo_x "" log 6 -n "Info: Auth method: " # USER already logged in? if [ "$ENABLE_USERMODE_AUTHENTICATION" = "1" ] then LOGIN_SUCCESS="1" LOGIN_METHOD="USERMODE" USER=$(whoami) fi # PASSDB based auth if [ "$ENABLE_PASSDB_AUTHENTICATION" = "1" -a "$LOGIN_SUCCESS" = "0" ] then log 6 -n "passdb " if [ $(passdb_get_crypt_pass "$PASS") = $(passdb_get_pass "$USER") ] then LOGIN_SUCCESS="1" LOGIN_METHOD="PASSDB" fi fi # SSH based auth if [ "$ENABLE_SSH_AUTHENTICATION" = "1" -a "$LOGIN_SUCCESS" = "0" ] then log 6 -n "ssh " export COMMAND_SSH echo "$PASS" | $PATH_BIN/nxnode-login -- ssh "$USER" "$SSHD_PORT" "$PATH_BIN/nxnode" --check 2>&1 >/dev/null if [ $? -eq 0 ] then LOGIN_SUCCESS="1" LOGIN_METHOD="SSH" fi fi # SU based auth if [ "$ENABLE_SU_AUTHENTICATION" = "1" -a "$LOGIN_SUCCESS" = "0" ] then log 6 -n "su " echo "$PASS" | $PATH_BIN/nxnode-login -- su "$USER" "" "$PATH_BIN/nxnode" --check 2>&1 >/dev/null if [ $? -eq 0 ] then LOGIN_SUCCESS="1" LOGIN_METHOD="SU" fi fi # Check if user in passdb if [ "$ENABLE_USER_DB" = "1" ] then log 6 "userdb check" passdb_user_exists "$USER" || LOGIN_SUCCESS="0" fi log 6 "" if [ "$LOGIN_SUCCESS" = "1" ] then # Reread the config files (so that $USER.node.conf get sourced) . $(PATH=$(cd $(dirname $0) && pwd):$PATH which nxloadconfig) --userconf setup_usermode_auth echo_x "NX> 103 Welcome to: $SERVER_NAME user: $USER" break else echo_x "NX> 404 ERROR: wrong password or login" echo_x "NX> 999 Bye" exit 1 fi ;; esac done # remove old session infos from history session_cleanup # # call it with: server_get_params $CMD # no ""! # server_get_params() { SERVER_PARAMS=$(echo "$@" | sed "s/^$1/\"/g; s/\" --/\&/g; s/\"//g") if [ "$SERVER_PARAMS" = "" ] then echo_x -n "NX> 106 Parameters: " read SERVER_PARAMS2 SERVER_PARAMS=$(echo $SERVER_PARAMS2 | sed 's/%2B/+/g') echo_x fi } nxnode_start() { : #CMD="$1" #shift #echo "$@" | $PATH_BIN/nxnode "$CMD" } #NX> 1002 Commit #NX> 1006 Session status: running server_nxnode_start() { CMD="$1" USER="$2" shift shift # Use nxnode-login? if [ "$LOGIN_METHOD" = "SSH" ] then export COMMAND_SSH echo "$PASS" | NXNODE_TOSEND="$@" $PATH_BIN/nxnode-login -- ssh "$USER" "$SSHD_PORT" "$PATH_BIN/nxnode" "$CMD" 2>&1 | log_tee elif [ "$LOGIN_METHOD" = "SU" ] then echo "$PASS" | NXNODE_TOSEND="$@" $PATH_BIN/nxnode-login -- su "$USER" "" "$PATH_BIN/nxnode" "$CMD" 2>&1 | log_tee elif [ "$LOGIN_METHOD" = "USERMODE" ] then echo "$@" | $PATH_BIN/nxnode "$CMD" 2>&1 | log_tee else echo "$@" | $COMMAND_SSH -l "$USER" 127.0.0.1 -p $SSHD_PORT -x -2 -i $NX_ETC_DIR/users.id_dsa -o 'PubkeyAuthentication yes' -o 'RSAAuthentication yes' -o 'RhostsAuthentication no' -o 'PasswordAuthentication no' -o 'RhostsRSAAuthentication no' -o 'StrictHostKeyChecking no' $PATH_BIN/nxnode "$CMD" | log_tee fi } server_add_usession() { [ "$ENABLE_USESSION" = "1" ] || return $COMMAND_SESSREG -l ":$SESS_DISPLAY" -h "$USERIP" -a $USER 2>&1 | log_error } server_remove_usession() { [ "$ENABLE_USESSION" = "1" ] || return $COMMAND_SESSREG -l ":$SESS_DISPLAY" -h "$USERIP" -d $USER 2>&1 | log_error } server_nxnode_echo() { [ "$SERVER_CHANNEL" = "1" ] && echo "$@" [ "$SERVER_CHANNEL" = "2" ] && echo "$@" >&2 } server_nxnode_exit_func() { log 1 "Info: Emergency-Shutting down due to kill signal ..." session_fail $uniqueid server_remove_usession # remove lock file [ -e "/tmp/.nX$SESS_DISPLAY-lock" ] && rm -f /tmp/.nX$SESS_DISPLAY-lock } server_nxnode_start_wait() { server_add_usession # Trap did fire unnecessarily according to Sunil, so removed it again. #trap server_nxnode_exit_func EXIT SERVER_CHANNEL=1 KILL_WAIT_PID=1 server_nxnode_start "$@" | while read CMD do case "$CMD" in "NX> 1006"*|"NX> 1005"*|"NX> 1009"*) case "$CMD" in *running*) [ "$KILL_WAIT_PID" = "1" ] && kill $SERVER_WAIT_PID KILL_WAIT_PID=0 session_status $uniqueid "Running" SERVER_CHANNEL=2 ;; *closed*) session_close $uniqueid ;; *suspended*) [ "$KILL_WAIT_PID" = "1" ] && kill $SERVER_WAIT_PID KILL_WAIT_PID=0 session_suspend $uniqueid ;; *terminating*) session_status $uniqueid "Terminating" # we need to stop sending to client as it will have already # closed his side of the channel and this will lead to not # closed sessions. SERVER_CHANNEL=0 esac ;; "NX> 1004"*) [ "$KILL_WAIT_PID" = "1" ] && kill $SERVER_WAIT_PID KILL_WAIT_PID=0 session_fail $uniqueid # FIXME: Need correct error code. server_nxnode_echo "NX> 504 Session startup failed." log 4 "NX> 504 Session startup failed." ;; esac case $CMD in "NX> "*) server_nxnode_echo $CMD ;; esac done trap "" EXIT server_remove_usession # remove lock file [ -e "/tmp/.nX$SESS_DISPLAY-lock" ] && rm -f /tmp/.nX$SESS_DISPLAY-lock } server_check_session_count() { session_count_user "$USER" if [ "$SESSION_COUNT" -ge "$SESSION_LIMIT" ] then echo_x "NX> 599 Reached the maximum number of concurrent sessions on this server." echo_x "NX> 500 ERROR: Last operation failed." return 1 fi if [ "$SESSION_COUNT_USER" -ge "$SESSION_USER_LIMIT" ] then echo_x "NX> 599 Server capacity: reached for user: $USER" echo_x "NX> 500 ERROR: Last operation failed." return 1 fi return 0 } server_startrestore_session() { ACTION="$1" server_get_params $CMD PARAMS=$SERVER_PARAMS PARAMS="$PARAMS&clientproto=$PROTO" CMDLINE=$PARAMS echo_x # If we can't get the userip and SSHD_CHECK_IP is set to 1 # we bail out. if [ -z "$SSH_CLIENT" -a -z "$SSH2_CLIENT" ] then if [ "$SSHD_CHECK_IP" = "1" ] then echo_x "NX> 504 Session startup failed. (Missing SSH_CLIENT environment variable)" return 1 else log 2 "Warning: Failed to determine the client IP." log 2 "Warning: The SSH_CLIENT or SSH2_CLIENT variable was not provided by SSHD." log 2 "Warning: Please set SSHD_CHECK_IP=1 if you want to refuse the connection." fi fi export ENCRYPTION=$(getparam encryption) if [ "$ENABLE_FORCE_ENCRYPTION" = "1" -a "$ENCRYPTION" != "1" ] then echo_x "NX> 504 Unencrypted sessions are not allowed." return 1 fi # check if there is a suspended session, which we could resume if [ "$ENABLE_AUTORECONNECT" = "1" -a "$ACTION" = "start" ] then restore=$(session_get_user_suspended "$USER" "Suspended") if [ -n "$restore" ] then PARAMS="$PARAMS&restore=$restore" CMDLINE=$PARAMS ACTION="resume" fi fi # as only $SSH_CLIENT or $SSH2_CLIENT will be set, this should work USERIP=$(echo $SSH_CLIENT $SSH2_CLIENT | cut -d" " -f1 | sed 's/::ffff://g') [ -z "$USERIP" ] && USERIP="*" if [ "$ACTION" = "start" ] then server_check_session_count || return 1 # start nxnode SESS_DISPLAY=$DISPLAY_BASE let SESS_DISPLAY_LIMIT=$DISPLAY_BASE+$DISPLAY_LIMIT # stupid but working algo ... # TODO: need to check for _all_ offset and ports :-/ while true do while [ -e /tmp/.X$SESS_DISPLAY-lock -o -e "/tmp/.nX$SESS_DISPLAY-lock" ] do let SESS_DISPLAY=$SESS_DISPLAY+1 done # Check if there is already an agent running on that display let AGENT_DISPLAY=$SESS_DISPLAY+6000 if $COMMAND_NETCAT -z 127.0.0.1 $AGENT_DISPLAY 2>/dev/null then log 2 "Warning: Stray nxagent without .X$SESS_DISPLAY-lock found on port $AGENT_DISPLAY." let SESS_DISPLAY=$SESS_DISPLAY+1 continue fi SESS_LOCKFILE=$(mktemp "/tmp/.nX$SESS_DISPLAY-lock.XXXXXXXXX") # ln is an atomic operation ln "$SESS_LOCKFILE" "/tmp/.nX$SESS_DISPLAY-lock" 2>/dev/null && break done rm -f "$SESS_LOCKFILE" if [ "$SESS_DISPLAY" -gt "$SESS_DISPLAY_LIMIT" ] then # fixme we need the correct error code echo_x "NX> 504 Error: Display limit exceeded. Please remove some files from /tmp/.X*-lock." rm -f "/tmp/.nX$SESS_DISPLAY-lock" return fi uniqueid=$(echo $[$RANDOM*$RANDOM] | $COMMAND_MD5SUM | cut -d" " -f1 | tr "[a-z]" "[A-Z]") FULL_PARAMS="$PARAMS&user=$USER&userip=$USERIP&uniqueid=$uniqueid&display=$SESS_DISPLAY" log_secure "6" "$FULL_PARAMS" # now update the session listing CMDLINE="a=b&$FULL_PARAMS" session_add $uniqueid "sessionName=$(getparam session)&display=$(getparam display)&status=Running&startTime=$(date +%s)&foreignAddress=$(getparam userip)&type=$(getparam type)&sessionId=$uniqueid&creationTime=$(date +%s)&userName=$USER&serverPid=$SERVER_PID&screeninfo=$(getparam screeninfo)&geometry=$(getparam geometry)" else uniqueid=$(getparam restore) [ -z "$uniqueid" ] && uniqueid=$(getparam id) # 1.4.0-5 compatibility session_change "$uniqueid" "foreignAddress" "$USERIP" CMDLINE=$(session_get "$uniqueid") FULL_PARAMS="$PARAMS&user=$USER&userip=$(getparam foreignAddress)&uniqueid=$uniqueid&display=$(getparam display)" SESS_DISPLAY=$(getparam display) fi # now start the node (sleep $AGENT_STARTUP_TIMEOUT; exit 1) & SERVER_WAIT_PID=$! server_nxnode_start_wait --"$ACTION"session $USER "$FULL_PARAMS" & SERVER_PID=$! disown $SERVER_PID wait $SERVER_WAIT_PID if [ $? -eq 1 ] then # Something went wrong ... [ "$ACTION" = "start" ] && session_fail $uniqueid # FIXME: Need correct error code. echo_x "NX> 1004 Error: Session did not start." echo_x "NX> 504 Session startup failed." echo_x "NX> 999 Bye" # FIXME: Send node signal to terminate exit 1 fi } # Session stage while true do echo_x -n "NX> 105 " unset CMD read CMD 2>/dev/null # FIXME? [ "$CMD" = "" ] && CMD="quit" # Logging case "$CMD" in startsession*|restoresession*|addmount*|addprinter*) echo_secure "$CMD" log_secure "4" "$CMD" ;; *) echo "$CMD" log "4" "$CMD" ;; esac case "$CMD" in quit|QUIT) echo_x "Quit" echo_x "NX> 999 Bye" exit 0 ;; exit|EXIT) echo_x "Exit" echo_x "NX> 999 Bye" exit 0 ;; bye|BYE) echo_x "Bye" 1>&2 echo_x "NX> 999 Bye" 1>&2 if [ "$ENCRYPTION" = "1" ] then let PROXY_DISPLAY=$SESS_DISPLAY+4000 $COMMAND_NETCAT 127.0.0.1 $PROXY_DISPLAY exit 0 else echo_x "NX> 1001 Bye." fi ;; startsession*) server_startrestore_session "start" ;; list*) server_get_params $CMD PARAMS=$SERVER_PARAMS CMDLINE=$PARAMS status=$(getparam status) if [ "$status" = "Suspended" -a -n "$(getparam screeninfo)" ] then session_list_user_suspended "$USER" "Suspended" "$(getparam screeninfo)" "$(getparam type)" | log_tee elif [ "$status" = "Suspended,Running" -o "$status" = "Suspended" ] # since 1.4.0-5 then # disabled due to problems with 1.4.0-5 client #session_list_user_suspended "$USER" 'Suspended$|^status=Running$' "$(getparam geometry)" "$(getparam type)" | log_tee session_list_user_suspended "$USER" 'Suspended' "$(getparam geometry)" "$(getparam type)" | log_tee elif [ "$status" = "suspended,running" -o "$status" = "suspended" ] # since 1.5.0 then session_list_user_suspended "$USER" 'Suspended' "$(getparam geometry)" "$(getparam type)" | log_tee else session_list_user "$USER" | log_tee fi ;; suspend*) server_get_params $CMD PARAMS=$SERVER_PARAMS CMDLINE=$PARAMS if session_find_id_user "$(getparam sessionid)" "$USER" then # FIXME: Check for success/error server_nxnode_start --suspend "$USER" "$PARAMS" session_suspend $(getparam sessionid) fi ;; terminate*) server_get_params $CMD PARAMS=$SERVER_PARAMS CMDLINE=$PARAMS if session_find_id_user "$(getparam sessionid)" "$USER" then # FIXME: Check for success/error server_nxnode_start --terminate "$USER" "$PARAMS" session_close $(getparam sessionid) fi ;; restoresession*) server_startrestore_session "resume" ;; passwd) echo_x "NX> 113 Changing password of user '$USER'" echo_x -n "NX> 102 Current password:" read -s PASS ENC_PASS=$(passdb_get_crypt_pass "$PASS") REAL_PASS=$(passdb_get_pass "$USER") echo_x if [ "$ENC_PASS" = "$REAL_PASS" ] then echo_x -n "NX> 102 Password:" read -s NEW_PASS1 if [ ${#NEW_PASS1} -lt 5 ] then echo_x "NX> 500 ERROR: incorrect password format, password must be long at least five characters" continue fi echo_x echo_x -n "NX> 102 Confirm password:" read -s NEW_PASS1 echo_x if [ "$NEW_PASS1" = "$NEW_PASS2" ] then ENC_PASS=$(passdb_get_crypt_pass "$NEW_PASS1") passdb_chpass "$USER" "$ENC_PASS" echo_x "NX> 114 Password of user '$USER' changed" else echo_x "NX> 537 ERROR: passwords do not match" fi else echo_x "NX> 500 ERROR: current password doesn't match" fi ;; addmount*) server_get_params $CMD PARAMS=$SERVER_PARAMS server_nxnode_start --smbmount "$USER" "$PARAMS" >/dev/null 2>&1 | log_error >/dev/null echo_x "NX> 719 SMB filesystem: running" ;; addprinter*) server_get_params $CMD PARAMS=$SERVER_PARAMS server_nxnode_start --addprinter "$USER" "$PARAMS" >/dev/null 2>&1 | log_error >/dev/null ;; *) # disabled for 1.4.0-5 snapshot client #echo_x "NX> 503 Error: undefined command: '$CMD'" ;; esac done fi # # End of Main nxserver <--> nxclient communication module # ################### PACKAGE cmd.bm ############################ # # library functions for nxserver-commandline cmds # # Policy: All functions and variables need to start with CMD_ / cmd_ # Needed global vars: $NX_VERSION, $NX_LICENSE, $NX_ETC_DIR, $PATH_BIN, $NX_HOME_DIR, $SSH_AUTHORIZED_KEYS # Needed package: passdb cmd_usage() { echo "NXSERVER - Version $NX_VERSION $NX_LICENSE" echo "Usage: nxserver