Sendmail中的SASL SMTP认证

12/3/2006来源:Qmail人气:8728

一:概述

在现代网络环境中,mail relay是个讨论得非常热烈的话题,如何在公司的邮件服务器上
允许外部用户或者移动用户进行mail relay则是人们关注的焦点,随着标准化的SASL认证
的出现并结合开放源软件Sendmail新版本中对SMTP AUTH的支持,问题已经逐渐变得明朗
而易于解决。

二:目的

本文的主要目的是要在任何一台linux系统上,不论是什么版本,我们将编译Cyrus-SASL
和Sendmail 8.11来使系统支持SASL的SMTP认证,详尽解释如何编译和实现该功能及相关
的问题。

三:环境

我所用的编译和测试环境是Redhat Linux 6.1和VA Linux 6.2.4,使用cyrus-SASL 1.5.24
和Sendmail 8.11.4。在Redhat Linux 7.1上已经不需要再编译,只需要生成自己的
sendmail.cf即可。

四:步骤

1. 从ftp://ftp.andrew.cmu.edu/pub/cyrus-mail下载最新的cyrus-sasl-1.5.24.tar.gz
放在/home/jephe目录下

#cd /home/jephe
#tar xvfz cyrus-sasl-1.5.24.tar.gz
#cd cyrus-sasl-1.5.24
#./configure --enable-login (默认配置不支持login认证机制,但对Outlook ExPRess是必需的)
#make
#make install

这将自动安装所有的SASL库文件在/usr/local/lib/sasl/目录和头文件在/usr/local/include/目录,
但是Sendmail却在/usr/lib/sasl中寻找这些文件,因此最简单的办法就是创建符号链接,做下面的:

#cd /usr/lib
#ln -sf /usr/local/lib/sasl sasl
#cp /usr/local/lib/libsasl* /usr/lib

注意上面最后一步拷贝时把相关的符号链接文件也拷贝成了硬链接文件,再做下面的:

#cd /usr/lib
#rm -f libsasl.so libsasl.so.7
#ln -sf libsasl.so.7.1.8 libsasl.so
#ln -sf libsasl.so.7.1.8 libsasl.so.7

最后应该看上去象下面:

[[email protected] lib]$ ls libsasl* sasl -l
-r-x------ 1 root root 683 Jul 27 16:32 libsasl.la
lrwxrwxrwx 1 root root 16 Jul 27 16:32 libsasl.so -> libsasl.so.7.1.8
lrwxrwxrwx 1 root root 16 Jul 27 16:33 libsasl.so.7 -> libsasl.so.7.1.8
-r-x------ 1 root root 194079 Jul 27 16:32 libsasl.so.7.1.8
lrwxrwxrwx 1 root root 19 Jul 27 16:32 sasl -> /usr/local/lib/sasl

现在更改文件的许可权限

#chmod -R 500 /usr/local/lib/sasl /usr/local/lib/libsasl* /usr/lib/sasl /usr/lib/libsasl*

再编辑文件/etc/ld.so.conf,加下面的行

#/usr/lib/sasl

然后运行

#/sbin/ldconfig (不应该有任何错误警告显示)

2. 现在编译Sendmail,从www.sendmail.org下载最新的Sendmail.8.11.4.tar.gz也放于/home/jephe目录下

#cd /home/jephe
#tar xvfz sendmail.8.11.4.tar.gz
#cd /home/jephe/sendmail-8.11.4

放下面的行到devtools/Site/site.config.m4 (注意文件名不要弄错,用vi编辑新文件site.config.m4)

APPENDDEF(`confENVDEF', `-DSASL')
APPENDDEF(`conf_sendmail_LIBS', `-lsasl')
APPENDDEF(`confLIBDIRS', `-L/usr/lib/sasl')
APPENDDEF(`confINCDIRS', `-I/usr/local/include')

再用vi编辑一个新的配置文件放在cf/cf/config.mc,内容如下:(注意没有行号,此处的行号是
为了下面对每行进行解释的方便)

divert(-1) #
# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
# The Regents of the University of California. All rights reserved.
#

# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
#


1 VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
2 OSTYPE(linux)dnl
3 DOMAIN(generic)dnl
4 MAILER(local)dnl
5 MAILER(smtp)dnl

6 define(`confPRIVACY_FLAGS', `authwarnings,needmailhelo,novrfy,noexpn')dnl
7 define(QUEUE_DIR,`/var/spool/mqueue/q*')


8 FEATURE(`use_cw_file')dnl
9 FEATURE(`mailertable',`hash -o /etc/mail/mailertable')dnl
10 FEATURE(`domaintable',`hash -o /etc/mail/domaintable')dnl
11 FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable')dnl

12 dnl FEATURE(`genericstable',`hash -o /etc/mail/genericstable')dnl
13 dnl GENERICS_DOMAIN_FILE(`/etc/mail/genericsdomain')dnl
14 dnl FEATURE(allmasquerade)dnl
15 dnl FEATURE(masquerade_envelope)dnl
16 dnl MASQUERADE_AS(yourdomain.com)dnl

17 FEATURE(redirect)dnl
18 FEATURE(always_add_domain)dnl
19 FEATURE(`access_db')dnl
20 FEATURE(`blacklist_recipients')dnl

21 define(`confAUTH_MECHANISMS', `LOGIN PLAIN GSSAPI KERBEROS_V4 DIGEST-md5 CRAM-MD5')dnl
22 TRUST_AUTH_MECH(`LOGIN PLAIN GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')dnl
23 DAEMON_OPTIONS(`Port=smtp, Name=MTA')dnl
24 FEATURE(`no_default_msa')dnl
25 DAEMON_OPTIONS(`Port=587, Name=MSA, M=Ea')dnl

注: 第6行 增强sendmail的安全性
第7行 使用多个邮件队列增加性能
第12-16行 此处被注释了,如果你需要这些高级设置你可以去掉前面的dnl来使用它,
但你必须清楚地知道你在做什么。
第20-25行 这些行最重要,因为它是用于SMTP AUTH的必须设置


现在你能编译Sendmail.

#cd /home/jephe/sendmail-8.11.4
#sh ./Build (如果你已经不是第一次编译,则要sh ./Build -c 清除上一次编译的内容)
#cd cf/cf
#sh ./Build config.cf

现在准备编译Sendmail,编译之前,请备份你原先版本的sendmail执行文件和配置文件,一般为
/usr/sbin/sendmail 和 /etc/sendmail.cf

#cd ../../
#sh ./Build install
#cp -f config.cf /etc/mail/sendmail.cf
#cd /var/spool/mqueue
#mkdir q1 q2 q3 q4 q5 ( 你可以随时创建更多的目录,只要以q开头即可被立刻当作队列目录使用)
#/etc/rc.d/init.d/sendmail restart

确信在编译过程中你能看见下面的行:

...-I /usr/lib/include -DNEWDB -DSASL


新版本的sendmail放所有的配置文件在/etc/mail下,你可能需要做下面的事情:

a. #cp /etc/aliases /etc/mail/aliases

b. #cp /etc/sendmail.cw /etc/mail/local-host-names
c. #/etc/rc.d/init.d/sendmail restart

现在,编译应该结束,试着运行下面的命令检查输出

#/usr/sbin/sendmail -d0.1 -bv root |grep SASL

你应该看到象下面的行

NETUNIX NEWDB QUEUE SASL SCANF SMTP USERDB XDEBUG


3. 准备设置SASL认证

用vi编辑新文件/usr/lib/sasl/Sendmail.conf放下面的行

pwcheck_method:pam

既然Redhat Linux普遍使用PAM,我们就用PAM 认证,后面再讲SASLDB方式的认证。


现在放下面的行到/etc/pam.d/smtp (用vi编辑新文件smtp)

#%PAM-1.0

1 #auth required /lib/security/pam_deny
2 #auth required /lib/security/pam_shells.so

3 auth required /lib/security/pam_pwdb.so shadow md5

4 auth sufficient /lib/security/pam_listfile.so item=user sense=allow file=/etc/m
ail/smtpsuperusers.allow

5 auth required /lib/security/pam_listfile.so item=user sense=deny file=/etc/mail
/smtpusers.deny
6 auth required /lib/security/pam_listfile.so item=group sense=allow file=/etc/ma
il/smtpgroup.allow


如果你有大量的POP3用户,且想使用与POP3同样的密码,则可使用PAM认证方式,上面的各行解释如下

第1行 如果你想禁止所有人mail relay时,则简单地去掉前面的注释即可
第2行 如果打开了,则如果用户的登录shell不在/etc/shells中,则禁止mail relay
第3-6行 使用PAM_listfile模块通过外部文件控制认证

第3行 必须包括此行来使用文件/etc/shadow密码认证,放在最前面使得任何用户首先必须通过
密码认证,再检查后面的规则

第4行 只要用户被列在文件/etc/mail/smtpsuperusers.allow中,则允许relay
注意这里用的是sufficient不是required,你必须放这一行在最前面,这样
只要检测到用户被列在该文件中,则不再往下检查,无论如何允许mail relay

第5行 如果用户列在/etc/mail/smtpusers.deny,一行一个用户名,则禁止relay

第6行 如果用户所在的组列在/etc/mail/smtpgroup.allow且不在/etc/mail/smtpusers.deny中,
则允许relay



现在可以用telnet来测试:

#telnet localhost 25
Trying 127.0.0.1...
Connected to test.domain.com.
Escape character is '^]'.
220 test.domain.com ESMTP Sendmail 8.11.4/8.11.4; Sun, 10 Dec 2000 17:56:54 -0800
EHLO localhost
250-test.domain.com Hello IDENT:[email protected] [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-EXPN
250-VERB
250-8BITMIME
250-SIZE
250-DSN
250-ONEX
250-ETRN
250-XUSR
250-AUTH LOGIN PLAIN
250 HELP
quit
221 2.0.0 test.domain.com closing connection
Connection closed by foreign host.

你需要看见login和plain在那里,否则不能进行smtp认证。

Outlook Express使用LOGIN认证,Netscape Mail使用PLAIN认证,Foxmail 3.11 一般使用LOGIN认证。

既然上面这些我们最常用的邮件客户程序Outlook Express和Netscape Mail不支持加密的认证方式如
DIGEST-MD5和CRAM-MD5,那么我们最好也就不要enable加密认证方式,加密的认证方式必须要设置

pwcheck_method:sasldb,用PAM只能用于login和plain两种非加密方式。如果你的大多数客户都是outlook
Express和Netscape Mail用户,假设你的pwcheck_method设成PAM,但是又enable了加密认证,这样当邮件
客户端程序如The bat(支持cram-md5加密认证)向服务器连接进行认证时,它根据服务器端的可接受的认证
机制类型的响应而自动使用cram-md5认证,这样反而不能通过认证,因为你的pwcheck_method是PAM。然而,
如果你没有enable加密认证,则The Bat根据服务器的响应自动使用login的认证机制。也就是说,它会优先
使用加密的认证,只要服务器宣称支持的话。

(Foxmail 3.11宣称支持cram-md5,仍待测试)

下面说明SASLDB认证,当你仅有很少的用户,且想用另一个数据库不用/etc/shadow来验证,则可用
SASLDB的方式,在/usr/lib/sasl/Sendmail.conf中设置

pwcheck_method:sasldb

然后进行/usr/local/sbin以saslpasswd命令创建至少一个新用户,如

./saslpasswd jephe
PassWord: *******
Again (for verification): *******

这将创建文件/etc/sasldb,你不得不改变许可权限至400

#chmod 400 /etc/sasldb

然后可以检查哪些用户在数据库中

./sasldblistusers
user: jephe realm: smtp.domain.com mech: DIGEST-MD5
user: jephe realm: smtp.domain.com mech: PLAIN
user: jephe realm: smtp.domain.com mech: CRAM-MD5

如果有错误,检查/var/log/mailog和/var/log/messages.

现在再次用telnet检查,现在应该出现Digest-md5和cram-md5加密认证。

#telnet localhost 25
Trying 127.0.0.1...
Connected to test.domain.com.
Escape character is '^]'.
220 test.domain.com ESMTP Sendmail 8.11.4/8.11.4; Sun, 10 Dec 2000 17:56:54 -0800
EHLO localhost
250-test.domain.com Hello IDENT:[email protected] [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-EXPN
250-VERB
250-8BITMIME
250-SIZE
250-DSN
250-ONEX
250-ETRN
250-XUSR
250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
250 HELP
quit
221 2.0.0 test.domain.com closing connection
Connection closed by foreign host.

4. 设置你的Outlook Express and Netscape Mail

在‘工具'-‘帐号'-‘属性'-‘服务器‘-
'发送邮件服务器'中选中‘我的服务器需要认证'

然后在‘登录用户帐号'上填上

用户名和密码即可,如果不工作,则试着在用户名栏填入
你的用户名@你的realm冒号后面的服务器全称域名

如上面我的情况则用户名栏为[email protected]

对Netscape Mail,则在edit/preferences/mail servers/outgoing mail server username
中填入用户名即可。

5. 如何简单地只是使用telnet来测试SMTP AUTH?

是的,你能快速地测试是否哪个用户允许认证,就用#telnet localhost 25 能做到

a. 下载base64编码和解码器C语言源程序

http://www.sendmail.org/~ca/email/prgs/ed64.c

然后用下面的命令编译成linux上的执行文件

#gcc -o ed64 ed64.c -I/usr/include

命令可选项 -e ,象下面的用法

#[[email protected] /root]# ./ed64 -e jephe (把字符串jephe编码成base64格式的可打印字符串)
'jephe ->
'amVwaGU='

#[[email protected] /root]# ./ed64 VXNlcm5hbWU6 (把该base64字符串解码成ASCII字符串)
'VXNlcm5hbWU6 ->
'Username:'

b. #telnet localhost 25

250-smtp.domain.com Hello localhost.localdomain [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-SIZE
250-DSN
250-ONEX
250-ETRN

250-XUSR
250-AUTH LOGIN PLAIN
250 HELP
auth login
334 VXNlcm5hbWU6
amVwaGU=
334 UGFzc3dvcmQ6
bXlwYXNzd29yZA==
235 2.0.0 OK Authenticated


6. 常见问题解答

a. 当你每次改pwcheck_method:后面的参数时需要重启Sendmail,用killall -HUP sendmail

b. 为了临时禁止cram-md5和digest-md5加密认证,可以用#chmod 440 /etc/sasldb改变许可权
然后killall -HUP sendmail,则加密认证自动禁止;
也可以编译时用--disable-cram --disable-digest永久禁止

c. 为什么不需要用pwcheck后台程序检测密码?

因为Sendmail本身就以root运行,pwcheck后台程序是为那些不是以root身份运行的应用程序使用的
当这些应用程序运行时,它通过pwcheck来验证用户身份。

d. 如果你想在用PAM的同时,每当用户成功认证后更改SASL数据库,可在/usr/lib/sasl/Sendmail.conf
中使用
pwcheck_method:pam
auto_transition:true


这样你必须象上面介绍的一样设置好SASL,且确保/etc/sasldb权限为400,这样当每次用户通过PAM成功
认证后,/etc/sasldb数据库同时被更新。

e. 如果不工作,也许你需要试着加与/usr/lib/sasl/Sendmail.conf中同样的行
到/usr/lib/sasl/saslpassword.conf
pwcheck_method:pam

f. 如果你想在/var/log/maillog中log住用户认证的用户名,则在/etc/mail/sendmail.cf
中改loglevel=10。

g. 如果你用的是Redhat 7.1,你不需要编译,因为Redhat已经做过了编译工作,你要作的就是改
/usr/share/sendmail-cf/cf下的redhat.mc成下面的,然后生成自己的/etc/mail/sendmail.cf,
再根据上面的配置设置就可以了。

divert(-1)
dnl This is the sendmail macro config file. If you make changes to this file,
dnl you need the sendmail-cf rpm installed and then have to generate a
dnl new /etc/sendmail.cf by running the following command:
dnl
dnl m4 /etc/mail/sendmail.mc > /etc/sendmail.cf
dnl
include(`../m4/cf.m4')
VERSIONID(`linux setup for Red Hat Linux')dnl
OSTYPE(`linux')
define(`confDEF_USER_ID',``8:12'')dnl
undefine(`UUCP_RELAY')dnl
undefine(`BITNET_RELAY')dnl
define(`confAUTO_REBUILD')dnl
define(`confTO_CONNECT', `1m')dnl
define(`confTRY_NULL_MX_LIST',true)dnl
define(`confDONT_PROBE_INTERFACES',true)dnl
define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail')dnl
define(`ALIAS_FILE', `/etc/aliases')dnl
define(`STATUS_FILE', `/var/log/sendmail.st')dnl
define(`UUCP_MAILER_MAX', `2000000')dnl
define(`confUSERDB_SPEC', `/etc/mail/userdb.db')dnl
define(`confPRIVACY_FLAGS', `authwarnings,novrfy,noexpn,restrictqrun')dnl
define(`confAUTH_OPTIONS', `A')dnl
define(QUEUE_DIR,`/var/spool/mqueue/q*')
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
DAEMON_OPTIONS(`Port=25,Name=MTA')dnl
DAEMON_OPTIONS(`Port=587,Name=MSA,M=Ea')dnl
dnl define(`confTO_QUEUEWARN', `4h')dnl
dnl define(`confTO_QUEUERETURN', `5d')dnl
dnl define(`confQUEUE_LA', `12')dnl
dnl define(`confREFUSE_LA', `18')dnl
dnl FEATURE(delay_checks)dnl
FEATURE(`no_default_msa',`dnl')dnl
FEATURE(`smrsh',`/usr/sbin/smrsh')dnl
FEATURE(`mailertable',`hash -o /etc/mail/mailertable')dnl
FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable')dnl
FEATURE(redirect)dnl
FEATURE(always_add_domain)dnl
FEATURE(use_cw_file)dnl

FEATURE(use_ct_file)dnl
FEATURE(local_procmail)dnl
FEATURE(`access_db')dnl
FEATURE(`blacklist_recipients')dnl

EXPOSED_USER(`root')dnl
dnl This changes sendmail to only listen on the loopback device 127.0.0.1
dnl and not on any other network devices. Comment this out if you want
dnl to accept email over the network.
dnl DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')
dnl We strongly recommend to comment this one out if you want to protect
dnl yourself from spam. However, the laptop and users on computers that do
dnl not have 24x7 DNS do need this.

dnl FEATURE(`accept_unresolvable_domains')dnl
dnl FEATURE(`relay_based_on_MX')dnl
MAILER(smtp)dnl
MAILER(procmail)dnl
,