This server (tarragon) runs a postfix instance which provides mail service for my own wmbuck.net as well as for about a dozen other domains belonging to friends and clients. Postfix offers three different ways that a server can receive (be the final destination for) mail directed to a domain:
1) as what postfix calls the canonical destination (i.e. mail for firstname.lastname@example.org) where tarragon IS wmbuck.net, and each mail recipient maps onto a user who has a login account on the server, and messages are delivered to that account;
2) as a virtual alias destination, where mail directed to email@example.com is accepted, but for each such address there is a corresponding forward address to some other location firstname.lastname@example.org or something, and the actual mail messages do not reside on the server; and finally
3) as a virtual mailbox destination, where mail directed to email@example.com arrives and is stored in mailboxes on tarragon, awaiting pickup/reading by the user, but without requiring that there be a user z with an actual login account on tarragon. This requires that the mail store on tarragon be set up to maintain different sets of mailboxes for different domains. There can be a user firstname.lastname@example.org and another user email@example.com and the mail is not intermixed.
Tarragon uses cyrus-imap as the mail store, and it provides the ability to have different mailboxes for different domains. To support that, the mailboxes are actually constructed differently, so that cyrus-imap can have a mailbox fred, but can also have a mailbox firstname.lastname@example.org.
This requires, in turn, that the imap server be able to identify the correct mailbox when a mail client attaches, and be able to separately authenticate for each mailbox. When cyrus-imap is configured to support this separation, it requires that the username on login be email@example.com, rather than simply fred.
Cyrus-imap uses the saslauthd daemon to authenticate, and saslauthd in turn calls upon pam, passing in the username, password and realm (domain) received from imap (or postfix for smtp, or apache for website auth), who receives it in the login message from the user’s mail client. Pam’s authentication for mail is set to use a module called pam_mysql, which is able to match against credentials in a mysql database.
Here is where things get tricky. Take the mail account firstname.lastname@example.org. There is also a user dee with a system account (i.e a type 1 canonical mail account email@example.com). I can choose either to have a) only one entry in the database, for user dee, with a password. That same entry is consulted for access to either mailbox (firstname.lastname@example.org or email@example.com) but the are still separate mailboxes. Or alternatively, b) I can have different database entries for dee and firstname.lastname@example.org, each with its own password.
A digression: I could, and for many years did, choose to list thegraygeek.com as a canonical final destination in postfix. If I do that, then mail for email@example.com goes into the mailbox for user dee on tarragon, just the same as mail for firstname.lastname@example.org. They go into the same mailbox. But when I began supporting virtual mailbox domains, I separated them – using the gray geek account as a test case for hosting virtual mailbox domains.
Originally I set it up with the idea that there would be seapate database entries. With them separated, an imap login for user dee at host wmbuck.net will attach to the mailbox for the user dee, while an imap login for user email@example.com at host wmbuck.net will attach to the mailbox for user firstname.lastname@example.org who does not have an account on tarragon.
I set all this up over a year ago, and it seemed to be working. Then I set up a new account for a friend who had a new domain name. And I discovered that I had a problem. It so happened that in every case where I had created a mailbox of the form email@example.com, I actually also had an account fred on wmbuck.net, many of those never used and left over from the days when I was only doing canonical logins. I discovered that even though I had entries in the database for login as firstname.lastname@example.org, the login process was actually using the database entry for fred. It so happened that all these accounts (fred and fred@) had the same password. As soon as I added an account bob@ which did NOT have a corresponding server login account bob, with the same password, it failed.
When I tried using testsaslauthd -u email@example.com -p <pw> it would work, so the pam machinery and the pam_mysql plugin were working right. The problem occurred between cyrus-imap and saslauthd. I discovered that (a) cyrus imap takes an incoming username of a@b and separates it into “username” and “realm”, and passes those separately to saslauthd, and (b) saslauthd has a parameter ‘-r’ which I had previously failed to discover, which causes it to append the incoming ‘realm’ to the incoming ‘username’ when it attempts to authenticate. Without the ‘-r’ parameter, saslauthd was using only the incoming ‘username’ – fred or bob, in its call on pam. If there was such an account and the password matched, saslauthd would succeed, and the connection would be permitted. Note that cyrus-imapd would now actually connect to the correct mailbox – the issue was that it used the wrong database entry to authenticate against.
Once I turned on the ‘-r’ parameter to saslauthd, imap works for both dee and firstname.lastname@example.org, but I get a problem in smtp. On the call from smtp->saslauthd->pam_mysql when saslauthd has the -r parameter simply ‘dee’ as the username will not authenticate. The log record coming from pam_mysql indicates the username comes across as ‘dee’, but fails. If I create a database entry for email@example.com, and set the username on smtp to firstname.lastname@example.org, it works.
After a couple of weeks, I began to change my mind. The database is used for several kinds of logins. Going this way – with separate logins for email@example.com and bob meant: I have to have 2 records in the database. Bob could get confused if he changed his password on one but not the other. For some users I could probably just delete the ‘bob’ entry, and force bob to type in his full email address in order to log in for other things. But I decided this was unappealing.
So I have turned off the ‘r’ parameter, and eliminated all the entries that say firstname.lastname@example.org from the database. Bob must still use his full email address when connecting to imap but for plain logins in other places, he can use just bob. This also means I no longer have to have a separate database record for canonical mail users to do smtp.