CheckPassword
=============

Checkpassword is an authentication interface originally implemented by qmail
[http://www.qmail.org/]. Checkpassword combines both the <password database>
[PasswordDatabase.txt] and <user database> [UserDatabase.txt] lookups into a
single checkpassword lookup, which makes the standard implementation unsuitable
for a standalone userdb. With Dovecot extensions it's also possible to use
checkpassword as a userdb.

Typically you'll use <prefetch> [UserDatabase.Prefetch.txt] as the userdb, but
it's not required that you use the checkpassword script's userdb capabilities.
You can still use for example <static userdb> [UserDatabase.Static.txt] if
you're using only a single UID and GID, and your home directory fits into a
template.

Deliver
-------

If your checkpassword script doesn't support Dovecot extensions, you can't use
it as a user database. This means that if you wish to use <LDA.txt>, you can't
use the '-d' parameter to do userdb lookups. There are two ways to solve this:

 1. Use another userdb which does the lookup for deliver, for example <SQL>
    [AuthDatabase.SQL.txt] or <static> [UserDatabase.Static.txt]. Add this
    userdb after the prefetch userdb.
 2. Use a script to look up the user's home directory and run deliver without
    '-d' parameter. For example:

---%<-------------------------------------------------------------------------
#!/bin/sh

# <<Lookup user's home directory here.>>

# If users have different UIDs/GIDs, make sure to also change this process's
UID and GID.
# If you want to override any settings, use dovecot-lda's -o parameter
# (e.g. dovecot-lda -o mail_location=maildir:~/Maildir).

export HOME
exec /usr/local/libexec/dovecot/dovecot-lda
---%<-------------------------------------------------------------------------

Checkpassword Interface
-----------------------

The interface is specified in http://cr.yp.to/checkpwd/interface.html. However
here's a quick tutorial for writing a script:

 * Read '<username> NUL <password> NUL' from fd 3.
 * Verify the username and password.
    * If the authentication fails, exit with code 1. This makes Dovecot give
      "Authentication failed" error to user.
       * This error is returned both for password mismatch and also if the user
         doesn't exist at all. Internally Dovecot maps this as password
         mismatch.
    * If you encounter an internal error, exit with code 111. This makes
      Dovecot give "Temporary authentication failure" error to user.
 * If the authentication succeeds, you'll need to:
    * Set user's home directory to '$HOME' environment. This isn't required,
      <but highly encouraged> [VirtualUsers.txt].
    * Set '$USER' environment variable. If the user name was changed (eg. if
      you lowercased "Username" to "username"), you can tell about it to
      Dovecot by setting '$USER' to the changed user name.
    * Change the process's effective UID and GID to the user's <UNIX UID and
      GID> [UserIds.txt].
       * Alternatively you could set 'userdb_uid' and 'userdb_gid' environments
         and add them to 'EXTRA' environment (see below for Dovecot
         extensions).
    * Your program received a path to 'checkpassword-reply' binary as the first
      parameter. Execute it.

Qmail-LDAP
----------

Note that auth_imap that comes with qmail-ldap is not compatible with this
interface. You can get a patch that adds auth_dovecot functionality to
qmail-ldap here
[http://japc.uncovering.org/dovecot/qmail-ldap-1.03-20060201-dovecot.patch]. Or
you can use auth_pop instead, but you may need to pass /aliasempty/ to let
auth_pop find the Maildir, so it is recommended to write a
/var/qmail/bin/auth_dovecot wrapper (don't forget to chmod +x it) around
auth_pop.

---%<-------------------------------------------------------------------------
#!/bin/sh
QMAIL="/var/qmail"
if [ -e $QMAIL/control/defaultdelivery ]; then
    ALIASEMPTY=`head -n 1 $QMAIL/control/defaultdelivery 2> /dev/null`
else
    ALIASEMPTY=`head -n 1 $QMAIL/control/aliasempty 2> /dev/null`
fi
ALIASEMPTY=${ALIASEMPTY:-"./Maildir/"}
exec $QMAIL/bin/auth_pop "$@" $ALIASEMPTY
---%<-------------------------------------------------------------------------

you can also use this wrapper to pass LOGLEVEL environmental variable to
auth_pop.

Dovecot Extensions
------------------

If you wish to return <extra fields> [PasswordDatabase.ExtraFields.txt] for
Dovecot, set them in environment variables and then list them in EXTRA
environment variable. The <userdb extra fields> [UserDatabase.ExtraFields.txt]
can be returned by prefixing them with 'userdb_'. For example:

---%<-------------------------------------------------------------------------
userdb_quota_rule=*:storage=10000
userdb_mail=mbox:$HOME/mboxes
EXTRA=userdb_quota_rule userdb_mail
---%<-------------------------------------------------------------------------

Dovecot also sets some environment variables that the script may use:

 * 'SERVICE': contains eg. imap, pop3 or smtp
 * 'TCPLOCALIP' and 'TCPREMOTEIP': Client socket's IP addresses if available
 * 'MASTER_USER': If master login is attempted. This means that the password
   contains the master user's password and the normal username contains the
   user who master wants to log in as.
 * 'AUTH_*': All of the <auth variables> [Variables.txt] are available as
   'AUTH_<long name>' extra fields. For example '%{cert}' is in 'AUTH_CERT'.
   (v2.0.16+)

Checkpassword as userdb
-----------------------

Dovecot calls the script with 'AUTHORIZED=1' environment set when performing a
userdb lookup. The script must acknowledge this by changing the environment to
'AUTHORIZED=2', otherwise the lookup fails. Other than that, the script works
the same way as a passdb checkpassword script. If user doesn't exist, use exit
code 3.

Checkpassword with passdb lookups (v2.1.2+)
-------------------------------------------

Normally checkpassword answers to questions "is user X's password Y?" This
doesn't work with non-plaintext auth mechanisms, or when Dovecot wants to do a
non-authenticating passdb lookup (e.g. for LMTP proxy). These passdb
credentials lookups can be implemented the same way as a userdb lookup (i.e.
change the 'AUTHORIZED' environment).

 * 'AUTHORIZED=1' is set, just like for userdb lookup
 * When doing a non-plaintext authentication:
    * 'CREDENTIALS_LOOKUP=1' environment is set
    * The password scheme that Dovecot wants is available in 'SCHEME'
      environment (e.g.'SCHEME=CRAM-MD5')
    * If a password is returned, it must be returned as
      'password={SCHEME}secret'.
 * When doing a passdb lookup, e.g. a proxy which doesn't really want the
   password, just the passdb extra fields:
    * Neither 'CREDENTIALS_LOOKUP' nor 'SCHEME' is set.
    * FIXME: Unfortunately it looks like you currently can't easily
      differentiate a passdb lookup from userdb lookup!
 * If user doesn't exist, use exit code 3.

Example
-------

The standard way:

---%<-------------------------------------------------------------------------
passdb {
  driver = checkpassword
  args = /usr/bin/checkpassword
}
userdb {
  driver = prefetch
}
# If you want to use deliver -d and your users are in SQL:
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
---%<-------------------------------------------------------------------------

Using checkpassword only to verify the password:

---%<-------------------------------------------------------------------------
passdb {
  driver = checkpassword
  args = /usr/bin/checkpassword
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/home/%u
}
---%<-------------------------------------------------------------------------

(This file was created from the wiki on 2012-07-03 04:42)
