|
ISP Mailserver Solution Howto
Author: Martin List-Petersen - martin at list-petersen dot dk
The newest version of this document can allways be found at http://www.marlow.dk/postfix/
To see this document outside the frames, click here.
Version: 0.30
Created: May 11th, 2002
Last updated: October 6th, 2003
Acknowledgements: There has been many efforts out there to describe how to get a mailserver to work with storing tables, users and so on in databases, but most of the stuff found out there did only describe parts of, what was needed. So what i try, is to describe the setup, the way i did it. This is maybe not the solution you want, but it'll give you pretty much insight in, how it can be done. This document describes a working solution, which is used in production on several hosting servers with multiple domains, but gives you no warranty on that it'll work for you. This document is provided as is.
On June 8th, 2003 the whole thing took a new turn. I've decided to release the software, that i wrote for management of postfix. This is released on http://www.ispworks.org/ and because of that i changed the whole database structure to match the management system. The management systems handles Postfix, PureFTPd, PowerDNS and a good bunch more. Fell free to download and test it.
Thanks to Ryan Skov for testing and the work spend on getting this setup together.
I also want to thank everybody, who send in feedback regarding this documentation. This really helps to make it better.
Purpose
The goals of this document:
- archieve an ISP hosting solution that is dynamically and easy to manage.
- to get rid of different limitations in comparison to creating unix accounts for every mailuser.
- to archieve the possibility for CRAM-MD5 encryptet password challenges on POP and IMAP instead of cleartext.
- the domains hosted should be handled independant to each other (different namespaces for every domain).
- to be able to act as SMTP for clients without knowing their ip upfront, but still not being an open relay.
- scan mails for virus and notify hostmaster, sender and receiver on virus alerts.
Related Stuff:
- Postfix (MTA): http://www.postfix.org/ - Note: This document covers Postfix 1.x, there are several changes in Postfix 2.x which i will document in the future, but haven't found the time to test this setup on Postfix 2.x yet.
- MySQL (sql server): http://www.mysql.com/
- Courier-IMAP, POP3, SqWebMail, Maildrop (IMAP4/POP3 servers, webmail and mail processing/filtering tool, supporting maildirs): http://sourceforge.net/projects/courier/
- pam-mysql (pam plugin for storing auth data in mysql): http://sourceforge.net/projects/pam-mysql/
- sasl (client/server library for smtp auth): http://asg.web.cmu.edu/sasl/ - Note: I'm not covering sasl v2 yet (Be aware that only Postfix from Debian Woody / Stable is usable. Debian Sarge / Testing Postfix 1.1.11 is compiled against sasl2 libs).
- Amavis (wrapper script for virusscan): http://www.amavis.org/ or amavisd-new (grew out of the amavisd project) http://www.ijs.si/software/amavisd/
Packages which can be used on Debian:
postfix-mysql, postfix-tls
mysql-server
courier-imap, courier-pop, courier-authdaemon, courier-authmysql
libpam-mysql
libsasl7, libsasl-modules-plain
-- optionally courier-imap-ssl, courier-pop-ssl
-- optionally sqwebmail
-- optionally courier-maildrop, but the version in Debian has no MySQL support, needs recompile.
The Background Story
The reason for this setup was quite simple. I wanted a solution, that was as flexible and easy to support as possible. To keep this as short and clear as possible, i'll take this in different parts.
- the user should have an easy login, like their complete email-address.
This does not polute the passwd file with thousands of different aliases and gives you as the system administrator a good view on, what customer you are talking to. Besides a customer knows nearly allways his email-address, since he uses it all the time. The username is easily forgotten. Another thing is, that you allways know the answer, if a customer can't remember his/her username.
- the password should be stored in plain text, not encryptet.
There are two reasons why this should be done. However, it's your choice. You have the ability to store it encryptet in the database, if you like that better.
The first reason is, that you'll be able to use CRAM-MD5 encryption for the password challenge. For this you need the plaintext password on both sides, since this is a one way encryption method. (actually smtp-auth also requires plain passwords because of the same reason).
The customers i know personally (and that are many of them) can give me a call and get their password on the phone, if they should forget it or so ...
- the smtp server should be used as smtp relay for accounts located on it.
There are several methods to archieve that (pop-over-smtp, domain based relay, ip based relay and so on) without getting an open relay, but most of them require, that you know your customers location or requires him to authentificate on pop3 before being able to use smtp. I wanted to use the smtp-auth feature, which is supported by most clients and to use the same username and password as on the pop3/imap server. Makes it easier for the customer to remember things. Also i didn't want to store the username in two places. I did choose pam-mysql for that, because the sasl-mysql patch out there is quite buggy. I managed to apply it and compiled the sasl lib afterwards, but couldn't get it to work. Pam-mysql works nice and does exactly fit my needs. Also in mind, that i can use it for whatever i want afterwards (samba, shell-login .....)
- maildir is used for faster access to mails and a better structure, which mails are stored in. Also i want to use the courier pop3/imap daemons, which only support maildir.
Installation
Debian sources
If you are going to use the packages that i prepared and maybe also want to update them, whenever i put new packages in the repository, you can use these Debian apt sources:
deb ftp://debian.marlow.dk/ woody virus
deb-src ftp://debian.marlow.dk/ woody virus
That way all the packages i mention through the howto get apt-get'able.
McAfee uvscan
Originally Amavis was looking for the virusscanner during configuration. Since this is not necessary anymore, you can install it whenever you want. Of a old habbit i start to install it first anyway. I presonally use McAfee uvscan (which requires, that you'll buy a license for it), but you are free to choose whatever virusscanner you like and of course is supported of Amavis.
You need to install the libstdc++2.8 package, before you can get McAfee uvscan to work. If you can't find it for Debian, i've stored a copy of the original Potato package at http://debian.marlow.dk/dists/wo ... +2.8_2.90.29-2.deb.
After that you can start to download the evaluation version from McAfee. The evaluation version of the commandline scanner you'll find at http://www.networkassociates.com/us/downloads/evals/. Choose "English" and "Linux" there. Download the "McAfee VirusScan Command Line Scanner for Linux". When you have been through the registration process there, downloaded and installed it, we are ready to go. Besides: it chooses to install in /usr/local/uvscan, which is ok. Amavis will look for it at that place. One last step is left, since the virus-scanner engine in the tar-ball from McAfee is out of date (4.1.40). The newer version is found on their public ftp: ftp://ftp.mcafee.com/pub/antivirus/engine/4.x/. Currently we are talking engine 4.1.60 (elnx4160.zip), but look if there isn't a newer version there.
F-Prot - http://www.f-prot.com/
Another option for a virus-scanner is F-Prot. F-Prot is free for private use and there has been prepared a very nice installer for Debian, which supports auto updating. The package is called "f-prot-installer" and is currently only available in Debian Sarge (testing) and up. If you want to use this, basically the only thing beyond configuring amavisd/amavisd-new is to edit /etc/cron.d/f-prot-installer and enable the two lines, to get f-prot to update itself on a daily basis.
I do not use this antivirus scanner, but i've had positive reports from other people using it.
Amavis
amavisd-new (Installed from Debian packages) - http://www.ijs.si/software/amavisd/
file (upgrade this to the newest version, there have been security issues), bzip2, lha (at least rev. 1.14g), unarj, unzip, gzip, unrar, zoo, lzop
perl, libio-stringy-perl, mailtools, libmime-perl, libmailtools-perl, libmime-base64-perl, libcompress-zlib-perl
libconvert-uulib-perl, libconvert-tnef-perl, tnef, libarchive-tar-perl, libarchive-zip-perl, libtime-hires-perl, libunix-syslog-perl
libnet-perl, libnet-server-perl, amavisd-new (however, read my comments regarding the last 3 packages !)
Also you will need arc, which can be found here: http://debian.marlow.dk/dists/wo ... rc_5.21e-5_i386.deb
If you are a Debian user amavisd-new is probably the best solution, because the packages exist in testing and unstable today (The amavis-postfix in stable are unfortunately a older version of amavis and not really recent anymore. I used the amavisd-new package from unstable and recompiled it to work with 5.6.x, since i didn't want to upgrade to the perl packages from Sid yet. Also needed are the packages libnet-perl, which is not recent enough in stable and libnet-server-perl, which can't be found in stable. These packages i took from testing and recompiled for woody also.
You are welcome to use the packages, i recompiled for woody dependencies. They are found here:
http://debian.marlow.dk/dists/wo ... 0030616p3-1_all.deb
http://debian.marlow.dk/dists/wo ... perl_1.12-1_all.deb
http://debian.marlow.dk/dists/wo ... perl_0.84-3_all.deb
Configuring Amavis
The following changes i did to the /etc/amavis/amavisd.conf file:
@inet_acl = qw( 127/8 1.2.3.4/32 ); # 1.2.3.4 is your external ip .. because want maybe also accept mail from that interface, it's up to you.
$warnvirussender = 1; # I want to warn people, who have got virus.
$warnvirusrecip = 1; # I want to warn my users about virus send to them.
$warn_offsite = 1; # I want to warn senders/recipients, that are not located on my server
$mailfrom_notify_admin = 'virusalert@example.com'; #
$mailfrom_notify_recip = 'virusalert@example.com'; # Change these to the appropriate email-adresses, you wish to use as sender
$mailfrom_notify_spamadmin = 'spam.police@example.com'; # for spam and virus warnings
$hdrfrom_notify_sender = 'AMaViS (content filter) <postmaster@example.com>';
$virus_admin = 'virus-admin@example.com'; #
$spam_admin = 'spam-admin@example.com'; #
And make sure, that this section not is commented out. Evt. remove all unnecessary virusscanners from that section:
@av_scanners = (
['NAI McAfee AntiVirus (uvscan)', 'uvscan',
'--secure -rv --summary --noboot {}', [0], [13],
qr/(?x) Found (?:
\ the\ (.+)\ (?:virus|trojan) |
\ (?:virus|trojan)\ or\ variant\ ([^ ]+) |
:\ (.+)\ NOT\ a\ virus)/ ],
);
Start the amavisd daemon by either /etc/init.d/amavis start (on Debian, installed from packages) or as described in the INSTALL document of the amavis tarball. If you installed from the tarball, please make sure, that amavis get's started on reboot, an best before postfix starts, avoiding having a non functioning mail server.
When finishing the postfix installation you will also have to fix these in /etc/postfix/master.cf:
Find the following line:
smtp inet n - n - - smtpd
and change it to:
smtp inet n - n - - smtpd
-o content_filter=smtp-amavis:[127.0.0.1]:10024
After that add the following lines:
smtp-amavis unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o disable_dns_lookups=yes
127.0.0.1:10025 inet n - n - - smtpd
-o local_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 strict_rfc821_envelopes=yes
amavisd (Skip this part, if you allready did the Debian stuff)
If you not are using Debian or want to install the whole thing by compiling it yourself, then you should fetch the most recent version of amavisd from the Sourceforge project page (http://sf.net/projects/amavis/) and unpack that in a directory somewhere. You can also choose use amavisd-new (http://www.ijs.si/software/amavisd/) but then you should stick to the configuration from the amavisd-new section above.
However, before you go on and compile amavis, you need to install perl (Version 5.6.x is the recommended minimum), a couple of modules for perl and some decompression tools first. The following tools are needed on your system: file (upgrade this to the newest version, there have been security issues), bzip2, lha (at least rev. 1.14g), unarj, unzip, gzip, unrar, zoo
To start the installation of the needed perl modules from CPAN type the following on your shell:
perl -MCPAN -e shell
If you haven't configured the Perl CPAN installation before, you'll have to go through the initially setup and evt. install the following:
cpan> install CPAN
cpan> install LWP
After that we can start installing the needed packages:
cpan> install Archive::Tar
cpan> install Archive::Zip
cpan> install Compress::Zlib
cpan> install Convert::TNEF
cpan> install Convert::UUlib
cpan> install MIME::Base64
cpan> install MIME:arser
cpan> install Mail::Internet
cpan> install Net::Server
cpan> install Net::SMTP
cpan> install Digest::MD5
cpan> install IO::Stringy
cpan> install Time::HiRes
cpan> install Unix::Syslog
Some of these packages will need configuration, but the system will ask you for the data necessary and that's something you simply must through. It should be more or less self explaining. If you don't know the answers, simply go with the default. Mostly it's sufficient.
Preperations for installation
After all these packages are installed you need to add a user and group, which your amavis will run under. Please add a "amavis" user and group or whatever you decide, you want to use. Create also the directories /var/log/amavis and /var/amavis (which also should be user amavis homedir), chmod them to 750 and chown them to amavis.amavis.
Now we can compile Amavis. Change to the directory, where you extracted it and configure the source:
./configure --enable-postfix --with-logdir=/var/log/amavis \
--with-amavisuser=amavis
make
make install
Edit the /etc/amavis/amavisd.conf file. It does not look like the one described below, since amavisd in Debian packages seems to be somewhat newer than the latest official release. Here are the lines, that i changed:
# Notify admin/sender/recipient?
$warnadmin = "yes";
$warnsender = "yes";
$warnrecip = "yes";
# Notify off-site recipients?
$warn_offsite = "yes";
# Who reports are sent from
$mailfrom = 'hostmaster@domain.tld';
# Where to send virus reports
$mailto = 'your_email@domain.tld';
The master.cf entries look a bit different, than the Debian install:
smtp inet n n n - - smtpd
-o content_filter=smtp-amavis:
smtp-amavis unix - n n - 10 pipe user=amavis argv=/usr/sbin/amavis ${sender} ${recipient}
127.0.0.1:10025 inet n - n - - smtpd
-o local_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 strict_rfc821_envelopes=yes
Also asure, that you get amavis started (by calling the /usr/sbin/amavisd daemon) before you start postfix. It could be added to the /etc/init.d/postfix script, just before postfix starts up.
SpamAssassin
This configuration only covers the use of spamassassin together with amavisd-new. I haven't been using it together with amavisd. Amavisd-new more of less autodetects the presence of spamassassin and uses it. The packages in stable are a bit old, so i prepared the packages necessary and placed them here:
ftp://debian.marlow.dk/dists/sta ... ssin_2.60-1_all.deb
ftp://debian.marlow.dk/dists/sta ... amc_2.60-1_i386.deb
All other packages necessary (libgdbm3 libhtml-parser-perl libhtml-tagset-perl, maybe some others, but these will depend upon these packages) are taken from woody.
The configuration of spamassassin is done in /etc/amavis/amavisd.conf.
To make it simple, here are the lines, that i changed (mostly they are there, but commented out):
# @bypass_spam_checks_acl = qw( . ); # comment this line out to get spamassassin running
$final_spam_destiny = 0; # this should be 0 (discard) instead of -1 (reject)
# we don't want to notify spammers, that we discarded
# their spam, since most of them anyway fake the sender-adress
$warnspamsender = 0; # again, we don't want to send anything back
$sa_kill_level_deflt = 6.9; # Normally you don't need to change this, unless you want a lower/higher level
# It tells spamassassin, when to categorise a message as spam.
More is there actually not to it. There will be only send notifies to the email-adress specified in $spam_admin.
If you want to have the spamassassin headers in every mail, to better be able to track, why a message not was filtered, you will have to add change this line
@local_domains = qw ( .domain1.com .domain2.com ); # local domains, for which X-Spam-Status
# and X-Spam-Level should be added
# even if it's not considered spam.
$sa_tag_level_deflt = 0; # Add header at what point ?
This version of spamassassin does have Bayesian spam filters, but you need to make a configuration file for it (/etc/spamassassin/local.cf). This is done the easiest way by using http://www.yrex.com/spam/spamconfig.php.
More about training the Bayesian filters and optimising this will follow. Happy spam filtering.
Database
- "postix_alias" table:
Overview
+-------------+--------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+--------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| alias | varchar(128) | | | | | |
| destination | varchar(128) | | | | | |
+-------------+--------------+------------+------+-----+---------+----------------+
Comment
This table is only used on local delivery. So it wont work, if you deliver "virtual". Just have that in mind, when you configure your aliases. Also this is the only table, where can execute scripts directly.
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
alias The alias, you wish to redirect, could be postmaster, root or other aliases.
destination This field can hold several types of destinations. I can be one or more addresses (delimited by comma), a file for delivery to file, a "pipe" to a command for executing a script handling STDIN or an include, which has several addresses, one on each line.
Manual: aliases(5)
- "postfix_relocated" table:
Overview
+-------------+--------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+--------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| email | varchar(128) | | | | | |
| destination | varchar(128) | | | | | |
+-------------+--------------+------------+------+-----+---------+----------------+
Comment
This table is only used to tell senders, that the user, they tried to contact doesn't exist on the server anymore, but has moved to a new address. All this does is generating a mailer-daemon message, telling the sender the new address, where this recipient moved to.
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
email The originally email-address.
destination The email-address, where the user can be found now. Eventually you just put "unknown" here, if you don't want to refer to a new address or you don't know the users new address.
Manual: relocated(5)
- "postfix_transport" table:
Overview
+-------------+--------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+--------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| domain | varchar(128) | | | UNI | | |
| destination | varchar(128) | | | | | |
+-------------+--------------+------------+------+-----+---------+----------------+
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
domain The domain field contains the domainnames, of the domains you host.
destination This field is describing the way, postfix should deliver the mail. "local:" would be for local delivery, "virtual:" for delivery to the virtual accounts, we are going to use. You can use every transport type you want in this place. "maildrop:" for mails, who have to be filtered first (see description of maildrop, later in this document) or "uucp:" for delivery to UUCP. IMPORTANT: The hosts primary hostname has to be "local:" delivery !!
Manual: transport(5)
- "postfix_users" table:
Overview
+-------------+---------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+---------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| email | varchar(128) | | | UNI | | |
| clear | varchar(128) | | | | | |
| name | tinytext | | | | | |
| uid | int(11) | UNSIGNED | | | 1001 | | < replace with your vmail users uid
| gid | int(11) | UNSIGNED | | | 1001 | | < replace with your vmail users gid
| homedir | tinytext | | | | | |
| maildir | tinytext | | | | | |
| quota | tinytext | | | | | |
| access | enum('y','n') | | | | y | |
| postfix | enum('y','n') | | | | y | |
+-------------+---------------+------------+------+-----+---------+----------------+
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
email The users eMail-address and username
clear The cleartext password used for smtp-auth, pop3 and imap
name The users name. This is only for informational purpose and totally optionally. Courier can use it, but wont need it necessarily.
uid The uid (User ID) of the vmail-user, that we are going to create. This is the only unix-user, that is needed for virtual-delivery, since there still must be some kind of ownership on the stored mails.
You can also create your local unix-users in this table, if you want to give them the possibility to use CRAM-MD5 challenging and maybe give them another password, than the one used for local access. The fun thing about Courier is, that it will check both this and the local password, so that the unix-user will be able to authentificate with both passwords, however CRAM-MD5 challenging can not be used on allready encryptet passwords.
gid The gid (Group ID) of the vmail-user.
homedir This is the path, where the path where the homedir of the user resides. It's "/home/vmail" for our virtual users and should be the same allways for the virtual user, since postfix not looks at this field, it get's the homedir from the passwd file. For any local unix-user this is his/her homepath. If this field not does match the value in the passwd file, be aware, that maildrop will look for the .mailfilter file in the path specified here (in the database) and not in the value specified for the vmail unix user in the passwd file.
maildir This is the path, where the mails reside inside the homedir. Postfix-style is, that the mails reside in "Maildir/" on local unix-users. For our vmail-user this is a bit different, because all mails for all users reside in the same homedir. Personally i use the format "domain.tld/user/", some other prefer "domain.tld/user/Maildir/". This is totally up to you, to choose, what fits your needs best. There is one caveeat here: Remember the trailing slash or else postfix will deliver your mail to a mailspool instead of a maildir. Also be aware, there should not be any slash in front of the path. If you put a leading slash on this, this forces courier and postfix to use this path as the absolute path (ignoring the homedir field).
quota This is unused, since quota in postfix only works with mailspool delivery (not maildir, which is required for the use of courier). If you want to use quota with maildir and postfix, you'll have to look at maildrop (which is partly documented here) or the softquota/maildir++ patch for postfix at http://www.oav.net/~kiwi/postfix/.
Configuration for maildrop:
For maildrop this field definatly is a varchar or tinytext, containing the following values: S is used for the maximum size of all messages in the maildir and C is used for the amount of messages in the maildir. The value "5000000S,300C" then would mean a quota of 5,000,000 bytes or 300 messages, whichever comes first. It's ok just to use one of them as in "300C" for only quota on the amount of messages. If this field is left empty, quota is disabled.
access With this field you can enable or disable pop3, imap and smtp-auth access for an account.
postfix This field can be used to disable a certain account in postfix/maildrop, thereby forcing these not to accept mail for that account anymore.
- "postfix_virtual" table:
Overview
+-------------+--------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+--------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| email | varchar(128) | | | | | |
| destination | varchar(128) | | | | | |
+-------------+--------------+------------+------+-----+---------+----------------+
Comment - IMPORTANT !!
There are some caveeats in this table and the way, i've chosen to setup my postfix. If you want to use catchall-address (addresses, that collect all mails not going to other recipients), you'll have to make a virtual alias in the postfix_virtual table for every account created in the users-table. If an user isn't found in the postfix_virtual table, but a catchall-address is found, mails will be delivered to the catchall-address instead. By creating a row containing the user (some@domain.tld) in the email- and destination-fields, this doesn't happen. Postfix then also checks the users table and delivers the mail correctly.
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
email The email-address field. Here you can specify aliases of addresses in the format user@domain.tld, create a catchall-address, create domain-canonicals or distributers.
The formats are accepted:
"domain.tld" - destination just has to contain anything. This is used for domains that are hosted without actually having an account. If you have an entry in the transport-table allready, you should not create this type, but in every other case it's needed to tell postfix, that this domain is hosted. This type has top priority for postfix. It'll allways be the first thing for a domain, that postfix looks for.
"user@domain.tld" - an email-alias or entry as mentioned in the comment. It's also the second priority.
"@domain.tld" - a catchall-address. This takes all mail not yet delivered and sends it all to one recipient. Read the comment earlier in this document carefully, if you plan to use this. This thing has third priority.
The priorities are a nice thing about postfix, meaning, that you don't have to care about the order you insert your aliases in the database. Postfix handles this totally by itself and doesn't care about where in the database your aliases are and what order they are in.
One additional nice feature is having "@domain.tld" in email and "@other-domain.tld" in destination. This is normally used in the canonical table, but can also be put here, which is the reason, why i left the canonical table out. So if you want to have the same accounts on two domains you can do it this way.
destination The destination address for the alias. This could be a virtual user (user@domain.tld), a local unix-users or a remote email-address. You can also specify more than one recipient delimited by comma.
Manual: virtual(5)
- "postfix_access" table:
Overview
+-------------+--------------+------------+------+-----+---------+----------------+
| Field | Type | Attributes | Null | Key | Default | Extra |
+-------------+--------------+------------+------+-----+---------+----------------+
| id | int(11) | UNSIGNED | | PRI | | auto_increment |
| source | varchar(128) | | | | | |
| access | varchar(128) | | | | | |
| type | enum(...) | | | |recipient| |
+-------------+--------------+------------+------+-----+---------+----------------+
Description id This is not necessary, but I also use the id field as an unique identifier in some other places, so it's up to you, if you want to use it.
source If type is set as follows, this is what happens:
recipient
- this could be domain.top or user@domain.top. Depending on your choice it allows discards either all mail that should go to "domain.top" or overrides other filters to allow mail from that domain. Specifying and email-address does the same, just for a single address.
sender
- the same as recipient, just that this goes for sender-addresses.
client
- domain.top will whitelist or blacklist all mails originating from any host, which has this as it's domain part ..
access This field specifies wether this is a whitelist or a blacklist entry. The values here can be "OK", "REJECT" or something like "550 Too much spam in this world.", which then would result in a fail with 550 and the info "Too much spam in this world.".
type The values possible here are "recipient", "sender" or "client". Depending on the value this goes for that kind of filter.
MySQL Dump of the tables
CREATE TABLE postfix_alias (
id int(11) unsigned NOT NULL auto_increment,
alias varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) TYPE=MyISAM;
CREATE TABLE postfix_relocated (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) TYPE=MyISAM;
CREATE TABLE postfix_transport (
id int(11) unsigned NOT NULL auto_increment,
domain varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY domain (domain)
) TYPE=MyISAM;
CREATE TABLE postfix_users (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
clear varchar(128) NOT NULL default '',
name tinytext NOT NULL,
uid int(11) unsigned NOT NULL default '1011',
gid int(11) unsigned NOT NULL default '1011',
homedir tinytext NOT NULL,
maildir tinytext NOT NULL,
quota tinytext NOT NULL,
access enum('Y','N') NOT NULL default 'Y',
postfix enum('Y','N') NOT NULL default 'Y',
PRIMARY KEY (id),
UNIQUE KEY email (email)
) TYPE=MyISAM;
CREATE TABLE postfix_virtual (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) TYPE=MyISAM;
CREATE TABLE postfix_access (
id int(10) unsigned NOT NULL auto_increment,
source varchar(128) NOT NULL default '',
access varchar(128) NOT NULL default '',
type enum('recipient','sender','client') NOT NULL default 'recipient',
PRIMARY KEY (id)
) TYPE=MyISAM
Configuration
Linux Users/Files
Create a unix-user named vmail or whatever you want and change the configuration accordingly to that. Maildirs are created automatically by Postfix, when the first mail to an account arrive (if you've set the correct rights to the vmail-homedir). If you however use maildrop, then you'll be forced to create the maildirs manually with the maildirmake command, since maildrop and all other Courier utilities don't create maildirs automatically.
For Virus-scan add also a user named amavis, which is the user Amavis will be running under.
Postfix
Locate the postfix configuration files. These should reside in /etc/postfix on most Linux distributions (OpenBSD uses this also) or on FreeBSD you probably can locate them in /usr/local/etc/postfix
# master.cf
We'll have to change the following deliveries (or create them, if they don't exist):
smtp inet n - n - - smtpd
virtual unix - n n - - virtual
# main.cf
Here we got several changes to do. Please add the following lines (evt. changing the paths to suit your needs):
home_mailbox = Maildir/
- this tells postfix to deliver Maildir-style.
mydestination = $myhostname, $transport_maps
- this tells postfix, to accept mails to $myhostname (should be the hostname of your host) and mails send to any domain in the transport-table. Of course postfix also will look in the virtual-table, if that exists. Eventually you should specify $mydomain here also, but i do it in the transport-table instead. Remember, that default delivery is local, unless anything else is specified in the transport table.
alias_maps = mysql:/etc/postfix/mysql-aliases.cf
relocated_maps = mysql:/etc/postfix/mysql-relocated.cf
transport_maps = mysql:/etc/postfix/mysql-transport.cf
virtual_maps = mysql:/etc/postfix/mysql-virtual.cf
- here we tell postfix, where to find the tables needed for this. Every of the files mentioned has information about, how to get the needed data out of the sql database.
local_recipient_maps = $alias_maps $virtual_mailbox_maps unix:passwd.byname
- these are the methods, how postfix will deliver to local recipients
virtual_mailbox_base = /home/vmail
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-maps.cf
virtual_uid_maps = mysql:/etc/postfix/mysql-virtual-uid.cf
virtual_gid_maps = mysql:/etc/postfix/mysql-virtual-gid.cf
- and finally the information about the virtual users. As you can see, the homedir is hardcoded here, where it is stored in the database for use by Courier.
broken_sasl_auth_clients = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
- these are for activation of sasl (smtp-auth)
maps_rbl_domains = relays.ordb.org,
dev.null.dk,
opm.blitzed.org,
sbl.spamhaus.org
- if you want to check for spammers, this is a moderate choice of rbl-lists to check. However it's you choice, what to use and what not
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated,
check_recipient_access mysql:/etc/postfix/mysql-recipient.cf,
reject_maps_rbl,
check_relay_domains,
permit
- the permit_mynetworks allows your networks access no matter what, perm_sasl_authenticated is for smtp authentification, check_recipient_access checks the postfix_access list for recipient filters, reject_maps_rbl rejects all mail from known spamsites and open relays defined by the maps_rbl_domains and the last permit allows everyone else to deliver to your site if the domain is located at your site.
smtpd_sender_restrictions = check_sender_access mysql:/etc/postfix/mysql-sender.cf
smtpd_client_restrictions = check_client_access mysql:/etc/postfix/mysql-client.cf
- these two are for checking the sender and the client rules in postfix_access.
Next the defintion of the mysql-queries. Note, that multiple sql-servers can be defined. This gives you the possibility for clustering. Also be careful: "127.0.0.1" is used intentionally instead of "localhost". Postfix tries to connect via socket, if you use "localhost" and that does somehow not work. By using "127.0.0.1" postfix get forced to connect by network via localhost.
Remember also to disable the "skip-networking" option in your MySQL configuration (on Debian /etc/mysql/my.cnf). It could give you trouble, if that is enabled.
# mysql-aliases.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_alias
select_field = destination
where_field = alias
hosts = 127.0.0.1
# mysql-relocated.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_relocated
select_field = destination
where_field = email
hosts = 127.0.0.1
# mysql-transport.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_transport
select_field = destination
where_field = domain
hosts = 127.0.0.1
# mysql-virtual.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_virtual
select_field = destination
where_field = email
hosts = 127.0.0.1
# mysql-recipient.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'recipient'
hosts = 127.0.0.1
# mysql-sender.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'sender'
hosts = 127.0.0.1
# mysql-client.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'client'
hosts = 127.0.0.1
Now the definitions for the virtual users, providing postfix with maildir-directory, uid and gid to deliver to.
# mysql-virtual-maps.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_users
select_field = maildir
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
# mysql-virtual-uid.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_users
select_field = uid
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
mysql-virtual-gid.cf
user = mysql-postfix-user
password = mysql-postfix-pass
dbname = postfix
table = postfix_users
select_field = gid
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
Courier
Couriers configuration resides under /etc/courier on Debian. We'll have to edit a few of the configuration files here. I'll only mention lines to be changed. Everything else should stay in default or be changed to suit your needs # imapd
AUTHMODULES="authdaemon"
- we want all authentification handled by the authdaemon
IMAP_CAPABILITY="IMAP4rev1 CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT AUTH=CRAM-MD5 AUTH=CRAM-SHA1 IDLE"
- this tells the IMAP daemon about the stuff it can handle. Change it to suit your needs, however note the AUTH= parameters, which enable CRAM-MD5 and CRAM-SHA1 authentification.
IMAPDSTART=YES
- this has to be yes, if you want the IMAP daemon to start.
# pop3d
AUTHMODULES="authdaemon"
- also here we want the authdaemon to handle the authentification.
POP3AUTH="LOGIN CRAM-MD5 CRAM-SHA1"
- and also here we want to provide CRAM-MD5 and CRAM-SHA1 challenging methods.
POP3DSTART=YES
- this has to be yes, if you want the POP3 daemon to start.
# authdaemonrc
authmodulelist="authmysql authpam"
- we specify authmysql for mysql authenfication and if you want to authentificate local users also, you can, like here, specify authpam or authshadow also. All types will be checked in that order you provide them.
# authmysqlrc
MYSQL_SERVER localhost
MYSQL_USERNAME mysql-postfix-user
MYSQL_PASSWORD mysql-postfix-pass
MYSQL_PORT 0
MYSQL_OPT 0
MYSQL_DATABASE postfix
MYSQL_USER_TABLE postfix_users
MYSQL_LOGIN_FIELD email
#MYSQL_CRYPT_PWFIELD crypt ## remember to uncomment this field
MYSQL_CLEAR_PWFIELD clear
MYSQL_UID_FIELD uid
MYSQL_GID_FIELD gid
MYSQL_HOME_FIELD homedir
MYSQL_MAILDIR_FIELD maildir
MYSQL_WHERE_CLAUSE access='y'
- here we specify the access to the database for both pop3 and imap, actually even sqWebMail, if you want to use that. sqWebMail is a Webmail-Solution, which also is in the Courier Project. It works quite well and is pretty fast, since it accesses the maildirs directly and is written in C. It uses the same authdaemon and can easily be customized, since it uses templates.
Here are some other options, which might be of your interest:
MYSQL_SOCKET /var/mysql/mysql.sock
- this gives you the possibility to use a local socket instead of an ip connnection.
MYSQL_CRYPT_PWFIELD crypt
- if you rather want to store your passwords encryptet, use this. Remember to change the database and be aware of that you cannot use SMTP-AUTH or CRAM-MD5 encryption with allready encrypted passwords. Also keep in mind, that you have to use the crypt() function and not the password() function in mysql to encrypt passwords.
MYSQL_NAME_FIELD name
- as mentioned before this is only of informational purpose and optional. Use it, if you want.
MYSQL_QUOTA_FIELD quota
- This is not supported by postfix. Either the softquota/maildir patch for postfix or maildrop is needed. See discription of the mySQL table for more info.
SASL library
yep .... you saw right, this baby also needs a bit configuration
The configuration file needed is /usr/local/lib/sasl/smtpd.conf and contains the following: On Debian this file is located at /usr/lib/sasl/smtpd.conf for all postfix before version 1.1.11. For all postfix from version 1.1.11 and on it got moved to /etc/postfix/sasl/smtpd.conf .
pwcheck_method: PAM
Remember: If you use crypt passwords in the database, you'll have to store smtp-auth passwords sasl.db or likewise. pam-mysql/smtp-auth is not possible with crypted passwords.
That should cover it.
PAM-MySQL
Most Linux Distributions have this file at /etc/pam.d/smtp, however you can also use other services with pam-mysql authentification. This is only the example, how to do it for postfix with smtp-auth.
# smtp
auth optional pam_mysql.so host=127.0.0.1 db=postfix user=mysql-postfix-user \
passwd=mysql-postfix-pass table=postfix_users usercolumn=email passwdcolumn=clear crypt=n where=access='y'
account required pam_mysql.so host=127.0.0.1 db=postfix user=mysql-postfix-user \
passwd=mysql-postfix-pass table=postfix_users usercolumn=email passwdcolumn=clear crypt=n where=access='y'
As you can see, also here you'll be able to change to having the passwords encryptet. I haven't tried it, but since smtp-auth also sends encryptet passwords, i'm not sure, it'll work with encryptet passwords in this case.
Maildrop
If you're going to install maildrop filtering, add this line to /etc/postfix/master.cf:
maildrop unix - n n - - pipe
flags=R user=vmail argv=/usr/bin/maildrop -d ${recipient}
Also, you'll have to recompile the courier-maildrop package, since mySQL support not is compiled in the standard Debian packages. You can however very easyly check, if your maildrop has mySQL support. Start configuring the mySQL settings of maildrop.
This is usually /etc/maildrop/maildropmysql.config :
hostname localhost
port 3306
database postfix
dbuser mysql-postfix-user
dbpw mysql-postfix-pass
dbtable postfix_users
default_uidnumber 1001
default_gidnumber 1001
uid_field email
uidnumber_field uid
gidnumber_field gid
maildir_field maildir
homedirectory_field homedir
quota_field quota
# unused for now, but needs to be a valid field.
mailstatus_field postfix
where_clause "where postfix = 'y'"
After you configured that, you run "maildrop -v". It should state "Virtual user database via MySQL extension enabled." in the output. If not, you've got a maildrop without MySQL support and need to recompile that.
After installing maildrop make a symlink from /usr/sbin/sendmail to /usr/bin/sendmail. Maildrop needs it.
There are at least 2 ways of configuring maildrop in a virtual user environment. Either by doing it the way i specify here or by using absolute paths in the maildir field and specifying different homedirs for every user. How you do it is up to you.
Since maildrop is called as the vmail user, it will look in /home/vmail for the configuration (.mailfilter). The file you put there is quite simple:
LOGNAME=tolower($LOGNAME)
include "/home/vmail/.mailfilters/$LOGNAME"
This .mailfilter will now include the filter-file for every individual user (/home/vmail/.mailfilters/user@domain.top) on mail delivery and process the filter rules included there.
To get postfix to deliver using maildrop you just need to change the transport for the domain in the transport table to "maildrop:"
Important !!
You will have to add a filterfile for every user on a domain, that is delivering by maildrop. Mail can't be delivered, if the filterfile not is present.
Here is the minimum filterfile:
FROM='user@domain.top'
to "/home/vmail/domain.top/user/."
Another thing, you shouldn't forget, is that you've got to create the maildirs yourself, if you use maildrop. Maildrop will NOT create maildirs, if they don't exist. It will just report a temporary failure (means, mail don't get lost, but can't be delivered).
I've prepared 2 PHP shell scripts (maildrop-import.php and maildrop-gen.php) which make it possible to import the filterfile generated from sqWebmail to database and also create a filterfile from this database again. They only have a very small subset of the commands, that maildrop understands, but they should be quite usefull for some of you out there. The SQL skeleton looks like this:
CREATE TABLE maildrop_rules (
id int(11) NOT NULL auto_increment,
email tinytext NOT NULL,
no int(11) NOT NULL default '0',
op tinytext NOT NULL,
m_header tinytext NOT NULL,
m_value tinytext NOT NULL,
m_folder tinytext NOT NULL,
m_from tinytext NOT NULL,
options tinytext NOT NULL,
name tinytext NOT NULL,
active enum('y','n') NOT NULL default 'y',
PRIMARY KEY (id)
) TYPE=MyISAM
With these scripts, it should be possible to build a web frontend to edit the filters and then write them to disk (running maildrop-gen.php by cron or something). These scripts are only ment to give you an idea on how this can be resolved. I will not do ANY support on them. If you can't get them to work, then let them be.
Here is some sample data of the stuff, that the scripts handle:
INSERT INTO maildrop_rules (email, no, op, m_header, m_value, m_folder, m_from, options, name) VALUES ('martin@list-petersen.dk', 1, 'contains', 'From', 'daemon@ispworks.org', '.Daemons.ISPWorks', '', 'PlainString', 'ISPWorks Monitor Daemon');
INSERT INTO maildrop_rules (email, no, op, m_header, m_value, m_folder, m_from, options, name) VALUES ('martin@list-petersen.dk', 2, 'startswith', 'Subject', 'TuxBox ISPWorks Download', '.Develop.tuxbox_ispworks.download', '', '', 'TuxBox Download');
INSERT INTO maildrop_rules (email, no, op, m_header, m_value, m_folder, m_from, options, name) VALUES ('martin@list-petersen.dk', 3, 'hasrecipient', '', 'banner@ispworks.org', '.Emne.Banner', '', '', 'Banner Stats');
INSERT INTO maildrop_rules (email, no, op, m_header, m_value, m_folder, m_from, options, name) VALUES ('martin@list-petersen.dk', 4, 'islargerthan', '', '0', '!87654321@sms.ispworks.org', '', 'PlainString Continue', 'sms-notify');
Try it out and check, how it looks like. Remember to change the address in the email-field to a valid account on your system. The script will get some data from the postfix_users database first and then parse the filterdata.
One of the things, that is missing here is a description on how to use maildrop for quota (since it supports it for maildir). I've not tested that yet, but will do so soon and then update the howto.
sqWebmail
sqWebmail works out of the box, as soon as the courier-authdamon is configured and running. No big deal there. However, maybe you want to use some of the extra features this tool offers, like letting your users edit their maildrop filters.
This can be archieved by putting a file named "maildirfilterconfig" in the users maildir (would be /home/vmail/domain.top/user/). This file should contain the following:
MAILDIRFILTER=/home/vmail/.mailfilters/user@domain.top
MAILDIR=/home/vmail/domain.top/user
sqWebmail will, after the file is placed, offer two new menuitems to that user: "Edit Mail Filters" and "Edit Autoreplies".
History
0.31 - added new spamhaus rbl sources, added new spamassassin (2.60) to repository.
0.30 - remove spamhaus rbl sources, since they seem to gone out of order.
0.29 - added recipient, sender and client white/blacklists. Updated spamassassin.
0.28 - fixed a minor mistake in the spamassassin part.
0.27 - added Debian sources and F-Prot section. Updated amavisd-new section.
0.26 - added SpamAssassin section.
0.25 - fixed a minor bug in the maildrop-gen.php script and added the activate field to the maildrop_rules table.
0.24 - added some sample data for the maildrop scripts.
0.23 - added maildrop sql scripts.
0.22 - fixed some sasl stuff and changed some dead urls.
0.21 - added option for disabling pop3,imap,smtp-auth access for accounts.
0.20 - changed some stuff regarding amavisd-new/amavis. Added some links.
0.19 - added some maildrop configuration stuff
0.18 - added link to ISPWorks, since it's released now
0.17 - changes to the database structure due to soon release of admin system and cleanup in the text.
0.16 - fix on courier mysql configuration
0.15 - update of Amavis installation from Sources
0.14 - Minor correction
0.13 - Updated the description of the quota field in the database (for maildrop)
0.12 - Continued documenting manual (non Debian packaged) amavis installation. Not finished yet.
0.11 - Brought uvscan and amavis installation up to speed.
0.10 - Updated the configuration of pam-mysql, mysql-tables and rbl info. Added the documentation of my maildrop and sqWebmail setup.
0.09 - Updated information regarding quota
0.08 - Updated RBL part to my recent rbl's
0.07 - Changed some words in the document, to avoid misunderstanding of catchall and the maildrop application.
0.06 - Due to some changes in the official Debian postfix package, the smtpd.conf for sasl authentification has moved.
0.01 to 0.05 - these where the initial tasks for creation and bugfixing of this howto. |
|