Mailzu Setup (MySQL authentication)

Home. This is a guide for installing MailZU on a spamfilter created using the guide at http://verchick.com/mecham/public_html/spam/spamfilter20110303.html or http://verchick.com/mecham/public_html/spam/spamfilter2.html. See http://sourceforge.net/projects/mailzu. We will store the user names and passwords in the MySQL database, but you do have the option for other authentication mechanisms. This document was created for the author's personal use and entertainment. There is absolutely no warranty. Use entirely at your own risk. See the disclaimer at http://verchick.com/mecham/public_html/spam/.

I suggest you save this document to your machine and using a plain text editor (like Wordpad) do a search and replace on the following items:
Root's MySQL password: roots_password
Amavisd-new's MySQL password: amavis_password
IP address of this server (as viewed when on the server): 192.168.1.222
MailZU database access password: mailzu_password
SpamAssassin Bayes database access password: sa_password

We will first install MySQL. During MySQL installation you will be asked for root's password: roots_password
apt-get install mysql-server

Out of the box MySQL is tuned for a system with very little memory. We need to allocate more memory for caching items. This will make a huge difference in performance. We are going to change all tables to InnoDB so we will adjust some InnoDB settings. If you currently have data in MySQL or you have made changes to /etc/mysql/my.cnf you should not perform these steps to replace your my.cnf file with mine! Also, I am assuming you have at the very least 1GB of physical memory installed (2GB recommended - 3GB even better):
cd /etc/mysql/
cp my.cnf my.cnf.original
wget http://verchick.com/mecham/public_html/spam/my.cnf.innodb.patch.txt
patch my.cnf < my.cnf.innodb.patch.txt
/etc/init.d/mysql restart


This is what the patch has added to /etc/mysql/my.cnf:
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!

innodb_data_home_dir = /var/lib/mysql/
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /var/lib/mysql/
innodb_buffer_pool_size = 192M
innodb_additional_mem_pool_size = 4M
innodb_log_file_size = 48M
innodb_log_buffer_size = 8M

#

Log into MySQL using root's password: roots_password
mysql -p

From the mysql> prompt, run these commands:
SHOW VARIABLES LIKE 'innodb_fast_shutdown';
QUIT


Make a mental note of the innodb_fast_shutdown setting. The default is "1".

Since my patch changed the size of innodb_log_file_size, we will have to create new logs. If innodb_fast_shutdown was something other than "1", edit /etc/mysql/my.cnf and add an entry "innodb_fast_shutdown = 1" and then restart mysql with "/etc/init.d/mysql restart". Once innodb_fast_shutdown = 1 then:
/etc/init.d/mysql stop

Make sure that it shuts down without errors (to ensure that there is no information for outstanding transactions in the logs). Then:
mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/iblogfile0-old
mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/iblogfile1-old
/etc/init.d/mysql start
ls -l /var/lib/mysql/ib_*


It should show our two log files are now 48MB in size (50331648). I have set "innodb_buffer_pool_size = 192M" which will give much better performance than the default of 8M, and "innodb_log_file_size = 48M" which is 25% of the innodb_buffer_pool_size. If you have plenty of RAM, you can increase innodb_buffer_pool_size even more, but personally I would not set it to more than 25% of physical RAM.

Grab the amavisd-new database schema from me:
cd
wget http://verchick.com/mecham/public_html/spam/amavisd-new-mysql-ro-2.7.0.txt
wget http://verchick.com/mecham/public_html/spam/amavisd-new-mysql-rw-2.7.0.txt


Log in to MySQL:
mysql -p

and set up the database:
CREATE DATABASE amavis;
GRANT CREATE, DROP, ALTER, SELECT, INSERT, UPDATE, DELETE ON amavis.* TO amavis@localhost IDENTIFIED BY 'amavis_password';
FLUSH PRIVILEGES;
USE amavis;
SOURCE amavisd-new-mysql-ro-2.7.0.txt;
SOURCE amavisd-new-mysql-rw-2.7.0.txt;
quit


Depending on your setup, edit either vi /etc/amavis/amavisd.conf or vi /etc/amavis/conf.d/50-user and near the bottom of the file, configure amavisd-new to use MySQL and store quarantined messages there. Note the 192.168.1.222 IP address shown here must be the IP address of the local machine (where our MySQL quarantine will be stored):
# Here we set up access to MySQL data:
@lookup_sql_dsn = ( ['DBI:mysql:amavis:localhost', 'amavis', 'amavis_password'] );
@storage_sql_dsn = @lookup_sql_dsn;

# required because we set msgs.time_iso to type TIMESTAMP (required by MailZu)
$timestamp_fmt_mysql = 1;

# If using MailZu, store banned files and spam to MySQL if you want to give users the
# ability to read those messages in the MailZu interface:
$banned_files_quarantine_method = 'sql:';
$spam_quarantine_method         = 'sql:';
$virus_quarantine_method        = 'sql:';

## If using Mailzu, use this instead:
$inet_socket_port = [10024, 9998];

## If using Mailzu, use this instead:
$inet_socket_bind = undef;

## Interface to MailZu
$interface_policy{'9998'} = 'AM.PDP';
$policy_bank{'AM.PDP'} = {
    protocol => 'AM.PDP',
    inet_acl => [qw( 127.0.0.1 [::1] 192.168.1.222 )],
    auth_required_release => 0, # don't require secret-id for release
};

#------------ Do not modify anything below this line -------------
1;  # ensure a defined return
You can restart amavisd-new now:
/etc/init/amavis restart

Install Apache2 and PHP:
apt-get install apache2 libapache2-mod-php5 php-mail-mime php-mail-mimedecode php5 php5-common php5-mysql php5-gd php-db php5-imap php-net-socket php5-ldap

Patch the current version of php-mail-mimedecode:
sed -i "s/\&new Mail_mimeDecode/new Mail_mimeDecode/" /usr/share/php/Mail/mimeDecode.php

Download, install, patch and partially configure MailZU:
cd /var/www
wget http://verchick.com/mecham/public_html/spam/MailZu_0.8RC3.tar.gz
tar xzf MailZu_0.8RC3.tar.gz
mv MailZu_0.8RC3.tar.gz /usr/local/src/
mv MailZu_0.8RC3 mailzu
cd mailzu/config
cp config.php.sample config.php
cp config.php.sample config.php.original

cd /var/www/mailzu/lib/
cp AmavisdEngine.class.php AmavisdEngine.class.php.original
wget http://verchick.com/mecham/public_html/spam/AmavisdEngine.patch1.txt
patch -p0 < AmavisdEngine.patch1.txt
cp DBEngine.class.php DBEngine.class.php.original
sed -i 's/dbtype/dbType/' DBEngine.class.php
sed -i 's/COUNT(content)/COUNT(msgs.content)/' DBEngine.class.php
sed -i 's/WHERE content=/WHERE msgs.content=/' DBEngine.class.php

cd /var/www/mailzu/config
sed -i "s/set_magic_quotes_runtime(0);/ini_set('magic_quotes_runtime', 0);/" init.php
sed -i "s/'user'/'amavis'/" config.php
sed -i "s/'pass'/'amavis_password'/" config.php
sed -i "s/'dbname'/'amavis'/" config.php
sed -i "s/hostname.example.com/localhost/" config.php
sed -i "s/binquar'] = false/binquar'] = true/" config.php
sed -i "s/'emailType'] = 'mail'/'emailType'] = 'sendmail'/" config.php
touch /var/log/mailzu.log
chown www-data:www-data /var/log/mailzu.log
chmod 660 /var/log/mailzu.log
chown -R root:www-data /var/www/mailzu
chmod 640 config.php

cd /etc/logrotate.d
wget http://verchick.com/mecham/public_html/spam/mailzu.logrotate.txt
mv mailzu.logrotate.txt mailzu
cd
For MySQL authentication, create the MySQL table that will hold the usernames and passwords of the users:
mysql -p
CREATE DATABASE mailzu;
USE mailzu;
CREATE TABLE mailzu_users (
  username      varchar(255) NOT NULL UNIQUE,
  password      varchar(255) DEFAULT NULL,
  fullname      varchar(255) DEFAULT NULL,
  emailaddress  varchar(255) DEFAULT NULL
);
GRANT SELECT ON mailzu.* TO mailzu@localhost IDENTIFIED BY 'mailzu_password';
quit;
Now we set up MailZU to use the mailzu_users database to look for user names and passwords:
sed -i "s/'serverType'\] = 'ldap'/'serverType'\] = 'sql'/" /var/www/mailzu/config/config.php
sed -i "s/'dbHostSpec'\] = ''/'dbHostSpec'\] = 'localhost:3306'/" /var/www/mailzu/config/config.php
sed -i "s/'dbUser'\] = ''/'dbUser'\] = 'mailzu'/" /var/www/mailzu/config/config.php
sed -i "s/'dbPass'\] = ''/'dbPass'\] = 'mailzu_password'/" /var/www/mailzu/config/config.php
sed -i "s/'dbName'\] = ''/'dbName'\] = 'mailzu'/" /var/www/mailzu/config/config.php
sed -i "s/'dbTable'\] = ''/'dbTable'\] = 'mailzu_users'/" /var/www/mailzu/config/config.php
sed -i "s/'dbTableUsername'\] = ''/'dbTableUsername'\] = 'username'/" /var/www/mailzu/config/config.php
sed -i "s/'dbTablePassword'\] = ''/'dbTablePassword'\] = 'password'/" /var/www/mailzu/config/config.php
sed -i "s/'dbTableName'\] = ''/'dbTableName'\] = 'fullname'/" /var/www/mailzu/config/config.php
sed -i "s/'dbTableMail'\] = ''/'dbTableMail'\] = 'emailaddress'/" /var/www/mailzu/config/config.php


We will want to take a look and see if it appears to be set up correctly:
vi /var/www/mailzu/config/config.php

Now you need to log in to MySQL and add at least one user to the mailzu_users table. This is an *example*, you must change to meet your needs for each user you add:
mysql -p

use mailzu;
INSERT INTO mailzu_users VALUES ( 'garyv@example.com', MD5('passwd'), 'Gary V', 'garyv@example.com' );

A couple examples of queries where you might change a password, or delete a record:

use mailzu;
UPDATE mailzu_users SET password=MD5('newpasswd') WHERE username='garyv@example.com';

use mailzu;
DELETE from mailzu_users WHERE username='garyv@example.com';


Restart apache2:
/etc/init.d/apache2 restart

You should be able to at least log into MailZU at this point:
http://192.168.1.222/mailzu

It's up to you to configure your DNS settings so people can use the web server name instead of the IP address.

There are a few settings that need to be changed in /var/www/mailzu/config/config.php, so:
vi /var/www/mailzu/config/config.php

and change these settings as required (they start on line 279):
// List of Super Admins
// Super Admins can do anything mail admins can plus
// change settings
$conf['auth']['s_admins'] = array ('user1', 'user2');

// The full url to the root directory of MailZu
// Please do not include the trailing slash
$conf['app']['weburi'] = 'https://mailzuhost.example.com/mailzu';

// The email addresses of the support staff and/or administrator
// An email is sent to these addresses when a user reports an error
// or clicks the "Email Administrator" link
$conf['app']['adminEmail'] = array('support@example.com');


Keep an eye on /var/log/apache2/error.log and /var/log/mailzu.log for error messages.

This nice little program can perform backups of our MySQL data. We will make local backups (and keep 4 days worth). Keep an eye on free disk space once you get going, copies of your MySQL databases will take up some space.
apt-get install libxml-parser-perl bsd-mailx

cd /usr/local/src
wget http://www.zmanda.com/downloads/community/ZRM-MySQL/2.2/Debian/mysql-zrm_2.2.0_all.deb
dpkg -i mysql-zrm_2.2.0_all.deb

sed -i 's/#user="wikiuser"/user="root"/' /etc/mysql-zrm/mysql-zrm.conf
sed -i 's/#password="userwiki"/password="roots_password"/' /etc/mysql-zrm/mysql-zrm.conf
sed -i 's/#retention-policy=10W/retention-policy=4D/' /etc/mysql-zrm/mysql-zrm.conf
sed -i 's/#mailto="mysqldba@company.com"/mailto="root@example.com"/' /etc/mysql-zrm/mysql-zrm.conf
chown root:root /usr/share/man/man5/mysql-zrm*
chown root:root /usr/share/man/man1/mysql-zrm*
chmod 644 /usr/share/man/man5/mysql-zrm*
chmod 644 /usr/share/man/man1/mysql-zrm*

mysql-zrm-scheduler --now --backup-set dailyrun --backup-level 0

mysql-zrm-scheduler --add --interval daily --backup-set dailyrun --backup-level 0


This places entries in root's crontab. Run crontab -e and see if you have any extra newline characters separating any entries (and edit them out). The details of what just happened can be found here: http://www.howtoforge.com/mysql_zrm_debian_sarge. I suggest you save all five pages of that HOWTO to your computer (and maybe read them too). This program will send you a couple (annoying) email messages each day. You can turn them off if you like by commenting out the "mailto" line in /etc/mysql-zrm/mysql-zrm.conf.

Here is the user's manual for mysql-zrm: http://mysqlbackup.zmanda.com/index.php/Zmanda_Recovery_Manager_for_MySQL_Users_Manual

Install a couple maintenance scripts to prevent the amavis database from growing forever. Messages older than 24 days are deleted. These are not messages stored in mail boxes, they are messages that are stored in MySQL and are accessed via MailZu. If it grows forever, you or I made a mistake here:
cd /usr/sbin
wget http://verchick.com/mecham/public_html/spam/trim-amavis-msgs.txt
mv trim-amavis-msgs.txt trim-amavis-msgs
sed -i 's/Passw0rd/amavis_password/' trim-amavis-msgs
chmod 750 trim-amavis-msgs
cd /etc
wget http://verchick.com/mecham/public_html/spam/trim-amavis.sql.txt
mv trim-amavis.sql.txt trim-amavis.sql
cd /etc/cron.daily/
wget http://verchick.com/mecham/public_html/spam/trim-amavis.txt
mv trim-amavis.txt ztrim-amavis
sed -i 's/password/amavis_password/' ztrim-amavis
chmod 750 ztrim-amavis
./ztrim-amavis


If you want to use a different authentication method (in /var/www/mailzu/config/config.php), I suggest IMAP. Here is an example using port 143 to connect to my Exchange 2010 test server - test3.example.local. I think IMAP is disabled by default in Exchange 2010, so I did have to enable the IMAP service. See http://technet.microsoft.com/en-us/library/bb124489.aspx. Users log in using their full e-mail address - e.g. garyv@example.local:
// Available authentication methods
/* Options are:
        ldap -> Standard LDAP server, e.g. OpenLDAP
        ad   -> MS Active Directory
        sql  -> PHP PEAR compatible database
        exchange  -> MS Exchange 5.5
        imap  -> IMAP protocol
*/
$conf['auth']['serverType'] = 'imap';


/*** IMAP Authentication Settings ***/
// List of IMAP servers and ports (e.g.: 10.1.1.20:143)
$conf['auth']['imap_hosts'] = array( 'test3.example.local:143/novalidate-cert' );

// IMAP type
/* Options are:
        imap     -> default
        imaptls  -> do not do start-TLS to encrypt the session, even with servers that support it
        imapssl  -> use the Secure Socket Layer to encrypt the session
        imapcert -> use the Secure Socket Layer to encrypt the session,
                    do not validate certificates from TLS/SSL server, needed if server uses self-signed certificates
*/
$conf['auth']['imap_type'] = 'imap';

// Domain name part of the email address, (e.g.: example.com)
$conf['auth']['imap_domain_name'] = '';
As you are aware, it is better to use an encrypted connection, so this would be better:
// Available authentication methods
/* Options are:
        ldap -> Standard LDAP server, e.g. OpenLDAP
        ad   -> MS Active Directory
        sql  -> PHP PEAR compatible database
        exchange  -> MS Exchange 5.5
        imap  -> IMAP protocol
*/
$conf['auth']['serverType'] = 'imap';


/*** IMAP Authentication Settings ***/
// List of IMAP servers and ports (e.g.: 10.1.1.20:143)
$conf['auth']['imap_hosts'] = array( 'test3.example.local:993' );

// IMAP type
/* Options are:
        imap     -> default
        imaptls  -> do not do start-TLS to encrypt the session, even with servers that support it
        imapssl  -> use the Secure Socket Layer to encrypt the session
        imapcert -> use the Secure Socket Layer to encrypt the session,
                    do not validate certificates from TLS/SSL server, needed if server uses self-signed certificates
*/
$conf['auth']['imap_type'] = 'imapcert';

// Domain name part of the email address, (e.g.: example.com)
$conf['auth']['imap_domain_name'] = '';
However, in tail -f /var/log/apache2/error.log I now get an error:
[Sat May 26 17:50:46 2012] [error] [client 192.168.1.40] PHP Notice: Unknown: Kerberos error: Credentials cache file '/tmp/krb5cc_33' not found (try running kinit) for test3.example.local (errflg=1) in Unknown on line 0, referer: http://192.168.1.222/mailzu/index.php

I read http://php.net/manual/en/function.imap-open.php and discovered we can eliminate the error message by editing line 84 of vi /var/www/mailzu/lib/IMAPAuth.class.php and changing it from:
$connection = imap_open($host, $username, $password, OP_HALFOPEN);
to:
$connection = imap_open($host, $username, $password, OP_HALFOPEN, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'));

If you have a few different servers that you need to connect to for authentication, I suggest giving each a copy of the website and configuring each separately, for example:
cp -R -p /var/www/mailzu/ /var/www/example.com
vi /var/www/example.com/config/config.php


Now you can also log in to http://192.168.1.222/example.com


It's probably not a good idea to have people send passwords to this machine using an unencrypted connection, so you should probably configure Apache2 to use an SSL certificate and use https:. In one of my other documents I explain how to create your own certificate authority and sign your own certificate and set up Apache2 to use it. You will also need to save that document to your PC and edit the host name and domain name. Of course you can purchase a certificate from a certificate authority if desired. See my instructions at http://verchick.com/mecham/public_html/spam/ubuntu1204-maia.html#certs.


Since you have gone to the trouble of setting up MySQL, might as well use it for the Bayes database too. Placing Bayes and AWL data in MySQL will put a little more load on the MySQL server, but as long as you have been reasonably generous with innodb_buffer_pool_size and innodb_log_file_size you will greatly improve Bayes performance (do these in sections):
First, there is a bug in SpamAssassin 3.3.x that needs to be fixed:
cd /usr/share/perl5/Mail/SpamAssassin/BayesStore
grep -q 46675 MySQL.pm || wget http://verchick.com/mecham/public_html/spam/mysql-bug-46675.patch.txt
grep -q 46675 MySQL.pm || patch MySQL.pm < mysql-bug-46675.patch.txt

cd /etc/spamassassin/
wget http://verchick.com/mecham/public_html/spam/bayes2011.sql.txt
sed -i 's/paSSw0rd/sa_password/' bayes2011.sql.txt
mysql -u root -p < bayes2011.sql.txt

Enter roots_password to complete the process.

rm bayes2011.sql.txt
wget http://verchick.com/mecham/public_html/spam/local.cf-bayes-awl.v3.txt
cp local.cf local.cf-before-mysql
cat local.cf-bayes-awl.v3.txt local.cf-before-mysql > local.cf
sed -i 's/paSSw0rd/sa_password/' local.cf
chmod 0640 local.cf
chown root:amavis local.cf
spamassassin --lint
/etc/init.d/amavis restart

cd /var/lib/amavis
wget http://verchick.com/mecham/public_html/spam/sample-spam.txt
sa-learn --spam sample-spam.txt
sa-learn --dump magic
spamassassin --lint


It should show our nspam (number of spam) count is 1, and --lint should be clean. We should also create our .spamassassin directory and user_prefs file:
su amavis -c 'spamassassin <sample-spam.txt'

The warning message "warn: config: created user preferences file:" is a good thing.
We continue by adding an AWL and bayes_seen maintenance script (watch for errors):
cd /etc
wget http://verchick.com/mecham/public_html/spam/trim-awl.sql.txt
mv trim-awl.sql.txt trim-awl.sql
cd /usr/sbin
wget http://verchick.com/mecham/public_html/spam/trim-awl.txt
mv trim-awl.txt trim-awl
sed -i 's/paSSw0rd/sa_password/' trim-awl
chmod 0750 trim-awl
cd /etc/cron.weekly/
wget http://verchick.com/mecham/public_html/spam/trim-sql-awl-weekly.txt
mv trim-sql-awl-weekly.txt trim-sql-awl-weekly
chmod +x trim-sql-awl-weekly
./trim-sql-awl-weekly



mr88talent at yahoo dot com
26 MAY 2012