Sorry, this page is japanese only. last updated at 2002/08/21

sendmailのmilterでメールのウィルスを削除

ver 2.1 2002/08/21 ver 2.0に関する説明
ver 1.2 2001/08/12

動機

 近年、メールの添付ファイルによるウィルス/ワームが増殖しています。
 記憶に新しいところでは、"I LOVE YOU","Hybris","SirCam"等があります。

 これらのワームは、メールの添付ファイルとしてインターネット上を駆け巡り、増殖を続けています。
 最近のワームは、送信者情報が殆ど判らないものも多く、感染者に注意を呼びかけるのも難しい状態です。

 メール利用者に対し、うかつに添付ファイルを実行しないように意識改革を進めるのが本道ですが、 メール利用者にウィルスを渡さないことで、被害の拡大を抑えることも考えなければいけない状況になっています。
 メール利用者にウィルスを渡さないためには、メールサーバーがウィルスを削除してしまうのが効果的です。

 現在、市販のサーバー向けウィルスフィルタなども手に入るようですが、個人でサーバーを立てている身には、 価格やサポートしているOS等の問題で導入できそうもありません。

 そこで、sendmail-8.10.xから導入されたmilterを使ってウィルス類の添付ファイルを削除してしまうことにしました。
 milterは、外から来るメール以外にも、中から出すメールに対しても有効ですので、誤って自分が感染した場合も、外部に被害を拡大しないで済みます。

 以前からやらなくちゃいけないと思いつつ、後回しになっていたのですが、 特に最近になって、"SirCam"などにより、大きな添付ファイルを送りつけられるのがいやになって、作成に至りました。

 ウィルスチェッカーを通してから削除するという手段も有りえますが、未知のウィルスに対する予防まで考えると、 ウィルスに利用され、かつ、簡単に実行してしまいがちなファイル形式は、全て削除してしまうのがBESTと思います。


動作

 sendmailのmilterを使って、ウィルス類の添付ファイルを削除し、削除したことを示すメッセージに置き換えます。
 削除する添付ファイルは、以下の拡張子を持つものです。
  ".exe" ".scr" ".com" ".pif" ".bat" ".lnk" ".vbs" ".vbe" ".shs"
 添付ファイルの代わりに、以下のようなメッセージに置き換えます。

== WARNING Attached file deleted by mail filter ==
== deleted file is <HDBCDEHD.EXE> ==

Ver 2.0の新機能

 定義ファイルの設定により拡張子とヘッダーの内容を調べ、添付削除の他、拒否・メールそのもの削除・ 拡張子の付け替え等を行えるようにしました。
 ウィルス系の添付ファイルに特有の二重拡張子のチェックも一応できます。
 メール本文に注意事項を追加できます。(あまりお薦めしません)
 オリジナルメールを保存できるようにしました。(制限有り)
 テストのための機能の追加により、ストリーム型のフィルタにもなります。
 但し、milterとしてのテスト用ですのでパフォーマンスは良くありません。

効能

 誤ってウィルスを実行してしまうことがなくなる。
 添付ファイルを削除するので、メールのサイズが小さくなる。
 常駐型ウィルスチェッカーが文句を言わなくなる。
 なお、MS-WORD等のマクロウィルスには無力です。

未解決の問題

 8bit文字を含むファイル名全体をエンコードするメーラーがある。
 複数行を使ってファイル名が記述してある場合がある。(本来のRFCの仕様)
 multipartをちゃんと終了していないメールはフィルターがかからない。
 multipartでない、ファイルのみのメールに対応していない。(2.0は対応)
 当然ながら、自己展開アーカイブをメールでやり取りできなくなる。

 現状、これらの形態でメールを出すウィルスは見当たらないので、わざわざウィルスを転送してくる友人等がいなければ大丈夫でしょう。
 ファイルのみのメールはあるのかもしれません。(対応予定)

プログラムのダウンロード

注:sendmail-8.11.x用です。8.10.xは仕様が違いますので使えません。
exefilter-1.2.tgz (exefilter.c, Makefile, exefilter.sh, mailer.conf)
exefilter-2.1.tgz (exefilter.c, Makefile, exefilter.sh, mailer.conf, exefilter.rul.jis)

 ライセンス条件は、基本的にBSDライセンスに準じますが、ソースからCopyright表記をはずさない限りは、自由にして下さって結構です。
 当然のことですが、このプログラムを使用して重要なメールを受け取り損ねたりしても、当方は一切責任を負いませんので、覚悟してお使い下さい。
 でも、何かしら改善したら公開していただけると有りがたいです。

 他OSでは、
  strcasecmp, strncasecmp
 をなんとかしないといけないかもしれません。
 それぞれ大文字小文字を無視する strcmp, strncmp です。
 参考のサイトにあるプログラムに同様のことを行う関数がありますので、なんとかして下さい。

更新履歴

ver 2.1 2002/08/21
 envelope-のtypoが多数あって機能していなかった。
 フィルタに$content-typeを追加。
 Content-Type:audio/x-wav; でexeを添付しているメールを別扱いできるようになった。
ver 2.0b3 2001/12/18
 SAVEでファイルを2重にopenしていたたのを修正。
ver 2.0b2 2001/10/14
 message/rfc822に対応。エラーメールの添付ファイルも対象にする。
 拡張子なしを<>で表現できるようにした。
 ストリームフィルタがうまく動作していなかった。
ver 2.0b1 2001/08/15
 ルールファイルによる設定機能の追加。テストのためのストリームフィルタ機能

ver 1.2 2001/08/12
 大きなメールのbodyの処理にミスがあった。なぜか不具合になっていなかった。
ver 1.1 2001/08/02
 ファイル名が複数回存在するメールでメモリリークを起こしていたのを修正。
ver 1.0 2001/07/29
 公開初版

導入したシステム

 AT互換機のFreeBSD4.3-RELEASE 2001/07/27時点のports
 sendmail-8.11.4


参考資料

 http://aeschi.ch.eu.org/milter/
  ファイル名を変更することでウィルスの実行を抑止します。
  ウィルス本体は、メールに付いたままです。

 sendmail配布のlibmilter/README
  milterを使用するための設定情報と、サンプルプログラムが記述されています。

 sendmail配布のinclude/libmilter/mfapi.h
  libmilterの定数、関数の説明がコメントとして書かれています。

 ウィルスチェッカーを通したければ、以下のURLが参考になるでしょう。
  http://www.amavis.org/
  http://www2.defcon1.org/html/Linux_mode/install-swap/anti-virus-sendmail.html
  ローカルメーラーにウィルススキャナを組み込むタイプです。出て行くメールには何もしません。
  どうやら、amavisdがsendmailのmilterとして使えるようです。


milter対応のsendmailの作成

 FreeBSDに標準で入っているsendmailは、milterを使用できるようにはコンパイルされていません。
 そこで、milter機能を有効にしたsendmailを作成します。
 FreeBSDの場合は、sendmailの作成方法は複数あります。
  1. FreeBSDのportsシステムを使って作成する。
  2. オリジナルのsendmailを取ってきて作成する。
 通常のsendmailのインストール方法は他のページ等でいくらでも説明されていますので、ここでは扱いませんが、devtools/Site/site.config.m4を書きかえることでmilterに対応できます。

FreeBSDのportsでmilter対応のsendmailを作成する。

 まずは、/usr/ports/mail/sendmailに移動します。
 Makefileを眺めると、SENDMAIL_WITH_MILTERを定義することで、milter対応のsendmailが作成されることがわかります。

 cd /usr/ports/mail/sendmail
 make -DSENDMAIL_WITH_MILTER all install
 /etc/mail/mailer.conf内をインストール先の/usr/local/sbin/sendmailに書き換えます。

 これだけで、でき上がりです。
 portsって簡単すぎてあっけないぐらいです。先人の努力に感謝。

portsを使わない場合のmilter対応のsendmailの作成

 これでは、他のOSを使用している方の参考にならないので、milter対応のsendmailを作成する基本を書いておきます。
 sendmailのソースの展開後、devtools/Site/site.config.m4 の最後に以下の3行を追加します。

dnl Milter
APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1')
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1')

 普通にsendmailを作成します。
 一般的には、"./Build all"です。

 これだけでは、libmilterを作成してくれませんので、
 cd libmilter
 ./Build install

 libmilter.a が /usr/lib に
 mfapi.h が /usr/include にインストールされると思います。
 その他、こまごましたことは、他のsendmailのインストールページ等でお調べ下さい。


フィルタープログラムを作成する

exefilter.cをお手元にご用意下さい。
libmilter.a と mfapi.h のインストールされた場所を確認して下さい。

sendmailを普通にportsでインストールした場合は、
sendmail-8.11.xでは
 cc -O -I/usr/local/include -o exefilter exefilter.c /usr/local/lib/libmilter.a -pthread
sendmail-8.12.xでは
 cc -O -I/usr/local/include -o exefilter exefilter.c /usr/local/lib/libmilter.a /usr/local/lib/libsm.a -pthread
で、コンパイルします。

sendmailをソースからインストールした場合は、
sendmail-8.11.xでは
 cc -O -o exefilter exefilter.c -lmilter -pthread
sendmail-8.12.xでは
 cc -O -o exefilter exefilter.c -lmilter -lsm -pthread
でいいのかな?

他のOSでは、-pthreadは、対応するオプションに書きかえる必要があるようです。
/usr/local/libexecにでもインストールしておきましょう。
 install -c -s -o bin -g bin 555 exefilter /usr/local/libexec
Ver2.0では、ルール定義ファイルを用意し、/etc/mail/exefilter.rulに置きます。


sendmail.cfの作成

 cd /etc/mail
 cp freebsd.mc exefilter.mc
 exefilter.mcの適当なところに

  INPUT_MAIL_FILTER(`exefilter', `S=local:/var/run/f1.sock, F=R')

 を追加します。
 私は、FEATUREが並んでる部分の後ろに追加しました。
 なお、"F=R"は、exefilterが動作していない時は、メールの受け取りはエラーになります。
 "F=T"にすると、exefilterが動作していない時は、メールの受け取りは保留になります。
 "F="がない場合には、exefilterが動作していない時は、フィルターなしで受け取ります。

 make exefilter.cf とやりたい所ですが、こちらも、milter対応で作成しなければいけません。

 /usr/bin/m4 -D_FFR_MILTER=1 -D_CF_DIR_=/usr/local/share/sendmail/cf/ /usr/local/share/sendmail/cf/m4/cf.m4 exefilter.mc > exefilter.cf
 cp exefilter.cf sendmail.cf で新しいsendmail.cfに入れ替えます。

 他のOSをお使いの場合は、libmilter/READMEを読んで作ってください。
 cfで作る場合は、
  INPUT_MAIL_FILTER(`exefilter', `S=local:/var/run/f1.sock, F=R')
 を追加し、   m4 -D_FFR_MILTER=1 -D_CF_DIR_=cf/ cf/m4/cf.m4 foo.mc > foo.cf  とかやればできるんじゃないかと思います。
 sendmail.cfを直接いじる場合は、
  Xexefilter, S=local:/var/run/f1.sock, F=R
  O InputMailFilters=exefilter
 を追加することになります。


exefilterの起動とsendmailの起動

 sendmailとexefilter間のデータのやり取りは、socketで行われます。
 socketの名前は、sendmail.cfとexefilterの-pオプションで指定します。
 名前が違っていると動作しません。
 また、sendmailより先にexefilterが起動していないとうまく動作しません。
 FreeBSDのrc.confによる標準のsendmail起動では、exefilterを先に起動することができません。
 そこで、rc.confでは、sendmail_enable="NO"にしておき、/usr/local/etc/rc.dに起動スクリプトを置くことで対処します。

/usr/local/etc/rc.d/exefilter.sh
chmod +x exefilter.sh をお忘れ無く。
#!/bin/sh
case "$1" in
start)
	[ -x /var/run/f1.sock ] && ( /bin/rm /var/run/f1.sock )
	[ -x /usr/local/libexec/exefilter ] && ( /usr/local/libexec/exefilter -p /var/run/f1.sock ) && echo -n ' exefilter'
	/usr/local/sbin/sendmail -bd -q30m && echo -n ' sendmail'
	;;
stop)
	killall sendmail
	killall exefilter
	;;
esac

exit 0

おまけ

libmilter使用プログラム作成上の注意点
 複数のメールを同時受信する場合があるので、メール解析中のデータは、すべてsmfi_getpriv()で取得して使う。
 headerについては、sendmailが使いやすい形にしてくれるので、folding等を気にしなくてよい。
 bodyは、行の途中でも容赦なく切られて渡されるので、bodyの中身をいじる場合は、注意が必要。
 また、bodyの最後に'\0'を期待してはいけない。
 SMFIS_TEMPFAIL,SMFIS_REJECT等で後続処理を打ち切る場合、後始末をしっかりやらなければメモリリークが発生します。
 充分なテストを行わないで使用すると、不審なエラーを返したり、メールの行方不明等が発生します。

テストの仕方
 別にマシンを1台用意して、そちらにmilter使用の環境を作ります。
 普通に動作しているマシンから、.forwardなどでコピーをテストマシンに送ります。
 この時に、"|/usr/sbin/sendmail -ftestuser testuser@testmachine"のように"-f"を使用して、エラーが発生した場合に外部に迷惑をかけないようにしましょう。


ご意見、ご感想、改善案などは、hagi@nandemo.gr.jpまで
Copyright (c) 2001 Hagihara, Takayuki