#!/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 <FreeNX@fabian-franz.de>.
#
# 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 filename>
session_get_cmdline()
{
echo "a=b" | cat - $1 | tr '\n' '&'
}
# session_get <uniqueid>
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_id> <options>
session_add()
{
id=$1
shift
echo "$@" | tr '&' '\n' > $NX_SESS_DIR/running/sessionId'{'$id'}'
}
# session_change <session_id> <parameter> <new_value>
session_change()
{
[ -f $NX_SESS_DIR/running/sessionId'{'$1'}' ] && perl -pi -e "s/$2=.*/$2=$3/" $NX_SESS_DIR/running/sessionId'{'$1'}'
}
# session_id <new status>
session_status()
{
session_change "$1" "status" "$2"
}
# session_close <session_id> <end-time>
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 <option>" 1>&2
if [ "$1" = "root" ]
then
echo "--adduser <user>: Add a new user" 1>&2
echo "--passwd <user>: Change password of <user>" 1>&2
echo "--deluser <user>: Remove a user from nx" 1>&2
echo "--listuser: List enabled users" 1>&2
echo "" 1>&2
echo "--start: Start the nx server" 1>&2
echo "--stop: Stop the nx server" 1>&2
echo "--status: Show status of nx server" 1>&2
echo "--restart: Restart the nx server and terminate all running sessions" 1>&2
echo "" 1>&2
echo "--list [ user | sessionid ]: List running sessions of user or sessionid " 1>&2
echo "--history [ user | sessionid | clear ]: Show history [ of user | sessionid ] or clear the history" 1>&2
echo "--terminate <user | :display | sessionid>: Terminate the session pointed to by" 1>&2
echo " sessionid or display, or all sessions of the specified user." 1>&2
echo " Use * for all sessions." 1>&2
echo "--suspend <user | :display | sessionid>: Suspend the session pointed to by" 1>&2
echo " sessionid or display, or all sessions of the specified user." 1>&2
echo " Use * for all sessions." 1>&2
echo "--cleanup: Terminates all running sessions. Useful after power-outage."
echo "" 1>&2
echo "--broadcast <message>: Send a message to all users" 1>&2
echo "--send <user | :display | sessionid> <message>: Send a message to the specified user or sessionid" 1>&2
else
echo "--passwd: Change password" 1>&2
fi
exit 1
}
cmd_abort()
{
echo "NX> 500" "$@" 1>&2
echo "NX> 999 Bye" 1>&2
exit 1
}
cmd_user_passwd()
{
echo "NX> 100 NXSERVER - Version $NX_VERSION $NX_LICENSE"
echo "Sorry: Password changing for user is _not_ implemented, yet."
echo "Please login to NX-Server to change password"
echo "or ask your local system administrator."
#echo "NX> 113 Changing password of user '$USER'"
#echo "Old password:"
#read -s OLDPASS
#echo "New password:"
#read -s NEWPASS1
#echo "Repeat:"
#read -s NEWPASS2
}
cmd_passwd()
{
CMD_CHUSER=$2
egrep -q "^$CMD_CHUSER:" $NX_ETC_DIR/passwords || cmd_abort "Error: User $CMD_CHUSER not found in database."
echo -n "New password: "
read -s CMD_NEWPASS
echo
CMD_ENC_PASS=$(passdb_get_crypt_pass "$CMD_NEWPASS")
passdb_chpass "$CMD_CHUSER" "$CMD_ENC_PASS"
echo "Password changed."
}
cmd_adduser()
{
CMD_CHUSER=$2
[ ${#CMD_CHUSER} -ge 32 ] && cmd_abort "Error: User $CMD_CHUSER must be shorter than 32 characters."
egrep -q "^$CMD_CHUSER:" $NX_ETC_DIR/passwords && cmd_abort "Error: User $CMD_CHUSER already in database."
cat /etc/passwd | egrep -q "^$CMD_CHUSER:" || cmd_abort "Error: User $CMD_CHUSER not existing on local system. Can't add."
passdb_add_user "$CMD_CHUSER"
}
cmd_deluser()
{
CMD_CHUSER=$2
egrep -q "^$CMD_CHUSER:" $NX_ETC_DIR/passwords || cmd_abort "Error: User $CMD_CHUSER not found in database."
passdb_remove_user "$CMD_CHUSER"
}
cmd_listuser()
{
echo "NX> 146 NX users list"
echo
echo "Username"
echo "---------------"
echo
passdb_list_user
echo
}
cmd_start()
{
[ -f $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS ] && cmd_abort "ERROR: Service already running"
mv $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS.disabled $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS
echo "NX> 122 Service started"
}
cmd_stop()
{
[ -f $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS ] || cmd_abort "Service was already stopped"
mv $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS.disabled
# TODO: Stop all running sessions
echo "NX> 123 Service stopped"
}
cmd_status()
{
[ -f $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS ] && echo "NX> 110 NX Server is running"
[ -f $NX_HOME_DIR/.ssh/$SSH_AUTHORIZED_KEYS ] || echo "NX> 110 NX Server is stopped"
}
cmd_restart()
{
cmd_stop
cmd_start
}
cmd_parse_2_params()
{
if [ ${#1} -eq 32 ]
then
CMD_APARAMS="sessionid=sessionId{$1}"
else
if [ "$1" != "" ]
then
#egrep -q "^$1:" $NX_ETC_DIR/passwords || cmd_abort "Error: User $1 not found in database."
CMD_APARAMS="user=$1"
fi
fi
echo $CMD_APARAMS
}
cmd_parse_3_params()
{
if [ ${#1} -eq 32 ]
then
CMD_APARAMS=$(session_find_id $1)
[ -n "$CMD_APARAMS" ] || cmd_abort "Error: Session $1 could not be found."
elif [ "${1:0:1}" = ":" ]
then
CMD_APARAMS=$(session_find_display "${1:1}")
[ -n "$CMD_APARAMS" ] || cmd_abort "Error: No running sessions found for display $1."
elif [ "$1" = "*" ]
then
CMD_APARAMS=$(session_find_all)
[ -n "$CMD_APARAMS" ] || cmd_abort "Error: No running sessions found."
elif [ "$1" != "" ]
then
#egrep -q "^$1:" $NX_ETC_DIR/passwords || cmd_abort "Error: User $1 not found in database."
CMD_APARAMS=$(session_find_user "$1")
[ -n "$CMD_APARAMS" ] || cmd_abort "Error: No running sessions found for user $1."
else
cmd_abort "Error: Not enough parameters."
fi
echo $CMD_APARAMS
}
cmd_list_suspended()
{
CMD_PARAMS=$(cmd_parse_2_params "$2")
[ -n "$2" -a -z "$CMD_PARAMS" ] && exit 1
case $CMD_PARAMS in
user=*)
session_list_user_suspended $2 "Suspended"
;;
esac
}
cmd_list()
{
CMD_PARAMS=$(cmd_parse_2_params "$2")
[ -n "$2" -a -z "$CMD_PARAMS" ] && exit 1
case $CMD_PARAMS in
user=*)
session_list_user $2
;;
sessionid=*)
session_list $2
;;
*)
session_list_all
;;
esac
}
cmd_history_clear()
{
rm -f $NX_SESS_DIR/closed/*
rm -f $NX_SESS_DIR/failed/*
}
cmd_history()
{
if [ "$2" = "clear" ]
then
cmd_history_clear
fi
CMD_PARAMS=$(cmd_parse_2_params "$2")
user=""
sessid=""
case $CMD_PARAMS in
user=*)
user="$2"
;;
sessionid=*)
sessid="$2"
;;
esac
session_history "$user" "$sessid"
}
cmd_terminate()
{
CMD_PARAMS=$(cmd_parse_3_params "$2")
[ -z "$CMD_PARAMS" ] && exit 1
for i in $CMD_PARAMS;
do
CMDLINE=$(session_get_cmdline $i)
cmd_sessionid=$(getparam sessionId)
cmd_user=$(getparam userName)
cmd_type=$(getparam type)
cmd_status=$(getparam status)
# is it a "good" session?
case "$1" in
--suspend)
if [ "$cmd_status" = "Running" ] && stringinstring "unix-" "$cmd_type"
then
echo "sessionid=$cmd_sessionid" | su - "$cmd_user" -c "$PATH_BIN/nxnode --suspend"
session_suspend $cmd_sessionid
fi
;;
--terminate)
#if stringinstring "unix-" "$cmd_type"
# then
echo "sessionid=$cmd_sessionid" | su - "$cmd_user" -c "$PATH_BIN/nxnode --terminate"
session_close $cmd_sessionid
# fi
;;
esac
done
}
cmd_send()
{
if [ "$1" = "--broadcast" ]
then
CMD_PARAMS=$(session_find_all)
[ -z "$CMD_PARAMS" ] && cmd_abort "Error: No running session could be found."
else
CMD_PARAMS=$(cmd_parse_3_params "$2")
[ -z "$CMD_PARAMS" ] && exit 1
fi
shift
shift
for i in $CMD_PARAMS;
do
CMDLINE=$(session_get_cmdline $i)
cmd_display=$(getparam display)
cmd_user=$(getparam userName)
cmd_type=$(getparam type)
cmd_status=$(getparam status)
# is it a "good" session?
if [ "$cmd_status" = "Running" ] && stringinstring "unix-" "$cmd_type"
then
su - "$cmd_user" -c "$PATH_BIN/nxclient --dialog ok --caption \"NX Administrator Message\" --message \"$@\" --noautokill
-display \":$cmd_display\"" &
disown $!
fi
done
#nxnode_start --send "$CMD_PARAMS"
}
#
# user mode available functions
#
if [ $UID -ne 0 ]
then
[ "$1" != "--passwd" ] && cmd_usage
cmd_user_passwd
exit 0
fi
#
# root mode available functions
#
[ $# -lt 1 ] && cmd_usage "root"
[ "$1" = "--help" ] && cmd_usage "root"
if [ "$1" = "--version" ]
then
echo "NXSERVER - Version $NX_VERSION $NX_LICENSE"
exit 0
fi
CMD=$1
echo "NX> 100 NXSERVER - Version $NX_VERSION $NX_LICENSE"
case $CMD in
#
# User functions ...
#
--passwd)
cmd_passwd "$@"
;;
--adduser|--useradd)
cmd_adduser "$@"
;;
--deluser|--userdel)
cmd_deluser "$@"
;;
--listuser|--userlist)
cmd_listuser
;;
--start)
cmd_start
;;
--stop)
cmd_stop
;;
--status)
cmd_status
;;
--restart)
cmd_restart
;;
--list)
cmd_list "$@"
;;
--list-suspended)
cmd_list_suspended "$@"
;;
--history)
cmd_history "$@"
;;
--terminate|--suspend)
cmd_terminate "$@"
;;
--cleanup)
cmd_terminate "--terminate" "*"
;;
--send|--broadcast)
cmd_send "$@"
;;
*)
cmd_abort "Error: Function $CMD not implemented yet."
esac
echo "NX> 999 Bye"
syntax highlighted by Code2HTML, v. 0.9.1