Virtual Users and Domains with Courier-IMAP and MySQL
From postfix
Contents |
Introduction
This document is written for Postfix 2.0 and higher.
This document describes how to setup Virtual Domains (Aliases and Mailboxes) with Postfix, Courier-IMAP (or dovecot imap) and MySQL. I have found that this is the easiest combination that allows you to serve Virtual Domains, and Users. With this it's also very easy to implement webmail systems like SquirrelMail.
NOTE: One thing that you have to keep in mind is that Courier-IMAP only supports the Maildir format.
About the used software:
Postfix attempts to be fast, easy to administer, and secure, while at the same time being sendmail compatible enough to not upset existing users. Thus, the outside has a sendmail-ish flavor, but the inside is completely different.
Courier-IMAP is a server that provides IMAP access to Maildirs. This IMAP server does NOT handle traditional mailbox files (/var/spool/mail, and derivatives), it was written for the specific purpose of providing IMAP access to Maildirs.
The MySQL database server is the world's most popular open source database. Its architecture makes it extremely fast and easy to customize. Extensive reuse of code within the software and a minimalistic approach to producing functionally-rich features has resulted in a database management system unmatched in speed, compactness, stability and ease of deployment. The unique separation of the core server from the table handler makes it possible to run with strict transaction control or with ultra-fast transactionless disk access, whichever is most appropriate for the situation.
SASL is the Simple Authentication and Security Layer, a method for adding authentication support to connection-based protocols. To use SASL, a protocol includes a command for identifying and authenticating a user to a server and for optionally negotiating protection of subsequent protocol interactions. If its use is negotiated, a security layer is inserted between the protocol and the connection.
Postfix VDA enables quota support for Postfix.
Dovecot [1] Is an alternative IMAP server, known to perform a lot better than courier, especially with clients like thunderbird and mail.app. It is also slightly easier to configure, and works well with the virtual users setup.
If you are planning to use this howto as a basis for Postfix Admin, please be aware that there is some differences in the tables.
Please read the TABLE_CHANGES.TXT
Disclaimer
This document assumes that you have some knowledge on Postfix, Courier-IMAP, MySQL and SASL. At least enough to get everything installed. Installing the software is outside the scope of this document.
MySQL Install
Installation of MySQL is outside the scope of this document. I'm using an out of the box MySQL install on FreeBSD.
Since a long time, in Slackware you should do this (as root):
% su mysql && mysql_install_db && exit % sh /etc/rc.d/rc.mysqld start \ && mysql_secure_installation && mysqld_safe --user=mysql& \ && mysqladmin -u root password 'your password'
MySQL Setup
Create the database
% mysqladmin -u root --password='<your password>' create postfix
These columns are used to make your life easier together with Postfix Admin:
- created
- modified
- active
The "active" column is not used at the moment.
Create the Alias table
# # Table structure for table alias # USE postfix; CREATE TABLE `alias` ( `address` varchar(255) NOT NULL default '', `goto` text NOT NULL, `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (address) ) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Aliases';
Postfix: is using the "address" and "goto" column. Courier: is not using this table.
NOTE: This table can be used for virtual .forward files. This table is nothing more than /etc/aliases that you will find on any *nix OS. Multiple destination email addresses need to be separated by a "," (comma).
Create the Domain table
# # Table structure for table domain # USE postfix; CREATE TABLE `domain` ( `domain` varchar(255) NOT NULL default '', `description` varchar(255) NOT NULL default '', `aliases` int(10) NOT NULL default '0', `mailboxes` int(10) NOT NULL default '0', `maxquota` int(10) NOT NULL default '0', `transport` varchar(255) default NULL, `backupmx` tinyint(1) NOT NULL default '0', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (domain) ) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Domains';
Postfix: is using the "domain" and "description" column.
Courier: is not using this table.
Create the Mailbox table
# # Table structure for table mailbox # USE postfix; CREATE TABLE `mailbox` ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `name` varchar(255) NOT NULL default '', `maildir` varchar(255) NOT NULL default '', `quota` int(10) NOT NULL default '0', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`) ) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Mailboxes';
Postfix: is using the "username" and "maildir" column. Courier: is using the "username, "password", "name" and "maildir" column.
Populate the tables
USE postfix;
INSERT INTO domain (domain,description) VALUES ('domain.tld','Test Domain');
INSERT INTO alias (address,goto) VALUES ('alias@domain.tld', 'user@domain.tld');
INSERT INTO mailbox (username,password,name,maildir) VALUES ('user@domain.tld','$1$caea3837$gPafod/Do/8Jj5M9HehhM.','Mailbox User','user@domain.tld/');
The password (MD5 encrypted) is "secret" ($1$caea3837$gPafod/Do/8Jj5M9HehhM.)
This is a "standard" MD5 encrypted password out of /etc/passwd.
The first INSERT is to let Postfix know that this domain is a virtual domain and should be handled by Postfix. It's also possible to have everything in one table but I think this is nicer.
The second INSERT is a virtual alias pointing to the third INSERT.
The third INSERT is an actual Virtual Mailbox, as you can see I'm using MD5 password for backwards compatibility with local defined mail accounts. If you are using MD5 passwords, make sure you don't use the built in MySQL routine to generate MD5 passwords. This is not compatible with Courier-IMAP. If you want you can also use clear text or encrypted passwords.
To make sure that the new MySQL users are working, do the following from the command line.
% mysqladmin -u root --password='sua_senha, your password' reload
Postfix Install
Build and install Postfix 2.x, or the latest snapshot. Make sure that you at least build it with MySQL & Postfix VDA (quota). Apply patch like this:
% zcat postfix-x.x.x-vda.patch.gz | patch -p0
I built everything in FreeBSD and the default location is /usr/local/etc/postfix. Your configuration might be different.
RedHat 9 (including SASL):
% make makefiles 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH -I/usr/include/sasl' \ 'AUXLIBS=-L/usr/lib/mysql -lmysqlclient -lz -lm -L/usr/lib -lsasl' % make && make install;
Slackware 10 (need cyrus-sasl-mysql from LinuxPackages): (read Note below first)
% make makefiles 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH -I/usr/include/sasl' \ 'AUXLIBS=-L/usr/lib/mysql -lmysqlclient -lz -lm -L/usr/lib -lsasl2' % make && make install;
Note: Starting with Postfix's snapshot 20051220 (and so if you are compiling the latest version), you should change the above command to:
% make makefiles 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_CYRUS_SASL -DUSE_SASL_AUTH -I/usr/include/sasl' \ 'AUXLIBS=-L/usr/lib/mysql -lmysqlclient -lz -lm -L/usr/lib -lsasl2'
The error message in your postfix logs for not doing so is: unsupported SASL server implementation: cyrus
After that you have to create a directory to have all your virtual users mail dropped in, this directory needs to be owned by Postfix.
% mkdir /usr/local/virtual % chown -R postfix:postfix /usr/local/virtual % chmod -R 771 /usr/local/virtual
Postfix Setup
main.cf
The example below is the part that goes into your main.cf file of Postfix. The path to the mysql files might be different on your setup. The same might be for uid_maps, gid_maps and minimum_uid values. These values should *NOT* be the ones from the postfix user and group. Create a restricted user/group for this purpose.
virtual_alias_maps = mysql:/usr/local/etc/postfix/mysql_virtual_alias_maps.cf virtual_gid_maps = static:1001 virtual_mailbox_base = /usr/local/virtual virtual_mailbox_domains = mysql:/usr/local/etc/postfix/mysql_virtual_domains_maps.cf virtual_mailbox_limit = 51200000 virtual_mailbox_maps = mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_maps.cf virtual_minimum_uid = 1001 virtual_transport = virtual virtual_uid_maps = static:1001 # Additional for quota support virtual_create_maildirsize = yes virtual_mailbox_extended = yes virtual_mailbox_limit_maps = mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_limit_maps.cf virtual_mailbox_limit_override = yes virtual_maildir_limit_message = Sorry, the user's maildir has overdrawn his diskspace quota, please try again later. virtual_overquota_bounce = yes
If you want to use MySQL also to store your Backup MX domains add this as well
relay_domains = mysql:/usr/local/etc/postfix/mysql_relay_domains_maps.cf
Performance and reliability under high load will be much improved if you use the Postfix proxymap service with your MySQL interface. This allows MySQL query connections to be shared among Postfix smtpd processes; without it, you will need much higher-end database hardware as Postfix will need to spawn a number of SQL connections for every smtpd or cleanup process. This problem typically only shows up under high load, just when you least want to see it.
To access MySQL via proxymap, change the MySQL maps lines above to read:
virtual_alias_maps = proxy:mysql:/usr/local/etc/postfix/mysql_virtual_alias_maps.cf virtual_mailbox_domains = proxy:mysql:/usr/local/etc/postfix/mysql_virtual_domains_maps.cf virtual_mailbox_maps = proxy:mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_maps.cf
and
relay_domains = proxy:mysql:/usr/local/etc/postfix/mysql_relay_domains_maps.cf
To proxy your virtual_mailbox_limit_maps queries, you must add the map to the proxy_read_maps variable, as that map gets added via the VDA quota patch and is not included in the list of maps which Postfix will automatically allow to be proxied:
virtual_mailbox_limit_maps = proxy:mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_limit_maps.cf 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
master.cf
If you plan to run your postfix chrooted, be careful not to run virtual chrooted.
If virtual is running chrooted your mysql_*.cf will not be found by postfix.
Example for such an error:
postfix/virtual[8431]: fatal: open /etc/postfix/mysql_virtual_mailbox_maps.cf: No such file or directory
NOTE: for SuSE Systems have a look at #SuSE_Linux_note
# ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== smtp inet n - y - - smtpd [...] virtual unix - n n - - virtual [...]
mysql_virtual_alias_maps.cf
You will need to put this into a text file for postfix to pickup.
user = postfix password = postfix hosts = localhost dbname = postfix table = alias select_field = goto where_field = address #Syntax with postfix 2.2.x: user = postfix password = postfix hosts = localhost dbname = postfix query = SELECT goto FROM alias WHERE address='%s' AND active = 1
mysql_virtual_domains_maps.cf
You will need to put this into a text file for postfix to pickup.
user = postfix password = postfix hosts = localhost dbname = postfix table = domain select_field = domain where_field = domain #additional_conditions = and backupmx = '0' and active = '1' #Syntax with postfix 2.2.x: user = postfix password = postfix hosts = localhost dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' #optional query to use when relaying for backup MX #query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'
mysql_virtual_mailbox_maps.cf
You will need to put this into a text file for postfix to pickup.
user = postfix password = postfix hosts = localhost dbname = postfix table = mailbox select_field = maildir where_field = username #additional_conditions = and active = '1' #Syntax with postfix 2.2.x: user = postfix password = postfix hosts = localhost dbname = postfix query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1
NOTE: In the 2.2.x syntax above, postfix will use whatever it receives as the "maildir" argument to create the users maildir in the base directory you specified in your main.cf (i.e. /usr/local/virtual). For example, if you create user@domain.tld, his maildir will be /usr/local/virtual/user@domain.tld. Then when you create user@otherdomain.tld, his maildir will be /usr/local/virtual/user@otherdomain.tld... in other words, all user mailboxes will be in the same main directory, and not segregated into individual domain folders. If you'd like to create folders for each of your domains for the user boxes to be created under, you can modify the the 2.2.x syntax to be:
query = SELECT CONCAT(domain,'/',maildir) FROM mailbox WHERE username='%s' AND active = 1
This will create domain folders for each domain you host, and your users mailboxes will be created under those folders.
mysql_virtual_mailbox_limit_maps.cf
You will need to put this into a text file for postfix to pickup.
user = postfix password = postfix hosts = localhost dbname = postfix table = mailbox select_field = quota where_field = username #additional_conditions = and active = '1' #Syntax with postfix 2.2.x: user = postfix password = postfix hosts = localhost dbname = postfix query = SELECT quota FROM mailbox WHERE username='%s'
mysql_relay_domains_maps.cf
You will need to put this into a text file for postfix to pickup.
user = postfix password = postfix hosts = localhost dbname = postfix table = domain select_field = domain where_field = domain additional_conditions = and backupmx = '1' #Syntax with postfix 2.2.x: user = postfix password = postfix hosts = localhost dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'
For security you should do
chmod 640 mysql_* chgrp postfix mysql_*
User question/comment: Read last line here: http://www.postfix.org/faq.html#virtual_command. On RedHat based systems chmoding to 640 on mysql_* files might cause virtual errors like:
postfix/virtual[22114]: fatal: open /etc/postfix/mysql_virtual_mailbox_maps.cf: Permission denied
In this case try setting correct group for postfix.
MySQL note
Tip for chroot/jailed enviroment (default in Debian, Ubuntu and others).
Using "localhost" means that a local socket will be used to connect to mysql, which cause problems in a chroot'd environment. You must either create a link to the socket in the chroot environment or use hostname 127.0.0.1 to connect using TCP/IP instead. Postfix runs in a jailed enviroment in the /var/spool/postfix, and that's why it cannot connect to mysql.
- If you have skip-networking in your my.cnf that means mysql accept connections thru socket only. You need to create a link to the mysql.sock in the postfix jail. Just run these commands:
mkdir -p /var/spool/postfix/var/run/mysqld chown mysql /var/spool/postfix/var/run/mysqld ln /var/run/mysqld/mysqld.sock /var/spool/postfix/var/run/mysqld/mysqld.sock
For Debian users: insert the last line into /etc/mysql/debian-start, so that the link is automatically updated, when the mysql server is restarted.
- If your mysql listen on the loopback interface (localhost), the way is to change all the hosts in /etc/postfix/mysql_*_maps.cf files from localhost to 127.0.0.1. Quote from mysql_table(5):
NOTE: if you specify localhost as a hostname (even if you prefix it with
inet:), MySQL will connect to the default UNIX domain socket. In order
to instruct MySQL to connect to localhost over TCP you have to specify
hosts = 127.0.0.1
SuSE Linux note
Tip for SuSE Users and SuSEconfig (done on SuSE 9.1 Pro)
For having SuSEconfig work with "master.cf" when running postfix chroot/jailed and not want to have "virtual" chroot/jailed
apply the following patch to /sbin/conf.d/SuSEconfig.postfix
NOTE: make a backup of /sbin/conf.d/SuSEconfig.postfix but don't leave your backup inside /sbin/conf.d, because SuSEconfig will then run SuSEconfig.postfix and you backup. :)
do the following as root: cp -a /sbin/conf.d/SuSEconfig.postfix ~/SuSEconfig.postfix-orig
NOTE: this patch makes #MySQL note obsolete. Link for mysql.sock is created by SuSEconfig.postfix
--- SuSEconfig.postfix-orig 2006-02-05 14:34:03.000000000 +0100
+++ SuSEconfig.postfix 2006-02-06 13:52:31.501589142 +0100
@@ -78,6 +78,8 @@
rm -rvf etc lib usr var proc
elif [ "$(echo "$POSTFIX_UPDATE_CHROOT_JAIL" | tr 'A-Z' 'a-z' )" != "no" ]; then
echo "checking postfix chroot environment..."
+ echo "removing mysql.sock"
+ rm -rvf var/lib/mysql
if rpmqpack pam_ldap &> /dev/null; then
cpifnewer /etc/openldap/ldap.conf etc/openldap
@@ -133,6 +135,27 @@
fi
chown -R root /var/spool/postfix/{etc,lib,usr,var}
+
+ # something for having postfix comunicate with mysql via socket
+ HERE="/var/spool/postfix"
+ MS_DIR="var/lib/mysql"
+ MYSQL_SOCKET="/var/lib/mysql/mysql.sock"
+ CHR_MYSQL_SOCKET="var/lib/mysql/mysql.sock"
+ [ ! -d $MS_DIR ] && {
+ mkdir -p $MS_DIR
+ chown mysql: $MS_DIR
+ }
+ if [ ! -S $MYSQL_SOCKET ]; then
+ warn_user "\tMySQL has to be started to have mysql.sock linked\n\
++\tinto postfix chroot. Please start mysql and run\n\
++\tSuSEconfig again!"
+ else
+ [ ! -e $CHR_MYSQL_SOCKET -a ! -S $CHR_MYSQL_SOCKET ] && {
+ #echo "does not exist, linking socket"
+ ln $MYSQL_SOCKET $HERE/$CHR_MYSQL_SOCKET
+ }
+ fi
+
fi
}
@@ -513,7 +536,7 @@
my $match = 0;
foreach my $serv ( ( "smtp", "pickup", "cleanup", "qmgr", "rewrite",
- "bounce", "defer", "showq", "error", "virtual",
+ "bounce", "defer", "showq", "error",
"lmtp", "smtps", "tlsmgr", "localhost:10025" ) ) {
if( $line =~ /^$serv\s+/ ) {
$line =~ /(^$serv\s+\w+\s+[yn-]?\s+[yn-]?\s+)[yn-]?(.*)/;
SASL2 Install
The easiest is to get SASL2 compiled with Courier-IMAP authdaemon support.
When doing this SASL2 will hand-off the authentication to authdaemond.
On FreeBSD: make install WITH_AUTHDAEMON=yes
Sidenote: Dovecot also does Sasl with postfix and is in my (Gaqzi) opinion easier than these instructions. More information at: http://wiki.dovecot.org/PostfixAndDovecotSASL
The following has been built on Fedora Core 1-4 and has worked perfectly, if you have followed the directions above.
The best way to install SASL for Fedora is to use the following configure script. Change the paths for MySQL and Berkeley DB to reflect your paths.
Get SASL here: ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/cyrus-sasl-2.1.19.tar.gz
Then get this patch: http://frost.ath.cx/software/cyrus-sasl-patches/dist/2.1.19/cyrus-sasl-2.1.19-checkpw.c.patch
Apply the patch (from INSIDE the cyrus-sasl-2.1.19 directory):
$ patch -p0 < ../cyrus-sasl-2.1.19-checkpw.c.patch
Install:
$ export CPPFLAGS="-I/usr/local/mysql/include" $ ./configure \ --prefix=/usr/local/sasl2 \ --disable-cmulocal \ --enable-sample \ --enable-static=no \ --enable-shared=yes \ --enable-fast-install=yes \ --without-gnu-ld \ --disable-libtool-lock \ --enable-staticdlopen=no \ --without-purecov \ --without-purify \ --enable-java=no \ --with-javabase=no \ --without-dbpath \ --with-dblib=berkeley \ --with-bdb-libdir=/usr/local/bdb/lib \ --with-bdb-incdir=/usr/local/bdb/include \ --with-gdbm=no \ --with-pam=no \ --with-saslauthd=no \ --with-pwcheck=no \ --with-ipctype=unix \ --disable-alwaystrue \ --disable-checkapop \ --disable-cram \ --with-des=yes \ --disable-digest \ --with-openssl=/usr/bin/openssl \ --disable-otp \ --with-opie=no \ --disable-srp \ --disable-srp-setpass \ --disable-krb4 \ --disable-gssapi \ --enable-plain \ --disable-anon \ --disable-login \ --disable-ntlm \ --with-ldap=no \ --enable-sql \ --with-authdaemon=yes \ --with-mysql=/usr/local/mysql/lib \ --with-plugindir=/usr/local/lib/sasl2 \ --with-rc4 \ --without-dmalloc \ --without-sfio
In order to start saslauthd (this is only valid for cyrus-sasl when using the saslauthd, version >= 2.1.19), remember to use the -r option: this causes the daemon to pass user@domain.tld (instead of just the user part) to the authentication mechanizm, this is especially important when authenticating via PAM.
Another usefull option is to start the daemon in debug mode using -d, which allows you to monitor precisely what data is being used to authenticate your user.
SASL2 Setup
Postfix main.cf
The below example is the part that goes into your main.cf file of Postfix. There are also some additional UCE examples to block some spam. For more information on UCE check:
broken_sasl_auth_clients = yes smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_hostname, reject_rbl_client opm.blitzed.org, reject_rbl_client list.dsbl.org, reject_rbl_client bl.spamcop.net, reject_rbl_client sbl-xbl.spamhaus.org smtpd_sasl_auth_enable = yes smtpd_sasl_local_domain = $myhostname smtpd_sasl_security_options = noanonymous
SASL2 smtpd.conf
smtpd.conf locations:
- FreeBSD is in /usr/local/lib/sasl2
- Debian Sarge is in /etc/postfix/sasl
Your smtpd.conf should contain something like:
pwcheck_method: authdaemond log_level: 3 mech_list: PLAIN LOGIN authdaemond_path:/usr/local/var/spool/authdaemon/socket
socket locations:
- FreeBSD with courier-authlib-mysql-0.55 is /var/run/authdaemond/socket
- Debian Sarge is /var/run/courier/authdaemon/socket
Tip for FreeBSD (tested in 6.0-RELEASE by Jett Tayer)
Courier's autdaemond socket and pid directory must be readable by Postfix
chmod 755 /var/run/authdaemond
Tip for Debian (tested in sarge)
As for the mysql socket, you must create a link to the authdaemon socket in postfix's jail (as root):
mkdir -p /var/spool/postfix/var/run/courier/authdaemon ln /var/run/courier/authdaemon/socket /var/spool/postfix/var/run/courier/authdaemon/socket chown -R daemon:daemon /var/spool/postfix/var/run/courier
Don't forget check the permission of the path of /var/run/authdaemond/socket.
Please note
If your postfix runs in a jailed environment (like in Debian default package), you must recreate the hard link everytime the authdaemond restarts, or you will get lots of "Connection refused" on the log. This happens because authdaemond recreates the socket every time it starts, invalidating the old link.
In Debian, the simplest way is to put this on /etc/init.d/courier-authdaemond after authdaemond start
ln -f /var/run/courier/authdaemon/socket /var/spool/postfix/var/run/courier/authdaemon/socket
Please note you must restart saslauthd whenever making any changes are made to the smtpd.conf file. If you followed the above instructions to build cyrus-sasl, you will have disabled saslauthd, so this note does not apply.
Reload postfix:
- FreeBSD "postfix reload" or "/usr/local/etc/postfix reload" or "/etc/rc.d/sendmail restart" depending on how your /etc/rc.conf is configured.
- Debian Sarge "postfix reload" or "/etc/init.d/postfix reload"
- from chatran on slackware 10: I do this way:
pwcheck_method: saslauthd auxprop mech_list: login plain auxprop_plugin: sql sql_engine: mysql sql_hostnames: localhost sql_user: postfix sql_database: postfix sql_passwd: postfix sql_select: select password from mailbox where username = '%u@%r'
Note: this will only work if you use clear-text password, or if you patch the sql plugin as described in this article. --Beuc
- Also remember to chown 777 the directory of the socket, otherwise postfix will not be able to read it.
With FreeBSD you can add postfix to the group courier. Edit /etc/group and change the line courier:*:465: in courier:*:465:postfix
SASL2 PAM install
Alternatively (for example if you don't want to recompile sasl package and use your distribution's -- tested on Debian), you can use PAM authentication. Install pam_mysql.so in addition to sasl2 (In debian, you need: sasl2-bin libsasl2-modules libpam-mysql). Then set up /etc/postfix/sasl/smtpd.conf like this:
pwcheck_method: saslauthd mech_list: PLAIN LOGIN minimum_layer: 0
As mentioned above, if you don't want saslauthd to strip the domain name from logins, it needs to be run with the -r option. In Debian Stable (Sarge) you can update /etc/default/saslauthd:
START=yes MECHANISMS="pam" PARAMS="-r"
In Debian Stable (Etch) you can update "/etc/default/saslauthd":
START=yes MECHANISMS="pam" OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"
Then create /etc/pam.d/smtp and include something like this:
auth required pam_nologin.so auth required pam_mysql.so user=postfix passwd=password host=localhost db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1 #auth required pam_unix.so auth required pam_env.so # [1] account sufficient pam_mysql.so user=postfix passwd=password host=localhost db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1 account required pam_unix.so
(change password= to your database password). Everything else can be done as if you were using authdaemon from sasl (including main.cf changes).
You might also need to start SASL AuthDaemon in the Postfix chrooted environment for Debian. Taken from:
http://groups.google.com/group/mailing.postfix.users/browse_thread/thread/bc6dc028246f3bd7/32330aec53659ef6?lnk=st&q=warning%3A+SASL+authentication+failure%3A+cannot+connect+to+saslauthd+server%3A+No+such+file+or+directory&rnum=1#32330aec53659ef6
I had to edit /etc/init.d/saslauthd to include:
PARAMS="-m /var/spool/postfix/var/run/saslauthd"
keep in mind i'm not using sasl for anything other than postfix. this might not be where you want things if sasl is used by other processes..
and of course setup the necessary directories to accommodate the above:
mkdir /var/spool/postfix/var/ mkdir /var/spool/postfix/var/run/ mkdir /var/spool/postfix/var/run/saslauthd chown -R root:sasl /var/spool/postfix/var/
you might have to add postfix to the sasl group as well - i'm sure someone will chime in if this is not necessary. adduser postfix sasl
If you are running Debian Stable (Etch) I would recomend readin "/usr/share/doc/sasl2-bin/README.Debian" it states
Using saslauthd with Postfix:
If you run a chrooted server such as Postfix and wish to use saslauthd, you
must place the saslauthd socket ("mux") inside the Postfix chroot. You must
also set correct overrides for the run directory inside the chroot, using
dpkg-statoverride. Finally, you must add the postfix user to the sasl group.
These steps ensure that the Debian subsystems know how you want things to be
laid out.
To place the saslauthd socket inside the Postfix chroot, edit
/etc/default/saslauthd and set OPTIONS like this (you may omit -c):
OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd"
To set the run directory using dpkg-statoverride, run this command as root:
dpkg-statoverride --add root sasl 710 /var/spool/postfix/var/run/saslauthd
Finally, to add the postfix user to the sasl group:
adduser postfix sasl
The init script will automatically create the run directory with the
permissions you have set using dpkg-statoverride. Please note that you must
also configure Postfix correctly. There are many options related to SASL. See
the Postfix documentation for how to do this.
once things are working, you should see some *mux* files in
/var/spool/postfix/var/run/saslauthd/
Courier-IMAP Install
Build and install Courier-IMAP, make sure that this is built with MySQL.
The authentication daemon of Courier-IMAP is now distributed seperately, courier-authlib.
This means that the MySQL integration has moved from Courier-IMAP to courier-authlib.
Make sure that you build courier-authlib with MySQL support.
On FreeBSD: make WITH_MYSQL=yes install
Also on FreeBSD: Don't forget to add "courier_authdaemond_enable="YES" to your /etc/rc.conf. It's not obvious because courier-authlib is installed with courier-imap during a "make install", and the status message after install only reminds you to add courier-imap to your startup config.
On Debian: apt-get install courier-authdaemon courier-authmysql
Courier-IMAP Setup
First, make sure you include authmysql in authmodulelist of Courier's authdaemonrc
authmysqlrc
NOTE: Make sure that there are no (trailing) spaces in this file, only tabs!!
The below is a part of the authmysqlrc file that is relevant to our setup. The things that you might need to change are the default_domain, mysql_password, mysql_uid and mysql_gid.
#DEFAULT_DOMAIN domain.tld MYSQL_CRYPT_PWFIELD password MYSQL_DATABASE postfix MYSQL_GID_FIELD '1001' MYSQL_HOME_FIELD '/usr/local/virtual' MYSQL_LOGIN_FIELD username MYSQL_MAILDIR_FIELD maildir MYSQL_NAME_FIELD name MYSQL_OPT 0 MYSQL_PASSWORD postfix #MYSQL_PORT 0 # Uncomment below if you want quota support. #MYSQL_QUOTA_FIELD quota MYSQL_SERVER localhost # Default FreeBSD Socket #MYSQL_SOCKET /var/mysql/mysql.sock # Default RedHat Socket #MYSQL_SOCKET /var/lib/mysql/mysql.sock # Default Debian Sarge Socket #MYSQL_SOCKET /var/run/mysqld/mysqld.sock MYSQL_UID_FIELD '1001' MYSQL_USERNAME postfix MYSQL_USER_TABLE mailbox #MYSQL_WHERE_CLAUSE server='example.domain.com'
- Make sure that there are NO spaces in the authmysqlrc file, only tabs.
- Make sure that there are only single quotes ' around static values like: '/usr/local/virtual', 'UID', 'GID'
- NO single quotes around localhost!
- Make sure that localhost exists in your /etc/hosts file.
- Including IPv6 during the compilation could cause a problem.
- The MYSQL_GID_FIELD and MYSQL_UID_FIELD are for the UID and GID of the postfix user and group, NOT for the MySQL user and group.
- If you have more than one authdaemon in /usr/lib/courier-imap/authlib, make sure that version="authdaemond.mysql" in /etc/courier/authdaemonrc
User question/comment: I thought MYSQL_CRYPT_PWFIELD only handles the ENCRYPT() function in stead of MD5() (see postfix-mysql setup). Correct me when I'm wrong
User question/comment: MYSQL_CRYPT_PWFIELD only specifies the name of database field, it has nothing to do with crypt format. authlib can automatically detect several different formats of password hash, please refer to cryptpassword.c inside courier authlib source code for more info. Basically it checks if the first few characters of password hash is:
- "$1$": password is MD5 format password used by all Linux systems.
- "{MD5}": this is followed by standard MD5 hash of password phrase.
- "{SHA}": this is followed by standard SHA hash of password phrase.
- "{SHA256}": this is followed by standard SHA256 hash of password phrase.
- "{CRYPT}": this is followed by standard DES crypt() hash of password phrase.
User question/comment: MYSQL_HOME_FIELD '/usr/local/virtual' is not a field name and is not used as a literal by courier-authlib-0.57 although it should not be deleted or changed to ' ' as the default field of 'home' will be substituted causing errors. Try MYSQL_MAILDIR_FIELD CONCAT("/usr/local/virtual/",maildir) as a workaround.
imapd
Your Courier-IMAP imapd file should have a line similar to this.
IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE"
Dovecot IMAP Install
Recently I switched from courier imap to dovecot, which is a lot easier to configure than courier, and performs much better. You will find dovecot packages in most linux distributions and in the *BSD ports. Please make sure you compile dovecot with at least the mysql support. For freebsd:
cd /usr/ports/mail/dovecot && make install clean
And compile with the mysql module.
Dovecot IMAP Setup
You need to edit only three files (Thanks to [sylhouette] for his examples).
dovecot-openssl.cnf
First: /usr/local/share/dovecot/dovecot-openssl.cnf to make the certificates for imap-ssl and pop-ssl.
[ req ] default_bits = 1024 encrypt_key = yes distinguished_name = req_dn x509_extensions = cert_type prompt = no [ req_dn ] # country (2 letter code) C=NL # State or Province Name (full name) ST=nh # Locality Name (eg. city) L=Amsterdam # Organization (eg. company) O=FriendsOfTheMoose # Organizational Unit Name (eg. section) OU=IMAP server # Common Name (*.example.com is also possible) CN=hostname.yourdomain.tld # E-mail contact emailAddress=postmaster@yourdomain.tld [ cert_type ] nsCertType = server
Create /etc/ssl/certs and /etc/ssl/private directories if nessecary and run:
cd /usr/local/share/dovecot/ ./mkcert.sh
dovecot.conf
Then we edit /usr/local/etc/dovecot.conf. This configuration can be used, please make sure that first_valid_uid and first_valid_gid are set to those of postfix. Fill in the postmaster email addresse. Another thing: the namespace parameters that I filled in was to keep it compatible with courier imap, from which I migrated, without the need to change all clients. If you do not need this, read the section on namespaces: http://wiki.dovecot.org/Namespaces .
protocols = imap imaps
listen = *
login_process_size = 64
default_mail_env = maildir:/usr/local/virtual/%u/
namespace private {
separator = .
prefix = INBOX.
inbox = yes
}
namespace private {
separator = .
prefix =
inbox = yes
hidden = yes
}
mail_extra_groups = postfix
verbose_proctitle = yes
first_valid_uid = 125
first_valid_gid = 125
#umask = 0077
mbox_read_locks = fcntl
mbox_write_locks = fcntl
ssl_disable = no
ssl_cert_file = /etc/ssl/certs/dovecot.pem
ssl_key_file = /etc/ssl/private/dovecot.pem
# If key file is password protected, give the password here. Alternatively
# give it when starting dovecot with -p parameter.
ssl_key_password =
protocol imap {
imap_client_workarounds = delay-newmail outlook-idle netscape-eoh tb-extra-mailbox-sep
}
#People who use outlook are fux0red anyway...
#protocol pop3 {
# pop3_uidl_format = %08Xu%08Xv
# pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
#}
protocol lda {
postmaster_address = postmaster@yourdomain.tld
sendmail_path = /usr/local/sbin/sendmail
}
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
auth_debug = yes
auth_verbose = yes
auth default {
passdb sql {
args = /usr/local/etc/dovecot-mysql.conf
}
userdb sql {
args = /usr/local/etc/dovecot-mysql.conf
}
}
dovecot-mysql.conf
And then we edit /usr/local/etc/dovecot-mysql.conf.
# Database driver: mysql, pgsql driver = mysql # Currently supported schemes include PLAIN, PLAIN-MD5, DIGEST-MD5, and CRYPT. default_pass_scheme = CRYPT # Database options connect = host=localhost dbname=postfix user=dovecot password=assword password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = '1' user_query = SELECT maildir, 125 AS uid, 125 AS gid FROM mailbox WHERE username = '%u' AND active = '1' # eof
Fill in your proper password, and make sure that
125 AS uid 125 AS gid
contain the userid and group id of postfix.
database
Finally we make some adjustments to the database. There is a nasty bug that I struggled with. Apparantly, mysql 4.1 and higher use a new password scheme, while dovecot uses the old one. So this is what I do:
grant select on postfix.* to 'dovecot'@'localhost' identified by 'assword';
set password for 'dovecot'@'localhost' = old_password('assword');
remarks
Make note: there are a few instances of the number 125 in dovecot.conf and dovecot-mysql.conf. Make sure this is set to the uid and guid of postfix. In FreeBSD 6 this is 125. In FreeBSD 4.x this is 1001. Check /etc/passwd to make sure.
Check out the namespace thing that I mention above, if you are migrating from courier. Or using mail.app. Well, check it anyway, differences in namespaces seems to break certain clients.
Mutt may break with dovecot. I find that mutt-ng works without problems. You might need to set in .muttrc (or .muttngrc):
set imap_idle=no #May be nessecary for older mutt versions set folder=imap://localhost/ #Or whatever host dovecot is running set spoolfile=+INBOX #If you use the namespaces I use
Testing your setup
Below are the basic telnet commands for testing your setup:
SMTP:
telnet 127.0.0.1 25 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 220 localhost.localdomain ESMTP Postfix > EHLO test.com 250-localhost.localdomain 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN PLAIN 250 8BITMIME > AUTH PLAIN AHVzZXJAZG9tYWluLnRsZABzZWNyZXQ= 235 Authentication successful
A common question is: how do i obtain the auth code ?
Simple, just use this perl script, inserting the username and password in appropriate places:
perl -MMIME::Base64 -e 'print encode_base64("\0user\@domain.tld\0secret")'
Filtering
Postfix as well as Courier/Dovecot (make your life easy, choose Dovecot) are unable to do anykind of filtering in terms of putting certain mail in certain imap directories. I have been searching for possibilities to do so. I'm not an expert at all, but you can find my solution here: Combine With Maildrop Howto
This document was started by Mischa 10:07, 20 Apr 2005 (CEST)
