DSPAM Setup

DSPAM is a statistical hybrid filter for SPAM. It is very similar in nature to the junk mail filter that's built into Mail.app, but with one major advantage—the message processing is done on your mail server, not on the mail client.

By processing the messages on the server, you eliminate the need to download hundreds of messages just to throw them into a junk mail folder. Also, keeping statistics about SPAM on the server allows an administrator to build composite information gathered from all users of the mail server—allowing new users to benefit from the SPAM caught by previous users.

The following instructions will help you configure DSPAM on a stock Mac OS X Server installation (version 10.3.x). This configuration utilizes the existing tools that are installed: Postfix, Cyrus, MySQL and procmail.

To perform these steps, you should be feel comfortable using command line tools to download, configure, build and install software.

The latest version of DSPAM is available at the following URL:

<http://www.nuclearelephant.com/projects/dspam/>

These instructions were written for version 3.0.0 and assume that you have reviewed the README file from the DSPAM download. It is also assumed that you've put the DSPAM source code in ~/Temp/dspam-3.0.0/ after downloading.

0. Set up MySQL

MySQL is used as the backend storage for DSPAM. To set it up, run Applications > Server > MySQL Manager from the Finder. First use Install to copy files and then use Start to get the mysqld running.

1. Set up procmail.dspam

Create a copy of /usr/bin/procmail (called /usr/bin/procmail.dspam) so that CGI scripts can run the DSPAM agent (/usr/local/bin/dspam) which can then run procmail as root.

% cd /usr/bin
% cp procmail procmail.dspam
% sudo chmod u+s procmail.dspam
% sudo chgrp mail procmail.dspam
% sudo chmod o-x procmail.dspam

You should now see something like this:

% ls -la procmail*
-rwxr-xr-x  1 root  wheel  87208 17 Mar 15:41 procmail
-rwSr-xr--  1 root  mail   87208  7 Jun 16:56 procmail.dspam

2. Patch MySQL Library

Patch libmysqlclient.a because DSPAM build will fail with:

/bin/sh ./libtool --mode=link gcc  -g -O2 -Wall -Wmissing-prototypes -Wmissing-declarations  -L/usr/lib/mysql  -o libdspam.la -rpath /usr/local/lib -version-info 5:0:0 libdspam.lo tbt.lo lht.lo base64.lo buffer.lo util.lo nodetree.lo error.lo decode.lo mysql_drv.lo -lm -lmysqlclient  -lm -lz 
gcc -dynamiclib -flat_namespace -undefined suppress -o .libs/libdspam.5.0.0.dylib  .libs/libdspam.o .libs/tbt.o .libs/lht.o .libs/base64.o .libs/buffer.o .libs/util.o .libs/nodetree.o .libs/error.o .libs/decode.o .libs/mysql_drv.o -all_load  /usr/lib/mysql/libmysqlclient.a  -L/usr/lib/mysql -lm -lz -install_name  /usr/local/lib/libdspam.5.dylib -compatibility_version 6 -current_version 6.0
ld: common symbols not allowed with MH_DYLIB output format with the -multi_module option
/usr/lib/mysql/libmysqlclient.a(my_error.o) definition of common _errbuff (size 512)
/usr/bin/libtool: internal link edit command failed

To patch the library, use:

% cd /usr/lib/mysql
% mv libmysqlclient.a libmysqlclient.a.original

% mkdir /tmp/mysql 
% cd /tmp/mysql 
% ar x /usr/lib/mysql/libmysqlclient.a.original
% ld -r -d my_error.o 
% mv a.out my_error.o 
% libtool -o /usr/lib/mysql/libmysqlclient.a *.o 

(Ignore "no symbols" warnings)

More information on how this patch works can be found here: <http://curl.haxx.se/mail/lib-2002-06/0202.html>

3. Configure and Build DSPAM

To configure DSPAM to run with procmail as the delivery agent and MySQL as the backend, use:

% cd ~/Temp/dspam-3.0.0
% ./configure \
	--with-delivery-agent='/usr/bin/procmail.dspam' \
	--with-storage-driver=mysql_drv \
	--with-mysql-includes="/usr/include/mysql" \
	--with-mysql-libraries="/usr/lib/mysql"

If you want to build the debug version, change debug_text to static in error.h

41c41
< char debug_text[1024];
---
> static char debug_text[1024];

and add the following to the configure command above:

	--enable-debug \

Create and install the DSPAM binaries with:

% make
% sudo make install

This will populate:

/usr/local/lib
/usr/local/bin

and create:

/var/dspam

Make dspam setgid:

% chmod g+s /usr/local/bin/dspam

% ll /usr/local/bin/dspam
-r-x--s---  1 root  mail  391500 16 Jun 09:54 /usr/local/bin/dspam

4. Create MySQL database for DSPAM per user statistics

% mysqladmin create dspam

Grant access using instructions at: <http://dev.mysql.com/doc/mysql/en/Adding_users.html>

Create tables used by DSPAM:

% mysql -u root dspam < mysql_objects.sql.speed.optimized

Populate database with a backup of the prebuilt corpus (if you don't have a backup, skip this step):

% mysql -u root dspam < dspam-backup.sql

5. Create configuration file that allows DSPAM to connect to MySQL

Create /var/dspam/mysql.data with contents as:

127.0.0.1
3306
root

dspam

Note the blank line, it's because we have not set a password. The values are db host IP address, port, username, password and database name.

Set owner:group and permissions:

% chmod u+rw g-w o-rw mysql.data
% chown root:mail mysql.data

6. Setup DSPAM CGI

Using the Server Admin application, create a new web Domain in Web Service (DSPAM) enabled on port 8080. After setup, you will be accessing the DSPAM web tools with:

http://mail.yourserver:8080/DSPAM

General:

Set web folder to /Library/WebServer/Documents/DSPAM
Add "dspam.cgi" to default index files (at top of list)

Copy the entire contents of ~/Temp/dspam-3.0.0/cgi folder to /Library/WebServer/Documents/DSPAM

Change the owner of all CGI scripts (*.cgi) to "www", so you have:

-rwxrwxr--  1 www  admin  15825 17 Jun 10:14 admin.cgi
-rwxrwxr--  1 www  admin   3076 16 Jun 17:11 admingraph.cgi
-rwxrwxr--  1 www  admin  26098 17 Jun 11:52 dspam.cgi
-rwxrwxr--  1 www  admin   2660 16 Jun 11:21 graph.cgi

Options:

Enable CGI Execution.

Realms:

Create realm named DSPAM, add users who will be checking & processing mail with browse privileges, add group "admin" with browse and author privileges.

Using the Workgroup Manager, add the "www" user to "mail" group so that Apache can send mail.

Configure dspam.cgi (Perl source code):

## Configuration
#
$CONFIG{'DSPAM_HOME'}   = "/var/dspam";
$CONFIG{'ME'}           = "dspam.cgi";
$CONFIG{'DSPAM'}        = "/usr/local/bin/dspam";
$CONFIG{'DSPAM_ARGS'}   = "--deliver=innocent --mode=teft --class=innocent " .
                          "--source=error --user $ENV{'REMOTE_USER'} " .
                          "-t -m USER=$ENV{'REMOTE_USER'} /etc/procmailrc";
$CONFIG{'LARGE_SCALE'}  = 0;                    # --enable-large-scale
$CONFIG{'DOMAIN_SCALE'} = 0;                    # --enable-domain-scale
$CONFIG{'TEMPLATES'}    = "./templates";        # Location of HTML templates
$CONFIG{'HISTORY_SIZE'} = 200;                  # Number of items in history
$CONFIG{'MAX_COL_LEN'}  = 45;                   # Max chars in list columns
#
## End Configuration

Configure admin.cgi (Perl source code):

## Configuration
#
$CONFIG{'DSPAM_HOME'}   = "/var/dspam";
$CONFIG{'ME'}           = "admin.cgi";
$CONFIG{'TEMPLATES'}    = "./templates";        # Location of HTML templates
$CONFIG{'ALL_PROCS'}    = "ps -ax";
$CONFIG{'MAIL_QUEUE'}   = "mailq | grep '^[0-9,A-F]' | wc -l";
$CONFIG{'PREFIX'}       = "/usr/local";         # DSPAM prefix
$CONFIG{'LARGE_SCALE'}  = 0;
$CONFIG{'DOMAIN_SCALE'} = 0;
#
## End Configuration

Setup Graph::GD for graphics in Perl CGI scripts:

Download libpng from <http://www.libpng.org/pub/png/libpng.html> then build and install:

% cp scripts/makefile.macosx Makefile
% make
% sudo make install

(Ignore make errors for pngtest.)

Download libgd from <http://www.boutell.com/gd>, configure build and install:

% ./configure
% make
% sudo make install
% sudo ranlib /usr/local/lib/libpng.a

Get GD::Graph from CPAN:

% sudo cpan
cpan> install GD
installed? /usr/local/lib
support? PNG only
cpan> install GD::Graph::lines3d
cpan> quit

7. Setup Postfix to send messages to DSPAM

Add to end of /etc/postfix/master.cf.defaultserver:

# DSPAM processing before handling message to procmail
dspam     unix  -       n       n       -       -       pipe
  flags=Rhqu user=cyrus argv=/usr/local/bin/dspam --mode=teft --deliver=innocent --feature=chained,noise --user ${user} -t -m USER=${user} EXTENSION=${extension} /etc/procmailrc

Set flags="hqu" if you want to omit "Return-Path:" from the headers.

Add to /etc/postfix/main.cf

mailbox_transport = dspam
default_privs = cyrus

(Be careful to remove other instances of "mailbox_transport", there's one for Cyrus at end of file!)

After updating the Postfix configuration, shut down the mail service, remove the fscking stupid swap file, and restart the service.

% sudo serveradmin stop mail
% rm /etc/postfix/master.cf.defaultserver.swap
% sudo serveradmin start mail

Create /var/dspam/trusted.users with user ids that will need to run DSPAM:

root
cyrus
www
postfix

DSPAM uses special mail aliases, spam-user and ham-user, that update the per-user statistics. Create these aliases by editing the aliases file (as reported by the "postconf alias_maps" command):

cyrus:		root
debug:		root

spam-user:		"|'/usr/local/bin/dspam' --user 'user' --class=spam --source=error --mode=teft"
ham-user:		"|'/usr/local/bin/dspam' --user 'user' --class=innocent --source=error --mode=teft --deliver=innocent -t -m USER=user EXTENSION= /etc/procmailrc"

spam-global:	"|'/usr/local/bin/dspam' --user 'global' --class=spam --source=corpus --mode=teft"
ham-global:	"|'/usr/local/bin/dspam' --user 'global' --class=innocent --source=corpus --mode=teft"

Replace user with a real user name, there is a spam-user and ham-user for every user who receives mail on the server. The spam-global and ham-global are used to update the corpus used by all users.

The cyrus and debug aliases are used for debugging.

After the aliases are update, deploy them with:

% sudo newaliases

8. Create /etc/procmailrc

This procmailrc file will be processed after DSPAM has processed the message and determined that it is not SPAM. This allows you to do any processing necessary before the message is handed off to Cyrus' deliver command. This happens because the delivery agent was set to /usr/bin/procmail.dspam when running configure for DSPAM.

# to DEBUG the processing done by procmail, uncomment the following line:
#LOGFILE=/var/log/procmail
# the logfile needs to be created with:
# -rw-rw-r--  1 root  mail  2356 23 Jun 09:12 /var/log/procmail

VERBOSE=yes
HOME=/Users/$USER
DROPPRIVS=yes
 
# set shell so that formail used in autoreply will work correctly
SHELL=/bin/bash

# allow users to create their own recipes
INCLUDERC=$HOME/.procmail

# get debugging info
DEBUG="id='`id`' USER=$USER"

# get subject line from e-mail
#SUBJECT=`formail -xSubject:`

# body from e-mail
#BODY=`formail -I ""`

# convert user name to all lowercase
USER=`echo $USER | tr "[:upper:]" "[:lower:]"`

# debug autoreply
:0 h
* !^FROM_DAEMON
* !^FROM_MAILER
* !^X-Loop: debug_autoreply
* ^TO_debug@Monterey.local
| (formail -rt -A "Precedence: junk (autoreply)" \
                -A "X-Loop: debug_autoreply" ; \
        echo $DEBUG ; \
        echo "EOM" ) | $SENDMAIL -t -i -F "Debug" -f postmaster

# if no matches above, deliver message to the user's inbox
:0w
| /usr/bin/cyrus/bin/deliver -a $USER -m user/$USER

9. Create a global user for DSPAM statistics

Create a "global" user with Workgroup Manager:

Name: Global DSPAM User
Short name: global
Login: yes
Mail: None

Feed message from corpus into the global user:

% cd SA-Corpus
% chmod u+x train.pl
% sudo ./train.pl global

Create /var/dspam/group file with:

groupname:classification:*global

Merge individual user data into global:

% /usr/local/bin/dspam_merge bob carol ted alice -o global

Check that global reporting aliases "ham-global" and "spam-global" are in /etc/aliases. These can be used by other users to train the global user (by forwarding messages to the correct address.)

10. Test

At this point, any mail sent to a user account on the server will pass through DSPAM before being delivered. Any mail that is put into the quarantine (because it is thought to be SPAM) can be viewed with your web browser:

http://mail.yourserver:8080/DSPAM

Of course, nothing ever goes as planned, so if you have problems here are some good places to look:

/var/mail	for messages that are not getting delivered correctly

/var/log/mail.log	Postfix and Cyrus message processing
/var/log/system.log	Postfix and Cyrus errors

/var/dspam/dspam.debug	DSPAM processing log (if enabled during configure)
/var/dspam/dspam.messages	DSPAM message log (if enabled during configure)

/var/dspam/sql.errors	DSPAM errors with MySQL backend

/var/dspam/data/user/user.log	A log of messages processed for user (along with status)
/var/dspam/data/user/user.mbox	The quarantine for user

/etc/postfix/master.cf.defaultserver	Postfix transport configurations
/etc/postfix/main.cf	Postfix configuration

/etc/imap.conf	Cyrus configuration