Ssh – recursively print all current remote shells

sshtrace

Is there a way to print out all of the local and remote shells I am currently in, recursively?

For example, on my local machine, I will ssh into another machine. From there, I may switch users (opening another shell). Then I ssh to my local machine again, etc. And to complicate matters, I'll generally have multiple tabs (and even windows) of shells, so I can't usually remember my trail for each one.

What I would like is to have each of those sessions print out in order where I am. Or at least what shell I will be kicked back into if I exit the current shell.

After a few days or weeks of having multiple shells open, I have no idea where I will be sent if I type in exit. Will my shell window close (because I'm at the 'root' shell)? Will I be kicked back to another server?

In other words, I'd like a trace of my SSH hops.

Best Answer

You could write a script that just walks up the process tree printing out unique usernames/pids/executables/whatever as it went up the list, stopping when it finally left the terminal. sshd usually starts listening on a TTY after it has already done the setuid() to the user so the earliest process connected to the TTY will be running as the user you logged in with.

Here's a Linux-specific Bash script version of the concept.

script output:

Simple sudo to root:

[root@ditirlns04 ~]# ./test.sh
Current User: 0
Previous UID: 504

UID 504 is how I logged into the box so it worked:

[root@ditirlns04 ~]# logname
jadavis6
[root@ditirlns04 ~]# id jadavis6
uid=504(jadavis6) gid=504(jadavis6) groups=504(jadavis6),16777216(enterprise admins),16777217(ncatsys),16777218(sms admins),16777219(domain admins),16777220(aggieanywhere),16777221(group policy creator owners),16777222(tlh-test),16777223(dba admins),16777224(domain controllers),16777225(cupsadmin),16777226(linuxusers),16777227(da admins),16777228(webdev),16777229(schema admins),16777230,16777231(changeauditor operators - ncat),16777232(configmgr remote control users),16777233(changeauditor administrators - ncat),16777234(telnetclients),16777235(denied rodc password replication group)

Same as above, only going through an intermediary user (i.e: logged in 504, sudo'd to root, sudo'd to regular UID of 501, then back to root):

[root@ditirlns04 ~]# ./test.sh
Current User: 0
Previous UID: 501
Previous UID: 0
Previous UID: 504
[root@ditirlns04 ~]#

So each UID transition is caught in reverse order that it happened in. If you need it in the same order, just put the script into a function where you tac the output:

[root@ditirlns04 ~]# ./test.sh | tac
Previous UID: 504
Previous UID: 0
Previous UID: 501
Current User: 0
[root@ditirlns04 ~]#

script body:

#!/bin/bash

currentPID=$$
currentUser=$(id -u)
currentTTY=$(awk '{print $7}' /proc/$$/stat)

echo "Current User: $currentUser"

while /bin/true; do

  parentPID=$(awk '{print $4}' /proc/$currentPID/stat)
  parentTTY=$(awk '{print $7}' /proc/$currentPID/stat)

  if [ $parentTTY -ne $currentTTY ]; then
     break
  fi

  parentUser=$(awk '/^Uid:/ {print $2}' /proc/$currentPID/status)

  if [[ "x$parentUser" != "x$currentUser" ]]; then
     echo "Previous UID: $parentUser"
  fi

  currentPID=$parentPID
  currentUser=$parentUser

done

Basically, it just makes use of the per-pid stat and status files. You could make more platform independent versions wrapping around ps output, but I don't trust parsing command output when the datum is readily available in a format meant to be parsed, so I went the procfs route.

Basically, any time it finds a new UID it prints it out. They're guaranteed to be in the same order the user sudo'd so it should effectively cover your entire login session on that machine. You should be able to easily modify the above to print PID's or command names instead if you want that, but usually people thinking in this area are more concerned with who they'll be running as rather than the shell program that will be running.

Related Question