近頃のsendmail事情

(FreeBSD PRESS No.4)

梅本肇 / ume@mahoroba.org

1 CF vs. cf

 最近、sendmailのバージョンはどんどん上がるのだけど、「今まで使っていたsendmail.cfは使えるの?」とか、「新しいバージョン用のsendmail.cfはどうやって作れば良いの?」とかよく聞かれます。
 これまで、CFという非常に良くできた生成ツールがあり、日本語で書かれた非常に詳しいドキュメントが添付されていたおかげで、かなり楽をしてsendmail.cfを作ることができました。 少なくとも日本ではかなり多くのサイトが CF を使ってsendmail.cfを生成していると思います。 ところが、最近、ちょっと事情が変わってきています。
 この記事を書いている時点でのsendmailの最新バージョンは8.11.3です。 FreeBSD 4.2-RELEASEに添付されているバージョンは8.11.1で4.3-RELASEでは8.11.3になることでしょう。 8.10.X以降に対応したsendmail.cfのフォーマットのバージョンはV9/Berkeleyとなっています。 しかし、最新であるCF 3.7Wpl2*1)が対応しているのはV8/Berkeleyまでであり、以降、新しいCFがリリースされないまま、2年が過ぎています。
 幸いなことに、sendmail.cfの後方互換性は非常に良く、CFが生成したsendmail.cfは最新バージョンのsendmailでも、sendmailの新しい機能を使わないのであれば、そのまま使用することができます。
 ただし、4.2-RELEASE以降では/usr/libexec/mail.localがrootにsetuidされなくなりましたので、FreeBSD添付のsendmail.cfあるいは最近のcfで生成していないsendmail.cfをお使いの方は注意が必要です。 この変更に伴って、例えばCFが生成しているsendmail.cfを使用していると、ローカル宛のメイルが受け取れなくなります。 この問題への対処として、
  1. 従来通りmail.localをsetuidする。
  2. sendmail.cfを変更する。
のどちらかを行う必要があります。 1)の場合は、
chmod u+s /usr/libexec/mail.local
を実行します。 FreeBSDをmake installworldすると元に戻ってしまいますので、/etc/make.conf
.if ${.CURDIR} == "/usr/src/libexec/mail.local"
BINMODE=4555
INSTALLFLAGS=-fschg
.endif
と書いておくと良いでしょう。 2)の場合は、sendmail.cfでMlocalのF=にSを追加します。CFをお使いなら、
LOCAL_MAILER_FLAG_ADD='S'
を加えます。 どうしてもfetchmailのmda指定を使用したいなど特別の事情がない限り、できるだけ2)を選択しましょう。

2 cfによるsendmail.cfの生成

2.1 cfとは

 日本ではCFがあまりに普及しすぎていることもあり、sendmail自体が元々想定しているsendmail.cfの作り方を知らない方がほとんどだと思われます。 また、存在は知っていても、非常に難解であると尻込みされている方も多いと思います。 と言う筆者も、8.9.3の頃まではずっとCFを使っており、存在を知りつつも使うことはありませんでした。
 sendmail.cfを直に書くのは非常に大変です。 cfはsendmailの設定項目をマクロ化し、容易にsendmail.cfを作成できるように支援するマクロパッケージです。 sendmail.orgからオリジナルのsendmailを入手し展開するとcf/というディレクトリがあります。 cf/cf/にcdしてゴニョゴニョしてやれば、自分好みのsendmail.cfが作れるという寸法です。
 cfはm4というUn*xに標準的に装備されている汎用のマクロ言語プロセッサを使用しています。 もちろんm4はFreeBSDにも標準で付いていますので、ご心配なく。
 cf/READMEにcfについての詳しい説明があります。 しかし、cfについては日本語で読めるドキュメントがほとんどないのが難点かもしれません。 最近、cf/READMEの邦訳を行っているグループがあります。 参考にすると良いでしょう。
cf/READMEの日本語訳プロジェクト - cfプロジェクト(仮称)
URL: http://www.isoternet.org/~y-koga/cf/

2.2 FreeBSDにおけるsendmail.cfの生成方法

 FreeBSDをインストールしたときに付いてくるデフォルトのsendmail.cfはcfを用いて生成されています。 元ネタになるファイルはfreebsd.mcで/usr/src/etc/sendmail/にあります。
 /usr/src/以下を展開していれば、cd /usr/src/etc/sendmailしてmakeを実行してあげると、freebsd.cfというファイルができます。 これが/etc/mail/sendmail.cfです。 そのまま使うのであれば、sendmail.cfという名称で/etc/mail/にコピーしてあげれば良いです。
 freebsd.mcを自分用にカスタマイズして使いたければ、まず、freebsd.mcを例えばmyconfig.mcにコピーし、myconfig.mcを編集するようにします。 この場合、make myconfig.cfを実行するとmyconfig.mcからmyconfig.cfが生成されます。 生成されたmyconfig.cfを/etc/mail/sendmail.cfへコピーしてあげれば完了です。

2.3 /usr/share/sendmail/cf/での生成

 今までに述べた方法では/usr/src/以下が展開されていないとsendmail.cfを生成することはできませんでした。 4.2-RELEASE以降では、cf関連ファイルが/usr/share/sendmail/cf/にインストールされるようになりましたので、/usr/src/以下にソースを展開していなくても生成できるようになりました。 例えば、/usr/share/sendmail/cf/cf/に自分用のmyconfig.mcを用意し、make myconfig.cfで生成できます。 しかし、残念ながら、freebsd.mcはインストールされませんので、一から.mcファイルを書くか、どこかからベースになる.mcファイルを持ってこないといけません。

2.4 /etc/mail/での生成

 実は、4.2-RELEASEでのsendmail.cf生成環境はまだ発展途上で、最近の4.2-STABLEでは、/etc/mail/の下でsendmail.cfが生成できるようになっています。 この時、/usr/share/sendmail/cf/にインストールされているcf関係のマクロが使用されます。 また、freebsd.mcが/etc/mail/にインストールされるようになりました。
 /etc/mail/にmyconfig.mcという自分用の.mcファイルを用意し、/etc/make.confに
SENDMAIL_MC=/etc/mail/myconfig.mc
書いておくと、図1のように作業できるようになります。
図1 /etc/mail/でのsendmail.cfの生成
# cd /etc/mail
# make
/usr/bin/m4 -D_CF_DIR_=/usr/share/sendmail/cf/ /usr/share/sendmail/cf/m4/cf.m4  /etc/mail/myconfig.mc > /etc/mail/myconfig.cf
# make install
install -c -m 444 /etc/mail/myconfig.cf /etc/mail/sendmail.cf
 加えて、accessやmailertableなどのsendmailが使用するマップファイルをmakemapしたり、sendmailの再起動ができたりとか、非常に便利になっています。(表1)
表1 /etc/mail/Makefileのターゲット
ターゲット内容
allcf、マップ、aliases を生成します
cf.mcファイルから.cfファイルを生成します
maps各種機能用マップを生成します
aliasesエリアスファイルを生成します
install.cfファイルを/etc/mail/sendmail.cfとしてインストールします
start/etc/defaults/rc.confまたは/etc/rc.confで設定されているフラグを使用してsendmailを起動します
stopsendmailを停止します
restartsendmailを再起動します
 4.3-RELEASEではこの機能が使えることでしょう。

2.5 freebsd.mcの概要

 FreeBSDに標準的に付いて来るsendmail.cfは非常に高機能になっており、多くの場合、DNSがきちんと設定されており、正引き・逆引き共に間違いなく自分のホスト名解決ができれば、そのまま使うことができます。
 まず、freebsd.mcがどのような機能を持っているかを解説します。 リスト1を見て下さい。 これは、執筆時点、つまり、4.3-RELEASEに向けてコード凍結直後の4.3-BETAに添付されているfreebsd.mcです。 コメント部分は訳してあります。
 dnlで始まる部分はコメントです。 また、divert(-1)からdivert(0)の間もコメントです。
リスト1 freebsd.mc
divert(-1)
#
# Copyright (c) 1983 Eric P. Allman
# Copyright (c) 1988, 1993
#	The Regents of the University of California.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#	This product includes software developed by the University of
#	California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

#
#  これは 4.4 BSD をベースとするシステム一般用の設定です。
#  カスタマイズする場合は、あなたの環境に見合った適切な名称のファイルに
#  コピーし、そちらを変更して下さい。
#
#  .mc ファイルの最良のドキュメントは
#  /usr/share/sendmail/cf/README または
#  /usr/src/contrib/sendmail/cf/README です。
#

divert(0)
VERSIONID(`$FreeBSD: src/etc/sendmail/freebsd.mc,v 1.10.2.8 2001/03/06 02:12:59 gshapiro Exp $')
OSTYPE(bsd4.4)
DOMAIN(generic)

FEATURE(access_db, `hash -o /etc/mail/access')
FEATURE(blacklist_recipients)
FEATURE(local_lmtp)
FEATURE(mailertable, `hash -o /etc/mail/mailertable')
FEATURE(relay_based_on_MX)
FEATURE(virtusertable, `hash -o /etc/mail/virtusertable')

dnl リアルタイムブラックホールリストを利用する場合はコメントを外し
dnl ます (推奨!)。情報は http://maps.vix.com/rbl/ にあります。
dnl FEATURE(dnsbl)
dnl RBL 用のあなた独自のリジェクトメッセージを設定したい場合、こちらを
dnl 代わりに有効にします。
dnl FEATURE(dnsbl, `blackholes.mail-abuse.org', `"550 Mail from " $&{client_addr} " rejected, see http://mail-abuse.org/cgi-bin/lookup?" $&{client_addr}')

dnl その他の DNS ベースなブラックホールリスト
dnl -----------------------------------------
dnl MAPS リアルタイム SPAM スットパー (RSS): http://mail-abuse.org/rss/
dnl FEATURE(dnsbl, `relays.mail-abuse.org', `"550 Mail from " $&{client_addr} " rejected; see http://mail-abuse.org/cgi-bin/nph-rss?" $&{client_addr}')

dnl MAPS ダイアルアップユーザリスト (DUL): http://maps.vix.com/dul/
dnl FEATURE(dnsbl, `dialups.mail-abuse.org', `"550 Mail from dial-up rejected; see http://mail-abuse.org/dul/enduser.htm"')

dnl ORBS も DNS ベースなブラックホールリストの多くを提供しています。
dnl http://www.orbs.org/usingindex.html を参照。

dnl ダイアルアップユーザはコメントを外しこれを適切に定義しましょう。
dnl define(`SMART_HOST', `your.isp.mail.server')

dnl デフォルトである /etc/mail/local-host-names の位置を変更したい場合
dnl は、最初の行のコメントを外し、次の行をコメントにします。
dnl define(`confCW_FILE', `-o /etc/mail/sendmail.cw')
define(`confCW_FILE', `-o /etc/mail/local-host-names')

dnl IPv4 に加えて IPv6 でもメイルを受信したい場合は、以下の行の両方と
dnl ものコメントを外します。
dnl DAEMON_OPTIONS(`Name=IPv4, Family=inet')
dnl DAEMON_OPTIONS(`Name=IPv6, Family=inet6')

define(`confMAX_MIME_HEADER_LENGTH', `256/128')
define(`confNO_RCPT_ACTION', `add-to-undisclosed')
define(`confPRIVACY_FLAGS', `authwarnings,noexpn,novrfy')
MAILER(local)
MAILER(smtp)
VERSIONID(`$FreeBSD: src/etc/sendmail/freebsd.mc,v 1.10.2.6 2001/02/28 02:50:54 gshapiro Exp $')
 この.mcファイルのバージョンをあらわします。 CFのDEF_ID=に相当します。
OSTYPE(bsd4.4)
 OS種別です。 これによって、ローカルメイラのパスなどのOS固有の値が設定されます。 引数は、cf/ostype/*2)にある.m4ファイルから.m4を除いた名前です。 CFのOS_TYPE=に相当します。 これは必須です。 FreeBSDはbsd4.4のままで変更する必要ありません。
DOMAIN(generic)
 サイト固有の設定をcf/domain/に置いておき、取り込むことができます。 引数は、cf/domain/にある.m4ファイルから.m4を除いた名前です。 独自の設定ファイルを使わない場合はgenericを指定しておきます。
FEATURE(access_db, `hash -o /etc/mail/access')
 アクセスデータベース機能を有効にします。 アクセスデータベースを使うことで、特定ドメインからのメイルを許可したり拒否することができるようになります。 CFのSPAM_LIST=に近いですが、より細かい設定ができます。 加えて、リレー可否の設定も行うことができます。 基本的に、SPAM対策やリレーの可否はaccess_dbのみで全てまかなうことができます。
 外部データベースを使用しますので、/etc/mail/accessを変更した場合、makemapコマンドを使用して/etc/mail/access.dbに反映させます。 /etc/mail/accessを変更しても、sendmailの再起動は必要ありません。 なお、-oが指定されていますので、本機能を使用しないのであれば、/etc/mail/accessを用意する必要はありません。
FEATURE(blacklist_recipients)
 access_dbを使って、ローカルの特定の受信者宛や自ドメインの特定ホスト宛のメイルをブロックすることができるようになります。 ローカルユーザを指定する場合、「ユーザ名@」と書きます。
 CFのREJ_RCPT_LIST=に近いですが、access_dbを使用する点が異なります。
FEATURE(local_lmtp)
 ローカルへのメイル配送時にLMTP*3)を使用します。 CFには特にこれに対応する設定項目はありませんが、
LOCAL_MAILER_FLAG_ADD='z' LOCAL_MAILER_ARGS='mail.local -l'
を指定するのと等価です。 FreeBSDのローカル配信エージェントである/usr/libexec/mail.localはLMTP対応 ですので、指定しておきます。
FEATURE(mailertable, `hash -o /etc/mail/mailertable')
 特定ドメイン向けのメイルの配送経路を/etc/mail/mailertableで指定できるようになります。 CFのMAILERTABLE=に相当します。 なお、外部データベースを使用しますので、/etc/mail/mailertableを変更した場合、makemapコマンドを使用して/etc/mail/mailertable.dbに反映させます。 /etc/mail/mailertableを変更しても、sendmailの再起動は必要ありません。 なお、-oが指定されていますので、本機能を使用しないのであれば、/etc/mail/mailertableを用意する必要はありません。
FEATURE(relay_based_on_MX)
 送られてきたメイルの宛先のホスト部についてMXレコードを引いて、MXレコードが自ホストを指していた場合には、そのメイルのリレーを許可します。 これにより、セカンダリMXを受け持つ際にそのサイトへのリレーを許可する設定を入れる必要がなくなります。
 CFのLOWER_MX_OK=yesに相当します。
 この設定によって、SPAMのリレーに悪用されることはありません。 しかし、外部の者が彼らのサイト宛のメイルをリレーするのに利用する抜け道があります。 便利な機能ですが、気になる方は使わないようにコメントアウトした方が良いかもしれません。*4)
FEATURE(virtusertable, `hash -o /etc/mail/virtusertable')
 CFではバーチャルドメインの運用をするにはUSERTABLE_MAPS=を使用しますが、これに等価な機能はcfにはありません。 cfではvirtusertableを使用します。 USERTABLE_MAPSではドメイン毎にマップファイルを用意するのに対し、virtusertableは全てのバーチャルドメインをひとつのマップファイルで管理します。 また、USERTABLE_LOCAL_REWRITE=yesで提供される発信者アドレスの書き換えはcfではgenericstableで行います。
 virtusertableはオリジナルアドレスと実際の配信先との組からなります。 配信先がユーザ部のみの場合、ローカル宛となります。
 オリジナルアドレスに@domainのようにユーザ部が書かれていない場合は、そのドメイン宛のメイルは全て単一の配信先に配信されます。 また、オリジナルアドレスのユーザ部は%1として渡されますので、
@foo.org %1@example.com
のように書くこともできます。
 なお、外部データベースを使用しますので、/etc/mail/virtusertableを変更した場合、makemapコマンドを使用して/etc/mail/virtusertable.dbに反映させます。 /etc/mail/virtusertableを変更しても、sendmailの再起動は必要ありません。 なお、-oが指定されていますので、本機能を使用しないのであれば、/etc/mail/virtusertableを用意する必要はありません。
 バーチャルドメイン宛のメイルを自ホストで受け取ることができるように、オリジナルアドレスのホスト部は全てクラス{w}またはクラス{VirtHost}に記述されている必要があります。 クラス{VirtHost}はVIRTUSER_DOMAIN()またはVIRTUSER_DOMAIN_FILE()で指定します。
 クラス{w}には/etc/mail/local-host-namesに書いたホストが反映されます。 freebsd.mcでは元々confCW_FILEが指定されていますので、local-host-namesに書く方が簡単かもしれません。
define(`confCW_FILE', `-o /etc/mail/local-host-names')
 DOMAIN(generic)内でFEATURE(`use_cw_file')が指定されています。 ローカルとして扱うホスト名を表すクラス{w}に/etc/mail/local-host-namesからホスト名を取り込みます。 -oが指定されていますので、本機能を使用しないのであれば、/etc/mail/local-host-namesを用意する必要はありません。
define(`confMAX_MIME_HEADER_LENGTH', `256/128')
 MIMEヘッダの最大長を制限します。 MIMEヘッダによるバッファオーバーラン攻撃からクライアントを守ります。
define(`confNO_RCPT_ACTION', `add-to-undisclosed')
 To:ヘッダが付いていない場合に、
To: undisclosed-recipients:;
を付加します。
 CFのNO_RECIPIENT_ACTION=add-to-undisclosedと等価です。
define(`confPRIVACY_FLAGS', `authwarnings,noexpn,novrfy')
 プライバシ・フラグを設定します。 CFのPRIVACY_FLAGS=と等価です。
MAILER(local)
MAILER(smtp)
 配信エージェントを指定します。 引数は、cf/mailer/にある.m4ファイルから.m4を除いた名前です。 localとsmtpは必須です。
 以上がfreebsd.mcの概要です。 通常使いそうな機能が既にほとんど定義されていることがお分かり頂けたことと思います。
 さて、外部ファイルを使用する機能が多いことに気付かれたことと思います。 昔はメイルを受け取るべきホスト名やメイル配送経路などのホスト固有の設定をsendmail.cf 内に記述していました。 しかし、最近は外部ファイルに書いおくのがお奨めです。 そうしておくと、sendmail.cfをいじる必要性がほとんどなくなり、同じsendmail.cfを複数のホストで共有できるようになります。 また、データベースを使用するものについては、マップが大きくてもsendmailの起動が遅くなるようなことはありませんし、変更を加えてもsendmailを再起動する必要がありません。 ただし、外部データベースを変更した場合は、図2のようにmakemapを実行してデータベースを作り直す必要があります。
図2 makemapの実行
# makemap hash /etc/mail/mailertable < /etc/mail/mailertable
 これまで見てきましたように、freebsd.mcでは、標準で/etc/mail/access、/etc/mail/mailertable、/etc/mail/virtusertable、/etc/mail/local-host-namesが外部ファイルとして利用できるように設定されていますので、これらのファイルを適宜編集することで、ほとんどのニーズに対応できることと思います。 なお、これらのうちlocal-host-names以外はデータベースです。
 設定を積極的に外部ファイルに出していくかどうかはサイトの管理方針や好みによると思いますので、うまく使い分けていくと良いでしょう。

2.6 自分好みのsendmail.cfに仕立てる

 では、多くの人がカスタマイズしそうな機能について説明していきます。

2.6.1 メイルを受け取りたいホスト名

 多くのサイトが、ドメイン名宛のメイルを受け取るように設定しているでしょう。 CFではACCEPT_ADDRS=です。 cfでは、/etc/mail/local-host-namesに受け取りたいドメイン名を書いておきます。 8.9.X以前はこのファイル名はsendmail.cwだったので間違わないよう注意しましょう。
 この設定はもちろん.mcファイルに書くこともできます。 この場合、LOCAL_DOMAIN()を使って、以下のように.mcファイル内で直接書きます。
LOCAL_DOMAIN(`example.com')
 CFのACCEPT_LOWER=に相当するマクロはcfにはありません。 等価な処理をさせたい場合は、LOCAL_RULE_0を使って直接ルールを埋め込みます。 リスト2にACCEPT_LOWER=yes相当の例を挙げておきます。
リスト2 ACCEPT_LOWER=yesの代用
LOCAL_RULE_0
R$* < @ $* .$m. > $*		$1 < @ $m. > $3

($mはホスト名のドメイン部分を保持している定義マクロです。 もちろん、ドメイン名を明に指定しても構いません。)

2.6.2 メイルのFrom:

 freebsd.mcだと、メイルの発信時に自動的に付加されるFrom:にはホスト名が含まれます。 ドメイン名だけにしてホスト名は隠したい場合は、CFだと
FROM_ADDRESS='$m'
を指定していることでしょう。 cfでは、
MASQUERADE_AS(`$m')
FEATURE(`masquerade_envelope')
と書きます。 ただし、REWRITE_GENERIC_FROM=yes相当の動きをし、最初から From:にFQDNが指定されていた場合も、ホスト名が消えるよう書き換えられてしまいます。 あらかじめFrom:が付いていた場合は書き換えないようにするには、
FEATURE(`limited_masquerade')
も併せて指定すると良いでしょう。 このオプションを指定すると、MASQUERADE_DOMAIN()またはMASQUERADE_DOMAIN_FILE()で指定されたドメインのみが書き換えられるようになります。
 また、CFでRECIPIENT_GENERIC=yesを指定して、To:やCc:などの配送先指定フィールドがユーザ名のみの時にドメイン名を補うようにしている場合、
FEATURE(`allmasquerade')
も併せて指定します。

2.6.3 信頼できるユーザ

 メイリングリストを運用している場合、CFのTRUSTED_USERS=で信頼できるユーザを追加していることと思います。 cfではconfTRUSTED_USERを使用して
define(`confTRUSTED_USERS', `uucp majordom')
のように指定します。 あるいは、
define(`confCT_FILE', `-o /etc/mail/trusted-users')
を指定して、/etc/mail/trusted-usersに信頼できるユーザ記述するようにすることもできます。 ちなみに、以前はこのファイルはsendmail.ctという名称でしたが、変更になっています。

2.6.4 デフォルトの配送先

 ファイアウォールなどがあり特定のSMTPサーバを経由しないとメイルを出せないような環境や、ダイアルアップなどでISPのSMTPサーバを経由してメイルを出すようにするには、CFだと、
DIRECT_DELIVER_DOMAINS='example.com'
DEFAULT_RELAY='smtp:gateway.example.com'
のような設定をしていると思います。 cfだとSMART_HOSTを使います。
define(`SMART_HOST', `gateway.example.com')
を指定することで、ローカル宛以外のメイルはgateway.example.com宛に送られるようになります。
 CFのDIRECT_DELIVER_DOMAINS=に相当するマクロはありませんので、組織内宛はダイレクトに送るようにするには、/etc/mail/mailertableに
example.com smtp:example.com
.example.com smtp:%1.example.com
というように書いてあげれば良いです。 ここで、第1フィールドは転送したいドメイン名です。 第2フィールドは転送先の指定で、メイラ:ホスト名のペアです。 上記例の1行目はexample.comにのみマッチしそのサブドメインはマッチしません。 サブドメインを含めて全てマッチさせたい場合は2行目も必要です。
 上記例での第2フィールドに指定されたホスト名はMXレコードを検索されます。 MXレコードを検索させたくない場合は、
example.com smtp:[mail.example.com]
のようにホスト名を[]で囲んで記述します。
 mailertableを使用せず、sendmail.cf内に書きたい場合は、LOCAL_NET_CONFIGを用いてルールを直接記述します。 例えば、上記例だとリスト3のようになります。
リスト3 LOCAL_NET_CONFIGによる記述例
LOCAL_NET_CONFIG
R$* < @ $* example.com. > $*	$#smtp $@ $2example.com. $: $1 < @ $2example.com. > $3

2.6.5 アドレスの補完

 ファイアウォール内などでメイル宛先のDNSを引けない場合や、自サイトがワイルドカードMXを使っている場合には注意が必要です。 CFだとデフォルトがCANON=oneとなっており、メールアドレスのアドレス部が1語であるもののみネームサーバを参照して補完を試みるようになっていますので問題は生じませんが、cfだとデフォルトは補完を行うようになっていますので、問題が生じることがあります。
FEATURE(`nocanonify', `canonify_hosts')
を入れておきましょう。

2.6.6 エンベロープFROMのチェック

 8.9以降ではエンベロープFROMにDNSで引けないドメイン名が含まれていると、メイルの受け取りを拒否するようになっています。 ファイアウォール内とかDNSで送信者のアドレスを引くことができないような環境だと、
FEATURE(`accept_unresolvable_domains')
を加えて、エンベロープFROMのチェックを行わないようにする必要があります。 これはCFでUSE_SENDER_DNS_CHECK=noを指定するのと等価です。
 また、エンベロープFROMにドメイン部がないと、メイルを受け取りません。 そのようなメイルも受け取りたい場合は、
FEATURE(`accept_unqualified_senders')
を指定します。 CFでNEED_SENDER_DOMAIN=noとCHECK_FROM_FQDN=noを指定するのに相当します。

2.6.7 リレー制限

 おそらく、多くのサイトが、サイト外からのメイルのリレーは禁止するが、サイト内からのメイルはリレーを許可していることでしょう。
 freebsd.mcでは、relay_based_on_MXによるリレーのみが許可されています。 また、access_db機能が組み込まれていますので、access_dbを使ってアクセス制御を行うことができます。 つまり、access dbでRELAYとして許可されたホストあるいはドメインからのリレーが許可されます。 これ以外にも、access_dbは非常に多くの機能を持っています。
 あるいは、RELAY_DOMAINを使って以下のように.mcファイル内に直接書いておくこともできます。
RELAY_DOMAIN(`example.com')
RELAY_DOMAINには、ドメイン名やIPアドレスを指定することができます。
 また、FEATURE(relay_entire_domain)を指定すると、クラス{m}で定義されたドメイン全体に対してリレーが許可されるようになります。

2.6.8 Message-Id:不正

 CFでHDR_REJECT_BADMID=yesを指定し、Message-Id: ヘッダの内容に@が含まれない場合に受信を拒否している方も多いでしょう。 cfにはこれに対応するマクロはありませんのでリスト4のようにLOCAL_RULESETSを使って記述します。 この例では、HDR_REJECT_ACTION=discardの場合と等価になっています。
リスト4 Message-Id:不正メイルへの対処
LOCAL_RULESETS
HMessage-Id: $>CheckMessageId

SCheckMessageId
R< $+ @ $+ >		$@ OK
R$*			$#discard $: discard

3 SMTP AUTHを使おう

3.1 SMTP AUTHとは

 世の中にはPOP before SMTPという仕掛けがはびこっています。 多くのSPAMが飛び交う昨今、会員などの許可された人だけがSMTPサーバを使える仕掛けは必須と言えるでしょう。
 しかし、ここでちょっと疑問を持って頂きたい。 メイルを出すのに使われるプロトコルはあくまでSMTPです。 なぜPOPで認証しないといけないのでしょうか?
 答えは簡単です。 SMTPが認証の枠組を持っていなかったからです。 それを補うために考え出されたのがPOPbefore SMTPというやり方です。 要するに、メイルを出す前にPOP接続して、一定時間だけPOP接続元のホストからのメイルのリレーを受け付けるようにするわけです。
 しかし、今はそんなまどろっこしいことをしなくても、SMTP自体が認証の枠組を持っています。 sendmailは8.10.XからSMTP AUTH*5)に対応しています。
 ここで問題になるのがsendmail.cfです。8.10.Xというとsendmail.cfのフォーマットはV9/Berkeleyです。 SMTP AUTHの設定をしようとすると、V9/Berkeleyを使わなければなりません。 しかし、CFが対応していなのです。 つまり、CFを使っている限り (真っ当な方法では) SMTP AUTHは使えないということになります。
 ここであきらめてはいけません。 POP before SMTPを駆逐するために、もとい、SMTP AUTHを使うためにも、是非cfを使えるようになりましょう。

3.2 SASLライブラリのインストールと設定

 SMTP AUTHはSASLライブラリを使用します。 SASLはRFC2222に定義される認証のための枠組です。
 FreeBSDではports / packagesになっていますので、ports でインストールするなら、/usr/ports/security/cyrus-sasl/でmake installするだけです。
 SASLで利用できる認証方式として、CRAM-MD5、DIGEST-MD5、LOGIN、PLAINなどがあります。 LOGINとPLAINは一応base64でエンコードはされていますが生パスワードがネットワーク上を流れますので、基本的に使わない方が良いでしょう。 ただし、NetscapeやOutlookExpressはSMTP AUTHに一応対応しているものの、NetscapeはPLAINのみ、Outlook ExpressはLOGINのみしか使えませんので、これらのメイラに対応させたい場合はPLAINとLOGINを有効にしないといけません。 広く使用されているメイラですので、悩ましいところです。
 SASL認証は/usr/local/etc/sasldb.dbに格納されているパスワードによって行われます。 加えて、LOGINとPLAINについては、/etc/passwdを使うこともできます。 また、設定によってPAMなどを参照するようにもできます。
 デフォルトでは、sasldbしか見ませんので、/etc/passwdを使用しPLAINまたはLOGINを許可したい場合は、
pwcheck_method: pwcheck
と書いた/usr/local/lib/sasl/Sendmail.confを用意しましょう。
 ports / packagesでインストールすると、FreeBSDのブート時にに/usr/local/etc/rc.conf/pwcheck.shでpwcheckが起動されるようになります。 pwcheckはSASLライブラリをリンクしているアプリケーションがroot権限で動いていなくても、/etc/passwdを用いて認証できるように使用されるデーモンです。 pwcheck_methodにpwcheckを指定すると使用されます。 認証に/etc/passwdを使用しないのであれば、pwcheckを起動しないようにしてしまっても構いません。

3.3 ユーザ管理

 sasldbにパスワードを登録するには、sasldbに書き込みできる権限*6)でsaslpasswdコマンドを実行します。 例えばユーザumeを登録するには saslpasswd umeを実行します(図3)。 この時、realmはデフォルトでsaslpasswdコマンドを実行したホスト名になります。 realmを指定したい場合-uオプションを使用します。 ユーザを削除するのは-dオプションです。
図3 SASLパスワードの登録
ume@mille:125# saslpasswd  ume
Password: ********
Again (for verification): ********

(パスワードはエコーバックされません)
 オフィシャルドメイン名をconfDOMAIN_NAMEで明示的に指定している場合は注意して下さい。 hostnameコマンドが返すホスト名と異なる名前を指定している場合、saslpasswdコマンドでユーザを登録する際に、-uオプションで同じホスト名を指定してあげる必要があります。*7)
 現在登録されているユーザを確認したい場合はsasldblistusersコマンドを実行します(図4)。
図4 SASL登録ユーザの一覧表示
ume@mille:127# sasldblistusers 
user: ume realm: mille.mahoroba.org mech: DIGEST-MD5
user: ume realm: mille.mahoroba.org mech: PLAIN
user: ume realm: mille.mahoroba.org mech: CRAM-MD5

3.2 SASL対応sendmailの作成

 次に、sendmailにSASLライブラリをリンクします。 /etc/make.confにリスト5の3行を追加します。 こうしておくと、make buildworldした際に必ず有効になりますので、FreeBSDを作り直した際にsendmailが元に戻ってしまうことなく便利です。 ここで、-D_FFR_UNSAFE_SASLは、後で述べるGroupReadableSASLFileを使えるようにするオプションで、sasldbをsendmail以外のアプリケーションと共有する際に必要となります。*8)
リスト5 SASL用フラグ
SENDMAIL_CFLAGS=-I/usr/local/include/sasl -DSASL -D_FFR_UNSAFE_SASL
SENDMAIL_LDFLAGS=-L/usr/local/lib
SENDMAIL_LDADD=-lsasl
 さあ、sendmailを作り直しましょう。図5のようにmakeを行います。
図5 SASL対応sendmailの作成
# cd /usr/src/lib/libsmutil
# make obj && make depend && make
# cd /usr/src/usr.sbin/sendmail
# make obj && make depend && make && make install

3.2 sendmail.cfでのSASL関係ルール

 動くsendmail.cfの元となる.mcファイルが既に用意されているなら、リスト6を追加して生成しなおすだけで、ルール的にはOKです。
リスト6 SMTP AUTHのための.mcファイルの設定
define(`confDONT_BLAME_SENDMAIL', `GroupReadableSASLFile')
define(`confRUN_AS_USER', `root:mail')
define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5')
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5')
 では、それぞれの意味を説明していきましょう。
define(`confDONT_BLAME_SENDMAIL', `GroupReadableSASLFile')
define(`confRUN_AS_USER', `root:mail')
SASLライブラリをports / packagesでインストールした場合、Cyrus IMAPサーバからの利用を考慮した設定となっています。 具体的には、imapdからアクセスできるように、SASLのパスワードデータベースである/usr/local/etc/sasldb.dbは所有者: cyrus、グループ: mailとなっており、グループに対するリード権限が与えられています。(図6)
そのため、sendmail側で、sasldbにグループに対するリード権限が付いていても許してあげる必要があります。 sendmailからしかSASLを使わないのであれば、この設定を入れずに、sasldbをrootだけが読めるようにしても構いません。
図6 sasldbのパーミッション
-rw-r-----  1 cyrus  mail  16384 Feb  9 00:48 /usr/local/etc/sasldb.db
define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5')
 AUTHで使用する認証メカニズムの一覧を指定します。 実際には、ここで指定したもののうち実際にSASLライブラリで使用できるものが有効となります。 デフォルトでDIGEST-MD5とCRAM-MD5は含まれているので、LOGINやPLAINを使わないのであれば特に指定する必要はありません。
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5')
 リレーを許可する認証メカニズムを指定します。 この例では、DIGEST-MD5かCRAM-MD5で認証されればリレーを許可します。 LOGINやPLAINによる認証でも許可したい場合は、それらも含めます。

3.4 動作確認

 さぁ、ではsendmailがちゃんとSMTP AUTH対応になっているか試してみましょう。 SMTP AUTHに対応していれば、EHLOコマンドに対して、使用できる認証メカニズムの一覧を返します。(図7)
図7 EHLOに対する応答
ume@mille:147> telnet localhost smtp
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 mille.mahoroba.org ESMTP Sendmail 8.11.3/8.11.3/mille; Sun, 4 Mar 2001 03:47:34 +0900 (JST)
EHLO localhost
250-mille.mahoroba.org Hello ume@localhost [::1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-SIZE
250-DSN
250-ONEX
250-ETRN
250-XUSR
250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5	<----- 使用できる認証メカニズム
250 HELP
 これで、SMTP AUTHで認証されればリレーが許可されるようになります。
 では、実際にメイルを出してみます。Mewの開発版である1.95では、
(setq mew-smtp-auth t)
と設定すると、SMTP AUTHを喋るようになります。 SMTP AUTHで認証するユーザ名がローカルのログイン名と異なる場合は、
(setq mew-smtp-user "ユーザ名")
で設定します。 また、認証に使用したい認証メカニズムをmew-smtp-auth-listで設定できるようになっています。
 図8はMewでメイルを出し、SMTP AUTHのパスワードを入力しているところです。
図8 MewでSMTP AUTHを使う
MewでSMTP AUTHを使う

3.3 Received:ヘッダへの記録

 SMTP AUTHで認証された場合、Received:ヘッダに(authenticated)が付加されます。 しかし、これだとどのように認証されたのかわかりません。 デバッグなどでもう少し詳しい情報が欲しいかもしれないでしょう。
define(`_REC_AUTH_', `_REC_FULL_AUTH_')
を加えると、どの認証メカニズムを使って誰が認証されたのか記録されるようになります。 図9の例はSMTP AUTHを使用した場合のReceived:ヘッダです。 CRAM-MD5を使用して認証されていることがお分かりだと思います。
図9 認証時のReceived:ヘッダ
Received: from mille.mahoroba.org (ume@mille.mahoroba.org [2001:200:301:0:202:2dff:fe0a:6bee])
	(authenticated as ume with CRAM-MD5)	<----- CRAM-MD5で認証された
	by peace.mahoroba.org (8.11.3/8.11.3/peace) with ESMTP/inet6 id f23KAE373219
	for <ume@FreeBSD.org>; Sun, 4 Mar 2001 05:10:14 +0900 (JST)
	(envelope-from ume@mahoroba.org)
 ただし、_REC_AUTH_はドキュメントに書かれていない内部変数なので、将来的に使えるかどうかはわかりません。きちんと公開仕様に従うなら、confRECEIVED_HEADERを使うべきでしょう。(リスト7)
リスト7 confRECEIVED_HEADERを使用した設定例
define(`confRECEIVED_HEADER', `$?sfrom $s $.$?_($?s$|from $.$_)
	$.$?{auth_type}(authenticated$?{auth_ssf} (${auth_ssf} bits)$.)
	$.by $j ($v/$Z)$?r with $r$.$?{daemon_family}/${daemon_family}$. id $i$?{tls_version}
	(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})$.$?u
	for $u; $|;
	$.$b$?g
	(envelope-from $g)$.')

3.4 SMTP AUTH導入時の注意事項

 近頃はSMTP AUTHを使えるメイラは徐々に増えて来ているようですが、まだまだ少ないのが現状でしょう。 メジャーであるNetscapeやOutlook Expressも一応サポートしていますが、生パスワードを使うPLAINまたはLOGINのみです。
 PLAINまたはLOGINを有効にする場合、STARTTLSを併用し暗号路を確保することも検討した方が良いでしょう。*9)
 さらに、NetscapeなどいくつかのメイラはSMTPサーバがEHLOに250-AUTH LOGIN PLAINと答えると、無条件にSMTP AUTHを使用します。 認証にsasldbのみを使用するようにサーバ側を設定する場合、あらかじめ全てのユーザをsasldb側に登録しておかないと、そのようなメイラでは認証に失敗しメイルが出せないということになります。 このため、PLAINやLOGINを有効にすると、段階的移行が難しくなります。
 auto_transitionというPLAIN認証されれば自動的にsasldbに反映するオプションもあります。 しかし、アプリケーションがsasldbに書き込めるようにしないといけませんし、一旦反映されたあとユーザがパスワードを変更してもsasldb側はそのままですので、ユーザが混乱するかもしれません。
 また、セキュアな認証メカニズムを使用する場合、認証には基本的にはsaslsbを使うことになります。 つまり、POPなどメイル受信に使用するパスワードと連係しておらず、サーバ側では受信用パスワードと送信用パスワードを別々に管理することになります。 しかし、受信用パスワードと送信用パスワードを別々に扱えないメイラも存在します。
 Cyrus IMAPサーバ*10)を導入すると、SASL認証を用いてIMAP4およびPOPをサービスできますので、パスワードの二重管理の問題からは開放されます。 しかし、POP AUTH*11)に対応しているメイラは現状でほとんどないと思われますし、Cyrus IMAPサーバはAPOPをサポートしていませんので、POP中心の環境では生パスワードを使わざるを得ないため、非常に悩ましいです。*12)
 加えて、パスワードの変更はsaslpasswdコマンドで行うわけですが、管理者のみしか実行できないというのは実際の運用において非常に大きな制約になります。 ユーザレベルでパスワードの変更が行える管理ツールの登場が望まれます。

4 IPv6とsendmail

 sendmail 8.10.X以降では標準でIPv6をサポートしています。 ただし、-DNETINET6を付けてコンパイルする必要があります。 FreeBSD添付のsendmailは-DNETINET6付で作られており、IPv6が使用できる環境であれば、何も考えなくてもIPv6を使ってメイルを出すことができます。 しかし、そのままではIPv6でメイルを受けることはできません。 sendmail.cfでIPv4のみlistenするようになっているためです。
DAEMON_OPTIONS(`Name=MTA-v4, Family=inet')
DAEMON_OPTIONS(`Name=MTA-v6, Family=inet6')
と書いてあげると、どちらもlistenするようになります。 ちなみに、なぜデフォルトでそうしてないかというと、IPv4のみのkernelだとsendmailが動かなくなるためです。
 Received:ヘッダにIPv4かIPv6かどちらで受け取ったか記録したければ、
define(`_REC_BY_', `$.by $j ($v/$Z)$?r with $r$.$?{daemon_family}/${daemon_family}$. id $i$?{tls_version}')
と書いておきましょう。 ただし_REC_BY_は_REC_AUTH_と同様にドキュメント化されていませんので注意して下さい。

5 おわりに

 sendmail.cfの作り方をFreeBSD流に説明し、sendmailに最近追加された機能であるSMTP AUTHとIPv6サポートについて簡単ながら解説しました。 CFからcfへの移行に少しでもお役に立てれば幸いです。 そして、SMTP AUTHが普及しSPAMが少しでもなくなることを期待しつつ筆を置きます。

参考文献

 参考文献として、以下の2冊をあげておきます。 sendmail 8.8.Xの頃のものですので、内容的に若干古くなっておりますが、動作原理・設定方法などは基本的に変わっていませんので、非常に役に立つこと思います。 cf/READMEと併せて参照すると良いでしょう。
「sendmail システム管理」
Bryan Costales, Eric Allman 共著
中村素典 監訳, 鈴木克彦 訳
オライリージャパン 発行
ISBN4-900900-40-0
「sendmail リファレンス」
Bryan Costales, Eric Allman 共著
中村素典 監訳, 鈴木克彦 訳
オライリージャパン 発行
ISBN4-900900-41-9

*1) CF-3.7Wpl2-smtpcheck.patch1とCF-3.7Wpl2-smtpcheck.patch2の2つのパッチが出ています。
*2) FreeBSDでは/usr/share/sendmail/以下にあります。
*3) RFC2033 - Local Mail Transfer Protocol
*4) 筆者は使わないようにしています。
*5) RFC2554 - SMTP Service Extension for Authentication
*6) ports / packagesからインストールしていれば、ユーザcyrusの権限が必要です。 あるいはroot。
*7) FQDNをそのまま指定している場合は問題ありませんが、$w.$mのように定義マクロを使用していると、sasldbをうまく検索できなくなるようです。
*8) sendmail-8.12.0.Beta5では標準になりましたので-D_FFR_UNSAFE_SASLは必要ありません。 また、GroupReadableSASLFileはGroupReadableSASLDBFileに変更になっています。
*9) FreeBSDのsendmailは-DSTARTTLS付でコンパイルされれていますので設定を入れるだけで使用できます。
*10) http://asg.web.cmu.edu/cyrus/
執筆時点での最新は2.0.12です。 安定版である1.6.24がports/mail/cyrus/に、2.0.12がports/mail/cyrus-imapd/にあります。 ちなみに、ports/mail/cyrus-imapd/の方はIPv6対応してあります。
*11) RFC1734 - POP3 AUTHentication command
RFC2195 - IMAP/POP AUTHorize Extension for Simple Challenge/Response
*12) 筆者はとある事情でcyrus-imapd 2.0.Xを導入しましたが、日頃APOPを使用していますので、APOPが使えないと知り愕然としました。 生パスワードは絶対に使いたくないので、作者にお願いしてMewでPOP AUTHを使えるようにして頂きました。:-)


補足
All Rights Reserved, Copyright (C) 2001-2004 Hajimu UMEMOTO
Last Modified Jul 8, 2004
ume@mahoroba.org