15 Mar 2007

Synergy - two screens, two OSes

At work I need both Windows and Linux. So I've had a KVM switchbox from blackbox to easily switch between Windows and Linux. The KVM switch is showing it's age, since the display has lately become somewhat fuzzy. Recently I received two new LCD screens, and I decided to get rid of the old fuzzy KVM-switch. I wanted to try out Synergy - which enables two or more screens to be connected to different computers using one mouse and keyboard.

It relies on a client/master software to be installed on each computer. The computer where the mouse and keyboard are (physically) connected are the master. The client(s) then talks to the master over the network. When my mouse pointer leaves my Windows screen, it enters my Linux screen to the right seamlessly. The master then sends all mouse and keyboard signals to the correct host. The keyboard follow the mouse, so when my mouse pointer is on Linux so is my keyboard.

You'll get some nice, and a little bizarre, properties like cut'n'paste between Linux and Windows(!). Another nice feature is the ability to "lock" onto one screen by pressing "Scroll Lock".

Installation is a breeze. On Windows it's just click and install. On Linux, synergy can be found in both Fedora and Debian/Ubuntu packet repositories:

 $ apt-get install synergy

My keyboard and mouse are connected to my Widows computer, so that one is master. Linux is client. First I configure Windows and determine where my screens are (Windows to the left, Linux to the right). Then it's just to fire up synergy:

$ synergyc -f -n lin1016 192.168.3.125
INFO: synergyc.cpp,716: Synergy client 1.3.1 on Linux 2.6.18-1.2239.fc5 #1 Fri Nov 10 13:04:06 EST 2006 i686
DEBUG: CXWindowsScreen.cpp,840: XOpenDisplay(":0.0")
DEBUG: CXWindowsScreenSaver.cpp,339: xscreensaver window: 0x00a00001
DEBUG: CXWindowsScreen.cpp,110: screen shape: 0,0 1280x1024
DEBUG: CXWindowsScreen.cpp,111: window is 0x01400004
DEBUG: CScreen.cpp,38: opened display
NOTE: synergyc.cpp,330: started client

Debug messages when leaving and entering Linux:

INFO: CScreen.cpp,116: leaving screen
DEBUG: CXWindowsClipboard.cpp,313: open clipboard 1
DEBUG: CXWindowsClipboard.cpp,348: close clipboard 1
INFO: CScreen.cpp,98: entering screen

Debug messages when leaving Linux, copy something to the Windows clipboard:

INFO: CScreen.cpp,116: leaving screen
DEBUG: CXWindowsClipboard.cpp,313: open clipboard 1
DEBUG: CXWindowsClipboard.cpp,493: ICCCM fill clipboard 1
DEBUG: CXWindowsClipboard.cpp,512:   available targets: TIMESTAMP (386), TEXT (406),
COMPOUND_TEXT (260), STRING (31), TARGETS (384), LENGTH (468), DELETE (407), FILE_NAME (471),
CHARACTER_POSITION (472), LINE_NUMBER (473), COLUMN_NUMBER (474), OWNER_OS (467),
HOST_NAME (475), USER (463), CLASS (464), NAME (465), ATOM (4), INTEGER (19)
DEBUG: CXWindowsClipboard.cpp,555:   added format 0 for target STRING (31) (6 bytes)
DEBUG: CXWindowsClipboard.cpp,348: close clipboard 1

But there is one serious problem with this setup. Every keystroke are transmitted unencrypted between the master and client! So a potential eavesdropper could easily sniff all my password entered on Linux. To prevent that, we can tunnel all synergy traffic through SSH.

So, I download Windows version of OpenSSH server from http://sshwindows.sourceforge.net/. It hasn't been updated in a while, but works nicely here on my Win2K computer. I make sure SSH server automatically starts at boot and tries to log in.

Hm. No login? Time to read some documentation. Ok, here we go: Since SSH are based on Cygwin, it needs to extract user data from AD:

  C:\Program Files\OpenSSH\bin>mkgroup -d ..\etc\group
  C:\Program Files\OpenSSH\bin>mkpasswd -d ..\etc\passwd

Try again. Much better:

$ ssh 192.168.3.125

                            ****USAGE WARNING****

This is a private computer system. This computer system, including all
related equipment, networks, and network devices (specifically including
Internet access) are provided only for authorized use. This computer system
may be monitored for all lawful purposes, including to ensure that its use
is authorized, for management of the system, to facilitate protection against
unauthorized access, and to verify security procedures, survivability, and
operational security. Monitoring includes active attacks by authorized entities
to test or verify the security of this system. During monitoring, information
may be examined, recorded, copied and used for authorized purposes. All
information, including personal information, placed or sent over this system
may be monitored.

Use of this computer system, authorized or unauthorized, constitutes consent
to monitoring of this system. Unauthorized use may subject you to criminal
prosecution. Evidence of unauthorized use collected during monitoring may be
used for administrative, criminal, or other adverse action. Use of this system
constitutes consent to monitoring for these purposes.


nblks1@192.168.3.125's password:
CMD.EXE was started with '\\XXXXXX\nblks1$' as the current directory path. 
UNC paths are not supported.  Defaulting to Windows directory.
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

C:\WINNT>

Great. Now it's just to set up a tunnel and tell synergy to connect to localhost:

$ ssh -f -N -L 24800:192.168.3.125:24800 192.168.3.125
$ synergyc -n lin1016 localhost
INFO: synergyc.cpp,716: Synergy client 1.3.1 on Linux 2.6.18-1.2239.fc5 #1 Fri Nov 10 13:04:06 EST 2006 i686
DEBUG: CXWindowsScreen.cpp,840: XOpenDisplay(":0.0")
DEBUG: CXWindowsScreenSaver.cpp,339: xscreensaver window: 0x00a00001
DEBUG: CXWindowsScreen.cpp,110: screen shape: 0,0 1280x1024
DEBUG: CXWindowsScreen.cpp,111: window is 0x01400004
DEBUG: CScreen.cpp,38: opened display
NOTE: synergyc.cpp,330: started client

I've enabled both OpenSSH and Synergy to start automatically at boot on Windows. But since I'm tunneling through SSH and other users may use this workspace (and desktops), there no easy way of enabling Synergy automatic without manually typing password. One solution is to use a shared user with ssh-certificates, but neither I nor the security policy permits that. Instead I create a small script that fires up the ssh tunnel and synergy at login. Since it's called from ".xsession" it do need a keyboard on my Linux to type the SSH password - but I can live with that:

$ cat ~/bin/syn.sh
#/bin/sh
xhost +localhost
echo "Setting up ssh-tunnel"
ssh -f -N -L 24800:192.168.3.125:24800 192.168.3.125
echo "Starting synergy"
synergyc -n lin1016 localhost
echo "Remember to shut down the ssh tunnel before you log out!"
sleep 5
$ cat ~/.xsession
...
~/bin/syn.sh
...

12 Mar 2007

Log and disabling Ctrl+Alt+Del

In a server rack, one console are usually shared by several different servers. One rack may contain servers belonging to different departments. One of those departments are usually doomed to have one trigger happy sysadmin. This sysadmin may reboot the wrong server accidentally using Ctrl+Alt+Del. Ever been exposed to one of those? Luckily, it easy to disable Ctrl+Alt+Del on Linux. On Linux, "/etc/inittab" defines what should be done when Ctrl+Alt+Del are pressed. Usually, the file contains something like this:

$ cat /etc/inittab
...
# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
...

So, in runlevel 1-5, the command "shutdown" is to be executed when someone press Ctrl+Alt+Del. It could be changed to anything we'd like. We would like to log the incident and issue a warning to the user on the console:

ca:12345:ctrlaltdel:/usr/bin/logger -t init -s "Ctrl+Alt+Del pressed on console. Use normal shutdown routines."

When someone now tries the "three finger salute", they'll be told to use "normal shutdown routines". The incident are also logged:

# tail -1 /var/log/messages
Mar 12 20:50:19 titan INIT: Ctrl+Alt+Del pressed on console. Use normal shutdown routines.

Update! - Newer Ubuntu uses Upstart and things are a little different. You don't define what action to be taken in /etc/inittab (it no longer exists), but we have to modify a file in /etc/event.d/:

# cat /etc/event.d/control-alt-delete
# control-alt-delete - emergency keypress handling
#
# This task is run whenever the Control-Alt-Delete key combination
# is pressed.  Usually used to shut down the machine.

start on control-alt-delete

#exec /sbin/shutdown -r now "Control-Alt-Delete pressed"
/usr/bin/logger -t init -s "Ctrl+Alt+Del pressed on console. Use normal shutdown routines."

5 Mar 2007

Sort pictures based on Exif date

Recently, I bumped into a problem: I had received pictures from the same event from three different sources (cameras). How could I sort these based on when the pictures were taken?

A small Perl script are born to the rescue. The program "jhead" dumps Exif data contained in JPEG images. Running jhead on a image without options gives:

jhead IMG_1195.JPG
File name : IMG_1195.JPG
File size : 2988387 bytes
File date : 2007:03:04 15:37:34
Camera make : Canon
Camera model : Canon DIGITAL IXUS 800 IS
Date/Time : 2007:02:22 19:17:14
Resolution : 2816 x 2112
Flash used : Yes (auto)
Focal length : 5.8mm (35mm equivalent: 37mm)
CCD width : 5.72mm
Exposure time: 0.017 s (1/60)
Aperture : f/2.8
Whitebalance : Auto
Metering Mode: matrix

The "Date/Time" header gives the time stamp. Renaming the file to the date, would make it easy to sort the pictures in time based on filename:

IMG_1195.JPG --> 20070222_191714.jpg

Instead of manually renaming a couple of hundred images, Perl can do the job:

#!/usr/bin/perl -w
#
# filename: exif_date_sort.pl
#
# Small utility that renames pictures based on the Exif date.
#
# Date: Sun Mar 4 19:13:42 CET 2007
#
# Lars Strand
#

use strict;
use File::Glob qw(:globally :nocase);
use File::Copy;

die "Usage: $0 PATH" if $#ARGV < 0; 

while (@ARGV) { 
   my @filelist = glob($ARGV[0]."*.jpg"); 
   foreach my $file (@filelist) { 
       for my $line (`jhead "$file"`) { 
           if ($line =~ /^Date\/Time\s*:\s*(\d+):(\d+):(\d+)\s*(\d+):(\d+):(\d+)/) { 
              print "$file --> $1$2$3_$4$5$6.jpg\n";
              copy("$file", "$1$2$3_$4$5$6.jpg") or die "Error: Copy failed: $!";
           }
       }
  }
  shift @ARGV;
}

The script takes one or more directories as argument. Every JPG file that has a Exif date header, are copied to a new "date-filename".

Running it gives the following output:

~/exif_date_sort.pl 200702-Veggli/
200702-Veggli/IMG_1196.JPG --> 20070222_194000.jpg
200702-Veggli/IMG_1197.JPG --> 20070222_194007.jpg
200702-Veggli/IMG_1198.JPG --> 20070222_194012.jpg
200702-Veggli/IMG_1200.JPG --> 20070222_194437.jpg
200702-Veggli/IMG_1201.JPG --> 20070222_194443.jpg
200702-Veggli/IMG_1202.JPG --> 20070222_194643.jpg
200702-Veggli/IMG_1203.JPG --> 20070222_194844.jpg
...

.. or, as I'll learned later, you can just alias jhead to:

jhead-iso is aliased to `jhead -n%Y-%m-%d_%H:%M:%S'