http:// qmail.jms1.net / scripts / mkauth.shtml

mkauth

The most recent version of the script is dated 2007-10-02. The script itself contains a list of what changes were made, each time I made a change.

The most common questions I receive about the AUTH_CDB patch involve how to create an "auth.cdb" file in the first place, or how to use the same file on multiple servers. The mkauth script can be a major part of the answer to both questions. This web page will show how I'm using mkauth on my own server.

I should point out that you are not required to use mkauth in order to benefit from the AUTH_CDB patch- any mechanism which produces a list of all valid mailboxes on your system, with their encrypted passwords, will work. As long as you correctly turn this text into a cdb file, qmail-smtpd will be able to use it.

Also, there is no requirement that you use the name "auth.cdb" for the file- you can use any name you like, so long as the file is readable to the userid as which qmail-smtpd runs. This page will use the name "auth.cdb" for example purposes- the filename you use on your own server should match the name you have in the AUTH_CDB variable for your qmail-smtpd service.


Installing the cdb package

Before you install the script, there are a few other packages which need to be installed on the system. The first is djb's cdb library and tools, which contains the cdbmake-12 program, which converts a text file into a cdb file. This package should be installed using the directions on djb's web site. A quick walk-through is shown here:

$ wget http://cr.yp.to/cdb/cdb-0.75.tar.gz
...
$ tar xvzf cdb-0.75.tar.gz
...
$ cd cdb-0.75

If you are using a system with glibc version 2.3 or later, the original djb source code will cause an error in the file error.h, because the newer versions of glibc implement the errno variable differently than how it has been done in the past. (errno is a global variable which libc uses to tell the caller whether the last I/O function call was successful or not, and if there was an error, it will contain a number identifying the error.)

There is a simple fix, which can actually be done on all systems whether it's necessary or not, without causing any problems. If you know (or suspect) that you need this fix, or if you have tried to compile the code and gotten an error about error.h, or if you just want to do it anyway, here's the fix:

Open the file error.h with a text editor.

$ vi error.h

Find this line:

#ifndef ERROR_H
#define ERROR_H

extern int errno;

extern int error_intr;
extern int error_nomem;

Comment the line out, and add this new line below it:

#ifndef ERROR_H
#define ERROR_H

/* extern int errno; */
#include <errno.h>


extern int error_intr;
extern int error_nomem;

You can also make this change with a one-line sed command, useful for scripts:

$ sed -i '/extern int errno/{s/^/\/* /;s/$/ *\//;G;s/$/#include <errno.h>/;}' error.h

Then finish compiling and installing the package as normal. Note that this same problem can occur, and the same procedure will fix it, in most of djb's programs, including qmail, ucspi-tcp, daemontools, and djbdns.

$ make
...
$ su -
Password: you should not see the root password as you type it
# make setup check
...
# exit

Installing the CDB_File module

The mkvalidrcptto script reads several cdb files in order to do its job, which means that you need to install the CDB_File perl module, available through CPAN, the Comprehensive Perl Archive Network, which is an archive of Perl modules which are not included with Perl itself, but which others have decided to share in the hope that they will prove useful.

This is a quick walk-through of how to install the module.

$ su -
Password: you should not see the root password as you type it
# perl -MCPAN -e shell

If you have never run the CPAN shell before, you will be asked to configure the module first. This will involve setting the path to the various utilities that CPAN uses for downloading and building modules, as well as selecting one or more CPAN "mirrors". Mirrors are web and FTP sites around the world which have copies of all of the CPAN modules. You should go through this process if it asks you to- for most of the questions you can just hit ENTER and be okay, and for mirrors you should try to choose at least three of them, preferably ones which are in your part of the world.

cpan> install CDB_File
...
cpan> exit
# exit

After installing any Perl modules, it's a good idea to run the pfix script, available on the code section of my normal (non-qmail) web site. Some Perl modules don't correctly set the permissions on their files when you install them- the pfix script resets the permissions on all directories in Perl's default library path so that everything is owned by root and is world-readable but only writable to root.

$ su -
Password: you should not see the root password as you type it
# cd /usr/local/bin
# wget http://www.jms1.net/code/pfix
...
# chmod 755 pfix

The script is now installed. From now on, you can run the "pfix" command as root to fix the permissions on the perl library directories whenever you install new perl modules.

# pfix

# exit

Installing mkauth

Believe it or not, this is actually the easiest part of the whole process. All you need to do is download it into a directory which is in your PATH and set the permissions.

File: mkauth
Size: 12,521 bytes
Date: 2007-10-02 20:45:24 +0000
MD5: 55ab27943db6ebf644fb83dba02fc2d6
SHA-1: d60c35c9ddcf9c29870eb06b9efa575175ee9be9
RIPEMD-160: 9047cfe9d2d477c1d723d09c7e3e8bdb53a069ca
PGP Signature: mkauth.asc

# cd /usr/local/bin
# wget http://qmail.jms1.net/scripts/mkauth
...
# chmod 755 mkauth

One thing that wouldn't hurt is to make sure that your installation of perl is happy with the script and can find the modules. You can do this by running this command as a non-root user:

$ perl -c /usr/local/bin/mkauth
/usr/local/bin/mkauth syntax OK

You should then run it once as root and make sure the output makes sense for your system. The output should be a list of every valid email address on your system, one on each line.

# mkauth
alan@domain1.xyz $1$dhuMd.kf$UUGFyA3DCaMWU3pFL2QTqk
jms1@domain1.xyz $1$GLKcu17D$TSNDEEt9Gii0oh6WLV2lWx
postmaster@domain1.xyz $1$I/hnPBSk$1QST1iKis22t/cm5pE8pkz
thomas@domain1.xyz $1$r/JKcyUw$RNfIgJ0ZtkpIIOUmoKBYYL
postmaster@domain2.xyz $1$oHXkhAIU$nG1z7gPNd7eBcYB0hCmLX2
postmaster@domain3.xyz $1$iNeEuq4u$I4GHPUKYr9KPuCuK5fD/28
user@domain3.xyz $1$EDjIhtfL$iWwoLY3pBRxc46xy9fTHfW


Using the script

As shown in the example above, simply running the script as root will produce a list of every mailbox on your system, along with their encrypted passwords. This output can be piped through "cdbmake-12" in order to produce a .cdb file.

# mkauth | cdbmake-12 new.cdb new.tmp

If there are any active qmail-smtpd services using the file, you should not build the file directly- you should build it using a different name, then set the ownership and permissions correctly, and then rename the new file over the old one. This example assumes that qmail-smtpd is running as the "qmaild" user (which is the standard way to do it.)

# chown root:nofiles new.cdb
# chmod 0640 new.cdb
# mv new.cdb auth.cdb

Another option is to use the "-m" option, which produces its output in the format needed by the cdbmake program. I don't see many people using this option, however it's there if you're more comfortable with it.

# mkauth -m
+16,34:alan@domain1.xyz->$1$dhuMd.kf$UUGFyA3DCaMWU3pFL2QTqk
+16,34:jms1@domain1.xyz->$1$GLKcu17D$TSNDEEt9Gii0oh6WLV2lWx
+22,34:postmaster@domain1.xyz->$1$I/hnPBSk$1QST1iKis22t/cm5pE8pkz
+18,34:thomas@domain1.xyz->$1$r/JKcyUw$RNfIgJ0ZtkpIIOUmoKBYYL
+22,34:postmaster@domain2.xyz->$1$oHXkhAIU$nG1z7gPNd7eBcYB0hCmLX2
+22,34:postmaster@domain3.xyz->$1$iNeEuq4u$I4GHPUKYr9KPuCuK5fD/28
+16,34:user@domain3.xyz->$1$EDjIhtfL$iWwoLY3pBRxc46xy9fTHfW

# mkauth -m | cdbmake new.cdb new.tmp
# chown root:nofiles new.cdb
# chmod 0640 new.cdb
# mv new.cdb auth.cdb
Note that the extra blank line between the data and the next command is part of cdbmake's file format- it needs that blank line to flag the end of the data.

Probably the easiest option is to use the "-c" option, which generates the .cdb file directly.

# mkauth -c new.cdb
# chown root:nofiles new.cdb
# chmod 0640 new.cdb
# mv new.cdb auth.cdb

Other options

The "-n" option causes mkauth to NOT generate output for "local" domains. It will still generate output for virtual domains managed by vpopmail. This was something I used while testing the script, and I didn't see any harm in leaving it there, so if you have a need for it, you have it. Enjoy.

The other option, "-e", specifies a file containing environment variables to be attached to users' entries in the file. Version 7.02 of the combined patch added the ability to specify environment variables, which qmail-smtpd adds to the environment (or changes in the environment) when that particular user authenticates. For now the only use I can see for this is being able to specify per-user DATABYTES limits, however I'm sure others will come up with a use for this mechanism.

The file containing the variables consists of lines. Each line starts with an email address, or in the case of a "local" user, just the userid. After the email address should be one or more spaces or tabs, followed by the variable(s) you wish to set. If you specify multiple variables on a single line, they should be separated with a comma (i.e. ",", ASCII 44, 0x2C.) Note that you can specify an email address on more than one line, and the variables from the various lines will be combined in the output.

Here's an example which shows the relevant pieces of information:

# cat authenv.txt
jms1@domain1.xyz     DATABYTES="0"
thomas@domain1.xyz   DATABYTES="0" , FNORD="mu"
jms1@domain1.xyz     FNORD = " moo "
# mkauth -e authenv.txt
alan@domain1.xyz $1$dhuMd.kf$UUGFyA3DCaMWU3pFL2QTqk
jms1@domain1.xyz $1$GLKcu17D$TSNDEEt9Gii0oh6WLV2lWx,DATABYTES="0",FNORD=" moo "
postmaster@domain1.xyz $1$I/hnPBSk$1QST1iKis22t/cm5pE8pkz
thomas@domain1.xyz $1$r/JKcyUw$RNfIgJ0ZtkpIIOUmoKBYYL,DATABYTES="0",FNORD="mu"
postmaster@domain2.xyz $1$oHXkhAIU$nG1z7gPNd7eBcYB0hCmLX2
postmaster@domain3.xyz $1$iNeEuq4u$I4GHPUKYr9KPuCuK5fD/28
user@domain3.xyz $1$EDjIhtfL$iWwoLY3pBRxc46xy9fTHfW

Of course, this option can be combined with the "-m" or "-c" options as well...

# mkauth -e authenv.txt -c new.cdb
# chown root:nofiles new.cdb
# chmod 0640 new.cdb
# mv new.cdb auth.cdb
# cdbget jms1@domain1.xyz < auth.cdb
$1$GLKcu17D$TSNDEEt9Gii0oh6WLV2lWx,DATABYTES="0",FNORD=" moo "#
Note that "cdbget" does not automatically add a newline to the end of its output, so the next prompt appears at the end of the output instead of at the beginning of the next line.

Automating the process

I use a daemontools service called qmail-updater to update my auth.cdb and validrcptto.cdb files on a regular basis. The web page has details about how to set it up.

In addition, I use (and wrote) the vpopmail ONCHANGE patch, so that vpopmail itself can trigger the files to be rebuilt whenever something changes- a mailbox is added or removed, a password is changed, or whatever the case may be. This prevents users from having to wait until a cron job gets around to starting.


Scripting for multiple systems

One of the biggest advantages of having auth.cdb as a stand-alone file is that it can be copied to other machines. The most common scenario is to have one machine handling the mailboxes, and one or more other machines (which I call "mailhubs") which handle incoming email from the outside world. These mailhubs' only job is to do RBL, virus, and/or spam checking on the incoming email, and only accept messages which are "clean". If a mailhub has an auth.cdb file available, it can validate AUTH commands, and authorized users can relay mail through the mailhubs without involving the mailbox server at all.

The mailhub page explains this scenario in more detail. It also includes scripts to handle automatically replicating certain qmail control files from the mailbox machine to the mailhubs- specifically the rcpthosts and morercpthosts.cdb files, the smtproutes file, the validrcptto.cdb file, and of course the auth.cdb file.