Wednesday, December 26, 2012

Anatomy of a .screenrc

Having talked about GNU Screen in most of my previous posts, I wanted to cover my .screenrc configuration file. The config file is relatively short and simple.
startup_message off
vbell off
vbellwait 0
defscrollback 8192
defflow off

hardstatus alwayslastline "%-w%{= BW}%50>%n %t%{-}%+w%<"

escape ^\\
idle 1800 lockscreen
I will now break it down:
startup_message off
No big surprise, this turns off the GNU Screen Welcome Message.
vbell off
vbellwait 0
Disable the visual bell flash and status line.
defscrollback 8192
The default number of lines of scrollback is 100, way way too low. Sometimes 8192 is too low for me, but this does affect memory usage.
defflow off
Turn off screen's flow control, always messes me up.
hardstatus alwayslastline "%-w%{= BW}%50>%n %t%{-}%+w%<"
Change the last line of the display to a status line containing a partial list of windows, centered around the window you are on. Do this in a color that I don't find completely awful. Highlight the window that is selected. You can get all fancy and put system information, time/data, etc. in the status line, but I am content with a boiled down list of my windows.
escape ^\\
This is the Holy Grail line that messes me up if it is missing. The default command character for Screen is Ctl-a. For those use to GNY Readline/Bash key bindings, Ctl-a brings you to the beginning of the line, I use this extensively. In my search for an appropriate alternate key, I tried many and finally settled on Ctl-\. This does still have the issue that the default binding for Ctl-\ is the Quit character in terminals. So if you do not have GNU Screen running and hit Ctl-\, you will likely kill your foreground process. This can be combated with 'stty quit undef' but often if you aren't in a screen session it is because you are on a console, or using a terminal on a machine that isn't your home, in other words the stty command isn't going to be in your startup files and you are going to kill your foreground process, hopefully it doesn't cause too big of a problem.
idle 1800 lockscreen
You don't want all of your shells sitting around unlocked when you run to lunch do you? Do you sometimes forget to send that lockscreen command on your own (C-\ C-x for me or C-a C-x by default), this will automatically lock the screen after 30 minutes.

Wednesday, December 19, 2012

Privileged redirection with sudo

It is sometimes useful to execute something via sudo and use shell redirection that also needs to happen via sudo. This can be accomplished in a number of ways, some better (IMO) than others. The problem:
sudo cat foo > bar
The "cat foo" portion is executed as root, the "> bar" is executed as the original user. The first option is to execute a shell as the privileged user, and then execute the commands.
sudo -s
cat foo > bar
The downside of this is that an audit trail of commands executed with privilege is lost. To maintain an audit trail, each command has to be individually executed via sudo. But if both the command and the redirect need to happen as root, it can be done in two manners:
sudo sh -c "cat foo > bar"
sudo cat foo | tee sudo bar
I prefer the first method, it will create a single entry in the audit trail and seems more elegant.

Monday, December 17, 2012

Reconnecting to Screen

As I have previously mentioned, I use GNU Screen a lot. The most typical way I use it is via a PuTTY ssh session from Windows. In these cases, I have a PuTTY profile, that gets rid of scroll bars, and automatically reconnects to screen using 'screen -x'

Unfortunately, 'screen -x' does not start a screen session if there isn't one available. This isn't a problem except when I reboot the box that hosts my screen sessions, and then because of two factor authentication, I have to bumble around (ssh in, start screen, and then connect with the correct PuTTY profile, etc).

A simple solution to this would be to add screen to your crontab with @reboot but the easy solution is not seemless. Specifically, on Ubuntu the default /bin/sh is 'dash'. When cron executes dash, no TTY is allocated which causes screen to fail. So try making your crontab something like:
@reboot         screen -d -m 1> /dev/null 2>&1

Wednesday, December 12, 2012

Scripting to reduce repetition.

There are things, simple things, that I don't know how people who can't write a script deal with. For example, setting ID3v2 tags on 100+ mp3s that compose an audiobook so that they sort correctly, etc. It is a very simple exercise using bash to pull this off, but by hand it seems like a pain.

AUTH="Jim Butcher"
TITL="Cursors Fury"

for x in `find . -name \*.mp3 |sort`
TEMPY=`printf "%03d" $Y`
id3v2 -a "$AUTH" -A "$TITL" -t "$TITL $TEMPY" -T $Y $x
Y=`expr $Y + 1`
Do the filenames happen to have spaces in them? Possibly the 'rename' command will help out.
rename 's/ /_/g'

Monday, December 10, 2012

GNU Screen and many ssh windows

I use GNU Screen extensively as a terminal multiplexor.  From my Windows desktop, I use PuTTY to connect to a linux box and run screen in that terminal.  I then use that single terminal to open ssh sessions to various machines.  After a dozen windows, it can be difficult to pick the correct window out of the list even if you are naming your screen windows.  So I use the following script (screenssh) to execute all of my ssh sessions:


if [ `ps waux |grep "ssh $1" | grep -v screenssh | grep -v grep |wc -l` -gt 0 ] ; then

    echo -n "There is an existing session to $1, do you want to attempt to select it? "

    read YN

    case $YN in

        [yY] | [yY][Ee][Ss] )

            echo "Selecting first $1"

            screen -X select $1



        * )

            echo Starting new screen window.



screen -X screen -t $1 ssh $1

Because I am a fiend with the tab button in terminals running Bash, I also want tab completion for 'screenssh' similar to 'ssh'.  So my .bashrc has the following in it:
if [ -f /etc/bash_completion ]; then
    source /etc/bash_completion
    source /usr/share/bash-completion/completions/ssh
    complete -F _ssh screenssh

Using libpam-google-authenticator with a Hardware token (C200).

We have started using libpam-google-authenticator to implement two factor authentication for our Linux servers accessed via SSH.  We have a number of users who are resistant to the usage of a software token such as the Google Authenticator app available for smartphones.

Google doesn't seem to provide a whole lot of information on how to use existing OATH OTP hardware tokens with libpam-google-authenticator, so I dug in on my own.

  1. Acquire a hardware token.  I saw some information online that the Gooze C200 token might be a good candidate, so I purchased one from
    Note: You need to get the C200 time based token.
  2. While you are waiting for your package, install libpam-google-authenticator, configure and test it using the software token.  
  3. The first hurdle you will encounter is that the C200 seed (Gooze will provide the seed in a variety of ways including printed on paper with the token) is in HEX, libpam-google-authenticator requires a seed in Base32.  So you need to convert it, either whip out your calculator or head over to:
  4. Edit the ~/.google_authenticator file and input your base32 seed as the first line, removing the existing seed.
  5. At this point, rejoice, you will have locked yourself out of your account.  After you much digging, you may find out that the C200 hardware token as a Step Size of 60 seconds instead of the 30 seconds used by the software token.  A patch has been supplied to Google Code that will make the Step size configurable, it is available at:
  6. How you apply, compile, and install the modified libpam-google-authenticator will vary depending on distribution, the following should work on Debian based systems.
  7. Get the source using 'apt-get source libpam-google-authenticator'
  8. Get the build-deps using 'apt-get build-dep libpam-google-authenticator'
  9. Copy the patch from above into the build tree at debian/patches, remove the first 24 lines up to
    diff --git a/libpam/pam_google_authenticator.c
  10. Modify debian/patches/series to apply the patch.  
  11. Build package with 'dpkg-buildpackage'
  12. Install newly built package with dpkg -i.
  13. Add a configuration option with the other options:
  14. Test.