cyrusimap / cyrus-imapd

Cyrus IMAP is an email, contacts and calendar server
http://cyrusimap.org
Other
522 stars 145 forks source link

defaultdomain is case sensitive; rejects mail to user@DOMAIN #3414

Open amessina opened 3 years ago

amessina commented 3 years ago

When beginning the migration from a single domain installation toward the potential future "default" for virtualdomains as suggested in #2847:

virtdomains: userid
deaultdomain: example.com

I found that my system began rejecting mail to user@EXAMPLE.COM or USER@EXAMPLE.COM -- anything with an uppercase domain.

postfix/lmtp[613203]: C9C3DD2575: to=<USER@EXAMPLE.COM>, relay=mail.example.com[/run/cyrus/socket/lmtp], delay=0.02, delays=0/0.01/0.01/0.01, dsn=5.1.1, status=bounced (host mail.example.com[/run/cyrus/socket/lmtp] said: 550-Mailbox unknown.  Either there is no mailbox associated with this 550-name or you do not have authorization to see it. 550 5.1.1 User unknown (in reply to RCPT TO command))

If I switch defaultdomain: example.com (lowercase) to defaultdomain: EXAMPLE.COM (uppercase), mail to user@example.com (lowercase domain) was rejected.

It appears that the defaultdomain is case sensitive and should not be.

Using cyrus-imapd-3.0.13-13.fc33.x86_64

elliefm commented 3 years ago

Hmm, that's strange. Does it behave the same way for other domains, or only for defaultdomain?

Like, if you have

virtdomains: userid
defaultdomain: example.com

and two users, user [@example.com], and another@somethingelse.com, what happens when postfix delivers for another@SOMETHINGELSE.COM? Does Cyrus also reject it due to the case not matching, or does it accept it case-insensitively like you'd expect?

We usually recommend setting defaultdomain to something undeliverable (like "internal", which is also the default value for this setting in more recent Cyrus versions), and only using bare-usernames for admin accounts (e.g. "cyrus") which should not receive mail -- all the real accounts would be created fully-qualified. This would mean renaming all your existing accounts to include the domain, and all those users would need to change how they log in... I guess setting defaultdomain to the existing single-domain seems like it should be a reasonable intermediate step, so it would be nice if it worked smoothly!

There might be a way to downcase the rcpt domain in Postfix, but I'm not familiar with Postfix configuration, and a quick search mostly turned up old mailing lists saying "just do this ..." "no don't do that, it's bad", so I dunno.

amessina commented 3 years ago

Well, I don't have multiple domains, only the default/single domain installation.

With defaultdomain: internal, the mail is delivered correctly for uppercase or lowercase domain, however the issue is that a user that can authenticate with bare username gets folders autocreated without the defaultdomain appended, leading to two separate folder structures.

I appreciate it's best to control auth via fully qualified name, but for a single domain setup where defaultdomain is set to a real domain, bare username and fully qualified username should end up using the same folder structure, else inconsistencies are present.

dilyanpalauzov commented 3 years ago

Does setting lmtp_downcase_rcpt: 1 help?

As described at https://www.cyrusimap.org/imap/reference/faqs/o-mixedcase.html this option is supposed to lowercase also the domain.

Do you have a multi-domain system and are the non-default domains handled in case-insensitive manner? (If you do not have a multi-domain system, I suggest you create one and test on it, so that you can answer the question)

amessina commented 3 years ago

Hi @dilyanpalauzov, lmtp_downcase_rcpt: 1 does appear to downcase the user@domain when virtualdomain support is enabled, but it does not do so for defaultdomain: example.com scenario -- that is essentially what I am reporting...

I have a single domain setup. As a part of my testing I created virtdomains: userid defaultdomain: example.com. I also created mailboxes with user@example.lan.

Mail to user@EXAMPLE.COM was rejected whereas mail to user@EXAMPLE.LAN was accepted.

I also noticed in testing that even if a fully qualified bob@defaultdomain mailbox existed, if mail was received for user@defaultdomain or that user logged in as user rather than bob@defaultdomain, a new mailbox was created at /var/spool/imap/b/user/bob, rather than the /var/spool/imap/domain/e/example.com/b/user/bob location.

dilyanpalauzov commented 3 years ago

Proposed fix:

diff --git a/imap/mboxname.c b/imap/mboxname.c
--- a/imap/mboxname.c
+++ b/imap/mboxname.c
@@ -376,7 +376,7 @@ EXPORTED mbname_t *mbname_from_recipient(const char *recipient, const struct nam
     if (at) {
         mbname->localpart = xstrndup(recipient, at - recipient);
         const char *domain = at+1;
-        if (config_virtdomains && strcmpsafe(domain, config_defdomain))
+        if (config_virtdomains && strcasecmpsafe(domain, config_defdomain))
             mbname->domain = xstrdupnull(domain);
         /* otherwise we ignore domain entirely */

One can do the case-insensitive matching for the domain name, only when lmtp_downcase_rcpt is set, but I see no usecase why mail domains, in particular the default_domain, shall be handled in a case-sensitive manner.

amessina commented 3 years ago

@dilyanpalauzov I'm certainly not an expert on the specs, but is there ever a valid use case for either the username or domain to be case sensitive? It seems like many SMTP implementations in the wild assume user@domain == USER@DOMAIN.

dilyanpalauzov commented 3 years ago

If there is an uppercased folder Xyz, then mails to it shall be directed at user+Xyz@domain.

amessina commented 3 years ago

If there is an uppercased folder Xyz, then mails to it shall be directed at user+Xyz@domain.

@dilyanpalauzov, yes.

cwalther commented 1 year ago

I just ran into the same problem on cyrus-imapd 3.4.2. I have not tried dilyanpalauzov’s patch but it looks sensible. The source of the problem really seems to be that the downcasing induced by lmtp_downcase_rcpt (mbname_downcaseuser()) comes after mbname_from_recipient() checks for equality with the defaultdomain, when conceptually it should come before. Doing that check case-insensitively as the patch proposes is the easiest way out. Alternatively, mbname_downcaseuser() could check for equality with defaultdomain again after downcasing and set the domain to NULL in that case, but that seems more complicated.

vladki77 commented 8 months ago

I have noticed similar behavior. lmtp_downcase_rcpt: yes, username_tolower: 0 (changed to 1) but it had no effect. Mails to fully qualified domains with all-caps are delivered OK. Mails to default domain in all-caps are (dependent on cyrus version): rejected in curus-3.2.6 (550-Mailbox unknown). But in cyrus-3.6.1 mail is delivered, but lmtpd fails: 421 4.3.0 lmtpd: Internal error: assertion failed: imap/mailbox.c: 1314: listitem && &listitem->m == mailbox. Exim thus gets a temporary error, and retries the email for a few days, each try makes a duplicate delivery, and after a few days it sends non-delivery report.

This happens only if the mail address was not touched by any alias processing in Exim. Even a trivial alias "user: user", fixes the case and mail is delivered without problems.

vladki77 commented 8 months ago

Just for completeness, problem is only if the defaultdomain is in uppercase. Username may be in uppercase and delivery is OK: USER@defaultdomain - OK USER@NON_DEFAULTDOMAIN - OK user@DEFAULTDOMAIN - assertion fail USER@DEFAULTDOMAIN - assertion fail

DanielO commented 4 months ago

Any update on this? I just got bit by it today and used the patch as a work around but it would be nice if it were committed.