A hax.gs How-to covering:
Cyrus-SASL-2.1.19 + checkpw.c CRYPT PATCH + MySQL-3.23.x + Postfix-2.x
Author: Cody Tubbs 02/14/2005
This how-to is posted on and linked from http://www.postfix.org/docs.html

NOTE: This documention covers installing SASL2 with the checkpw.c crypt patch allowing sasl to query MySQL and validate authentication via encrypted passwords held in the database. We will review some of the severe issues encountered while trying to get things running properly with the titled software versions. I had read roughly ten other how-to's and roughly 100+ message board comments. Everyone had something different to say, especially conflicting instructions based on BSD vs Linux, and deprecated versions of the above packages.

I already had: Postfix2.x + MySQL + Courier-IMAP + Procmail + Amavisd-new + SpamAssassin + Clam-AV + SquirrelMail working fluent together, this how-to will also comply with a SASL2 inclusion within the above active setup. I will not go in any detail regarding the other packages. I did not have to modify any of them when configuring SASL2, other than Postfix. I already had Courier-IMAP parsing crypted passwords from MySQL.


Our first step will be cleaning and removing any other possibly versions of SASL you've attempted to install. This how-to will only work with Cyrus-SASL-2.1.19 (because there is not a crypt patch yet for 2.1.20).

Change directory to other version paths and type:

# make uninstall

Now we're on to installing Cyrus-SASL-2.1.19 with the checkpw.c crypt patch. Get both of these files:

# wget ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/cyrus-sasl-2.1.19.tar.gz
# wget http://frost.ath.cx/software/cyrus-sasl-patches/dist/2.1.19/cyrus-sasl-2.1.19-checkpw.c+sql.c.patch

Next we uncompress and patch:

# tar zxf cyrus-sasl-2.1.19.tar.gz
# cd cyrus-sasl-2.1.19
# patch -p1 < ../cyrus-sasl-2.1.19-checkpw.c+sql.c.patch

Now we configure and install:

# ./configure --enable-anon --enable-plain --enable-login --enable-sql --disable-krb4 \
  --disable-otp --enable-cram --enable-digest --with-mysql=/usr/include/mysql \
  --without-pam --without-saslauthd --with-pwcheck --without-dblib \
  --with-openssl=/usr/share/ssl --with-des=yes --with-plugindir=/usr/local/lib/sasl2 \
  --with-mysql=/usr/local/mysql/lib/mysql
# make

*** If it gives you an error of either of these two: ***

1) /usr/bin/ld: cannot find -lmysqlclient
2) sql.c:66:19: mysql.h: No such file or directory

Re configure with "--with-mysql=/usr/include/mysql" or your according path. Either of these two paths may be wrong, so set them accordingly if these do not work.

# make install

If you have not already installed postfix 2.x yet, install Cyrus-SASL-2.1.19 first (and we will cover Postfix installation at the end). Although if you have already installed Postfix 2.x, don't worry, as for we will now check the Postfix binary with ldd and see what libsasl library it links to. If it links to an old one, we will remove it and link to the newest one after a fresh SASL 2.1.19 install, make sure it has libcrypt linked.

My postfix binary is located at: /usr/sbin/postfix, if you have a correct PATH ENV defined you can locate yours by typing `which postfix`.

# ldd `which postfix`
    libmysqlclient.so.10 => /usr/local/mysql/lib/mysql/libmysqlclient.so.10
    libz.so.1 => /usr/lib/libz.so.1
    libm.so.6 => /lib/tls/libm.so.6
    libsasl2.so.2 => /usr/lib/libsasl2.so.2
    libpcre.so.0 => /lib/libpcre.so.0
    libdb-4.0.so => /lib/libdb-4.0.so
    libnsl.so.1 => /lib/libnsl.so.1
    libresolv.so.2 => /lib/libresolv.so.2
    libc.so.6 => /lib/tls/libc.so.6
    libcrypt.so.1 => /lib/libcrypt.so.1
    libdl.so.2 => /lib/libdl.so.2
    libpthread.so.0 => /lib/tls/libpthread.so.0
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2

There you'll see it linked to /lib/libcrypt.so.1 and /usr/lib/libsasl2.so.2

Now here's the reason a huge percentage of the people with errors are having authentication problems, you need to do an:

# ls -al /usr/lib/libsasl2.so.2
lrwxrwxrwx 1 root root 33 Feb 12 14:01 /usr/lib/libsasl2.so.2 -> /usr/local/lib/libsasl2.so.2.0.19

If it is linked to libsasl2.so.2.0.10, that is incorrect. If it is linked to linksasl2.so.2.0.20, that is also incorrect. I tried installing sasl 2.0.20 first and forgot to clean up before downgrading so that the crypt patch would work. This will screw everything up.

Type:

# ls -al /usr/local/lib/libsasl2.so.2.0.19
-rwxr-xr-x  1 root  root  380219 Feb 12 14:31 /usr/local/lib/libsasl2.so.2.0.19

Make sure it isn't symlinked anywhere. If not, that's a start.

Now type:

# ldd /usr/local/lib/libsasl2.so.2.0.19
    libdl.so.2 => /lib/libdl.so.2
    libresolv.so.2 => /lib/libresolv.so.2
    libcrypt.so.1 => /lib/libcrypt.so.1
    libc.so.6 => /lib/tls/libc.so.6
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2

Make sure it is linked to libcrypt.so.1. If it is not, you did not cleanup or compile correctly, or something is still linked incorrectly. This was the root of all that is evil when I was debugging (for hours).

Now delete and re symlink the one the postfix binary is linked to, to the correct one like so:

# rm -fr /usr/lib/libsasl2.so.2
# ln -s /usr/local/lib/libsasl2.so.2.0.19 /usr/lib/libsasl2.so.2

Now you can verify by typing:

# ldd `which postfix`
    libmysqlclient.so.10 => /usr/local/mysql/lib/mysql/libmysqlclient.so.10
    libz.so.1 => /usr/lib/libz.so.1
    libm.so.6 => /lib/tls/libm.so.6
    libsasl2.so.2 => /usr/lib/libsasl2.so.2
    libpcre.so.0 => /lib/libpcre.so.0
    libdb-4.0.so => /lib/libdb-4.0.so
    libnsl.so.1 => /lib/libnsl.so.1
    libresolv.so.2 => /lib/libresolv.so.2
    libc.so.6 => /lib/tls/libc.so.6
    libcrypt.so.1 => /lib/libcrypt.so.1
    libdl.so.2 => /lib/libdl.so.2
    libpthread.so.0 => /lib/tls/libpthread.so.0
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2

Then do:

# ldd /usr/lib/libsasl2.so.2
    libdl.so.2 => /lib/libdl.so.2
    libresolv.so.2 => /lib/libresolv.so.2
    libcrypt.so.1 => /lib/libcrypt.so.1
    libc.so.6 => /lib/tls/libc.so.6
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2

Both postfix and libsasl2 are linked to libcrypt, that's excellent.

Now another problem everyone was having is wondering where the default smtpd.conf is stored. Above we configured with "--with-plugindir=/usr/local/lib/sasl2" so that solves your problems, the smtpd.conf is located in /usr/local/lib/sasl2

You will also most likely have a /usr/lib/sasl and a /usr/lib/sasl2. On my server these are not used and causing a headache. Do not worry about /usr/lib/sasl, but as for /usr/lib/sasl2, just do this:

# mv /usr/lib/sasl2 /usr/lib/sasl2.old
# ln -s /usr/local/lib/sasl2 /usr/lib/sasl2
# ls -al /usr/lib | grep /usr/local/lib/sasl2
lrwxrwxrwx  1  root  root  20 Feb 12 06:17 sasl2 -> /usr/local/lib/sasl2

Okay now here's my smtpd.conf:

pwcheck_method: auxprop
auxprop_plugin: sql
allowanonymouslogin: no
allowplaintext: yes
mech_list: LOGIN PLAIN
sql_engine: mysql
#srp_mda: md5
srvtab: /dev/null
opiekeys: /dev/null
password_format: crypt_trad
sql_user: postfix
sql_passwd: pfpwd
sql_hostnames: localhost
sql_database: postfix
sql_select: SELECT password FROM mailbox WHERE username = '%u@%r'
log_level: 10
sql_verbose: yes

There are 3 different methods you can define for password_format:

1) plaintext - Passwords are stored in plaintext format - This is default if not defined
2) crypt - Passwords are stored as modular crypt hashes (md5 or blowfish crypt)
3) crypt_trad - Passwords are stored as des crypt hashes (2 character salt crypt)

If you are using option 2, crypt, you can un-punch "srp_mda: md5". I never tested with crypt (md5/blowfish), thus I don't know if you really need that argument defined in the conf.

Okay now the question is how are you storing passwords within MySQL. I am using encrypt('password') when entering users into MySQL (from perl scripts), thus it's standard crypt(3). This is another reason loads of people are having issues... they simply do not know what kind of encryption algorithm their passwords are stored with. I am using standard des crypt, thus I used crypt_trad.

Here's part of my main.cf for Postfix 2:


smtpd_recipient_restrictions =
  permit_sasl_authenticated,
  permit_mynetworks,
  #reject_non_fqdn_hostname,   
  reject_non_fqdn_sender,
  reject_non_fqdn_recipient,
  reject_unauth_destination,
  reject_unauth_pipelining,
  reject_invalid_hostname,
  reject_rbl_client opm.blitzed.org,
  reject_rbl_client list.dsbl.org,
  reject_rbl_client bl.spamcop.net, 
  reject_rbl_client sbl-xbl.spamhaus.org
broken_sasl_auth_clients = yes
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks
smtpd_sasl_auth_enable = yes
#smtp_sasl_auth_enable = yes
smtpd_sasl_local_domain =
smtpd_sasl_security_options = noanonymous

And here is a line from my master.cf:

smtp      inet  n       -       n       -       -       smtpd -v

Note the -v, it will turn on verbosity, you can remove that when you're finished, along with the log_level and sql_verbose entries in smtpd.conf.

To use Sasl2 with MySQL and Postfix2 you do not need saslauthd, postfix will do all of the work for you. We did not include saslauthd within our compilation. You also do not need to compile sasl2 with PAM either, it's not needed anymore. You also do not need sasldb.

If you have not compiled Postfix2 yet, here's how I do it:

# make tidy
# make -f Makefile.init makefiles 'CCARGS=-DHAS_MYSQL \
  -I/usr/local/mysql/include/mysql -DUSE_SASL_AUTH -I/usr/local/include/sasl' \
  'AUXLIBS=-L/usr/local/mysql/lib/mysql -lmysqlclient -lz -lm \
  -L/usr/local/lib -lsasl2'
# make install

Now go through the above steps if that was your first time installing postfix. Make sure everything is correct. Now populate your MySQL database accordingly and start postfix:

# `which postfix` start

After reviewing debugging information within /var/log/messages and confirming everything works, you can let an rc file start the daemon for you (ie: "service postfix start"). You can then remove the verbosity settings within your smtpd.conf and also remove the "-v" in master.cf for the smtp line (this will prevent log bloat). This how-to supports PLAIN and LOGIN at the moment, you can configure TLS/SSL support if you'd like, I will not cover that.


Author: Cody Tubbs 02/14/2005


Leave your Comments / Questions / Suggestions (* = required)
(By submitting your question, you agree to opt-in our personal (non-distributed and private) email list, so that we can reply to your comment and answer your questions, all information you enter is kept private).



* Name:
E-Mail:
Your URL:
City: State: Country:
* Comments:
*

mmx <p_intron [^AT^] hotmail.com>
TH - Tuesday, March 08, 2005 at 03:51:03 (CST)

Mar 8 16:47:35 mail postfix/smtpd[22958]: SQL engine 'mysql' not supported
Mar 8 16:47:35 mail postfix/smtpd[22958]: auxpropfunc error no mechanism available

i can not send use smtp auth

Cody Tubbs <sasldoc [^AT^] hax.gs>
USA - Wednesday, March 09, 2005 at 14:15:36 (CST)

Try specifying auxprop_plugin as "sql" rather than "mysql" in smtpd.conf. Also make sure you compiled with mysql.
mmx <p_intron [^AT^] hotmail.com>
Bangkok, TH - Thursday, March 10, 2005 at 05:10:23 (CST)

Yes I coppy any text from your web site here no change any thing except password and domain database
Cody Tubbs <sasldoc [^AT^] hax.gs>
Tyler, TX USA - Thursday, March 10, 2005 at 09:50:46 (CST)

When you ./configure SASL2, when it's complete, please paste any warnings it prints.
Andres Romero <andresramilo [^AT^] yahoo.com.br>
Rio, RJ Brasil - Thursday, March 17, 2005 at 01:27:06 (CST)

I´ve used your howto and i cant compile postfix with support to sasl and mysql at same time. if i get a compilation using only -DHAS_SASL the authentication doesnt work. it seems that smtpd cant connect to mysql. It´s absolute necessary have postfix compiled with mysql support to sasl authentication works? If i compile with -DHAS_MYSQL and -DHAS_SASL like in your howto i get "no sasl support" in my log even checking postfix with ldd and see that libsasl2.so.2 is linked. what can i do? One more question, this patch is absolutely necessary for the sql plugin works with auxprop?
Cody Tubbs <sasldoc [^AT^] hax.gs>
Tyler, TX USA - Thursday, March 17, 2005 at 03:27:36 (CST)

If you look at how I compile postfix2 I do not use -DHAS_SASL, I use -DUSE_SASL_AUTH That is most likely your error. The patch is not necessary unless you want to store the passwords encrypted within MySQL, which should be required if you ask me.
Tony <tchentchen[^AT^]gmail.com>
USA - Saturday, March 19, 2005 at 17:53:41 (CST)

I'm currently trying to get this to work with SASL 2.1.20, and it's not working. Why did you downgrade to 2.1.19 with patch? I'm getting these problems:
Mar 19 18:34:57 salad postfix/smtpd[11121]: [ID 197553 mail.info] connect from localhost[127.0.0.1]
Mar 19 18:35:05 salad postfix/smtpd[11121]: [ID 947731 mail.warning] warning: SASL authentication failure: Can only find author (no password)
Mar 19 18:35:05 salad postfix/smtpd[11121]: [ID 947731 mail.warning] warning: localhost[127.0.0.1]: SASL PLAIN authentication failed
Mar 19 18:35:06 salad postfix/smtpd[11121]: [ID 197553 mail.info] disconnect from localhost[127.0.0.1]

Not sure what do at this point. All my libraries are properly linked as far as I can tell and I've got all the logging turned on verbose and this is as much as it's telling me.

Cody Tubbs <sasldoc [^AT^] hax.gs>
tyler, tx USA - Saturday, March 19, 2005 at 20:26:35 (CST)

Was that with 2.1.20?
Tony <tchentchen[^AT^]gmail.com>
USA - Sunday, March 20, 2005 at 22:03:47 (CST)

Yep...it sure is. Actually, I have more information...

Here's some more debug info. Here's a conversation with my SMTP server.
220 myhost.mydomain.com ESMTP Postfix
EHLO mydomain.com
250-myhost.mydomain.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250 8BITMIME
AUTH PLAIN Y3luAGN5bgozNDU=
535 Error: authentication failed
QUIT
221 Bye

And here's my syslog:
Mar 20 22:41:04 salad postfix/smtpd[11244]: [ID 197553 mail.info] smtpd_sasl_aut henticate: sasl_method PLAIN, init_response Y3luAGN5bgozNDU=
Mar 20 22:41:04 salad postfix/smtpd[11244]: [ID 197553 mail.info] smtpd_sasl_aut henticate: decoded initial response cyn
Mar 20 22:41:04 salad postfix/smtpd[11244]: [ID 947731 mail.warning] warning: SA SL authentication failure: Can only find author/en (no password)
Mar 20 22:41:04 salad postfix/smtpd[11244]: [ID 947731 mail.warning] warning: lo calhost[127.0.0.1]: SASL PLAIN authentication failed

Also, I have MySQL running in debug mode and postfix/SASL isn't even talking to it for authentication purposes. I have postfix installed with MySQL support installed and I know it works because I'm using it to store config options.


Cody Tubbs <sasldoc [^AT^] hax.gs>
Tyler, TX USA - Sunday, March 20, 2005 at 22:51:26 (CST)

Well if you look at their patch directory, the nearest patch available is for 2.1.19:
http://frost.ath.cx/software/cyrus-sasl-patches/dist/
has a patch for 2.1.17 and 2.1.19. So if you applied this patch to 2.1.20 that may be your problem, I havn't ever seen the problem you're stating with the patches applied to the version they were made for. Also have you put MySQL is verbose mode and checked what is actually being queried, I'm assuming nothing in regards to a few things it should be querying for. Apply to 2.1.19 according the above instructions, everything should work that way.

Chris Bell
San Francisco, CA USA - Thursday, March 24, 2005 at 23:57:02 (CST)

I was having troubles until I found this... everything works like it should now. Thanks for clearing things up and getting me on the right track!!!
Jano <andreabarbieri6 [^AT^] tin.it>
Italy - Friday, March 25, 2005 at 15:33:08 (CST)

Hi,
I had the same issue as Tony, the problem appears when your password (and maybe user) begins with a number example:

perl -MMIME::Base64 -e 'print encode_base64("user\0user\08g6h8j6k6");'

will give a wrong encoded string cause of \0+number, so you should try:

perl -MMIME::Base64 -e 'print encode_base64("user\0user\0"."8g6h8j6k6");'
...joining 2 strings.
This worked for me, hope this helps you too.

Tony <tchentchen[^AT^]gmail.com>
USA - Saturday, March 26, 2005 at 03:49:16 (CST)

I was so hopeful that was the answer, but no avail. One thing I noticed is that I do not have a shared lib for libsql in my /usr/local/lib/sasl2 dir. I've got ones for everything else. I'm suspecting this might be it since it's not even hitting the MySQL database to authenticate. I think the reason why SASL didn't build a shared lib for libsql might be because I'm using a pre-built MySQL for Solaris. What do you guys think?
Jano <andreabarbieri6 [^AT^] tin.it>
Italy - Saturday, March 26, 2005 at 10:51:52 (CST)

As far as I can see from your logs, SASL cannot simply decode your password, decoding the base64 encrypted string you pass Y3luAGN5bgozNDU= you get something like :
cyn^@cyn
345

That is not a valid PLAIN login, You should get something like :
cyn^@cyn^@345

I would suggest You to try a new base64 encoded string, maybe post how You got it and a verbose log showing the errors.

Ruben
- Friday, April 01, 2005 at 07:28:48 (CST)

Thank you a bunch... you have solved my problem :D I was getting crazy, till i found this howto. My problem was I was applying the checkpw.c crypt patch to Cyrus-SASL-2.1.20 ... Thanks again :)
Tony <tchentchen[^AT^]gmail.com>
USA - Monday, April 04, 2005 at 04:47:07 (CDT)

OK. Jano was right. I was using a bad encoded string, but even then, it sitll didn't work. Like I said, it's not even hitting the database. I'm thinking it's a SASL lib/postfix problem. My suspicion it's the libsql not having its shared counterpart. I'm about to try compiling my own MySQL, recompiling SASL, and recompiling Postfix. Wish me luck.
Jason Broe
USA - Tuesday, April 26, 2005 at 07:40:59 (CDT)

Helped me get it working. So glad I found this!
Gregory <mok [^AT^] kde.ru>
- Saturday, April 30, 2005 at 11:24:21 (CDT)

Excellent how-to, many thanks Cody. BTW,
password_format: crypt
works fine for me with blowfish crypted passwords (aka FreeBSD MD5 [32/32])in MySQL.

Benjamin Engle <progman [^AT^] prog-x.com>
PA USA - Monday, June 27, 2005 at 04:39:52 (CDT)

I have this setup with password_format: crypt but when i send mail, it wont take the password - but it will take the md5 sum. Its not trying to look at the password as md5, whats wrong? I also have srp_mda: md5
Max
Netherlands - Thursday, July 07, 2005 at 10:43:15 (CDT)

Wow, after struggling with this for ages, after reading howto after howto, after I've read most mailing list archives front to back... This one finally works. Granted, it's using all the non-crypted passwords, but the bloody thing works.
Wow. You guys rock.

Greg <sasl_patch [^AT^] 11g.ch>
nyon, vd Switzerland - Thursday, August 04, 2005 at 11:38:09 (CDT)

Hi,
The passwords in my mysql db are generated like this:
$pwd = rand();
$salt = substr($pwd, 3,2);
$passwdcrypte = crypt($passwd,$salt);

your code looks like this:
/* crypt(3)-ed password? */
+ if (password_format != PASSWORD_FORMAT_CLEARTEXT) {
+ /* compare password */
+ if (auxprop_values[0].name && auxprop_values[0].values && auxprop_values[0].values[0] && strcmp(crypt(passwd, salt), auxprop_values[0].values[0]) == 0)
+ return SASL_OK;
+ else
+ ret = SASL_BADAUTH;
+ }
How can both values be equal, they will never be since the salt is different and random no ?

Cody Tubbs <sasldoc [^AT^] hax.gs>
Tyler, TX USA - Monday, August 15, 2005 at 05:43:08 (CDT)

In response to Greg:
Please read these two following links. The first explains standard crypt(3) passwords and how the salt is obtained via the first two characters of the encrypted string (thus even though you randomize them in your code, the decryption mechanism still knows the salt (if designed correctly ofcourse)).
The second link is regarding MySQL Encrypt functions ... they should easily be portable into your Perl code/MySQL inserts. Hope that helps! (ps. That is not my patch, it's owner is derived from the link the patch was obtained from).