add script 'set_amavis_local_domains_maps.sh'.
This commit is contained in:
285
set_amavis_local_domains_maps.sh
Executable file
285
set_amavis_local_domains_maps.sh
Executable file
@@ -0,0 +1,285 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# amavis-local-domains-auto.sh
|
||||||
|
#
|
||||||
|
# Zweck
|
||||||
|
# -----
|
||||||
|
# Ersetzt in /etc/amavis/conf.d/50-user die lokale Domains-Definition
|
||||||
|
#
|
||||||
|
# @local_domains_maps = ( ["."] );
|
||||||
|
#
|
||||||
|
# durch eine dynamische Definition, die aus der (effektiv aktiven) Postfix-
|
||||||
|
# Konfiguration ermittelt wird (pgsql oder mysql). Damit werden Spam-Header
|
||||||
|
# nur für Domains geschrieben, die Postfix tatsächlich als "lokal/relay" kennt.
|
||||||
|
#
|
||||||
|
# WICHTIG:
|
||||||
|
# - Das Skript ändert NUR dann etwas, wenn die Zeile exakt ( ["."] ); ist.
|
||||||
|
# - Backups werden IMMER nach /etc/amavis/ geschrieben (nicht neben die Datei).
|
||||||
|
# - DB-Typ wird automatisch aus "postconf -n" erkannt (robust inkl. includes).
|
||||||
|
#
|
||||||
|
# Features
|
||||||
|
# --------
|
||||||
|
# - Auto-Detect Backend: pgsql | mysql (aus Postfix-Maps)
|
||||||
|
# - Optionaler Fallback: wenn DB nicht erkennbar, dann auf ( ["."] ); setzen
|
||||||
|
# (standardmäßig AUS, weil produktiver Betrieb)
|
||||||
|
# - Dry-run Modus
|
||||||
|
# - Optional reload/restart von amavis
|
||||||
|
# - Atomare Aktualisierung (schreibt erst tmp, dann mv)
|
||||||
|
#
|
||||||
|
# Nutzung
|
||||||
|
# -------
|
||||||
|
# sudo ./amavis-local-domains-auto.sh --dry-run
|
||||||
|
# sudo ./amavis-local-domains-auto.sh --apply --reload
|
||||||
|
# sudo ./amavis-local-domains-auto.sh --apply --restart
|
||||||
|
#
|
||||||
|
# Optional:
|
||||||
|
# sudo ./amavis-local-domains-auto.sh --apply --allow-fallback-all
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Konfigurierbare Pfade
|
||||||
|
# ----------------------------
|
||||||
|
AMAVIS_50="${AMAVIS_50:-/etc/amavis/conf.d/50-user}"
|
||||||
|
|
||||||
|
# Backup-Verzeichnis (gewünscht: /etc/amavis/)
|
||||||
|
BACKUP_DIR="${BACKUP_DIR:-/etc/amavis}"
|
||||||
|
|
||||||
|
# Optional: Dateimap für relay_domains (falls vorhanden)
|
||||||
|
RELAY_BTREE_DEFAULT="/etc/postfix/relay_domains"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Schalter / Optionen
|
||||||
|
# ----------------------------
|
||||||
|
DO_APPLY=false
|
||||||
|
DO_DRY_RUN=false
|
||||||
|
DO_RESTART=false
|
||||||
|
DO_RELOAD=false
|
||||||
|
ALLOW_FALLBACK_ALL=false
|
||||||
|
|
||||||
|
# Optional overrides
|
||||||
|
HOST_FQDN_OVERRIDE=""
|
||||||
|
RELAY_BTREE_OVERRIDE=""
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
amavis-local-domains-auto.sh [OPTIONS]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--dry-run Show what would change, do not modify files
|
||||||
|
--apply Apply change (only if @local_domains_maps is exactly ( ["."] );)
|
||||||
|
--restart Restart amavis after apply
|
||||||
|
--reload Reload amavis after apply (preferred if supported)
|
||||||
|
--allow-fallback-all If DB backend not detectable, replace with ( ["."] ); anyway
|
||||||
|
(default: fail safely / do nothing)
|
||||||
|
--host-fqdn FQDN Override hostname -f used in the block
|
||||||
|
--relay-btree PATH Override btree file path (default: /etc/postfix/relay_domains)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
sudo ./amavis-local-domains-auto.sh --dry-run
|
||||||
|
sudo ./amavis-local-domains-auto.sh --apply --reload
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
die(){ echo "ERROR: $*" >&2; exit 1; }
|
||||||
|
log(){ echo "INFO: $*" >&2; }
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Argumente parsen
|
||||||
|
# ----------------------------
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dry-run) DO_DRY_RUN=true; shift ;;
|
||||||
|
--apply) DO_APPLY=true; shift ;;
|
||||||
|
--restart) DO_RESTART=true; shift ;;
|
||||||
|
--reload) DO_RELOAD=true; shift ;;
|
||||||
|
--allow-fallback-all) ALLOW_FALLBACK_ALL=true; shift ;;
|
||||||
|
--host-fqdn) HOST_FQDN_OVERRIDE="${2:-}"; shift 2 ;;
|
||||||
|
--relay-btree) RELAY_BTREE_OVERRIDE="${2:-}"; shift 2 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) die "Unknown option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! $DO_DRY_RUN && ! $DO_APPLY; then
|
||||||
|
die "Choose one: --dry-run or --apply"
|
||||||
|
fi
|
||||||
|
if $DO_RESTART && $DO_RELOAD; then
|
||||||
|
die "Choose only one: --restart or --reload"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Sanity Checks
|
||||||
|
# ----------------------------
|
||||||
|
command -v postconf >/dev/null || die "postconf not found"
|
||||||
|
[[ -r "$AMAVIS_50" ]] || die "Missing $AMAVIS_50"
|
||||||
|
[[ -d "$BACKUP_DIR" ]] || die "Backup dir missing: $BACKUP_DIR"
|
||||||
|
[[ -w "$BACKUP_DIR" ]] || die "Backup dir not writable: $BACKUP_DIR"
|
||||||
|
|
||||||
|
HOST_FQDN="${HOST_FQDN_OVERRIDE:-$(hostname -f 2>/dev/null || hostname)}"
|
||||||
|
RELAY_BTREE="${RELAY_BTREE_OVERRIDE:-$RELAY_BTREE_DEFAULT}"
|
||||||
|
|
||||||
|
# Regex: exakt @local_domains_maps = ( ["."] );
|
||||||
|
DOTLINE_REGEX='^[[:space:]]*@local_domains_maps[[:space:]]*=[[:space:]]*\([[:space:]]*\[[[:space:]]*"\."[[:space:]]*\][[:space:]]*\)[[:space:]]*;[[:space:]]*$'
|
||||||
|
|
||||||
|
if ! grep -qE "$DOTLINE_REGEX" "$AMAVIS_50"; then
|
||||||
|
log "No change: @local_domains_maps is not exactly ( [\".\"] );"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# DB-Typ + Map-Dateien aus Postfix ermitteln
|
||||||
|
# (postconf -n berücksichtigt includes, master.d, etc.)
|
||||||
|
# ----------------------------
|
||||||
|
VMD_LINE="$(postconf -n virtual_mailbox_domains 2>/dev/null || true)"
|
||||||
|
RD_LINE="$(postconf -n relay_domains 2>/dev/null || true)"
|
||||||
|
|
||||||
|
extract_db_map() {
|
||||||
|
# Findet den ersten Token, der :pgsql: oder :mysql: enthält
|
||||||
|
# und gibt "scheme|/path/to/map.cf" aus.
|
||||||
|
local line="$1"
|
||||||
|
for tok in $line; do
|
||||||
|
tok="${tok%,}"
|
||||||
|
if [[ "$tok" == *":pgsql:"* ]]; then
|
||||||
|
echo "pgsql|${tok##*:pgsql:}"
|
||||||
|
return 0
|
||||||
|
elif [[ "$tok" == *":mysql:"* ]]; then
|
||||||
|
echo "mysql|${tok##*:mysql:}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
DB_SCHEME=""
|
||||||
|
VDOM_CF=""
|
||||||
|
RELAY_CF=""
|
||||||
|
|
||||||
|
if out="$(extract_db_map "$VMD_LINE")"; then
|
||||||
|
DB_SCHEME="${out%%|*}"
|
||||||
|
VDOM_CF="${out##*|}"
|
||||||
|
else
|
||||||
|
if $ALLOW_FALLBACK_ALL; then
|
||||||
|
DB_SCHEME="all"
|
||||||
|
else
|
||||||
|
die "Could not detect pgsql/mysql from postfix virtual_mailbox_domains. Use --allow-fallback-all to force."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DB_SCHEME" != "all" ]]; then
|
||||||
|
if out="$(extract_db_map "$RD_LINE")"; then
|
||||||
|
rd_scheme="${out%%|*}"
|
||||||
|
rd_cf="${out##*|}"
|
||||||
|
if [[ "$rd_scheme" == "$DB_SCHEME" ]]; then
|
||||||
|
RELAY_CF="$rd_cf"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -r "$VDOM_CF" ]] || die "Detected map not readable: $VDOM_CF"
|
||||||
|
if [[ -n "$RELAY_CF" ]]; then
|
||||||
|
[[ -r "$RELAY_CF" ]] || die "Detected relay map not readable: $RELAY_CF"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Replacement-Block bauen (in temp Datei)
|
||||||
|
# ----------------------------
|
||||||
|
TMPDIR="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
BLOCKFILE="$TMPDIR/block.txt"
|
||||||
|
|
||||||
|
if [[ "$DB_SCHEME" == "all" ]]; then
|
||||||
|
cat >"$BLOCKFILE" <<'EOF'
|
||||||
|
@local_domains_maps = ( ["."] );
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "@local_domains_maps = ("
|
||||||
|
echo " [qw(${HOST_FQDN} localhost)],"
|
||||||
|
echo ""
|
||||||
|
echo " # Domains, die als virtuelle Mailbox-Domains gehostet sind:"
|
||||||
|
echo " '${DB_SCHEME}:${VDOM_CF}',"
|
||||||
|
if [[ -n "$RELAY_CF" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo " # Domains, die als relay_domains akzeptiert werden:"
|
||||||
|
echo " '${DB_SCHEME}:${RELAY_CF}',"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo " # relay_domains DB-map nicht erkannt – wird übersprungen"
|
||||||
|
fi
|
||||||
|
echo " 'btree:${RELAY_BTREE}',"
|
||||||
|
echo ");"
|
||||||
|
} >"$BLOCKFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Geplante Änderung anzeigen
|
||||||
|
# ----------------------------
|
||||||
|
log "Detected backend: ${DB_SCHEME}"
|
||||||
|
if [[ "$DB_SCHEME" != "all" ]]; then
|
||||||
|
log "virtual_mailbox_domains map: ${DB_SCHEME}:${VDOM_CF}"
|
||||||
|
if [[ -n "$RELAY_CF" ]]; then
|
||||||
|
log "relay_domains map: ${DB_SCHEME}:${RELAY_CF}"
|
||||||
|
else
|
||||||
|
log "relay_domains map: (not detected / not used)"
|
||||||
|
fi
|
||||||
|
log "btree relay domains: btree:${RELAY_BTREE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $DO_DRY_RUN; then
|
||||||
|
echo "----- Would replace this line in $AMAVIS_50 -----"
|
||||||
|
echo '@local_domains_maps = ( ["."] );'
|
||||||
|
echo "----- With this block -----"
|
||||||
|
cat "$BLOCKFILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Backup in /etc/amavis/ erstellen
|
||||||
|
# ----------------------------
|
||||||
|
STAMP="$(date +%F_%H%M%S)"
|
||||||
|
BACKUP_FILE="${BACKUP_DIR}/50-user.bak.${STAMP}"
|
||||||
|
cp -a "$AMAVIS_50" "$BACKUP_FILE"
|
||||||
|
log "Backup created: $BACKUP_FILE"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Datei neu schreiben (atomar)
|
||||||
|
# - Wir ersetzen nur die exakt passende (["."]) Zeile durch den neuen Block.
|
||||||
|
# ----------------------------
|
||||||
|
OUTFILE="$TMPDIR/50-user.new"
|
||||||
|
|
||||||
|
awk -v blockfile="$BLOCKFILE" '
|
||||||
|
BEGIN {
|
||||||
|
while ((getline line < blockfile) > 0) {
|
||||||
|
newblock = newblock line "\n"
|
||||||
|
}
|
||||||
|
close(blockfile)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if ($0 ~ /^[[:space:]]*@local_domains_maps[[:space:]]*=[[:space:]]*\([[:space:]]*\[[[:space:]]*"\."[[:space:]]*\][[:space:]]*\)[[:space:]]*;[[:space:]]*$/) {
|
||||||
|
printf "%s", newblock
|
||||||
|
} else {
|
||||||
|
print
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$AMAVIS_50" > "$OUTFILE"
|
||||||
|
|
||||||
|
mv "$OUTFILE" "$AMAVIS_50"
|
||||||
|
log "Updated $AMAVIS_50"
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Optionaler Reload/Restart von amavis
|
||||||
|
# ----------------------------
|
||||||
|
if $DO_RELOAD; then
|
||||||
|
log "Reloading amavis..."
|
||||||
|
systemctl reload amavis || die "amavis reload failed"
|
||||||
|
elif $DO_RESTART; then
|
||||||
|
log "Restarting amavis..."
|
||||||
|
systemctl restart amavis || die "amavis restart failed"
|
||||||
|
else
|
||||||
|
log "No service action requested (--reload/--restart)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Done."
|
||||||
|
|
||||||
Reference in New Issue
Block a user