1
0
mirror of https://github.com/docker-mailserver/docker-mailserver.git synced 2025-10-08 23:51:57 +02:00

fix: accounts.sh - Support first valid local account (#4581)

- Ensure catch-all alias entries (eg: `@example.test`) are also skipped. Adding a dummy account for catch-all will not match a `quota-status` query to Dovecot by Postfix for a recipient.
- When there are multiple addresses provided, they will now be iterated through by the `,` delimiter, instead of as a single value that fails. This way the first valid aliased address to a local Dovecot mailbox account will now be used for the dummy alias account.
- The common logic for extracting the quota user attribute is now split out to a common function call.
This commit is contained in:
Brennan Kinney
2025-10-09 08:58:49 +13:00
committed by GitHub
parent 5e5e005162
commit e5185e0e84
3 changed files with 65 additions and 47 deletions

View File

@@ -6,6 +6,11 @@ All notable changes to this project will be documented in this file. The format
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes. > **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
### Fixed
- **Internal:**
- `ENABLE_QUOTAS=1` - When an alias has multiple addresses, the first local mailbox address found will be used for the Dovecot dummy account workaround ([#4581](https://github.com/docker-mailserver/docker-mailserver/pull/4581))
### Removed ### Removed
- **SpamAssassin:** - **SpamAssassin:**
@@ -36,7 +41,7 @@ All notable changes to this project will be documented in this file. The format
- [ENV can be declared with a `__FILE` suffix](https://docker-mailserver.github.io/docker-mailserver/v15.1/config/environment/) to read a value from a file during initial DMS setup scripts ([#4359](https://github.com/docker-mailserver/docker-mailserver/pull/4359)) - [ENV can be declared with a `__FILE` suffix](https://docker-mailserver.github.io/docker-mailserver/v15.1/config/environment/) to read a value from a file during initial DMS setup scripts ([#4359](https://github.com/docker-mailserver/docker-mailserver/pull/4359))
- Improved docs for the ENV `OVERRIDE_HOSTNAME` ([#4492](https://github.com/docker-mailserver/docker-mailserver/pull/4492)) - Improved docs for the ENV `OVERRIDE_HOSTNAME` ([#4492](https://github.com/docker-mailserver/docker-mailserver/pull/4492))
- **Internal:** - **Internal:**
- [`DMS_CONFIG_POLL`](https://docker-mailserver.github.io/docker-mailserver/v15.0/config/environment/#dms_config_poll) supports adjusting the polling rate (seconds) for the change detection service `check-for-changes.sh` ([#4450](https://github.com/docker-mailserver/docker-mailserver/pull/4450)) - [`DMS_CONFIG_POLL`](https://docker-mailserver.github.io/docker-mailserver/v15.1/config/environment/#dms_config_poll) supports adjusting the polling rate (seconds) for the change detection service `check-for-changes.sh` ([#4450](https://github.com/docker-mailserver/docker-mailserver/pull/4450))
### Fixes ### Fixes

View File

@@ -36,16 +36,7 @@ function _create_accounts() {
USER=$(echo "${LOGIN}" | cut -d @ -f1) USER=$(echo "${LOGIN}" | cut -d @ -f1)
DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2) DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2)
# test if user has a defined quota USER_ATTRIBUTES="$(_add_attribute_dovecot_quota "${LOGIN}" "${USER_ATTRIBUTES}")"
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]; then
declare -a USER_QUOTA
IFS=':' read -r -a USER_QUOTA < <(grep "${USER}@${DOMAIN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
if [[ ${#USER_QUOTA[@]} -eq 2 ]]; then
USER_ATTRIBUTES="${USER_ATTRIBUTES:+${USER_ATTRIBUTES} }userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
fi
fi
if [[ -z ${USER_ATTRIBUTES} ]]; then if [[ -z ${USER_ATTRIBUTES} ]]; then
_log 'debug' "Creating user '${USER}' for domain '${DOMAIN}'" _log 'debug' "Creating user '${USER}' for domain '${DOMAIN}'"
else else
@@ -82,41 +73,53 @@ function _create_accounts() {
fi fi
} }
# Required when using Dovecot Quotas to avoid blacklisting risk from backscatter # Required when using Dovecot Quotas to avoid blacklisting risk from backscatter.
# Note: This is a workaround only suitable for basic aliases that map to single real addresses, # Note: This is a workaround only suitable for basic aliases that map to a single real address,
# not multiple addresses (real accounts or additional aliases), those will not work with Postfix # not multiple addresses (real accounts or additional aliases), those will not work with
# `quota-status` policy service and remain at risk of backscatter. # the Postfix `quota-status` policy service and remain at risk of backscatter.
# #
# see https://github.com/docker-mailserver/docker-mailserver/pull/2248#issuecomment-953313852 # for more details on this method, see:
# for more details on this method # https://github.com/docker-mailserver/docker-mailserver/pull/2248#issuecomment-953313852
function _create_dovecot_alias_dummy_accounts() { function _create_dovecot_alias_dummy_accounts() {
local DATABASE_VIRTUAL='/tmp/docker-mailserver/postfix-virtual.cf' local DATABASE_VIRTUAL='/tmp/docker-mailserver/postfix-virtual.cf'
# NOTE: `DATABASE_ACCOUNTS` should be in scope (provided from the expected caller: `_create_accounts()`)
# Add aliases associated to DMS mailbox accounts as dummy entries into Dovecot's userdb,
# These will share the same storage as a real account for the `quota-status` check to query.
if [[ -f ${DATABASE_VIRTUAL} ]] && [[ ${ENABLE_QUOTAS} -eq 1 ]]; then if [[ -f ${DATABASE_VIRTUAL} ]] && [[ ${ENABLE_QUOTAS} -eq 1 ]]; then
# adding aliases to Dovecot's userdb local ALIAS ALIASED DOVECOT_USERDB_LINE
while read -r ALIAS ALIASED; do
# Skip any alias lacking `@` (aka local-part only) or is a catch-all domain (starts with `@`):
[[ ! ${ALIAS} =~ .+@.+ ]] && continue
# ${REAL_FQUN} is a user's fully-qualified username # ${REAL_FQUN} is a user's fully-qualified username
local ALIAS REAL_FQUN DOVECOT_USERDB_LINE unset REAL_FQUN
while read -r ALIAS REAL_FQUN; do local REAL_FQUN REAL_USERNAME REAL_DOMAINNAME
# alias is assumed to not be a proper e-mail
# these aliases do not need to be added to Dovecot's userdb
[[ ! ${ALIAS} == *@* ]] && continue
# clear possibly already filled arrays # Support checking multiple aliased addresses (split by `,` delimiter):
# do not remove the following line of code # - The first local account matched will be associated to the alias
unset REAL_ACC USER_QUOTA # - Does not support resolving FQUN if it were also an alias
declare -a REAL_ACC USER_QUOTA for FQUN in ${ALIASED//,/ }
do
local REAL_USERNAME REAL_DOMAINNAME if grep -q "${FQUN}" "${DATABASE_ACCOUNTS}"; then
REAL_FQUN="${FQUN}"
REAL_USERNAME=$(cut -d '@' -f 1 <<< "${REAL_FQUN}") REAL_USERNAME=$(cut -d '@' -f 1 <<< "${REAL_FQUN}")
REAL_DOMAINNAME=$(cut -d '@' -f 2 <<< "${REAL_FQUN}") REAL_DOMAINNAME=$(cut -d '@' -f 2 <<< "${REAL_FQUN}")
break
fi
done
if ! grep -q "${REAL_FQUN}" "${DATABASE_ACCOUNTS}"; then if [[ -z ${REAL_FQUN} ]] || ! grep -q "${REAL_FQUN}" "${DATABASE_ACCOUNTS}"; then
_log 'debug' "Alias '${ALIAS}' is non-local (or mapped to a non-existing account) and will not be added to Dovecot's userdb" _log 'debug' "Alias '${ALIAS}' is non-local (or mapped to a non-existing account) and will not be added to Dovecot's userdb"
continue continue
fi fi
_log 'debug' "Adding alias '${ALIAS}' for user '${REAL_FQUN}' to Dovecot's userdb" _log 'debug' "Adding alias '${ALIAS}' for user '${REAL_FQUN}' to Dovecot's userdb"
# Clear possibly already filled arrays (do not remove the following line of code)
unset REAL_ACC USER_QUOTA
declare -a REAL_ACC USER_QUOTA
# ${REAL_ACC[0]} => real account name (e-mail address) == ${REAL_FQUN} # ${REAL_ACC[0]} => real account name (e-mail address) == ${REAL_FQUN}
# ${REAL_ACC[1]} => password hash # ${REAL_ACC[1]} => password hash
# ${REAL_ACC[2]} => optional user attributes # ${REAL_ACC[2]} => optional user attributes
@@ -126,13 +129,8 @@ function _create_dovecot_alias_dummy_accounts() {
_dms_panic__misconfigured 'postfix-accounts.cf' 'alias configuration' _dms_panic__misconfigured 'postfix-accounts.cf' 'alias configuration'
fi fi
# test if user has a defined quota # Update user attributes with custom quota if found for the `REAL_FQUN`:
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]; then REAL_ACC[2]="$(_add_attribute_dovecot_quota "${REAL_FQUN}" "${REAL_ACC[2]}")"
IFS=':' read -r -a USER_QUOTA < <(grep "${REAL_FQUN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
if [[ ${#USER_QUOTA[@]} -eq 2 ]]; then
REAL_ACC[2]="${REAL_ACC[2]:+${REAL_ACC[2]} }userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
fi
fi
DOVECOT_USERDB_LINE="${ALIAS}:${REAL_ACC[1]}:${DMS_VMAIL_UID}:${DMS_VMAIL_GID}::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}/home::${REAL_ACC[2]:-}" DOVECOT_USERDB_LINE="${ALIAS}:${REAL_ACC[1]}:${DMS_VMAIL_UID}:${DMS_VMAIL_GID}::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}/home::${REAL_ACC[2]:-}"
# Match a full line with `-xF` to avoid regex patterns introducing false positives matching `ALIAS`: # Match a full line with `-xF` to avoid regex patterns introducing false positives matching `ALIAS`:
@@ -178,3 +176,19 @@ function _create_masters() {
done < <(_get_valid_lines_from_file "${DATABASE_DOVECOT_MASTERS}") done < <(_get_valid_lines_from_file "${DATABASE_DOVECOT_MASTERS}")
fi fi
} }
function _add_attribute_dovecot_quota() {
local MAIL_ACCOUNT="${1}"
local USER_ATTRIBUTES="${2}"
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]; then
declare -a USER_QUOTA
IFS=':' read -r -a USER_QUOTA < <(grep -i "${MAIL_ACCOUNT}:" /tmp/docker-mailserver/dovecot-quotas.cf)
if [[ ${#USER_QUOTA[@]} -eq 2 ]]; then
USER_ATTRIBUTES="${USER_ATTRIBUTES:+${USER_ATTRIBUTES} }userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
fi
fi
echo "${USER_ATTRIBUTES}"
}

View File

@@ -27,19 +27,18 @@ function teardown_file() { _default_teardown ; }
assert_line --index 3 'added@localhost.localdomain' assert_line --index 3 'added@localhost.localdomain'
assert_line --index 4 'pass@localhost.localdomain' assert_line --index 4 'pass@localhost.localdomain'
assert_line --index 5 'alias1@localhost.localdomain' assert_line --index 5 'alias1@localhost.localdomain'
# TODO: Probably not intentional?:
assert_line --index 6 '@localdomain2.com'
# Dovecot "dummy accounts" for quota support, see `test/config/postfix-virtual.cf` for more context # Dovecot "dummy accounts" for quota support, see `test/config/postfix-virtual.cf` for more context
assert_line --index 7 'prefixtest@localhost.localdomain' assert_line --index 6 'prefixtest@localhost.localdomain'
assert_line --index 8 'test@localhost.localdomain' assert_line --index 7 'test@localhost.localdomain'
assert_line --index 9 'first-name@localhost.localdomain' assert_line --index 8 'first-name@localhost.localdomain'
assert_line --index 10 'first.name@localhost.localdomain' assert_line --index 9 'first.name@localhost.localdomain'
_should_output_number_of_lines 11 _should_output_number_of_lines 10
refute_line --partial '@localdomain2.com'
# Relevant log output from scripts/helpers/accounts.sh:_create_dovecot_alias_dummy_accounts(): # Relevant log output from scripts/helpers/accounts.sh:_create_dovecot_alias_dummy_accounts():
# [ DEBUG ] Adding alias 'alias1@localhost.localdomain' for user 'user1@localhost.localdomain' to Dovecot's userdb # [ DEBUG ] Adding alias 'alias1@localhost.localdomain' for user 'user1@localhost.localdomain' to Dovecot's userdb
# [ DEBUG ] Alias 'alias2@localhost.localdomain' is non-local (or mapped to a non-existing account) and will not be added to Dovecot's userdb # [ DEBUG ] Alias 'alias2@localhost.localdomain' is non-local (or mapped to a non-existing account) and will not be added to Dovecot's userdb
# [ DEBUG ] Adding alias '@localdomain2.com' for user 'user1@localhost.localdomain' to Dovecot's userdb
} }
# Dovecot "dummy accounts" for quota support, see `test/config/postfix-virtual.cf` for more context # Dovecot "dummy accounts" for quota support, see `test/config/postfix-virtual.cf` for more context