Ảo hóa tài khoản người dùng và tên miền

Trong bài viết sau, Quản Trị Mạng sẽ hướng dẫn, giải thích với các bạn cách cài đặt hệ thống mail server dựa trên Postfix – được xây dựng trên tài khoản user và domain ảo (ví dụ 2 giá trị này được lưu trữ trong cơ sở dữ liệu MySQL). Đồng thời chúng tôi cũng xây dựng lại toàn bộ quá trình cài đặt và thiết lập của Courier (Courier-POP3, Courier-IMAP), qua đó Courier có thể nhận dạng được luồng thông tin dữ liệu tương tự như MySQL.

Kết quả của Postfix server là khả năng hỗ trợ cơ chế xác thực SMTP-AUTH, TLS và quota (quota không được tích hợp cùng với Postfix ở chế độ mặc định), trong đó mật khẩu sẽ được lưu trữ dưới mẫu encrypted trong cơ sở dữ liệu. Bên cạnh đó, bài viết cũng sẽ chỉ ra cách cài đặt Amavisd, SpamAssassin và ClamAV để quét email và phát hiện các hiểm họa đi kèm.

Lưu ý sơ bộ

Hệ thống sử dụng ở đây dựa trên nền tảng Fedora 13 server x86_64, có địa chỉ IP tĩnh192.168.0.100 và hostname là server1.example.com. Thêm vào đó, tắt bỏ tính năng firewall và SELinux.

Cài đặt 1 số phần mềm yêu cầu

Trước tiên, chúng ta cần cập nhật 1 số gói ứng dụng trên hệ thống:

yum update

yum groupinstall 'Development Tools'

yum groupinstall 'Development Libraries'

Cài đặt Apache, MySQL, phpMyAdmin

Chỉ với 1 dòng lệnh duy nhất, có bao gồm các gói cần thiết để xây dựng hệ thống Courier-IMAP sau này:

yum install ntp httpd mysql-server php php-mysql php-mbstring rpm-build gcc mysql-devel openssl-devel cyrus-sasl-devel pkgconfig zlib-devel phpMyAdmin pcre-devel openldap-devel postgresql-devel expect libtool-ltdl-devel openldap-servers libtool gdbm-devel pam-devel gamin-devel

Cài đặt Courier-IMAP, Courier-Authlib, và Maildrop

Thật bất tiện khi không có gói rpm dành cho Courier-IMAP, Courier-Authlib, và Maildrop, do đó chúng ta cần tự xây dựng mã nguồn. Chú ý rằng các gói RPM không nên được dựng bằng tài khoản root, courier-imap sẽ tự động tắt bỏ khỏi quá trình biên dịch nếu phát hiện trình biên dịch đang thực hiện bằng tài khoản root. Do đó, chúng ta cần tạo 1 tài khoản bình thường (trong ví dụ này là falko) và tạo mật khẩu đi kèm:

useradd -m -s /bin/bash falko
passwd falko

Chúng ta sẽ cần đến cú pháp sudo sau này, để tài khoản falco có thể biên dịch và cài đặt các gói rpm. Nhưng trước tiên, chúng ta phải cho phép tài khoản falko để chạy tất cả câu lệnh sử dụng sudo:

visudo

Trong file vừa mở ra, sẽ có dòng root ALL=(ALL) ALL. Hãy thêm 1 dòng tương tự dành cho falko ngay bên dưới:

[...]
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
falko ALL=(ALL) ALL
[...]

Và bây giờ, chúng ta đã sẵn sàng xây dựng các gói rpm. Trước tiên, đăng nhập vào tài khoản falko:

su falko

Tạo các biến môi trường:

mkdir $HOME/rpm
mkdir $HOME/rpm/SOURCES
mkdir $HOME/rpm/SPECS
mkdir $HOME/rpm/BUILD
mkdir $HOME/rpm/BUILDROOT
mkdir $HOME/rpm/SRPMS
mkdir $HOME/rpm/RPMS
mkdir $HOME/rpm/RPMS/i386
mkdir $HOME/rpm/RPMS/x86_64

echo "%_topdir $HOME/rpm" >> $HOME/.rpmmacros

Tạo tiếp thư mục downloads và tải bộ mã nguồn từ đây:

mkdir $HOME/downloads
cd $HOME/downloads

wget https://sourceforge.net/projects/courier/files/authlib/0.63.0/courier-authlib-0.63.0.tar.bz2/download
wget https://sourceforge.net/projects/courier/files/imap/4.8.0/courier-imap-4.8.0.tar.bz2/download
wget https://sourceforge.net/projects/courier/files/maildrop/2.5.0/maildrop-2.5.0.tar.bz2/download

Vẫn ở trong thư mục $HOME/downloads, xây dựng gói courier-authlib:

sudo rpmbuild -ta courier-authlib-0.63.0.tar.bz2

Sau đó, gói rpm sẽ có trong $HOME/rpm/RPMS/x86_64 ($HOME/rpm/RPMS/i386 nếu bạn sử dụng i386):

cd $HOME/rpm/RPMS/x86_64

Sử dụng lệnh:

ls -l

để liệt kê các gói rpm thích hợp:

[falko@server1 x86_64]$ ls -l
total 516
-rw-r--r-- 1 root root 124304 Jun 10 17:48 courier-authlib-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 258896 Jun 10 17:48 courier-authlib-debuginfo-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 35064 Jun 10 17:48 courier-authlib-devel-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 17424 Jun 10 17:48 courier-authlib-ldap-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13956 Jun 10 17:48 courier-authlib-mysql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13120 Jun 10 17:48 courier-authlib-pgsql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 8328 Jun 10 17:48 courier-authlib-pipe-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 34160 Jun 10 17:48 courier-authlib-userdb-0.63.0-1.fc13.x86_64.rpm
[falko@server1 x86_64]$

Chọn 1 gói thích hợp và cài đặt như sau:

sudo rpm -ivh courier-authlib-0.63.0-1.fc13.x86_64.rpm courier-authlib-mysql-0.63.0-1.fc13.x86_64.rpm courier-authlib-devel-0.63.0-1.fc13.x86_64.rpm

Tiếp theo, quay trở lại thư mục downloads:

cd $HOME/downloads

và chạy lệnh rpmbuild lại lần nữa, nhưng không có sudo nếu không quá trình biên dịch sẽ thất bại:

rpmbuild -ta courier-imap-4.8.0.tar.bz2

Sau quá trình này, gói rpm sẽ được tìm thấy trong thư mục HOME/rpm/RPMS/x86_64 ($HOME/rpm/RPMS/i386 nếu bạn đang sử dụng hệ thống i386):

cd $HOME/rpm/RPMS/x86_64

Dùng lệnh:

ls -l

sẽ liệt kê ra các gói rpm phù hợp:

[falko@server1 x86_64]$ ls -l
total 2300
-rw-r--r-- 1 root root 124304 Jun 10 17:48 courier-authlib-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 258896 Jun 10 17:48 courier-authlib-debuginfo-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 35064 Jun 10 17:48 courier-authlib-devel-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 17424 Jun 10 17:48 courier-authlib-ldap-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13956 Jun 10 17:48 courier-authlib-mysql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13120 Jun 10 17:48 courier-authlib-pgsql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 8328 Jun 10 17:48 courier-authlib-pipe-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 34160 Jun 10 17:48 courier-authlib-userdb-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 falko falko 632296 Jun 10 17:58 courier-imap-4.8.0-1.13.x86_64.rpm
-rw-r--r-- 1 falko falko 1188976 Jun 10 17:58 courier-imap-debuginfo-4.8.0-1.13.x86_64.rpm
[falko@server1 x86_64]$

Và cài đặt courier-imap như sau:

sudo rpm -ivh courier-imap-4.8.0-1.13.x86_64.rpm

Quay trở lại thư mục downloads:

cd $HOME/downloads

tiếp tục chạy lệnh rpmbuild, lần này là để xây dựng gói maildrop:

sudo rpmbuild -ta maildrop-2.5.0.tar.bz2

Khi hoàn thành, gói rpm sẽ có trong thư mục $HOME/rpm/RPMS/x86_64 ($HOME/rpm/RPMS/i386 nếu bạn sử dụng hệ thống i386):

cd $HOME/rpm/RPMS/x86_64

Gõ lệnh:

ls -l

để liệt kê các gói phù hợp:

[falko@server1 x86_64]$ ls -l
total 5400
-rw-r--r-- 1 root root 124304 Jun 10 17:48 courier-authlib-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 258896 Jun 10 17:48 courier-authlib-debuginfo-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 35064 Jun 10 17:48 courier-authlib-devel-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 17424 Jun 10 17:48 courier-authlib-ldap-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13956 Jun 10 17:48 courier-authlib-mysql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 13120 Jun 10 17:48 courier-authlib-pgsql-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 8328 Jun 10 17:48 courier-authlib-pipe-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 34160 Jun 10 17:48 courier-authlib-userdb-0.63.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 falko falko 632296 Jun 10 17:58 courier-imap-4.8.0-1.13.x86_64.rpm
-rw-r--r-- 1 falko falko 1188976 Jun 10 17:58 courier-imap-debuginfo-4.8.0-1.13.x86_64.rpm
-rw-r--r-- 1 root root 1759056 Jun 10 18:06 maildrop-2.5.0-1.13.x86_64.rpm
-rw-r--r-- 1 root root 1243400 Jun 10 18:06 maildrop-debuginfo-2.5.0-1.13.x86_64.rpm
-rw-r--r-- 1 root root 99764 Jun 10 18:06 maildrop-devel-2.5.0-1.13.x86_64.rpm
-rw-r--r-- 1 root root 62536 Jun 10 18:06 maildrop-man-2.5.0-1.13.x86_64.rpm
[falko@server1 x86_64]$

Và cài đặt maildrop như sau:

sudo rpm -ivh maildrop-2.5.0-1.13.x86_64.rpm

Sau khi hoàn tất các quá trình trên, đăng nhập vào hệ thống bằng tài khoản root:

exit


Áp dụng bản vá Quote với Postfix

Ở đây, chúng ta sẽ phải tìm cách patch Quota với Postfix theo cách sau: tải mã nguồn, áp dụng bản vá, xây dựng gói cài đặt rpm của Postfix và cài đặt:

cd /usr/src
wget http://ftp-stud.fht-esslingen.de/pub/Mirrors/fedora/linux/releases/13/Fedora/source/SRPMS/postfix-2.7.0-1.fc13.src.rpm
rpm -ivh postfix-2.7.0-1.fc13.src.rpm

Câu lệnh cuối cùng sẽ chỉ ra 1 vài cảnh báo, bạn có thể bỏ qua những cảnh báo này:

warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root

cd /root/rpmbuild/SOURCES

wget http://vda.sourceforge.net/VDA/postfix-vda-2.7.0.patch
cd /root/rpmbuild/SPECS/

Tiếp theo, chỉnh sửa file postfix.spec:

vi postfix.spec

Thêm cú pháp Patch0: postfix-vda-2.7.0.patch vào vị trí # Patches, và %patch0 -p1 -b .vda vào %setup -q:

[...]
# Patches

Patch0: postfix-vda-2.7.0.patch

Patch1: postfix-2.7.0-config.patch
Patch2: postfix-2.6.1-files.patch
Patch3: postfix-alternatives.patch
Patch8: postfix-large-fs.patch
Patch9: pflogsumm-1.1.2-datecalc.patch
[...]
%prep
%setup -q
# Apply obligatory patches
%patch0 -p1 -b .vda
%patch1 -p1 -b .config
%patch2 -p1 -b .files
%patch3 -p1 -b .alternatives
%patch8 -p1 -b .large-fs
[...]

Sau đó, xây dựng gói cài đặt rpm của Postfix với quota và MySQL hỗ trợ:

rpmbuild -ba postfix.spec

Gói rpm cài đặt Postfix được tạo ra ở thư mục /root/rpmbuild/RPMS/x86_64 (/root/rpmbuild/RPMS/i386 nếu bạn sử dụng hệ thống i386):

cd /root/rpmbuild/RPMS/x86_64

Sử dụng lệnh:

ls -l

để liệt kê các gói phù hợp:

[root@server1 x86_64]# ls -l
total 8804
-rw-r--r-- 1 root root 2197708 Jun 10 18:17 postfix-2.7.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 6746304 Jun 10 18:17 postfix-debuginfo-2.7.0-1.fc13.x86_64.rpm
-rw-r--r-- 1 root root 61460 Jun 10 18:17 postfix-perl-scripts-2.7.0-1.fc13.x86_64.rpm
[root@server1 x86_64]#

Chọn gói Postfix phù hợp và cài đặt bằng lệnh sau:

rpm -ivh postfix-2.7.0-1.fc13.x86_64.rpm

Thiết lập mật khẩu cho MySQL và thiết lập phpMyAdmin

Khởi động MySQL:

chkconfig --levels 235 mysqld on
/etc/init.d/mysqld start

Thiết lập mật khẩu cho tài khoản MySQL root:

mysql_secure_installation

[root@server1 ~]# mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!


In order to log into MySQL to secure it, we'll need the current
password for the root user. If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): <-- ENTER
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] <-- ENTER
New password: ← đặt mật khẩu root sql
Re-enter new password: <-- đặt mật khẩu root sql
Password updated successfully!
Reloading privilege tables..
... Success!


By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] <-- ENTER
... Success!

Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] <-- ENTER
... Success!

By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] <-- ENTER
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] <-- ENTER
... Success!

Cleaning up...



All done! If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!


[root@server1 ~]#

Tiếp theo, chúng ta phải thiết lập phpMyAdmin, thay đổi Apache để phpMyAdmin chấp nhận các kết nối không chỉ từ localhost:

vi /etc/httpd/conf.d/phpMyAdmin.conf

# phpMyAdmin - Web based MySQL browser written in php
#
# Allows only localhost by default
#
# But allowing phpMyAdmin to anyone other than localhost should be considered
# dangerous unless properly secured by SSL

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin
#<Directory /usr/share/phpMyAdmin/>
# order deny,allow
# deny from all
# allow from 127.0.0.1
# allow from ::1
#</Directory>

# This directory does not require access over HTTP - taken from the original
# phpMyAdmin upstream tarball
#
<Directory /usr/share/phpMyAdmin/libraries>
Order Deny,Allow
Deny from All
Allow from None
</Directory>

# This configuration prevents mod_security at phpMyAdmin directories from
# filtering SQL etc. This may break your mod_security implementation.
#
#<IfModule mod_security.c>
# <Directory /usr/share/phpMyAdmin>
# SecRuleInheritance Off
# </Directory>
#</IfModule>

Tạo đường dẫn khởi động cho Apache và kích hoạt:

chkconfig --levels 235 httpd on
/etc/init.d/httpd start

Mở trình duyệt và gõ địa chỉ http://server1.example.com/phpMyAdmin/ hoặc http://192.168.0.100/phpMyAdmin/, đăng nhập bằng tài khoản root và mật khẩu MySQL khai báo ở phía trên.


Tạo cơ sở dữ liệu MySQL dành cho Postfix/Courier

Ở đây, chúng ta sẽ tạo cơ sở dữ liệu với tên là mail:

mysqladmin -u root -p create mail

Di chuyển tới MySQL shell:

mysql -u root -p

Và tại đây, chúng ta sẽ tạo tài khoản mail_admin với mật khẩu mail_admin_password (thay thế với mật khẩu tùy chọn của bạn) với những quyền cơ bản như SELECT, INSERT, UPDATE, DELETE trên cơ sở dữ liệu mail. Tài khoản này sẽ được Postfix và Courier sử dụng để kết nối tới cơ sở dữ liệu mail:

GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost' IDENTIFIED BY 'mail_admin_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost.localdomain' IDENTIFIED BY 'mail_admin_password';
FLUSH PRIVILEGES;

Tạo tiếp những bảng mà Postfix và Courier cần:

USE mail;

CREATE TABLE domains (
domain varchar(50) NOT NULL,
PRIMARY KEY (domain) )
TYPE=MyISAM;

CREATE TABLE forwardings (
source varchar(80) NOT NULL,
destination TEXT NOT NULL,
PRIMARY KEY (source) )
TYPE=MyISAM;

CREATE TABLE users (
email varchar(80) NOT NULL,
password varchar(20) NOT NULL,
quota bigint(20) DEFAULT '10485760',
PRIMARY KEY (email)
) TYPE=MyISAM;

CREATE TABLE transport (
domain varchar(128) NOT NULL default '',
transport varchar(128) NOT NULL default '',
UNIQUE KEY domain (domain)
) TYPE=MyISAM;

quit;

Với câu lệnh quit; chúng ta sẽ thoát khỏi MySQL shell và quay trở lại Linux shell.

Bảng dữ liệu domains sẽ lưu trữ mỗi domain ảo mà Postfix sử dụng để nhận email (ví dụ example.com).

Bảng forwardings dành cho các email trỏ tới email khác, ví dụ trỏ từ info@example.com tới sales@example.com

Bảng users lưu trữ tất cả thông tin tài khoản ảo và mật khẩu cùng giá trị quota dành cho mail box (trong ví dụ này là giá trị mặc định 10485760 bytes tương đương với 10MB).

Bảng transport là lựa chọn thêm, dành cho những người dùng nâng cao, cho phép chuyển tiếp mail đối với mỗi người dùng đơn lẻ, hoặc toàn bộ domain cũng như tất cả mail tới server khác.

Điều chỉnh Postfix

Tiếp theo, chúng ta phải chỉ ra cho Postfix tìm tất cả các thông tin trong cơ sở dữ liệu, do đó chúng ta phải tạo 6 file text. Postfix sẽ kết nối tới MySQL bằng địa chỉ IP: 127.0.0.1 bên trong localhost:

vi /etc/postfix/mysql-virtual_domains.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT domain AS virtual FROM domains WHERE domain='%s'
hosts = 127.0.0.1
vi /etc/postfix/mysql-virtual_forwardings.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT destination FROM forwardings WHERE source='%s'
hosts = 127.0.0.1
vi /etc/postfix/mysql-virtual_mailboxes.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s'
hosts = 127.0.0.1
vi /etc/postfix/mysql-virtual_email2email.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT email FROM users WHERE email='%s'
hosts = 127.0.0.1
vi /etc/postfix/mysql-virtual_transports.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT transport FROM transport WHERE domain='%s'
hosts = 127.0.0.1
vi /etc/postfix/mysql-virtual_mailbox_limit_maps.cf

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT quota FROM users WHERE email='%s'
hosts = 127.0.0.1
chmod o= /etc/postfix/mysql-virtual_*.cf
chgrp postfix /etc/postfix/mysql-virtual_*.cf

Tạo tài khoản người dùng và nhóm có tên là vmail cùng thư mục gốc /home/vmail. Đây sẽ là nơi lưu trữ tất cả mail box.

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /home/vmail -m

Tiếp theo, chúng ta tiến hành chỉnh sửa 1 vài thông số của Postfix, hãy chắc chắn rằng bạn đã thay thế đúng giá trị server1.example.com với FQDN tương ứng, nếu không Postfix sẽ không hoạt động bình thường:

postconf -e 'myhostname = server1.example.com'
postconf -e 'mydestination = server1.example.com, localhost, localhost.localdomain'
postconf -e 'mynetworks = 127.0.0.0/8'
postconf -e 'virtual_alias_domains ='
postconf -e ' virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf'
postconf -e 'virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf'
postconf -e 'virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf'
postconf -e 'virtual_mailbox_base = /home/vmail'
postconf -e 'virtual_uid_maps = static:5000'
postconf -e 'virtual_gid_maps = static:5000'
postconf -e 'smtpd_sasl_auth_enable = yes'
postconf -e 'broken_sasl_auth_clients = yes'
postconf -e 'smtpd_sasl_authenticated_header = yes'
postconf -e 'smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination'
postconf -e 'smtpd_use_tls = yes'
postconf -e 'smtpd_tls_cert_file = /etc/postfix/smtpd.cert'
postconf -e 'smtpd_tls_key_file = /etc/postfix/smtpd.key'
postconf -e 'transport_maps = proxy:mysql:/etc/postfix/mysql-virtual_transports.cf'
postconf -e 'virtual_create_maildirsize = yes'
postconf -e 'virtual_maildir_extended = yes'
postconf -e 'virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_limit_maps.cf'
postconf -e 'virtual_mailbox_limit_override = yes'
postconf -e 'virtual_maildir_limit_message = "The user you are trying to reach is over quota."'
postconf -e 'virtual_overquota_bounce = yes'
postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps'
postconf -e 'inet_interfaces = all'

Sau đó tạo cơ chế xác thực SSL cần thiết đối với TLS:

cd /etc/postfix
openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 365 -x509

Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:

Sau đó thay đổi giới hạn quyền của smtpd.key:

chmod o= /etc/postfix/smtpd.key


Điều chỉnh Saslauthd

Thay đổi /usr/lib64/sasl2/smtpd.conf (/usr/lib/sasl2/smtpd.conf nếu bạn sử dụng hệ thống i386), sẽ trông giống thế này:

vi /usr/lib64/sasl2/smtpd.conf

pwcheck_method: authdaemond
log_level: 3
mech_list: PLAIN LOGIN
authdaemond_path:/var/spool/authdaemon/socket

Tắt bỏ chức năng Sendmail và khởi động Postfix, saslauthd, và courier-authlib:

chmod 755 /var/spool/authdaemon
chkconfig --levels 235 courier-authlib on
/etc/init.d/courier-authlib start

chkconfig --levels 235 sendmail off
chkconfig --levels 235 postfix on
chkconfig --levels 235 saslauthd on
/etc/init.d/sendmail stop
/etc/init.d/postfix start
/etc/init.d/saslauthd start

Điều chỉnh Courier

Tiếp theo, chúng ta cần chỉ định Courier xác thực thông tin nhận dạng từ cơ sở dữ liệu MySQL. Trước tiên, chỉnh sửa file /etc/authlib/authdaemonrc và thay thế giá trị authmodulelist:

vi /etc/authlib/authdaemonrc

[...]

authmodulelist="authmysql"
#authmodulelist="authuserdb authpam authpgsql authldap authmysql authcustom authpipe"
[...]

Tiếp tục chỉnh sửa file /etc/authlib/authmysqlrc:

cp /etc/authlib/authmysqlrc /etc/authlib/authmysqlrc_orig
cat /dev/null > /etc/authlib/authmysqlrc
vi /etc/authlib/authmysqlrc

MYSQL_SERVER localhost

MYSQL_USERNAME mail_admin
MYSQL_PASSWORD mail_admin_password
MYSQL_PORT 0
MYSQL_DATABASE mail
MYSQL_USER_TABLE users
MYSQL_CRYPT_PWFIELD password
#MYSQL_CLEAR_PWFIELD password
MYSQL_UID_FIELD 5000
MYSQL_GID_FIELD 5000
MYSQL_LOGIN_FIELD email
MYSQL_HOME_FIELD "/home/vmail"
MYSQL_MAILDIR_FIELD CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/')
#MYSQL_NAME_FIELD
MYSQL_QUOTA_FIELD quota

Sau đó khởi động lại Courier:

chkconfig --levels 235 courier-imap on
/etc/init.d/courier-authlib restart
/etc/init.d/courier-imap restart

Khi courier-imap khởi động lần đầu tiên, ứng dụng sẽ tự động tạo file xác thực /usr/lib/courier-imap/share/imapd.pemusr/lib/courier-imap/share/pop3d.pem từ file /usr/lib/courier-imap/etc/imapd.cnf/usr/lib/courier-imap/etc/pop3d.cnf. Vì file .cnf chứa dòng tham số CN=localhost, nhưng server của chúng ta lại có tên dạng server1.example.com, và quá trình xác thực sẽ xảy ra vấn đề khi sử dụng kết nối TLS. Để giải quyết việc này, ta xóa bỏ cả 2 file trên:

cd /usr/lib/courier-imap/share
rm -f imapd.pem
rm -f pop3d.pem

và thay thế dòng CN=localhost trong /usr/lib/courier-imap/etc/imapd.cnf/usr/lib/courier-imap/etc/pop3d.cnf với CN=server1.example.com:

vi /usr/lib/courier-imap/etc/imapd.cnf

[...]

CN=server1.example.com
[...]
vi /usr/lib/courier-imap/etc/pop3d.cnf

[...]

CN=server1.example.com
[...]

Sau đó tạo lại cả 2 file xác thực:

./mkimapdcert
./mkpop3dcert

khởi động lại restart courier-authlib và courier-imap:

/etc/init.d/courier-authlib restart
/etc/init.d/courier-imap restart

Chạy lệnh:

telnet localhost pop3

để kiểm tra xem POP3 server có hoạt động bình thường hay không. Kết quả trả về sẽ có dạng như +OK Hello there (gõ quit để quay trở lại Linux shell)

[root@server1 share]# telnet localhost pop3
Trying ::1...
Connected to localhost.
Escape character is '^]'.
+OK Hello there.
quit
+OK Better luck next time.
Connection closed by foreign host.
[root@server1 share]#

Chỉnh sửa /etc/aliases

Bây giờ, chúng ta sẽ mở file /etc/aliases. Hãy chắc chắn rằng biến postmaster trỏ tới tài khoản root như thế này:

vi /etc/aliases

[...]

postmaster: root
root: postmaster@yourdomain.tld
[...]

hoặc như thế này (nếu là tài khoản administrator):

[...]

postmaster: root
root: administrator
[...]

Mỗi khi chỉnh sửa /etc/aliases, hãy chạy lệnh sau:

newaliases

và sau đó khởi động lại Postfix:

/etc/init.d/postfix restart


Cài đặt Amavisd-new, SpamAssassin và ClamAV

Để cài đặt những ứng dụng trên, sử dụng lệnh sau:

yum install amavisd-new spamassassin clamav clamav-data clamav-server clamav-update unzip bzip2

Tiếp theo, chỉnh sửa file /etc/amavisd/amavisd.conf:

vi /etc/amavisd/amavisd.conf

Trong file này, chúng ta sẽ chỉnh sửa 5 tham số:

Thứ nhất, đổi:

$mydomain = 'example.com'; # a convenient default for other settings

thành:

$mydomain = 'localhost';
#$mydomain = 'example.com'; # a convenient default for other settings

Thứ 2, đổi:

$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.2; # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.9; # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent

thành:

$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 4.0; # add 'spam detected' headers at that level
$sa_kill_level_deflt = $sa_tag2_level_deflt; # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent

#$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level

#$sa_tag2_level_deflt = 6.2; # add 'spam detected' headers at that level
#$sa_kill_level_deflt = 6.9; # triggers spam evasive actions (e.g. blocks mail)
#$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent

Lưu ý: điều chỉnh tham số spam score theo ý thích

Thứ 3, đổi:

# @lookup_sql_dsn =
# ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'user1', 'passwd1'],
# ['DBI:mysql:database=mail;host=host2', 'username2', 'password2'],
# ["DBI:SQLite:dbname=$MYHOME/sql/mail_prefs.sqlite", '', ''] );
# @storage_sql_dsn = @lookup_sql_dsn; # none, same, or separate database

thành:

# @lookup_sql_dsn =
# ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'user1', 'passwd1'],
# ['DBI:mysql:database=mail;host=host2', 'username2', 'password2'],
# ["DBI:SQLite:dbname=$MYHOME/sql/mail_prefs.sqlite", '', ''] );
# @storage_sql_dsn = @lookup_sql_dsn; # none, same, or separate database

@lookup_sql_dsn =

( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'mail_admin', 'mail_admin_password'] );

$sql_select_policy = 'SELECT "Y" as local FROM domains WHERE CONCAT("@",domain) IN (%k)';


$sql_select_white_black_list = undef; # undef disables SQL white/blacklisting


$recipient_delimiter = '+'; # (default is '+')


$replace_existing_extension = 1; # (default is false)


$localpart_is_case_sensitive = 0; # (default is false)

Tiếp theo, đổi:

# $recipient_delimiter = '+'; # undef disables address extensions altogether
# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+

thành:

$recipient_delimiter = undef; # undef disables address extensions altogether
# $recipient_delimiter = '+'; # undef disables address extensions altogether
# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+

Cuối cùng, thay đổi:

$final_virus_destiny = D_DISCARD;
$final_banned_destiny = D_BOUNCE;
$final_spam_destiny = D_DISCARD;
$final_bad_header_destiny = D_BOUNCE;

thành:

$final_virus_destiny = D_REJECT;
$final_banned_destiny = D_REJECT;
$final_spam_destiny = D_PASS;
$final_bad_header_destiny = D_PASS;

#$final_virus_destiny = D_DISCARD;

#$final_banned_destiny = D_BOUNCE;
#$final_spam_destiny = D_DISCARD;
#$final_bad_header_destiny = D_BOUNCE;

Sau khi áp dụng việc thay đổi, file /etc/amavisd/amavisd.conf sẽ giống như thế này:

use strict;

# a minimalistic configuration file for amavisd-new with all necessary settings
#
# see amavisd.conf-default for a list of all variables with their defaults;
# see amavisd.conf-sample for a traditional-style commented file;
# for more details see documentation in INSTALL, README_FILES/*
# and at http://www.ijs.si/software/amavisd/amavisd-new-docs.html


# COMMONLY ADJUSTED SETTINGS:

# @bypass_virus_checks_maps = (1); # controls running of anti-virus code 
# @bypass_spam_checks_maps = (1); # controls running of anti-spam code
# $bypass_decode_parts = 1; # controls running of decoders&dearchivers

$max_servers = 2; # num of pre-forked children (2..30 is common), -m
$daemon_user = 'amavis'; # (no default; customary: vscan or amavis), -u
$daemon_group = 'amavis'; # (no default; customary: vscan or amavis), -g

$mydomain = 'localhost';
#$mydomain = 'example.com'; # a convenient default for other settings

$MYHOME = '/var/spool/amavisd'; # a convenient default for other settings, -H
$TEMPBASE = "$MYHOME/tmp"; # working directory, needs to exist, -T
$ENV{TMPDIR} = $TEMPBASE; # environment variable TMPDIR, used by SA, etc.
$QUARANTINEDIR = undef; # -Q
# $quarantine_subdir_levels = 1; # add level of subdirs to disperse quarantine
# $release_format = 'resend'; # 'attach', 'plain', 'resend'
# $report_format = 'arf'; # 'attach', 'plain', 'resend', 'arf'

# $daemon_chroot_dir = $MYHOME; # chroot directory or undef, -R

$db_home = "$MYHOME/db"; # dir for bdb nanny/cache/snmp databases, -D 
# $helpers_home = "$MYHOME/var"; # working directory for SpamAssassin, -S
$lock_file = "/var/run/amavisd/amavisd.lock"; # -L
$pid_file = "/var/run/amavisd/amavisd.pid"; # -P
#NOTE: create directories $MYHOME/tmp, $MYHOME/var, $MYHOME/db manually

$log_level = 0; # verbosity 0..5, -d
$log_recip_templ = undef; # disable by-recipient level-0 log entries
$DO_SYSLOG = 1; # log via syslogd (preferred)
$syslog_facility = 'mail'; # Syslog facility as a string
# e.g.: mail, daemon, user, local0, ... local7
$syslog_priority = 'debug'; # Syslog base (minimal) priority as a string,
# choose from: emerg, alert, crit, err, warning, notice, info, debug

$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny)
$enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1
$nanny_details_level = 2; # nanny verbosity: 1: traditional, 2: detailed
$enable_dkim_verification = 1; # enable DKIM signatures verification
$enable_dkim_signing = 1; # load DKIM signing code, keys defined by dkim_key

@local_domains_maps = ( [".$mydomain"] ); # list of all local domains

@mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10 
10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 );

$unix_socketname = "$MYHOME/amavisd.sock"; # amavisd-release or amavis-milter 
# option(s) -p overrides $inet_socket_port and $unix_socketname

$inet_socket_port = 10024; # listen on this local TCP port(s) 
# $inet_socket_port = [10024,10026]; # listen on multiple TCP ports

$policy_bank{'MYNETS'} = { # mail originating from @mynetworks 
originating => 1, # is true in MYNETS by default, but let's make it explicit
os_fingerprint_method => undef, # don't query p0f for internal clients
};

# it is up to MTA to re-route mail from authenticated roaming users or
# from internal hosts to a dedicated TCP port (such as 10026) for filtering
$interface_policy{'10026'} = 'ORIGINATING';

$policy_bank{'ORIGINATING'} = { # mail supposedly originating from our users 
originating => 1, # declare that mail was submitted by our smtp client
allow_disclaimers => 1, # enables disclaimer insertion if available
# notify administrator of locally originating malware
virus_admin_maps => ["virusalert\@$mydomain"],
spam_admin_maps => ["virusalert\@$mydomain"],
warnbadhsender => 1,
# forward to a smtpd service providing DKIM signing service
forward_method => 'smtp:[127.0.0.1]:10027',
# force MTA conversion to 7-bit (e.g. before DKIM signing)
smtpd_discard_ehlo_keywords => ['8BITMIME'],
bypass_banned_checks_maps => [1], # allow sending any file names and types
terminate_dsn_on_notify_success => 0, # don't remove NOTIFY=SUCCESS option
};

$interface_policy{'SOCK'} = 'AM.PDP-SOCK'; # only applies with $unix_socketname

# Use with amavis-release over a socket or with Petr Rehor's amavis-milter.c 
# (with amavis-milter.c from this package or old amavis.c client use 'AM.CL'):
$policy_bank{'AM.PDP-SOCK'} = {
protocol => 'AM.PDP',
auth_required_release => 0, # do not require secret_id for amavisd-release
};

$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 4.0; # add 'spam detected' headers at that level
$sa_kill_level_deflt = $sa_tag2_level_deflt; # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent
#$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
#$sa_tag2_level_deflt = 6.2; # add 'spam detected' headers at that level
#$sa_kill_level_deflt = 6.9; # triggers spam evasive actions (e.g. blocks mail)
#$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent
$sa_crediblefrom_dsn_cutoff_level = 18; # likewise, but for a likely valid From
# $sa_quarantine_cutoff_level = 25; # spam level beyond which quarantine is off
$penpals_bonus_score = 8; # (no effect without a @storage_sql_dsn database)
$penpals_threshold_high = $sa_kill_level_deflt; # don't waste time on hi spam
$bounce_killer_score = 100; # spam score points to add for joe-jobbed bounces

$sa_mail_body_size_limit = 400*1024; # don't waste time on SA if mail is larger
$sa_local_tests_only = 0; # only tests which do not require internet access?

# @lookup_sql_dsn =
# ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'user1', 'passwd1'],
# ['DBI:mysql:database=mail;host=host2', 'username2', 'password2'],
# ["DBI:SQLite:dbname=$MYHOME/sql/mail_prefs.sqlite", '', ''] );
# @storage_sql_dsn = @lookup_sql_dsn; # none, same, or separate database

@lookup_sql_dsn = 
( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'mail_admin', 'mail_admin_password'] );

$sql_select_policy = 'SELECT "Y" as local FROM domains WHERE CONCAT("@",domain) IN (%k)'; 

$sql_select_white_black_list = undef; # undef disables SQL white/blacklisting 

$recipient_delimiter = '+'; # (default is '+') 

$replace_existing_extension = 1; # (default is false) 

$localpart_is_case_sensitive = 0; # (default is false) 

# $timestamp_fmt_mysql = 1; # if using MySQL *and* msgs.time_iso is TIMESTAMP;
# defaults to 0, which is good for non-MySQL or if msgs.time_iso is CHAR(16)

$virus_admin = undef; # notifications recip. 

$mailfrom_notify_admin = undef; # notifications sender
$mailfrom_notify_recip = undef; # notifications sender
$mailfrom_notify_spamadmin = undef; # notifications sender
$mailfrom_to_quarantine = ''; # null return path; uses original sender if undef

@addr_extension_virus_maps = ('virus'); 
@addr_extension_banned_maps = ('banned');
@addr_extension_spam_maps = ('spam');
@addr_extension_bad_header_maps = ('badh');
$recipient_delimiter = undef; # undef disables address extensions altogether
# $recipient_delimiter = '+'; # undef disables address extensions altogether
# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+

$path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin';
# $dspam = 'dspam';

$MAXLEVELS = 14; 
$MAXFILES = 1500;
$MIN_EXPANSION_QUOTA = 100*1024; # bytes (default undef, not enforced)
$MAX_EXPANSION_QUOTA = 300*1024*1024; # bytes (default undef, not enforced)

$sa_spam_subject_tag = '***SPAM*** '; 
$defang_virus = 1; # MIME-wrap passed infected mail
$defang_banned = 1; # MIME-wrap passed mail containing banned name
# for defanging bad headers only turn on certain minor contents categories:
$defang_by_ccat{+CC_BADH.",3"} = 1; # NUL or CR character in header
$defang_by_ccat{+CC_BADH.",5"} = 1; # header line longer than 998 characters
$defang_by_ccat{+CC_BADH.",6"} = 1; # header field syntax error


# OTHER MORE COMMON SETTINGS (defaults may suffice):

# $myhostname = 'host.example.com'; # must be a fully-qualified domain name! 

# $notify_method = 'smtp:[127.0.0.1]:10025'; 
# $forward_method = 'smtp:[127.0.0.1]:10025'; # set to undef with milter!

$final_virus_destiny = D_REJECT; 
$final_banned_destiny = D_REJECT;
$final_spam_destiny = D_PASS;
$final_bad_header_destiny = D_PASS;
#$final_virus_destiny = D_DISCARD;
#$final_banned_destiny = D_BOUNCE;
#$final_spam_destiny = D_DISCARD;
#$final_bad_header_destiny = D_BOUNCE;
# $bad_header_quarantine_method = undef;

# $os_fingerprint_method = 'p0f:*:2345'; # to query p0f-analyzer.pl

## hierarchy by which a final setting is chosen: 
## policy bank (based on port or IP address) -> *_by_ccat
## *_by_ccat (based on mail contents) -> *_maps
## *_maps (based on recipient address) -> final configuration value


# SOME OTHER VARIABLES WORTH CONSIDERING (see amavisd.conf-default for all)

# $warnbadhsender, 
# $warnvirusrecip, $warnbannedrecip, $warnbadhrecip, (or @warn*recip_maps)
#
# @bypass_virus_checks_maps, @bypass_spam_checks_maps,
# @bypass_banned_checks_maps, @bypass_header_checks_maps,
#
# @virus_lovers_maps, @spam_lovers_maps,
# @banned_files_lovers_maps, @bad_header_lovers_maps,
#
# @blacklist_sender_maps, @score_sender_maps,
#
# $clean_quarantine_method, $virus_quarantine_to, $banned_quarantine_to,
# $bad_header_quarantine_to, $spam_quarantine_to,
#
# $defang_bad_header, $defang_undecipherable, $defang_spam


# REMAINING IMPORTANT VARIABLES ARE LISTED HERE BECAUSE OF LONGER ASSIGNMENTS

@keep_decoded_original_maps = (new_RE( 
qr'^MAIL$', # retain full original message for virus checking
qr'^MAIL-UNDECIPHERABLE$', # recheck full mail if it contains undecipherables
qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i,
# qr'^Zip archive data', # don't trust Archive::Zip
));


# for $banned_namepath_re (a new-style of banned table) see amavisd.conf-sample

$banned_filename_re = new_RE( 

### BLOCKED ANYWHERE 
# qr'^UNDECIPHERABLE$', # is or contains any undecipherable components
qr'^\.(exe-ms|dll)$', # banned file(1) types, rudimentary
# qr'^\.(exe|lha|tnef|cab|dll)$', # banned file(1) types

### BLOCK THE FOLLOWING, EXCEPT WITHIN UNIX ARCHIVES: 
# [ qr'^\.(gz|bz2)$' => 0 ], # allow any in gzip or bzip2
[ qr'^\.(rpm|cpio|tar)$' => 0 ], # allow any in Unix-type archives

qr'.\.(pif|scr)$'i, # banned extensions - rudimentary 
# qr'^\.zip$', # block zip type

### BLOCK THE FOLLOWING, EXCEPT WITHIN ARCHIVES: 
# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ], # allow any within these archives

qr'^application/x-msdownload$'i, # block these MIME types
qr'^application/x-msdos-program$'i,
qr'^application/hta$'i,

# qr'^message/partial$'i, # rfc2046 MIME type 
# qr'^message/external-body$'i, # rfc2046 MIME type

# qr'^(application/x-msmetafile|image/x-wmf)$'i, # Windows Metafile MIME type 
# qr'^\.wmf$', # Windows Metafile file(1) type

# block certain double extensions in filenames 
qr'\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)[.\s]*$'i,

# qr'\{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?'i, # Class ID CLSID, strict 
# qr'\{[0-9a-z]{4,}(-[0-9a-z]{4,}){0,7}\}?'i, # Class ID extension CLSID, loose

qr'.\.(exe|vbs|pif|scr|cpl)$'i, # banned extension - basic
# qr'.\.(exe|vbs|pif|scr|cpl|bat|cmd|com)$'i, # banned extension - basic+cmd
# qr'.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
# inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
# ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
# wmf|wsc|wsf|wsh)$'ix, # banned ext - long
# qr'.\.(ani|cur|ico)$'i, # banned cursors and icons filename
# qr'^\.ani$', # banned animated cursor file(1) type

# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i, # banned extension - WinZip vulnerab. 
);
# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631
# and http://www.cknow.com/vtutor/vtextensions.htm


# ENVELOPE SENDER SOFT-WHITELISTING / SOFT-BLACKLISTING

@score_sender_maps = ({ # a by-recipient hash lookup table, 
# results from all matching recipient tables are summed

# ## per-recipient personal tables (NOTE: positive: black, negative: white) 
# 'user1@example.com' => [{'bla-mobile.press@example.com' => 10.0}],
# 'user3@example.com' => [{'.ebay.com' => -3.0}],
# 'user4@example.com' => [{'cleargreen@cleargreen.com' => -7.0,
# '.cleargreen.com' => -5.0}],

## site-wide opinions about senders (the '.' matches any recipient) 
'.' => [ # the _first_ matching sender determines the score boost

new_RE( # regexp-type lookup table, just happens to be all soft-blacklist
[qr'^(bulkmail|offers|cheapbenefits|earnmoney|foryou)@'i => 5.0],
[qr'^(greatcasino|investments|lose_weight_today|market\.alert)@'i=> 5.0],
[qr'^(money2you|MyGreenCard|new\.tld\.registry|opt-out|opt-in)@'i=> 5.0],
[qr'^(optin|saveonlsmoking2002k|specialoffer|specialoffers)@'i => 5.0],
[qr'^(stockalert|stopsnoring|wantsome|workathome|yesitsfree)@'i => 5.0],
[qr'^(your_friend|greatoffers)@'i => 5.0],
[qr'^(inkjetplanet|marketopt|MakeMoney)\d*@'i => 5.0],
),

# read_hash("/var/amavis/sender_scores_sitewide"), 

{ # a hash-type lookup table (associative array) 
'nobody@cert.org' => -3.0,
'cert-advisory@us-cert.gov' => -3.0,
'owner-alert@iss.net' => -3.0,
'slashdot@slashdot.org' => -3.0,
'securityfocus.com' => -3.0,
'ntbugtraq@listserv.ntbugtraq.com' => -3.0,
'security-alerts@linuxsecurity.com' => -3.0,
'mailman-announce-admin@python.org' => -3.0,
'amavis-user-admin@lists.sourceforge.net'=> -3.0,
'amavis-user-bounces@lists.sourceforge.net' => -3.0,
'spamassassin.apache.org' => -3.0,
'notification-return@lists.sophos.com' => -3.0,
'owner-postfix-users@postfix.org' => -3.0,
'owner-postfix-announce@postfix.org' => -3.0,
'owner-sendmail-announce@lists.sendmail.org' => -3.0,
'sendmail-announce-request@lists.sendmail.org' => -3.0,
'donotreply@sendmail.org' => -3.0,
'ca+envelope@sendmail.org' => -3.0,
'noreply@freshmeat.net' => -3.0,
'owner-technews@postel.acm.org' => -3.0,
'ietf-123-owner@loki.ietf.org' => -3.0,
'cvs-commits-list-admin@gnome.org' => -3.0,
'rt-users-admin@lists.fsck.com' => -3.0,
'clp-request@comp.nus.edu.sg' => -3.0,
'surveys-errors@lists.nua.ie' => -3.0,
'emailnews@genomeweb.com' => -5.0,
'yahoo-dev-null@yahoo-inc.com' => -3.0,
'returns.groups.yahoo.com' => -3.0,
'clusternews@linuxnetworx.com' => -3.0,
lc('lvs-users-admin@LinuxVirtualServer.org') => -3.0,
lc('owner-textbreakingnews@CNNIMAIL12.CNN.COM') => -5.0,

# soft-blacklisting (positive score)
'sender@example.net' => 3.0,
'.example.net' => 1.0,

}, 
], # end of site-wide tables
});


@decoders = (
['mail', \&do_mime_decode],
['asc', \&do_ascii],
['uue', \&do_ascii],
['hqx', \&do_ascii],
['ync', \&do_ascii],
['F', \&do_uncompress, ['unfreeze','freeze -d','melt','fcat'] ],
['Z', \&do_uncompress, ['uncompress','gzip -d','zcat'] ],
['gz', \&do_uncompress, 'gzip -d'],
['gz', \&do_gunzip],
['bz2', \&do_uncompress, 'bzip2 -d'],
['lzo', \&do_uncompress, 'lzop -d'],
['rpm', \&do_uncompress, ['rpm2cpio.pl','rpm2cpio'] ],
['cpio', \&do_pax_cpio, ['pax','gcpio','cpio'] ],
['tar', \&do_pax_cpio, ['pax','gcpio','cpio'] ],
['deb', \&do_ar, 'ar'],
# ['a', \&do_ar, 'ar'], # unpacking .a seems an overkill
['zip', \&do_unzip],
['7z', \&do_7zip, ['7zr','7za','7z'] ],
['rar', \&do_unrar, ['rar','unrar'] ],
['arj', \&do_unarj, ['arj','unarj'] ],
['arc', \&do_arc, ['nomarch','arc'] ],
['zoo', \&do_zoo, ['zoo','unzoo'] ],
['lha', \&do_lha, 'lha'],
# ['doc', \&do_ole, 'ripole'],
['cab', \&do_cabextract, 'cabextract'],
['tnef', \&do_tnef_ext, 'tnef'],
['tnef', \&do_tnef],
# ['sit', \&do_unstuff, 'unstuff'], # broken/unsafe decoder
['exe', \&do_executable, ['rar','unrar'], 'lha', ['arj','unarj'] ],
);


@av_scanners = (

# ### http://www.clanfield.info/sophie/ (http://www.vanja.com/tools/sophie/) 
# ['Sophie',
# \&ask_daemon, ["{}/\n", '/var/run/sophie'],
# qr/(?x)^ 0+ ( : | [\000\r\n]* $)/m, qr/(?x)^ 1 ( : | [\000\r\n]* $)/m,
# qr/(?x)^ [-+]? \d+ : (.*?) [\000\r\n]* $/m ],

# ### http://www.csupomona.edu/~henson/www/projects/SAVI-Perl/ 
# ['Sophos SAVI', \&sophos_savi ],

# ### http://www.clamav.net/ 
['ClamAV-clamd',
\&ask_daemon, ["CONTSCAN {}\n", "/var/spool/amavisd/clamd.sock"],
qr/\bOK$/m, qr/\bFOUND$/m,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd, or run it under its own
# # uid such as clamav, add user clamav to the amavis group, and then add
# # AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# # this entry; when running chrooted one may prefer socket "$MYHOME/clamd".

# ### http://www.clamav.net/ and CPAN (memory-hungry! clamd is preferred)
# # note that Mail::ClamAV requires perl to be build with threading!
# ['Mail::ClamAV', \&ask_clamav, "*", [0], [1], qr/^INFECTED: (.+)/m ],

# ### http://www.openantivirus.org/ 
# ['OpenAntiVirus ScannerDaemon (OAV)',
# \&ask_daemon, ["SCAN {}\n", '127.0.0.1:8127'],
# qr/^OK/m, qr/^FOUND: /m, qr/^FOUND: (.+)/m ],

# ### http://www.vanja.com/tools/trophie/ 
# ['Trophie',
# \&ask_daemon, ["{}/\n", '/var/run/trophie'],
# qr/(?x)^ 0+ ( : | [\000\r\n]* $)/m, qr/(?x)^ 1 ( : | [\000\r\n]* $)/m,
# qr/(?x)^ [-+]? \d+ : (.*?) [\000\r\n]* $/m ],

# ### http://www.grisoft.com/ 
# ['AVG Anti-Virus',
# \&ask_daemon, ["SCAN {}\n", '127.0.0.1:55555'],
# qr/^200/m, qr/^403/m, qr/^403 .*?: ([^\r\n]+)/m ],

# ### http://www.f-prot.com/
# ['F-Prot fpscand', # F-PROT Antivirus for BSD/Linux/Solaris, version 6
# \&ask_daemon,
# ["SCAN FILE {}/*\n", '127.0.0.1:10200'],
# qr/^(0|8|64) /m,
# qr/^([1235679]|1[01345]) |<[^>:]*(?i)(infected|suspicious|unwanted)/m,
# qr/(?i)<[^>:]*(?:infected|suspicious|unwanted)[^>:]*: ([^>]*)>/m ],

# ### http://www.f-prot.com/ 
# ['F-Prot f-protd', # old version
# \&ask_daemon,
# ["GET {}/*?-dumb%20-archive%20-packed HTTP/1.0\r\n\r\n",
# ['127.0.0.1:10200', '127.0.0.1:10201', '127.0.0.1:10202',
# '127.0.0.1:10203', '127.0.0.1:10204'] ],
# qr/(?i)<summary[^>]*>clean<\/summary>/m,
# qr/(?i)<summary[^>]*>infected<\/summary>/m,
# qr/(?i)<name>(.+)<\/name>/m ],

# ### http://www.sald.com/, http://www.dials.ru/english/, http://www.drweb.ru/
# ['DrWebD', \&ask_daemon, # DrWebD 4.31 or later
# [pack('N',1). # DRWEBD_SCAN_CMD
# pack('N',0x00280001). # DONT_CHANGEMAIL, IS_MAIL, RETURN_VIRUSES
# pack('N', # path length
# length("$TEMPBASE/amavis-yyyymmddTHHMMSS-xxxxx/parts/pxxx")).
# '{}/*'. # path
# pack('N',0). # content size
# pack('N',0),
# '/var/drweb/run/drwebd.sock',
# # '/var/amavis/var/run/drwebd.sock', # suitable for chroot
# # '/usr/local/drweb/run/drwebd.sock', # FreeBSD drweb ports default
# # '127.0.0.1:3000', # or over an inet socket
# ],
# qr/\A\x00[\x10\x11][\x00\x10]\x00/sm, # IS_CLEAN,EVAL_KEY; SKIPPED
# qr/\A\x00[\x00\x01][\x00\x10][\x20\x40\x80]/sm,# KNOWN_V,UNKNOWN_V,V._MODIF
# qr/\A.{12}(?:infected with )?([^\x00]+)\x00/sm,
# ],
# # NOTE: If using amavis-milter, change length to:
# # length("$TEMPBASE/amavis-milter-xxxxxxxxxxxxxx/parts/pxxx").

### http://www.kaspersky.com/ (kav4mailservers)
['KasperskyLab AVP - aveclient',
['/usr/local/kav/bin/aveclient','/usr/local/share/kav/bin/aveclient',
'/opt/kav/5.5/kav4mailservers/bin/aveclient','aveclient'],
'-p /var/run/aveserver -s {}/*',
[0,3,6,8], qr/\b(INFECTED|SUSPICION|SUSPICIOUS)\b/m,
qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.+)/m,
],
# NOTE: one may prefer [0],[2,3,4,5], depending on how suspicious,
# currupted or protected archives are to be handled

### http://www.kaspersky.com/ 
['KasperskyLab AntiViral Toolkit Pro (AVP)', ['avp'],
'-* -P -B -Y -O- {}', [0,3,6,8], [2,4], # any use for -A -K ?
qr/infected: (.+)/m,
sub {chdir('/opt/AVP') or die "Can't chdir to AVP: $!"},
sub {chdir($TEMPBASE) or die "Can't chdir back to $TEMPBASE $!"},
],

### The kavdaemon and AVPDaemonClient have been removed from Kasperky
### products and replaced by aveserver and aveclient
['KasperskyLab AVPDaemonClient',
[ '/opt/AVP/kavdaemon', 'kavdaemon',
'/opt/AVP/AvpDaemonClient', 'AvpDaemonClient',
'/opt/AVP/AvpTeamDream', 'AvpTeamDream',
'/opt/AVP/avpdc', 'avpdc' ],
"-f=$TEMPBASE {}", [0,8], [3,4,5,6], qr/infected: ([^\r\n]+)/m ],
# change the startup-script in /etc/init.d/kavd to:
# DPARMS="-* -Y -dl -f=/var/amavis /var/amavis"
# (or perhaps: DPARMS="-I0 -Y -* /var/amavis" )
# adjusting /var/amavis above to match your $TEMPBASE.
# The '-f=/var/amavis' is needed if not running it as root, so it
# can find, read, and write its pid file, etc., see 'man kavdaemon'.
# defUnix.prf: there must be an entry "*/var/amavis" (or whatever
# directory $TEMPBASE specifies) in the 'Names=' section.
# cd /opt/AVP/DaemonClients; configure; cd Sample; make
# cp AvpDaemonClient /opt/AVP/
# su - vscan -c "${PREFIX}/kavdaemon ${DPARMS}"

### http://www.centralcommand.com/
['CentralCommand Vexira (new) vascan',
['vascan','/usr/lib/Vexira/vascan'],
"-a s --timeout=60 --temp=$TEMPBASE -y $QUARANTINEDIR ".
"--log=/var/log/vascan.log {}",
[0,3], [1,2,5],
qr/(?x)^\s* (?:virus|iworm|macro|mutant|sequence|trojan)\ found:\ ( [^\]\s']+ )\ \.\.\.\ /m ],
# Adjust the path of the binary and the virus database as needed.
# 'vascan' does not allow to have the temp directory to be the same as
# the quarantine directory, and the quarantine option can not be disabled.
# If $QUARANTINEDIR is not used, then another directory must be specified
# to appease 'vascan'. Move status 3 to the second list if password
# protected files are to be considered infected.

### http://www.avira.com/
### Avira AntiVir (formerly H+BEDV) or (old) CentralCommand Vexira Antivirus
['Avira AntiVir', ['antivir','vexira'],
'--allfiles -noboot -nombr -rs -s -z {}', [0], qr/ALERT:|VIRUS:/m,
qr/(?x)^\s* (?: ALERT: \s* (?: \[ | [^']* ' ) |
(?i) VIRUS:\ .*?\ virus\ '?) ( [^\]\s']+ )/m ],
# NOTE: if you only have a demo version, remove -z and add 214, as in:
# '--allfiles -noboot -nombr -rs -s {}', [0,214], qr/ALERT:|VIRUS:/,

### http://www.commandsoftware.com/ 
['Command AntiVirus for Linux', 'csav',
'-all -archive -packed {}', [50], [51,52,53],
qr/Infection: (.+)/m ],

### http://www.symantec.com/ 
['Symantec CarrierScan via Symantec CommandLineScanner',
'cscmdline', '-a scan -i 1 -v -s 127.0.0.1:7777 {}',
qr/^Files Infected:\s+0$/m, qr/^Infected\b/m,
qr/^(?:Info|Virus Name):\s+(.+)/m ],

### http://www.symantec.com/
['Symantec AntiVirus Scan Engine',
'savsecls', '-server 127.0.0.1:7777 -mode scanrepair -details -verbose {}',
[0], qr/^Infected\b/m,
qr/^(?:Info|Virus Name):\s+(.+)/m ],
# NOTE: check options and patterns to see which entry better applies

# ### http://www.f-secure.com/products/anti-virus/ version 4.65 
# ['F-Secure Antivirus for Linux servers',
# ['/opt/f-secure/fsav/bin/fsav', 'fsav'],
# '--delete=no --disinf=no --rename=no --archive=yes --auto=yes '.
# '--dumb=yes --list=no --mime=yes {}', [0], [3,6,8],
# qr/(?:infection|Infected|Suspected): (.+)/m ],

### http://www.f-secure.com/products/anti-virus/ version 5.52
['F-Secure Antivirus for Linux servers',
['/opt/f-secure/fsav/bin/fsav', 'fsav'],
'--virus-action1=report --archive=yes --auto=yes '.
'--dumb=yes --list=no --mime=yes {}', [0], [3,4,6,8],
qr/(?:infection|Infected|Suspected|Riskware): (.+)/m ],
# NOTE: internal archive handling may be switched off by '--archive=no'
# to prevent fsav from exiting with status 9 on broken archives

# ### http://www.avast.com/ 
# ['avast! Antivirus daemon',
# \&ask_daemon, # greets with 220, terminate with QUIT
# ["SCAN {}\015\012QUIT\015\012", '/var/run/avast4/mailscanner.sock'],
# qr/\t\[\+\]/m, qr/\t\[L\]\t/m, qr/\t\[L\]\t([^[ \t\015\012]+)/m ],

# ### http://www.avast.com/ 
# ['avast! Antivirus - Client/Server Version', 'avastlite',
# '-a /var/run/avast4/mailscanner.sock -n {}', [0], [1],
# qr/\t\[L\]\t([^[ \t\015\012]+)/m ],

['CAI InoculateIT', 'inocucmd', # retired product
'-sec -nex {}', [0], [100],
qr/was infected by virus (.+)/m ],
# see: http://www.flatmtn.com/computer/Linux-Antivirus_CAI.html

### http://www3.ca.com/Solutions/Product.asp?ID=156 (ex InoculateIT) 
['CAI eTrust Antivirus', 'etrust-wrapper',
'-arc -nex -spm h {}', [0], [101],
qr/is infected by virus: (.+)/m ],
# NOTE: requires suid wrapper around inocmd32; consider flag: -mod reviewer
# see http://marc.theaimsgroup.com/?l=amavis-user&m=109229779912783

### http://mks.com.pl/english.html 
['MkS_Vir for Linux (beta)', ['mks32','mks'],
'-s {}/*', [0], [1,2],
qr/--[ \t]*(.+)/m ],

### http://mks.com.pl/english.html
['MkS_Vir daemon', 'mksscan',
'-s -q {}', [0], [1..7],
qr/^... (\S+)/m ],

# ### http://www.nod32.com/, version v2.52 (old) 
# ['ESET NOD32 for Linux Mail servers',
# ['/opt/eset/nod32/bin/nod32cli', 'nod32cli'],
# '--subdir --files -z --sfx --rtp --adware --unsafe --pattern --heur '.
# '-w -a --action-on-infected=accept --action-on-uncleanable=accept '.
# '--action-on-notscanned=accept {}',
# [0,3], [1,2], qr/virus="([^"]+)"/m ],

# ### http://www.eset.com/, version v2.7 (old) 
# ['ESET NOD32 Linux Mail Server - command line interface',
# ['/usr/bin/nod32cli', '/opt/eset/nod32/bin/nod32cli', 'nod32cli'],
# '--subdir {}', [0,3], [1,2], qr/virus="([^"]+)"/m ],

# ### http://www.eset.com/, version 2.71.12 
# ['ESET Software ESETS Command Line Interface',
# ['/usr/bin/esets_cli', 'esets_cli'],
# '--subdir {}', [0], [1,2,3], qr/virus="([^"]+)"/m ],

### http://www.eset.com/, version 3.0
['ESET Software ESETS Command Line Interface',
['/usr/bin/esets_cli', 'esets_cli'],
'--subdir {}', [0], [1,2,3],
qr/:\s*action="(?!accepted)[^"]*"\n.*:\s*virus="([^"]*)"/m ],

## http://www.nod32.com/, NOD32LFS version 2.5 and above 
['ESET NOD32 for Linux File servers',
['/opt/eset/nod32/sbin/nod32','nod32'],
'--files -z --mail --sfx --rtp --adware --unsafe --pattern --heur '.
'-w -a --action=1 -b {}',
[0], [1,10], qr/^object=.*, virus="(.*?)",/m ],

# Experimental, based on posting from Rado Dibarbora (Dibo) on 2002-05-31 
# ['ESET Software NOD32 Client/Server (NOD32SS)',
# \&ask_daemon2, # greets with 200, persistent, terminate with QUIT
# ["SCAN {}/*\r\n", '127.0.0.1:8448' ],
# qr/^200 File OK/m, qr/^201 /m, qr/^201 (.+)/m ],

### http://www.norman.com/products_nvc.shtml
['Norman Virus Control v5 / Linux', 'nvcc',
'-c -l:0 -s -u -temp:$TEMPBASE {}', [0,10,11], [1,2,14],
qr/(?i).* virus in .* -> \'(.+)\'/m ],

### http://www.pandasoftware.com/ 
['Panda CommandLineSecure 9 for Linux',
['/opt/pavcl/usr/bin/pavcl','pavcl'],
'-auto -aex -heu -cmp -nbr -nor -nos -eng -nob {}',
qr/Number of files infected[ .]*: 0+(?!\d)/m,
qr/Number of files infected[ .]*: 0*[1-9]/m,
qr/Found virus :\s*(\S+)/m ],
# NOTE: for efficiency, start the Panda in resident mode with 'pavcl -tsr'
# before starting amavisd - the bases are then loaded only once at startup.
# To reload bases in a signature update script:
# /opt/pavcl/usr/bin/pavcl -tsr -ulr; /opt/pavcl/usr/bin/pavcl -tsr
# Please review other options of pavcl, for example:
# -nomalw, -nojoke, -nodial, -nohackt, -nospyw, -nocookies

# ### http://www.pandasoftware.com/
# ['Panda Antivirus for Linux', ['pavcl'],
# '-TSR -aut -aex -heu -cmp -nbr -nor -nso -eng {}',
# [0], [0x10, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xF0],
# qr/Found virus :\s*(\S+)/m ],

# GeCAD AV technology is acquired by Microsoft; RAV has been discontinued. 
# Check your RAV license terms before fiddling with the following two lines!
# ['GeCAD RAV AntiVirus 8', 'ravav',
# '--all --archive --mail {}', [1], [2,3,4,5], qr/Infected: (.+)/m ],
# # NOTE: the command line switches changed with scan engine 8.5 !
# # (btw, assigning stdin to /dev/null causes RAV to fail)

### http://www.nai.com/
['NAI McAfee AntiVirus (uvscan)', 'uvscan',
'--secure -rv --mime --summary --noboot - {}', [0], [13],
qr/(?x) Found (?:
\ the\ (.+)\ (?:virus|trojan) |
\ (?:virus|trojan)\ or\ variant\ ([^ ]+) |
:\ (.+)\ NOT\ a\ virus)/m,
# sub {$ENV{LD_PRELOAD}='/lib/libc.so.6'},
# sub {delete $ENV{LD_PRELOAD}},
],
# NOTE1: with RH9: force the dynamic linker to look at /lib/libc.so.6 before
# anything else by setting environment variable LD_PRELOAD=/lib/libc.so.6
# and then clear it when finished to avoid confusing anything else.
# NOTE2: to treat encrypted files as viruses replace the [13] with:
# qr/^\s{5,}(Found|is password-protected|.*(virus|trojan))/

### http://www.virusbuster.hu/en/
['VirusBuster', ['vbuster', 'vbengcl'],
"{} -ss -i '*' -log=$MYHOME/vbuster.log", [0], [1],
qr/: '(.*)' - Virus/m ],
# VirusBuster Ltd. does not support the daemon version for the workstation
# engine (vbuster-eng-1.12-linux-i386-libc6.tgz) any longer. The names of
# binaries, some parameters AND return codes have changed (from 3 to 1).
# See also the new Vexira entry 'vascan' which is possibly related.

# ### http://www.virusbuster.hu/en/ 
# ['VirusBuster (Client + Daemon)', 'vbengd',
# '-f -log scandir {}', [0], [3],
# qr/Virus found = (.*);/m ],
# # HINT: for an infected file it always returns 3,
# # although the man-page tells a different story

### http://www.cyber.com/ 
['CyberSoft VFind', 'vfind',
'--vexit {}/*', [0], [23], qr/##==>>>> VIRUS ID: CVDL (.+)/m,
# sub {$ENV{VSTK_HOME}='/usr/lib/vstk'},
],

### http://www.avast.com/
['avast! Antivirus', ['/usr/bin/avastcmd','avastcmd'],
'-a -i -n -t=A {}', [0], [1], qr/\binfected by:\s+([^ \t\n\[\]]+)/m ],

### http://www.ikarus-software.com/ 
['Ikarus AntiVirus for Linux', 'ikarus',
'{}', [0], [40], qr/Signature (.+) found/m ],

### http://www.bitdefender.com/ 
['BitDefender', 'bdscan', # new version
'--action=ignore --no-list {}', qr/^Infected files\s*:\s*0+(?!\d)/m,
qr/^(?:Infected files|Identified viruses|Suspect files)\s*:\s*0*[1-9]/m,
qr/(?:suspected|infected)\s*:\s*(.*)(?:\033|$)/m ],

### http://www.bitdefender.com/ 
['BitDefender', 'bdc', # old version
'--arc --mail {}', qr/^Infected files *:0+(?!\d)/m,
qr/^(?:Infected files|Identified viruses|Suspect files) *:0*[1-9]/m,
qr/(?:suspected|infected): (.*)(?:\033|$)/m ],
# consider also: --all --nowarn --alev=15 --flev=15. The --all argument may
# not apply to your version of bdc, check documentation and see 'bdc --help'

### ArcaVir for Linux and Unix http://www.arcabit.pl/
['ArcaVir for Linux', ['arcacmd','arcacmd.static'],
'-v 1 -summary 0 -s {}', [0], [1,2],
qr/(?:VIR|WIR):[ \t]*(.+)/m ],

# ### a generic SMTP-client interface to a SMTP-based virus scanner 
# ['av_smtp', \&ask_av_smtp,
# ['{}', 'smtp:[127.0.0.1]:5525', 'dummy@localhost'],
# qr/^2/, qr/^5/, qr/^\s*(.*?)\s*$/m ],

# ['File::Scan', sub {Amavis::AV::ask_av(sub{ 
# use File::Scan; my($fn)=@_;
# my($f)=File::Scan->new(max_txt_size=>0, max_bin_size=>0);
# my($vname) = $f->scan($fn);
# $f->error ? (2,"Error: ".$f->error)
# : ($vname ne '') ? (1,"$vname FOUND") : (0,"Clean")}, @_) },
# ["{}/*"], [0], [1], qr/^(.*) FOUND$/m ],

# ### fully-fledged checker for JPEG marker segments of invalid length
# ['check-jpeg',
# sub { use JpegTester (); Amavis::AV::ask_av(\&JpegTester::test_jpeg, @_) },
# ["{}/*"], undef, [1], qr/^(bad jpeg: .*)$/m ],
# # NOTE: place file JpegTester.pm somewhere where Perl can find it,
# # for example in /usr/local/lib/perl5/site_perl

); 


@av_scanners_backup = ( 

### http://www.clamav.net/ - backs up clamd or Mail::ClamAV
['ClamAV-clamscan', 'clamscan',
"--stdout --no-summary -r --tempdir=$TEMPBASE {}",
[0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

### http://www.f-prot.com/ - backs up F-Prot Daemon, V6 
['F-PROT Antivirus for UNIX', ['fpscan'],
'--report --mount --adware {}', # consider: --applications -s 4 -u 3 -z 10
[0,8,64], [1,2,3, 4+1,4+2,4+3, 8+1,8+2,8+3, 12+1,12+2,12+3],
qr/^\[Found\s+[^\]]*\]\s+<([^ \t(>]*)/m ],

### http://www.f-prot.com/ - backs up F-Prot Daemon (old) 
['FRISK F-Prot Antivirus', ['f-prot','f-prot.sh'],
'-dumb -archive -packed {}', [0,8], [3,6], # or: [0], [3,6,8],
qr/(?:Infection:|security risk named) (.+)|\s+contains\s+(.+)$/m ],

### http://www.trendmicro.com/ - backs up Trophie 
['Trend Micro FileScanner', ['/etc/iscan/vscan','vscan'],
'-za -a {}', [0], qr/Found virus/m, qr/Found virus (.+) in/m ],

### http://www.sald.com/, http://drweb.imshop.de/ - backs up DrWebD 
['drweb - DrWeb Antivirus', # security LHA hole in Dr.Web 4.33 and earlier
['/usr/local/drweb/drweb', '/opt/drweb/drweb', 'drweb'],
'-path={} -al -go -ot -cn -upn -ok-',
[0,32], [1,9,33], qr' infected (?:with|by)(?: virus)? (.*)$'m ],

### http://www.kaspersky.com/
['Kaspersky Antivirus v5.5',
['/opt/kaspersky/kav4fs/bin/kav4fs-kavscanner',
'/opt/kav/5.5/kav4unix/bin/kavscanner',
'/opt/kav/5.5/kav4mailservers/bin/kavscanner', 'kavscanner'],
'-i0 -xn -xp -mn -R -ePASBME {}/*', [0,10,15], [5,20,21,25],
qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.*)/m,
# sub {chdir('/opt/kav/bin') or die "Can't chdir to kav: $!"},
# sub {chdir($TEMPBASE) or die "Can't chdir back to $TEMPBASE $!"},
],

# Commented out because the name 'sweep' clashes with Debian and FreeBSD 
# package/port of an audio editor. Make sure the correct 'sweep' is found
# in the path when enabling.
#
# ### http://www.sophos.com/ - backs up Sophie or SAVI-Perl
# ['Sophos Anti Virus (sweep)', 'sweep',
# '-nb -f -all -rec -ss -sc -archive -cab -mime -oe -tnef '.
# '--no-reset-atime {}',
# [0,2], qr/Virus .*? found/m,
# qr/^>>> Virus(?: fragment)? '?(.*?)'? found/m,
# ],
# # other options to consider: -idedir=/usr/local/sav

# Always succeeds and considers mail clean.
# Potentially useful when all other scanners fail and it is desirable
# to let mail continue to flow with no virus checking (when uncommented).
# ['always-clean', sub {0}],

); 


1; # insure a defined return value

Trong đó, amavisd-new là ứng dụng gắn kết Postfix và SpamAssassin/ClamAV với nhau. Khi cài đặt ClamAV, 1 trình tự công việc đã được thiết lập để cập nhật cơ sở dữ liệu nhận dạng cho ClamAV 3 giờ 1 lần. Nhưng tính năng chỉ hoạt động khi ta kích hoạt bên trong /etc/sysconfig/freshclam and /etc/freshclam.conf:

vi /etc/sysconfig/freshclam

và chú thích bên ngoài dòng FRESHCLAM_DELAY ở phía cuối như sau:

## When changing the periodicity of freshclam runs in the crontab,
## this value must be adjusted also. Its value is the timespan between
## two subsequent freshclam runs in minutes. E.g. for the default
##
## | 0 */3 * * * ...
##
## crontab line, the value is 180 (minutes).
# FRESHCLAM_MOD=


## A predefined value for the delay in seconds. By default, the value is
## calculated by the 'hostid' program. This predefined value guarantees
## constant timespans of 3 hours between two subsequent freshclam runs.
##
## This option accepts two special values:
## 'disabled-warn' ... disables the automatic freshclam update and
## gives out a warning
## 'disabled' ... disables the automatic freshclam silently
# FRESHCLAM_DELAY=


### !!!!! REMOVE ME !!!!!!
### REMOVE ME: By default, the freshclam update is disabled to avoid
### REMOVE ME: network access without prior activation
#FRESHCLAM_DELAY=disabled-warn # REMOVE ME
vi /etc/freshclam.conf

chú thích bên ngoài dòng Example:

[...]
# Comment or remove the line below.
#Example
[...]

Bước tiếp theo, tạo đường dẫn khởi động cho ClamAV và amavisd-new, cập nhật ClamAV và khởi động cả 2 dịch vụ đó:

chkconfig --levels 235 amavisd on
chkconfig --levels 235 clamd.amavisd on
/usr/bin/freshclam
/etc/init.d/amavisd start
/etc/init.d/clamd.amavisd start

Tiếp theo, cấu hình Postfix để có thể gửi mail thông qua amavisd-new:

postconf -e 'content_filter = amavis:[127.0.0.1]:10024'
postconf -e 'receive_override_options = no_address_mappings'

Sau đó thêm dòng lệnh sau vào /etc/postfix/master.cf:

vi /etc/postfix/master.cf

[...]
amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes

127.0.0.1:10025 inet n - - - - smtpd

-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o strict_rfc821_envelopes=yes
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
-o smtpd_bind_address=127.0.0.1

Khởi động lại Postfix để áp dụng các sự thay đổi:

/etc/init.d/postfix restart


Cài đặt Razor, Pyzor và DCC đồng thời cấu hình SpamAssassin

Razor, Pyzor và DCC là các bộ lọc email với tính năng tương tác lẫn nhau. Để cài đặt Razor và Pyzor, gõ lệnh sau:

yum install perl-Razor-Agent pyzor

Khởi tạo cả 2 dịch vụ:

chmod -R a+rX /usr/share/doc/pyzor-0.5.0 /usr/bin/pyzor /usr/bin/pyzord
chmod -R a+rX /usr/lib/python2.6/site-packages/pyzor
su -m amavis -c 'pyzor --homedir /var/spool/amavisd discover'
su -m amavis -c 'razor-admin -home=/var/spool/amavisd -create'
su -m amavis -c 'razor-admin -home=/var/spool/amavisd -register'

Và cài đặt DCC theo cách sau:

cd /tmp
wget http://www.dcc-servers.net/dcc/source/dcc-dccproc.tar.Z
tar xzvf dcc-dccproc.tar.Z
cd dcc-dccproc-1.3.126
./configure --with-uid=amavis
make
make install
chown -R amavis:amavis /var/dcc
ln -s /var/dcc/libexec/dccifd /usr/local/bin/dccifd

Bước tiếp theo, chúng ta cần “thông báo” cho SpamAssassin để sử dụng 3 chương trình này. Chỉnh sửa file /etc/mail/spamassassin/local.cf như sau:

vi /etc/mail/spamassassin/local.cf

# These values can be overridden by editing ~/.spamassassin/user_prefs.cf

# (see spamassassin(1) for details)

# These should be safe assumptions and allow for simple visual sifting

# without risking lost emails.

#required_hits 5

#report_safe 0
#rewrite_header Subject [SPAM]

# dcc

use_dcc 1
dcc_path /usr/local/bin/dccproc

#pyzor

use_pyzor 1
pyzor_path /usr/bin/pyzor

#razor

use_razor2 1
razor_config /var/spool/amavisd/razor-agent.conf

#bayes

use_bayes 1
use_bayes_rules 1
bayes_auto_learn 1

Tiếp theo, kích hoạt plugin DCC trong SpamAssassin. Mở /etc/mail/spamassassin/v310.pre và bỏ ghi chú của dòng loadplugin Mail::SpamAssassin::Plugin::DCC:

vi /etc/mail/spamassassin/v310.pre

[...]
# DCC - perform DCC message checks.
#
# DCC is disabled here because it is not open source. See the DCC
# license for more details.
#
loadplugin Mail::SpamAssassin::Plugin::DCC
[...]

Kiểm tra lại toàn bộ thiết lập của SpamAssassin bằng lệnh sau:

spamassassin --lint

Nếu thành công, thì chương trình sẽ không thông báo gì cả. Sau đó, chạy lệnh:

/etc/init.d/amavisd restart

Tiến hành cập nhật các quy luật của SpamAssassin như sau:

sa-update --no-gpg

Tạo tham số cron để bộ quy luật này cập nhật thường xuyên và có trình tự. Chạy lệnh sau:

crontab -e

để mở thẻ chỉnh sửa cron. Tạo tham số sau:

23 4 */2 * * /usr/bin/sa-update --no-gpg &> /dev/null

Có nghĩa là việc cập nhật sẽ được tiến hành hàng ngày vào lúc 4.23h.

Cảnh báo về Quota Exceedance

Để thiết lập nhận thông tin cảnh báo đối với những tài khoản sử dụng email vượt quá mức quota cho phép, tạo file /usr/local/sbin/quota_notify:

cd /usr/local/sbin/
vi quota_notify 

#!/usr/bin/perl -w 

# Author <jps@tntmax.com> 
#
# This script assumes that virtual_mailbox_base in defined
# in postfix's main.cf file. This directory is assumed to contain
# directories which themselves contain your virtual user's maildirs.
# For example:
#
# -----------/
# |
# |
# home/vmail/domains/
# | |
# | |
# example.com/ foo.com/
# |
# |
# -----------------
# | | |
# | | |
# user1/ user2/ user3/
# |
# |
# maildirsize
#

use strict; 

my $POSTFIX_CF = "/etc/postfix/main.cf"; 
my $MAILPROG = "/usr/sbin/sendmail -t";
my $WARNPERCENT = 80;
my @POSTMASTERS = ('postmaster@domain.tld');
my $CONAME = 'My Company';
my $COADDR = 'postmaster@domain.tld';
my $SUADDR = 'postmaster@domain.tld';
my $MAIL_REPORT = 1;
my $MAIL_WARNING = 1;

#get virtual mailbox base from postfix config
open(PCF, "< $POSTFIX_CF") or die $!;
my $mboxBase;
while (<PCF>) {
next unless /virtual_mailbox_base\s*=\s*(.*)\s*/;
$mboxBase = $1;
}
close(PCF);

#assume one level of subdirectories for domain names 
my @domains;
opendir(DIR, $mboxBase) or die $!;
while (defined(my $name = readdir(DIR))) {
next if $name =~ /^\.\.?$/; #skip '.' and '..'
next unless (-d "$mboxBase/$name");
push(@domains, $name);
}
closedir(DIR);
#iterate through domains for username/maildirsize files
my @users;
chdir($mboxBase);
foreach my $domain (@domains) {
opendir(DIR, $domain) or die $!;
while (defined(my $name = readdir(DIR))) {
next if $name =~ /^\.\.?$/; #skip '.' and '..'
next unless (-d "$domain/$name");
push(@users, {"$name\@$domain" => "$mboxBase/$domain/$name"});
}
}
closedir(DIR);

#get user quotas and percent used
my (%lusers, $report);
foreach my $href (@users) {
foreach my $user (keys %$href) {
my $quotafile = "$href->{$user}/maildirsize";
next unless (-f $quotafile);
open(QF, "< $quotafile") or die $!;
my ($firstln, $quota, $used);
while (<QF>) {
my $line = $_;
if (! $firstln) {
$firstln = 1;
die "Error: corrupt quotafile $quotafile"
unless ($line =~ /^(\d+)S/);
$quota = $1;
last if (! $quota);
next;
}
die "Error: corrupt quotafile $quotafile"
unless ($line =~ /\s*(-?\d+)/);
$used += $1;
}
close(QF);
next if (! $used);
my $percent = int($used / $quota * 100);
$lusers{$user} = $percent unless not $percent;
}
}

#send a report to the postmasters 
if ($MAIL_REPORT) {
open(MAIL, "| $MAILPROG");
select(MAIL);
map {print "To: $_\n"} @POSTMASTERS;
print "From: $COADDR\n";
print "Subject: Daily Quota Report.\n";
print "DAILY QUOTA REPORT:\n\n";
print "----------------------------------------------\n";
print "| % USAGE | ACCOUNT NAME |\n";
print "----------------------------------------------\n";
foreach my $luser ( sort { $lusers{$b} <=> $lusers{$a} } keys %lusers ) {
printf("| %3d | %32s |\n", $lusers{$luser}, $luser);
print "---------------------------------------------\n";
}
print "\n--\n";
print "$CONAME\n";
close(MAIL);
}

#email a warning to people over quota
if ($MAIL_WARNING) {
foreach my $luser (keys (%lusers)) {
next unless $lusers{$luser} >= $WARNPERCENT; # skip those under quota
open(MAIL, "| $MAILPROG");
select(MAIL);
print "To: $luser\n";
map {print "BCC: $_\n"} @POSTMASTERS;
print "From: $SUADDR\n";
print "Subject: WARNING: Your mailbox is $lusers{$luser}% full.\n";
print "Reply-to: $SUADDR\n";
print "Your mailbox: $luser is $lusers{$luser}% full.\n\n";
print "Once your e-mail box has exceeded your monthly storage quota\n";
print "your monthly billing will be automatically adjusted.\n";
print "Please consider deleting e-mail and emptying your trash folder to clear some space.\n\n";
print "Contact <$SUADDR> for further assistance.\n\n";
print "Thank You.\n\n";
print "--\n";
print "$CONAME\n";
close(MAIL);
}
}

Hãy chắc chắn rằng bạn đã điều chỉnh các biến phù hợp ở trên đầu (đặc biệt là địa chỉ postmaster@domain.tld)

Và tiếp đó, tạo file thực thi đoạn mã này:

chmod 755 quota_notify

Và gõ lệnh:

crontab -e

để tạo tham số cron cho đoạn mã đó:

0 0 * * * /usr/local/sbin/quota_notify &> /dev/null


Kiểm tra Postfix

Để kiểm tra chắc chắn Postfix có hoạt động với SMTP-AUTH và TLS, chạy lệnh sau:

telnet localhost 25

Sau khi bạn thiết lập 1 kết nối bất kỳ đến Postfix mail server, gõ lệnh:

ehlo localhost

Và sẽ thấy những dòng thông báo sau:

250-STARTTLS

250-AUTH LOGIN PLAIN

Nghĩa là mọi thứ đều ổn.

[root@server1 sbin]# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 server1.example.com ESMTP Postfix
ehlo localhost
250-server1.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.
[root@server1 sbin]#

Gõ:

quit

để quay trở lại hệ thống.

Đồng bộ hóa các cơ sở dữ liệu và kiểm tra

Để thực hiện bước này, gõ câu lệnh sau:

mysql -u root -p

USE mail;

Và tối thiểu, bạn phải tạo những thành phần sau trong bảng domains và users:

INSERT INTO `domains` (`domain`) VALUES ('example.com');
INSERT INTO `users` (`email`, `password`, `quota`) VALUES ('sales@example.com', ENCRYPT('secret'), 10485760);

Hãy cẩn thận khi dùng cú pháp ENCRYPT trong lệnh INSERT thứ 2 để mã hóa mật khẩu.

Nếu muốn tiếp tục thêm dữ liệu vào các bảng khác, thì hãy làm theo cách sau:

INSERT INTO `forwardings` (`source`, `destination`) VALUES ('info@example.com', 'sales@example.com');
INSERT INTO `transport` (`domain`, `transport`) VALUES ('example.com', 'smtp:mail.example.com');

Thoát khỏi MySQL shell, gõ lệnh:

quit;

Đối với nhiều người, sẽ dễ dàng và đơn giản hơn rất nhiều nếu quản lý và điều khiển MySQL bằng giao diện, qua đó, có thể sử dụng thêm phpMyAdmin (ở bài viết này là http://192.168.0.100/phpMyAdmin/ hoặc http://server1.example.com/phpMyAdmin/) để quản lý cơ sở dữ liệu mail. Bên cạnh đó, mỗi khi tạo mới tài khoản, hãy nhớ sử dụng chức năng ENCRYPT để mã hóa password:

Và tương tự, bảng dữ liệu forwardings sẽ trông như thế này:

Bảng transport:

Gõ lệnh:

man transport

để biết thêm thông tin chi tiết cụ thể.

Gửi email Welcome để tạo Maildir

Khi bạn tạo 1 tài khoản email mới, và thử lấy email từ đó (với chuẩn POP3/IMAP), thông thường sẽ nhận được thông báo lỗi rằng Maildir không tồn tại. Maildir sẽ tự động được tạo ra khi email đầu tiên được tạo đối với tài khoản đầu tiên tương ứng. Trước tiên, cài đặt gói mailx:

yum install mailx

Để gửi email welcome tới địa chỉ sales@example.com, làm như sau:

mailx sales@example.com

Bạn sẽ nhận được thông báo của tiêu đề, gõ bất kỳ nội dung nào (ví dụ Welcome), sau đó nhấn Enter. Trong dòng tiếp theo, gõ nội dung thông báo. Khi hoàn tất phần nội dung, nhấn Enter để bắt đầu 1 dòng mới, tại đây nhấn CTRL+D:

[root@server1 ~]# mailx sales@example.com
Subject: Welcome <-- ENTER
Welcome! Have fun with your new mail account. <-- ENTER
<-- CTRL+D
EOT
[root@server1 ~]#


Cài đặt SquirrelMail

SquirrelMail là hệ thống quản lý webmail có giao diện, cho phép người sử dụng gửi và nhận email thông qua trình duyệt. Để cài đặt SquirrelMail, gõ lệnh sau:

yum install squirrelmail php-pear-DB

Sau đó, khởi động lại Apache:

/etc/init.d/httpd restart

SquirrelMail có đi kèm với 1 số plugin có sẵn, nhưng thật không may, không có plugin nào hỗ trợ người dùng thay đổi mật khẩu email trong cơ sở dữ liệu MySQL. Nhưng thay vào đó, các bạn có thể sử dụng plugin thay thế sau:

cd /usr/share/squirrelmail/plugins
wget http://www.squirrelmail.org/countdl.php?fileurl=http%3A%2F%2Fwww.squirrelmail.org%2Fplugins%2Fchange_sqlpass-3.3-1.2.tar.gz
tar xvfz change_sqlpass-3.3-1.2.tar.gz
cd change_sqlpass
cp config.php.sample config.php

Tiếp theo, chúng ta phải điều chỉnh config.php, thay đổi các biến sau: $csp_dsn, $lookup_password_query, $password_update_queries, $password_encryption, $csp_salt_static, và $csp_delimiter như sau và chú thích bên ngoài $csp_salt_query:

vi config.php

[...]

$csp_dsn = 'mysql://mail_admin:mail_admin_password@localhost/mail';
[...]
$lookup_password_query = 'SELECT count(*) FROM users WHERE email = "%1" AND password = %4';
[...]
$password_update_queries = array('UPDATE users SET password = %4 WHERE email = "%1"');
[...]
$password_encryption = 'MYSQLENCRYPT';
[...]
$csp_salt_static = 'LEFT(password, 2)';
[...]
//$csp_salt_query = 'SELECT salt FROM users WHERE username = "%1"';
[...]
$csp_delimiter = '@';
[...]

File sau khi chỉnh sửa sẽ trông giống thế này:

<?php

/** 
* SquirrelMail Change SQL Password Plugin
* Copyright (C) 2001-2002 Tyler Akins
* 2002 Thijs Kinkhorst <kink@users.sourceforge.net>
* 2002-2005 Paul Lesneiwski <paul@openguild.net>
* This program is licensed under GPL. See COPYING for details
*
* @package plugins
* @subpackage Change SQL Password
*
*/


// Global Variables, don't touch these unless you want to break the plugin
//
global $csp_dsn, $password_update_queries, $lookup_password_query,
$force_change_password_check_query, $password_encryption,
$csp_salt_query, $csp_salt_static, $csp_secure_port,
$csp_non_standard_http_port, $csp_delimiter, $csp_debug,
$min_password_length, $max_password_length, $include_digit_in_password,
$include_uppercase_letter_in_password, $include_lowercase_letter_in_password,
$include_nonalphanumeric_in_password;



// csp_dsn
//
// Theoretically, any SQL database supported by Pear should be supported
// here. The DSN (data source name) must contain the information needed
// to connect to your database backend. A MySQL example is included below.
// For more details about DSN syntax and list of supported database types,
// please see:
// http://pear.php.net/manual/en/package.database.db.intro-dsn.php
//
//$csp_dsn = 'mysql://user:password@localhost/email_users';
$csp_dsn = 'mysql://mail_admin:mail_admin_password@localhost/mail';


// lookup_password_query 
//
// This plugin will always verify the user's old password
// against their login password, but an extra check can also
// be done against the database for more security if you
// desire. If you do not need the extra password check,
// make sure this setting is empty.
//
// This is a query that returns a positive value if a user
// and password pair are found in the database.
//
// This query should return one value (one row, one column), the
// value being ideally a one or a zero, simply indicating that
// the user/password pair does in fact exist in the database.
//
// %1 in this query will be replaced with the full username
// (including domain), such as "jose@example.com"
// %2 in this query will be replaced with the username (without
// any domain portion), such as "jose"
// %3 in this query will be replaced with the domain name,
// such as "example.com"
// %4 in this query will be replaced with the current (old)
// password in whatever encryption format is needed per other
// plugin configuration settings (Note that the syntax of
// the password will be provided depending on your encryption
// choices, so you NEVER need to provide quotes around this
// value in the query here.)
// %5 in this query will be replaced with the current (old)
// password in unencrypted plain text. If you do not use any
// password encryption, %4 and %5 will be the same values,
// except %4 will have double quotes around it and %5 will not.
//
//$lookup_password_query = '';
// TERRIBLE SECURITY: $lookup_password_query = 'SELECT count(*) FROM users WHERE username = "%1" AND plain_password = "%5"';
//$lookup_password_query = 'SELECT count(*) FROM users WHERE username = "%1" AND crypt_password = %4';
$lookup_password_query = 'SELECT count(*) FROM users WHERE email = "%1" AND password = %4';


// password_update_queries
//
// An array of SQL queries that will all be executed
// whenever a password change attempt is made.
//
// Any number of queries may be included here.
// The queries will be executed in the order given here.
//
// %1 in all queries will be replaced with the full username
// (including domain), such as "jose@example.com"
// %2 in all queries will be replaced with the username (without
// any domain portion), such as "jose"
// %3 in all queries will be replaced with the domain name,
// such as "example.com"
// %4 in all queries will be replaced with the new password
// in whatever encryption format is needed per other
// plugin configuration settings (Note that the syntax of
// the password will be provided depending on your
// encryption choices, so you NEVER need to provide quotes
// around this value in the queries here.)
// %5 in all queries will be replaced with the new password
// in unencrypted plain text - BEWARE! If you do not use
// any password encryption, %4 and %5 will be the same
// values, except %4 will have double quotes around it
// and %5 will not.
//
// $password_update_queries = array(
// 'UPDATE users SET crypt_password = %4 WHERE username = "%1"',
// 'UPDATE user_flags SET force_change_pwd = 0 WHERE username = "%1"',
// 'UPDATE users SET crypt_password = %4, force_change_pwd = 0 WHERE username = "%1"',
// );
$password_update_queries = array('UPDATE users SET password = %4 WHERE email = "%1"');


// force_change_password_check_query 
//
// A query that checks for a flag that indicates if a user
// should be forced to change their password. This query
// should return one value (one row, one column) which is
// zero if the user does NOT need to change their password,
// or one if the user should be forced to change it now.
//
// This setting should be an empty string if you do not wish
// to enable this functionality.
//
// %1 in this query will be replaced with the full username
// (including domain), such as "jose@example.com"
// %2 in this query will be replaced with the username (without
// any domain portion), such as "jose"
// %3 in this query will be replaced with the domain name,
// such as "example.com"
//
//$force_change_password_check_query = 'SELECT IF(force_change_pwd = "yes", 1, 0) FROM users WHERE username = "%1"';
//$force_change_password_check_query = 'SELECT force_change_pwd FROM users WHERE username = "%1"';
$force_change_password_check_query = '';



// password_encryption
//
// What encryption method do you use to store passwords
// in your database? Please use one of the following,
// exactly as you see it:
//
// NONE Passwords are stored as plain text only
// MYSQLPWD Passwords are stored using the MySQL password() function
// MYSQLENCRYPT Passwords are stored using the MySQL encrypt() function
// PHPCRYPT Passwords are stored using the PHP crypt() function
// MD5CRYPT Passwords are stored using encrypted MD5 algorithm
// MD5 Passwords are stored as MD5 hash
//
//$password_encryption = 'MYSQLPWD';
$password_encryption = 'MYSQLENCRYPT';


// csp_salt_query 
// csp_salt_static
//
// Encryption types that need a salt need to know where to get
// that salt. If you have a constant, known salt value, you
// should define it in $csp_salt_static. Otherwise, leave that
// value empty and define a value for the $csp_salt_query.
//
// Leave both values empty if you do not need (or use) salts
// to encrypt your passwords.
//
// The query should return one value (one row, one column) which
// is the salt value for the current user's password. This
// query is ignored if $csp_salt_static is anything but empty.
//
// %1 in this query will be replaced with the full username
// (including domain), such as "jose@example.com"
// %2 in this query will be replaced with the username (without
// any domain portion), such as "jose"
// %3 in this query will be replaced with the domain name,
// such as "example.com"
//
//$csp_salt_static = 'LEFT(crypt_password, 2)';
//$csp_salt_static = '"a4"'; // use this format with MYSQLENCRYPT
//$csp_salt_static = '$2$blowsomefish$'; // use this format with PHPCRYPT
//$csp_salt_static = '';
$csp_salt_static = 'LEFT(password, 2)';

//$csp_salt_query = 'SELECT SUBSTRING_INDEX(crypt_password, '$', 1) FROM users WHERE username = "%1"'; 
//$csp_salt_query = 'SELECT SUBSTRING(crypt_password, (LENGTH(SUBSTRING_INDEX(crypt_password, '$', 2)) + 2)) FROM users WHERE username = "%1"';
//$csp_salt_query = 'SELECT salt FROM users WHERE username = "%1"';
//$csp_salt_query = '';



// csp_secure_port
//
// You may ensure that SSL encryption is used during password
// change by setting this to the port that your HTTPS is served
// on (443 is typical). Set to zero if you do not wish to force
// an HTTPS connection when users are changing their passwords.
//
// You may override this value for certain domains, users, or
// service levels through the Virtual Host Login (vlogin) plugin
// by setting a value(s) for $vlogin_csp_secure_port in the vlogin
// configuration.
//
$csp_secure_port = 0;
//$csp_secure_port = 443;



// csp_non_standard_http_port
//
// If you serve standard HTTP web requests on a non-standard
// port (anything other than port 80), you should specify that
// port number here. Set to zero otherwise.
//
// You may override this value for certain domains, users, or
// service levels through the Virtual Host Login (vlogin) plugin
// by setting a value(s) for $vlogin_csp_non_standard_http_port
// in the vlogin configuration.
//
//$csp_non_standard_http_port = 8080;
$csp_non_standard_http_port = 0;



// min_password_length
// max_password_length
// include_digit_in_password
// include_uppercase_letter_in_password
// include_lowercase_letter_in_password
// include_nonalphanumeric_in_password
//
// You can set the minimum and maximum password lengths that
// you accept or leave those settings as zero to indicate that
// no limit should be applied.
//
// Turn on any of the other settings here to check that the
// new password contains at least one digit, upper case letter,
// lower case letter and/or one non-alphanumeric character.
//
$min_password_length = 6;
$max_password_length = 0;
$include_digit_in_password = 0;
$include_uppercase_letter_in_password = 0;
$include_lowercase_letter_in_password = 0;
$include_nonalphanumeric_in_password = 0;



// csp_delimiter
//
// if your system has usernames with something other than
// an "@" sign separating the user and domain portion,
// specify that character here
//
//$csp_delimiter = '|';
$csp_delimiter = '@';



// debug mode 
//
$csp_debug = 0;



?> 

Mặt khác, plugin Change SQL Password cũng phụ thuộc phần lớn vào khả năng tương thích của các hệ thống plugin như sau:

cd /usr/share/squirrelmail/plugins
wget http://www.squirrelmail.org/countdl.php?fileurl=http%3A%2F%2Fwww.squirrelmail.org%2Fplugins%2Fcompatibility-2.0.16-1.0.tar.gz
tar xvfz compatibility-2.0.16-1.0.tar.gz

Bước tiếp theo, di chuyển tới mục điều chỉnh SquirrelMail và “thông báo” tới SquirrelMail rằng chúng ta sẽ sử dụng Courier như chuẩn POP3 và IMAP server, đồng thời kích hoạt 2 plugin Change SQL Password và Compatibility:

/usr/share/squirrelmail/config/conf.pl

Menu điều khiển sẽ hiển thị:

SquirrelMail Configuration : Read: config.php (1.4.0)
---------------------------------------------------------
Main Menu --
1. Organization Preferences
2. Server Settings
3. Folder Defaults
4. General Options
5. Themes
6. Address Books
7. Message of the Day (MOTD)
8. Plugins
9. Database
10. Languages

D. Set pre-defined settings for specific IMAP servers 

C Turn color off 
S Save data
Q Quit

Command >> <-- gõ D 


SquirrelMail Configuration : Read: config.php 
---------------------------------------------------------
While we have been building SquirrelMail, we have discovered some
preferences that work better with some servers that don't work so
well with others. If you select your IMAP server, this option will
set some pre-defined settings for that server.

Please note that you will still need to go through and make sure 
everything is correct. This does not change everything. There are
only a few settings that this will change.

Please select your IMAP server: 
bincimap = Binc IMAP server
courier = Courier IMAP server
cyrus = Cyrus IMAP server
dovecot = Dovecot Secure IMAP server
exchange = Microsoft Exchange IMAP server
hmailserver = hMailServer
macosx = Mac OS X Mailserver
mercury32 = Mercury/32
uw = University of Washington's IMAP server
gmail = IMAP access to Google mail (Gmail) accounts

quit = Do not change anything 
Command >> <-- gõ courier


imap_server_type = courier
default_folder_prefix = INBOX.
trash_folder = Trash
sent_folder = Sent
draft_folder = Drafts
show_prefix_option = false
default_sub_of_inbox = false
show_contain_subfolders_option = false
optional_delimiter = .
delete_folder = true

Press any key to continue... <-- nhấn phím bất kỳ 


SquirrelMail Configuration : Read: config.php (1.4.0) 
---------------------------------------------------------
Main Menu --
1. Organization Preferences
2. Server Settings
3. Folder Defaults
4. General Options
5. Themes
6. Address Books
7. Message of the Day (MOTD)
8. Plugins
9. Database
10. Languages

D. Set pre-defined settings for specific IMAP servers 

C Turn color off 
S Save data
Q Quit

Command >> <-- gõ 8 


SquirrelMail Configuration : Read: config.php (1.4.0) 
---------------------------------------------------------
Plugins
Installed Plugins
1. delete_move_next
2. squirrelspell
3. newmail

Available Plugins: 
4. administrator
5. bug_report
6. calendar
7. change_sqlpass
8. compatibility
9. filters
10. fortune
11. info
12. listcommands
13. mail_fetch
14. message_details
15. sent_subfolders
16. spamcop
17. test
18. translate

R Return to Main Menu 
C Turn color off
S Save data
Q Quit

Command >> <-- gõ 8 


SquirrelMail Configuration : Read: config.php (1.4.0)
---------------------------------------------------------
Plugins
Installed Plugins
1. delete_move_next
2. squirrelspell
3. newmail
4. compatibility

Available Plugins: 
5. administrator
6. bug_report
7. calendar
8. change_sqlpass
9. filters
10. fortune
11. info
12. listcommands
13. mail_fetch
14. message_details
15. sent_subfolders
16. spamcop
17. test
18. translate

R Return to Main Menu 
C Turn color off
S Save data
Q Quit

Command >> <-- gõ 8 (số thứ tự của plugin change_sqlpass) 


SquirrelMail Configuration : Read: config.php (1.4.0) 
---------------------------------------------------------
Plugins
Installed Plugins
1. delete_move_next
2. squirrelspell
3. newmail
4. compatibility
5. change_sqlpass

Available Plugins: 
6. administrator
7. bug_report
8. calendar
9. filters
10. fortune
11. info
12. listcommands
13. mail_fetch
14. message_details
15. sent_subfolders
16. spamcop
17. test
18. translate

R Return to Main Menu 
C Turn color off
S Save data
Q Quit

Command >> <-- gõ S 


SquirrelMail Configuration : Read: config.php (1.4.0)
---------------------------------------------------------
Plugins
Installed Plugins
1. delete_move_next
2. squirrelspell
3. newmail
4. compatibility
5. change_sqlpass

Available Plugins: 
6. administrator
7. bug_report
8. calendar
9. filters
10. fortune
11. info
12. listcommands
13. mail_fetch
14. message_details
15. sent_subfolders
16. spamcop
17. test
18. translate

R Return to Main Menu 
C Turn color off
S Save data
Q Quit

Command >> gõ S 

Data saved in config.php 
Press enter to continue... <-- nhấn ENTER


SquirrelMail Configuration : Read: config.php (1.4.0)
---------------------------------------------------------
Plugins
Installed Plugins
1. delete_move_next
2. squirrelspell
3. newmail
4. compatibility
5. change_sqlpass

Available Plugins: 
6. administrator
7. bug_report
8. calendar
9. filters
10. fortune
11. info
12. listcommands
13. mail_fetch
14. message_details
15. sent_subfolders
16. spamcop
17. test
18. translate

R Return to Main Menu 
C Turn color off
S Save data
Q Quit

Command >> <-- gõ Q

Điều cuối cùng cần thực hiện là chỉnh sửa file /etc/squirrelmail/config_local.php và chú thích bên ngoài biến $default_folder_prefix – nếu không thực hiện bước này, bạn sẽ nhận được thông báo lỗi trong SquirrelMail sau khi đăng nhập: Query: CREATE "Sent" Reason Given: Invalid mailbox name.

vi /etc/squirrelmail/config_local.php

<?php


/**

* Local config overrides.
*
* You can override the config.php settings here.
* Don't do it unless you know what you're doing.
* Use standard PHP syntax, see config.php for examples.
*
* @copyright &copy; 2002-2006 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id: config_local.php,v 1.2 2006/07/11 03:33:47 wtogami Exp $
* @package squirrelmail
* @subpackage config
*/

//$default_folder_prefix = '';

?>

Mở trình duyệt và gõ địa chỉ sau: http://server1.example.com/webmail hoặc http://192.168.0.100/webmail để truy cập SquirrelMail, sử dụng tài khoản email (ở đây là sales@example.com) và mật khẩu khai báo bên trên:

Bạn sẽ thấy email welcome trong mục inbox:

Để thay đổi mật khẩu, chọn Options > Change Password:

Gõ mật khẩu hiện tại và mật khẩu mới 2 lần:

Ngay sau khi đổi mật khẩu, bạn sẽ bị “văng” ra khỏi cửa sổ làm việc hiện tại và phải tiến hành đăng nhập lại:

Chúc các bạn thành công!

Thứ Bảy, 30/09/2023 10:13
31 👨 3.789
0 Bình luận
Sắp xếp theo