Valid XHTML 1.0 Strict
Valid CSS!

[ Docs | Tools | Advisories | Full-Disclosure ]

Introduction

This document clearly outlines the steps required to create a copy of Sendmail that implements the SMTP AUTH command (see RFC 2554), using the SASL library (see RFC 2222).
This approach has been verified to work with a number of mail clients, including Microsoft Windows clients such as Outlook Express and Pegasus Mail.

Revision History:

2001-06-11 Initial Revision
2002-01-18 Added Sendmail 8.12.x/Solaris 8 information
2002-03-29 Added Server-Server AUTH information

Instructions

1. Download the latest version of Sendmail and the Cyrus SASL library

... available from:

ftp://ftp.sendmail.org/pub/sendmail/

ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/

2. Take some backups before we start!

cp /etc/mail/sendmail.cf /etc/mail/sendmail.cf.old
cp /usr/lib/sendmail /usr/lib/sendmail.old

3. Build the SASL library and install it

gzip -cd cyrus-sasl.1.5.24.tar.gz | tar xvf - 
cd cyrus-sasl.1.5.24 
./configure --enable-login --prefix=/opt/local  -includedir=/usr/include -libdir=/usr/lib --with-dbpath=/etc/mail/sasldb
make
make install
cd ..

(Updated: 2002-03-29) Note that if you are building on Solaris 8 and need to use the gss api or kerberos, you have to install Sun's supplemental encryption packages.
SASL seems to require the following libraries in that case: libgssapi_krb5, libkrb5, libk5crypto and libcom_err.
You can disable gss and kerberos by specifying: --disable-krb4 --disable-gssapi, if your objective is to merely provide a somewhat secure relay mail server.

The --enable-login command makes the SASL library compatible with Outlook Express, but enables a rather weak 'encryption' scheme in this case.

As Sun Microsystems recommend, we refuse to use the default installation path of /usr/local, so we put everything into /opt/local instead.
We choose to install the libraries in a standard location, however, so that Sendmail does not have trouble finding them at runtime.
However, SASL will then expect to find the libraries in /usr/lib/sasl. The easiest workaround is to create a symlink as follows:

ln -s /opt/local/lib/sasl/ /usr/lib/sasl

4. Create your site.config.m4 file

Unpack Sendmail:

gzip -cd sendmail.8.11.4.tar.gz | tar xvf -
cd sendmail.8.11.4

Choose the definition from the devtools/OS folder that most closely matches your target system, and copy it to devtools/Site/site.config.m4.

For example, on a Solaris 2.6 machine:

cp devtools/OS/SunOS.5.6 devtools/Site/site.config.m4

5. Add SASL support to Sendmail

Edit the site.config.m4 file that you just created, and edit it as follows:

vi devtools/Site/site.config.m4

Change the confENVDEF statement to include -DSASL

Change the confLIBS statement to include -lsasl

Now is also the time to add any extra features you might want to compile in, such as TCP Wrapper support.
For example, on a Solaris 2.6 machine with SASL and TCP Wrappers enabled, the file would look like this:

define(`confCC', `gcc')
define(`confLDOPTS_SO',`-G')
define(`confSONAME',`-h')
define(`confBEFORE', `sysexits.h')
define(`confMAPDEF', `-DNDBM -DNIS -DNISPLUS -DMAP_REGEX')
define(`confENVDEF', `-DSOLARIS=20600 -DTCPWRAPPERS -DSASL')
define(`confLIBS', `-lsocket -lnsl -lkstat -lwrap -lsasl')
define(`confMTLDOPTS', `-lpthread')
define(`confMBINDIR', `/usr/lib')
define(`confEBINDIR', `/usr/lib')
define(`confSBINGRP', `sys')
define(`confINSTALL', `${BUILDBIN}/install.sh')
define(`confDEPEND_TYPE', `CC-M')
PUSHDIVERT(3)
sysexits.h:
        if [ -r /usr/include/sysexits.h ]; 
        then 
                ln -s /usr/include/sysexits.h; 
        fi
POPDIVERT

(Updated: 2002-01-21) For Sendmail 8.11.6 on Solaris 8 we used:

./Build -I/opt/local/BerkeleyDB/include -I/opt/local/include -L/opt/local/BerkeleyDB/lib -L/opt/local/lib

Our site.config.m4 looked like:

define(`confCC', `gcc')
define(`confLDOPTS_SO', `-G')
define(`confBEFORE', `sysexits.h')
define(`confMAPDEF', `-DNEWDB -DNDBM -DNIS -DNISPLUS -DMAP_REGEX -DLDAPMAP')
define(`confENVDEF', `-DSOLARIS=20800 -DNETINET6 -DSASL')
define(`confLIBS', `-lsocket -lnsl -lldap -lsasl')
define(`confMTLDOPTS', `-lpthread')
define(`confMBINDIR', `/usr/lib')
define(`confEBINDIR', `/usr/lib')
define(`confSBINGRP', `sys')
define(`confINSTALL', `${BUILDBIN}/install.sh')
define(`confDEPEND_TYPE', `CC-M')
PUSHDIVERT(3)
sysexits.h:
        if [ -r /usr/include/sysexits.h ]; 
        then 
                ln -s /usr/include/sysexits.h; 
        fi
POPDIVERT

(Updated: 2002-01-21)For Sendmail 8.12.1 on Solaris 8, our site.config.m4 looked like this:

divert(0)dnl
VERSIONID(`$Id: generic-solaris.mc,v 8.13 2001/06/27 21:46:30 gshapiro Exp $')
OSTYPE(solaris2)dnl
define(`confPRIVACY_FLAGS', ``authwarnings,noexpn,novrfy'')dnl
FEATURE(`local_procmail', `/opt/local/bin/procmail')
FEATURE(`access_db', `btree -T<TMPF> /etc/mail/access')dnl
FEATURE(`relay_entire_domain')dnl
FEATURE(`virtusertable', `btree -T<TMPFgt; /etc/mail/virtusers')dnl
FEATURE(`blacklist_recipients')dnl
FEATURE(`delay_checks')dnl
define(`confRUN_AS_USER',`smmsp')
define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5 LOGIN')dnl
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5 LOGIN')dnl
define(`confMAX_QUEUE_RUN_SIZE', `40000')dnl
define(`confMAX_MESSAGE_SIZE', `10000000')dnl
define(`confCHECKPOINT_INTERVAL',`3')dnl
define(`confTO_INITIAL',`40s')dnl
define(`confTO_CONNECT',`30s')dnl
define(`confTO_ICONNECT',`15s')dnl
define(`confTO_HOSTSTATUS',`1h')dnl
define(`confQUEUE_LA',`4')dnl
define(`confREFUSE_LA',`8')dnl
define(`confMAX_DAEMON_CHILDREN',`60')dnl
define(`confCONNECTION_RATE_THROTTLE',`16')dnl
define(`confSEPARATE_PROC', `False')dnl
define(`confEIGHT_BIT_HANDLING',`pass8')dnl
define(`confSINGLE_THREAD_DELIVERY', `False')dnl
define(`confCW_FILE',`/etc/mail/local-host-names')dnl
define(`confTO_IDENT', `0')dnl
define(`LOCAL_MAILER_FLAGS', `/59:@ADFMflmnqsw|')
DOMAIN(generic)dnl
MAILER(local)dnl
MAILER(smtp)dnl

Notes: We use procmail as local delivery agent. If you don't, then just delete the following:

FEATURE(`local_procmail', `/opt/local/bin/procmail')
define(`LOCAL_MAILER_FLAGS', `/59:@ADFMflmnqsw|')

... since the default local mailer and flags will work fine for your OS.

This config would be suitable for a pre-8.12 release of Sendmail if run as root - simply remove:

define(`confRUN_AS_USER',`smmsp')

6. Now compile Sendmail and check to see if SASL is working OK

cd sendmail
sh Build
cd ../obj.SunOS.5.6.sun4/sendmail/
./sendmail -d0.1 -bt < /dev/null

You should see output similar to this:

Version 8.11.4
Compiled with: 
MAP_REGEX LOG MATCHGECOS MIME7TO8 MIME8TO7 NAMED_BIND
NDBM NETINET NETUNIX NIS NISPLUS QUEUE SASL SCANF SMTP XDEBUG

Note the SASL, which indicates that the library was built into Sendmail correctly.

7. Configure Sendmail

Here we create our sendmail.cf configuration file, starting by choosing the most appropriate default file, then tweaking it until it suits us 100%. In our example, we choose the Solaris 2.x configuration as our base.

cd ../../cf/cf
cp generic-solaris2.mc myconfig.mc

Then we add a few options to suit our tastes, but the important part as far as getting the SMTP AUTH command to work are these lines:

define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5 LOGIN')
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5 LOGIN')dnl

This says the following: Allow users to authenticate using with the DIGEST-MD5, CRAM-MD5, or LOGIN protocols.
The second m4 command says, 'trust any user who has authenticated themselves using one of these protocols.'

Now we're ready to build the sendmail.cf file from the m4 source:

sh Build myconfig.cf

8. Test the new Sendmail configuration

The myconfig.cf will soon be installed into /etc/mail/sendmail.cf, but before we do that, we have one last testing opportunity:

../../obj.SunOS.5.6.sun4/sendmail/sendmail -C myconfig.cf -bt -d0.15 < /dev/null

If you like what you see, then you can install Sendmail and the new configuration file as follows:

/etc/init.d/sendmail stop
cp myconfig.cf /etc/mail/sendmail.cf
cd ../../sendmail/
sh Build install
/etc/init.d/sendmail start

If everything has gone to plan, your shiny new Sendmail daemon should be running, and you're ready to test the SMTP AUTH feature.

9. Create users and test the SMTP AUTH command

The next step is to populate /etc/mail/sasldb with usernames and passwords. These are added using the saslpasswd utility like this:

/opt/local/sbin/saslpasswd -u yourrealm test
Password: ****
Again (for verification): ****

We can list the users in this file with the sasldblistusers program:

/opt/local/sbin/sasldblistusers
user: test realm: mailserver.foo.com mech: DIGEST-MD5
user: test realm: mailserver.foo.com mech: CRAM-MD5
user: test realm: mailserver.foo.com mech: PLAIN

This shows us that the 'test' user can use SASL with any one of three authentication methods. We now need to check that Sendmail is ready and waiting to accept the SMTP AUTH command:

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mailserver.foo.com ESMTP server ready
EHLO foo
250- mailserver.foo.com Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-SIZE 10000000
250-DSN
250-ONEX
250-ETRN
250-XUSR
250-AUTH DIGEST-MD5 CRAM-MD5 LOGIN
250 HELP
QUIT
221 2.0.0 mailserver.foo.com closing connection
Connection closed by foreign host.

As you can see, the 250-AUTH command was returned, with a list of the valid authentication methods for this server. We're ready to set up an email client now.

10. Mail Client Configuration

This varies greatly between clients, but the principles are always the same. Find the configuration for your SMTP server, and select 'this server requires authentication' or the similar option.

The username will be formed from the name and 'realm' shown in the output of sasldblistusers: for example, in our previous output listing the username would be test@mailserver.foo.com.
There is an option to saslpasswd, -u DOM, that lets you change the realm (or domain part of the above address).
This is useful if you want to set the SMTP username and password to be the same as the POP password for certain users.

The password will be whatever you entered into saslpasswd before.

Once this is set up, try to send a message to yourself, and once it comes back to you, check the headers:

Received: from johnc (foo.com [xxx.xxx.xxx.xxx])
(authenticated)
by mailserver.foo.com (8.11.4/8.11.4) with ESMTP id f56dvg972875
for <johnc@foo.com>

The presence of the 'authenticated' header means that everything has been installed and is working successfully.

11. Server to Server authentication

It is also possible to use SMTP AUTH to authenticate between servers. This is perhaps most useful when used to allow a mail relay to authenticate to a central mail hub machine. The configuration is fairly straightforward:

Firstly, on the server that will be authenticated to - i.e. the true 'server' in the client->server authentication - you must create an account with saslpasswd as you would a regular user account:

/opt/local/sbin/saslpasswd -u foo mailrelay
Password: ****
Again (for verification): ****

This is all that need be done on this side of the connection.
Next, we must configure the authenticating server (or 'client').

the sendmail.mc file must be altered to include the following entry:

FEATURE(`authinfo',`btree -T<TMPF> /etc/mail/authinfo')  

or similar - in our example we choose to use btree, but dbm, etc are equally suitable. This instructs Sendmail to use an external AuthInfo map, located in /etc/mail/authinfo.

Following this change you must regenerate your sendmail.cf in the usual manner. The next step is to populate this file so that we may generate a map.
In our example, mailrelay.foo.com will authenticate to mailhub.foo.com with realm 'foo' and username 'mailrelay'. The corresponding AuthInfo file is shown below:

AuthInfo:mailhub.foo.com "U:mailrelay" "I:mailrelay" "P:secret" "R:foo" "M:DIGEST-MD5"

The line reads as follows: for server 'mailhub.foo.com', use (U)sername 'mailrelay', authentication (I)d 'mailrelay', (P)assword:'secret', (R)ealm 'foo', and (M)ethod 'DIGEST-MD5'. You need only specify a 'U' or 'I' entry - they are interpreted the same way by the server.

Following successful authentication, you will notice a log message such as:

Mar 29 16:07:50 mailrelay sendmail[3097]: [ID 702911 mail.info] AUTH=client, relay=mailhub.foo.com, mech=DIGEST-MD5, bits=128

That is basically all that is required to get server-server authentication set up. This allows you to remove your relay machines from your access maps and force them to authenticate in the same way your users do.

Another great use for this is to provide an audit trail through your mail system. I like to have entries on every server so that they can all authenticate with each other (by adding saslpasswd accounts and AuthInfo maps to every appropriate Sendmail installation.)

12. Troubleshooting your installation

Your best friend when troubleshooting is the log file. Start up Sendmail with a high LogLevel, e.g.:

/usr/lib/sendmail -bd -OLogLevel=14

... And watch for errors in the appropriate log file (typically /var/log/syslog in the case of Solaris, or /var/log/maillog elsewhere)

Common errors include unsafe files (chmod g-w / /etc /etc/mail /usr /usr/lib) and similar file permission issues that are usually quick to resolve. If you see something like:

Jan 21 02:02:07 yourhost sendmail[10558]: [ID 801593 mail.warning] g0L727a10558: AUTH failure (LOGIN): user not found (-20)

Then you probably forgot to use a realm when creating the sasl user account..

One problem that has reared its ugly head on several occasions is the inclusion in the logs of messages like this:

Unable to dlopen /usr/lib/sasl/libdigestmd5.so: ld.so.1: /usr/lib/sendmail: fatal: relocation error: file /usr/lib/sasl/libdigestmd5.so: symbol des_ecb_encrypt: referenced symbol not found

The solution here is to rebuild the SASL library without support for DIGEST-MD5. This can be accomplished by repeating step 3 with the addition of the option --disable-digest. Kerberos (use --disable-krb4) can cause similar problems too.

A tell-tale sign that you have library problems is that when running sasldblistusers, not all the authentication mechanisms you defined are listed. For instance, if DIGEST-MD5 didn't work correctly, the output would just look like:

/opt/local/sbin/sasldblistusers
user: test realm: mailserver.foo.com mech: CRAM-MD5
user: test realm: mailserver.foo.com mech: PLAIN

Rebuilding SASL is definitely the quickest fix for these problems. However, one caveat is that you must then remove the appropriate auth mechanisms from the Sendmail configuration, so repeat step 7, altering as appropriate, before copying it over /etc/mail/sendmail.cf

As far as client support goes, you should be able to support 99% of mail clients using CRAM-MD5, while the remainder use PLAIN, so the DIGEST-MD5 mechanism isn't going to be mission-critical in most cases.

Conclusion

SMTP AUTH is a useful command that allows you to maintain a closed mail relay whilst allowing selected mails to bypass this protection.
Although there are a few potential problems, hopefully this article will assist you in implementing your own authenticated SMTP server, and fixing it if it goes wrong.

John Cartwright <johnc@grok.org.uk>