Mimedefang 安裝

作者:David Chang
E-mail:david@tmv.gov.tw
如內容有誤歡迎來函指正


------------------------------
一﹐前言
------------------------------

隨著email在企業裡廣泛使用,它已經成為傳播病毒(Virus)、蠕蟲(Worm)的最主要的手段,保護企業用戶免受可能帶病毒的郵件附件的感染,尤其是可執行文件的郵件附件,需要過濾那些可能帶有病毒的附件的郵件。在企業上的做法除了為每一部 PC 加裝防毒軟體外,有錢的企業還會買個 Visus Scaner for Mail Server (例如 Sophos,McAfee)即時掃描含有病毒的郵件。但是這些產品通常是架構在 Windows平台上的 Exchange Server 而且上述 products 的 virusdb 更新需要授權(意味著需要 $$)。
對於在 SMTP Server 佔有率遠超過 Exchange Server 的用戶而言 Mimedefang+ClamAV 的出現讓愛用 Sendmail 的用戶也能享有 Online scan 的好處,更重要的是這完全免費。

------------------------------
二﹐Sendmail、Mimedefang、
ClamAV 的關係
------------------------------

SendmailMimedefangClamAV 的關係
MimedefangSendmail 所支援郵件過濾器(Milter)的一種。
ClamAVMimedefang 所支援防毒軟體的一種,ClamAV 的 virus database 是以 OpenAntiVirus 為基準,時常更新而且免費。




------------------------------
三﹐使用 mimedefang 的好處
------------------------------


1. 封鎖病毒郵件
2. 封鎖垃圾郵件(spam)
3. 移除 HTML 格式電子郵件的附件
4. Add boilerplate disclaimers to outgoing mail
5. 移除或變更郵件的附件

------------------------------
四﹐安裝 Mimedefang 的需求
------------------------------

1.作業系統(OS):Linux 或 Unix 系統,下列系統已被測試過
Red Hat Linux 9
Red Hat Linux 8.0
Red Hat Linux 7.3
Red Hat Linux 7.2 (筆者使用)
Red Hat Linux 7.1
Red Hat Linux 7.0
Red Hat Linux 6.2
Red Hat Linux 6.1
Slackware Linux 9.0
Slackware Linux 8.1
Slackware Linux 8.0
Slackware Linux 7.1
Slackware Linux 7.0
SuSE Linux 7.3
Solaris 8
Solaris 7
Solaris 2.5.1
FreeBSD 4.5-STABLE
OpenBSD 3.0
AIX 5.1
AIX 4.3.3
HP-UX 11.00

2. Perl 5.001 以上的版本



------------------------------
五﹐參考資料
------------------------------


Mimedefang 首頁 http://www.roaringpenguin.com/mimedefang/
Mimedefang 是 sendmail(http://www.sendmail.org) 的一種 miller (http://www.milter.org)
這份安裝文件參考自 http://www.rudolphtire.com/mimedefang-howto/

------------------------------
六﹐開始實作
------------------------------



《※※※ PART I、安裝 sendmail 8.12.9 以上※※※》 (必須安裝)
1. 建立群組 smmsp
# groupadd -g 25 smmsp

2. 建立使用者 smmsp
# useradd -u 25 -g smmsp -d /dev/null -s /bin/false

3. 備份 /etc/mail 及 /usr/sbin/sendmail (或者 /usr/lib/sendmail)
#cp -Rp /etc/mail /etc/mail.org
#cp -p /usr/sbin/sendmail /usr/sbin/sendmail.org


4. 自 sendmail.org 下載 sendmail 8.12.10 到 /tmp 目錄中
#cd /tmp
#wget ftp://ftp.sendmail.org/pub/sendmail/sendmail.8.12.10.tar.gz


5. 解開壓縮檔
#tar zxvf sendmail.8.12.10.tar.gz
#cd sendmail-8.12.10


6. 建立新檔案 /tmp/sendmail-8.12.10/devtool/Site/site.config.m4 並加入以下三行資料
dnl Milter
APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER_ROOT_UNSAFE')


7. 編譯 sendmail
#cd /tmp/sendmail-8.12.10/sendmail
#sh Build -c


8. 建立 sendmail 設定檔
#cd /tmp/sendmail-8.12.10/cf/cf
#cp generic-linux.mc local.mc


9. 修改 local.mc 並加入下面這一行
INPUT_MAIL_FILTER(`mimedefang', `S=unix:/var/spool/MIMEDefang/mimedefang.sock, T=S:5m;R:5m')


10. 產生 sendmail.cf
#sh Build local.cf
#cp local.cf /etc/mail/sendmail.cf


11. 安裝 sendmail 8.12.10
#cd /tmp/sendmail-8.12.10
#cd sendmail/
#sh Build install
#cd ..
#cd makemap
#sh Build
#sh Build install
#cd ..

#cd libmilter
#sh Build
#sh Build install
#cd ..

#cd smrsh
#sh Build
#sh Build install
#cd ..
#cd /usr/src/sendmail/sendmail-8.12.10


12. 安裝 MIMEDefang 所需要的的 headers and libraries :
#mkdir -p /usr/local/include/sendmail
#cp -R include/* /usr/local/include/sendmail
#cp -R sendmail/*.h /usr/local/include/sendmail
#mkdir -p /usr/local/lib
#cp obj.Linux.2.4.7-10.i686/*/*.a /usr/local/lib


13. 編輯相關檔案
# vi /etc/mail/local-host-names (如果郵件伺服器有別名請在此建立)
yourcompany.com
mail.yourcompany.com



# vi /etc/mail/relay-domains (允許 relay 的機器)
yourcompany.com


# vi /etc/mail/aliases (將 mimedefang 與 root 設定到可用的住址)
root:yourname@example.com
mimedefang:yourname@example.com


14. 啟動 sendmail
# /usr/sbin/sendmail -L sm-mta -bd -q15m
# /usr/sbin/sendmail -L sm-msp-queue -Ac -q30m




《※※※ PART II、安裝 Perl's Modules ※※※》 (必須安裝)
請參考 http://www.rudolphtire.com/mimedefang-howto/#s5

1.安裝 IO-stringy 模組
# cd /tmp
#wget http://www.cpan.org/authors/id/ERYQ/IO-stringy-2.108.tar.gz
#tar xvfz IO-stringy-2.108.tar.gz
#cd IO-stringy-2.108
#perl Makefile.PL
#make
#make test
#su -c 'make install'


2.安裝 MIME-Base64 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/GAAS/MIME-Base64-2.21.tar.gz
#tar xvfz MIME-Base64-2.21.tar.gz
#cd MIME-Base64-2.21
#perl Makefile.PL
#make
#make test
#su -c 'make install'


3.安裝 MailTools 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/M/MA/MARKOV/MailTools-1.60.tar.gz
#tar xvfz MailTools-1.60.tar.gz
#cd MailTools-1.60
#perl Makefile.PL
#make
#make test
#su -c 'make install'


4.安裝 MIME-tools 模組
#cd /tmp
#wget http://www.mimedefang.org/static/MIME-tools-5.411a-RP-Patched-02.tar.gz
#tar xvfz MIME-tools-5.411a-RP-Patched-02.tar.gz
#cd MIME-tools-5.411a-RP-Patched-02
#perl Makefile.PL
#make
#make test
#su -c 'make install'


5.安裝 Digest-SHA1 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/GAAS/Digest-SHA1-2.06.tar.gz
#tar xvfz Digest-SHA1-2.06.tar.gz
#cd Digest-SHA1-2.06
#perl Makefile.PL
#make
#make test
#su -c 'make install'


6.安裝 libnet 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/GBARR/libnet-1.17.tar.gz
#tar xvfz libnet-1.17.tar.gz
#cd libnet-1.17
#perl Makefile.PL
#make
#make test
#su -c 'make install'


7.安裝 Mail-Audit 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/S/SI/SIMON/Mail-Audit-2.1.tar.gz
#tar xvfz Mail-Audit-2.1.tar.gz
#cd Mail-Audit-2.1
#perl Makefile.PL
#make
#make test
#su -c 'make install'


8.安裝 Time-HiRes 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/J/JH/JHI/Time-HiRes-1.51.tar.gz
#tar xvfz Time-HiRes-1.51.tar.gz
#cd Time-HiRes-1.51
#perl Makefile.PL
#make
#make test
#su -c 'make install'


9.安裝 HTML-Tagset 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/S/SB/SBURKE/HTML-Tagset-3.03.tar.gz
#tar xvfz HTML-Tagset-3.03.tar.gz
#cd HTML-Tagset-3.03
#perl Makefile.PL
#make
#make test
#su -c 'make install'


10.安裝 HTML-Parser 模組
#cd /tmp
#wget http://www.cpan.org/authors/id/G/GA/GAAS/HTML-Parser-3.33.tar.gz
#tar xvfz HTML-Parser-3.33.tar.gz
#cd HTML-Parser-3.33
#perl Makefile.PL
#make
#make test
#su -c 'make install'


《※※※ PART III、安裝 Spamassassin ※※※》 (選項安裝)
請參考 http://www.rudolphtire.com/mimedefang-howto/#s6
1.下載 SpamAssassin 2.60
#cd /tmp
#wget http://www.spamassassin.org/released/Mail-SpamAssassin-2.60.tar.gz
#tar xvfz Mail-SpamAssassin-2.60.tar.gz
#perl Makefile.PL
#make
#su -c 'make install'

請注意!不要執行 make test

2.移除不必要的 whitelist
#rm /usr/share/spamassassin/60_whitelist.cf

3.由於 spamassassin 將相關的 conf 檔安裝在 /usr/share/spamassassin 中,但 spamassassin 主程式預設的讀取路徑是 /etc/mail/spamassassin ,所以記得再執行下面這個指令:
#cp /usr/share/spamassassin/* /etc/mail/spamassassin




《※※※ PART IV、安裝 Virus Scanner--ClamAV ※※※》 (必須安裝)
請參考 http://linux-sxs.org/administration/clamav.html 安裝步驟
1.下載 ClamAV
#cd /tmp
#wget http://keihanna.dl.sourceforge.net/sourceforge/clamav/clamav-0.60.tar.gz


2.解開壓縮檔
#tar zxvf clamav-0.60.tar.gz
#cd clamav-0.60


3.建立所需要的群組 clamav
#groupadd clamav

4.建立所需要的使用者 clamav
#useradd -g clamav -d /dev/null clamav

5.編譯與安裝
#./configure --prefix=/usr --sysconfdir=/etc
#make
#make install


6.編輯 clamav 設定檔 /etc/clamav.conf,內容如下:
##
## config file for Clam AV daemon
##

# This option allows you to save the process identifier of the listening
# daemon (main thread).
PidFile /var/spool/MIMEDefang/clamd.pid

# Path to a directory containing .db files.
# Default is the hardcoded directory (mostly /usr/local/share/clamav,
# it depends on installation options).
DataDirectory /usr/share/clamav

# The daemon works in local or network mode. Currently the local mode is
# recommended for security reasons.

# Path to the local socket. The daemon doesn't change the mode of the
# created file (portability reasons). You may want to create it in a directory
# which is only accessible for a user running daemon.
LocalSocket /var/spool/MIMEDefang/clamd.sock

# Maximal number of a threads running at the same time.
# Default is 5, and it should be sufficient for a typical workstation.
# You may need to increase threads number for a server machine.
MaxThreads 200

# Maximal depth the directories are scanned at.
MaxDirectoryRecursion 15

# Run as selected user (clamd must be started by root).
# By default it doesn't drop priviledges.
User defang

##
## Archive support
##

# Comment this line to disable scanning of the archives.
ScanArchive

# Options below protect your system against Denial of Service attacks
# with archive bombs.

# Files in archives larger than this limit won't be scanned.
# Value of 0 disables the limit.
# WARNING: Due to the unrarlib implementation, whole files (one by one) in RAR
# archives are decompressed to the memory. That's why never disable
# this limit (but you may increase it of course!)
ArchiveMaxFileSize 10M

# Archives are scanned recursively - e.g. if Zip archive contains RAR file,
# the RAR file will be decompressed, too (but only if recursion limit is set
# at least to 1). With this option you may set the recursion level.
# Value of 0 disables the limit.
ArchiveMaxRecursion 5

# Number of files to be scanned within archive.
# Value of 0 disables the limit.
ArchiveMaxFiles 1000


7.建立更新病毒碼程序檔 /root/clamav_update,內容如下:
#!/bin/sh
/usr/bin/freshclam --quiet --stdout --datadir /usr/share/clamav --log /var/tmp/clamav_update


8.變更檔案模式為可執行
#chmod 755 /root/clamav_update

9.將 /root/clam_update 複製到 /etc/cron.daily 中每日定時更新
#cp /root/clam_update /etc/cron.daily

10.建立 clamav 系統啟動程序 /etc/init.d/clamav,內容如下:
#!/bin/sh

FOO_BIN=/usr/sbin/clamd
test -x $FOO_BIN || exit 5

case "$1" in
start)
echo "Starting `$FOO_BIN -V`"
$FOO_BIN

;;
stop)
echo "Shutting down `$FOO_BIN -V`"
killall $FOO_BIN

;;
restart)
$0 stop
$0 start

;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac


11. 啟動 ClamAV Daemon
#/etc/init.d/clamav start



《※※※ PART V、安裝 MIMEDefang ※※※》 (必須安裝)
請參考 http://www.rudolphtire.com/mimedefang-howto/#s8

1.建立所需要的群組 defang
#groupadd defang

2.建立所需要的使用者 defang
#useradd -g defang -d /var/spool/MIMEDefang defang

3.建立所需目錄
#mkdir /var/spool/MIMEDefang
#chmod 700 /var/spool/MIMEDefang
#chown defang /var/spool/MIMEDefang
#chgrp defang /var/spool/MIMEDefang


4.下載Mimedefang
#cd /tmp
#wget http://www.mimedefang.org/static/mimedefang-2.38.tar.gz


5.解開壓縮檔
#tar zxvf mimedefang-2.38.tar.gz
#cd mimedefang-2.38


6.編譯與安裝 Mimedefang
#./configure
#make
#su -c 'make install'


7.建立 Mimedefang 系統啟動程序 /etc/init.d/mimedefang
#su -c 'cp examples/init-script /etc/init.d/mimedefang'

8.啟動 Mimedefang Daemon
# /etc/init.d/mimedefang start


備註:
1.本人在安裝完 mimedefang 2.35 後無法啟動,經查驗 /var/log/maillog 出現 /usr/lib/perl5/5.6.0/i386-linux/Sys/Syslog.pm line 277 的錯誤訊息。將該檔案 277 行改為 my $syslog = _PATH_LOG() || croak "_PATH_LOG not found in syslog.ph";即可正常啟動。

2.Mimedefang 設定檔(for 2.35) /etc/mimedefang 的一些說明:
通常安裝完 Mimedefang ,後其設定檔無須任何的變動即可使用。
# -*- Perl -*-
#***********************************************************************
#
# mimedefang-filter
#
# Suggested minimum-protection filter for Microsoft Windows clients, plus
# SpamAssassin checks if SpamAssassin is installed.
#
# Copyright (C) 2002 Roaring Penguin Software Inc.
#
# This program may be distributed under the terms of the GNU General
# Public License, Version 2, or (at your option) any later version.
#
# $Id: suggested-minimum-filter-for-windows-clients,v 1.65 2003/07/03 23:56:05 dfs Exp $
#***********************************************************************

#***********************************************************************
# Set administrator's e-mail address here. The administrator receives
# quarantine messages and is listed as the contact for site-wide
# MIMEDefang policy. A good example would be 'defang-admin@mydomain.com'
#***********************************************************************
# 管理員的電子郵件住址及名稱
$AdminAddress = 'david@tmv.gov.tw';
$AdminName = "David CHang";

#***********************************************************************
# Set the e-mail address from which MIMEDefang quarantine warnings and
# user notifications appear to come. A good example would be
# 'mimedefang@mydomain.com'. Make sure to have an alias for this
# address if you want replies to it to work.
#***********************************************************************
# Mimedefang 發信人的電子郵件住址
$DaemonAddress = 'mimedefang@localhost';

#***********************************************************************
# If you set $AddWarningsInline to 1, then MIMEDefang tries *very* hard
# to add warnings directly in the message body (text or html) rather
# than adding a separate "WARNING.TXT" MIME part. If the message
# has no text or html part, then a separate MIME part is still used.
#***********************************************************************
$AddWarningsInline = 0;

#***********************************************************************
# To enable syslogging of virus and spam activity, add the following
# to the filter:
# md_graphdefang_log_enable();
# You may optionally provide a syslogging facility by passing an
# argument such as: md_graphdefang_log_enable('local4'); If you do this, be
# sure to setup the new syslog facility (probably in /etc/syslog.conf).
# An optional second argument causes a line of output to be produced
# for each recipient (if it is 1), or only a single summary line
# for all recipients (if it is 0.) The default is 1.
# Comment this line out to disable logging.
#***********************************************************************
md_graphdefang_log_enable('mail', 1);

#***********************************************************************
# Uncomment this to block messages with more than 50 parts. This will
# *NOT* work unless you're using Roaring Penguin's patched version
# of MIME tools, version MIME-tools-5.411a-RP-Patched-02 or later.
#
# WARNING: DO NOT SET THIS VARIABLE unless you're using at least
# MIME-tools-5.411a-RP-Patched-02; otherwise, your filter will fail.
#***********************************************************************
# $MaxMIMEParts = 50;

#***********************************************************************
# Set various stupid things your mail client does below.
#***********************************************************************

# Set the next one if your mail client cannot handle nested multipart
# messages. DO NOT set this lightly; it will cause action_add_part to
# work rather strangely. Leave it at zero, even for MS Outlook, unless
# you have serious problems.
$Stupidity{"flatten"} = 0;

# Set the next one if your mail client cannot handle multiple "inline"
# parts.
$Stupidity{"NoMultipleInlines"} = 0;

# The next lines force SpamAssassin modules to be loaded and rules
# to be compiled immediately. This may improve performance on busy
# mail servers. Comment the lines out if you don't like them.
if ($Features{"SpamAssassin"}) {
spam_assassin_init()->compile_now(1) if defined(spam_assassin_init());

# If you want to use auto-whitelisting:
# if (defined($SASpamTester)) {
# use Mail::SpamAssassin::DBBasedAddrList;
# my $awl = Mail::SpamAssassin::DBBasedAddrList->new();
# $SASpamTester->set_persistent_address_list_factory($awl) if defined($awl);
# }
}

# This procedure returns true for entities with bad filenames.
sub filter_bad_filename ($) {
my($entity) = @_;
my($bad_exts, $re);

# Bad extensions
# 下列副檔名的電子郵件附加檔案將被過濾移除

$bad_exts = '(ade|adp|app|asd|asf|asx|bas|bat|chm|cmd|com|cpl|crt|dll|exe|fxp|hlp|hta|hto|inf|ini|ins|isp|jse?|lib|lnk|mdb|mde|msc|msi|msp|mst|ocx|pcd|pif|prg|reg|scr|sct|sh|shb|shs|sys|url|vb|vbe|vbs|vcs|vxd|wmd|wms|wmz|wsc|wsf|wsh|\{)';

# Do not allow:
# - curlies
# - bad extensions (possibly with trailing dots) at end or
# followed by non-alphanum
$re = '\.' . $bad_exts . '\.*([^-A-Za-z0-9_.,]|$)';
return re_match($entity, $re);
}

# Scan for a virus using the first supported virus scanner we find.
sub message_contains_virus () {
return message_contains_virus_avp() if ($Features{'Virus:AVP'});
return message_contains_virus_fprot() if ($Features{'Virus:FPROT'});
return message_contains_virus_fsav() if ($Features{'Virus:FSAV'});
return message_contains_virus_hbedv() if ($Features{'Virus:HBEDV'});
return message_contains_virus_nai() if ($Features{'Virus:NAI'});
return message_contains_virus_nvcc() if ($Features{'Virus:NVCC'});
return message_contains_virus_rav() if ($Features{'Virus:RAV'});
return message_contains_virus_sophie() if ($Features{'Virus:SOPHIE'});
return message_contains_virus_trophie() if ($Features{'Virus:TROPHIE'});
return message_contains_virus_sophos() if ($Features{'Virus:SOPHOS'});
return message_contains_virus_trend() if ($Features{'Virus:TREND'});
return message_contains_virus_filescan() if ($Features{'Virus:FileScan'});
return message_contains_virus_clamd() if ($Features{'Virus:CLAMD'});
return message_contains_virus_clamav() if ($Features{'Virus:CLAMAV'});
return message_contains_virus_carrier_scan() if ($Features{'Virus:SymantecCSS'});
return (wantarray ? (0, 'ok', 'ok') : 0);
}

# Scan for a virus using the first supported virus scanner we find.
sub entity_contains_virus ($) {
my($e) = @_;
return entity_contains_virus_avp($e) if ($Features{'Virus:AVP'});
return entity_contains_virus_fprot($e) if ($Features{'Virus:FPROT'});
return entity_contains_virus_fsav($e) if ($Features{'Virus:FSAV'});
return entity_contains_virus_hbedv($e) if ($Features{'Virus:HBEDV'});
return entity_contains_virus_nai($e) if ($Features{'Virus:NAI'});
return entity_contains_virus_nvcc($e) if ($Features{'Virus:NVCC'});
return entity_contains_virus_rav($e) if ($Features{'Virus:RAV'});
return entity_contains_virus_sophie($e) if ($Features{'Virus:SOPHIE'});
return entity_contains_virus_trophie($e) if ($Features{'Virus:TROPHIE'});
return entity_contains_virus_sophos($e) if ($Features{'Virus:SOPHOS'});
return entity_contains_virus_trend($e) if ($Features{'Virus:TREND'});
return entity_contains_virus_filescan($e) if ($Features{'Virus:FileScan'});
return entity_contains_virus_clamd($e) if ($Features{'Virus:CLAMD'});
return entity_contains_virus_clamav($e) if ($Features{'Virus:CLAMAV'});
return entity_contains_virus_carrier_scan($e) if ($Features{'Virus:SymantecCSS'});
return (wantarray ? (0, 'ok', 'ok') : 0);
}

#***********************************************************************
# %PROCEDURE: filter_begin
# %ARGUMENTS:
# None
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Called just before e-mail parts are processed
#***********************************************************************
sub filter_begin () {
# ALWAYS drop messages with suspicious chars in headers
if ($SuspiciousCharsInHeaders) {
md_graphdefang_log('suspicious_chars');
action_quarantine_entire_message("Message quarantined because of suspicious characters in headers");
# Do NOT allow message to reach recipient(s)
return action_discard();
}

# Scan for viruses if any virus-scanners are installed
my($code, $category, $action) = message_contains_virus();

# Lower level of paranoia - only looks for actual viruses
$FoundVirus = ($category eq "virus");

# Higher level of paranoia - takes care of "suspicious" objects
# $FoundVirus = ($action eq "quarantine");

if ($action eq "tempfail") {
action_tempfail("Problem running virus-scanner");
md_syslog('warning', "Problem running virus scanner: code=$code, category=$category, action=$action");
}
}

#***********************************************************************
# %PROCEDURE: filter
# %ARGUMENTS:
# entity -- a Mime::Entity object (see MIME-tools documentation for details)
# fname -- the suggested filename, taken from the MIME Content-Disposition:
# header. If no filename was suggested, then fname is ""
# ext -- the file extension (everything from the last period in the name
# to the end of the name, including the period.)
# type -- the MIME type, taken from the Content-Type: header.
#
# NOTE: There are two likely and one unlikely place for a filename to
# appear in a MIME message: In Content-Disposition: filename, in
# Content-Type: name, and in Content-Description. If you are paranoid,
# you will use the re_match and re_match_ext functions, which return true
# if ANY of these possibilities match. re_match checks the whole name;
# re_match_ext checks the extension. See the sample filter below for usage.
# %RETURNS:
# Nothing
# %DESCRIPTION:
# This function is called once for each part of a MIME message.
# There are many action_*() routines which can decide the fate
# of each part; see the mimedefang-filter man page.
#***********************************************************************
sub filter ($$$$) {
my($entity, $fname, $ext, $type) = @_;

return if message_rejected(); # Avoid unnecessary work

# Block message/partial parts
if (lc($type) eq "message/partial") {
md_graphdefang_log('message/partial');
action_bounce("MIME type message/partial not accepted here");
return action_discard();
}

# Virus scan
if ($FoundVirus) {
my($code, $category, $action);
$VirusScannerMessages = "";
($code, $category, $action) = entity_contains_virus($entity);
# If you are more paranoid, change to: if ($action eq "quarantine") {
if ($category eq "virus") {
md_graphdefang_log('virus',$VirusName, $RelayAddr);

# Bounce the mail!
action_bounce("Virus $VirusName found in mail - rejected");

# But quarantine the part for examination later. Comment
# the next line out if you don't want to bother.
action_quarantine($entity, "A known virus was discovered and deleted. Virus-scanner messages follow:\n$VirusScannerMessages\n\n");

return;
}
if ($action eq "tempfail") {
action_tempfail("Problem running virus-scanner");
md_syslog('warning', "Problem running virus scanner: code=$code, category=$category, action=$action");
}
}

if (filter_bad_filename($entity)) {
md_graphdefang_log('bad_filename', $fname, $type);
return action_quarantine($entity, "An attachment named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
}

# eml is bad if it's not multipart
if (re_match($entity, '\.eml')) {
md_graphdefang_log('non_multipart');
return action_quarantine($entity, "A non-multipart attachment named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
}
# Clean up HTML if Anomy::HTMLCleaner is installed.
if ($Features{"HTMLCleaner"}) {
if ($type eq "text/html") {
return anomy_clean_html($entity);
}
}

return action_accept();
}

#***********************************************************************
# %PROCEDURE: filter_multipart
# %ARGUMENTS:
# entity -- a Mime::Entity object (see MIME-tools documentation for details)
# fname -- the suggested filename, taken from the MIME Content-Disposition:
# header. If no filename was suggested, then fname is ""
# ext -- the file extension (everything from the last period in the name
# to the end of the name, including the period.)
# type -- the MIME type, taken from the Content-Type: header.
# %RETURNS:
# Nothing
# %DESCRIPTION:
# This is called for multipart "container" parts such as message/rfc822.
# You cannot replace the body (because multipart parts have no body),
# but you should check for bad filenames.
#***********************************************************************
sub filter_multipart ($$$$) {
my($entity, $fname, $ext, $type) = @_;

if (filter_bad_filename($entity)) {
md_graphdefang_log('bad_filename', $fname, $type);
action_notify_administrator("A MULTIPART attachment of type $type, named $fname was dropped.\n");
return action_drop_with_warning("An attachment of type $type, named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
}

# eml is bad if it's not message/rfc822
if (re_match($entity, '\.eml') and ($type ne "message/rfc822")) {
md_graphdefang_log('non_rfc822',$fname);
return action_drop_with_warning("A non-message/rfc822 attachment named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
}

# Block message/partial parts
if (lc($type) eq "message/partial") {
md_graphdefang_log('message/partial');
action_bounce("MIME type message/partial not accepted here");
return;
}

return action_accept();
}


#***********************************************************************
# %PROCEDURE: defang_warning
# %ARGUMENTS:
# oldfname -- the old file name of an attachment
# fname -- the new "defanged" name
# %RETURNS:
# A warning message
# %DESCRIPTION:
# This function customizes the warning message when an attachment
# is defanged.
#***********************************************************************
sub defang_warning ($$) {
my($oldfname, $fname) = @_;
return
"An attachment named '$oldfname' was converted to '$fname'.\n" .
"To recover the file, right-click on the attachment and Save As\n" .
"'$oldfname'\n";
}

# If SpamAssassin found SPAM, append report. We do it as a separate
# attachment of type text/plain
sub filter_end ($) {
my($entity) = @_;

# If you want quarantine reports, uncomment next line
# send_quarantine_notifications();

# IMPORTANT NOTE: YOU MUST CALL send_quarantine_notifications() AFTER
# ANY PARTS HAVE BEEN QUARANTINED. SO IF YOU MODIFY THIS FILTER TO
# QUARANTINE SPAM, REWORK THE LOGIC TO CALL send_quarantine_notifications()
# AT THE END!!!

# No sense doing any extra work
return if message_rejected();

# Spam checks if SpamAssassin is installed
if ($Features{"SpamAssassin"}) {
if (-s "./INPUTMSG" < 100*1024) {
# Only scan messages smaller than 100kB. Larger messages
# are extremely unlikely to be spam, and SpamAssassin is
# dreadfully slow on very large messages.
my($hits, $req, $names, $report) = spam_assassin_check();
if ($hits >= $req) {
md_graphdefang_log('spam', $hits, $RelayAddr);
my($score);
if ($hits < 40) {
$score = "*" x int($hits);
} else {
$score = "*" x 40;
}
# We add a header which looks like this:
# X-Spam-Score: 6.8 (******) NAME_OF_TEST,NAME_OF_TEST
# The number of asterisks in parens is the integer part
# of the spam score clamped to a maximum of 40.
# MUA filters can easily be written to trigger on a
# minimum number of asterisks...
action_change_header("X-Spam-Score", "$hits ($score) $names");

# If you find the SA report useful, add it, I guess...
action_add_part($entity, "text/plain", "-suggest",
"$report\n",
"SpamAssassinReport.txt", "inline");
} else {
# Delete any existing X-Spam-Score header?
action_delete_header("X-Spam-Score");
}
}
}

# I HATE HTML MAIL! If there's a multipart/alternative with both
# text/plain and text/html parts, nuke the text/html. Thanks for
# wasting our disk space and bandwidth...

# If you don't mind HTML mail, comment out the next line.
# 如果你想要直接開啟 HTML 格式的電子郵件,請將下面一行改為 #remove_redundant_html_parts($entity);
remove_redundant_html_parts($entity);
}

# DO NOT delete the next line, or Perl will complain.
1;



最後如果 /etc/mail/mimefang-filter 有變更,記得執行
#/etc/init.d/mimedefang restart