Mail ssh Setup

From Wiki99

Jump to: navigation, search

↑ Computers ↑
← prev: Mail postfix and IMAP Setup next: Mail SSL Setup →


Contents

Introduction to Setting up ssh

We now want to set up Mail.app on our other computers that will talk to this computer to send mail and receive mail. But before we can do that, we have to set up the ssh tunnels that each computer will use to talk to our server.

Command-line ssh

Let's get a feel for ssh.
Go to some other computer that you want to use to access your server. In a Terminal window on that computer (which I will call your portable), type

ssh username@10.0.1.201

(Of course you will use whatever IP address you set for your server when we configured IP addresses on the LAN some pages back.)

There will be a brief pause, then you will be asked for the password for user username on 10.0.1.201. Type it in, and now you are connected to 10.0.1.201 and you can do all the usual command line things like ls or cd or cat. Now type exit to kill the connection.

Something interesting happened in all this that you didn't see and probably didn't think about. Consider what happened when you were asked for your password. It was a program running on your portable that asked for your password, the password for your account on the server. At this point the portable knows the password for your account on the server. The server also knows that password. But we can't just send that password over the network to the server so that the server can look at it, say "yes it's correct" and allow the portable to connect to it! As we've mentioned many times, sending passwords over the network is a bad idea. So what we want to happen is for the server to be convinced that the portable knows the same password that it, the server knows, but without either of them sending the password over the network. This might seem impossible, but it's not, just a little complicated and not relevant to our discussion. Read about challenge-response authentication if you are interested in how this is done.

After the password issues are handled, subsequent traffic between the two computers is now encrypted so that anyone else reading the packets can not learn anything useful from them.

ssh without passwords

So now you can use ssh to connect to your server using the command line. However a problem with this is that you had to type in a password. We want to use ssh to move mail data between the server and our portable, but we don't want to be typing in passwords every time this happens.

Ssh has a way to deal with this using a concept called public-key cryptography. The idea is that you use a program to create two file, one called your private key and one called your public key. If a computer which has your private key stored on it tries to contact a server with your public key stored on it, then through some complicated shenanigans the server can use the public key to verify that the computer contacting it is who it claims to be, without any passwords having to be exchanged.

Let's see this in action. First of all, on your portable type

ssh-keygen -t dsa

The computer will now think for about a minute, doing various complicated mathematics, and then will ask you

Enter file in which to save the key (/Users/mjh/.ssh/id_dsa):

Just hit return at this point. Now you will be asked for a passphrase. Again just hit return; we don't need a passphrase for what we are doing.

At this point we now have two files, called /Users/mjh/.ssh/id_dsa and /Users/mjh/.ssh/id_dsa.pub which, if you cat them, look like they are filled with random garbage. You can freely give out the one called id_dsa.pub (the pub stands for public), but you should treat the one called id_dsa like a password and not give it out to anyone.

We now need to put the public key onto the server. We can copy it over using the command scp which is like cp only it works over the network. Type

scp ~/.ssh/id_dsa.pub username@10.0.1.201:~/.ssh/authorized_keys

You will be asked for your password (on the server, to prove that you really are the person you claim to be and have permission to write files on the server) and the file will be copied over. Note that on the server the file id_dsa.pub is to be stored as a file called authorized_keys. This file can have other ssh public keys added to it, a new public key for each computer that wants to connect to it. If you want to add more public keys to this file then, obviously, you need to copy the public key to the server using a name on the server that is not ~/.ssh/authorized_keys, and then cat the public key file to the end of authorized_keys.

It would be really nice if Apple integrated the handling of ssh public keys, private keys and other paraphernalia with Keychain.app giving us a nice GUI for all this, but that hasn't happened yet.

NOTE
The editor pico is pretty stupid about handling long lines of text, lines that wrap in the terminal window.
The file authorized_keys includes such long lines.
If you need to edit this file manually, use an editor that understands long lines, not pico.

The effect of copying a public key into the ~/.ssh/authorized_keys file is that when an ssh connection starts, the server will trust (and not ask for the password of) a computer connecting to it that has the id_dsa file, the private key that was created at the same time as the public key. That's why the id_dsa is like a password that you must keep secret.

So let's make sure this worked. On your portable once again type in

ssh username@10.0.1.201

Now after a short pause you should be logged in automatically, without being asked for your password.

Good, we now have ssh set up so that it works without passwords.

Set up xinetd to use ssh tunnels for ports 25 and 143

Now we have to set things up so that when, on the portable, Mail.app connects to local port 25 (the smtp port), that traffic gets encrypted, sent over the network to the server, decrypted on the server and written locally to the server's port 25. Likewise for port 143 (the imap port).

This can be done in two ways; just as we discussed when setting up binc imap on the server, the old-style way, still used on most unix systems, uses xinetd , while the new preferred way for MacOS X uses launchd.

NOTE: Just as before, we will give an in-depth discussion based on xinetd, but don't create or type in these files; we will follow this by giving the launchd equivalents of the files.

xinetd

On the client (any client we wish to be able to communicate with our server to send or receive email) in the directory /etc/xinetd.d we are going to create two files, one to handle port 25 and one to handle port 143.

xinetd config file for port 25

Let's create the first one. In terminal type

cd /etc/xinetd.d
sudo pico smtp_via_ssh

The exact name of the files you create doesn't matter, but the name I have used above is fairly descriptive. If you are using pico and not some other editor you prefer like vi or emacs, make the terminal window you are typing into as wide as possible. Pico does some strange things with lines of text that are longer than the window width, and that may confuse you if you don't know pico well, so best to avoid the problem by using a wide window. Using pico, type in (or copy and paste)

service smtp
{
disable = no
only_from = localhost
socket_type = stream
wait = no
groups = yes
user = your_username_on_the_client
server = /usr/bin/ssh
server_args = your_username_on_the_server@bluecloud.com -c arcfour -C -q nc localhost 25
}

Replace your_username_on_the_client and your_username_on_the_server@bluecloud.com as appropriate. Once you've typed this in, (if using pico) hit control-O to save your text then control-X to quit.

What does this mean?

service smtp

The first line says service smtp. This means that xinetd will listen on the smtp port for packets, and when a packet comes in, it will do something with it.

How does xinetd know that the smtp port equals port 25?
It looks in /etc/services which lists a ton of ports, most of which you've never heard of and which are obsolete, and the standard services they are used for.

server

What does xinetd do when packets reach port 25?
It runs the program listed in the server line (which is ssh), with the arguments listed in the line below, and feeds the traffic coming in through port 25 to said program via stdin.

server_args

What are the arguments to ssh?
The first argument tells ssh to connect to your server, eg bluecloud.com, as your_username_on_the_server.
The -c blowfish argument tells ssh to use the arcfour encryption algorithm which is faster than triple-DES, the default ssh encryption algorithm, but still secure.
Of the algorithms provided by ssh, the fastest is arcfour, followed by blowfish at about half the speed, and then by aes and cast which are slightly slower than blowfish, with 3des as the slowest.

As an interesting aside, ssh also uses different so-called message digest algorithms, which validate that your encrypted data was not modified by some third party while it was travelling over the internet. There are two different digest algorithms offered, md5 and sha, but the default, md5, is faster than sha, so there's no reason for us to tell ssh to use a diffent digest algorithm.

The -C flag tells ssh to use compression. It's up to you whether to use this flag or not. When connecting to your server at home, where you are using ethernet or fast wifi it possibly slows things down some tiny amount, since the compression takes a small amount of time, whereas the network is so fast that sending more data over it is not a problem. On the other hand, if you are out somewhere out of the house, sucking down your mail over the public internet, in the worst case scenario travelling somewhere where you might even be using a modem, this flag helps a lot. My opinion is that I'd rather have it always on rather than try to remember to switch it on when I happen to be connecting via a slow internet connection.
The -q tells rsync to be quiet, ie not to report minor warnings. Reporting warnings is pointless in this case because there is no user interface set up to display them to you, and the warnings get passed on to the smtp server which treats them as an error, your connection fails for no obvious reason, and life sucks.

Finally nc localhost 25 describes what happens to the data after ssh decrypts it on the server. ssh will feed the decrypted data to a program called nc. nc is short for net cat, ie something that acts like the standard cat program, but targetted at TCP/IP. nc is a program that simply copies what it is fed through stdin to some port on some server. The server we choose to send it to is localhost, and the port we send it to is port 25, the smtp port.

In general for ssh, the first argument in the ssh commandline that does not have a - in it is treated as the name of the command that you want ssh to run on the remote computer. All arguments after this first command name are then treated as arguments to that command. An example might be
ssh myServer.local -C ls -la
where the command to be run on the remote machine would be
ls -la

Some people like to make this obvious by putting the remote command string in quotes, ie
ssh myServer.local -C "ls -la"
The problem with this is that different contexts in UNIX have different rules for interpreting quotation marks. Quoting in this way and in shell scripts usually does what you want, but quoting in this way in a xinetd config file does not work. So use quotes if you think it makes things clearer, but always test that the quotes are doing what you think and are actually working.

other lines

The other lines are technical. If you use xinetd for other services, they will usually stay the same. If you really want to understand them, read man xinetd.

summmary

Thus the final result is that a packet sent to port 25 on the client machine is

  1. caught by xinetd
  2. sent to ssh which encrypts it and sends it to the server
  3. which decrypts it and gives it to nc
  4. which feeds it to port 25 on localhost, ie on the server.

The net result is that the packet is

  1. transferred over the network encrypted
  2. as far as the listener on server port 25, ie postfix is concerned, the packet originated locally on the server

xinetd config file for port 143

Now we do the same thing for imap. Type

sudo pico imap_via_ssh

and in the pico window type

service imap
{
disable = no
only_from = localhost
socket_type = stream
wait = no
groups = yes
user = your_username_on_the_client
server = /usr/bin/ssh
server_args = your_username_on_the_server@bluecloud.com -c arcfour -C -q nc localhost 143
}

The only difference from the smtp case is that we are dealing with service imap, and the server_args now has nc delivering the data to port 143.

launchd

Apple recommends that launchd files that provide services for a single user be stored in ~/Library/LaunchAgents. You may have to create this directory. Copy the two files below to that directory, then use Lingon to look at them.

These (especially when viewed in Lingon) should map fairly obviously to the xinetd files we discussed above. Note that you will obviously change your_username_on_the_server@bluecloud.com in both the files below.

launchd config file for port 25

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>smtp</string>
	<key>Nice</key>
	<integer>-6</integer>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/bin/ssh</string>
		<string>your_username_on_the_server@bluecloud.com</string>
		<string>-c</string>
		<string>arcfour</string>
		<string>-C</string>
		<string>-q</string>
		<string>nc</string>
		<string>localhost</string>
		<string>25</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>smtp</key>
		<dict>
			<key>SockNodeName</key>
			<string>127.0.0.1</string>
			<key>SockServiceName</key>
			<string>smtp</string>
		</dict>
	</dict>
	<key>inetdCompatibility</key>
	<dict>
		<key>Wait</key>
		<false/>
	</dict>
</dict>
</plist>

launchd config file for port 143

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>imap</string>
	<key>Nice</key>
	<integer>-7</integer>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/bin/ssh</string>
		<string>your_username_on_the_server@bluecloud.com</string>
		<string>-c</string>
		<string>arcfour</string>
		<string>-C</string>
		<string>-q</string>
		<string>nc</string>
		<string>localhost</string>
		<string>143</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>imap</key>
		<dict>
			<key>SockNodeName</key>
			<string>127.0.0.1</string>
			<key>SockServiceName</key>
			<string>imap</string>
		</dict>
	</dict>
	<key>inetdCompatibility</key>
	<dict>
		<key>Wait</key>
		<false/>
	</dict>
</dict>
</plist>

Testing using telnet

To test this, we need to make xinetd aware of the files we have created. The simplest way to do this would be to reboot the machine. (You have to reboot. xinetd is owned by the operating system, not by a single user, so just logging out as a user will not affect xinetd.) But we covered an easier alternative, sending a HUP signal, earlier:

sudo kill -HUP `cat /var/run/xinetd.pid`

Now that xinetd has noted the files we put in /etc/xinetd.d, we can test if they work. Remember back when we were at the server and we typed in the lines

telnet localhost 25

to connect to the smtp demon? Now, on the portable, in a terminal window, type in the same command. You should get the same response. Through the magic of our ssh tunnel, connections to port 25 on our portable connect directly to port 25 on the server. Again on the portable you can type

telnet localhost 143

to connect to imapd, give it the same . login and . examine commands and get the same response.

Setting up Mail.app

Now we can finally set up Mail.app on the portable. In Mail.app, create a new account named IMAP or bluecloud.com or whatever you want. Fill everything in just like you did when setting up Mail.app on the server.

You can also, if you want to start filing your mail, create a new folder in Mail using the little + icon at the bottom of the Mailboxes drawer. In the dialog box that appears, use the popup menu to set the location of the folder being created to your IMAP server rather than "On my Mac". You can now file mail into this folder. Mail filed in this way will be stored both on your server (and accessible to any IMAP connection) and cached locally on your portable (so you can read it or organize it or whatever even when you don't have a network connection). After making changes in Mail.app that involve IMAP folders, and when you are back connected to a network, control click on the folder and select "Synchronize IMAP" to inform the server of your changes. You may, alternatively, prefer to modify the IMAP account settings (through Mail.app's preference pane) to automatically synchronize folders. In earlier versions of MacOS X this auto-synchronization was pretty dodgy, but as of the later versions of 10.4 it works well.

If you go back to Mail.app running on your server, you will see that the Mail.app there also shows your new folder and shows whatever messages you moved to it as being there. Everything stays nicely synchronized.

Once you are happy with your setup, you will probably want to move all your old stored mail to the IMAP server. You can do that easily just by dragging any folder of mail from the outer level named "On My Mac" to the outer level folder name "IMAP". Of course if you are copying a lot of email, it may take a while for all the email to be copied over the network to the server. You can then delete that mail from "On My Mac".

Making ssh faster in general

It is fine for our xinetd config files to include flags telling ssh to use the fastest available encryption scheme, but we'd like ssh to do this more generally, whenever it makes a connection, whether it is us opening a command line on a remote machine, or a backup script using ssh to transfer data from a remote machine.

The easiest way to ensure this is to modify ssh's global preferences file which is /etc/ssh_config.

sudo pico /etc/ssh_config

Scroll to the bottom of this file and add the lines

Cipher blowfish
Ciphers arcfour,blowfish-cbc,aes128-cbc,3des-cbc,cast128-cbc,aes192-cbc,aes256-cbc

The first line says that if ssh connects to a machine running a very old version of ssh, one that speaks only the version 1 protocol of ssh, then use blowfish as the encryption algorithm.
The second line says that, in the more common situation of ssh connecting to a server that speaks the version 2 protocol, preferrentially use the encryption algorithms is the order given. Under normal circumstances, this means that the first algorithm in the list, arcfour, will be used.

There are many many other settings you can place in this configuration file, but chances are you don't need a single one of them. In particular, unless you have good reason to do so, you probably don't want to specify here that ssh should always use compression. Compression is a great idea when ssh is running in a batch mode, but it can slow down the interactive use of ssh and make it irritating. But it's up to you. Try ssh in various situations with and without compression (ie using the -C command-line flag) and see what you think.

Caveats when using Mail.app

You should be aware of two things.

The first is that neither Mail.app nor imapd are smart enough to check for duplicated messages and throw them away. What this means is that if you usually read mail on two different computers, and you sometimes were using POP with "keep on server" and sometimes not, so that they each have some mail that's the same and some that is different, you can't just blindly copy all the mail over from both computers into the IMAP folder, or rather you can do that, but you will land up with duplicates. Depending on how much mail you have, you may then just want to go through the lot by eye, looking for duplicates. Alternatively you could probably write an Applescript to do this for you --- something like

    for each mailbox
        order the mail by date
        for each piece of mail
            if date+time == date+time of previous piece of email and
               sender    == sender    of previous piece of email and
               subject   == subject   of previous piece of email
            then delete this email

but I'm afraid I don't have this problem of lots of duplicate emails, and I don't know much AppleScript, so I can't write the script for you. Sadly, while Apple provides us with a number of essentially useless scripts for Mail.app, it does not provide us with this useful script.

The second problem is that any movement of mail into an IMAP mailbox will lose the "Date Received" of the mail if the mail was received on a day of the month that begins with 8 or 9. (Why such a bizarre bug? Has to do with strings being written as decimal then interpreted as octal.) The easiest way to deal with this is set your mail to sort and display based on the "Date Sent" rather than the "Date Received" since, barring very weird circumstances, these are the same give or take a few minutes. I have informed Apple of this bug (4692445), and we shall see whether it's fixed in Leopard.

Using Another Computer as a Client

What if you have another computer you also want to use to connect to your IMAP/postfix server? You don't have to do the whole ssh key_gen thing again. Remember that any computer that has the id_dsa file (the private key) is trusted by your server. So let's suppose you now want your imac to be able to connect to your server:

Set up ssh on the new client

Copy over the id_dsa file

You could copy over the id_dsa files using AppleTalk (by activating File Sharing on the imac) but that's a hassle when trying to copy over files that live in UNIX directories that are hidden by the Finder, and ~/.ssh is one of these directories that the Finder hides. Besides, as always, it's useful to learn the UNIXy way of doing things.

give the new client a useful name

First thing you need to do is open up the Sharing preferences pane on the imac, and look at the top where there is a line that says something like
Computer Name: Fred Smith's Computer. You can name your computer whatever you want, the main thing is that if you have three computers all named "Fred Smith's Computer" (which is what you will get as the Apple default) life gets complicated. So give your imac a name you like that differs from your other computers.

find the DNS name for the new client

Now hit the button at the top of the Preferences window that says "Show All", and select the "Sharing" preferences pane again. You will see, under the name of your computer, text which says something like "Other computers on your local subnet can reach your computer at Freds-Imac.local". (This name is generated from the computer name you set in the previous paragraph, but stripped of special characters like punctuation.)

This is all part of the magic of Bonjour. Remember our discussion about IP addresses, then domain names, and then dynamic DNS. Bonjour is basically a type of dynamic DNS that is built into MacOSX, but that is limited to your local subnet (that is, all the computers on your wireless network, but not beyond your router). (Bonjour doesn't go out beyond the router not because Apple is mean and want to make your life hard, but because there are good technical reasons why this is difficult and problematic.)

copy the id_dsa file to the new client

Now that we have a standard DNS type name for your imac, we can use scp to copy to it. Going back to your portable, type

scp ~/.ssh/id_dsa imacusername@Freds-Imac.local:~/.ssh/id_dsa

Now the imac has the magic id_dsa file that matches the id_dsa.pub we copied to the server, and so the imac can also connect to the server using ssh and without being asked for a password.

Or create a new public/private key pair

Alternatively, if you prefer, you can run
ssh-keygen -t dsa
on the

imac. There's no good reason to do this, but it will work. This will once again create a public/private key pair, and you would copy over the public key to the server and append it to ~/.ssh/authorized_keys.

Set up xinetd on the new client

From this point on, things are just as before. On the imac create and fill in the two files /etc/xinetd.d/smtp_via_ssh and /etc/xinetd.d/imap_via_ssh, (or copy them from portable using scp), test them using telnet, then set up an account in Mail.app.


← prev: Mail postfix and IMAP Setup next: Mail SSL Setup →

Personal tools