From ff49c1d0e47d85bdfce6fdbe8f6b1e75dda0d5f7 Mon Sep 17 00:00:00 2001 From: Andrew Cutler Date: Thu, 22 Jan 2026 15:10:52 +1100 Subject: [PATCH] Fix SMTPD_USERS sasl authentication broken by drift in postfix chroot configuration --- Dockerfile | 2 +- Makefile | 21 +++++++++++++++++---- etc/s6/postfix/run | 7 ++++--- test/postfix.bats | 34 ++++++++++++++++++++++++++++++++++ test/sasl.bats | 26 ++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 test/sasl.bats diff --git a/Dockerfile b/Dockerfile index 08f9eff..ebf40f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,7 +66,7 @@ FROM base AS development RUN set -x \ && export DEBIAN_FRONTEND=noninteractive \ && apt-get update \ -&& apt-get install -y --no-install-recommends bats \ +&& apt-get install -y --no-install-recommends bats swaks \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ ; diff --git a/Makefile b/Makefile index b61fe81..516cbd8 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,18 @@ run: ## Runs the docker image in a test mode @docker attach ${ID} @docker kill ${ID} +run-users: ## Runs the docker image in a test mode with SMTPD_USERS + $(eval ID := $(shell docker rm -f $(NAME) >/dev/null 2>&1; docker run -d --name $(NAME) --hostname mail.example.com \ + -e MAILNAME=mail.example.com \ + -e SIZELIMIT=20480000 \ + -e SMTPD_USERS='user1:pass1,user2:pass2' \ + -e LOGOUTPUT=/var/log/maillog \ + $(IMAGE_NAME):$(TAG))) + $(eval IP := $(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${ID})) + @echo "Running ${ID} @ smtp://${IP}" + @docker attach ${ID} + @docker kill ${ID} + run-dkim: dkim.key ## Runs the docker image in a test mode with DKIM $(eval ID := $(shell docker rm -f $(NAME) >/dev/null 2>&1; docker run -d --name $(NAME) --hostname mail.example.com \ -e RELAYHOST=172.17.0.2 \ @@ -53,11 +65,12 @@ push: ## Pushes the docker image to hub.docker.com docker push $(IMAGE_NAME):$(TAG) clean: ## Remove built image - docker rmi $(IMAGE_NAME):$(TAG) + docker rmi $(IMAGE_NAME):$(TAG) || true + docker rmi $(IMAGE_NAME):$(TAG)-dev || true -test: ## Build a test image and run bats tests in docker - docker build --target development -t $(IMAGE_NAME):test-dev . - docker run --rm -v $(shell pwd):/app -w /app $(IMAGE_NAME):test-dev bats test/ +test: clean ## Build a test image and run bats tests in docker + docker build --target development -t $(IMAGE_NAME):$(TAG)-dev . + docker run --rm -v $(shell pwd):/src -w /src $(IMAGE_NAME):$(TAG)-dev bats test/ _ci_test: test true diff --git a/etc/s6/postfix/run b/etc/s6/postfix/run index 171977b..c0f6240 100755 --- a/etc/s6/postfix/run +++ b/etc/s6/postfix/run @@ -205,10 +205,11 @@ if [ ! -z "${SMTPD_USERS}" ]; then echo "postfix >> Adding user SASL user: ${user}" echo "${password}" | saslpasswd2 -p -c -u "${MAILNAME}" "${user}" done < <(echo "${SMTPD_USERS}" | tr ',' '\n') - echo "smtp >> Info: \"saslpasswd2: error deleting entry from sasldb: BDB0073 DB_NOTFOUND: No matching key/data pair found\" can be ignored see https://github.com/cyrusimap/cyrus-sasl/issues/264" - chown postfix:sasl /etc/sasldb2 + # give postfix user access to the sasldb + usermod -aG sasl postfix + chown root:sasl /etc/sasldb2 # /etc/sasldb2 needs to be in the postfix chroot, this is a bit of a hack - sed -i -E 's/etc\/host\.conf etc\/nsswitch\.conf etc\/nss_mdns\.config"/etc\/host.conf etc\/nsswitch.conf etc\/nss_mdns.config etc\/sasldb2"/' /usr/lib/postfix/configure-instance.sh + sed -i -E 's/^chroot_extra_files=$/chroot_extra_files=etc\/sasldb2/' /usr/lib/postfix/configure-instance.sh fi # Configure logging diff --git a/test/postfix.bats b/test/postfix.bats index 3936c85..8663bd7 100644 --- a/test/postfix.bats +++ b/test/postfix.bats @@ -89,3 +89,37 @@ teardown() { [ "$status" -eq 0 ] [ "$output" = "inet:localhost:8891" ] } + +@test "SMTPD_USERS sets up smtpd.conf and enables SASL" { + # Execute the setup script with the necessary environment variables + ( + # Set env vars to test against + export MAILNAME="test.example.com" + export MYNETWORKS="10.0.0.0/8 127.0.0.0/8" + export SMTPD_USERS='user1:pass1,user2:pass2' + export USE_TLS="no" # Disable TLS to avoid slow cert generation + + # Execute the setup script + bash -x "${BATS_TMPDIR}/run" + ) + + run postconf -h smtpd_sasl_auth_enable + [ "$status" -eq 0 ] + [ "$output" = "yes" ] + + run postconf -h broken_sasl_auth_clients + [ "$status" -eq 0 ] + [ "$output" = "yes" ] + + run postconf -h smtpd_sasl_local_domain + [ "$status" -eq 0 ] + [ "$output" = '$myhostname' ] + + # Check /etc/postfix/sasl/smtpd.conf + run cat /etc/postfix/sasl/smtpd.conf + [ "$status" -eq 0 ] + [[ "$output" =~ "pwcheck_method: auxprop" ]] + [[ "$output" =~ "auxprop_plugin: sasldb" ]] + [[ "$output" =~ "mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM" ]] + +} diff --git a/test/sasl.bats b/test/sasl.bats new file mode 100644 index 0000000..dda8e90 --- /dev/null +++ b/test/sasl.bats @@ -0,0 +1,26 @@ +#!/usr/bin/env bats + +setup() { + # The entrypoint script will configure and start all services via s6 + # We run it in the background to not block the test + env MAILNAME='mail.example.com' SMTPD_USERS='user:password' MYNETWORKS='10.0.0.0/8' /entry.sh /usr/bin/s6-svscan /etc/s6 & + # And give it some time to start up + sleep 5 +} + +teardown() { + # Stop the s6 supervisor and all its services + s6-svscanctl -t /etc/s6 +} + +@test "Test SMTPD_USERS sasl authentication" { + # Test auth on submission port + run swaks --to "test@example.com" \ + --from "user@example.com" \ + --server "127.0.0.1:587" \ + --auth-user "user" \ + --auth-password "password" + echo "status: ${status}" + echo "output: ${output}" + [ "${status}" -eq 0 ] +}