Skip to content

Add aliases to Dovecot's userdb & Adjust the passdb / userdb configuration#2248

Merged
polarathene merged 11 commits intomasterfrom
dovecot-aliases
Nov 1, 2021
Merged

Add aliases to Dovecot's userdb & Adjust the passdb / userdb configuration#2248
polarathene merged 11 commits intomasterfrom
dovecot-aliases

Conversation

@georglauterbach
Copy link
Copy Markdown
Member

@georglauterbach georglauterbach commented Oct 14, 2021

Description

See #2091 (comment).

Fixes #2091

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (README.md or the documentation under docs/)
  • If necessary I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@georglauterbach georglauterbach added priority/medium service/dovecot area/scripts kind/improvement Improve an existing feature, configuration file or the documentation labels Oct 14, 2021
@georglauterbach georglauterbach added this to the v10.3.0 milestone Oct 14, 2021
@georglauterbach georglauterbach requested a review from a team October 14, 2021 18:02
@georglauterbach georglauterbach self-assigned this Oct 14, 2021
@georglauterbach
Copy link
Copy Markdown
Member Author

@docker-mailserver/maintainers tests pass, all seems well. Not sure why my local systems reported errors. Do I need extra software to run tests these days (like jq)?

@polarathene
Copy link
Copy Markdown
Member

Do I need extra software to run tests these days (like jq)?

jq is required only for the TLS tests, the contributor docs should mention that for running tests.

I looked over this PR earlier today, I didn't provide an approval as I don't know the changes well enough to properly review, but nothing stands out that concerns me. I can provide an approval, just giving time for others to review (we're about to hit the weekend, probably no rush).

@georglauterbach
Copy link
Copy Markdown
Member Author

Alright:)

Take your time, no rush to merge this PR. If you feel like giving an approval, do so, if not, don't :)

Comment thread target/dovecot/auth-passwdfile.inc
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
@georglauterbach
Copy link
Copy Markdown
Member Author

@casperklein all of your suggestions are valid, I just didn't have the time yet. Will tend to it ASAP.

Comment thread target/scripts/startup/setup-stack.sh
Comment thread target/scripts/startup/setup-stack.sh
Comment thread target/scripts/startup/setup-stack.sh
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh
@casperklein
Copy link
Copy Markdown
Member

casperklein commented Oct 20, 2021

IIRC there was a bat test in another issue, which could reproduce the problem (cannot find it right now 😞). It might be a good idea to add the test for this?

@andrewlow Do you have a working bats test, to reproduce the issue that this PR is going to fix?

polarathene
polarathene previously approved these changes Oct 21, 2021
@andrewlow
Copy link
Copy Markdown
Contributor

@casperklein No - I'm sorry - the sum of my .bat test efforts were captured in the issue: #2091 (comment)

Unfortunately my unfamiliarity with the test structure and the alias problem at a technical level doesn't give me confidence that my test is useful.

@polarathene
Copy link
Copy Markdown
Member

Unfortunately my unfamiliarity with the test structure and the alias problem at a technical level doesn't give me confidence that my test is useful.

I think there's enough info for me to take a stab at it, I might have time to in the weekend.

@andrewlow
Copy link
Copy Markdown
Contributor

FWIW - there are some existing tests for aliases in the testing framework.

I was trying to create something specific to detect the dovecot error saying "I don't know who this alias is" - then later once the alias is mapped - the mail is delivered.

@georglauterbach
Copy link
Copy Markdown
Member Author

Unfortunately my unfamiliarity with the test structure ...

I think there's enough info for me to take a stab at it, I might have time to in the weekend.

That's be great! I will see whether final code cleanup is needed after all the new comments :)

@polarathene
Copy link
Copy Markdown
Member

polarathene commented Oct 23, 2021

Reproduction

Based on the test example from @andrewlow . Not presently adapted to a bats test.

# Clone PR branch
git clone https://github.com/docker-mailserver/docker-mailserver --branch dovecot-aliases --recurse-submodules

# Build image:
cd docker-mailserver
make build

# Create the accounts and duplicate config directory for container to use:
make generate-accounts
mkdir -p test/duplicate_configs/x_alias/
rsync -a test/config/ test/duplicate_configs/x_alias/

# Initialize the test container:
docker run --rm -itd --name "alias_test" \
  --hostname "mail.my-domain.com" \
  --volume "${PWD}/test/test-files:/tmp/docker-mailserver-test:ro" \
  --volume "${PWD}/test/duplicate_configs/x_alias:/tmp/docker-mailserver" \
  "mailserver-testing:ci"

# Send mail to local alias `[email protected]` from external `[email protected]`
docker exec alias_test sh -c 'nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-alias-local.txt'

# Check for failure (result is 1):
docker logs alias_test | grep 'dovecot: auth: passwd-file([email protected]): unknown user' | wc -l
# 1

Info

docker logs alias_test output:

Oct 23 21:16:37 mail postfix/master[943]: daemon started -- version 3.4.14, configuration /etc/postfix
Oct 23 21:17:20 mail postfix/postscreen[1173]: cache btree:/var/lib/postfix/postscreen_cache full cleanup: retained=0 dropped=0 entries
Oct 23 21:17:20 mail postfix/postscreen[1173]: CONNECT from [127.0.0.1]:38234 to [127.0.0.1]:25
Oct 23 21:17:20 mail postfix/postscreen[1173]: WHITELISTED [127.0.0.1]:38234
Oct 23 21:17:20 mail postfix/smtpd[1174]: connect from localhost[127.0.0.1]
Oct 23 21:17:20 mail opendmarc[240]: ignoring connection from localhost
Oct 23 21:17:20 mail postfix/smtpd[1174]: improper command pipelining after HELO from localhost[127.0.0.1]: MAIL FROM: [email protected]\nRCPT TO: [email protected]\nDATA\nFrom: Docker Mail Server <do
Oct 23 21:17:20 mail postfix/smtpd[1174]: 47E059F0679: client=localhost[127.0.0.1]
Oct 23 21:17:20 mail postfix/cleanup[1179]: 47E059F0679: message-id=<[email protected]>
Oct 23 21:17:20 mail opendkim[234]: 47E059F0679: no signing table match for '[email protected]'
Oct 23 21:17:20 mail opendkim[234]: 47E059F0679: no signature data
Oct 23 21:17:20 mail postfix/qmgr[947]: 47E059F0679: from=<[email protected]>, size=516, nrcpt=1 (queue active)
Oct 23 21:17:20 mail postfix/smtpd[1174]: disconnect from localhost[127.0.0.1] helo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
Oct 23 21:17:20 mail postfix/smtpd[1182]: connect from localhost[127.0.0.1]
Oct 23 21:17:20 mail postfix/smtpd[1182]: 5B7419F0682: client=localhost[127.0.0.1]
Oct 23 21:17:20 mail postfix/cleanup[1179]: 5B7419F0682: message-id=<[email protected]>
Oct 23 21:17:20 mail postfix/qmgr[947]: 5B7419F0682: from=<[email protected]>, size=506, nrcpt=1 (queue active)
Oct 23 21:17:20 mail amavis[318]: (00318-01) Passed CLEAN {RelayedInbound}, [127.0.0.1]:38234 <[email protected]> -> <[email protected]>, Queue-ID: 47E059F0679, Message-ID: <[email protected]>, mail_id: 2XGeI-msw1kd, Hits: -, size: 289, queued_as: 5B7419F0682, 70 ms
Oct 23 21:17:20 mail postfix/smtp[1180]: 47E059F0679: to=<[email protected]>, orig_to=<[email protected]>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.1, delays=0.01/0.01/0.01/0.07, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 5B7419F0682)
Oct 23 21:17:20 mail postfix/qmgr[947]: 47E059F0679: removed
Oct 23 21:17:20 mail dovecot: lmtp(1184): Connect from local
Oct 23 21:17:20 mail dovecot: auth: passwd-file([email protected]): unknown user 
Oct 23 21:17:20 mail postfix/lmtp[1183]: 5B7419F0682: to=<[email protected]>, relay=mail.my-domain.com[/var/run/dovecot/lmtp], delay=0.05, delays=0/0.02/0.01/0.01, dsn=5.1.1, status=bounced (host mail.my-domain.com[/var/run/dovecot/lmtp] said: 550 5.1.1 <[email protected]> User doesn't exist: [email protected] (in reply to RCPT TO command))
Oct 23 21:17:20 mail dovecot: lmtp(1184): Disconnect from local: Client has quit the connection (state=READY)
Oct 23 21:17:20 mail postfix/cleanup[1179]: 66D359F0685: message-id=<[email protected]>
Oct 23 21:17:20 mail postfix/qmgr[947]: 66D359F0685: from=<>, size=2606, nrcpt=1 (queue active)
Oct 23 21:17:20 mail postfix/bounce[1185]: 5B7419F0682: sender non-delivery notification: 66D359F0685
Oct 23 21:17:20 mail postfix/qmgr[947]: 5B7419F0682: removed
Oct 23 21:17:20 mail postfix/smtp[1187]: 66D359F0685: to=<[email protected]>, relay=none, delay=0.02, delays=0/0.02/0/0, dsn=5.4.4, status=bounced (Host or domain name not found. Name service error for name=external.tld type=AAAA: Host not found)
Oct 23 21:17:20 mail postfix/qmgr[947]: 66D359F0685: removed

setup alias list output:

setup email list output:

* [email protected] ( 0 / ~ ) [0%]
    [ aliases -> [email protected], @localdomain2.com]

* [email protected] ( 0 / ~ ) [0%]

* [email protected] ( 0 / ~ ) [0%]

doveadm(# this is a test comment, please don't delete me :'(): Error: User doesn't exist
/usr/local/bin/listmailuser: line 12: 1024 *  : syntax error: operand expected (error token is "*  ")
/usr/local/bin/listmailuser: line 12: 1024 *  : syntax error: operand expected (error token is "*  ")
* # this is a test comment, please don't delete me :'( (  /  ) [%]
    [ aliases -> #]

doveadm(# this is also a test comment, :O): Error: User doesn't exist
/usr/local/bin/listmailuser: line 12: 1024 *  : syntax error: operand expected (error token is "*  ")
/usr/local/bin/listmailuser: line 12: 1024 *  : syntax error: operand expected (error token is "*  ")
* # this is also a test comment, :O (  /  ) [%]
    [ aliases -> #]

cat test/test-files/email-templates/existing-alias-local.txt:

HELO mail.external.tld
MAIL FROM: [email protected]
RCPT TO: [email protected]
DATA
From: Docker Mail Server <[email protected]>
To: Existing Local Alias <[email protected]>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-alias-local.txt
This is a test mail.

.
QUIT

Observations

  • The alias is used with a FQDN (localhost.localdomain) in Postfix $mynetworks to accept IIRC, and maps to an account for the FQDN otherdomain.tld (FQDN might not be the right word here but w/e).
  • The email template existing-alias-local.txt has MAIL FROM and From values with different accounts at the external.tld FQDN.
  • This is a local IP so is handled differently for SMTP arrivals I think, unlike the issue this PR is intended for with external IP sending mail to an alias. So may not be a reliable reproduction of the problem.
  • We can see that the alias is for an external account, it lacks a local account managed by the server beyond the alias though and I assume that's a problem (which postfix/lmtp later implies perhaps with "User doesn't exist: [email protected]"?), unless that's a non-issue?
  • Log suggests the docker-server container is relaying the mail instead? I really don't know much about the alias setup stuff, I am aware of our docs having an example guide where at the bottom they have two alias examples to relay to gmail, one which has nested/chained aliases.
  • A lookup is performed for external.tld and fails.

Would it be right to assume that Postfix delegated to Dovecot for auth to check if the alias had an account/mailbox managed by docker-mailserver to deliver to, reported that [email protected] wasn't managed by docker-mailserver and thus Postfix tried to relay, but failed to lookup the IP due to invalid FQDN?

At least that is the impression I got, that no authentication was being attempted/failed, just checking with Dovecot if the user was managed by the mailserver. So no value in making the above an actual test?

I'd need to modify the test method to have a local account for the alias, and possibly send from an IP that isn't considered local to docker-mailserver.


EDIT: Regarding remote/local SMTP client connecting to Postfix, I assume the Dovecot auth part is what these Postfix SASL docs are about?

@polarathene polarathene mentioned this pull request Oct 23, 2021
11 tasks
@georglauterbach
Copy link
Copy Markdown
Member Author

I wonder if we should change the default for ENABLE_QUOTAS back to zero (disabled).

Asked myself the same question. I think would be a good thing to do.

@polarathene
Copy link
Copy Markdown
Member

It still strikes me as somewhat wrong - the quota check appears to happen too early - before the email has been resolved to the actual destination.

Please see my reference notes comment here, specifically the larger quote block about what the quota-status check_policy_service is doing.

This happens before Postfix hands anything off to Dovecot, and before it accepts mail. It is using the RCPT TO part of the SMTP protocol exchange, this alias is not expanded at this stage and there doesn't appear to be any way to configure it to do so, without us proxying the quota-status service ourselves to perform the alias lookup to ask Dovecot to check the correct user quota policy.

So the quota check is happening at the correct point in time, it's just check_policy_service is only provided with the original recipient as data, no additional processing is done at this stage by Postfix and there doesn't appear to be any obvious way to invoke the alias expansion during the restriction checks.

If you do not do this, quotas can be bypassed via aliases. The easier workaround is to create the dummy Dovecot accounts that share the intended real user account data, but I agree that's not ideal.

One approach that can be done that Postfix docs advise is to have the public MTA on port 25 do all the usual filtering to reject bad mail, and then forward that to a 2nd internal instance to receive where IIRC the alias would have been expanded, effectively relaying the mail.


I wonder if we should change the default for ENABLE_QUOTAS back to zero (disabled).

Asked myself the same question. I think would be a good thing to do.

Without quotas, you cannot limit mail storage capacity but I guess the backscatter/blacklisting concern no longer applies.

I'm not sure what happens when you run out of actual disk storage space, but I guess that's more of a sysadmin concern to avoid in the first place?

Given the ENV name, it sort of implied to me that it was something you'd need to enable explicitly, not disable 😅 I haven't looked at our other similar named ENV, perhaps that's been the convention.

I can understand the value in the feature, but as this failure would have been silent and our workaround not ideal, probably best to make it opt-in as a breaking change release note (_at least I consider changing default ENV like this breaking changes, I think we didn't with ONE_DIR 🤷‍♂️ _).

Docs should be clear about the workaround with alias support though?


This was made the default in this PR

No.. that is just adding it to a complimentary ENV file. I don't ever user that myself.

So it's always been default since the introduction in Apr 2020 (v8 release).

I'm fine with making it opt-in instead. That should be handled via separate PR however.

polarathene
polarathene previously approved these changes Oct 28, 2021
Copy link
Copy Markdown
Member

@polarathene polarathene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh

# alias is assumed to not be a proper e-mail
# these aliases do not need to be added to Dovecot's userdb
[[ ! ${ALIAS} == *@* ]] && continue
Copy link
Copy Markdown
Member

@casperklein casperklein Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering, why non "FQUN" aliases like amavis don't need to be present in Dovecots userdb. Could you explain, thx.

Edit:

@polarathene Or maybe you can answer this too

Copy link
Copy Markdown
Member

@polarathene polarathene Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This problem only applies to inbound mail from external senders AFAIK.

I would need to check if smtpd_recipient_restrictions apply or not when a local service in the container sends mail to Postfix to deliver to Dovecot.

Even if it does, we have some rules earlier in these restrictions such as permit_mynetworks which will approve accepting the mail earlier. This prevents checking the quota policy against Dovecot. That'd probably not be great usually, but when the mail originates from you as the sender, then the backscatter concern of bouncing mail back to yourself probably doesn't apply?

I am not familiar with amavis other than it having something to do with spam handling. If it's not a concern, and the alias maps to an account that Dovecot receives mail for, and that quota is exceeded, then Dovecot bounces the mail (which from descriptions I read, is repeated multiple times 🤷‍♂️ )

Copy link
Copy Markdown
Member

@casperklein casperklein Oct 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for clarification. FYI, I use the amavis alias because of this.
That's why I have something like this: amavis [email protected] in postfix-virtual.cf.

Copy link
Copy Markdown
Member Author

@georglauterbach georglauterbach Oct 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as [email protected] is not a real address (in postfix-accounts.cf), this PR will not change / add anything because (as @polarathene has pointed out) only 1-to-1 aliases (alias -> real user) are expandend. Should all be fine here then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the whole point of this PR is to avoid some nasty error messages? So in any case, this PR should not harm in any way. Or do I miss something fundamental at the moment?

[email protected] is a real address (in postfix-accounts.cf). Why it shouldn't?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[email protected] is a real address (in postfix-accounts.cf). Why it shouldn't?

This was just an assumption (in this case, an entry will be added to Dovecot's userdb). This PR (should) does not do harm in any way, of course.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. But then, when someone have something like this in postfix-virtual.cf, this would not add an entry to dovecots userdb?

amavis [email protected] in postfix-virtual.cf

PS: I don't know, if it's valid to point an alias to an other alias.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why I have something like this: amavis [email protected] in postfix-virtual.cf.

I believe that should be in postfix-aliases.cf (parameter main.cf:alias_maps) like the comment you linked to mentions with aliasing the amavis account to root (which can alias again to postmaster@<FQDN>.

postfix-virtual.cf (parameter main.cf:virtual_alias_map with generated file /etc/postfix/virtual) and postfix-accounts.cf (parameter main.cf:virtual_mailbox_maps with generated file /etc/postfix/vmailbox) provide unique domains for the generated file /etc/postfix/vhost (_parameter main.cf:virtual_mailbox_domains).

Postfix should receive mail from local account without any FQDN, eg from amavis and match it to an alias in hash:/etc/aliases (/etc/aliases is plain-text, hash database generated by postalias is /etc/aliases.db that Postfix uses, values are sourced from postfix-aliases.cf populating /etc/aliases at startup or change event). Mappings in /etc/aliases lack an FQDN, but Postfix will under some conditions receive mail and extract the local part (eg left side of @) from incoming mail recipient and lookup these /etc/aliases if no explicit match was found in virtual aliases.

Since postfix-aliases.cf (unix user aliases) is purely meant for these aliases, while postfix-accounts.cf (virtual mailboxes, storage not tied to unix user) and postfix-virtual.cf (virtual aliases, no unix user) are handled by us differently (contributing to vhost domains), I think you would place amavis and the like in postfix-aliases.cf 😅 (don't worry, I'm probably as confused as you are right now 😛 )


Got it. But then, when someone have something like this in postfix-virtual.cf, this would not add an entry to dovecots userdb?

Postfix address rewriting docs on virtual aliases shows an example of a 1-to-1 mapping in postfix-virtual.cf that's got no associated FQDN, so even I'm confused about it vs the postfix-alias.cf kind. This is perfectly valid as you point out..

Dovecot AFAIK doesn't care what the user name is, eg amavis or [email protected]? What I believe happens here is Postfix will append main.cf:myorigin or if not available another fallback domain it's aware of, and then deliver that to Dovecot to store in /var/mail.

In the case of Amavis, it should only be mail to and from your server, if Dovecot can't be configured to ignore quota for system user accounts (eg: [email protected]) you could make the quota really high. In regards to the issue this PR is solving, there are "permit" rules that can come before the quota policy check, eg mynetworks and the one for SASL authenticated is probably safe and both of these are configured to come before the quota check, thus Postfix will accept and if Dovecot rejects, it bounces but if the accounts that sent it aren't external, the backscatter blacklisting concern shouldn't apply?


PS: I don't know, if it's valid to point an alias to an other alias.

I have read of an all alias that expands to many users, some which I guess could be aliases. 1-to-1 alias that maps to another alias seems a bit silly, but our docs have an example of working around SPOOF_PROTECTION issue for aliasing to gmail via an alias to alias mapping which then maps the 2nd level alias to the external account.


Probably good to eventually investigate further the above for definitive answers about account/alias handling and document that somewhere, but I don't have time to allocate to that right now 😬

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the log issue with Postfix asking Dovecot for quota status of an alias that Dovecot doesn't know about is always the RCPT TO (envelope recipient) address the email was originally sent to.

Regardless of nested chains, Postfix does not expand that aliases at this point (which could be N levels deep or expand to multiple addresses to send to). In the docs mention in my previous comment, that means the gmail account with double aliases won't be added to Dovecot, not that it matters since that's aliasing to an external account anyway.

If it ever turns out to be an issue, we can probably regard it as niche and unsupported. Our responsibility would just be to make the caveat with quota support with aliases visible in our docs, and that we only assist with direct aliasing to a single real mailbox account, any fancy aliasing beyond that puts the user as risk of backscatter if they have quotas enabled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't worry, I'm probably as confused as you are right now

😆

Thank you for you detailed answer!

Comment thread target/scripts/startup/setup-stack.sh Outdated
Comment thread target/scripts/startup/setup-stack.sh Outdated
@andrewlow
Copy link
Copy Markdown
Contributor

@polarathene

This was made the default in this PR

No.. that is just adding it to a complimentary ENV file. I don't ever user that myself.

From a user perspective, the complimentary ENV file defines the defaults.

I'm not sure what happens when you run out of actual disk storage space, but I guess that's more of a sysadmin concern to avoid in the first place?

I've run my previous mail server (also postfix/dovecot but not docker-mailserver based) out of storage - things fail, but I'd say it's graceful enough. If you reach in and fix the storage problem mail resumes flowing. For the most part - sending servers simply fail to deliver, and the receiving server doesn't succeed in receiving the email and sends an error code - so if you address the storage issue soon enough no mail is bounced because the sending server will re-try a few times.

@wernerfred
Copy link
Copy Markdown
Member

yep, still using it!

I can understand the value in the feature, but as this failure would have been silent and our workaround not ideal, probably best to make it opt-in as a breaking change release note

Definitly a breaking change imho

So it's always been default since the introduction in Apr 2020 (v8 release).
I'm fine with making it opt-in instead. That should be handled via separate PR however.

But making it opt-in doesn't solve the problem, does it? The people that enable quotas would still face this behavior? Or am i missunderstanding something (admitting not reading all 55 comments and linked issues/pr comments in detail)?

@andrewlow
Copy link
Copy Markdown
Contributor

So it's always been default since the introduction in Apr 2020 (v8 release).
I'm fine with making it opt-in instead. That should be handled via separate PR however.

But making it opt-in doesn't solve the problem, does it? The people that enable quotas would still face this behavior? Or am i missunderstanding something (admitting not reading all 55 comments and linked issues/pr comments in detail)?

The "problem" here is extra entries in the log files - where for every alias, you will see an error indicating that dovecot cannot find the alias user when it is trying to check the quota.

This problem is invisible, until you enable the optional logwatch reporting https://docker-mailserver.github.io/docker-mailserver/edge/config/environment/#logwatch_interval

Logwatch is detecting these log lines about the alias as an error, and reporting. It makes the logwatch report quite difficult to read if you have a lot of traffic to aliases.

@wernerfred
Copy link
Copy Markdown
Member

Thanks for clarifying!
So the "problem" is just a stylistic/extra log line problem. But in fact i am right with the assumption that disabling the env by default doesn't solve the problem and users with enabled env will still "see" those log lines.
If this is the only outcome of changing the default behavior of the setting i would suggest keeping it as it is now (to avoid a breaking change) but to mention this issue in the documentation and how to solve it (disabling the quota env)
Wouldn't that be the "better" solution ?

@polarathene
Copy link
Copy Markdown
Member

(admitting not reading all 55 comments and linked issues/pr comments in detail)

@wernerfred this comment should cover everything you need to know, if not no worries let me know and I'll clarify/expand further 👍


So the "problem" is just a stylistic/extra log line problem.

No it is not. This affects anyone using aliases and the default quota feature for Dovecot.

It risks making the docker-mailserver instance vulnerable to backscatter, which allows spammers to forge a return address, bypass the Postfix quota-status policy check to reject mail at the smtpd_recipient_restrictions stage, delivering the mail to Dovecot which if quota has exceed, bounces it back to the return address.

That can get you blacklisted.

The quota feature itself is useful to enforce storage limitations for mail, or per user to avoid any abuse that could fill up the mail server storage, and thus no longer having space for others to store received mail.

If you don't need that, disabling quota support avoids the backscatter issue with aliases (still requires quota to actually be exceeded though).

The log message itself is only because Postfix is checking with Dovecot with the alias account in the RCPT TO envelope recipient address before reaching a stage that alias expansion happens (once mail passes criteria to accept and hand off to the cleanup process which will add it to the "incoming queue").


with the assumption that disabling the env by default doesn't solve the problem and users with enabled env will still "see" those log lines.

With this PR they would not see the log lines. The workaround is to add the alias account as a dummy account to Dovecot which shares the same mailbox of the real account with a quota.

The workaround is probably a bit naive though, in that:

  • Aliases can map to other aliases.
  • Not only can aliases nest/chain many times, but you can have one alias expand into multiple addresses, not just a 1-to-1 mapping.

postmap -q <alias> <table> can be used to query the alias (for docker-mailserver with a plain-text file alias table and if not using the regexp alias table then we can do the same ourselves manually). Unfortunately there doesn't appear to be support from the Postfix utilities to resolve the alias expansion fully.

Due to that, this workaround is naive in that it will only resolve simple alias mappings that map an alias to a single real account directly AFAIK. The proper fix would be to not have Dovecot care about these dummy accounts at all, and write a policy service for Postfix to call that resolves the alias fully and checks any mapped accounts to the Dovecot quota-status service, this would be a proxy service and requires more effort to implement.

The quota support is also not implemented by docker-mailserver for LDAP users, making it opt-in for non-LDAP would ensure a more consistent base setup and make troubleshooting potentially related issues a bit easier when we know the user reports opt-in via ENABLE_QUOTAS=1.

Alternatively we could implement quota support for LDAP too, but I don't think anyone here is interested in tackling that 😅


Summary

If you use quotas

The problem

  • This log will appear with aliases due to no equivalent account on Dovecot as Postfix does not expand aliases prior to accepting mail and this log entry occurs when validating the RCPT TO against a quota policy check to Dovecot so that the mail can be rejected early and avoid enabling spammers via backscatter, which can get you blacklisted.
  • The quota-status policy check will only reject when Dovecot knows it will reject for exceeding quota, if an account is not known, this will not result in rejection, so aliases will bypass the check and then possibly get rejected if quota exceeded.
  • You do not want to reject when accounts aren't known to Dovecot during this check however as that'd always result in no delivery from that alias.

The workaround fix

  • The PR provides a workaround by creating dummy accounts for Dovecot to be aware of the alias accounts.
  • These are only added if the alias has a simple 1-to-1 mapping with a real account, not to multiple accounts or additional aliases, those will still run into the problem.

If you don't use quotas

  • The policy check for quotas isn't performed, so no problem.
  • Your only problem without quotas is trust that you won't have storage issues that could be abused and negatively impact other users.
  • LDAP users don't have quota support implemented by docker-mailserver.

TL;DR

  • The log is about an actual problem and shouldn't be dismissed, it can get you blacklisted for backscatter abuse from spammers.
  • The fix is to not use quotas, or use the PR workaround that creates dummy Dovecot accounts for simple alias mappings.
  • A better fix could be implemented but is more effort (proxying the policy service to resolve aliases fully and query all resolved addresses to the quota policy service).
  • As docker-mailserver does not have quota support for LDAP users, it's probably better to make it opt-in for a more consistent base setup that assists with troubleshooting.

@polarathene
Copy link
Copy Markdown
Member

polarathene commented Oct 29, 2021

From a user perspective, the complimentary ENV file defines the defaults.

@andrewlow the complimentary ENV file is it's own set of defaults. Not all users add that. I don't expect users to know about internals, but for public facing ENV defaults, our ENV documentation should be a more reliable source for users to know what is default. I would like to better automate genating that ENV file from our docs to keep them in sync though.

The source you provided was about updating that ENV file, while the actual quota support had an implicit default not "documented" in that ENV file for quite some time prior... an entire year.

The "problem" here is extra entries in the log files - where for every alias, you will see an error indicating that dovecot cannot find the alias user when it is trying to check the quota.

This problem is invisible, until you enable the optional logwatch reporting

It becomes a real problem when quota is exceeded. See my previous comment for details.


i would suggest keeping it as it is now (to avoid a breaking change) but to mention this issue in the documentation and how to solve it (disabling the quota env)
Wouldn't that be the "better" solution ?

@wernerfred

The issue probably still needs to be documented either way, especially the caveat (only basic alias mappings) for the workaround proposed.

A breaking change doesn't have to be introduced straight away, I've asked for a separate PR for any default ENV change. This way it can be merged at a later date as there are other changes inbound unrelated to this PR that are likely to warrant a major version bump.

@wernerfred
Copy link
Copy Markdown
Member

@wernerfred this comment should cover everything you need to know, if not no worries let me know and I'll clarify/expand further 👍

Insane, thank you!

So what i am not understanding right now is how POSTFIX_MAILBOX_SIZE_LIMIT is involved in this issue here. Does setting this ENV (and therefore limiting everys mailbox size) prevent exploiting this issue?

@polarathene
Copy link
Copy Markdown
Member

polarathene commented Oct 30, 2021

So what i am not understanding right now is how POSTFIX_MAILBOX_SIZE_LIMIT is involved in this issue here. Does setting this ENV (and therefore limiting everys mailbox size) prevent exploiting this issue?

Where are you referring to this from? I recall that being part of the quota feature PR, but not this one. Postfix main.cf:mailbox_size_limit is what you're referring to? I don't think this has anything to do with Dovecot Quota, but is similar for the Postfix local delivery agent, which shouldn't need to go through any recipient restrictions to be accepted by Postfix AFAIK.

I've not looked into that personally so I don't quite know what happens there, presumably it relays over LMTP to Dovecot, if so then either it bypasses the quota check and could be an issue, or by relaying via LMTP it may go through the proper checks again on the recipient, however by this time Postfix probably already expanded the alias via local delivery first.


UPDATE:

This is a docker-mailserver ENV you were referring to, my bad. It does map to the same Postfix main.cf parameter setting I mention above, it is used by us only here:

function _setup_postfix_sizelimits
{
_notify 'inf' "Configuring postfix message size limit"
postconf -e "message_size_limit = ${POSTFIX_MESSAGE_SIZE_LIMIT}"
_notify 'inf' "Configuring postfix mailbox size limit"
postconf -e "mailbox_size_limit = ${POSTFIX_MAILBOX_SIZE_LIMIT}"
_notify 'inf' "Configuring postfix virtual mailbox size limit"
postconf -e "virtual_mailbox_limit = ${POSTFIX_MAILBOX_SIZE_LIMIT}"
}

When receiving mail, presumably Postfix has or had some notion of the mailbox size (we may have shifted that to Dovecot, so I'm not sure if that's true anymore), and Postfix could look at the size of the incoming mail and reject it if it would exceed the mailbox limit or individual mail size limit that's been configured. In that sense it's similar to quotas I think, but no issue here in that it has nothing to do with Dovecot (unclear regarding mailbox limit associated to recipient).

Some tests and complimentary documentation would probably be good about the above 😅

Comment thread target/scripts/startup/setup-stack.sh Outdated
@polarathene polarathene merged commit 5372470 into master Nov 1, 2021
@polarathene polarathene deleted the dovecot-aliases branch November 1, 2021 01:20
@polarathene

This comment has been minimized.

@georglauterbach

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/scripts kind/improvement Improve an existing feature, configuration file or the documentation priority/medium service/dovecot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weird Dovecot login failures for emails arriving to a virtual alias

6 participants