21

I'm trying to set up OfflineIMAP to authenticate via a gpg encrypted file (that way I can consolidate all my encryption to my gpg-agent process).

From the documentation, it seems the only way to encrypt one's server passwords is to use gnome-keyring (which I'd prefer not to run on my headless server). Is there a way to pipe in my password from a gpg file the way you can with mutt?

I know you can add extra features to offlineimap with the extension python file, but I'm afraid I wouldn't know where to start with that.

8
  • 1
    Does this work?
    – jasonwryan
    Commented Jul 29, 2012 at 9:04
  • @jasonwryan Link is down? NVM: Correct link.
    – jw013
    Commented Jul 31, 2012 at 21:06
  • That link is a bit misleading. Encrypting files is a good way to prevent people from getting anything useful when they steal your hard drive / computer, but it's only a minor speed bump for a malicious root user on the same box you are logging in on. There are many things a root user could do to get around the encryption. Remember that even X11 forwarding from untrusted machines (e.g. via ssh -X) is not safe.
    – jw013
    Commented Jul 31, 2012 at 21:12
  • I just dump all my password-containing configuration files in an ecryptfs container that mounts when I log in, replace the original with a symlink, and be done with it.
    – jw013
    Commented Jul 31, 2012 at 21:14
  • 1
    Check also quotenil.com/OfflineIMAP-with-Encrypted-Authinfo.html Commented Apr 18, 2014 at 9:08

4 Answers 4

33

I use the following method, which works fairly well:

1) Store your passwords in separate gpg encrypted files. For example ~/.passwd/<accountname>.gpg

2) Create a python extension file with a name of your choosing (e.g., ~/.offlineimap.py), with the following contents:

def mailpasswd(acct):
  acct = os.path.basename(acct)
  path = "/home/<username>/.passwd/%s.gpg" % acct
  args = ["gpg", "--use-agent", "--quiet", "--batch", "-d", path]
  try:
    return subprocess.check_output(args).strip()
  except subprocess.CalledProcessError:
    return ""

3) Modify your .offlineimaprc file to tell it about the python file, and to tell it how to read your passwords

[general]
pythonfile = ~/.offlineimap.py
# ...

[Repository <reponame>]
# add this line for each remote repository
remotepasseval = mailpasswd("<accountname>")

If you have several accounts that get checked simultaneously (separate threads), and you use gpg-agent, then it will ask for you passphrase for each account. I prime the agent by creating a file (echo "prime" | gpg -e -r [email protected] > ~/.passwd/prime.gpg), and priming the gpg agent by decrypting this file on launch of offlineimap. To do this, add the following to the end of ~/.offlineimap.py:

def prime_gpg_agent():
  ret = False
  i = 1
  while not ret:
    ret = (mailpasswd("prime") == "prime")
    if i > 2:
      from offlineimap.ui import getglobalui
      sys.stderr.write("Error reading in passwords. Terminating.\n")
      getglobalui().terminate()
    i += 1
  return ret

prime_gpg_agent()
1
  • 2
    This answer works really well. Just make sure you use absolute paths, or the subprocess command won't find the encrypted files. Commented Feb 27, 2013 at 10:42
7

Another method of leaving offlineimap running with knowledge of your password, but without putting the password on disk, is to leave offlineimap running in tmux/screen with the autorefresh setting enabled in your ~/.offlineimaprc

You need to add autorefresh = 10 to the [Account X] section of the offlineimaprc file, to get it to check every 10 minutes. Also delete any config line with password or passwordeval.

Then run offlineimap - it will ask for your password and cache it in memory. It will not exit after the first run, but will sleep for 10 minutes. Then it will wake up and run again, but it will still remember your password.

So you can leave a tmux session running with offlineimap, enter your password once, and offlineimap will be fine there after.

5

Loving the answer from @kbeta. However subprocess.check_output() was only introduced in python 2.7 - so here is a version of offlineimap.py that will work with older versions of python:

import os
import subprocess

def mailpasswd(acct):
    acct = os.path.basename(acct)
    path = "/home/hamish/.passwd/%s.gpg" % acct
    args = ["gpg", "--use-agent", "--quiet", "--batch", "-d", path]
    proc = subprocess.Popen(args, stdout=subprocess.PIPE)
    output = proc.communicate()[0].strip()
    retcode = proc.wait()
    if retcode == 0:
        return output
    else:
        return ''
0

ArchLinux wiki has some good infos.

I was able to store the password to the KDE Wallet following this guide.

~/offlineimaprc

[general]
accounts = main
pythonfile = ~/offlineimap.py

[Account main]
# Identifier for the local repository; e.g. the maildir to be synced via IMAP.
localrepository = main-local
# Identifier for the remote repository; i.e. the actual IMAP, usually non-local.
remoterepository = main-remote

[Repository main-local]
# OfflineIMAP supports Maildir, GmailMaildir, and IMAP for local repositories.
type = Maildir
# Where should the mail be placed?
localfolders = ~/imap-backup

[Repository main-remote]
type = IMAP
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
remotehost = my.host
remoteuser = my.user
remotepasseval = get_password()

~/offlineimap.py

#! /usr/bin/env python2
from subprocess import check_output

def get_password():
    return check_output('qdbus org.kde.kwalletd5 /modules/kwalletd5 readPassword "$(qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.open kdewallet 0 "kde-service-menu-nowardev-scanner")" "imap" "akonadi_imap_resource_0rc" "kde-service-menu-nowardev-scanner"', shell=True).splitlines()[0]

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .