Goals

My purpose in writing this is to document how to automate mail retrieval from a remote host (everybody.org in this case) without typing your password anywhere. Additionally, I want to ensure that the attacker who compromises the account running fetchmail doesn't automatically gain access to more than your email.

That is, if your mail account is a Unix Shell account on a foreign machine and your fetchmail account is on your local machine, we do not want the account theif to immediately compromise the foreign machine if he compromises your local account.

Methods

To do this we will set up an non-passphrase-protected ssh keypair whose sole purpose is to set up the ssh tunnel for fetchmail. The only command that it can run on the remote host is /usr/local/libexec/imapd.

Procedure

  1. Generate the key:
    $ ssh-keygen -b 1024 -f .ssh/mail_check -C "email@everybody.org" -P ""
    Generating RSA keys:  ...............ooooooO.........................................................ooooooO
    Key generation complete.
    Your identification has been saved in .ssh/mail_check.
    Your public key has been saved in .ssh/mail_check.pub.
    The key fingerprint is:
    c0:ad:49:92:81:ea:b9:88:2e:f5:2d:a3:0a:11:59:67 email@everybody.org
    
  2. Edit ~/.ssh/authorized_keys on the remote host. Append the contents of ~/.ssh/mail_check.pub from your local machine to the authorized_keys file on the foreign machine. At the beginning of the the line (before the 1024), put
    command="/usr/local/libexec/imapd",no-port-forwarding,no-agent-forwarding,no-pty,from="64.81.114.147"
    
    Substitute your local ip address or machine name for the "from" so that you end up with a line that looks something like this:
    command="/usr/local/libexec/imapd",no-port-forwarding,no-agent-forwarding,
    no-pty,from="64.81.114.147" 1024 35 12333076430575175720679678139920022817
    89498644456404978922984154121892210952586059656597621419128673230763955818
    83313833477831564339602412421858693735833396268917555082416634587359216687
    65943880395794712702731984198836856573658173059252907635286070846169196850
    8497070380705371764478951144154324073806602053641 email@everybody.org
    
    (If you put that line in your authorized_keys file without changing the "from" parameter, I'll be able to run "echo hi" on your machine.)
  3. Set up the ~/.ssh/config on your local machine to use the identity file whenever you contact the mail host. Here are the lines I've put at the beginning of my config file:
    Host check-mail
        BatchMode yes
        HostName everybody.org
        IdentityFile ~/.ssh/mail_check
        LogLevel QUIET
    
    Now, whenever we run ssh check-mail, ssh will connect to everybody.org using the identity found in ~/.ssh/mail_check.
  4. Test it. Since the only thing that the key we've prepared is authorized to do on the remote host is run the /usr/local/libexec/imapd command, anytime we ssh to check-mail, we should get "* PREAUTH [...]" on STDOUT, no matter what command we give ssh to run. After testing the key, you can type '. logout' to quit the IMAP session. It is extremely important that you see the "PREAUTH" on the first line. fetchmail will see it and understand that the session is already authenticated.
    $ ssh check-mail
    hi
    $ ssh check-mail echo testing
    hi
    $
    
  5. Add an entry for fetchmail to your ~/.fetchmailrc. This should be adequate:
    poll everybody.org with proto IMAP preauth ssh:
        plugin "ssh check-mail 2> /dev/null"
    
    We are redirecting STDERR to /dev/null because otherwise it we'll get warnings about no TTYs which are annoying when fetchmail is run in a cronjob.
  6. Ensure that .fetchmailrc has permissions not greater than 0710
    $ chmod 0700 ~/.fetchmailrc
    
  7. Test fetchmail.
    $ fetchmail -c
    fetchmail: No mail for mah at everybody.org
    
  8. Assuming everyting is working, set up a cron job to run fetchmail at 15 minute intervals:
    $ (crontab -l 2> /dev/null | echo '0,15,30,45 * * * * fetchmail') | crontab -
    

Mail should start arriving in your mailbox shortly. You may want to send yourself a message just to verify that it travels to the mailhost and fetchmail returns it to your local mailbox. Check