#!/usr/bin/env bash
# setup-mail.sh — Self-Hosted Email Server lab (ch.7)
# ---------------------------------------------------------------------------
# Stands up Postfix (SMTP + submission) + Dovecot (IMAP) + OpenDKIM/OpenDMARC on
# Debian 13 with self-signed TLS, a test mailbox, and signing keys.
# LAB-SAFE: Postfix is bound loopback-only and outbound :25 is blocked — you
# validate delivery INTERNALLY, you do not send to the internet.
# Run as root:  ./setup-mail.sh [domain]
# ---------------------------------------------------------------------------
set -uo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
print_header(){ echo -e "\n${GREEN}=== $1 ===${NC}"; }
die(){ echo -e "${RED}[x] $1${NC}"; exit 1; }
[[ ${EUID:-$(id -u)} -eq 0 ]] || die "Run as root."
export DEBIAN_FRONTEND=noninteractive
DOMAIN="${1:-lab.local}"
FQDN="mail.${DOMAIN}"

print_header "Installing Postfix, Dovecot, OpenDKIM, OpenDMARC"
debconf-set-selections <<<"postfix postfix/mailname string ${DOMAIN}"
debconf-set-selections <<<"postfix postfix/main_mailer_type string 'Internet Site'"
apt-get update -qq
apt-get install -y postfix dovecot-imapd dovecot-pop3d opendkim opendkim-tools \
                   opendmarc mailutils openssl || die "package install failed"

print_header "Self-signed TLS (lab only)"
install -d /etc/mail/tls
[ -f /etc/mail/tls/mail.crt ] || openssl req -x509 -newkey rsa:2048 -nodes -days 825 \
  -keyout /etc/mail/tls/mail.key -out /etc/mail/tls/mail.crt -subj "/CN=${FQDN}" >/dev/null 2>&1
chmod 600 /etc/mail/tls/mail.key

print_header "Configuring Postfix"
postconf -e "myhostname = ${FQDN}"
postconf -e "mydomain = ${DOMAIN}"
postconf -e "myorigin = \$mydomain"
postconf -e "mydestination = \$myhostname, ${DOMAIN}, localhost.localdomain, localhost"
postconf -e "home_mailbox = Maildir/"
postconf -e "inet_interfaces = loopback-only"     # lab safety: do not listen on the wire
postconf -e "inet_protocols = ipv4"
postconf -e "relayhost ="                          # never relay to the internet
postconf -e "smtpd_tls_cert_file = /etc/mail/tls/mail.crt"
postconf -e "smtpd_tls_key_file = /etc/mail/tls/mail.key"
postconf -e "smtpd_tls_security_level = may"
postconf -e "smtp_tls_security_level = may"
postconf -e "smtpd_sasl_type = dovecot"
postconf -e "smtpd_sasl_path = private/auth"
postconf -e "smtpd_sasl_auth_enable = yes"
postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"
postconf -e "milter_default_action = accept"
postconf -e "smtpd_milters = local:opendkim/opendkim.sock, local:opendmarc/opendmarc.sock"
postconf -e "non_smtpd_milters = \$smtpd_milters"
# authenticated submission on 587 (TLS required)
postconf -M submission/inet="submission inet n - y - - smtpd"
postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"

print_header "Configuring Dovecot (IMAP + SASL socket for Postfix)"
sed -i 's|^#\?mail_location =.*|mail_location = maildir:~/Maildir|' /etc/dovecot/conf.d/10-mail.conf
sed -i 's/^#\?disable_plaintext_auth =.*/disable_plaintext_auth = yes/' /etc/dovecot/conf.d/10-auth.conf
sed -i 's/^#\?auth_mechanisms =.*/auth_mechanisms = plain login/' /etc/dovecot/conf.d/10-auth.conf
cat > /etc/dovecot/conf.d/99-postfix-sasl.conf <<'EOF'
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode  = 0660
    user  = postfix
    group = postfix
  }
}
EOF

print_header "OpenDKIM signing + DNS records to publish"
install -d -o opendkim -g opendkim "/etc/opendkim/keys/${DOMAIN}"
opendkim-genkey -b 2048 -d "${DOMAIN}" -s mail -D "/etc/opendkim/keys/${DOMAIN}" 2>/dev/null || true
chown -R opendkim:opendkim /etc/opendkim
cat > /etc/opendkim.conf <<EOF
Syslog yes
UMask 007
Mode sv
Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
InternalHosts 127.0.0.1, ::1, ${DOMAIN}
EOF
echo "mail._domainkey.${DOMAIN} ${DOMAIN}:mail:/etc/opendkim/keys/${DOMAIN}/mail.private" > /etc/opendkim/KeyTable
echo "*@${DOMAIN} mail._domainkey.${DOMAIN}" > /etc/opendkim/SigningTable
install -d -o opendkim  -g postfix /var/spool/postfix/opendkim
install -d -o opendmarc -g postfix /var/spool/postfix/opendmarc

print_header "Creating a test mailbox"
id labuser >/dev/null 2>&1 || useradd -m -s /usr/sbin/nologin labuser
echo "labuser:labpass123" | chpasswd

print_header "Starting services"
systemctl restart opendkim opendmarc dovecot postfix
postfix check && echo -e "${GREEN}postfix config OK${NC}"

print_header "Done"
echo -e "${GREEN}Mail stack up on ${FQDN} (lab-local).${NC}"
echo "Send a test:   echo 'hi' | mail -s 'lab test' labuser@${DOMAIN}"
echo "Read it:       ls -l /home/labuser/Maildir/new/  (or IMAP on 127.0.0.1:143 as labuser/labpass123)"
echo
echo -e "${YELLOW}For real use (NOT the lab) publish these, then unblock :25 and bind to the wire:${NC}"
echo "  DKIM : mail._domainkey.${DOMAIN}  TXT  -> /etc/opendkim/keys/${DOMAIN}/mail.txt"
echo "  SPF  : ${DOMAIN}.        TXT  \"v=spf1 mx -all\""
echo "  DMARC: _dmarc.${DOMAIN}. TXT  \"v=DMARC1; p=quarantine; rua=mailto:dmarc@${DOMAIN}\""
