5

I have a Xubuntu 14.04 Server here that runs xrdp to have a couple of users connect to it.
Now there's one problem: users who access this server via RDP from Windows thin clients often use the "X" to close the RDP session (therefore disconnect but not logout).

I know there are some options in sesman.ini to deal with that kind of behaviour, but as the manpage says, those options are currently ignored (and have been for years).
The options which would solve my problems are:
KillDisconnected
DisconnectedTimeLimit
IdleTimeLimit

Now I need to hack something that deals with disconnected sessions. My first thought was to just kill all remote users who are disconnected - but I don't know how to get that information which sessions are disconnected.

So... how do I find disconnected sessions?
Or: is there already any preferred way to deal with disconnected sessions?

wullxz
  • 1,023
  • 2
  • 15
  • 29

4 Answers4

4

Here is a way to obtain a list of disconnected xrdp sessions. It relies on the fact that the xrdp server is, in normal X session manager usage, the only client that establishes a TCP connection to the Xvnc X Window System display server. When an xrdp session is active, the associated Xvnc display server has two TCP connections, one in the ESTABLISHED state, and the other in the LISTEN state. That looks something like this using the lsof(1) program.

$ sudo lsof  -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
Xvnc    1625 guest    1u  IPv4 252910      0t0  TCP 127.0.0.1:5910 (LISTEN)
Xvnc    1625 guest    9u  IPv4 261226      0t0  TCP 127.0.0.1:5910->127.0.0.1:35242 (ESTABLISHED)

If the user of the remote session abandons it by closing the RDP connection (or, in the case of an Apache Guacamole RDP session, by closing the browser window) it looks something like this:

COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
Xvnc    1625 guest    1u  IPv4 252910      0t0  TCP 127.0.0.1:5910 (LISTEN)

Notice there's no ESTABLISHED connection on this disconnected Xvnc display server process. So, any Xvnc process that's only listening is a disconnected session.

Here's a shell script (named lsdisconnected) that displays the PID and USER for each disconnected remote session. It uses lsof(1) and gawk(1) to implement the connection logic.

#!/bin/bash
sudo lsof -FRgpLT -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999  |
gawk '
      match($0,/^p([0-9]+)/,       p) {pid = p[1]; pids[pid]=0; } ;
      match($0,/^L([A-Za-z0-9]+)/, p) {user[pid] = p[1]; } ;
      /TST=LISTEN/ {pids[pid] = pids[pid] - 1 ;};
      /TST=ESTABLISHED/{pids[pid] = pids[pid] + 1};
      END {
          for (pid in pids){
              if (pids[pid] < 0) {
                  print pid, user[pid];
              }
          }};
     '

This is a handy way to find disconnected remote desktop sessions; it works immediately upon disconnection, without needing to use an idle time.

For those who may not be familiar with lsof(1) here's an explanation of the command line parameters in this example.

  • -b -w avoids lsof kernel waits. They're not needed here.
  • -n avoids DNS lookups for hostnames.
  • -c /^Xvnc$/b looks for processes with the exact command name Xvnc, using a regex.
  • -a tells lsof to use AND, not OR, when filtering.
  • -iTCP:5900-5999 filters by TCP ports numbered 5900 - 5999, the ones used for X display connections.)
O. Jones
  • 233
  • 3
  • 6
3

I finally found a solution to this.
First of all, I had to install a small program called xprintidle:

sudo apt-get install xprintidle

After that I wrote a small bash script that first fetches all displayes used by Xvnc and xrdp and then checks those display sessions if they've been idle for more than a number of minutes:

#!/bin/bash

displays=`ps aux | grep Xvnc | grep -v 'grep\|sed' | sed -r 's|.*(Xvnc :[0-9]*).*|\1|' | cut -d' ' -f 2`
limit=180


date
echo "Checking for inactive sessions!"
while read -r d; do
    export DISPLAY=$d
    idle=`xprintidle`
    idleMins=$(($idle/1000/60))
    if [[ $idleMins -gt $limit ]]; then
        echo "WARN Display $d is logged in for longer than ${limit}min (${idleMins}m)"
    else
        echo "INFO Display $d is still ok (${idleMins}m)"
    fi  
done <<< "$displays"
wullxz
  • 1,023
  • 2
  • 15
  • 29
  • I took the next step to automatically kill sessions which were idle longer than 30 minutes: https://gist.github.com/mnebuerquo/e825530cf2bfd363b6c3cd82fe697d94 – Mnebuerquo Jun 24 '16 at 11:42
1

Old post, but I have the same problem : parameters KillDisconnected/DisconnectedTimeLimit/IdleTimeLimit in sesman.ini are inactive with Xvnc.

A simple solution is adding these parameters to the sesman.ini in [Xvnc] paragraph :

paramX=-MaxDisconnectionTime
paramX=3600

(with X depend on how many paramters are already defined)

With that, disconnected sessions are automaticly killed after 1 hour.

david
  • 11
  • 1
1

Thanks for the lsof-fu! Detecting 'dead' Xvnc sessions has been a long standing problem with Xrdp. I've incorporated O. Jones's code into a shell script which can be loaded at boot and run from screen to clean up dead Xvnc processes left behind when a user closes their RDP window, or the connection drops our for whatever reason. I've never found a way with Xrdp to deal with this so this lsof code is perfect.

#!/bin/bash

#
# this could be launched from rc.local via screen
#   echo '/usr/bin/screen -dmS xrdp_cleanup /root/bin/xrdp_cleanup_discod_sessions' | at now
#
while [ 1 ]; do
   # loop through all listening Xvnc processes and make sure there's an established connection
   for pid in `lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep L[I]STEN | awk '{print $2};'`; do

      # new sessions may take a second or two on busy systems. 
      # wait for new LISTEN sessions to be become established. this also acts as a throttle for the loop
      sleep 2

      # get user for the established session
      euser=`lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep L[I]STEN | grep "$pid" | awk '{print $3};'`
      esta=`lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep E[S]TABLISHED | grep "$pid" | awk '{print $2};'`

      test -z "$euser" && echo "Unable to find user in lsof output!"

      if [ -n "$esta" ]; then
         # regular status update
         echo "user $euser has an established sesson on pid $pid"
      else
         isrunning="yes"

         # make sure the process is killed. keep trying.
         while [ -n "$isrunning" ]; do
            echo "Established session for user $euser is gone. killing pid $pid.."
            kill $pid
            sleep 1
            isrunning=`ps -ef | grep $pid | grep -v grep`
            test -z "$isrunning" && echo "$pid killed OK"
         done
      fi
   done
done
Server Fault
  • 3,454
  • 7
  • 48
  • 88