From 2a70f33a4bfc3f9d45d8b521f01c7fa7a8419203 Mon Sep 17 00:00:00 2001 From: mwnx Date: Mon, 24 Aug 2020 20:46:50 +0200 Subject: [PATCH 1/3] Fix checksum race condition in check-for-changes.sh If a change to one of the tracked files happened soon after (<1 second?) a previously detected change, it could end up going undetected. In particular, this could cause integration tests to fail (see next commits). Fixed by computing the new checksum file _before_ checking for changes. --- target/check-for-changes.sh | 35 ++++++++++++++++------------------ target/helper_functions.sh | 20 +++++++++++++++++++ target/start-mailserver.sh | 12 +----------- test/mail_ssl_letsencrypt.bats | 2 +- test/tests.bats | 2 +- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/target/check-for-changes.sh b/target/check-for-changes.sh index 40793d47..b8d69936 100755 --- a/target/check-for-changes.sh +++ b/target/check-for-changes.sh @@ -16,7 +16,6 @@ if [ ! -f postfix-accounts.cf ]; then fi # Verify checksum file exists; must be prepared by start-mailserver.sh -CHKSUM_FILE=/tmp/docker-mailserver-config-chksum if [ ! -f $CHKSUM_FILE ]; then echo "${log_date} ${CHKSUM_FILE} is missing! Start script failed? Exit!" exit @@ -32,12 +31,6 @@ fi PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}" echo "${log_date} Using postmaster address ${PM_ADDRESS}" -# Create an array of files to monitor, must be the same as in start-mailserver.sh -declare -a cf_files=() -for file in postfix-accounts.cf postfix-virtual.cf postfix-aliases.cf dovecot-quotas.cf /etc/letsencrypt/acme.json "/etc/letsencrypt/live/$HOSTNAME/key.pem" "/etc/letsencrypt/live/$HOSTNAME/fullchain.pem"; do - [ -f "$file" ] && cf_files+=("$file") -done - # Wait to make sure server is up before we start sleep 10 @@ -48,10 +41,12 @@ while true; do log_date=$(date +"%Y-%m-%d %H:%M:%S ") # Get chksum and check it, no need to lock config yet -chksum=$(sha512sum -c --ignore-missing $CHKSUM_FILE) +monitored_files_checksums >"$CHKSUM_FILE.new" -if [[ $chksum == *"FAIL"* ]]; then +if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then echo "${log_date} Change detected" + changed=$(grep -Fxvf "$CHKSUM_FILE" "$CHKSUM_FILE.new" | sed 's/^[^ ]\+ //') + mv "$CHKSUM_FILE.new" "$CHKSUM_FILE" # Bug alert! This overwrites the alias set by start-mailserver.sh # Take care that changes in one script are propagated to the other @@ -63,13 +58,18 @@ if [[ $chksum == *"FAIL"* ]]; then ( flock -e 200 - if [[ $chksum == *"/etc/letsencrypt/acme.json: FAILED"* ]]; then - for certdomain in $SSL_DOMAIN $HOSTNAME $DOMAINNAME; do - if extractCertsFromAcmeJson "$certdomain"; then - break - fi - done - fi + for file in $changed; do + case $file in + /etc/letsencrypt/acme.json) + for certdomain in $SSL_DOMAIN $HOSTNAME $DOMAINNAME; do + if extractCertsFromAcmeJson "$certdomain"; then + break + fi + done + ;; + #TODO: Perform updates below conditionally as well. + esac + done #regen postix aliases. echo "root: ${PM_ADDRESS}" > /etc/aliases @@ -211,9 +211,6 @@ if [[ $chksum == *"FAIL"* ]]; then supervisorctl restart dovecot fi - echo "${log_date} Update checksum" - sha512sum ${cf_files[@]/#/--tag } >$CHKSUM_FILE - ) 200/dev/null to ignore warnings about files that don't exist) + exec sha512sum 2>/dev/null -- \ + postfix-accounts.cf \ + postfix-virtual.cf \ + postfix-aliases.cf \ + dovecot-quotas.cf \ + /etc/letsencrypt/acme.json \ + "/etc/letsencrypt/live/$HOSTNAME/key.pem" \ + "/etc/letsencrypt/live/$HOSTNAME/fullchain.pem" + ) + return 0 +} diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index 28342741..e9bde163 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -500,19 +500,9 @@ function _setup_file_permissions() { function _setup_chksum_file() { notify 'task' "Setting up configuration checksum file" - if [ -d /tmp/docker-mailserver ]; then - pushd /tmp/docker-mailserver - - declare -a cf_files=() - for file in postfix-accounts.cf postfix-virtual.cf postfix-aliases.cf dovecot-quotas.cf /etc/letsencrypt/acme.json "/etc/letsencrypt/live/$HOSTNAME/key.pem" "/etc/letsencrypt/live/$HOSTNAME/fullchain.pem"; do - [ -f "$file" ] && cf_files+=("$file") - done - notify 'inf' "Creating $CHKSUM_FILE" - sha512sum ${cf_files[@]/#/--tag } >$CHKSUM_FILE - - popd + monitored_files_checksums >"$CHKSUM_FILE" else # We could just skip the file, but perhaps config can be added later? # If so it must be processed by the check for changes script diff --git a/test/mail_ssl_letsencrypt.bats b/test/mail_ssl_letsencrypt.bats index 8acfdb3a..0a8cc62b 100644 --- a/test/mail_ssl_letsencrypt.bats +++ b/test/mail_ssl_letsencrypt.bats @@ -118,7 +118,7 @@ function teardown_file() { assert_output --partial "Cert found in /etc/letsencrypt/acme.json for *.example.com" assert_output --partial "postfix: stopped" assert_output --partial "postfix: started" - assert_output --partial "Update checksum" + assert_output --partial "Change detected" run docker exec mail_lets_acme_json /bin/bash -c "cat /etc/letsencrypt/live/mail.my-domain.com/key.pem" assert_output "$(cat "`pwd`/test/config/letsencrypt/changed/key.pem")" diff --git a/test/tests.bats b/test/tests.bats index 05900c64..0d77ae5c 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -20,7 +20,7 @@ function wait_for_service() { function count_processed_changes() { containerName=$1 - docker exec $containerName cat /var/log/supervisor/changedetector.log | grep "Update checksum" | wc -l + docker exec $containerName cat /var/log/supervisor/changedetector.log | grep "Change detected" | wc -l } # From 1286a1266b519c41f8a63ac918244a4452345acc Mon Sep 17 00:00:00 2001 From: mwnx Date: Mon, 24 Aug 2020 22:08:11 +0200 Subject: [PATCH 2/3] Fix/refactor relayhost_map update when dynamically adding account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check-for-changes.sh did not have a special case to handle lines in postfix-relaymap.cf consisting of only a domain (indicating that said domain should never be relayed). This case is handled by start-mailserver.sh so when such a line existed, things would work well until a config file update was detected by check-for-changes.sh. After that, the generated relayhost_map file would be corrupted. Fixed by factoring a 'populate_relayhost_map' function out of start-mailserver.sh and into helper_functions.sh and reusing it in check-for-changes.sh. Note: There are certainly quite a few more pieces of code that could be refactored in a similar fashion. Note2: check-for-changes.sh would previously never update the relayhost_map file when $ENABLE_LDAP was set to 1. I don't think this was intended —there is after all no such condition in start-mailserver.sh— and so this condition no longer applies. --- target/check-for-changes.sh | 22 ++------- target/helper_functions.sh | 87 ++++++++++++++++++++++++++++++++++++ target/start-mailserver.sh | 89 +------------------------------------ test/mail_with_relays.bats | 41 ++++++++++++----- 4 files changed, 123 insertions(+), 116 deletions(-) diff --git a/target/check-for-changes.sh b/target/check-for-changes.sh index b8d69936..3ff8ffa1 100755 --- a/target/check-for-changes.sh +++ b/target/check-for-changes.sh @@ -95,7 +95,6 @@ if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then if [ ! -z "$RELAY_HOST" ]; then # keep old config echo -n > /etc/postfix/sasl_passwd - echo -n > /etc/postfix/relayhost_map if [ ! -z "$SASL_PASSWD" ]; then echo "$SASL_PASSWD" >> /etc/postfix/sasl_passwd fi @@ -111,14 +110,6 @@ if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then if [ ! -z "$RELAY_USER" ] && [ ! -z "$RELAY_PASSWORD" ]; then echo "[$RELAY_HOST]:$RELAY_PORT $RELAY_USER:$RELAY_PASSWORD" >> /etc/postfix/sasl_passwd fi - # add relay maps from file - if [ -f /tmp/docker-mailserver/postfix-relaymap.cf ]; then - (grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-relaymap.cf || true) | while read line; do - if ! echo "$line" | grep -q -e "\s*#"; then - echo "$line" >> /etc/postfix/relayhost_map - fi - done - fi fi # Creating users @@ -152,22 +143,15 @@ if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then # Copy user provided sieve file, if present test -e /tmp/docker-mailserver/${login}.dovecot.sieve && cp /tmp/docker-mailserver/${login}.dovecot.sieve /var/mail/${domain}/${user}/.dovecot.sieve echo ${domain} >> /tmp/vhost.tmp - # add domains to relayhost_map - if [ ! -z "$RELAY_HOST" ]; then - if ! grep -q -e "^@${domain}\s" /etc/postfix/relayhost_map; then - echo "@${domain} [$RELAY_HOST]:$RELAY_PORT" >> /etc/postfix/relayhost_map - fi - fi done fi + if [ ! -z "$RELAY_HOST" ]; then + populate_relayhost_map + fi if [ -f /etc/postfix/sasl_passwd ]; then chown root:root /etc/postfix/sasl_passwd chmod 0600 /etc/postfix/sasl_passwd fi - if [ -f /etc/postfix/relayhost_map ]; then - chown root:root /etc/postfix/relayhost_map - chmod 0600 /etc/postfix/relayhost_map - fi if [ -f postfix-virtual.cf ]; then # regen postfix aliases echo -n > /etc/postfix/virtual diff --git a/target/helper_functions.sh b/target/helper_functions.sh index 96261ab5..50f829f5 100644 --- a/target/helper_functions.sh +++ b/target/helper_functions.sh @@ -74,6 +74,93 @@ for key, value in acme.items(): fi } +declare -A DEFAULT_VARS +DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}" + +function notify () { + c_red="\e[0;31m" + c_green="\e[0;32m" + c_brown="\e[0;33m" + c_blue="\e[0;34m" + c_bold="\033[1m" + c_reset="\e[0m" + + notification_type=$1 + notification_msg=$2 + notification_format=$3 + msg="" + + case "${notification_type}" in + 'taskgrp') + msg="${c_bold}${notification_msg}${c_reset}" + ;; + 'task') + if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then + msg=" ${notification_msg}${c_reset}" + fi + ;; + 'inf') + if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then + msg="${c_green} * ${notification_msg}${c_reset}" + fi + ;; + 'started') + msg="${c_green} ${notification_msg}${c_reset}" + ;; + 'warn') + msg="${c_brown} * ${notification_msg}${c_reset}" + ;; + 'err') + msg="${c_red} * ${notification_msg}${c_reset}" + ;; + 'fatal') + msg="${c_red}Error: ${notification_msg}${c_reset}" + ;; + *) + msg="" + ;; + esac + + case "${notification_format}" in + 'n') + options="-ne" + ;; + *) + options="-e" + ;; + esac + + [[ ! -z "${msg}" ]] && echo $options "${msg}" +} + +# setup /etc/postfix/relayhost_map +# -- +# @domain1.com [smtp.mailgun.org]:587 +# @domain2.com [smtp.mailgun.org]:587 +# @domain3.com [smtp.mailgun.org]:587 +function populate_relayhost_map() { + echo -n > /etc/postfix/relayhost_map + chown root:root /etc/postfix/relayhost_map + chmod 0600 /etc/postfix/relayhost_map + + if [ -f /tmp/docker-mailserver/postfix-relaymap.cf ]; then + notify 'inf' "Adding relay mappings from postfix-relaymap.cf" + # Keep lines which are not a comment *and* have a destination. + sed -n '/^\s*[^#[:space:]]\S*\s\+\S/p' /tmp/docker-mailserver/postfix-relaymap.cf \ + >> /etc/postfix/relayhost_map + fi + # Note: Won't detect domains when lhs has spaces (but who does that?!). + sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf | + while read domain; do + if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map && + ! grep -qs -e "^\s*@${domain}\s*$" /tmp/docker-mailserver/postfix-relaymap.cf; then + # Domain not already present *and* not ignored. + notify 'inf' "Adding relay mapping for ${domain}" + echo "@${domain} [$RELAY_HOST]:$RELAY_PORT" >> /etc/postfix/relayhost_map + fi + done +} + # File storing the checksums of the monitored files. CHKSUM_FILE=/tmp/docker-mailserver-config-chksum diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index e9bde163..b456e43c 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -29,7 +29,7 @@ DEFAULT_VARS["POSTFIX_MAILBOX_SIZE_LIMIT"]="${POSTFIX_MAILBOX_SIZE_LIMIT:="0"}" DEFAULT_VARS["POSTFIX_INET_PROTOCOLS"]="${POSTFIX_INET_PROTOCOLS:="all"}" DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}" DEFAULT_VARS["SMTP_ONLY"]="${SMTP_ONLY:="0"}" -DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}" +# DEFAULT_VARS["DMS_DEBUG"] defined in helper_functions.sh DEFAULT_VARS["OVERRIDE_HOSTNAME"]="${OVERRIDE_HOSTNAME}" DEFAULT_VARS["POSTSCREEN_ACTION"]="${POSTSCREEN_ACTION:="enforce"}" DEFAULT_VARS["SPOOF_PROTECTION"]="${SPOOF_PROTECTION:="0"}" @@ -309,62 +309,6 @@ function _register_misc_function() { ########################################################################## -function notify () { - c_red="\e[0;31m" - c_green="\e[0;32m" - c_brown="\e[0;33m" - c_blue="\e[0;34m" - c_bold="\033[1m" - c_reset="\e[0m" - - notification_type=$1 - notification_msg=$2 - notification_format=$3 - msg="" - - case "${notification_type}" in - 'taskgrp') - msg="${c_bold}${notification_msg}${c_reset}" - ;; - 'task') - if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then - msg=" ${notification_msg}${c_reset}" - fi - ;; - 'inf') - if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then - msg="${c_green} * ${notification_msg}${c_reset}" - fi - ;; - 'started') - msg="${c_green} ${notification_msg}${c_reset}" - ;; - 'warn') - msg="${c_brown} * ${notification_msg}${c_reset}" - ;; - 'err') - msg="${c_red} * ${notification_msg}${c_reset}" - ;; - 'fatal') - msg="${c_red}Error: ${notification_msg}${c_reset}" - ;; - *) - msg="" - ;; - esac - - case "${notification_format}" in - 'n') - options="-ne" - ;; - *) - options="-e" - ;; - esac - - [[ ! -z "${msg}" ]] && echo $options "${msg}" -} - function defunc() { notify 'fatal' "Please fix your configuration. Exiting..." exit 1 @@ -1339,36 +1283,7 @@ function _setup_postfix_relay_hosts() { fi # end /etc/postfix/sasl_passwd - # setup /etc/postfix/relayhost_map - # -- - # @domain1.com [smtp.mailgun.org]:587 - # @domain2.com [smtp.mailgun.org]:587 - # @domain3.com [smtp.mailgun.org]:587 - - echo -n > /etc/postfix/relayhost_map - - if [ -f /tmp/docker-mailserver/postfix-relaymap.cf ]; then - notify 'inf' "Adding relay mappings from postfix-relaymap.cf" - while read line; do - if ! echo "$line" | grep -q -e "\s*#"; then - echo "$line" >> /etc/postfix/relayhost_map - fi - done < /tmp/docker-mailserver/postfix-relaymap.cf - fi - grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf | while IFS=$'|' read login pass - do - domain=$(echo ${login} | cut -d @ -f2) - if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map; then - notify 'inf' "Adding relay mapping for ${domain}" - echo "@${domain} [$RELAY_HOST]:$RELAY_PORT" >> /etc/postfix/relayhost_map - fi - done - # remove lines with no destination - sed -i '/^@\S*\s*$/d' /etc/postfix/relayhost_map - - chown root:root /etc/postfix/relayhost_map - chmod 0600 /etc/postfix/relayhost_map - # end /etc/postfix/relayhost_map + populate_relayhost_map postconf -e \ "smtp_sasl_auth_enable = yes" \ diff --git a/test/mail_with_relays.bats b/test/mail_with_relays.bats index fa2ea0ef..f57b749c 100644 --- a/test/mail_with_relays.bats +++ b/test/mail_with_relays.bats @@ -9,8 +9,13 @@ function teardown() { } function setup_file() { + # We use a temporary config directory since we'll be dynamically editing + # it with setup.sh. + tmp_confdir=$(mktemp -d /tmp/docker-mailserver-config-relay-hosts-XXXXX) + cp -aT test/config/relay-hosts "$tmp_confdir" + docker run -d --name mail_with_relays \ - -v "`pwd`/test/config/relay-hosts":/tmp/docker-mailserver \ + -v "$tmp_confdir":/tmp/docker-mailserver \ -v "`pwd`/test/test-files":/tmp/docker-mailserver-test:ro \ -e RELAY_HOST=default.relay.com \ -e RELAY_PORT=2525 \ @@ -25,6 +30,7 @@ function setup_file() { function teardown_file() { docker rm -f mail_with_relays + rm -rf "$tmp_confdir" } @test "first" { @@ -32,30 +38,45 @@ function teardown_file() { } @test "checking relay hosts: default mapping is added from env vars" { - run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/relayhost_map | grep -e "^@domainone.tld\s\+\[default.relay.com\]:2525" | wc -l | grep 1' - assert_success + run docker exec mail_with_relays grep -e domainone.tld /etc/postfix/relayhost_map + assert_output -e '^@domainone.tld\s+\[default.relay.com\]:2525$' +} + +@test "checking relay hosts: default mapping is added from env vars for new user entry" { + run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map + assert_output '' + run ./setup.sh -c mail_with_relays email add user0@domainzero.tld password123 + for i in {1..10}; do + sleep 1 + run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map + [[ $status == 0 ]] && break + done + assert_output -e '^@domainzero.tld\s+\[default.relay.com\]:2525$' } @test "checking relay hosts: custom mapping is added from file" { - run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/relayhost_map | grep -e "^@domaintwo.tld\s\+\[other.relay.com\]:587" | wc -l | grep 1' - assert_success + run docker exec mail_with_relays grep -e domaintwo.tld /etc/postfix/relayhost_map + assert_output -e '^@domaintwo.tld\s+\[other.relay.com\]:587$' } @test "checking relay hosts: ignored domain is not added" { - run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/relayhost_map | grep -e "^@domainthree.tld\s\+\[any.relay.com\]:25" | wc -l | grep 0' - assert_success + run docker exec mail_with_relays grep -e domainthree.tld /etc/postfix/relayhost_map + assert_failure 1 + assert_output '' } @test "checking relay hosts: auth entry is added" { - run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^@domaintwo.tld\s\+smtp_user_2:smtp_password_2" | wc -l | grep 1' + run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^@domaintwo.tld\s\+smtp_user_2:smtp_password_2" | wc -l' assert_success + assert_output 1 } @test "checking relay hosts: default auth entry is added" { - run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^\[default.relay.com\]:2525\s\+smtp_user:smtp_password" | wc -l | grep 1' + run docker exec mail_with_relays /bin/sh -c 'cat /etc/postfix/sasl_passwd | grep -e "^\[default.relay.com\]:2525\s\+smtp_user:smtp_password" | wc -l' assert_success + assert_output 1 } @test "last" { # this test is only there to reliably mark the end for the teardown_file -} \ No newline at end of file +} From 42352a32592a27d4df2154558866654c987b808d Mon Sep 17 00:00:00 2001 From: mwnx Date: Mon, 24 Aug 2020 22:53:54 +0200 Subject: [PATCH 3/3] Update relayhost_map with virtual accounts too Previously, only postfix-relaymap.cf and postfix-accounts.cf would be used to populate the relayhost_map file. Now, also use postfix-virtual.cf when present. To me, there is nothing absurd about sending mail "From:" a virtual account (or more specifically its domain) so it makes sense that when a $RELAY_HOST is defined it should be used for virtual accounts as well. --- target/check-for-changes.sh | 1 + target/helper_functions.sh | 9 ++++++--- test/config/relay-hosts/postfix-virtual.cf | 1 + test/mail_with_relays.bats | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test/config/relay-hosts/postfix-virtual.cf diff --git a/target/check-for-changes.sh b/target/check-for-changes.sh index 3ff8ffa1..c04ca6e0 100755 --- a/target/check-for-changes.sh +++ b/target/check-for-changes.sh @@ -81,6 +81,7 @@ if ! cmp --silent -- "$CHKSUM_FILE" "$CHKSUM_FILE.new"; then #regen postfix accounts. echo -n > /etc/postfix/vmailbox echo -n > /etc/dovecot/userdb + if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox diff --git a/target/helper_functions.sh b/target/helper_functions.sh index 50f829f5..bfb50c1a 100644 --- a/target/helper_functions.sh +++ b/target/helper_functions.sh @@ -149,9 +149,12 @@ function populate_relayhost_map() { sed -n '/^\s*[^#[:space:]]\S*\s\+\S/p' /tmp/docker-mailserver/postfix-relaymap.cf \ >> /etc/postfix/relayhost_map fi - # Note: Won't detect domains when lhs has spaces (but who does that?!). - sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf | - while read domain; do + { + # Note: Won't detect domains when lhs has spaces (but who does that?!). + sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf + [ -f /tmp/docker-mailserver/postfix-virtual.cf ] && + sed -n '/^\s*[^#[:space:]]/ s/^\s*[^@[:space:]]*@\(\S\+\)\s.*/\1/p' /tmp/docker-mailserver/postfix-virtual.cf + } | while read domain; do if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map && ! grep -qs -e "^\s*@${domain}\s*$" /tmp/docker-mailserver/postfix-relaymap.cf; then # Domain not already present *and* not ignored. diff --git a/test/config/relay-hosts/postfix-virtual.cf b/test/config/relay-hosts/postfix-virtual.cf new file mode 100644 index 00000000..e428c154 --- /dev/null +++ b/test/config/relay-hosts/postfix-virtual.cf @@ -0,0 +1 @@ +@domain1.tld user1@domainone.tld diff --git a/test/mail_with_relays.bats b/test/mail_with_relays.bats index f57b749c..5ae3e82d 100644 --- a/test/mail_with_relays.bats +++ b/test/mail_with_relays.bats @@ -42,6 +42,11 @@ function teardown_file() { assert_output -e '^@domainone.tld\s+\[default.relay.com\]:2525$' } +@test "checking relay hosts: default mapping is added from env vars for virtual user entry" { + run docker exec mail_with_relays grep -e domain1.tld /etc/postfix/relayhost_map + assert_output -e '^@domain1.tld\s+\[default.relay.com\]:2525$' +} + @test "checking relay hosts: default mapping is added from env vars for new user entry" { run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map assert_output '' @@ -54,6 +59,18 @@ function teardown_file() { assert_output -e '^@domainzero.tld\s+\[default.relay.com\]:2525$' } +@test "checking relay hosts: default mapping is added from env vars for new virtual user entry" { + run docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map + assert_output '' + run ./setup.sh -c mail_with_relays alias add user2@domain2.tld user2@domaintwo.tld + for i in {1..10}; do + sleep 1 + run docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map + [[ $status == 0 ]] && break + done + assert_output -e '^@domain2.tld\s+\[default.relay.com\]:2525$' +} + @test "checking relay hosts: custom mapping is added from file" { run docker exec mail_with_relays grep -e domaintwo.tld /etc/postfix/relayhost_map assert_output -e '^@domaintwo.tld\s+\[other.relay.com\]:587$'