#!/bin/bash # # configure-miab-metrics.sh - Enable extended metrics logging on Mail-in-a-Box # # Enables SpamAssassin rules logging and/or TLS cipher logging for # postfix-metrics.sh to collect detailed metrics. # set -euo pipefail SCRIPT_NAME=$(basename "$0") VERSION="1.0.0" # Defaults DRY_RUN=false VERBOSE=false ENABLE_SPAMASSASSIN=false ENABLE_TLS=false BACKUP=true FORCE=false STATUS_ONLY=false # Colors (disabled if not a terminal) if [[ -t 1 ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' else RED='' GREEN='' YELLOW='' BLUE='' NC='' fi usage() { cat <&2 } log_dry() { echo -e "${YELLOW}[DRY-RUN]${NC} $*" } log_verbose() { if $VERBOSE; then echo -e "${BLUE}[VERBOSE]${NC} $*" fi } run_cmd() { local desc="$1" shift if $DRY_RUN; then log_dry "$desc: $*" return 0 fi log_verbose "Running: $*" if ! "$@"; then log_error "Failed: $desc" return 1 fi return 0 } write_file() { local file="$1" local content="$2" local desc="${3:-$file}" if $DRY_RUN; then log_dry "Would create $desc:" echo "$content" | sed 's/^/ /' return 0 fi if [[ -f "$file" ]] && $BACKUP; then local backup="${file}.bak.$(date +%Y%m%d%H%M%S)" log_verbose "Backing up $file to $backup" cp "$file" "$backup" fi echo "$content" > "$file" log_ok "Created $desc" } check_root() { if [[ $EUID -ne 0 ]]; then log_error "This script must be run as root (use sudo)" exit 1 fi } check_miab() { if [[ ! -d /home/user-data ]] && [[ ! -f /etc/mailinabox.conf ]]; then log_warn "This doesn't appear to be a Mail-in-a-Box installation" if ! $FORCE; then read -rp "Continue anyway? [y/N] " response if [[ ! "$response" =~ ^[Yy] ]]; then exit 1 fi fi fi } confirm_action() { local msg="$1" if $FORCE || $DRY_RUN; then return 0 fi read -rp "$msg [y/N] " response [[ "$response" =~ ^[Yy] ]] } # ============================================================================ # SpamAssassin Configuration # ============================================================================ SPAMPD_DEFAULTS="/etc/default/spampd" check_spampd() { if ! systemctl list-unit-files spampd.service &>/dev/null; then log_error "spampd service not found" return 1 fi return 0 } is_spampd_debug_enabled() { # Check /etc/default/spampd for --debug in ADDOPTS if [[ -f "$SPAMPD_DEFAULTS" ]]; then if grep -qE '^ADDOPTS\s*=.*--debug' "$SPAMPD_DEFAULTS" 2>/dev/null; then return 0 fi fi return 1 } is_rsyslog_spamassassin_configured() { [[ -f /etc/rsyslog.d/50-spamassassin.conf ]] } is_logrotate_configured() { [[ -f /etc/logrotate.d/spamassassin ]] } configure_spamassassin() { log_info "Configuring SpamAssassin rules logging..." if ! check_spampd; then return 1 fi local changes_made=false # 1. Enable debug mode via /etc/default/spampd if is_spampd_debug_enabled; then log_ok "spampd debug mode already enabled" else log_info "Enabling spampd debug mode..." if [[ ! -f "$SPAMPD_DEFAULTS" ]]; then log_error "$SPAMPD_DEFAULTS not found" return 1 fi # Get current ADDOPTS value local current_addopts="" if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" 2>/dev/null; then current_addopts=$(grep -E '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" | tail -1 | sed 's/^ADDOPTS\s*=\s*//' | tr -d '"'"'") fi # Build new ADDOPTS with --debug appended local new_addopts if [[ -n "$current_addopts" ]]; then new_addopts="${current_addopts} --debug" else new_addopts="--debug" fi if $DRY_RUN; then log_dry "Would update ADDOPTS in $SPAMPD_DEFAULTS:" if [[ -n "$current_addopts" ]]; then echo " Current: ADDOPTS=\"$current_addopts\"" fi echo " New: ADDOPTS=\"$new_addopts\"" else if $BACKUP; then local backup="${SPAMPD_DEFAULTS}.bak.$(date +%Y%m%d%H%M%S)" cp "$SPAMPD_DEFAULTS" "$backup" log_verbose "Backed up to $backup" fi if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS"; then # Update existing ADDOPTS line sed -i "s|^ADDOPTS\s*=.*|ADDOPTS=\"$new_addopts\"|" "$SPAMPD_DEFAULTS" log_ok "Updated ADDOPTS to include --debug" else # Add new ADDOPTS line cat >> "$SPAMPD_DEFAULTS" </dev/null && [[ "$smtp_level" -ge 1 ]] 2>/dev/null } configure_tls() { log_info "Configuring TLS cipher logging..." if [[ ! -f "$POSTFIX_MAIN_CF" ]]; then log_error "Postfix main.cf not found at $POSTFIX_MAIN_CF" return 1 fi if is_tls_logging_enabled; then log_ok "TLS logging already enabled in Postfix" return 0 fi log_info "Adding TLS log level settings to $POSTFIX_MAIN_CF..." if $DRY_RUN; then log_dry "Would add to $POSTFIX_MAIN_CF:" echo " smtpd_tls_loglevel = 1" echo " smtp_tls_loglevel = 1" else if $BACKUP; then local backup="${POSTFIX_MAIN_CF}.bak.$(date +%Y%m%d%H%M%S)" cp "$POSTFIX_MAIN_CF" "$backup" log_verbose "Backed up to $backup" fi # Remove any existing settings first (to avoid duplicates) sed -i '/^smtpd_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF" sed -i '/^smtp_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF" # Add new settings cat >> "$POSTFIX_MAIN_CF" </dev/null | cut -f1) echo -e "${GREEN}EXISTS${NC} ($size)" else echo -e "${YELLOW}MISSING${NC}" fi echo -n "SpamAssassin logrotate: " if is_logrotate_configured; then echo -e "${GREEN}CONFIGURED${NC}" else echo -e "${YELLOW}NOT CONFIGURED${NC}" fi echo -n "Postfix TLS logging: " if is_tls_logging_enabled; then echo -e "${GREEN}ENABLED${NC}" else echo -e "${YELLOW}DISABLED${NC}" fi # Show service status echo "" echo -n "spampd service: " if systemctl is-active --quiet spampd 2>/dev/null; then echo -e "${GREEN}RUNNING${NC}" else echo -e "${YELLOW}STOPPED${NC}" fi echo -n "postfix service: " if systemctl is-active --quiet postfix 2>/dev/null; then echo -e "${GREEN}RUNNING${NC}" else echo -e "${YELLOW}STOPPED${NC}" fi echo "" } # ============================================================================ # Main # ============================================================================ main() { # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in -s|--spamassassin) ENABLE_SPAMASSASSIN=true shift ;; -t|--tls) ENABLE_TLS=true shift ;; -a|--all) ENABLE_SPAMASSASSIN=true ENABLE_TLS=true shift ;; -n|--dry-run) DRY_RUN=true shift ;; -f|--force) FORCE=true shift ;; -v|--verbose) VERBOSE=true shift ;; --no-backup) BACKUP=false shift ;; --status) STATUS_ONLY=true shift ;; -h|--help) usage ;; --version) version ;; *) log_error "Unknown option: $1" echo "Use --help for usage information" exit 1 ;; esac done # Default to both if neither specified if ! $ENABLE_SPAMASSASSIN && ! $ENABLE_TLS; then ENABLE_SPAMASSASSIN=true ENABLE_TLS=true fi # Check root (skip for dry-run or status-only) if ! $DRY_RUN && ! $STATUS_ONLY; then check_root fi check_miab # Show current status show_status # Exit if status-only mode if $STATUS_ONLY; then exit 0 fi # Build action summary local actions="" if $ENABLE_SPAMASSASSIN; then actions+="SpamAssassin rules logging" fi if $ENABLE_TLS; then [[ -n "$actions" ]] && actions+=", " actions+="TLS cipher logging" fi if $DRY_RUN; then log_info "DRY RUN - showing changes that would be made for: $actions" echo "" else if ! confirm_action "Enable $actions?"; then log_info "Aborted" exit 0 fi echo "" fi local exit_code=0 if $ENABLE_SPAMASSASSIN; then if ! configure_spamassassin; then exit_code=1 fi echo "" fi if $ENABLE_TLS; then if ! configure_tls; then exit_code=1 fi echo "" fi if [[ $exit_code -eq 0 ]]; then if $DRY_RUN; then log_info "Dry run complete - no changes made" else log_ok "Configuration complete!" echo "" echo "Metrics should now be available after some mail traffic." echo "Run your postfix-metrics.sh script to verify." fi else log_error "Some configurations failed" fi exit $exit_code } main "$@"