4

I'm trying to setup Postfix and Dovecot, the latter with virtual users stored in a MySQL database, following this guide (but here I recap everything as there are some "bugs" in the guide I fixed following the comments). Preamble: I have Postfix, Dovecot, postfix-mysql and dovecot-mysql installed from Ubuntu repositories.

Let's start with Postfix config:

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no   
readme_directory = no

myhostname = localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = localhost
relayhost = 
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

relay_domains = *
virtual_alias_maps = proxy:mysql:/etc/postfix/virtual_alias_maps.cf
virtual_mailbox_domains = proxy:mysql:/etc/postfix/virtual_mailbox_domains.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/virtual_mailbox_maps.cf
virtual_mailbox_base = /home/vmail
virtual_mailbox_limit = 512000000
virtual_minimum_uid = 5000
virtual_transport = virtual
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
transport_maps = hash:/etc/postfix/transport

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/run/dovecot/auth-client
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/ssl/private/server.crt
smtpd_tls_key_file = /etc/ssl/private/server.key
smtpd_sasl_local_domain = $myhostname
broken_sasl_auth_clients = yes
smtpd_tls_loglevel = 1

Then I created user vmail to store emails:

groupadd -g 5000 vmail
useradd -u 5000 -g vmail -s /usr/bin/nologin -d /home/vmail -m vmail

And MySQL database and user to store info about domains and virtual users:

CREATE DATABASE postfix_db;
USE postfix_db;
CREATE USER postfix_user@localhost IDENTIFIED BY 'password';
GRANT ALL ON postfix_db.* TO postfix_user@localhost;
FLUSH PRIVILEGES;

Then I created the tables related to domains, forwardings and users:

CREATE TABLE `domains` (
  `domain` varchar(50) NOT NULL default "",
  PRIMARY KEY  (`domain`),
  UNIQUE KEY `domain` (`domain`)
);


CREATE TABLE `forwardings` (
  `source` varchar(80) NOT NULL default "",
  `destination` text NOT NULL,
  PRIMARY KEY  (`source`)
);

CREATE TABLE `users` (
  `email` varchar(80) NOT NULL default "",
  `password` varchar(20) NOT NULL default "",
  `quota` varchar(20) NOT NULL default '20971520',
  `domain` varchar(255) NOT NULL default "",
  UNIQUE KEY `email` (`email`)
);

I added my domain (which has A and MX records properly set) in the table:

INSERT INTO `domains` VALUES ('virtualdomain.tld');

And an account related to that domain:

INSERT INTO `users` VALUES ('info@virtualdomain.tld', ENCRYPT('password'), '20971520', 'virtualdomain.tld');

Then I created a self-signed cert:

cd /etc/ssl/private/
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server.key
chmod 400 server.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
chmod 444 server.crt

And then the files I was referring to in Postfix config:

/etc/postfix/virtual_alias_maps.cf

user = postfix_user
password = hunter2
hosts = localhost
dbname = postfix_db
table = domains
select_field = domain
where_field = domain

/etc/postfix/virtual_mailbox_domains.cf

user = postfix_user
password = hunter2
hosts = localhost
dbname = postfix_db
table = forwardings
select_field = destination
where_field = source

/etc/postfix/virtual_mailbox_maps.cf

user = postfix_user
password = hunter2
hosts = localhost
dbname = postfix_db
table = users
select_field = concat(domain,'/',email,'/')
where_field = email

And then

touch /etc/postfix/transport
postmap /etc/postfix/transport

Now I deleted the default Dovecot config file, replacing it with:

protocols = imap
auth_mechanisms = plain
passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}
userdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}

service auth {
    unix_listener auth-client {
        group = postfix
        mode = 0660
        user = postfix
    }
    user = root
}

mail_home = /home/vmail/%d/%u
mail_location = maildir:~

ssl_cert = </etc/ssl/private/server.crt
ssl_key = </etc/ssl/private/server.key

I created the /etc/dovecot/dovecot-sql.conf file:

driver = mysql
connect = host=localhost dbname=postfix_db user=postfix_user password=hunter2
# The new name for MD5 is MD5-CRYPT so you might need to change this depending on version
default_pass_scheme = MD5-CRYPT
# Get the mailbox
user_query = SELECT '/home/vmail/%d/%u' as home, 'maildir:/home/vmail/%d/%u' as mail, 5000 AS uid, 5000 AS gid, concat('dirsize:storage=',  quota) AS quota FROM users WHERE email = '%u'
# Get the password
password_query = SELECT email as user, password, '/home/vmail/%d/%u' as userdb_home, 'maildir:/home/vmail/%d/%u' as userdb_mail, 5000 as  userdb_uid, 5000 as userdb_gid FROM users WHERE email = '%u'
# If using client certificates for authentication, comment the above and uncomment the following
#password_query = SELECT null AS password, ‘%u’ AS user

... and finally restarted dovecot and postfix:

service postfix dovecot restart

The problem is that when I try to send an email to info@virtualdomain.tld, I see this in logs:

NOQUEUE: reject: RCPT from blablabla.com[xxx.xxx.xxx.xxx]: 451 4.3.0 <info@virtualdomain.tld>: Temporary lookup failure; from=<my@email.tld> to=<info@virtualdomain.tld> proto=ESMTP helo=<blablabla.com>

And the mail bounces back with the error

550 5.1.1 "Recipient address rejected: User unknown in virtual alias table"
MultiformeIngegno
  • 1,687
  • 9
  • 26
  • 31
  • What's the result of command `postmap -q virtualdomain.tld mysql:/etc/postfix/virtual_alias_maps.cf` and `postmap -q virtualdomain.tld mysql:/etc/postfix/virtual_mailbox_domains.cf`? Please also check maillog after you run those commands. – masegaloeh Oct 31 '14 at 23:41
  • Thanks for the reply. Here are the results: `root:~# postmap -q virtualdomain.tld mysql:/etc/postfix/virtual_alias_ maps.cf virtualdomain.tld root:~# postmap -q virtualdomain.tld mysql:/etc/postfix/virtual_mailbox_domains.cf (empty)` Better in pastebin: http://pastebin.com/raw.php?i=66UGqx9L Nothing in server logs – MultiformeIngegno Nov 01 '14 at 01:00
  • 1
    As you said, the tutorial is broken (duh!). Remember, you should consult [official documentation](http://www.postfix.org/) whenever you using any tutorial to getting started. – masegaloeh Nov 01 '14 at 01:12

2 Answers2

3

Looks like, your virtual_alias_maps and virtual_mailbox_domains was swapped. Try to rename them

mv /etc/postfix/virtual_alias_maps.cf /tmp/virtual_mailbox_domains.tmp
mv /etc/postfix/virtual_mailbox_domains.cf /etc/postfix/virtual_alias_maps.cf 
mv /tmp/virtual_mailbox_domains.tmp /etc/postfix/virtual_mailbox_domains.cf

Don't forget to run postfix reload.

masegaloeh
  • 18,236
  • 10
  • 57
  • 106
  • Ooook!!! Something seems to start working now!! I can see the mail in `/home/vmail/virtualdomain.tld/info@virtualdomain.tld/new`. And here's the syslog: http://pastebin.com/raw.php?i=pAf3VL2V. But if I try to connect from an email client specifying my FQDN as host and username&password specified in "users" table I get these errors in syslog `"Auth failed. TLS: Disconnected"` `"warning: SASL: Connect to /var/run/dovecot/auth-client failed: No such file or directory"` and `"fatal: no SASL authentication mechanisms"` – MultiformeIngegno Nov 01 '14 at 02:30
  • If I set PLAIN instead of MD5-CRYPT everything works I can even access from my external client. Seems MySQL ENCRYPT function used when adding the password to the users table isn't encrypting as MD5 (it doesn't even start with $1)... mmm – MultiformeIngegno Nov 01 '14 at 02:52
2

I'm sure Dovecot is the one that creates the auth file, as postfix talks to dovecot and dovecot does the authentication so in your 'dovecot.conf' add:

path = /var/run/dovecot/auth-client

into the client block like so:

service auth {
    unix_listener auth-client {
        path = /var/run/dovecot/auth-client
        group = postfix
        mode = 0660
        user = postfix
    }

or

service auth {
    unix_listener /var/run/dovecot/auth-client {
        group = postfix
        mode = 0660
        user = postfix
    }

Restart dovecot

Check if /var/run/dovecot/auth-client is created

type in ls -l /var/run/dovecot/auth-client to confirm.

Then retry.

devatnull
  • 106
  • 5
  • I found the correct dirs. Apparently since ubuntu 12.04 the path is /var/spool/postfix/private/auth. Now the only problem seems to be the MD5 encrypt function by MySQL. When I insert the data in "users" table ENCRYPT('password') doesn't actually store the password as MD5-CRYPT scheme.. Which function should I use instead? – MultiformeIngegno Nov 01 '14 at 03:35
  • Your Password row varchar(20) doesn't seem enough for the md5-crypt hash: `password` varchar(20) NOT NULL default "" Change the varchar length value to varchar(64) – devatnull Nov 01 '14 at 04:00
  • Thanks. I'll try as soon as the screenshot of the VPS is complete. :D – MultiformeIngegno Nov 01 '14 at 04:03
  • BTW MD5 is considered a weak encryption method, once you get the set up working look into another more secure encryption method like sha512/256 etc – devatnull Nov 01 '14 at 04:04
  • Check this post for a reference to a similiar situation: http://stackoverflow.com/questions/24186158/sha512-crypt-mysql-and-dovecot – devatnull Nov 01 '14 at 04:12
  • Thanks for the reference. But I was wondering, when is this encryption used? When client is sending credentials to the server? Or "inside" the server..? Because single mails are in plain text too.. – MultiformeIngegno Nov 01 '14 at 04:21
  • varchar(64) wouldn't be enough for SHA512.. right? – MultiformeIngegno Nov 01 '14 at 04:23
  • Sorry since its an MD5 it should be varchar(32) or better still char(32). Varchar is used for strings when your not sure of the length, char expects exactly the length given and is better performance wise. – devatnull Nov 01 '14 at 04:29
  • Ok, I'm trying with SHA512 right now, so I'll go with char(128) – MultiformeIngegno Nov 01 '14 at 04:31
  • No SHA512 would create 128 character hashes so char(128) – devatnull Nov 01 '14 at 04:33
  • Your using plaintext over TLS, the encrption is internal. Sorry I would start a chat but not enough reps yet :) – devatnull Nov 01 '14 at 04:49
  • Sorry just noticed to, In order to let Outlook clients use SMTP-AUTH you may need to change: `auth_mechanisms = plain` in dovecot.conf to `auth_mechanisms = plain login`. Restart Dovecot. – devatnull Nov 01 '14 at 04:52
  • Yep I read that! Now I'm practically done. Just one thing I realized is that if I have different domains I should also have the ability to serve different certificates. Now I serve one signed cert for a domain, but when I setup a new domain I won't be able to serve the related signed cert – MultiformeIngegno Nov 01 '14 at 04:57
  • Postfix and Dovecot will use the cert globally for all domains? – devatnull Nov 01 '14 at 05:04
  • Mmmm, here I read it has SNI suppor: http://wiki2.dovecot.org/SSL/DovecotConfiguration But when I try to wrap the ssl variables like this `local_name domain.tld { ssl_cert = – MultiformeIngegno Nov 01 '14 at 05:07
  • Seems certs variables are ignored.. maybe local_name doesn't match because the domain is "virtual"..? – MultiformeIngegno Nov 01 '14 at 05:15
  • Try it without the leading `<` `ssl_cert_file = /var/www/blablab/ssl/ssl.crt` `ssl_key_file = /var/www/blablab/ssl/ssl.key` – devatnull Nov 01 '14 at 05:23
  • Nope, same problem – MultiformeIngegno Nov 01 '14 at 05:29
  • However its important to note that "ssl = yes" must be set globally if you require SSL for any protocol (or dovecot will not listen on the SSL ports), which in turn requires that a certificate and key are specified globally even if you intent to specify certificates per protocol. The per protocol certificate settings override the global setting.: [link]http://wiki2.dovecot.org/SSL/DovecotConfiguration – devatnull Nov 01 '14 at 05:37
  • Found!!!!!!!! I needed a dot, like this local_name .domain.tld {} EDIT: No it's not true.. just seemed to work :( – MultiformeIngegno Nov 01 '14 at 05:56
  • I'm trying to use only one table for both users and domains. So I need a way to only select unique domains inserted in "users" table. I digged a little and I think that `HAVING` is the way to go but I can't figure out how to use it in the file.. `table = users select_field = domain where_field = domain` – MultiformeIngegno Nov 01 '14 at 12:58