Introduction
A passwd entry is a database record that contains some basic information about a user. Traditionally this information included the user’s password, which is why a passwd entry is called a passwd entry, but these days the password itself is typically stored somewhere more secure.
Consequently, passwd entries can be used for listing or validating users but cannot be used for authenticating users.
Both Dovecot and Postfix must deal with this dichotomy.
This article:
- describes the very misaligned approaches that Dovecot and Postfix take to address this dichotomy, with special attention to using LDAP as the database backend
- suggests a more aligned approach
- mentions various error messages encountered along the way and how to resolve them
- discusses a couple of other unrelated questions that came up along the way
A common Dovecot+Postfix configuration with LDAP support
On networks with real Unix accounts for each mail user, a common Postfix+Dovecot configuration is:
- Dovecot validates and authenticates users via LDAP
- Dovecot offers an LDAP user authentication service to Postfix
- Postfix authenticates users by using the service provided by Dovecot
- Postfix validates users via LDAP (using OS-level LDAP services)
The first and last points need some clarification.
Firstly, Dovecot may need to look up the user’s passwd entry or authenticate a user for several reasons:
- check if the user is authorised to read the mail that the user is asking Dovecot to retrieve via IMAP
- maybe to get the user’s UID so that it can set the owner of the files into which it moves mails
We tell Dovecot to use LDAP as follows:
mandala# fgrep -B 1 -A 1 ldap /etc/dovecot/dovecot.conf userdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf } -- passdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf }
and we tell Dovecot the LDAP connection parameters as follows:
mandala# egrep -v '^ *(#|$)' /etc/dovecot/dovecot-ldap.conf base = ou=Users,dc=pasta,dc=net uris = ldaps://ldap.pasta.freemyip.com/ auth_bind = yes auth_bind_userdn = uid=%u,ou=Users,dc=pasta,dc=net tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt ...
With this information, Dovecot can establish a TCP connection to the LDAP server and make its query.
Additionally, we tell Dovecot how to hone its query and how to interpret the results:
... user_filter = (&(objectClass=posixAccount)(uid=%n)) user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid mandala#
Secondly, Postfix may need to look up the user’s passwd entry or authenticate a user for several reasons:
- to check if a user exists
- to check what is in the user’s .forward file
- to authenticate a remote user who is attempting to relay mail via Postfi
- maybe to save incoming mail into an INBOX in the user’s home
In the common Dovecot+Postfix configuration outlined earlier, Postfix delegates looking up a user’s password entry to either NSS or PAM and delegates authenticating a user to Dovecot.
The delegation to NSS or PAM are very similar, consisting of a series of functions calling other functions calling other functions with the last function connecting to an LDAP server, submitting a query, fetching results and passing them back up the call stack. I am going to describe the NSS route because I am more familiar with it and it is easier to follow.
The C standard libary contains a few functions for looking up passwd entries:
We would expect that the Postfix source code contains calls to some of these and we can confirm this by running:
mandala# dpkg -L postfix | xargs nm -D 2>/dev/null \ sort -u | grep getpw U getpwnam@GLIBC_2.2.5 U getpwnam_r@GLIBC_2.2.5 U getpwuid@GLIBC_2.2.5 U getpwuid_r@GLIBC_2.2.5 U getpwnam@GLIBC_2.2.5 U getpwuid@GLIBC_2.2.5 U getpwnam@GLIBC_2.2.5 U getpwnam@GLIBC_2.2.5 mandala#
That command is listing the contents of the postfix package – including directories, binaries, man pages, READMEs – and searching all of them for calls to functions containing ‘getpw
‘ in their names. That search is obviously going to produce errors when it looks for calls inside directories, man pages and READMEs, so we discard any error messages. We are left with:
getpwnam()
retrieves a passwd entry for a specified usernamegetpwuid()
retrieves a passwd entry for a specified numeric user ID- The
*_r()
functions provide the same functionality but are more suited to threaded environments
We will follow the route taken by getpwnam()
, but similar routes would apply to the other functions.
We have already established that Postfix calls getpwnam()
and we can reasonably assume that it does this for the reasons described above. Note that “reasonably assume”; using nm
to examine the functions that a program or library can call does not prove that the program or library actually calls a particular function, but it does strongly suggest that – in some circumstances – it does.
So then getpwnam()
looks in /etc/nsswitch.conf to see where passwd entries could be stored and finds this:
mandala# grep passwd /etc/nsswitch.conf passwd: files ldap mandala#
So then getpwnam()
checks if the user is mentioned in the local /etc/passwd file by delegating to this function:
mandala# nm -D /lib/x86_64-linux-gnu/libnss_files.so \ | grep getpwnam 0000000000006770 T _nss_files_getpwnam_r@@GLIBC_PRIVATE mandala#
and then – assuming the user it is looking up is not listed in /etc/passwd because it is listed in LDAP instead – it checks in LDAP by delegating to this function:
mandala# nm -D /lib/x86_64-linux-gnu/libnss_ldap.so.2 \ | grep getpwnam 0000000000006900 T _nss_ldap_getpwnam_r@@EXPORTED mandala#
nss_ldap_getpwnam_r()
delegates to nslcd
(8),the local LDAP name service daemon, which does LDAP queries on behalf of local processes:
mandala# ps -C nslcd PID TTY TIME CMD 1075 ? 00:00:01 nslcd mandala#
nss_ldap_getpwnam_r()
probably communicates with nslcd
through one of these sockets:
mandala# lsof -p 1075 -E | grep unix nslcd 1075 nslcd 5u unix 0x0000000092a56bcc 0t0 18974 type=DGRAM ->INO=11198 229,systemd-j,6u 1,systemd,122u nslcd 1075 nslcd 6u unix 0x00000000fb6e0ef7 0t0 18989 /var/run/nslcd/socket type=STREAM mandala#
nslcd
looks – or rather it looked when it was first started – in /etc/ldap/ldap.conf to get the LDAP connection parameters:
mandala# egrep -v '^ *($|#)' /etc/nslcd.conf uid nslcd gid nslcd uri ldaps://ldap.pasta.freemyip.com/ base dc=pasta,dc=net tls_cacertfile /etc/ssl/certs/ca-certificates.crt mandala#
and connects to the LDAP server and forwards it the query.
The LDAP server replies to nslcd
, which replies to nss_ldap_getpwnam_r()
, which replies to getpwnam()
, which replies to Postfix.
So what’s wrong with that and how can we fix it?
- Postfix delegates some LDAP communication (i.e. user authentication) to Dovecot, but not all of it (i.e. user validation), meaning that two different stacks need to be configured
- Dovecot does not at all delegate LDAP communication
- meaning that in total three different stacks need to be configured
Can it be simplified?
- Can Postfix and Dovecot be configured to access LDAP via NSS?
- Can Postfix and Dovecot be configured to access LDAP directly?
- Can Postfix be configured to delegate all LDAP communication to Dovecot?
We will consider each of these options in the next sections.
Can Postfix and Dovecot be configured to access LDAP via NSS?
I would guess that making Postfix not delegate user authentication to Dovecot, by removing these lines from /etc/postfix/main.cf:
smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth
would probably be enough to make it use NSS for user authentication instead.
However, making Dovecot use NSS is a bigger problem. The userdb documentation leads to the passwd authentication documentation, which suggests it is possible, by setting:
userdb { driver = passwd args = blocking=no }
but the same page says that passwd cannot be used for passdb, because of the splitting out of the password into /etc/shadow.
There is the alternative nss
driver, which is probably better (because probably the passwd
driver goes straight to /etc/passwd, whereas nss
will go to /etc/nsswitch.conf). It is documented here but that documentation says that a service
parameter is required, like this:
userdb { driver = nss args = service=ldap }
But we do not want to tell Dovecot to use LDAP; we want to tell it to use NSS (and for nss to look in /etc/nsswitch.conf and discover that I want it to use LDAP). I could not find any documention regarding what other args = server=whatever
options were possible. If we omit args=service=ldap
and duplicate the stanza for the passdb, i.e.:
userdb { driver = nss } passdb { driver = nss }
then starting up mutt results in Dovecot complaining:
Dec 15 09:42:20 mandala dovecot: auth: Fatal: Unknown passdb driver 'nss'
This passdb page lists (rather obtusely) the possible passdb drivers. The equivalent of userdb/passwd seems to be passdb/shadow but the shadow authentication page says that can be problematic and that driver pam is preferred.
The PAM page makes for pessmistic reading but the file it refers to – /etc/pam.d/dovecot, which goes on to include /etc/pam.d/common-auth – actually looks quite suitable:
mandala# egrep -v '^(#|$)' /etc/pam.d/common-auth auth [success=2 default=ignore] pam_unix.so nullok auth [success=1 default=ignore] pam_ldap.so minimum_uid=1000 use_first_pass auth requisite pam_deny.so auth required pam_permit.so mandala#
But rather inconsistently there is no pam driver for the userdb database. The closest seems to the nss driver. So let’s try:
userdb { driver = nss #args = service=ldap } passdb { driver = pam args = failure_show_msg=yes }
which causes:
Dec 15 10:02:39 mandala dovecot: auth: Fatal: Unknown userdb driver 'nss'
So NSS is not an option in Debian 11’s Dovecot for either userdb or passdb.
What other userdb drivers would force Dovecot to delegate to the OS rather than going directly to LDAP? The userdb page does not list pam
as a possibility but it does say:
The user and password databases … may be the same or they may be different depending on your needs.
If we try userdb/pam, then that fails with:
Dec 15 10:06:07 mandala dovecot: auth: Fatal: Unknown userdb driver 'pam'
So I conclude that both Postfix and Dovecot cannot be configured to access LDAP via NSS.
Can Postfix and Dovecot be configured to access LDAP directly?
We revert Dovecot to our original configuration:
userdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf } passdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf }
with /etc/dovecot/dovecot-ldap.conf specifying how to connect to the LDAP server, hone queries and filter results, as discussed earlier.
Can we make Postfix talk directly to the LDAP server in the same way?
The postconf(5) man page does not mention accessing LDAP directly.
So I conclude that both Postfix and Dovecot cannot be configured to access LDAP directly.
A digression
While reading postconf(5) I saw this:
smtpd_relay_restrictions …
With Postfix versions before 2.10, the rules for relay permission and spam blocking were combined under smtpd_recipient_restrictions, resulting in error-prone configuration. As of Postfix 2.10, relay permission rules are preferably implemented with smtpd_relay_restrictions, so that a permissive spam blocking policy under smtpd_recipient_restrictions will no longer result in a permissive mail relay policy.
which looks like it might be useful!
Currently my smtp_recipient_restrictions
are:
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit
But this could be split this into:
smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, reject
and:
smtpd_recipient_restrictions = reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, reject_unverified_recipient, check_policy_service inet:127.0.0.1:10023, permit
Note that the reject_unverified_recipient
necessitates Postfix delegating to Dovecot and will result in a mail being rejected if the local part of the address does not match any known user (in LDAP).
Can Postfix be configured to delegate all LDAP communication to Dovecot?
I googled ‘postfix validate local address dovecot’ and that led here, which says:
With Dovecot 2.0 you can also use LMTP and the Postfix setting “reject_unverified_recipient” for dynamic address verification. It is really nice because Postfix does not need to query an external datasource (MySQL, LDAP…).
which sounds like what I want! I.e. stop Postfix from using (OS-level) LDAP and get it to use Dovecot.
Dovecot’s page about LMTP says:
LMTP uses the same settings as LDA ( See Common configuration), as specified in conf.d/15-lda.conf in example configuration. There is also a bit of extra configuration in conf.d/20-lmtp.conf.
I installed dovecot-lmtp package.
No settings are applied by default:
mandala# egrep -v '^ *(#|$)' /etc/dovecot/conf.d/15-lda.conf protocol lda { } mandala# egrep -v '^ *(#|$)' /usr/share/dovecot/conf.d/20-lmtp.conf protocol lmtp { } mandala#
I.e. no settings were applied by default.
I modified dovecot.conf:
protocols = " ... lmtp" service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix } }
and also in /etc/postfix/main.cf:
# This was the old setting #mailbox_command = /usr/lib/dovecot/deliver # This is the new setting mailbox_transport = lmtp:unix:private/dovecot-lmtp
I restart Dovecot and Postfix.
My tests are as follows:
- mutt/imap: can Mutt open an IMAP connection to the Dovecot server, authenticate itself and read my inbox?
- cercis/mpcdf: can a remote SMTP client (cercis) authenticate itself with the Postfix server and upload a mail for a remote address (mpcdf) and is that mail delivered succesfully?
- mpcdf/alexis: can a remote SMTP client (mpcdf) send mail to a valid user on my mail server (alexis@my-mail-server’s-internet-facing-name)
The test results were:
- mutt/imap: ok
- cercis/mpcdf: failed:
Dec 15 11:45:04 mandala postfix/smtpd[10119]: NOQUEUE: reject: RCPT from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216]: 554 5.7.1 Service unavailable; Client host [88.111.68.216] blocked using zen.spamhaus.org; https://www.spamhaus.org/query/ip/88.111.68.216; from=<root@cercis.freemyip.com> to=<alexis.huxley@mpcdf.mpg.de> proto=ESMTP helo=<cercis.freemyip.com>
- mpcdf/alexis: skipped
The digression revisited
By removing the two reject_rbl_client
directives in the setting of smtpd_recipient_restrictions
, I established that this mail that should be relayed is not being checked against smtpd_relay_restrictions
, but rather it is checked against smtpd_recipient_restrictions
, which is wrong: since (a) cercis is sending mail to alexis.huxley@mpcdf.mpg.de and (b) that domain is not in mydestination
, then the relay rule should apply.
I found somebody asking for help with the same problem but no solution is offered.
Debian 11’s) postconf(5) suggests that that person and I are right to be puzzled:
smtpd_relay_restrictions (default: permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination)
Access restrictions for mail relay control that the Postfix SMTP server applies in the context of the RCPT TO command, before smtpd_recipient_restrictions. See SMTPD_ACCESS_README, section “Delayed evaluation of SMTP access restriction lists” for a discussion of evaluation context and time.
Note that “before”.
Googling ‘smtpd_recipient_restrictions
processed before smtp_relay_restrictions
‘ sent me to this page, which includes:
smtpd_relay_before_recipient_restrictions (default: see “postconf -d” output)
Evaluate smtpd_relay_restrictions before smtpd_recipient_restrictions. Historically, smtpd_relay_restrictions was evaluated after smtpd_recipient_restrictions, contradicting documented behavior.
Background: the smtpd_relay_restrictions feature is primarily designed to enforce a mail relaying policy, while smtpd_recipient_restrictions is primarily designed to enforce spam blocking policy. Both are evaluated while replying to the RCPT TO command, and both support the same features.
This feature is available in Postfix 3.6 and later.
but:
mandala# postconf -d | grep smtpd_recipient_restrictions mandala#
and indeed, by Postfix is too old to have this setting:
mandala# dpkg -l | grep postfix ii postfix 3.5.6-1+b1 amd64 High-performance mail transport agent mandala#
So the meaning of the two directives is:
- smtpd_recipient_restrictions: restrictions for local and relayed mail
- smtpd_relay_restrictions: additional restrictions only for relayed mail
Are there any other smtp_*_restriction
s that might be helpful? Perhaps something like smtp_notrelay_restrictions
?
mandala# man 5 postconf | grep '^smtpd_[^ ]*_restrictions' smtpd_client_restrictions (default: empty) smtpd_data_restrictions (default: empty) smtpd_end_of_data_restrictions (default: empty) smtpd_etrn_restrictions (default: empty) smtpd_helo_restrictions (default: empty) smtpd_recipient_restrictions (default: see postconf -d output) smtpd_relay_restrictions (default: permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination) smtpd_sender_restrictions (default: empty) mandala#
smtpd_client_restrictions
would apply to google, not to a mail sent by a spammer to alexishuxley@gmail.com, so I think it is not useful.
smtpd_sender_restrictions
would not help as senders are commonly faked.
How about I revert to using only smtpd_recipient_restrictions
but now with the understanding that it’s also for relayed mail?
# Restrictions for local *and* relayed mail. smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unverified_recipient, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit # No *additional* restrictions for relaying. #smtpd_relay_restrictions =
I ran my tests:
- mutt/imap: ok
- cercis/mpcdf: ok
- mpcdf/alexis: failed:
Dec 15 13:48:07 mandala postfix/smtpd[13116]: NOQUEUE: reject: RCPT from a1962.mx.srv.dfn.de[194.95.232.160]: 450 4.1.1 <alexis@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis@pasta.freemyip.com> User doesn't exist: alexis@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis@pasta.freemyip.com> proto=ESMTP helo=<a1962.mx.srv.dfn.de>
It looks like lmtp needs to be told either to drop the ‘@’ sign and fully qualified domain name (FQDN) when it checks if the user is in LDAP, or it needs to be told what FQDNs are valid.
Googling ‘dovecot lmtp drop domain’ turned up a question on stackexchange, which suggests either to set auth_username_format
in /etc/dovecot/conf.d/10-auth.conf:
auth_username_format = %Ln
or to set user_filter
in /etc/dovecot/dovecot-ldap.conf to set:
user_filter = (&(objectClass=posixAccount)(uid=%n)
The auth_username_format’s documentation says:
auth_username_format
Default: %Lu
Values: StringFormatting applied to username before querying the auth database.
You can use the standard variables here.Examples:
%Lu – lowercases the username
%n – drops the domain if one was supplied
%n-AT-%d – changes the “@” symbol into “-AT-” before lookupThis translation is done after the changes specified with the auth_username_translation setting.
and the user_filter’s documentation says:
user_filter
Default: <empty>
Values: String
Filter for user lookup (userdb lookup). See also LDAP Backend Configuration
Below variables can be used.Variable Long name Description
%u %{user} username
%n %{username} user part in user@domain, same as %u if there’s no domain
%d %{domain} domain part in user@domain, empty if user there’s no domainSee Config Variables for full list
Example:
user_filter = (&(objectClass=posixAccount)(uid=%u))
The former looks better because it takes effect slightly earlier. So I added the following to dovecot.conf:
auth_username_format = %Ln
and restarted Dovecot and re-ran my tests:
- mutt/imap: ok
- cercis/mpcdf: ok
- mpcdf/alexis: failed
Dec 15 14:19:10 mandala postfix/smtpd[13394]: NOQUEUE: reject: RCPT from c1962.mx.srv.dfn.de[194.95.238.160]: 450 4.1.1 <alexis@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis@pasta.freemyip.com> User doesn't exist: alexis@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis@pasta.freemyip.com> proto=ESMTP helo=<c1962.mx.srv.dfn.de>
Since that did not work, I reverted that change to dovecot.conf.
It looks like lmtp is still looking up the wrong user. Perhaps auth_username_format
does not apply when the username is coming from Postfix rather than from an IMAP client?
So then I tried the alternative. I changed the following in dovecot-ldap.conf:
#user_filter = uid=%u user_filter = (&(objectClass=posixAccount)(uid=%n))
and restarted Dovecot and re-ran my tests:
- mutt/imap: ok
- cercis/mpcdf: ok
- mpcdf/alexis: failed
Dec 15 14:24:07 mandala postfix/smtpd[13436]: NOQUEUE: reject: RCPT from a1962.mx.srv.dfn.de[194.95.232.160]: 450 4.1.1 <alexis@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis@pasta.freemyip.com> User doesn't exist: alexis@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis@pasta.freemyip.com> proto=ESMTP helo=<a1962.mx.srv.dfn.de>
Since that did not work, I reverted the change to dovecot-ldap.conf.
After some googling, I found a post on the Dovecot mailing list that described running doveadm -u user <user>
to test how Dovecot handles different addresses. So I commented out the setting of auth_username_format
altogether, restarted Dovecot and ran:
mandala# doveadm user -u alexis@pasta.freemyip.com userdb lookup: user alexis@pasta.freemyip.com doesn't exist mandala#
This error was to be expected with the changes I just made.
So then I set:
auth_username_format = %Ln
restarted Dovecot and run the doveadm
command and now it works:
mandala# doveadm user -u alexis@pasta.freemyip.com userdb: alexis@pasta.freemyip.com user : alexis home : /home/alexis uid : 1000 gid : 1000 mandala#
So although when I tested this setting of auth_username_format above, all my tests failed, I do now know that I am on the right track!
Perhaps private/dovecot-lmtp says alexis@pasta.freemyip.com not only in the message but also when it talks to the LDAP server?
As a stupid test, on my LDAP server orzo, I cloned the uid=alexis
entry to uid=alexis@pasta.freemyip.com
:
orzo# shelldap ~ > cd ou=Users ou=Users,~ > ls - uid=alexis - uid=cercis - uid=guest - uid=repomaster - uid=suzie ou=Users,~ > cp uid=alexis uid=alexis@pasta.freemyip.com Success ou=Users,~ >
and then I retried (no need to restart Dovecot), but it made no difference: the test still failed.
Reading further in the same link I ran:
mandala# doveadm auth test alexis@pasta.freemyip.com Password: passdb: alexis@pasta.freemyip.com auth succeeded extra fields: user=alexis original_user=alexis@pasta.freemyip.com mandala#
At this point I felt quite stuck.
Can the Dovecot mailing list help?
Hi, I’m trying to set up Postfix +Dovecot, with Postfix delegating to Dovecot for authentication (with LDAP backend), local user validation (again with LDAP backend) and local email delivery. It’s partly working but ultimately Dovecot reports “User doesn’t exist” with the user mentioned having user@domain format:
Dec 15 15:24:49 mandala postfix/smtpd[13945]: NOQUEUE: reject: RCPT from b1962.mx.srv.dfn.de[194.95.234.160]: 450 4.1.1 <alexis@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis@pasta.freemyip.com> User doesn't exist: alexis@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis@pasta.freemyip.com> proto=ESMTP helo=<b1962.mx.srv.dfn.de>(pasta.freemyip.com is my mailserver’s internet-facing name and name for which I have a LetsEncrypt SSL certificate; mandala.pasta.net is its name on my pasta.net home network; alexis.huxley@mpcdf.mpg.de is from where I sent a test mail, via mailservers at dfn.de.)
However, if I just ask doveadm to check if the user exists then it is okay:
mandala# doveadm user -u alexis@pasta.freemyip.com userdb: alexis@pasta.freemyip.com user : alexis home : /home/alexis uid : 1000 gid : 1000 mandala#Similarly with auth test:
mandala# doveadm auth test alexis@pasta.freemyip.com Password: passdb: alexis@pasta.freemyip.com auth succeeded extra fields: user=alexis original_user=alexis@pasta.freemyip.com mandala#My IMAP client can connect without problems.
As can external clients that authenticate in order to relay mails.
I had already added two fixes to drop the @domain from the user name; this in the dovecot-ldap.conf
user_filter = (&(objectClass=posixAccount)(uid=%n)) pass_filter = (&(objectClass=posixAccount)(uid=%n))and this in dovecot.conf:
auth_username_format = %nI believe that *either* of those fixes makes doveadm work and *should* make Dovecot work too [1] but still it does not.
The relevant parts of main.cf are:
... smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth ... smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unverified_recipient, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit ... mailbox_transport = lmtp:unix:private/dovecot-lmtp ...(I know about the preferred separation between smtpd_recipient_restrictions and smtpd_relay_restrictions, but this is Postfix 3.5.6 and that consults smtpd_recipient_restrictions before smtpd_relay_restrictions, and is not overrulable, making smtpd_relay_restrictions almost pointless [2] [3].)
I’ve reach the tearing-my-hair-out stage. Could anybody advise please?
Version and config info below.
Many thanks!
Alexis
[1] https://serverfault.com/questions/658703/postfix-%E2%86%92-dovecot-lmtp-user-does-not-exist-uiddomain
[2] https://list.postfix.users.narkive.com/DoyVr83m/postfix-3-2-0-during-the-processing-of-the-relays-applies-the-rules-from-smtpd-relay-restrictions
[3] from http://www.postfix.org/postconf.5.html:
smtpd_relay_before_recipient_restrictions (default: see “postconf -d” output)Evaluate smtpd_relay_restrictions before smtpd_recipient_restrictions. Historically, smtpd_relay_restrictions was evaluated after smtpd_recipient_restrictions, contradicting documented behavior.
Background: the smtpd_relay_restrictions feature is primarily designed to enforce a mail relaying policy, while smtpd_recipient_restrictions is primarily designed to enforce spam blocking policy. Both are evaluated while replying to the RCPT TO command, and both support the same features.
This feature is available in Postfix 3.6 and later.
mandala# lsb_release -a No LSB modules are available. Distributor ID: Debian Description: Debian GNU/Linux 11 (bullseye) Release: 11 Codename: bullseye mandala# dpkg -l | egrep '(postfix|dovecot)' ii dovecot-core 1:2.3.13+dfsg1-2 amd64 secure POP3/IMAP server - core files ii dovecot-imapd 1:2.3.13+dfsg1-2 amd64 secure POP3/IMAP server - IMAP daemon ii dovecot-ldap 1:2.3.13+dfsg1-2 amd64 secure POP3/IMAP server - LDAP support ii dovecot-lmtpd 1:2.3.13+dfsg1-2 amd64 secure POP3/IMAP server - LMTP server ii postfix 3.5.6-1+b1 amd64 High-performance mail transport agent mandala# dovecot -n # 2.3.13 (89f716dc2): /etc/dovecot/dovecot.conf # Pigeonhole version 0.5.13 (cdd19fe3) # OS: Linux 5.10.0-9-amd64 x86_64 Debian 11.1 ext4 # Hostname: mandala.pasta.net auth_username_format = %n disable_plaintext_auth = no listen = * mail_location = maildir:/var/mail/maildir/%u:INDEX=/var/mail/indexes/%u mail_privileged_group = mail passdb { args = /etc/dovecot/dovecot-ldap.conf driver = ldap } protocols = imap lmtp service auth { unix_listener /var/spool/postfix/private/auth { group = postfix mode = 0660 user = postfix } } service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix } } ssl = required ssl_cert = </etc/letsencrypt/live/mail.pasta.freemyip.com/fullchain.pem ssl_key = # hidden, use -P to show it userdb { args = /etc/dovecot/dovecot-ldap.conf driver = ldap } mandala# mandala# egrep -v '^ *(#|$)' /etc/dovecot/dovecot-ldap.conf base = ou=Users,dc=pasta,dc=net uris = ldaps://ldap.pasta.freemyip.com/ auth_bind = yes auth_bind_userdn = uid=%u,ou=Users,dc=pasta,dc=net user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid user_filter = (&(objectClass=posixAccount)(uid=%n)) pass_filter = (&(objectClass=posixAccount)(uid=%n)) mandala# mandala# egrep -v '^ *(#|$)' /etc/postfix/main.cf myhostname = mandala.pasta.net inet_interfaces = all mynetworks_style = subnet smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unverified_recipient, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit smtpd_use_tls = yes smtpd_tls_security_level = may smtpd_tls_cert_file = /etc/letsencrypt/live/mail.pasta.freemyip.com/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mail.pasta.freemyip.com/privkey.pem smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3 smtpd_tls_protocols = !SSLv2 !SSLv3 smtp_use_tls = yes smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache smtp_tls_mandatory_protocols = !SSLv2 !SSLv3 smtp_tls_protocols = !SSLv2 !SSLv3 smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_security_options = masquerade_domains = $mydomain masquerade_classes = envelope_sender, header_sender, header_recipient, envelope_recipient local_header_rewrite_clients = permit_mynetworks virtual_alias_maps = hash:/etc/postfix/virtual mydestination = localhost, $mydomain, mail.pasta.freemyip.com, pasta.freemyip.com relayhost = smtp.gmail.com smtp_host_lookup = native alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mailbox_size_limit = 0 mailbox_transport = lmtp:unix:private/dovecot-lmtp recipient_delimiter = + inet_protocols = ipv4 append_dot_mydomain = no compatibility_level = 9999 message_size_limit = 102400000 mandala#
Does this configuration necessitate virtual users?
Before I posted that it dawned on my that ‘virtual’ (a term bandied about in the Postfix documentation), could refer to users that do not have corresponding Unix accounts, which is the case when I stop nslcd. However, after more thought, I concluded:
- virtual was going to be much too complicated (there are so many different directives for main.cf that contain ‘virtual’!)
- probably I would have to tell Postfix how to contact LDAP itself (or at OS level) and one of the points of this whole procedure was to get Postfix to always delegate interactions with LDAP to Dovecot
- telling Postfix to delegate to Dovecot only for user validation and user authentication is probably not sufficient (perhaps Postfix wants to examine a user’s .forward file and so wants to know where
~user
is).
So I think virtual users is not a viable solution.
Which part of Postfix is it that is complaining that it cannot find a user?
The last error message was:
Dec 16 09:40:17 mandala postfix/smtpd[1512]: NOQUEUE: reject: RCPT from b1962.mx.srv.dfn.de[194.95.234.160]: 550 5.1.1 <alexis@pasta.freemyip.com>: Recipient address rejected: User unknown in local recipient table; from=<alexis.huxley@mpcdf.mpg.de> to=<alexis@pasta.freemyip.com> proto=ESMTP helo=<b1962.mx.srv.dfn.de>
It’s smtpd deciding that there is no local user! The recipient restriction that says to ask dovecot/lmtp did not reject the mail, so Dovecot understood that this is a local user (or a mail to be relayed, which would not cause it to reject it). Googling that message ‘User unknown in local recipient table’ turns up some Postfix documentation that says:
As of Postfix version 2.0, the Postfix SMTP server rejects mail for unknown recipients in local domains (domains that match $mydestination or the IP addresses in $inet_interfaces or $proxy_interfaces) with “User unknown in local recipient table”. This feature was optional with earlier Postfix versions.
So smtpd is validating the local user. With nslcd stopped it fails but it nslcd running it succeeds.
Reading further at that link:
The local_recipient_maps parameter specifies lookup tables with all names or addresses of local recipients. A recipient address is local when its domain matches $mydestination, $inet_interfaces or $proxy_interfaces. If a local username or address is not listed in $local_recipient_maps, then the Postfix SMTP server will reject the address with “User unknown in local recipient table”.
So this means that smtpd did not find ‘alexis’ in local_recipient_maps
. So what is local_recipient_maps
? I do not define it in main.cf and the default is:
mandala# postconf -d local_recipient_maps local_recipient_maps = proxy:unix:passwd.byname $alias_maps mandala#
So that explains it! getent passwd alexis
fails when nslcd is not running and succeeds when it is. So what should I set local_recipient_maps
to avoid it delegating to the OS?
postconf(5) says of local_recipient_maps
:
If this parameter is non-empty (the default), then the Postfix SMTP server will reject mail for unknown local users.
To turn off local recipient checking in the Postfix SMTP server, specify “local_recipient_maps =” (i.e. empty).
So should I set local_recipient_maps =
(i.e. without a value)? Well, yes, I think it is safe to do this: remember that the smtpd_recipient_restrictions
already say that if an invalid local user is recipient then the mail is to be rejected, so I think it is safe to say here that we just accept all mails (that are in $mydestination
). So I added:
local_recipient_maps =
and re-ran my test:
- mutt/imap: skipped
- cercis/mpcdf: skipped
- mpcdf/alexis: failed:
Dec 16 10:13:49 mandala postfix/local[1752]: warning: error looking up passwd info for alexis: No such file or directory
Okay, so the local transport agent is complaining now, presumably because it cannot establish some attribute of user alexis that it can establish when nslcd is running; the home directory of the user is the most probable.
But why is the local agent not handing the mail to Dovecot? I have in my main.cf:
#mailbox_command = /usr/lib/dovecot/deliver mailbox_transport = lmtp:unix:private/dovecot-lmtp
(mailbox_command
was my original one; mailbox_transport
was what I added earlier in this procedure.)
Regarding mailbox_transport
postconf(5) says:
Optional message delivery transport that the local(8) delivery agent should use for mailbox delivery to all local recipients, whether or not they are found in the UNIX passwd database.
Whoah! Well, that sounds reasonable, right? But obviously the local transport agent is encountering a problem before it passes the mail on to Dovecot. Perhaps we can get Postfix to pass the mail on to Dovecot earlier, i.e. before the local transport agent does this home lookup (if that is what it is that causes the error) or perhaps we can get Postfix to use Dovecot as the transport!
I believe I need a local_transport
setting (if it is possible to set it to one thing) or local_transports_map
(if it is possible to set it to a list). Indeed local_transport
exists and can I copy the value from mailbox_transport
(and discard mailbox_transport
altogether as that is only used by the Postfix local transport), i.e.:
#mailbox_command = /usr/lib/dovecot/deliver #mailbox_transport = lmtp:unix:private/dovecot-lmtp local_transport = lmtp:unix:private/dovecot-lmtp
I re-ran my tests:
- mutt/imap: ok
- cercis/mpcdf: ok
- mpcdf/alexis: ok
The main question posed by this article is now addressed, but along the way some other questions came up.
Can recipient restriction ordering be improved?
smtpd_recipient_restrictions
is set to:
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unverified_recipient, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit
which leads to a couple of questions:
Mails sent from my work email (mpcdf) to alexis2@pasta.freemip.com (not a valid address) should be rejected by smtpd because of the reject_unverified_recipient
directive, but mails sent from cercis (a remote SMTP client that authenticates) to the same address would be accepted by smtpd because the permit_sasl_authenticated directive is earlier in the list, but then later rejected because when Postfix passes the mail to dovecot/lmtp in its role as the local delivery agent, dovecot/lmtp will reject it, which presumably will trigger a bounce that could have been avoided, right?
Let’s verify:
Dec 16 10:35:16 mandala postfix/smtpd[2565]: connect from b1962.mx.srv.dfn.de[194.95.234.160] Dec 16 10:35:16 mandala postgrey[243]: action=greylist, reason=new, client_name=b1962.mx.srv.dfn.de, client_address=194.95.234.160/32, sender=alexis.huxley@mpcdf.mpg.de, recipient=alexis2@pasta.freemyip.com Dec 16 10:35:16 mandala postfix/smtpd[2565]: NOQUEUE: reject: RCPT from b1962.mx.srv.dfn.de[194.95.234.160]: 450 4.1.1 <alexis2@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis2@pasta.freemyip.com> User doesn't exist: alexis2@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis2@pasta.freemyip.com> proto=ESMTP helo=<b1962.mx.srv.dfn.de> Dec 16 10:35:16 mandala postfix/smtpd[2565]: disconnect from b1962.mx.srv.dfn.de[194.95.234.160] ehlo=2 starttls=1 mail=1 rcpt=0/1 data=0/1 rset=1 quit=1 commands=6/8
Okay, that was a bit unfortunate that postgrey greylisted it, but oddly lmtp did reject it, ah, ok, I get it! postgrey got its message logged
first, but actually ran
second. We know the latter because we can see the order of directives in the setting of smtpd_recipient_restrictions
. Err … but in that case why was postgrey even called at all?
I checked postconf(5) smtpd_recipient_restrictions
and it does not even mention check_policy_service
! I am sure that – perhaps in an earlier version – it was allowed. check_policy_service
is mentioned in the section for smtpd_client_restrictions
(that’s client, not recipient). The man page says to also see the SMTPD_POLICY_README document. Let’s do that, to see if there is any mention of sucj checks being done in parallel or for backward compatibility still allowed to be declared in the recipient restrictions but actually done during the client restriction phase (CONNECT-time, rather than RCTP TO
-time?).
I did not find any reference in SMTPD_POLICY_README to what happened.
However, after a couple of tests, the postgrey program had got used to the ‘alexis2’ address and did not interfere, leaving it to lmtp to reject it:
Dec 16 11:00:27 mandala postfix/smtpd[2612]: connect from b1962.mx.srv.dfn.de[194.95.234.160] Dec 16 11:00:28 mandala postgrey[243]: action=pass, reason=triplet found, client_name=b1962.mx.srv.dfn.de, client_address=194.95.234.160/32, sender=alexis.huxley@mpcdf.mpg.de, recipient=alexis2@pasta.freemyip.com Dec 16 11:00:28 mandala postfix/smtpd[2612]: NOQUEUE: reject: RCPT from b1962.mx.srv.dfn.de[194.95.234.160]: 450 4.1.1 <alexis2@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis2@pasta.freemyip.com> User doesn't exist: alexis2@pasta.freemyip.com (in reply to RCPT TO command); from=<alexis.huxley@mpcdf.mpg.de> to=<alexis2@pasta.freemyip.com> proto=ESMTP helo=<b1962.mx.srv.dfn.de> Dec 16 11:00:28 mandala postfix/smtpd[2612]: disconnect from b1962.mx.srv.dfn.de[194.95.234.160] ehlo=2 starttls=1 mail=1 rcpt=0/1 data=0/1 rset=1 quit=1 commands=6/8
Interestingly, I did not immediately see a bounce mail at MPCDF; just in case it does arrive it was subject ‘test404’). So the right thing happened there.
But what about when I sent it from cercis, which will do SASL authentication and so be permitted due to smtpd_recipient_restrictions
? Indeed:
Dec 16 11:04:36 mandala postfix/smtpd[2618]: connect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] Dec 16 11:04:36 mandala postfix/smtpd[2618]: ED21A42CC: client=88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216], sasl_method=PLAIN, sasl_username=cercis Dec 16 11:04:37 mandala postfix/cleanup[2622]: ED21A42CC: message-id=<20211216100435.F40A9769@cercis.freemyip.com> Dec 16 11:04:37 mandala postfix/qmgr[2507]: ED21A42CC: from=<root@cercis.freemyip.com>, size=611, nrcpt=1 (queue active) Dec 16 11:04:37 mandala postfix/smtpd[2618]: disconnect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 quit=1 commands=8 Dec 16 11:04:37 mandala dovecot: lmtp(2624): Connect from local Dec 16 11:04:37 mandala postfix/lmtp[2623]: ED21A42CC: to=<alexis2@pasta.freemyip.com>, relay=mandala.pasta.net[private/dovecot-lmtp], delay=0.32, delays=0.19/0.01/0.07/0.05, dsn=5.1.1, status=bounced (host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis2@pasta.freemyip.com> User doesn't exist: alexis2@pasta.freemyip.com (in reply to RCPT TO command)) Dec 16 11:04:37 mandala dovecot: lmtp(2624): Disconnect from local: Client has quit the connection (state=READY) Dec 16 11:04:37 mandala postfix/cleanup[2622]: 3F63F4587: message-id=<20211216100437.3F63F4587@mandala.pasta.net> Dec 16 11:04:37 mandala postfix/bounce[2625]: ED21A42CC: sender non-delivery notification: 3F63F4587 Dec 16 11:04:37 mandala postfix/qmgr[2507]: 3F63F4587: from=<>, size=2762, nrcpt=1 (queue active) Dec 16 11:04:37 mandala postfix/qmgr[2507]: ED21A42CC: removed Dec 16 11:04:38 mandala postfix/smtp[2626]: 3F63F4587: to=<root@cercis.freemyip.com>, relay=smtp.gmail.com[173.194.76.109]:25, delay=1.7, delays=0.02/0.02/0.59/1.1, dsn=2.0.0, status=sent (250 2.0.0 OK 1639649078 l26sm4024502wms.15 - gsmtp) Dec 16 11:04:38 mandala postfix/qmgr[2507]: 3F63F4587: removed
The mail was accepted for delivery and smtpd closed the connection with the client, so the client thinks it is going to be delivered. Only later does lmtp complain that it cannot save the mail into alexis2’s INBOX and postfix/bounce sends a bounce to root@cercis.freemyip.com. Ok, it will not be able to delivery that, but that is smtp.gmail.com’s problem to deal with.
But could we avoid that unnecessary bounce by re-ordering the restrictions so that reject_unverified_recipient
appears before permit_sasl_authenticated
? But does reject_unverified_recipient
cause mails that are to be relayed to be rejected because they do not match local users?
Let’s try:
smtpd_recipient_restrictions = reject_unverified_recipient, permit_sasl_authenticated, permit_mynetworks, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit
cercis–>alexis2@pasta.freemyip.com:
Dec 16 11:11:27 mandala postfix/smtpd[2811]: connect from unknown[141.98.10.220] Dec 16 11:11:27 mandala postfix/smtpd[2811]: warning: unknown[141.98.10.220]: SASL LOGIN authentication failed: Invalid authentication mechanism Dec 16 11:11:27 mandala postfix/smtpd[2811]: disconnect from unknown[141.98.10.220] ehlo=1 auth=0/1 quit=1 commands=2/3 Dec 16 11:12:19 mandala postfix/smtpd[2811]: connect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] Dec 16 11:12:19 mandala postfix/smtpd[2811]: NOQUEUE: reject: RCPT from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216]: 450 4.1.1 <alexis2@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis2@pasta.freemyip.com> User doesn't exist: alexis2@pasta.freemyip.com (in reply to RCPT TO command); from=<root@cercis.freemyip.com> to=<alexis2@pasta.freemyip.com> proto=ESMTP helo=<cercis.freemyip.com> Dec 16 11:12:19 mandala postfix/smtpd[2811]: disconnect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] ehlo=2 starttls=1 auth=1 mail=1 rcpt=0/1 data=0/1 rset=1 quit=1 commands=7/9
That looks good. Interestingly, cercis mail logs said:
Dec 16 11:12:18 cercis postfix/pickup[8528]: B52D876F: uid=0 from=<root> Dec 16 11:12:18 cercis postfix/cleanup[8930]: B52D876F: message-id=<20211216101218.B52D876F@cercis.freemyip.com> Dec 16 11:12:18 cercis postfix/qmgr[1130]: B52D876F: from=<root@cercis.freemyip.com>, size=387, nrcpt=1 (queue active) Dec 16 11:12:19 cercis postfix/smtp[8932]: B52D876F: to=<alexis2@pasta.freemyip.com>, relay=mail.pasta.freemyip.com[188.192.9.35]:25, delay=1, delays=0.07/0.04/0.84/0.1, dsn=4.1.1, status=deferred (host mail.pasta.freemyip.com[188.192.9.35] said: 450 4.1.1 <alexis2@pasta.freemyip.com>: Recipient address rejected: unverified address: host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <alexis2@pasta.freemyip.com> User doesn't exist: alexis2@pasta.freemyip.com (in reply to RCPT TO command) (in reply to RCPT TO command))
Note the status=deferred
! So the mail queue … err … yes, the mailq
command shows the mail sitting on cercis waiting for another attempt.
Okay, so that test looks good now, but what about when cercis wants to relay mails through my mail server?
cercis–>mpcdf:
Dec 16 11:18:08 mandala postfix/smtpd[2828]: connect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] Dec 16 11:18:08 mandala postfix/smtpd[2828]: 924B6420C: client=88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216], sasl_method=PLAIN, sasl_username=cercis Dec 16 11:18:08 mandala postfix/cleanup[2835]: 924B6420C: message-id=<20211216101808.16E9376E@cercis.freemyip.com> Dec 16 11:18:08 mandala postfix/qmgr[2809]: 924B6420C: from=<root@cercis.freemyip.com>, size=611, nrcpt=1 (queue active) Dec 16 11:18:08 mandala postfix/smtpd[2828]: disconnect from 88-111-68-216.dynamic.dsl.as9105.com[88.111.68.216] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 quit=1 commands=8 Dec 16 11:18:10 mandala postfix/smtp[2838]: 924B6420C: to=<alexis.huxley@mpcdf.mpg.de>, relay=smtp.gmail.com[173.194.76.108]:25, delay=2.1, delays=0.07/0.03/0.64/1.3, dsn=2.0.0, status=sent (250 2.0.0 OK 1639649890 m36sm4207359wms.25 - gsmtp) Dec 16 11:18:10 mandala postfix/qmgr[2809]: 924B6420C: removed
So the right thing happened: ‘alexis.huxley’ is not a local user but did not cause a rejection because reject_unverified_recipient
is only checking when the domain matches something in $mydestination
. Does postconf(5) confirm that is what reject_unverified_recipient
does?
It is not clear because it says this is delegated to the verify(8) Postfix subsystem and I did not read that far. But what it did say was this:
The unverified_recipient_reject_code parameter specifies the numerical response code when an address is known to bounce (default: 450, change into 550 when you are confident that itis safe to do so).
Since Dovecot and Postfix have their own LDAP configuration, can I remove the OS’s LDAP configuration?
I have deleted much of the original progress log stored here as it was very incoherent and complicated by use of PCMS. A summary is presented instead.
Without the following line in /etc/ldap/ldap.conf:
TLS_CACERT /etc/ssl/certs/ca-certificates.crt
mail does not work. But it looks like I can tell Dovecot directly about the certificate authorities instead; I added this to dovecot-ldap.conf:
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
and re-commented-out the line in /etc/ldap/ldap.conf, at which point there are no ldap processes or files outside of Dovecot.
Is it only the Postfix local delivery agent that understands aliases?
/etc/aliases specifies that mail to root should be sent to alexis.
I ran tests:
- mpcdf—>root@pasta.freemyip.com: greylisted (okay, I suspect)
- alexis@pasta—>root: ok
which worked!
main.cf contains:
alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases
which raises some questions:
- are both needed?
- why do they work at all now that Postfix’s local transport is not involved?
postconf(5) does not really clarify this but does suggest that the local transport agent is still involved. I think I need simply to test it but removing things.
First I send a few mails from work to root@pasta.freemyip.com to get past the greylisting. Then by setting:
#alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliasesxxx
I was able to show that the newaliases
command reads alias_database
:
mandala# newaliases postalias: fatal: open /etc/aliasesxxx: No such file or directory mandala#
so we should set:
alias_database = hash:/etc/aliases
in order that the newaliases
command works and that the aliases file is where we expect it to be. However:
mandala# postconf -d alias_database alias_database = hash:/etc/aliases mandala#
I.e. if that is what we are going to set it to then we do not need to set it explicitly at all. So we will comment alias_database
out.
Regarding alias expansion, is it enough to set alias_database
?
I had not realised it but I still had this entry:
virtual_alias_maps = hash:/etc/postfix/virtual
and:
mandala# cat /etc/postfix/virtual root alexis@pasta.net mandala#
So I think that that is why it worked!
When I commented out virtual_alias_maps
and uncommented back in the alias_database
and alias_maps
then mail to root@pasta.freemyip.com failed as follows:
Dec 16 14:34:51 mandala postfix/smtpd[21012]: connect from b1962.mx.srv.dfn.de[194.95.234.160] Dec 16 14:34:52 mandala postgrey[250]: action=pass, reason=triplet found, client_name=b1962.mx.srv.dfn.de, client_address=194.95.234.160/32, sender=alexis.huxley@mpcdf.mpg.de, recipient=root@pasta.freemyip.com Dec 16 14:34:52 mandala postfix/smtpd[21012]: 337CD420D: client=b1962.mx.srv.dfn.de[194.95.234.160] Dec 16 14:34:52 mandala postfix/cleanup[21017]: 337CD420D: message-id=<20211216133449.u4ckhgnkjhnmtlvt@damson.rzg.mpg.de> Dec 16 14:34:52 mandala postfix/qmgr[21010]: 337CD420D: from=<alexis.huxley@mpcdf.mpg.de>, size=1393, nrcpt=1 (queue active) Dec 16 14:34:52 mandala postfix/smtpd[21012]: disconnect from b1962.mx.srv.dfn.de[194.95.234.160] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7 Dec 16 14:34:52 mandala dovecot: lmtp(21019): Connect from local Dec 16 14:34:52 mandala postfix/lmtp[21018]: 337CD420D: to=<root@pasta.freemyip.com>, relay=mandala.pasta.net[private/dovecot-lmtp], delay=0.37, delays=0.33/0.01/0.01/0.03, dsn=5.1.1, status=bounced (host mandala.pasta.net[private/dovecot-lmtp] said: 550 5.1.1 <root@pasta.freemyip.com> User doesn't exist: root@pasta.freemyip.com (in reply to RCPT TO command)) Dec 16 14:34:52 mandala dovecot: lmtp(21019): Disconnect from local: Client has quit the connection (state=READY) Dec 16 14:34:52 mandala postfix/cleanup[21017]: 4896444DC: message-id=<20211216133452.4896444DC@mandala.pasta.net> Dec 16 14:34:52 mandala postfix/qmgr[21010]: 4896444DC: from=<>, size=3529, nrcpt=1 (queue active) Dec 16 14:34:52 mandala postfix/bounce[21020]: 337CD420D: sender non-delivery notification: 4896444DC Dec 16 14:34:52 mandala postfix/qmgr[21010]: 337CD420D: removed Dec 16 14:34:53 mandala postfix/smtp[21021]: 4896444DC: to=<alexis.huxley@mpcdf.mpg.de>, relay=smtp.gmail.com[173.194.76.108]:25, delay=1.3, delays=0.02/0.02/0.57/0.74, dsn=2.0.0, status=sent (250 2.0.0 OK 1639661693 n4sm5038645wrc.1 - gsmtp) Dec 16 14:34:53 mandala postfix/qmgr[21010]: 4896444DC: removed
It is interesting that lmtp did not reject the mail for smtpd but it did reject it when it came to try to save it in the inbox, which, because smtpd had already hung up the connection, meant a bounce was triggered.
So now we know this:
- with the default values for
alias_database
,alias_maps
andvirt_alias_maps
and withroot: alexis
in /etc/aliases (and newaliases having been run) mail to root is not delivered, implying that lmtp does not read aliases - newliases reads
alias_database
to find out what to rebuild - with
virtual_alias_maps
set then Postfix redirects mail saving it locally (and we knew ages ago that Postfix would redirect it remotely using this file)
So a configuration comes to mind:
alias_database = hash:/etc/aliases alias_maps = virt_alias_maps = hash:/etc/aliases
This way /etc/aliases becomes not only for local mail, newaliases knows to regenerate it and we do not create unnecessary extra maps.
It did not work: mail to root@pasta.freemyip.com was rejected. Changing virt_alias_maps
back to /etc/postfix/virtual, which contained:
mandala# cat /etc/postfix/virtual root alexis@pasta.net mandala#
worked.
Hmm … so either virt_alias_maps
wants the maps to have entries of form user@domain (not just user) or it is unhappy about sharing its value with alias_database
and alias_maps
.
Let’s set it back to hash:/etc/aliases but put fully qualified right hand sides in. That worked!
So now let’s extend the test with this in aliases:
root: alexis@pasta.net www-data: root test: alexis.huxley@mpcdf.mpg.de
and try sending mails to those three addresses from outside:
- root: ok
- www-data: ok (after greylisting)
- test: ok (after greylisting)
So this configuration works:
virtual_alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases alias_maps = hash:/etc/aliases
But I think that alias_database should be redundant, so I set:
alias_database =
and I re-ran my testts:
- root: ok
- www-data: ok
- test: ok
Conclusions
Postfix can be made to delegate both validation and authentication to Dovecot!