ぶっちゃけ、Let's Encrypt で個人での証明書が取りやすくなったので、saslpasswd2 で SASL 用パスワードファイルを作って CRAM-MD5 を使うよりは、SSL で包んで PLAIN/LOGIN 使った方が楽です。OS の PAM 認証使えるし。

Berkeley DBの更新

OSデフォルトのBerkeley DBはBerkeley DB 1.85を利用しているが、この状態でsaslpasswd2を使ってSASL用パスワードデータベースを作成すると、maillogに

warning: SASL authentication failure: no user in db
というエラーが出る。
これはBerkeley DB 3以上に更新することで解決されるので、OSにdb42-4.2.52_5などをインストールすること。

Cyrus-SASL のビルドとインストール

SMTP Auth は Project Cyrus の Cyrus-SASL を使用する。
Cyrus-SASL ダウンロード バージョンは1と2があるが、必ず2を使用すること。

ダウンロードしたら展開してビルドしてインストールを行う。
make後にsaslpasswd2がlibdb-4.2などをリンクしていることを確認しておく。

% ./configure --with-openssl=/usr/local/ssl
   --with-dblib=berkeley
   --with-bdb-libdir=/usr/local/lib/db42
   --with-bdb-incdir=/usr/local/include/db42
   --enable-login --disable-otp --disable-anon --disable-gssapi
% make
% ln -s ldd ./utils/.libs/saslpasswd2
./utils/.libs/saslpasswd2:
   libsasl2.so.2 => /usr/local/lib/libsasl2.so.2 (0x2808f000)
   libdb-4.2.so.2 => /usr/local/lib/libdb-4.2.so.2 (0x280a6000)
   libc.so.7 => /lib/libc.so.7 (0x2817a000)
# make install
# cd /usr/lib/
# ln -s /usr/local/lib/sasl2
もしlibtoolでエラーやWARNINGが出た場合はOSのlibtoolを使ってみる。
% make clean
% rm libtool
% ln -s /usr/local/bin/libtool
% make
(省略)

ここで一旦saslpasswd2でパスワードファイルを作成してみる。
saslpasswd2の書式は

saslpasswd2 -u [MAIL_DOMAIN] [MAIL_USERPART]
となっている。
# saslpasswd2 -u example.com test
Password: *****
Again (for verification): *****

saslpasswd2が成功したら/etc/sasldb2が出来ているはずなので、 postfixから利用するために所有権の変更を行っておく。

# chown postfix:postfix /etc/sasldb2
※UID/GIDはpostfixで利用しているものに合わせる

saslauthd が使用するディレクトリの作成。

# mkdir -p /var/state/saslauthd/
# chown root:wheel /var/state/saslauthd/
# chmod 755 /var/state/saslauthd/

configureで使用するいくつかのオプションについて説明を。

--with-dblib=berkeley
--with-bdb-libdir=/usr/local/lib/db42
--with-bdb-incdir=/usr/local/include/db42
OS標準の古いBDBではなくBDB42を使用する。
--with-openssl=/usr/local/ssl
OpenSSL 込みでビルドする。
もしSSLライブラリが/usr/local/lib/以外にインストールされているなら、SSLライブラリの1つ上のディレクトリを指定する。
Makefile では[指定されたディレクトリ]/lib/を参照している。
--enable-login
Outlook Expressサポート用。

Postfix の再ビルドと再インストール

ここでは Postfix は既に導入済みとする。

Postfix のソースを削除していたらもう一度展開。
ソースがあるならそのディレクトリに入る。
今回は/usr/src/software/に展開した。

% cd /usr/src/software/postfix-2.3.9/

ここで Postfix を作り直すわけだが、もし

以上の事例に該当するのであれば次のようにビルド・インストールすること。
% make tidy
% make makefiles \
     CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/local/include/sasl" \
     AUXLIBS="-L/usr/local/lib -lsasl2"
% make
# make upgrade
新規に Postfix をインストールする場合は以下のようにビルド・インストールする。
% make makefiles \
     CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/local/include/sasl" \
     AUXLIBS="-L/usr/local/lib -lsasl2"
% make
# make install

Cyrus-SASL の設定と起動

SASL用設定ファイルは存在しないので新規作成する。
ファイル名は

/usr/local/lib/sasl2/{SASL を使用するアプリケーション名}.conf
になるので、今回は /usr/local/lib/sasl2/smtpd.conf となる。
pwcheck_method: saslauthd

設定が完了したらsaslauthdを起動する。
今回はOSのパスワード情報を利用するのでgetpwentとする。

# /usr/local/sbin/saslauthd -a getpwent

なお、OSで利用できる認証メカニズムを確認するには以下のコマンドを使う。

# saslauthd -v

OSのID/パスワードを利用する場合はsaslauthdを使い、getpwentオプションでPLAIN/LOGIN認証を使用する。
PLAIN/LOGIN認証はOSのIDとパスワードを利用するのでアカウント情報を一元管理できるが、パスワードを平文で送信することになるので別途postfixをSSL化すると良い。
CRAM-MD5などのチャレンジ&レスポンス認証を利用する場合はpwcheck_methodの行はそのままで良いが、saslpasswd2にパスワードを登録する必要がある。

saslauthd は postfix が使用するので、postfix の起動起動スクリプトに一緒に記述しておくと良いだろう。
FreeBSD では /usr/local/etc/rc.d/postfix.sh になる。

Postfix の設定と起動

postfix は master.cf と main.cf を変更。

main.cf は次の行を追加する。

smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_authenticated_header = yes にすると、Received ヘッダに認証されたユーザー名が表示される。
Received: from localhost (localhost [127.0.0.1])
   (Authenticated sender: griffon)
   by mail.griffonworks.net (Postfix) with ESMTP id ABA191CCB9
     for ; Thu, 10 May 2007 13:18:15 +0900 (JST)
表示するか否かは自由なのでお好みで。

master.cf は次の部分を変更する。
submission の

-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
から "permit_mynetworks" を削除して
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
とし、認証を通過したクライアントのみ通信可能にするように設定しておく。
テストが終わったら元に戻しておくこと。

設定が完了したら postfix を再起動する。
念のため stop → start のほうが良いかもしれない。

# postfix stop
# postfix start

テストしてみる

まずは TCP-25 で正常にメールが配送できるかを確認。

# postfix start
# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.griffonworks.net ESMTP Postfix
もしここで SMTP バナーが出ない場合 (Escape character is '^]'. で止まる) は Postfix stop してからログを確認。
今回の場合はこうなった。
May 10 12:46:59 leviathan postfix/postfix-script: starting the Postfix mail system
May 10 12:46:59 leviathan postfix/master[65523]: daemon started -- version 2.3.9, configuration /etc/postfix
May 10 12:47:02 leviathan postfix/smtpd[65550]: warning: unsupported SASL server implementation: cyrus
May 10 12:47:02 leviathan postfix/smtpd[65550]: fatal: SASL per-process initialization failed
May 10 12:47:03 leviathan postfix/master[65523]: warning: process /usr/local/postfix/bin/smtpd pid 65550 exit status 1
May 10 12:47:03 leviathan postfix/master[65523]: warning: /usr/local/postfix/bin/smtpd: bad command startup -- throttling
May 10 12:47:15 leviathan postfix/smtpd[65565]: warning: unsupported SASL server implementation: cyrus
May 10 12:47:15 leviathan postfix/smtpd[65565]: fatal: SASL per-process initialization failed
May 10 12:47:16 leviathan postfix/master[65523]: warning: process /usr/local/postfix/bin/smtpd pid 65565 exit status 1
May 10 12:47:16 leviathan postfix/master[65523]: warning: /usr/local/postfix/bin/smtpd: bad command startup -- throttling
May 10 12:47:43 leviathan postfix/postfix-script: stopping the Postfix mail system
May 10 12:47:43 leviathan postfix/master[65523]: terminating on signal 15
このエラーは、make 時に CCARGS に -DUSE_CYRUS_SASL フラグを忘れていたために発生した。
# Postfix 2.2系では -DUSE_CYRUS_SASL は不要。
そこで -DUSE_CYRUS_SASL を追加してリビルド後起動し直すと正常に起動した。

TCP-25 でのメール配送が正常に行えることを確認できたら、今度は SMTP Auth を使ってメール送信を行う。
まずは SMTP Auth で利用するパスワード文字列を用意する。
ヌル文字 (\0) を使わなければならないので少しだけ perl を使う。
また、BASE64 エンコードを行わなければならないので、nkf も使う。

今回は変換文字列の表示にちょっとした perl スクリプトを書く。
以下のようなスクリプトを適当なファイルに記述する。
今回は pwd.pl とした。

print "USERNAME\0USERNAME\0PASSWORD";
\0 (円マークに数字のゼロ) はヌル文字を表す。
ダブルクオーテーションはシングルではなくダブルなので注意。

USERNAME と PASSWORD は UNIX アカウントで使用している有効なものを指定する。
また、USERNAME が 2カ所有るので注意すること。
今回はユーザー名は username、パスワードは password とした。

スクリプトが書けたらそれを BASE64 エンコードする。

% perl up.pl | nkf -MB
dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcm
ちなみにこれは BASE64 エンコードしただけなので、以下のようにするとユーザー名とパスワードに変換される。
% echo "dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcm" | nkf -mB | perl -pe 's/\0/\n/g'
username
username
passwo
BASE64 エンコード文字列が出来たら SMTP Auth が正常に利用可能かをチェック。
接続するポート番号は SMTP (Port-25/TCP) ではなく Submission (Port-587/TCP) なので注意すること。
% telnet localhost 587
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 leviathan.griffonworks.or.jp ESMTP Postfix
バナーが出たら EHLO コマンドを送信する。
EHLO/HELO コマンドの後ろには適当な文字列を付けておく。
EHLO localhost
すると、以下のように返ってくるので "250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5" となっているかを確認。
250-leviathan.griffonworks.or.jp
250-PIPELINING
250-SIZE 20480000
250-VRFY
250-ETRN
250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
250 8BITMIME
確認できたら AUTH コマンドでユーザー認証を行う。
ここで先ほど取得した BASE64 エンコード文字列を使用する。
AUTH PLAIN dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcm
ユーザー名とパスワードが有っていれば "235 Authentication successful" となるが、間違っていれば "535 Error: authentication failed" となる。
認証が終わったら QUIT コマンドで終了する。

ログの確認

認証が成功すればログには特に何も出ないが、失敗した場合はmaillogにエラーが出力される。

SASLパスワードデータベースファイルが無い
warning: SASL authentication problem: unable to open Berkeley db /etc/sasldb2: No such file or directory
SASL IDが登録されていない
warning: SASL authentication failure: no secret in database
smtpdauthが起動していない
warning: SASL authentication failure: cannot connect to saslauthd server: No such file or directory
SASLパスワードデータベースファイルのパーミッション設定ミス
warning: SASL authentication problem: unable to open Berkeley db /etc/sasldb2: Permission denied
パスワード間違い
warning: SASL authentication failure: Password verification failed
warning: localhost[127.0.0.1]: SASL PLAIN authentication failed: authentication failure
成功
Dec 21 16:15:01 leviathan postfix/smtpd[83152]: B95DA1146A:
  client=localhost[127.0.0.1], sasl_method=PLAIN, sasl_username=test@example.com

各メーラーの設定

各メーラーによって設定が違うので、ここでは目に付いたメーラーの説明を行う。

mew
.mew.elもしくは.emacs に設定を追加する。
mew-config-alistで接続環境を切り替えるように設定してある場合は、以下のように変更。
; MSA(Submission)用ポートを指定する。
("smtp-port" . "587")
; SMTP-Authを使用する場合はSMTP-Authに必要なアカウントを記述。
; USERIDを記述する。
; 認証メカニズムがPLAIN/LOGINの場合はUNIXアカウントを、
; それ以外のチャレンジ&レスポンス認証の場合はsaslpasswd2で登録した
; UID+ドメイン名をメールアドレス型式で記述する。

("smtp-user" . "test@example.com")
; ("smtp-user" . "unixuserid")
; 使用する認証メカニズムを記述する。
("smtp-auth-list" . ("PLAIN" "LOGIN" "CRAM-MD5"))

実際にメールを送信しようとすると、mewの最下段に

SMTP PLAIN password (USERNAME@localhost):
と出るので、ここでSMTP-Authのパスワード(今回はUNIXアカウントのパスワード)を入力する。
失敗すると
SMTP PLAIN password is wrong! This mail has been queued to +queue
と出て送信できないが、成功すると
Sending in background...done
と出てバックグラウンドで送信を行う。
Microsoft Outlook Express
アカウントのプロパティで、「サーバー」ペインの「送信メールサーバー」にチェックを入れる。

アカウントのプロパティ

更に、「設定」ボタンを押して SMTP Auth で使用するアカウントとパスワードの設定を行う。
今回は UNIX アカウント (POP アカウント) とパスワードを使用するので以下のようにデフォルトのままにしておく。

送信メールサーバーの詳細設定

「詳細設定」ペインでポート番号の変更を忘れないように注意。

ポートの設定

MS OE は APOP を使用できないので、もし MS OE 以外のメーラーから MS OE に乗り換え、かつ APOP を使って認証していたならば POP に変更しなければならない。
電信八号
ここでは、メール受信は POP ではなく APOP を使用している。
赤枠の部分を適切に設定すること。

サーバー別の設定