メッセージ

2022年12月26日の記事

2022/12/26(月)メールサーバの中規模改修と基礎知識(4)~ clamAV

clamav_logo.png

clamAV は、サーバサイドでの使用を想定したコンピュータウィルス検出ソフトウェアです。
2022/11/23 に最新版 Ver 1.0.0 がリリースされており、Ver 0.103.7 が旧版の安定バージョンとして 2022/07/26 にリリースされています。

ClamAV の概要

送信・受信共に電子メールメッセージを検査させるため、postfix で、milter インタフェースを介した動作とします。
milter は、インターネット黎明期から Unix 系で使用されてきた Sendmail(電子メール交換サーバソフトウェア) で「拡張機能」として初めて出現し、「Sendmail Content Management API」の短縮名称とされています。

つまり、電子メール送受信に際して、さまざまな拡張機能を提供する仕組みなのですが、「これ」といった仕様書がなく、過去に開発されたインタフェース手順を、ソースコードレベルで継承・踏襲しているといった感じのようです。

この「付加機能提供インタフェース」である、milter を利用して、電子メールメッセージにコンピュータウィルスが含まれているか否かを検査し、結果を反映するのが clamAV の役割です。
混同されがちなものに「コンピュータウィルス」と「spam」があります。前者は、使用しているパソコンや情報機器に具体的な障害を与えるものを含むもの(具体的には添付ファイルや障害を与えるコンテンツへのリンク)、「spam」は嫌がらせ目的や不快感を繰り返し助長するメッセージを主に指します。

なので、コンピュータウィルスの検査で、spam を実用的に検出するのは難しいものがあり、ClamAV と SpamAssassin を併用するのは、そういった観点があります。

ClamAV のインストール

インストール作業は、root アカウントで行います。
clamAV をインストールする場合、FreeBSD13 では、下記のモジュールが事前に必要です。(但し、2022/12/24 現在)
他のソフトウェアと比較すると、事前に必要なものが多いですが、これらの多くは、Ports や Package でインストールしても、管理上特段問題にはなりません。
 ・perl5-5.36.0 	 (Ports から カテゴリ:lang)
 ・autoconf-2.71	 (Ports から カテゴリ:devel)
 ・libltdl-2.4.7	 (Ports から カテゴリ:devel)
 ・libtool-2.4.7	 (Ports から カテゴリ:devel)
 ・pcre2-10.40		 (Ports から カテゴリ:devel)
 ・cmake-core-3.24.3_2	 (Ports から カテゴリ:devel)
 ・libxml2-2.10.3_1	 (Ports から カテゴリ:textproc)
 ・curl-7.86.0		 (Ports から カテゴリ:ftp)
 ・json-c-0.16		 (Ports から カテゴリ:devel)
 ・jsoncpp-1.9.5	 (Ports から カテゴリ:devel)
 ・check-0.15.2	 (Ports から カテゴリ:devel)
 ・libmspack-0.10.1	 (Ports から カテゴリ:archivers)
 ・tomsfastmath-0.13.1_4(Ports から カテゴリ:math)
 ・python39-3.9.16	 (Ports から カテゴリ:lang)
 ・py39-pytest-7.2.0,1	 (Ports から カテゴリ:devel)
 ・rust-1.66.0		 (Ports から カテゴリ:lang)
更に、インストールに先立ち、clamAV のセキュリティポリシーに従うため、ユーザ clamav を、vipw や useradd コマンドで追加します:

vipw コマンドの場合は、下記の1行を編集画面で追加します。
clamav::65002:65002::0:0:Clam antivirus:nonexistent:/usr/sbin/nologin
vipw でユーザ追加した場合、/etc/group に下記の1行を追加しておきます:
clamav:*:65002:
更に vipw でユーザ追加した場合は、つまらないセキュリティホールを作らないために、下記コマンドも一応実行しておきます:
# passwd clamav
clamAV のコンパイルは、Ver 0.105.0 から、cmake を使うようになりました。下記のように順に実施していきます:
# cp clamav-1.0.0.tar.gz /usr/local/src	 
# cd /usr/local/src	 
# tar xvzf clamav-1.0.0.tar.gz	 
# cd clamav-1.0.0	 
# mkdir build	 
# cd build	 
# cmake .. -D ENABLE_JSON_SHARED=OFF 	(JSONライブラリはスタティックリンク)
Configuration に成功すると、下記のようなサマリーが出力されます。
何かしらの問題がある場合は、問題点を指摘するメッセージが表示され、Configuration プロセスは失敗します。
-- Configuration Options Summary --
    Package Version:        ClamAV 1.0.0
    libclamav version:      11:0:0
    libfreshclam version:   2:2:0
    Install prefix:         /usr/local
    Install database dir:   /usr/local/share/clamav
    Install config dir:     /usr/local/etc
    Host system:            FreeBSD-13.1-RELEASE-p5
    Target system:          FreeBSD-13.1-RELEASE-p5
    Compiler:
        Build type:         RelWithDebInfo
        C compiler:         /usr/bin/cc
        C++ compiler:       /usr/bin/c++
        Rust toolchain:     /usr/local/bin/cargo (1.66.0)
        CFLAGS:             -O2 -g
        CXXFLAGS:           -O2 -g
        WARNCFLAGS:          -Wall -Wextra -Wformat-security
    Build Options:
        Build apps:         ON
        Shared library:     ON
        Static library:     OFF
        Enable UnRAR:       ON
        Examples:           OFF
        Tests:              ON
        Build man pages:    ON
        Build doxygen HTML: OFF
        Maintainer Mode:    OFF
    Build Extras:
        Build milter:       ON  (toggle with -DENABLE_MILTER=ON/OFF)
-- Engine Options --
        Bytecode Runtime:
            interpreter
-- Test Dependencies --
        Unit Test Framework:
            libcheck        /usr/local/include
                            /usr/local/lib/libcheck.so
        Feature Test Framework:
            python3         /usr/local/bin/python3.9
            test command    pytest;-v
-- libclamav Dependencies --
        Compression support:
            bzip2           /usr/include
                            /usr/lib/libbz2.so
            zlib            /usr/include
                            /usr/lib/libz.so
        XML support:
            libxml2         /usr/local/include/libxml2;/usr/local/include/libxml2
                            /usr/local/lib/libxml2.so
        RegEx support:
            libpcre2        /usr/local/include
                            /usr/local/lib/libpcre2-8.so
        Crypto support:
            openssl         /usr/include
                            /usr/lib/libssl.so;/usr/lib/libcrypto.so
        JSON support:
            json-c          /usr/local/include/json-c
                            /usr/local/lib/libjson-c.a
        Threading support:
            pthread
        Locale support:
            iconv           /usr/local/include
                            /usr/local/lib/libiconv.so
-- libfreshclam Extra Dependencies --
        HTTP support:
            curl            /usr/local/include
                            /usr/local/lib/libcurl.so
-- Application Extra Dependencies --
        GUI support:
            ncurses         /usr/include
                            /usr/lib/libncurses.so
        Milter Support:
            libmilter       /usr/include
                            /usr/lib/libmilter.so

-- Configuring done
-- Generating done
-- Build files have been written to: /usr/local/src/clamav-1.0.0/build
引き続き、以下の手順でソースコードからの構築を実施します:
# cmake --build . 			(ウィルススキャナの構築)
# cmake --build . --target install 	(ウィルススキャナのインストール)
続いて、動作に必要な環境とログファイルの初期化です。
# mkdir /var/run/clamav 		(clamd のプロセス情報保存領域)
# chown clamav:mailuser /var/run/clamav 	 
 	 
# touch /var/log/clamd.log	 
# chown clamav /var/log/clamd.log	 
# touch /var/log/clamav-milter.log	 
# chown clamav /var/log/clamav-milter.log	 
# touch /var/log/freshclam.log	 
# chown clamav /var/log/freshclam.log	 
# mkdir /usr/local/share/clamav		(ウィルスデータベース格納先)
# chown clamav:mailuser /usr/local/share/clamav
clamd,freshclam,clamAV-milter それぞれ、別々に動作します。
それぞれの設定ファイルを、/usr/local/etc 配下に作成します。通常、ここまでの手順を踏んでいれば、インストールされているはずです。

先ず、/usr/local/etc/clamd.conf の設定ファイルを、下記を参考に該当行を変更します。
# Example				  ← 削除
LogFile /var/log/clamd.log		  ← 追加又は変更
LogTime yes				  ← 追加又は変更
PidFile /var/run/clamav/clamd.pid	  ← 追加又は変更
DatabaseDirectory /usr/local/share/clamav  ← 追加又は変更
LocalSocket /var/run/clamav/clamd	  ← 追加又は変更
FixStaleSocket yes			  ← 追加又は変更
User clamav				  ← 追加又は変更
AllowSupplementaryGroups yes		  ← 追加又は変更
続いて、/usr/local/etc/freshclam.conf の設定ファイルを、下記を参考に該当行を変更します。
# Example				  ← 削除
DatabaseDirectory /usr/local/share/clamav  ← 追加又は変更
UpdateLogFile /var/log/freshclam.log	  ← 追加又は変更
PidFile /var/run/clamav/freshclam.pid	  ← 追加又は変更
DatabaseOwner clamav			  ← 追加又は変更
DatabaseMirror db.jp.clamav.net		  ← 追加又は変更
DatabaseMirror clamav.nara.wide.ad.jp	  ← 追加又は変更
NotifyClamd /usr/local/etc/clamd.conf	  ← 追加又は変更
最後に、/usr/local/etc/clamav-milter.confの設定ファイルを、下記を参考に該当行を変更します。
# Example					 ← 削除
MilterSocket unix:/var/run/clamav/clmilter.sock	 ← 追加又は変更
User clamav					 ← 追加又は変更
AllowSupplementaryGroups yes			 ← 追加又は変更
PidFile /var/run/clamav/clamav-milter.pid	 ← 追加又は変更
TemporaryDirectory /var/tmp			 ← 追加又は変更
ClamdSocket unix:/var/run/clamav/clamd		 ← 追加又は変更
LogFile /var/log/clamav-milter.log		 ← 追加又は変更
3つの設定ファイル変更が終わったら、以下の手順でウィルスパターン定義を初期化・最新版に更新します:
# rehash	 
# freshclam 	(ウィルススキャンデータベースを最新の状態にする)

起動・停止スクリプトの設置(FreeBSD に特化している項目)

これらのスクリプトは一度作っておくと、バージョンアップの際に再作成の必要はありません。

○ clamd の起動スクリプト
/usr/local/etc/rc.d/ ディレクトリ配下に、clamav_clamd のファイル名で下記内容を作成します。
実行権限を与えることを忘れないようにしてください:
#!/bin/sh

# PROVIDE: clamav_clamd
# REQUIRE: LOGIN
# BEFORE: mail
# KEYWORD: shutdown

#
# Add the following lines to /etc/rc.conf to enable clamd:
#
# clamav_clamd_enable="YES"
# clamav_clamd_flags=""
#
# See clamd(8) for flags
#

. /etc/rc.subr

name=clamav_clamd
rcvar=clamav_clamd_enable

# read settings, set default values
load_rc_config "$name"

: ${clamav_clamd_enable:=NO}
: ${clamav_clamd_socket="/var/run/clamav/clamd"}
: ${clamav_clamd_pidfile="/var/run/clamav/clamd.pid"}
: ${clamav_clamd_user="clamav"}

command=/usr/local/sbin/clamd
required_dirs=/var/db/clamav
required_files=/usr/local/etc/clamd.conf

start_precmd=clamav_clamd_precmd
extra_commands=reload
reload_cmd="/usr/local/bin/clamdscan --reload"

clamav_clamd_precmd()
{
        local rundir=${clamav_clamd_pidfile%/*}
        if [ ! -d $rundir ] ; then
                install -d -m 0755 -o ${clamav_clamd_user} -g ${clamav_clamd_user} $rundir
        fi
        if [ ! -f /var/db/clamav/main.cvd -a ! -f /var/db/clamav/main.cld ];then
                echo "Missing /var/db/clamav/*.cvd or *.cld files.  You must run freshclam first"
                exit 1
        fi
}

run_rc_command "$1"
○ freshclam の起動スクリプト
これは、一定時間毎に新しいコンピュータウィルス定義パターンを更新するためのものです。
/usr/local/etc/rc.d/ ディレクトリ配下に、clamav_freshclam のファイル名で下記内容を作成します。
実行権限を与えることを忘れないようにしてください:
#!/bin/sh

# PROVIDE: clamav_freshclam
# REQUIRE: LOGIN clamav_clamd
# BEFORE: mail
# KEYWORD: shutdown

#
# Add the following lines to /etc/rc.conf to enable the freshclam daemon:
#
# clamav_freshclam_enable="YES"
# clamav_freshclam_flags=""
#
# See freshclam(1) for flags
#

. /etc/rc.subr

name=clamav_freshclam
rcvar=clamav_freshclam_enable

# read settings, set default values
load_rc_config ${name}

: ${clamav_freshclam_enable:=NO}
: ${clamav_freshclam_pidfile=/var/run/clamav/freshclam.pid}
: ${clamav_freshclam_user=clamav}

command=/usr/local/bin/freshclam
pidfile=${clamav_freshclam_pidfile}
command_args="--daemon -p ${pidfile}"
required_dirs=/var/db/clamav
required_files=/usr/local/etc/freshclam.conf

start_precmd=clamav_freshclam_precmd

clamav_freshclam_precmd()
{
        local rundir=${clamav_freshclam_pidfile%/*}
        if [ ! -d $rundir ] ; then
                install -d -m 0755 -o ${clamav_freshclam_user} -g ${clamav_freshclam_user} $rundir
        fi
}

run_rc_command "$1"
○ clamav-milter の起動スクリプト
/usr/local/etc/rc.d/ ディレクトリ配下に、clamav_milter のファイル名で下記内容を作成します。
実行権限を与えることを忘れないようにしてください:
#!/bin/sh

# PROVIDE: clamav_milter
# REQUIRE: LOGIN clamav_clamd
# BEFORE: mail
# KEYWORD: shutdown

#
# Add the following lines to /etc/rc.conf to enable clamav-milter:
#
# clamav_milter_enable="YES"
#
# See clamav-milter(1) for flags
#

. /etc/rc.subr

name=clamav_milter
rcvar=clamav_milter_enable

load_rc_config $name

: ${clamav_milter_enable:=NO}
: ${clamav_milter_socket="/var/run/clamav/clmilter.sock"}
: ${clamav_milter_conf="/usr/local/etc/clamav-milter.conf"}
: ${clamav_milter_flags="-c ${clamav_milter_conf}"}
: ${clamav_milter_socktimeout=60}
: ${clamav_milter_socket_mode=777}
: ${clamav_milter_socket_user=clamav}
: ${clamav_milter_socket_group=mailuser}
: ${clamav_clamd_enable:=NO}
: ${clamav_clamd_socket="/var/run/clamav/clamd"}

command=/usr/local/sbin/clamav-milter
required_dirs=/var/db/clamav
required_files=${clamav_milter_conf}

start_precmd=start_precmd
start_postcmd=start_postcmd

start_precmd()
{
        if [ -S "$clamav_milter_socket" ]; then
                warn "Stale socket $clamav_milter_socket removed."
                rm "$clamav_milter_socket"
        fi
        rc_flags="${flags:-$clamav_milter_flags}"

        clamav_clamd_socket_prefix=${clamav_clamd_socket%:*}
        # We can have inet or inet6, try to remove 6
        clamav_clamd_socket_prefix=${clamav_clamd_socket_prefix%6}

        if checkyesno clamav_clamd_enable && [ "x$clamav_clamd_socket" != "x" -a "${clamav_clamd_socket_prefix}" != "inet" ]; then
                echo -n "Waiting for clamd socket.. "
                i=${clamav_milter_socktimeout}
                while [ $i -ne 0 ]
                do
                        [ -S "$clamav_clamd_socket" ] && break
                        if [ `expr $i % 10` -eq 0 ]; then
                                echo -n "${i}.. "
                        fi
                        sleep 1
                        i=$(($i-1))
                done
                echo
                if [ $i -eq 0 ]; then
                        echo "There is no clamd socket (${clamav_clamd_socket})!"
                        exit 1
                fi
        fi
}

start_postcmd()
{
        clamav_milter_socket_prefix=${clamav_milter_socket%:*}
        # We can have inet or inet6, try to remove 6
        clamav_milter_socket_prefix=${clamav_milter_socket_prefix%6}

        if [ "x$clamav_milter_socket" != "x" -a "${clamav_milter_socket_prefix}" != "inet" ]; then
                echo -n "Waiting for clamav-milter socket.. "
                i=${clamav_milter_socktimeout}
                while [ $i -ne 0 ]
                do
                        [ -S "$clamav_milter_socket" ] && break
                        if [ `expr $i % 10` -eq 0 ]; then
                                echo -n "${i}.. "
                        fi
                        sleep 1
                        i=$(($i-1))
                done
                echo
                if [ $i -eq 0 ]; then
                        echo "There is no clamav-milter socket (${clamav_milter_socket})!"
                        exit 1
                fi
                /bin/chmod ${clamav_milter_socket_mode} ${clamav_milter_socket}
                /usr/sbin/chown ${clamav_milter_socket_user}:${clamav_milter_socket_group} ${clamav_milter_socket}
        fi
}

run_rc_command "$1"
clamAV のインストールは、これでとりあえず完了です。