[Dovecot] checkpassword migration script in Python
Dan Udey
dan at communicate.com
Wed Sep 3 09:33:24 EEST 2008
Hey all,
First post to the list, so here goes, hope I don't break any rules (I
didn't see any rules about not being overly verbose)
I spent a long time looking for anything that would help me migrate
from our old IMAP server to our new one without a lot of client-side
fuss, multiple e-mail accounts, and so on. I find that a lot of our
users get confused by having two 'inboxes' in Outlook (one local,
unused, and one IMAP), so I figured the easier I could make it, the
better.
I figured there must be some way to do what I was looking for, but I
couldn't find it, so I hacked up a little something to do the job. As
the saying goes, it's nasty, brutish, and short, but in my tests it's
done everything I needed it to.
The problem: Our old mail system is hosted by another company,
outsourced before I was hired, so I don't have access to the old user/
passwd database, nor to their e-mail store; thus, I cannot do a clean,
simple migration by upgrading in-place as I have done on other servers.
The solution IMAP authentication proxying. The idea is that I don't
need to know the password, because the user's mail client knows the
password, so all I need is for it to tell me, and then I can create
their user. That is what this script is for.
To use, set up your authentication backend (passdb) first, and then
after that section, add a 'passdb checkpassword' section containing
this script. Thus, the following will happen.
1. Valid users who log into your system will be authenticated as you
would expect.
2. Users who could not be authenticated will fall through to the
checkpassword section
3. Checkpassword will look for the user in the password database; if
they exist, it is assumed that it is a valid user, but incorrect
password, and checkpassword fails the user as well.
4. If the user is not currently in the database, it will initiate an
IMAP4 connection to the remote host specified. If it succeeds in
logging in to the remote host, then we assume that the user is a valid
user and can be migrated to the local server. They are added to the
database, along with their password. It then **fails the user's login
regardless**
5. It /logs the username and password into the database/ so that
another process can use that information to migrate their e-mail over
to the new server (not yet implemented).
6. If the IMAP connection fails, the login is failed as well, and
dovecot continues as normal until it has exhausted all other passdb
backends.
Interested? A few things to note about the script:
1. It's a brutal hack. Really, ugly stuff. However, it gets the job
done, if your system is similar enough to mine.
2. It only works on MySQL. I only use MySQL in our system, so there's
no point for me to add other DBs, nor any way to test.
3. It doesn't support remote servers using SSL. Our current system
doesn't use it, so again, it's hard to test.
4. It does not currently migrate mailboxes. I'm working on this (see
below).
5. If your schema is at all different from mine, you will likely have
to rewrite all of the SQL. There's not much I can do about this.
6. If your backend database doesn't use MySQL, you're largely boned.
Exception: rewrite add_user() to do whatever you need to do to add
users to your system.
7. The script will **ALWAYS RETURN A FAILED LOGIN TO DOVECOT**. This
is because there are too many variables on every configuration, and
writing code for all of them is absurd. This way, the user's first
login will always fail, and their second login will always succeed. If
you want to avoid this, place your normal passdb authentication **both
before and after this checkpassword section**. That way, it will check
once, fail, pass to checkpassword, and then check again, success.
TODO:
1. Make it not ugly. Break more junk off into functions (e.g. IMAP
verification)
2. Send the user an e-mail ('Welcome to the server, sorry your mail is
gone, we'll fix that soon')
3. Spawn another process to run imapsync in the background to migrate
the user's old mailboxes over. This would be very site-dependent, as
there are a lot of variables. It might be best done as a cronjob that
polls the database every however often (1 minute? 2 minutes?) or a
daemon that sits in the background watching the db for changes, or
even accepting the data directly.
4. Stop being so verbose in my first postings to mailing lists.
5. Lots of other things.
URLS
Blah blah blah where's the code. Here you go.
Pretty syntax-highlighted version for browsing before you download, in
case I'm an evil hacker:
http://cdslash.net/temp/python/checkpassword.py
Ugly monochrome version for downloading so you don't get line numbers
in your junk:
http://cdslash.net/temp/python/checkpassword.raw
Questions, comments? I probably won't be on the list very long, so if
you want to ask something or have a suggestion, feel free to let me
know by e-mail at the address listed in the file's license
notification. Alternately, find me on Freenode, occasionally in
#dovecot or always in #macosx, as Darien, or some variant thereof.
PS: The code is licensed under a boilerplate MIT license lifted from
the OSI license page. If you want it under a different license, let me
know. ;)
Thanks,
Dan
More information about the dovecot
mailing list