sendmail を使いこなそう (sendmail の設定ファイル sendmail.cf を読もう)


最初はただの super-user ゼミ資料として作られたのですが、 意地でここまで大きくなってしまいました。 1999年に作った古い資料ですが,今でも役に立つこともあるかと思いますので置いておきます.
もともと LaTeX2e 形式のファイルだったのを 一括置換だけで日本語にしようとしているので、 TeX のコマンドの残り(\verb など)がありますが、気にしないでください。 (オリジナルである TeX ファイルの公開を望む方はメールを下さい)
また、間違いは各所に潜んでいるので、間違いを見つけた方、 指摘することを見つけた方は 作者にメールを送っていただけると幸いです。メールアドレスはTOPページに画像で置いてあります.

はじめに

MTA(Mail Transfer Agent) は通常、裏で働いてくれるプログラムなので 普通はお目にかかることはありません。いつもは「メールサーバ」と 呼ばれるマシンで黙々と働き続けています。

sendmail はカリフォルニア大学バークレー校の Eric Allman さん (他にも、syslog,tset,vacationなどが彼の手によって作られています) が最初に作ったもので、 元々delivermailと呼ばれており(4.0BSD,4.1BSDに添付されていました)、 ARPAnet,UUCP,BerkNet相互のメール交換プログラムとして作られました。

sendmail の他にも MTA として MMDF(かなり古い。 いまどきこんなものを使っているサイトはないと思う。) , qmail, zmailer, Post.Office などが知られています。

このプログラムは 「いろんな状況でメールの配送機能を実現する」 という設計理念の元に作られています。 言うならば、「メールルータ」とも言うべき性格を持った プログラムとも言えるでしょう。 そのために高度な柔軟性と設定機能を備えているのですが、 その代償として設定ファイルは複雑になってしまいました。

またその目的を達するため、 プログラムの機能はメールの配送機能に限定されており、 ユーザーインターフェースや実際に配信する作業は、 他のプログラムに任せる形をとっています。 (たったひとつの、そして最もよく使われる例外はありますが、 sendmailだけではローカルマシンにもメールの配信はできないのです。) そのために E-Mail だけとは言え、異なるネットワークを相互に接続でき、 (inter network!) 様々なネットワークを相互に接続することで The Internet の立役者となったのだと思います。

このように、 sendmail の利点としては設定ファイルの自由度が大きく、 いろいろなメールシステム同士を相互に接続できる (例えば、 DECnet や BITNET と The Internet をつなぐとか) ということがあります。 (ただし、sendmail.cf の生成に CF を使う場合には The Internet 相互間で つなぐことになります。最近ではこれが実際の障害になることは 考えにくいのですが。) 欠点としては、プログラム全体が suid root されている必要があるため セキュリティホールが生じやすいこと (アドレスの解析を行うプログラムが suid root されている必要は どこにもない)、巨大なプログラムになってしまったために 実装されている機能の少ない qmail などと比べて処理が 遅くなりがち、などが挙げられるでしょう。

ここでは、 CF を使った sendmail.cf の作り方や 「メールが送れない」時の対処策、 トラブルシューティングの時に必要な sendmail.cf の簡単な読み方について述べます。

sendmail.cf などというファイルは数ある設定ファイルの中でも もっとも難しいものの一種とされ、CFなどのツールを使って 記述するのが普通です。

しかし、実際はツールの吐き出したファイルをそのまま使うだけでは トラブルが起こった時に対処しきれない場合も出てきます。

そのときにこそ sendmail.cf の読み方を知っている必要があるわけです。


sendmailのお仕事

sendmail の挙動の観察

普通の人は sendmail なんて使ったことはないので、 どのようなことを行うプログラムなのかわかりにくいと思います。 そういうときには、実際に動かしてみるのが一番です。

% /usr/lib/sendmail アドレス < メール本文を書いたファイル名
% /usr/lib/sendmail -v アドレス < メール本文を書いたファイル名
として起動してみましょう。 (FreeBSD などでは、 /usr/sbin に sendmail が置かれています。 なぜ sendmail が /usr/lib に置かれているかについては謎ですが、 きっと 4.2BSD でここに置かれていたのでしょう。) 後者は Verbose モードで起動されます。 この場合、実際に sendmail がどのようなやり取り (SMTP) をして 送信しているかを観察することができます。

例えば、 tmp というファイル(ヘッダ部分も自分で書いておかなければ ならないことに注意してください)を foo@bar.jp に 送りたければ、

% /usr/lib/sendmail foo@bar.jp < tmp
とすればよいのです。ここまでは簡単ですね。

次に、foo@bar.jpにメールをどのようにして送っているかについて 考えてみましょう。 (受信するには、sendmailでなくてもどっちみちdaemonが必要ですので とりあえずは考えません)

そのために、 sendmail が通常行っていることをすべて手作業で行ってみました。

文章で書いても大変なので、実際にどうなるのかを示します。 (若干の加筆が行なわれています。) なお、この部分はセキュリティの話のところでも使うので、 hogehoge.chofu.tokyo.jpなるマシンとCanadian@hogehoge.chofu.tokyo.jp なるアドレスは実際には存在しません。

まずは、ice.uec.ac.jpというドメインから、 どこのマシンにメールを送るべきかの情報を DNS から得ます。 nslookup の動作はリゾルバと全く同じではないですが、 今回はその違いについてはとりあえず述べません。 また、 nslookup の使い方の詳細については、 DNS の項を参照してください。

% nslookup
Default Server:  lion.sw.cas.uec.ac.jp
Address:  130.153.198.2

> set type=mx  (検索対象を MX フィールドとする)
> ice.uec.ac.jp.  (最後の . に注意!)
Server:  lion.sw.cas.uec.ac.jp
Address:  130.153.198.2

Non-authoritative answer:
ice.uec.ac.jp   preference = 10, mail exchanger = master.ice.uec.ac.jp

Authoritative answers can be found from:
ice.uec.ac.jp   nameserver = master.ice.uec.ac.jp
master.ice.uec.ac.jp    internet address = 130.153.15.20
> 

そしてそのマシンに対して TCP 接続をかけます。 SMTP (Simple Mail Transfer Protocol) によりメールを転送します。 通常、 SMTP ポートは 25 番なので (25 番という特権ポートを使わなければならないことが sendmail に root 権限を与えておかなければならない 1 つの理由です。 FireWall 上などで動かす場合に特権ポートを使わないのであれば、 setuid root しておく必要がないこともあります。) telnet をかけるときには、マシン名と共にポート番号も指定します。 ちなみに、システムにもよりますが、 25 と書く代わりに smtp と書くことも可能です。

以下、例を示します。

% telnet 130.153.15.20 25
Trying...
Connected to 130.153.15.20.
Escape character is '^]'.
220 master.ice.uec.ac.jp ESMTP Sendmail 8.9.3/ICE-M01.1; Mon, 13 Dec 1999 14:30:25 +0900 (JST)
HELO hogehoge.chofu.tokyo.jp
250 master.ice.uec.ac.jp Hello lucifer.sw.cas.uec.ac.jp [130.153.198.27], pleased to meet you
MAIL FROM:Canadian@example.org
250 Canadian@example.org... Sender ok
RCPT TO:kanada
250 kanada... Recipient ok
DATA
354 Enter mail, end with "." on a line by itself
From: Canadian@example.com
To: kanada@example.jp
    (この空行により、ヘッダと本文が区切られます)
this is a test mail.
.
250 OAA23967 Message accepted for delivery
QUIT
221 master.ice.uec.ac.jp closing connection
Connection closed by foreign host.

この例においては、エンベローブについている From アドレスが Canadian@example.com になります。 メールスプールの上で"From "で始まる行に書かれている アドレスがエンベローブについている"From "アドレスなのですが、 このアドレスは通常 MUA が"From: "行から抽出して 記述するので普通に運用している分には問題になりません。 また、エンベローブに書かれている宛先 (kanada) に配送が行われ、 To: 行に書かれているアドレスである kanada@example.jpは基本的に配送に関係ないこともわかります。

このとき、実際に来たメールは以下のようになります。 Received: を見ると、本来なら 130.153.198.27 なる IPアドレスを持つ lucifer というマシンが master.ice.uec.ac.jp に対して、 自分を hogehoge.chofu.tokyo.jp と偽って接続してきたことがわかります。 なお、 Content-Length:は Solaris の local mailer (mail.local)がつけたものです。

From Canadian@example.com Mon Dec 13 14:32 JST 1999
Received: from hogehoge.chofu.tokyo.jp (lucifer.sw.cas.uec.ac.jp [130.153.198.27])
        by master.ice.uec.ac.jp (ICE-M01.1) with SMTP
        id OAA23967
        for kanada; Mon, 13 Dec 1999 14:30:53 +0900 (JST)
        (envelope-from Canadian@example.org)
Date: Mon, 13 Dec 1999 14:30:53 +0900 (JST)
Message-Id: <199912130530.OAA23967@master.ice.uec.ac.jp>
From: Canadian@example.com
To: kanada@example.jp
Content-Type: text
Content-Length: 21

this is a test mail.

ここで mbox 形式について見ておきましょう。 以下のような特徴があります。


sendmail のインストール

まず最初に sendmail.8.10.0.tar.gz を ftp.sendmail.org のミラーサイトから 取ってきます。そうしたら、展開しましょう。

% gzip -d sendmail.8.10.0.tar.gz
% tar xvf sendmail.8.10.0.tar

展開が終わると、 {\tt sendmail-8.10.0/} なるディレクトリができます。 どんなソフトでもそうですが、 習慣として {\tt READ\_ME、 src/READ\_ME} ぐらいは 一応目を通しておきましょう。 ここに書いてあることは英語ですが、大して難しくはないので ざっと目を通しておくと fj などで質問する時に恥をかかずに済みます。 また、時間があれば doc/op.ps に目を通しておくのもよい選択です。 sendmail の作者である Eric Allman 氏による詳細な解説がかかれています。

さて、ドキュメントに sendmail の作り方は書かれていますが、 急いで sendmail を作りたい場合は、 src ディレクトリで Build なるコマンドを打ち込むだけで完成します。

% cd sendmail-8.10.0/src/
% Build

これではコンパイルが止まってしまう場合がありますので、 その際には src/Makefile を編集する必要が生じます。

実際に、 Makefile を編集するときには、 以下の行を編集することが多いでしょう。

MAPDEF= -DNDBM -DNIS
ENVDEF= -D_PATH_SENDMAIL_CF="/etc/mail/sendmail.cf"

以上は一例ですが、\verb@MAPDEF=@ の行はデータベース形式として 何を使用するか(この場合 NIS と ndbm)、 \verb@ENVDEF=@ の行は、 この例においては sendmail.cf の位置をどこにするかを指定しています。


sendmail の別名

sendmail は \verb;argv[0]; によって動作を変えることができます。 なので、インストールの時にもこれらの別名をきちんと定義してやる 必要があります。

sendmail の認識する別名は以下の通りです。
名前 動作モード
hoststat 配信先ホストごとの配信成否記録を表示する(バージョン 8.8 以上)
mailq キューの内容を表示する (-bp と同じ)
newaliases aliases ファイルデータベースを再構築する (-bi と同じ)
purgestat 配信先ホストごとの配信成否記録を消去する(バージョン 8.8 以上)
smtpd デーモンモードで実行する (-bd と同じ)

通常、これらの別名は sendmail と同一の実体にするわけですが、 そのときにハードリンクを使用している場合には、 新しい sendmail 導入に際してちょっと注意が必要です。 (FreeBSD 2.2.5-REL でちょっとはまってしまいました) シンボリックリンクにしておくのがあとあと楽でしょう。

なお、どんな名前で起動されても syslog には sendmail と出力されます。


sendmail のコマンドラインオプション

通常のコマンドラインオプション

よく使う例として、

 # /usr/lib/sendmail -bd -q1h
 % /usr/lib/sendmail -q
 % /usr/lib/sendmail -C/tmp/tmp.cf -bt
が挙げられます。それぞれの例は となっています。

すべてのコマンドラインオプションの一覧は添付資料を参考にしてください。

デバッグオプション

よく使う例は、

 % /usr/lib/sendmail -d0.1 -bt
 % /usr/lib/sendmail -d8.8 -bt
 % /usr/lib/sendmail -d37.1 -bt
などです。 それぞれが何を意味しているかは一覧の資料を参考にしてください。 実際に実行してみてもわかるでしょう。

一つ注意しておかなければならないのは、 \verb;-d; オプションをつけても 他に何もないと、 sendmail は通常通り標準入力からメールを受け取り 配送を行おうとするため、配送をせずに sendmail を起動したい場合は \verb;-bt; オプションを指定しなければならないことです。

sendmail.cf のオプションを一時的に変更する

後述する sendmail.cf 内における \verb;O; コマンドの 設定をコマンドラインから上書きすることができます。 書式は次の通りです。

-oXarg
-OLongName=arg

X は単一文字のオプション名、 arg は引数です。 \verb;-o; コマンドは単一文字オプション名の時に使用します。

LongName は複数文字のオプション名です。 \verb;-O; コマンドは複数文字オプション名の時に使用します。

具体例としては、例えば以下のようになります。

-oQ/tmp
-OQueueDirectory=/tmp

この二つのコマンドラインオプションは全く同一のことを表していて、 キューディレクトリを(一般ユーザ権限での sendmail.cf のテストなどの理由により) 一時的に \verb;/tmp; に変更します。

特殊なオプション

\verb;--; というオプションはすべてのオプションの最後を意味します。 (バージョン 8 以降) このオプションにより、 \verb;-foo; という名前のユーザに メールを送ることができます。


CF を使った sendmail.cf の作成とテスト

CFとは?

CF とは、WIDE Project の一環として現京都大学経済学部助教授の 中村素典さんが中心になって作られたツールで、 sendmail.def などと呼ばれる、 CF 設定用のファイルから sendmail.cf の生成を行ってくれるものです。 このツールはどういうメリットがあるかといいますと、

などが挙げられるでしょう。

ただし、一つ注意しておかなければならないこととして、 CF で作成可能な sendmail.cf はすべての場合に対応できるとは限りません。 具体的には、 The Internet 以外の世界のメールの配信については あまり考えられてはいません。 だから、草の根 BBS やパソコン通信の世界と The Internet の相互接続に sendmail を 使用するときには、 CF を使うわけにはいきません。 そのような場合には、 sendmail.cf を直接記述する必要があります。

sendmail の成り立ちから考えるとこのような使い方をされるのは当然なのですが、 現在の状況としてはそのような状況はそうは生じないわけですし、 The Internet に接続できるホスト相互間についてはよっぽど特殊な事情がない限り CF を使って記述できるはずです。

CF のパッケージの一次配布元は {\tt ftp://ftp.kyoto.wide.ad.jp/pub/mail/CF/} にあります。 執筆現在(1999.12.13)の最新バージョンは CF-3.7Wpl2 です。

CF を使った sendmail.cf の作成

sw-domain における sendmail.def ファイルの骨子は 以下のようになっています。

CF_TYPE=R8V8
OS_TYPE=( OS 名)
MX_SENDMAIL=yes
MY_DOMAIN='sw.cas.uec.ac.jp'
OFFICIAL_NAME='$w.$m'
FROM_ADDRESS='$m'
#__mailhostがメールを集中管理する
SPOOL_HOST='mailhost.sw.cas.uec.ac.jp'

もちろん他にも設定項目は多数ありますが、 最低限この程度は必要でしょう。 実際に使用中のファイルは、私のホーム以下にある\verb@admin/CF/CF-3.7pl2@ 以下に置いてあります。興味のある方は見てみてください。 ちなみに、このファイル中で \verb@#_@ で始まる行は私のコメントです。 参考になるかどうかはわかりませんが…。

ルールテストモードを使ったsendmail.cf のテスト

以下は直接 CF と関係あるわけではありませんが、 話の流れからここに持ってきました。

% /usr/lib/sendmail -bt

と sendmail を起動し、ルールセット番号、スペース、アドレスの順に データを与えます。

具体例を見てみましょう。 (以下の例は適当なところで改行しています。)

% /usr/lib/sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter  
> 3,5,0 kanada rewrite: ruleset 3 input: kanada rewrite: ruleset 3 returns: kanada rewrite: ruleset 5 input: kanada rewrite: ruleset 88 input: < relay : mailhost . sw . cas . uec . ac . jp > . kanada rewrite: ruleset 88 returns: $# relay $@ mailhost . sw . cas . uec . ac . jp . $: kanada rewrite: ruleset 5 returns: $# relay $@ mailhost . sw . cas . uec . ac . jp . $: kanada rewrite: ruleset 0 input: $# relay $@ mailhost . sw . cas . uec . ac . jp . $: kanada rewrite: ruleset 0 returns: $# relay $@ mailhost . sw . cas . uec . ac . jp . $: kanada >

このように、入力されたアドレスが順に書き変わっていく様子を 観察できます。ここで、ローカルアドレスなのに smtp 接続しようとしていたりしていれば、 sendmail.cf が おかしいと判断できるわけです。

sendmail.cf がおかしいと自サイトだけでなく、他のサイトにも 迷惑をかけますのでしっかりテストしましょう。

他のテストの仕方もあります。以下のように与えます。

% /usr/lib/sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter  
> /parse kanada (at) ied.ice.uec.ac.jp

/parse では、ルールセットの名前を明示的に指定する必要はありません。 (この場合、 3,0,4 と選ばれています。) ただし、ルールセット 5 などは自動的に選ばれないので注意が必要です。


sendmail.cf ファイルの概要

sendmail.cf ファイルは sendmail の設定ファイルです。 コンパイル時のオプションにもよりますが、 \verb;/etc/sendmail.cf; に 置いておくのが普通です。 (System V 系列の OS の場合、 \verb;/etc/mail/sendmail.cf; に 置いておくことも多いようです。) 他にも設定ファイルなどはないわけではありませんが、 それらはすべて sendmail.cf ファイルの中で 存在する位置などを指定しています。

sendmail.cf コンフィグレーションファイルは行単位からなっています。 行の先頭がコマンドになっていて、一行に一つのコマンドを記述します。 (スペース、タブで始まる行は継続行とみなされます。)

まず、すべてのコマンドを示します。 コマンド、改行、スペース、タブ、\verb@#@ 以外のキャラクタが行の先頭にあるとエラーになります。
コマンド 説明
V sendmail.cfのバージョンを定義 (バージョン 8以上)
M メール配信エージェントを定義
D マクロを定義
R 書き換えルールを定義
S ルールセットの開始
O オプションを定義
H ヘッダを定義
C クラスマクロの定義
F ファイルやパイプからのクラスマクロを定義
P 配信のプライオリティを定義
T トランステッドユーザの定義
K キー付きデータベースの宣言 (バージョン 8以上)

難しいといわれる sendmail.cf ですが、これしかコマンドはありません. F コマンドなど、使わない事も多いコマンドや、ファイルの中に一度しか出てこない V コマンドなどもあるので、実際に覚えなければならないコマンドは そんなに多くないことはわかっていただけると思います。

以下、さまざまな例が登場しますが、ほとんど 実際に運用中の /etc/sendmail.cf からとったものです。

コメント

他人の書いたプログラムを読む場合と同様に、コメントのない設定ファイルは 何をしているのかわからないことが多々あります。 できるだけ詳しくコメントは記述した方が良いと思われます。

行頭の他にも行の途中からコメントを入れることも可能ですが、 バージョン 8 以前のsendmailでは、コメントは S,P,R コマンドの後にしか続けられません。 しかし、バージョン 8 sendmail 以上では、どんなコマンドの後にでも書くことができます。

\verb@#@から行末までがコメントと見なされます。

コメントの例です。

# this is a comment.
V8 # this is a comment.
R$*<$*>$* (tab) $2 (tab) this is a comment.

最後はちょっと特殊なコメントのしかたですがよくみられます。

V コマンド

Vコマンドの形式は以下のようになります。
V8
この場合、sendmail 8.9.x 以上のバージョン用の sendmail.cf であることを示します。 (sendmail 8 の場合、V3 になります)

8 と言う数字は大きな変化が 8 度あったことを示しています。

S コマンド

S コマンドの形式は簡単です。 例えば以下のようなコマンドです。
S0

これは、ルールセット(ルールの集まりからなるサブルーチンのようなもの) 0 がここから始まるということを示しています。 数字でなく、英数字を使うこともできます。

D コマンド

コマンド D は、マクロを定義します。 例えば、

# local domain name (defined automatically)
Dmsw.cas.uec.ac.jp
は、マクロ m に sw.cas.uec.ac.jp という値を定義します。

このマクロmの値を参照するには、この行以下に

# local host name without domain (defined automatically)
Dwmailhost
# my official SMTP hostname (defined automatically)
Dj$w.$m
のように書いて、\verb;$m;のようにして参照します。

マクロ名は一文字であることに注意して下さい。 なお、大文字、小文字は区別されます。 (バージョン 8.7 以降に限られますが) 複数文字列からなるマクロ名を使いたい場合は

D{hogehoge}foo.bar.jp
のようにします。

C コマンド

Cコマンドはクラスマクロを与えます。 「クラスマクロ」というより、「リスト」と言った方が わかりやすいかも知れません。 具体的にはこんなようになります。

CS root daemon news usenet
この場合、S というクラス名に、 root daemon news usenet という値が入ります。

この値を参照する時には\verb;$=S;とします。 そうすると、\verb;$=S;を書いたところが root daemon news usenet に置き換わります。

クラス名に複数文字からなる名前をつけたいときには以下のようにします。

C{SpamDom} aol.com msn.com hotmail.com

F コマンド

このコマンドは C コマンドとほとんど一緒です。 具体的には、/etc/sendmail.ss の内容が

root daemon news usenet
のとき、以下の3つのコマンドは同じことを行います。
CS root daemon news usenet
FS/etc/sendmail.ss
FS|'/bin/cat /etc/sendmail.ss'
1行目はすでに解説しましたが、2行目以降を解説すると、 2行目はファイルからクラスマクロの値を与えており、 3行目はコマンドの標準出力からクラスマクロの値を与えています。

この方法を使うと、クラスマクロの定義は sendmail.cf に 埋め込むのではなく外部ファイルすることができますが、 実際に使用するときにはセキュリティに気をつけてください。

複数文字の使用については C コマンドと同等です。

O コマンド

コマンドO は、オプションの数々を定義します。 具体的なコマンドの使用例としては以下のようになります。

O EightBitMode=pass8
このコマンドは、8bit message を通すことを意味します。 ただし、バージョン 8 sendmail を使っていない場合には、 7bit code しか 通しません。(この場合、Shift-JIS(MS漢字)、EUCコードは 文字化けを起こします。但し、漢字コードについては、NEWS-OS の OS 附属 sendmail を使っている場合には自動的に変換してくれます。 ただ、この場合にはフロントエンドとしてOS附属のUCBMailを使うと この機能に依存してしまうのであまり多用しない方がいいかもしれません。)

O AliasFile=/etc/mail/aliases
これは、エイリアスファイルの場所が /etc/aliases にあることを意味します。 swlab,tnlab,jtlab などのメーリングリストはエイリアス機能を 使うことで運営されています。

バージョン 8 sendmailでは、この行は複数置くことができ、 その時には同時に複数のエイリアスデータベースをつかうことができます。

また、コマンドラインオプション \verb;-bi;(または、\verb;newalias;コマンド) は、このオプションで指定された順序でデータベースを再構築します。 (\verb;-oA;スイッチを使った時を除く)

メーリングリストの作り方として、 アカウントをつくってそこに .forward ファイルを置く方法は、 セキュリティ面を考えるとあまり得策とはいえません。

他にもたくさんありますが、 O コマンドは名前からある程度機能を察することができるので 比較的わかりやすいでしょう。

H コマンド

メールは、ヘッダと空行、そして本文からなっています。

本文には何を書かなければならないと言う決まりはありませんが、 ヘッダはRFC 822 で何を書かなければならないかということが決まっています。 (X-???? という形で、自分で勝手にヘッダを付け加えることも可能です。) ヘッダのうちどのフィールドがメッセージに含められるべきなのかについて H コマンドは sendmail に指示します。

具体的なコマンドの使用例としては以下のようになります。

HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
 $.by $j ($v/$Z)$?r with $r$. id $i$?u for $u$.; $b

この場合、H コマンドはすべてのメールメッセージに対して Received: ヘッダをつけるように指示します。 \verb;$;が山ほどあるので、何を意味するのかがわかりにくいですが、 マクロの引用を行なう時には\verb;$;で始めるという規則を思い出せば、 見かけほど難しくはないように思います。

例えば、

$?sfrom $s $.
$?	if
s	マクロ s が存在すれば
from $s	from $s を出力する
$.	endif
を表します。 また、
$|
はここでは else 節の開始を意味します。

以上の説明で

HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
 $.by $j ($v/$Z)$?r with $r$. id $i$?u for $u$.; $b
がどういう内容になっているのかはわかると思います。

P コマンド

受信したメールの優先度を決定します。 具体的には以下のようになります。

Pspecial-delivery=100
Pfirst-class=0
Pjunk=-100

この行は、メールキューを処理する時に Precedence: ヘッダに special-delivery と書かれているメールを最優先に、 junk と書かれているメールを最後に処理することを意味します。 (数字が大きいものを優先して処理する)

通常のメールは優先度$0$に設定されます。 メーリングリストへのメールの時などは junk に設定すると良いでしょう。

T コマンド

T コマンドは Trusted User を定義するコマンドです。 8.7.x 以上のバージョンにおいては、 Trusted User が sendmail を \verb@-f@ オプションをつけ 起動したときにも警告を発しません。それだけです。 また、この場合 \verb@Ct@ が全く同じ意味を持ちます。

K コマンド

他ホストのリストなどを保有する時に、外部データベース(keyed Database)を 使用することがあります。

コマンドKは、そのような時にデータベースの配置と性質について sendmail に教えるためのコマンドです。

M コマンド

コマンド M は、メールを実際に配信する sendmail の下請け(メール配信エージェント)を定義します。

例えば、以下の行が何を表しているか考えます。

Mlocal,   P=/bin/mail,	F=lsDFMmrn,	S=10, R=20/0, A=mail -d $u
\verb@Mlocal@ はローカルメーラに関する定義であることを、 \verb@P=/bin/mail@ はローカルへのメールを \verb@/bin/mail@ を使って 送るということを表しています。

\verb@F=@ で始まる部分は、ローカルの配信エージェントであり{\tt (l)}、 クォーテーションマークを取り去り{\tt (s)}、 存在しない場合ヘッダに \verb@Date:@ {\tt (D)}、 \verb@From: @{\tt (F)}、 \verb@Message-id:@ {\tt (M)}をつけ、 配信エージェントが一人より多い受信者を扱え{\tt (m)}、 \verb@/bin/mail@ に \verb@-r $g@ のオプションをつけて起動し{\tt (r)}、 \verb*@From @ 行を自動的に追加しない(\verb@/bin/mail@ が生成する){\tt (n)} ということを表しています。

\verb@S=10,R=20/0@ は 発信者アドレスを処理するルールセット番号が 10 であり (エンベローブ、ヘッダ共)、エンベローブの受信者アドレスを処理する ルールセットの番号が 20 、ヘッダの受信者アドレスを処理する ルールセットの番号が 0 であることを示しています。

また、 \verb@mail -d $u@ は、\verb@/bin/mail@ に与えられる \verb@argv@ が \verb@mail -d $u@ になることを示します。

Rコマンド

コマンドRは、ルールの定義を行ないます。 この部分は多分もっとも難しいように見える部分ですが、 正規表現に関する知識があればそんなに難しくはないと思います。

まずはもっとも簡単な場合から見ていきましょう。

RTom	Jim
という R コマンドは、作業領域の中に Tom があれば Jim に置換します。

もう少し実際に即した例では、例えば以下のようになっています。

R$*<$+>$*	$2	basic RFC821/822 parsing

ちょっとわかりにくいですが、\verb;R$*<$+>$*; と \verb;$2; と コメントの間に入っている文字はタブ文字です。 ここをスペースに置き換えてしまうと、 sendmail は正しく ルールを認識できません。 注意として、エディタで sendmail.cf を編集するときには タブの変換がエディタ側で自動で行われがちなので気をつけましょう。

メールアドレスは左のルール\verb;($*<$+>$*);と比較され、 このルールと一致した時に右のルールに従って書き換えられます。 一番右はコメントです。 (Rコマンドは引数を二つしかとらないので、そういうことができるのです。)

この場合はどうなるかというと、

Kanada Naoki < foo@bar.jp > Nishino-Lab.
という入力に対して、$* が Kanada Naoki とマッチします。($1) その後 < が < とマッチ、 $+ が foo@bar.jp とマッチし($2)ます。 さらに > が > とマッチ、 $* が Nishino-Lab. とマッチ($3)します。 ですから、全体として入力にマッチします。 これを $2 に書き換えよ, という規則なのですから, 最終的には
foo@bar.jp
というように書き換えられます。 このルールでは全体として RFC821/822 形式で記述された コメントの除去を行っています。

なお、マッチしている限り、書き換えは何度でも行われます。 例えば、以下のルールセットを考えます。

R$+.	$1
このとき、末尾についている . は何個あっても除去されます。 (このルールに foo@bar.jp..... を与えれば foo@bar.jp が返ってきます。) 自分で書くときは無限ループにならないように注意しましょう。

R コマンドの一般形は、次のようになります。

R左式 (tab) 右式 (tab) コメント

左式(Left-Hand Side:LHS)では次のオペレータが使えます。
オペレータ 説明
$* 0 個以上のトークンとマッチ
$+ 1 個以上のトークンとマッチ
$- 1 個のトークンがあるときにマッチ
$@ 0 個のトークンがあるときにマッチ
$= クラスに含まれる任意のトークンとマッチ
$~ クラスに含まれない任意のトークンとマッチ

右式(Right-Hand Side:RHS)では次のオペレータが使えます。
オペレータ 説明
$数字 位置に基づくコピー
$: 一度だけ書き換える prefix
$@ 書き換えの後ルールセットを終了する prefix
$>set ルールセット set で書き換えをする
$[ $] ホスト名を標準化する
$( $) データベース検索

また、ルールセット 0 の中に限り、以下のオペレータが使用可能です。
オペレータ 説明
\verb;$#; 配信エージェント
\verb;$@; 受信ホスト
\verb;$:; 受信ユーザ
この3項組は必ずこの順序で並んでいる必要があることに注意してください。


セキュリティ

むかしむかし

SMTPポートにtelnetしたとき、debug というコマンドが発行できる 時代がありました。(このとき、showqという(外部から!) メールキューを覗くコマンドも発行できます。) この機能を使うと、sendmail が外部からデバッグモードになります。 外部から、 sendmail の権限でコマンドが実行できたりします。 この機能を利用して昔、インターネットワームが繁殖しました。

メールの偽造

前に示したように、メールを偽造して送ることは不可能ではありません。 ですから、管理者から「あなたのパスワードは危険なので今すぐ変更して下さい」 などというメールが送られてきてもすぐには信用してはいけません。

.forward ファイルの問題

もし、 \verb;root; や 特権を持つユーザが \verb;.forward; を持っていて、 自分以外の誰か(同じグループの人)によって書き込みができたすると 重大なセキュリティホールを作ってしまうことになります。

今、\verb;hogehoge;というログイン名を持つ人がそうだったとしましょう。 その時、侵入者は \verb;.forward; をこんなように書き換えると思われます。

\hogehoge
|'cp /bin/sh /tmp/... ; chmod u+s /tmp/...'
このようにすると、侵入者は\verb;hogehoge;にメールを送るだけで \verb;...;というわかりにくい名前の suid されたシェルを作ることができます。 あとはこれを実行すれば不正ログインと同等の効力を得ることができます。

これへの対策としては、

などがあるでしょう。

また、全く同じ問題がエイリアスファイル (およびそこから \verb@:include:@ によって読み込まれるファイル) にも起こり得ます。 sendmail はエイリアスファイルと そこから読み込まれるファイルについて、root 以外の者から 書き込みが可能であると危険であると見なし、 root 権限を放棄します。

例えば、エイリアスファイルから /usr/local/lists/maillist を 読んでいるときに、/usr/local/lists/maillist が root 以外の 人間から書き込み可能であるときにはもちろんのこと、 /usr/local が wheel から書き込み可能であると sendmail は /usr/local/lists/maillist を危険であると見なします。 このとき、バージョン 8.9.x 以降の sendmail では root 権限を放棄します。 root 権限を放棄した場合、 daemon として動作する場合には 正常に動作しません。 それを押さえるためには、sendmail.cf に

O DontBlameSendmail=GroupWritableDirPathSafe
などと書いておく必要があります。

sendmail.cf のパーミッション

sendmail.cf が root 以外の人間から書き込み可能であると 問題が生じます。 例えば、侵入者が次の不正な行を付け加えたとします。

FX|/tmp/.sh
O DefaultUser=0:0

このコマンドにより、\verb@/tmp/.sh@ が実行され、 その出力がクラス X に代入されますが、そのとき \verb@/tmp/.sh@ が 以下のようなファイルだったとします。

#!/bin/sh
cp /bin/sh /tmp/...
chmod u+s /tmp/...

この場合、 .forward の項で述べたのと全く同じ問題が発生します。 ここで、 sendmail.cf が root 以外の人間から書き込みできないように見えても、 例えば /etc/mail が wheel によって所有されているとき、 /etc/mail/sendmail.cf は wheel に権限を持つ人間によって 新たに生成されうることに注意しましょう。

統計ファイル

sendmail の吐く統計ファイル(ログファイル)を書き込むときに セキュリティ上の問題が発生することがあり得ます。 例えば、 sendmail.cf に
OS/usr/tmp/sendmail.st
と書いてあったとします。 (当面、統計の収集をするときに誰でもファイルを作成したり削除できるようにするためにそうしたのですが…) このとき、 \verb@/usr/tmp@ は誰でも書き込み可能なので、
ln -s /vmunix /usr/tmp/sendmail.st
などとやられてしまうと、 sendmail がカーネルを ぐちゃぐちゃに書き換えてしまいます。 ( sendmail は sendmail.st が存在し、 書き込み可能かだけをチェックするからです。)

そんなことがおこらないようにするには統計ファイル sendmail.st の場所を root のみが書き込み可能なディレクトリの下に、 root のみが書き込み可能なパーミッションで置く必要があります。 (置かないという選択肢も OK です。)


参考文献


Appendix

以下の表は「 sendmail リファレンス」からの引用ですので、 sendmail 8.8.x までにしか当てはまりません。

配信エージェントに書かれる式(8.8.x)

以下、(V8.7) という表記は sendmail 8.7.x 以降で使用可能なことを意味します。

配信エージェント式
フィールド名 意味
A= Argv 配信エージェントのコマンドライン引数
C= Charset デフォルトの MIME 文字セット(V8.7)
D= Directory 実行時のディレクトリのパス(V8.7)
E= EOL 行末文字列
F= Flags 配信エージェントの動作を記述するフラグ
L= Linelimit 行の最大の長さ(V8.1)
M= Maximum メッセージの最大サイズ
N= Niceness エージェントの nice(3)値 (V8.7)
P= Path 配信エージェントのパス
R= Recipient 受信者の書き換えルールセット
S= Sender 発信者の書き換えルールセット
T= Type DSN 診断のタイプ (V8.7)
U= UID エージェントの実行権限

配信エージェントのフラグ(8.8.x)

フラグ F= (アルファベット順)
フラグ 意味
0 配信エージェントの MX 検索を無効にする(V8.8)
3 quoted-printable を EBCDIC に展開する(V8.7)
5 エイリアス展開のあとでルールセット5を適用する(V8.7)
7 配信時にメッセージ本文の 8bit 目は 0 にする(V8.6)
8 この配信エージェントでEightBitMode=mのMIME符号化を抑制(pass8)(V8.7)
9 MIME メッセージの本文を quoted-printable または base64 から 8bit に(V8.8)
: :include: ファイルの使用を許可する(V8.7)
| プログラムのアドレスを解釈する(V8.7)
/ ファイルのアドレスを解釈する(V8.7)
@ ユーザをユーザデータベースのキーとして検索する(V8.7)
a ESMTP を使う (V8)
A ユーザに対してエイリアス展開を行う(V8.7)
b メッセージの最後に空行を追加する(V8.6)
c ヘッダの中にある \$g (通常 From: 行)からコメントを削除する(V8.6)
C @domain を持たない受信者にエンベローブ発信者の @domain を付加する
d route address を \verb;<>; で囲まない(V8.7)
D ヘッダに Date: を必要とする(慣習)
e expensive な配信エージェントであることを指定する
E 本文中に \verb*;From ; で始まる行があれば \verb*;>From ; に変更する
f 配信エージェント起動時の argv に -f を追加する
F ヘッダに From: を必要とする(慣習)
g From: の \verb;<>; (null address) を抑制する (V8.6)
h ホスト名の大文字を保存する
i Envelope From: に対してユーザ名データベースによる書き換えを行う(V8.7)
I SMTP VERB を送る(リモートのデバッグ)
j Header To: に対してユーザ名データベースによる書き換えを行う(V8.7)
k HELO コマンドでループ(自分自身への接続)チェックをしない(V8.7)
l ローカルエージェント
L SMTP における1行の文字数を 990 文字とする(廃止)
m 複数の受信者を扱うことのできる配信エージェントである
M ヘッダに message-ID: を必要とする(慣習)
n ヘッダで UNIX 形式の \verb*;From ; を使用しない
o 配信エージェントを受信者の権限で実行する(V8.7)
p Envelope From: アドレスに経路情報を付加する(推奨しない)
P ヘッダに Return-Path: を必要とする(慣習的)
q SMTP VRFY コードの選択 (250 or 252) (V8.8)
r 配信エージェント起動時の argv に -r \$g を追加する
R 特権ポートでのみ接続する(V8.6)
s アドレスに含まれるクォーテーションマークを取り去る
S U\= 式で指定される uid と gid の権限で実行する
u ユーザ名の大文字を保存する
U UUCP 形式の \verb*;From ; 行を指定する
w /etc/passwd エントリをチェックする
x ヘッダに Full-Name: を必要とする(慣習)
X 配信エージェントが RFC821 の hidden dot (行頭が . なら .. とする)を使う

sendmail(8.8.x) のコマンドラインスイッチ

コマンドラインスイッチ
スイッチ バージョン 意味
-B V8.1 メッセージ本文のタイプを指定
-ba V8.1-8.6 以外 Arpanet/Grey Book プロトコルを使う
-bD V8.8 デーモンとして実行するが fork() しない
-bd デーモンとして実行する
-bH V8.8 配信先ホストごとの配信成否記録の消去
-bh V8.8 配信先ホストごとの配信成否記録の表示
-bi エイリアスデータベースの再構築
-bm メール発信者になる(デフォルト)
-bp キューの内容を表示
-bs 標準入力に対して SMTP を実行する
-bt ルールテストモード
-bv ベリファイを行い、配信はしない
-bz 設定ファイルをフリーズする
-C 設定ファイルの場所
-d デバッグモードの指定
-E SONY NEWS EUC に変換
-F 発信者のフルネームを設定する
-f 発信者のアドレスを設定する
-J SONY NEWS JIS に変換
-M V8.7 コマンドラインでマクロに値を代入
-m MeToo(m) オプションを真に設定する
-N V8.8 DSN Notify 情報を指定する
-n ローカルのエイリアス展開を行わない
-O V8.7 複数文字オプションを設定する
-o 単一文字オプションを設定する
-p V8.1 プロトコルとホストの設定(UUCP etc.)
-q キューを処理する(一度だけ、定期的に)
-R V8.8 DSN でエラー通知の際に返す内容
-t メッセージヘッダから受信者アドレスを抽出する
-U V8.8 MUA から MTA への最初の送信であることを指示
-V V8.8 ENVID 文字列を指定する
-v 冗長モードで実行する
-X V8.1 トランザクションの記録
-x V8.2 無視される
-- V8 最後のオプション

sendmail(8.8.x) の別名

argv[0]として与える名前の一覧
名前 等価なオプション
hoststat -bh (V8.8)
mailq -bp
newaliases -bi
purgestat -bH (V8.8)
smtpd -bd

sendmail (8.8.x)のオプション一覧

ここで示したオプションは通常 sendmail.cf に記述されますが、 コマンドラインから指定することもできます。 詳しくは「 sendmail システム管理」を見てください。 誤字、脱字はきっとありますが、気にしないでください。

オプション一覧
オプション名 意味
AliasFile(A) 文字列 aliases ファイルの場所
AliasWait(a) 時間 aliases 再構築時の待ち時間
AllowBogusHELO 2値 HELO/EHLO でのホスト名省略を許す
AutoRebuildAliases(D) 2値 aliases データベースの自動再構築
BlankSub(B) 文字 クォートされない空白の置換文字を指定
CheckAliases(n) 2値 aliases の右側のアドレスの正当性チェック
CheckPointInterval(C) 数値 キューの処理にチェックポイントを設定
ClassFactor(z) 数値 優先度の評価式で用いる重み係数
ColonOkInAddr 2値 アドレス中にコロンを許す
ConnectionCacheSize 数値 同時に接続を保持する SMTP 接続の数
ConnectionCacheTimeout 時間 同時に接続を保持する SMTP 接続のタイムアウト
ConnectionRateThrottle 数値 接続を受ける SMTP 接続の頻度
DaemonPortOptions(O) 文字列 デーモンの TCP/IP ポートに与えるオプション
DefaultCharSet 文字列 Content-Type: に与える文字セット
DefaultUser(u) 文字列 配信エージェントのデフォルトユーザID
DefaultUser(g) 文字列 配信エージェントのデフォルトグループID
DeliveryMode(d) 文字 配信モードの設定
DialDelay 文字列 接続失敗時の再試行待ち時間
DontExpandCnames 2値 CNAME の展開を禁止
DontInitGroups 2値 initgourps(3) を使用しない
DontPruneRoutes(R) 2値 経路指定つきアドレスを削除しない
DoubleBounceAddress 文字列 エラー通知発進時のエラーの送り先
EightBitMode(8) 文字 MIME に変換する方法
ErrorHeader(E) 文字列 エラーメッセージヘッダの設定
ErrorMode(e) 文字 エラーの通知方法を指定
FallBackMXhost(V) 文字列 フォールバック MX ホスト
ForkEachJob(Y) 2値 キューファイルごとに別個のプロセスで処理
ForwardPath(J) 文字列 .forward 検索パスの設定
HelpFile(H) 文字列 ヘルプファイルの場所を設定
HoldExpensive(c) 2値 配信コストの高い宛先のメールを一旦キューに保存
HostsFile 文字列 /etc/hosts に変わるファイル名の指定
HostStatusDirectory 文字列 ホストの状態を表す外部データベースを置くディレクトリ
Ignoredots(i) 2値 メッセージ行頭のピリオドを無視(コマンドラインから)
LogLevel(L) 数値 ロギングレベルの設定
MatchGECOS(G) 2値 GECOS フィールドの情報で受信者を検索
MaxDaemonChildren 数値 生成する子プロセスの同時実行最大数
MaxHopCount(h) 数値 許容最大転送回数
MaxMessageSize 数値 ESMTP メッセージ受信時の最大バイト数
MaxQueueRunSize 数値 連続処理される最大のキューメッセージ数
MeToo(m) 2値 メーリングリストのメールを発信者にも送る
MinFreeBlocks(b) 数値 空きブロックを残す(ESMTP)
MinQueueAge 時間 キューメッセージの最小処理間隔
MustQuoteChars 文字列 クォートで囲むべき文字
NoRecipientAction 文字列 ヘッダに受信者を提示する方法
OldStyleHeaders(o) 2値 受信者リストの区切りに空白を許す
OperatorChars(\$oマクロ) 文字列 トークン分割文字を設定
PostmasterCopy 文字列 エラー通知を postmaster などにも送る
PrivacyOptions(p) 文字列 デーモンのプライバシー保護を強化する
QueueDirectory(Q) 文字列 キューディレクトリの場所
QueueFactor(q) 数値 高負荷時のキューイング判定のための係数
QueueLA(x) 数値 キューのみを使用する平均負荷下限
q/(負荷平均 - x + 1)と ッセージの優先度を比較する
QueueSortOrder 2値 キューの処理順序を決定するソート方法
QueueTimeout(T) 時間 キューでの最長保存期間
RecipientFactor(y) 数値 受信者数に課すペナルティ係数
priority = nbytes - (class * z) + (recipients *y)
RefuseLA(X) 数値 接続を拒否する平均負荷下限
ResolverOptions(I) 文字列 DNS の検索方法を調整
RetryFactor(Z) 数値 キューの再処理ごとのプライオリティの増分
RunAsUser 文字列 root 以外での実行
SafeFileEnvironment 文字列 ファイル書き込み用の安全なディレクトリ
SaveFromLine(f) 2値 UNIX 形式の From 行を保存
SendMimeErrors(j) 2値 MIME 形式のエラーを返す
ServiceSwitchFile 文字列 サービススイッチファイルの指定
SevenBitInput(7) 2値 入力の最上位ビットをクリア
SingleLineFromHeader 2値 From: から改行を削除
SingleThreadDelivery 2値 単一スレッド配信を行う
SmtpGreetingMessage(\$e) 文字列 SMTP のグリーティングメッセージ
StatusFile(S) 文字列 統計ファイルの指定
SuperSafe(s) 2値 安全のため、一旦キューに保存する
TempFileMode(F) 8進数 一時ファイルのパーミッション
TimeZoneSpec(t) 文字列 タイムゾーンの設定
Timeout(r) 文字列 各種タイムアウトの設定
TryNullMXList(w) 2値 最上位 MX レコードが自分を指すときに A レコードを使用
UNIXFromLine(\$l) 文字列 From 形式の定義
UnsafeGroupWrites 2値 危険なグループ書き込みパーミッションをチェック
UseErrorsTo(l) 2値 エラー通知に Errors-To: を使用
UserDatabaseSpec(U) 文字列 ユーザデータベースを指定
Verbose(v) 2値 冗長モード
(M) 文字列 マクロの定義


2000.4.26 作成
ホームに戻る