The Great Laptop Email Solution

Laptops are cool. Email is cool. Unfortunately it took me a while to figure out how to make them cooperate. Here’s what I wanted to be able to do:

The first is trivial. I have a workstation (shostakovich) with a permanent Internet connection and a static IP address. Shostakovich handles my email for me. I can check my email from any computer that has a ’net connection and ssh (and hopefully no keystroke logger).

The second bullet presents the problem. Of course, just using webmail or ssh works fine when you have a network connection, but what if you want to write email while on an aeroplane, at the beach, using long-distance dialup, …? Clearly this rules out systems like webmail and ssh.

A Local Copy

It’s not at all hard to keep a local copy of any relevant email folders on my laptop. I happen to use Unison, although if it were just for email I might as well use rsync or some such. That takes care of reading my email whether or not I’m connected. Just don’t save outgoing emails to folders that are also delivery targets on the master copy.

Sending from the Dark Side of the Moon

Of course, any halfway competent MTA (I use Postfix) will happily queue your email for you, so you can write your mail in the software of your choice (which is, of course, Mutt), tell it to send, and the MUA will pass off your message to the MTA, which will happily queue it. Add a line to explicitly flush the MTA queue whenever the network comes up, and you’re done, right?

Wrong. You see, that would have worked before a few thousand morons decided that their personal financial gain was more important than the very existence of the Internet. Not surprisingly, silly prohibitions against vigilante justice wouldn’t save most spammers from a gruesome and well-deserved lynching if they were identified, so they tend to fake their return addresses. One nice way to do this is to use an open relay—a sort of transfer point that accepts email from non-authenticated sources. Pre-asshole, this was a nice friendly way to run a public service. Now, it’s a nice friendly way to help spammers.

The solution, roughly, is that your email must always be sent from a machine that has a static IP address. In the case of POP3 and IMAP servers, there’s usually a hack such that when you log in to the server to retrieve your email, it remembers your IP address for a few minutes, during which time it will act as a relay for outgoing email sent from your IP address. But if, as in my case, you want to have your workstation host your email, the POP3 server never finds out about your laptop’s IP address. Sure, if you had a POP3 server available you could log into it from your laptop and immediately log out without retrieving your email (lest email be delivered randomly to master or slave copies, causing filesystem synchronisation conflicts), but I rejected that solution because it seemed ugly.

Those Who Know History Are Doomed To Re-Use It

The solution is UUCP. Brilliant!

Before everyone had dedicated optical fiber running everywhere, much of the Internet was run over sporadic dialup links. Since users couldn’t tell when the machine they were logged in to was going to be connected to the machine they wanted to use, UUCP was born. It lets you queue files, and even commands, that will be sent to another machine at the next opportunity. Sound familiar?

So, I write an email on my laptop using Mutt. When I send it, Mutt passes it off to Postfix. Postfix doesn’t queue it, but immediately sends it on to UUCP (still on my laptop), which queues it for delivery to shostakovich. When next I connect, my network script flushes the UUCP queue, which means that the UUCP system on my laptop connects (via SSH) to the UUCP daemon on shostakovich and hands off the email. Shostakovich’s UUCP daemon immediately passes the message to its local Postfix daemon, which, as it is running on a computer with a static IP address and a valid DNS entry, is recognised worldwide as a legitimate email sender.

And my bizarre, trivial, pedantic, and annoying opinions flow forth!

The Devil

Obviously, both computers need UUCP installed, and I will assume that it’s installed as user uucp.

There is definitely a security problem here: it’s very hard to protect data against someone with physical access to the machine. So a determined thief could quite possibly get access to user uucp’s ssh private key (which is not password-protected), and then execute arbitrary commands as user uucp on shostakovich. Since the only thing I use uucp for is throwing jobs at Postfix, and all incoming connections are logged, everything is pretty well contained, but still…

I’ll refer to the workstation—the computer with the legitimate reverse-DNS record or generally the ability to send email—as the “server”, and the other machine—with ad-hoc connectivity—as the “laptop”.

Postfix

/etc/postfix/main.cf

Add or change the lines
relayhost = shostakovich.cs.colorado.edu
default_transport = uucp
This ensures that all non-local email that Postfix needs to deliver goes through UUCP to the relayhost. Of course, if you don’t change the name to your own relayhost, my SSH daemon will log a lot of failed login attempts.

/etc/postfix/master.cf

Make sure you have
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -z -a$sender - $nexthop!rmail ($recipient)
Tell the UUCP transport how to deliver (ie. using uux).

UUCP setup on the laptop

/etc/uucp/config

It’s not a bad idea to make sure that UUCP knows the name you’ve chosen for your laptop, so there’s no confusion when it logs in to the server. My laptop is named “bach”:
hostname bach

/etc/uucp/port

The important lines that you will need to add look something like this:
port SSH
    type pipe
    command /usr/bin/ssh -x -o batchmode=yes uucp@shostakovich.cs.colorado.edu

/etc/uucp/sys

This is the file that contains the UUCP options for each remote system, including the chat script: a list of challenges and the correct responses that make up a login conversation. Here’s mine:
protocol gvG
protocol-parameter G packet-size 1024
# protocol-parameter G window 7
protocol-parameter G short-packets

system shostakovich.cs.colorado.edu
       chat-timeout 60
       alias shostakovich
       time any
       port SSH
       protocol t
       chat ogin: bach ssword: 12345
Note the chat script. The login and password are not used to establish the ssh connection, but internally by UUCP. As such they’re just an extra level of security that interacts with /etc/uucp/passwd on the server:

UUCP setup on the server

/etc/uucp/passwd

You saw in the client’s /etc/uucp/sys that UUCP has its own idea of a password. Duplicate that here.
bach                    12345
Yup, that’s the password, in plaintext even. Scary, isn’t it? Fortunately, it’s not a password on a network port, so the seeming lack of security isn’t much of a problem (if you know otherwise, tell me!).

/etc/uucp/sys

This just needs to know about the node that will be connecting to it. My laptop’s name is bach, so I add:
system bach
        time any
        port SSH
        protocol t

SSH on the laptop

Recall that the whole world should be run over an SSH tunnel, since SSH is a reasonably secure single entry point.

There will be a user uucp on the laptop. The home directory, as always, can be called ~uucp; on my system that’s /var/spool/uucp.

Log in to the laptop as user uucp and create an ssh keypair in whatever flavour you like (say, ~uucp/.ssh/id_dsa.pub), without a password (just press Enter when it asks for a passphrase).

ssh uses host keys to protect against man-in-the-middle attacks. You need the server’s ssh host key in the laptop’s ~uucp/.ssh/known_hosts, and you get it there like this: log in as user uucp and run ssh shostakovich.cs.colorado.edu (ie. exactly the same hostname you used in uucp’s configuration). ssh will ask you to confirm the host key fingerprint, and when you do, it saves it for you. Thanks to Kevin Lyda for reminding me about this!

SSH on the server

Copy uucp’s ssh public key from the laptop to the server’s UUCP ssh directory (~uucp/.ssh/), renaming it authorized_keys or whatever your system uses (authorized_keys2 was popular for ssh2 keys on older systems). Now UUCP can log in from the laptop to the server without a password, but won’t run the right program yet. Prepend to the relevant authorized_keys line:
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="/usr/sbin/uucico -l"

Among things, this makes sure that the appropriate uucp process will in fact execute.

I leave it as an exercise to the reader to make sure that uucp on the server can’t get up to anything more serious than executing sendmail.

Testing it

Try writing an email on the laptop. If you’re offline, the command uustat -a should display a line indicating that something is sitting in the uucp queue. Go online and run
/usr/sbin/uucico --master --force --debug chat
and watch what happens in the UUCP debug log (on my system, /var/log/uucp/Debug). With any luck you will see the chat take place, after which running uustat -a on the laptop will not display any jobs anymore. Success! Success?

Odds and Ends

It’s nice to explicitly flush the UUCP queue whenever your laptop gets a network connection. The line you’re looking for is something akin to
/usr/sbin/uucico --master --force
I’ve done this with an “up” command in /etc/network/interfaces; your system configuration may vary.

Finally, send me an email from your laptop.