Introduction
I’m using Dovecot on Debian 10 and switching the userdb/passdb backend from NIS to LDAP, mainly because I want to learn about LDAP.
If users’ home directories are not in the standard place, then Dovecot needs to be told how to extract their locations out of LDAP. We do this in dovecot-ldap.conf (or dovecot-ldap.conf.ext depending on your setup) with something like:
user_attrs = homeDirectory=home
This means “a user’s home can be found in the homeDirectory attribute within the user’s entry in the regular DIT”. So we need to give dovecot access to this attribute in LDAP. Later I realised that Dovecot knows about this location by default, but there are other things Dovecot may need to know (e.g. a user’s mail quota) that it does not know the location of in the LDAP database by default, so it remained a useful excercise to do.
The dovecot wiki explains how it can be done using slapd.conf, but I wanted to do it using the ‘cn=config’/ldapmodify method.
This page exists in the hope that it helps people googling about this problem.
What I tried
I started by examining what the RTC DIT says about the regular DIT:
ziti# ldapsearch -Y EXTERNAL -H ldapi:/// -W -b 'cn=config' -LLL "(objectClass=olcDatabaseConfig)" ... dn: olcDatabase={1}mdb,cn=config ... olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none olcAccess: {1}to attrs=shadowLastChange by self write by * read olcAccess: {2}to * by * read ... ziti#
I’m unsure if that to * by * read
applied to all users or only authenticated users so I tested by running:
ziti# ldapwhoami -x anonymous ziti# ldapsearch -x -b uid=alexis,ou=Users,dc=pasta,dc=net | grep homeDirectory homeDirectory: /home/alexis ziti#
which shows that I login (“bind”) to LDAP anonymously (using -x
without -W
or -w <passwd>
) and that I can read an attribute not explicity treated in a special way by the above ACLs. So, in fact Dovecot already has access to all attributes (and future attributes).
As a reference point, at the start, my dovecot-ldap.conf contains:
base = ou=Users,dc=pasta,dc=net uris = ldap://192.168.1.21/ auth_bind = yes auth_bind_userdn = uid=%u,ou=Users,dc=pasta,dc=net
So now I added to dovecot-ldap.conf:
user_attrs = homeDirectory=home
and restarted Dovecot, started my mail client (mutt) and now dovecot complains:
Error: Couldn't drop privileges: User is missing UID (see mail_uid setting)
So, to tell Dovecot to authenticate with LDAP, I added the following to dovecot.conf (not dovecot-ldap.conf):
mail_uid = dovecot mail_gid = mail
Now dovecot complains:
dovecot: imap(alexis): Error: Mail access for users with UID 111 not permitted (see first_valid_uid in config file, uid from mail_uid setting).
Eh? I’m not trying to access mail as UID 111! On the assumption that Dovecot had decided it couldn’t get the information it wanted anonymously any more and was now trying authenticate itself, I did the following:
- Create file /tmp/dovecot.ldif containing:
dn: cn=dovecot,dc=pasta,dc=net cn: dovecot objectClass: top objectClass: simpleSecurityObject objectClass: organizationalRole userPassword: <password-in-cleartext>
- Run:
ldapadd -x -D cn=admin,dc=pasta,dc=net -W -f /tmp/dovecot.ldif
- In dovecot.conf set:
mail_uid=dovecot mail_gid=mail
- In dovecot-ldap.conf set:
dn = cn=dovecot,dc=pasta,dc=net dnpass = <password-in-cleartext>
- Restart dovecot.
But that didn’t work and I undid it.
Then I wondered if it was because I hadn’t provided a UID for cn=dovecot,dc=pasta,dc=net in LDAP, so I redid those last steps, but this time using LDIF data:
dn: cn=dovecot,ou=Groups,dc=pasta,dc=net objectClass: posixGroup cn: dovecot gidNumber: 5000 description: Group account dn: uid=dovecot,ou=Users,dc=pasta,dc=net objectClass: account objectClass: posixAccount cn: dovecot uid: dovecot uidNumber: 5000 gidNumber: 5000 homeDirectory: /home/dovecot loginShell: /bin/bash gecos: dovecot description: User account
But that made no difference, but it gave me an idea!
Perhaps Dovecot “Couldn’t drop privileges” because my “User is missing UID”, and that because user_attrs was specifying only the home directory attribute mapping!
The solution
Set user_attrs to specify where all of home, uid and gid are in the users’ LDAP records as follows:
user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid