From 20d4c95404644c04b732d8e75485cc97d1c1de25 Mon Sep 17 00:00:00 2001 From: Christoph Date: Wed, 12 Nov 2025 23:59:59 +0100 Subject: [PATCH 1/2] install_postfix_advanced.sh: add support for DMARC reporting. --- install_postfix_advanced.sh | 191 +++++++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 4 deletions(-) diff --git a/install_postfix_advanced.sh b/install_postfix_advanced.sh index 6819d6a..2c98d3e 100755 --- a/install_postfix_advanced.sh +++ b/install_postfix_advanced.sh @@ -131,6 +131,8 @@ DEFAULT_SASL_AUTH_ENABLED=no DEFAULT_LISTEN_ON_ADDITIONAL_RELAY_PORT=false +DEFAULT_INSTALL_DMARC_REPORT_SUPPORT=false + # - Is this a systemd system? # - @@ -174,6 +176,11 @@ if [[ -z "$_LISTEN_ON_ADDITIONAL_RELAY_PORT" ]] ; then _LISTEN_ON_ADDITIONAL_RELAY_PORT=${DEFAULT_LISTEN_ON_ADDITIONAL_RELAY_PORT} fi +if [[ -z "$_INSTALL_DMARC_REPORT_SUPPORT" ]] ; then + _INSTALL_DMARC_REPORT_SUPPORT=${DEFAULT_INSTALL_DMARC_REPORT_SUPPORT} +fi + + echo "" echo "" echo "" @@ -443,6 +450,24 @@ else fi +if ! ${IS_RELAY_HOST} ; then + INSTALL_DMARC_REPORT_SUPPORT=false + echo "" + echo -e "\033[32m--\033[m" + echo "" + echo "Should this mail server support DMARC reporting?" + echo "" + echononl "Support DMARC reporting ? [ ${_INSTALL_DMARC_REPORT_SUPPORT} ]: " + read INPUT + if [[ "X${INPUT}" == "X" ]]; then + INPUT=$_INSTALL_DMARC_REPORT_SUPPORT + fi + if [[ "${INPUT,,}" == "yes" || "${INPUT,,}" == "true" ]]; then + INSTALL_DMARC_REPORT_SUPPORT=true + fi +fi + + ADMIN_EMAIL= echo "" echo "" @@ -459,10 +484,10 @@ if [[ -n "$_ADMIN_EMAIL" ]]; then fi else while [[ "X${ADMIN_EMAIL}" = "X" ]]; do - echononl "Admin e-mail address: " - read ADMIN_EMAIL - if [[ "X${ADMIN_EMAIL}" = "X" ]]; then - echo -e "\n\t\033[33m\033[1mAdmin e-mail address is reqired\033[m\n" + echononl "Admin e-mail address: " + read ADMIN_EMAIL + if [[ "X${ADMIN_EMAIL}" = "X" ]]; then + echo -e "\n\t\033[33m\033[1mAdmin e-mail address is reqired\033[m\n" fi done fi @@ -492,6 +517,8 @@ if $IS_RELAY_HOST ; then else echo -e "\tConfigure as relay host?..........: $IS_RELAY_HOST" echo -e "\tConfigure as complete mailserver..: \033[33m\033[1mtrue\033[m" + echo "" + echo -e "\tSupport DMARC reporting...........: \033[33m\033[1m${INSTALL_DMARC_REPORT_SUPPORT}\033[m" fi echo "" echononl "einverstanden (yes/no): " @@ -535,6 +562,10 @@ EOF _ADDITIONAL_RELAY_LISTEN_PORT=${ADDITIONAL_RELAY_LISTEN_PORT} EOF fi +else + cat << EOF >> $conf_file +_INSTALL_DMARC_REPORT_SUPPORT=${INSTALL_DMARC_REPORT_SUPPORT} +EOF fi if [[ $? -ne 0 ]]; then _failed=true @@ -547,6 +578,9 @@ fi [[ "$IPV6" = "disabled" ]] && IPV6="" +exit +clean_up 1 + # - Synchronise package index files with the repository # - @@ -592,6 +626,9 @@ _needed_packages="postfix postfix-pgsql postfix-mysql postfix-pcre libsasl2-modu if [[ "$SASL_AUTH_ENABLED" = "yes" ]]; then _needed_packages="$_needed_packages sasl2-bin" fi +if ${INSTALL_DMARC_REPORT_SUPPORT} ; then + _needed_packages="$_needed_packages ripmime xmlstarlet unzip gzip" +fi for _pkg in $_needed_packages ; do if `dpkg -l | grep $_pkg | grep -e "^i" > /dev/null 2>&1` ; then continue @@ -3411,6 +3448,7 @@ else fi + echononl " Create file \"relay_domains\"" if [[ ! -f /etc/postfix/relay_domains ]] ; then touch /etc/postfix/relay_domains @@ -3752,6 +3790,133 @@ EOF fi +if ${INSTALL_DMARC_REPORT_SUPPORT} ; then + # ---- + # - Add support for DMARC report + # ---- + + # - /var/lib/dmarc/ + # - ├── reports/ # Eingegangene XML-, GZ-, ZIP-Dateien + # - │ └── YYYY/MM/DD/ # Datumsbasierte Ablage + # - ├── processed/ # Originalmails (Archiv) + # - ├── exports/ # CSV- und Top-Auswertungen + # - └── logs/ # Logdateien + echononl "Add directory Structure for collecting and analysing DMARC reports.." + install -d -o root -g root -m 750 /var/lib/dmarc/{reports,processed,exports,logs} > /dev/null 2> $log_file + if [[ $? -eq 0 ]] ; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + + echononl "Add 'dmarc-pipe' entry to $postfix_master_cf .." + cat <> /etc/postfix/transport 2> $log_file + +# - Take care your master.cf file ($postfix_master_cf) contains: +# - +# - dmarc-pipe unix - n n - - pipe +# - flags=Rq user=vmail argv=/usr/local/bin/dmarc-collect.sh +# - +dmarc-reports@oopen.de dmarc-pipe: + +EOF + if [[ $? -eq 0 ]] ; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + + echononl "Create Postfix lookup table '/etc/postfix/transport'.." + postmap btree:/etc/postfix/transport > /dev/null 2> $log_file + if [[ $? -eq 0 ]] ; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + + echononl "Create script '/usr/local/bin/dmarc-collect.sh'.." + tee /usr/local/bin/dmarc-collect.sh > /dev/null 2> $log_file <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +BASE="/var/lib/dmarc" +INBOX="$BASE/reports" +PROC="$BASE/processed" +LOGF="$BASE/logs/collector.log" + +umask 027 + +TMPDIR="$(mktemp -d)" +EML="$TMPDIR/mail.eml" +cat > "$EML" + +ripmime --no-nameless --name-by-type --overwrite -i "$EML" -d "$TMPDIR" >>"$LOGF" 2>&1 || true + +TODAY="$(date -u +%Y/%m/%d)" +OUTDIR="$INBOX/$TODAY" +mkdir -p "$OUTDIR" + +moved=0 +shopt -s nullglob +for f in "$TMPDIR"/*; do + case "$f" in + *.xml|*.XML|*.gz|*.zip) + sha="$(sha256sum "$f" | awk '{print $1}')" + base="$(basename "$f")" + dst="$OUTDIR/$(date -u +%Y%m%dT%H%M%SZ)_${sha:0:12}_$base" + mv "$f" "$dst" + echo "$(date -Is) stored $dst" >> "$LOGF" + moved=$((moved+1)) + ;; + *) : ;; + esac +done + +mkdir -p "$PROC" +mv "$EML" "$PROC/$(date -u +%Y%m%dT%H%M%SZ)_mail.eml" || true +rm -rf "$TMPDIR" + +if (( moved > 0 )); then + exit 0 +else + echo "$(date -Is) no usable attachment in message" >> "$LOGF" + exit 0 +fi + +EOF + if [[ $? -eq 0 ]] ; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + + _failed=false + echononl "Set permissions for '/usr/local/bin/dmarc-collect.sh'.." + chown vmail:vmail /usr/local/bin/dmarc-collect.sh > /dev/null 2> $log_file + if [[ $? -ne 0 ]] ; then + _failed=true + fi + + chmod 750 /usr/local/bin/dmarc-collect.sh > /dev/null 2>> $log_file + if [[ $? -ne 0 ]] ; then + _failed=true + fi + + + if ${_failed} ; then + echo_failed + error "$(cat $log_file)" + else + echo_ok + fi + +fi + + ## - /etc/postfix/master.cf ## - ## - Create Listener for user authenticated smtp connection port 587 (submission) @@ -3784,6 +3949,12 @@ else policyd_spf_present=false fi +if grep -iq -E "^dmarc-pipe\s+" $postfix_master_cf > /dev/null 2>&1 ; then + dmarc_pipe_present=true +else + dmarc_pipe_present=false +fi + _found=false echononl " Create new file \"${postfix_master_cf}\"" if [[ -f "${postfix_master_cf}.$backup_date" ]]; then @@ -3894,6 +4065,18 @@ smtp-ipv6-only unix - - n - - smtp EOF fi + # - Add support for DMARC reporting + # - + if ${INSTALL_DMARC_REPORT_SUPPORT} ; then + if ! $(grep -iq -E "^dmarc-pipe\s+" "$postfix_master_cf" 2> /dev/null) ; then + cat <> $postfix_master_cf + +dmarc-pipe unix - n n - - pipe + flags=Rq user=vmail argv=/usr/local/bin/dmarc-collect.sh +EOF + fi + fi + echo_done warn "Please check file \"$postfix_master_cf\" !" else From 0303c79b0398e6f28a466d65c96f678b37a53e67 Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 13 Nov 2025 00:19:15 +0100 Subject: [PATCH 2/2] install_postfix_advanced.sh: fix permissions to service scripts for DMARC reporting. --- install_postfix_advanced.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_postfix_advanced.sh b/install_postfix_advanced.sh index 2c98d3e..f957b46 100755 --- a/install_postfix_advanced.sh +++ b/install_postfix_advanced.sh @@ -3802,7 +3802,7 @@ if ${INSTALL_DMARC_REPORT_SUPPORT} ; then # - ├── exports/ # CSV- und Top-Auswertungen # - └── logs/ # Logdateien echononl "Add directory Structure for collecting and analysing DMARC reports.." - install -d -o root -g root -m 750 /var/lib/dmarc/{reports,processed,exports,logs} > /dev/null 2> $log_file + install -d -o vmail -g vmail -m 750 /var/lib/dmarc/{reports,processed,exports,logs} > /dev/null 2> $log_file if [[ $? -eq 0 ]] ; then echo_ok else