diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ee8456..83473544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. +### 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 - **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)) - Improved docs for the ENV `OVERRIDE_HOSTNAME` ([#4492](https://github.com/docker-mailserver/docker-mailserver/pull/4492)) - **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 diff --git a/target/scripts/helpers/accounts.sh b/target/scripts/helpers/accounts.sh index 8510b6af..aa344f37 100644 --- a/target/scripts/helpers/accounts.sh +++ b/target/scripts/helpers/accounts.sh @@ -36,16 +36,7 @@ function _create_accounts() { USER=$(echo "${LOGIN}" | cut -d @ -f1) DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2) - # test if user has a defined quota - 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 - + USER_ATTRIBUTES="$(_add_attribute_dovecot_quota "${LOGIN}" "${USER_ATTRIBUTES}")" if [[ -z ${USER_ATTRIBUTES} ]]; then _log 'debug' "Creating user '${USER}' for domain '${DOMAIN}'" else @@ -82,41 +73,53 @@ function _create_accounts() { fi } -# 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, -# not multiple addresses (real accounts or additional aliases), those will not work with Postfix -# `quota-status` policy service and remain at risk of 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 a single real address, +# not multiple addresses (real accounts or additional aliases), those will not work with +# 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 +# for more details on this method, see: +# https://github.com/docker-mailserver/docker-mailserver/pull/2248#issuecomment-953313852 function _create_dovecot_alias_dummy_accounts() { 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 - # adding aliases to Dovecot's userdb - # ${REAL_FQUN} is a user's fully-qualified username - local ALIAS REAL_FQUN DOVECOT_USERDB_LINE - while read -r ALIAS REAL_FQUN; do - # alias is assumed to not be a proper e-mail - # these aliases do not need to be added to Dovecot's userdb - [[ ! ${ALIAS} == *@* ]] && continue + 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 - # 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_FQUN} is a user's fully-qualified username + unset REAL_FQUN + local REAL_FQUN REAL_USERNAME REAL_DOMAINNAME - local REAL_USERNAME REAL_DOMAINNAME - REAL_USERNAME=$(cut -d '@' -f 1 <<< "${REAL_FQUN}") - REAL_DOMAINNAME=$(cut -d '@' -f 2 <<< "${REAL_FQUN}") + # Support checking multiple aliased addresses (split by `,` delimiter): + # - The first local account matched will be associated to the alias + # - Does not support resolving FQUN if it were also an alias + for FQUN in ${ALIASED//,/ } + do + if grep -q "${FQUN}" "${DATABASE_ACCOUNTS}"; then + REAL_FQUN="${FQUN}" + REAL_USERNAME=$(cut -d '@' -f 1 <<< "${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" continue fi _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[1]} => password hash # ${REAL_ACC[2]} => optional user attributes @@ -126,13 +129,8 @@ function _create_dovecot_alias_dummy_accounts() { _dms_panic__misconfigured 'postfix-accounts.cf' 'alias configuration' fi - # test if user has a defined quota - if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]; then - 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 + # Update user attributes with custom quota if found for the `REAL_FQUN`: + REAL_ACC[2]="$(_add_attribute_dovecot_quota "${REAL_FQUN}" "${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`: @@ -178,3 +176,19 @@ function _create_masters() { done < <(_get_valid_lines_from_file "${DATABASE_DOVECOT_MASTERS}") 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}" +} diff --git a/test/tests/parallel/set3/mta/account_management.bats b/test/tests/parallel/set3/mta/account_management.bats index f0d47968..ae1ea9df 100644 --- a/test/tests/parallel/set3/mta/account_management.bats +++ b/test/tests/parallel/set3/mta/account_management.bats @@ -27,19 +27,18 @@ function teardown_file() { _default_teardown ; } assert_line --index 3 'added@localhost.localdomain' assert_line --index 4 'pass@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 - assert_line --index 7 'prefixtest@localhost.localdomain' - assert_line --index 8 'test@localhost.localdomain' - assert_line --index 9 'first-name@localhost.localdomain' - assert_line --index 10 'first.name@localhost.localdomain' - _should_output_number_of_lines 11 + assert_line --index 6 'prefixtest@localhost.localdomain' + assert_line --index 7 'test@localhost.localdomain' + assert_line --index 8 'first-name@localhost.localdomain' + assert_line --index 9 'first.name@localhost.localdomain' + _should_output_number_of_lines 10 + + refute_line --partial '@localdomain2.com' # 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 ] 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