the djb way

qmail with attitude

mailfront and smtp auth

Version: mailfront-0.90 (2004.02.09)
Download: check for latest release
Requirements: cvm, bglibs
Other: GPL

Bruce Guenter's mailfront package builds on the Credential Validation Modules we saw in the previous section on cvm, to support authentication for a number of qmail-related services. It currently offers the following main components:

All of these are useful, especially when you want to fully realize the value of the cvm approach to authentication. The smtpfront component may be the most desireable, though, as it enables RFC2554 SMTP-AUTH capabilities for a qmail service, without any modification whatsoever to the qmail source code.

To install the mailfront package, you will first need the bglibs and cvm packages, as described on the cvm installation page. Then download and unpack the latest mailfront package into a convenient build directory.

The build/install sequence is exactly the same as for cvm:

$ cd mailfront-0.90
$ make
$ ./instshow | less
$ su
# ./installer
# ./instcheck

It's a fast build, like "djb classic". The ./instshow command is optional, to show you exactly what will be installed where. We like it.

This result of the default build configuration will be a set of binaries installed in /usr/local/bin. A set of *.html documentation is included in the build directory; you may want to copy these files elsewhere for reference.

Oh boy! More services!

smtp authentication

In a basic qmail installation, we carefully setup values in control/rcpthosts and smtp.rules for tcpserver, to prevent the qmail-smtpd server from being used by spammers as an open relay. The idea is that we want only our own users to access the server for sending mail destined for other domains. So we generally arrange to enable $RELAYCLIENT only for connections from the local network, while all other connections must be sending mail only to the domains listed in control/rcpthosts (and, optionally, control/morercpthosts.cdb).

This mechanism for setting up $RELAYCLIENT is pretty much limited to authorizing relay access based on client IP address, though. While this works fine for the workstations installed on the local network, it is difficult to enable for staff roaming outside the office, who may be connecting from arbitrary IP addresses.

An SMTP service extension has been defined to help with this situation. RFC2554 describes a protocol for adding authentication to an SMTP session. It is similar to POP3 or IMAP authentication, in that a user presents credentials to gain access to the service. Unlike POP3 or IMAP though, SMTP authentication is optional. Connections are still permitted in the usual way without authentication. The use of SMTP authentication is an enhancement that allows specific identities to access the server as a mail relay.

The smtpfront-qmail component of the mailfront package implements SMTP AUTH for a qmail installation. In fact, the smtpfront-qmail component is more than a front-end for qmail-smtpd: it replaces it completely. On the plus side, this enables you to easily add an SMTP AUTH service to an existing qmail installation, without adding any patches to qmail source code.

The smtpfront-qmail module also offers these useful additional features:

Just be aware:

You should also note that, by itself, SMTP AUTH is emphatically not a secure solution. Unless you are encrypting the transport through other means, such as SSL, usernames and passwords are transmitted over the network in the clear.

If you can live with these caveats, an SMTP AUTH service can be as simple as rewriting the "run" script for the qmail-smtpd service. What we will do instead, though, is keep our existing qmail-smtpd and qmail-ofmipd services as is, and add a new qmail-authsmtpd service running on another port, say 587. In other words, we will use the smtpfront-qmail module for the specific purpose of putting up a mail relay service designated for users outside the local network.

The drill begins as usual, by making directories for the new service:

# mkdir /var/svc.d/qmail-authsmtpd/log

The daemontools "run" script for /var/svc.d/qmail-authsmtpd/run:

# qmail-authsmtpd/run
# daemontools run script for qmail smtp-auth service
# ** using bruce guenter's smtpfront-qmail (mailfront module) **
# envdir variables:
#   required:
#   CVM_SASL_PLAIN=cvm-local:/tmp/.cvm-unix.local
#   recommended:
#   MAILRULES=/var/qmail/control/authsmtp-mailrules
#   optional:
#   PATTERNS=/var/qmail/control/authsmtp-patterns
# ===
PORT=587     # rfc2476 "submission"

exec 2>&1
echo "*** Starting qmail-authsmtpd..."
exec \
  envdir ./env \
  envuidgid qmaild \
  softlimit -m 3000000 -f 10000000 \
  tcpserver -v -PR \
  -c ${CONLIMIT} \
  -x /etc/tcprules/authsmtp.cdb \
  0 ${PORT} /usr/local/bin/smtpfront-qmail 

### that's all, folks!

Make sure the script is executable, chmod 755. Compared to the original qmail-smptd service, this run script has just a few differences:

The envdir parameters will take a little explaining. Applications built with the cvm-sasl library, like smtpfront-qmail, may be configured through the use of environmental variables. $CVM_SASL_PLAIN here is used to point to the cvm-local.unix service we already installed in the discussion of cvm:

# echo "cvm-local:/tmp/.cvm-unix.local" > env/CVM_SASL_PLAIN

Now smtpfront-qmail will get generic POSIX password authentication from /etc/passwd, through the cvm module listening on the local domain socket /tmp/.cvm-unix.local. If you use an alternative cvm service, such as through a cvm-sql module with a MySQL database, change this parameter accordingly.

The other envdir variables are used to parameterize other features available with smtpfront-qmail. We will describe the use of $MAILRULES in a moment, for now set up the variable to point to it:

# echo "/var/qmail/control/authsmtp-mailrules" > env/MAILRULES

Setup a multilogger as usual, with this run script in qmail-authsmtpd/log/run:

# qmail-authsmtpd/log/run
# multilogger for qmail-authsmtpd service
# ===
exec setuidgid multilog multilog t /var/multilog/qmail-authsmtpd

### that's all, folks!

Make sure the script is exectuable, chmod 755. Then setup the log directory:

# mkdir /var/multilog/qmail-authsmtpd
# chown multilog /var/multilog/qmail-authsmtpd

Now define the tcprules for the service in /etc/tcprules/authsmtp.rules:

# authsmtp.rules

Compile the rules:

# (cd /etc/tcprules; make authsmtp.cdb)

Unlike smtp.rules for the original qmail-smtpd service, this configuration will allow connections from all hosts, yet not set $RELAYCLIENT for any. We'll see how to control relay permissions through other means.

Which bring us to $MAILRULES. First look at this example, to be installed in /var/qmail/control/authsmtp-mailrules:

# control/authsmtp-mailrules
# used by qmail-authsmtpd service (smtpfront-qmail)
# ===
### XXX named sections ("selector rules") dont work in 0.90!!!
### error in append_rule() routine in mailrules.c ???
# sender rules:
k**: I know you!
k**: An example.
d*:*: Sorry, service not available.
# recipient rules:
# none
### that's all, folks!

This is a non-standard qmail control file, specific to the mailfront smtpfront-* modules, and installed here in /var/qmail/control only for convenience. The syntax of this file is described in the documentation mailrules.html included with the package.

[Note: as indicated in the comments shown in the example, the "selector lines" do not function properly in the release we installed (0.90). By removing the "selector lines" (that is, :sender and :recipient), the rules shown here do work properly, according to an older "compatibility" syntax. The package author is currently reworking the mailrules specification entirely toward a new binary/compiled format (see "mailrulesx.html"). We will therefore limit our effort of describing the existing specification to a bare minimum.]

A rule line is any beginning with the key letters 'k', 'd', 'z', 'n', and 'p'. All other lines are ignored. The key letters specify the rule action. For example, 'k' means to accept the sender or recipient, and 'd' means to reject with a permanent error.

After the key letter, a rule line may have up to six colon (':') delimited fields:


The 'X' here marks the position of the key letter. Note there is no colon delimiter between the key letter and the first field.

The '*' character is used as a conventional wild-card character in the "sender" and "recipient" fields, to match any number of zero or more characters. Otherwise, characters are matched exactly.

Rules are applied in the order listed in the file; the first match "wins". The rules in the example may be described as follows:

  1. If the sender's address (MAIL FROM:) matches "*", accept it, and give the reply "I know you!". That is, accept any sender from the domain "".

  2. Likewise, accept any sender from the domain "".

  3. Reject any other sender address, with the reply "Sorry, service not available."

The effect of these rules is to allow clients sending mail addressed from specific domains, while rejecting everyone else. With this configuration we can accept mail addressed from our own users.

The story doesn't end here, though. Even if the messages addressed from "" and "" aren't rejected, it doesn't mean that such messages are now free to use the server as a relay. In fact that wouldn't be very good, because spammers could spoof tons of email through our server, simply by addressing it as though it were coming from us.

This is where SMTP AUTH comes in. Without authentication, this server behaves just like qmail-smtpd, allowing messages only destined for addresses defined in control/rcpthosts (and control/morercpthosts.cdb), or if $RELAYCLIENT is set. In our configuration, neither is true. So if a sender (or a spammer) tries to send a message without AUTH, he will be sorely disappointed.

But if our user's client software is configured to use AUTH, and she presents a valid username and password, --and if the recipient address is not rejected by $MAILRULES-- smtpfront-auth allows all recipient addresses.

Exactly what we want. A mail relay accepting messages only from our own authorized users.

Let's get it rolling:

# ln -s /var/svc.d/qmail-authsmtpd /service/qmail-authsmtpd

Send some test messages to the new service port and check the logs. Compare clients configured with and without the use of SMTP AUTH. Use recordio for awhile to see the complete SMTP dialogues.

Note that if you try to run a manual dialogue with the server, such as with the mconnect utility, you will find that SMTP AUTH requires usernames and passwords encoded in base64 format. The Perl MIME::Base64 module is one quick way to generate some base64 strings for testing.

Also note that you can use the smtpfront-echo utility to check the effect of a set of mailrules, before going on line with them:

$ MAILRULES=/path/to/testrules smtpfront-echo < testmsg.txt

And if you've gotten this far, great! You won't mind reading the rest of the documentation that comes with the package, where you may find even more features...

Copyright © 2003, 2004, 2005 Wayne Marshall.
All rights reserved.

Last edit 2005.05.02, wcm.