Tuesday, April 3, 2012

Case Study: EucaSchool Part 2 - Using Screen

In my last post I detailed the why on this project; this post will focus on the how.  Specifically this post will consolidate the various resources on the internet I culled to be able to set up screen to be used as a teaching tool.




We used a Ubuntu instance to demonstrate from, so these commands may be specific (apt-get, ufw etc.) however translation to another distro should be pretty easy.  Let's assume you have a Ubuntu image up and running and ready to be configured.   Install screen as root:
apt-get install screen
Next, let's test permissions for multiuser use of screen.  As root, enter the following:
root@host # screen -L -S learningsession
root@host # Ctrl+a :multiuser on
root@host # Ctrl+a :acladd UserA
root@host # Ctrl+a :aclchg UserA -w "#"
The above is from the primer lesson in screen located here. The idea is as root you start the session, pick UserA as your student account, and allow read-only access to the session for that user.  Now as UserA, log in and try to join the screen session via the following:
UserA@host # screen -x root/learningsession
If you're on Ubuntu at this point, you may see this error:
Must run suid root for multiuser support.
Change permissions on the screen binary:
root@host # chmod u+s /usr/bin/screen
Now you should be able to connect to root's screen session as a watcher.  I found that tip here (though in my Ubuntu screen's binary wasn't located at /usr/bin/screen.real, it was just /usr/bin/screen.)  Now if you join as that user you can try to enter a command and you will get an error saying you do not have write permissions.  We're ready to move on.

For UserA we're going to make it so they only get the screen session you set up when they log in and if they detach, they are logged out.  There's probably a thousand different ways to do this however I will only detail how to do this by manipulating the user's .bashrc and .profile files.

First, make sure the user's default shell is bash: edit /etc/passwd as root and verify it looks like this:
UserA:x:1000:1000:Test User,,,:/home/UserA:/bin/bash
The part we're interested in is making sure the last entry is /bin/bash.  Next in that user's account make sure there's a ~/.profile file that sources .bashrc:
~ $ cat .profile 
# ~/.profile: executed by Bourne-compatible login shells.

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi
Next, we add these two lines to the end of user's ~/.bashrc:
screen -x root/learningsession
exit
Now when that user logs in, that screen session will execute, and when that process ends the .bashrc file will exit the shell, ending the session.  Note: This is a very quick and dirty answer.  Best practices may be to set screen as the default login shell as well as constrict that user to a jailed session, but I won't use that method, specifically because I picked a name for my screen session and will reuse that name every time (ie. screen -S learningsession.) 

If you wanted you could now add the following to root's ~/.screenrc file so that the multiuser and read only permissions are automatically called for the student user.  Reference this page for specifics (note the common problems at the end.)  Example ~/.screenrc for root:
root: ~ $ cat .screenrc 
multiuser on
acladd UserA
aclchg UserA -w "#
Now any time root starts a screen session, it will be read-only available to UserA.  While not a desirable thing on a production machine in the wild, for a lab/training instance this is exactly what we would want.  Note: You can go one step further and alias a command in the .bashrc of root's account to automatically start the screen session with the correct name.  You could go one step further and add a line to .bashrc for root that not only checks for that screen if it is running, but starts it if it is not and joins root to the screen session.   For example, you could add this to root's .bashrc file:
LSCRN=($(screen -list | grep learningsession | awk -F"." '{print $2}'))
if [[ LSCRN == "learningsession" ]]; then
     screen -x $LRNSCRN;
else
     screen -L -c ~/.screenrc -S learningsession
fi
I actually haven't tested the above, but at the very minimum you can now set the password to UserA to anything you want, give the login credentials to your students and you're off to the races.  If you wanted to have a log session of what happened in screen, you'll find that log in root's home directory.  The "-L" flag on the screen command issued above has already told screen to log the session.

Important note: screen session logging won't log what happens inside another process.  For example, if you vi /etc/hosts in a demonstration, your changes inside the editor will not be logged but an execution of that command is.  If you are looking to log everything within the screen session for replay later, you'll want to use a screencasting/recording program to record your shell window and save that output for your static tutorial archive.

In my next post in this series I'll detail how to get your own irc server up and running with Pam/LDAP authentication for your student's accounts and tools you can use in your IRC channel to log your tutorial session for republication on a web page.

Finally, later on, I will demonstrate how to automate this process and build a Eucalyptus image to launch with these properties baked in: IRC server fully configured and ready to run, screen session at the ready and student account configured to only join a specific screen name.  The ultimate goal is to have a single command to launch an instance and be able to have users log in to IRC and the screen session (and only that) while you can demonstrate whatever topic you need to them.