# Copyright (C) 2019 Ian Kelling
# SPDX-License-Identifier: AGPL-3.0-or-later
+# todo: sandbox / harden exim:
+# 1. stop it from running as root. how?
+# https://www.exim.org/exim-html-current/doc/html/spec_html/ch-security_considerations.html
+# * avoid using .forward files, remove that router
+# * set deliver_drop_privilege
+# * set user to run as Debian-exim in systemd
+# * set port to something like 2500, and forward 25 to 2500 with iptables. same for 587.
+# https://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-443/1334552#1334552
+# * consider whether other routers like postmaster need modification / removal.
+# 2. restrict its filesystem access from within systemd
+
+# todo: harden dovecot. need to do some research. one way is for it to only listen on a wireguard vpn interface, so only clients that are on the vpn can access it.
+# todo: consider hardening cups listening on 0.0.0.0
+# todo: stop/disable local apache, and rpc.mountd, and kdeconnect when not in use.
+# todo: check that spamd and unbound only listen locally.
+
# todo: hosts should only allow external mail that is authed and
# destined for backup route. it is a minor issue since traffic is
# limited to the wghole network.
for service; do
# ignore services that dont exist
if systemctl cat $service &>/dev/null; then
- m systemctl stop $service;
- m systemctl disable $service
+ m systemctl disable --now $service
fi
done
}
m systemctl enable $service;
done
}
-sstart() {
- for service; do
- m systemctl enable --now $service;
- done
-}
mailhost() {
[[ $HOSTNAME == "$MAIL_HOST" ]]
}
bhost_t=false
case $HOSTNAME in
$MAIL_HOST) : ;;
- kd|frodo|x2|x3|kw|sy)
+ kd|frodo|x2|x3|kw|sy|bo)
bhost_t=true
;;
esac
# * Install universal packages
+
+# installs epanicclean
+/a/bin/ds/install-my-scripts
+
if [[ $(debian-codename-compat) == bionic ]]; then
cat >/etc/apt/preferences.d/spamassassin <<'EOF'
Package: spamassassin sa-compile spamc
# our nostart pi fails to avoid enabling
-# * user forward file
-case $HOSTNAME in
- $MAIL_HOST)
- # afaik, these will get ignored on MAIL_HOST because they are routing to my own
- # machine, but rm them is safer
- rm -fv $uhome/.forward /root/.forward
- ;;
- *)
- # this can\'t be a symlink and has permission restrictions
- # it might work in /etc/aliases, but this seems more proper.
- e setting $uhome/.forward to $forward
- install -m 644 {-o,-g}$u <(e $forward) $uhome/.forward
- ;;
-esac
-
# * Mail clean cronjob
i /etc/systemd/system/mailclean.timer <<'EOF'
# old.
#vpnser=mailvpn.service
+# todo: this hangs if it cant resolv the endpoint. we
+# want it to just retry in the background.
vpnser=wg-quick@wgmail.service
case $HOSTNAME in
bk)
bindpaths="/etc/10.173.8.1-resolv:/etc/127.0.0.1-resolv"
;;&
+ *)
+ d=/p/c/machine_specific/$HOSTNAME/filesystem/etc/wireguard/
+ if [[ -d $d ]]; then
+ rsync -aiSAX --chown=root:root --chmod=g-s $d /etc/wireguard
+ fi
+ ;;
esac
-i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
+case $HOSTNAME in
+ li) : ;;
+ *)
+ i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
[Unit]
Requires=mailnn.service
After=network.target mailnn.service
JoinsNamespaceOf=mailnn.service
BindsTo=mailnn.service
+StartLimitIntervalSec=0
[Service]
PrivateNetwork=true
# i dont think we need any of these, but it doesnt hurt to stay consistent
BindPaths=$bindpaths
+
+Restart=on-failure
+RestartSec=20
EOF
+ ;;
+esac
+
# https://selivan.github.io/2017/12/30/systemd-serice-always-restart.html
i /etc/systemd/system/mailvpn.service <<EOF
BindPaths=$bindpaths
Restart=always
# time to sleep before restarting a service
-RestartSec=1
+RestartSec=20
[Install]
WantedBy=multi-user.target
ExecStart=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns -n 10.173.8 start mail
ExecStop=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns stop mail
Restart=always
-RestartSec=10
+RestartSec=20
[Install]
WantedBy=multi-user.target
EOF
+i /etc/systemd/system/mailbindwatchdog.service <<EOF
+[Unit]
+Description=Watchdog to restart services relying on systemd-resolved dir
+After=syslog.target network-online.target
+Wants=network-online.target
+BindsTo=mailnn.service
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/mailbindwatchdog $vpnser ${nn_progs[@]} unbound.service radicale.service
+Restart=always
+# time to sleep before restarting a service
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
# old service name
BindPaths=$bindpaths
Restart=always
-RestartSec=1
+RestartSec=20
EOF
# sooo, there are a few ways to get traffic from the mail network
BindPaths=$bindpaths
Restart=always
-RestartSec=1
+RestartSec=20
EOF
done
;;
# * common exim4 config
+## old, not using forward files anymore
+rm -fv $uhome/.forward /root/.forward
+
+
# Make all system users be aliases. preventative
-# measure for things like cron mail for user without alias
-awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ { print $1 }' /etc/passwd| while read -r user; do
+# prevents things like cron mail for user without alias
+awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ || $7 ~ /\/nologin$/ { print $1 }' /etc/passwd| while read -r user; do
if [[ ! $user ]]; then
continue
fi
fi
done
+
+awk 'BEGIN { FS = ":" } ; $6 ~ /^\/home/ && $7 !~ /\/nologin$/ { print $1 }' /etc/passwd| while read -r user; do
+ case $HOSTNAME in
+ $MAIL_HOST)
+ sed -i "/^user:/d" /etc/aliases
+ ;;
+ *)
+ if ! grep -q "^$user:" /etc/aliases; then
+ echo "$user: root" |m tee -a /etc/aliases
+ fi
+ ;;
+ esac
+done
+
if ! grep -q "^ncsoft:" /etc/aliases; then
echo "ncsoft: graceq2323@gmail.com" |m tee -a /etc/aliases
fi
BindPaths=$bindpaths
Restart=always
# time to sleep before restarting a service
-RestartSec=1000
+RestartSec=20
[Install]
# for openvpn
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl_protocols = TLSv1.2
ssl_prefer_server_ciphers = no
-ssl_dh_parameters_length = 2048
protocol lmtp {
#per https://wiki2.dovecot.org/Pigeonhole/Sieve/Configuration
#### begin dl roundcube
# note, im r2e subbed to https://github.com/roundcube/roundcubemail/releases.atom
- v=1.4.11; f=roundcubemail-$v-complete.tar.gz
+ v=1.4.13; f=roundcubemail-$v-complete.tar.gz
cd /a/opt
if [[ -e $f ]]; then
timestamp=$(stat -c %Y $f)
m phpenmod -v php mcrypt imap
# dpkg says this is required
m a2enmod proxy_fcgi setenvif
- fpm=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* (php[^ ]*-fpm)( .*|$)/\1/p') # eg: php7.3-fpm
+ fpm=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* (php[^ ]*-fpm)( .*|$)/\1/p') # eg: php7.4-fpm
phpver=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* php([^ ]*)-fpm( .*|$)/\1/p')
m a2enconf $fpm
# 3 useless guides on php fpm fcgi debian 10 later, i figure out from reading
# https://github.com/nextcloud/user_external#readme
# plus mailinabox example
-\$CONFIG['user_backends'] = array(array('class' => 'OC_User_IMAP','arguments' => array('127.0.0.1', 143, null),),);
+#\$CONFIG['user_backends'] = array(array('class' => 'OC_User_IMAP','arguments' => array('127.0.0.1', 143, null),),);
# based on installer check
CHECK_RCPT_VERIFY_SENDER = true
# default config comment says: If you enable this, you might reject legitimate mail,
# but eggs has had this a long time, so that seems unlikely.
-CHECK_DATA_VERIFY_HEADER_SYNTAX = true
CHECK_RCPT_SPF = true
CHECK_RCPT_REVERSE_DNS = true
CHECK_MAIL_HELO_ISSUED = true
# note changes here also require change in passwd.client
route_list = * eximbackup.b8.nz
same_domain_copy_routing = yes
+errors_to = alerts@iankelling.org
no_more
EOF
.endif
hosts_require_auth = *
hosts_try_auth = *
- return_path = alerts@iankelling.org
envelope_to_add
- # manual return path because we dont want it to be the envelope sender
+ # manual return path because we want it to be the envelope sender
# we got not the one we are using in this smtp transport
headers_add = "Return-path: $sender_address"
.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
# this avoids some error. i cant remember what. todo:
# test it out and document why/if its needed.
- i /etc/exim4/host_local_deny_exceptions <<'EOF'
-mail.fsf.org
-*.posteo.de
-EOF
+ # i /etc/exim4/host_local_deny_exceptions <<'EOF'
+ # mail.fsf.org
+ # *.posteo.de
+ # EOF
# cron email from smarthost hosts will automatically be to
# USER@FQDN. I redirect that to alerts@, on the smarthosts, but in
/a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]]
# note: i put nn.b8.nz into bind for good measure
-10.173.8.2 nn.b8.nz mail.iankelling.org
+10.173.8.2 nn.b8.nz mx.iankelling.org
EOF
# note: systemd-resolved will consult /etc/hosts, dnsmasq wont. this assumes
# weve configured this file in dnsmasq if we are using it.
/a/exe/cedit mail /etc/dnsmasq-servers.conf <<'EOF' || [[ $? == 1 ]]
-server=/mail.iankelling.org/127.0.1.1
+server=/mx.iankelling.org/127.0.1.1
EOF
# I used to use debconf-set-selections + dpkg-reconfigure,
# which then updates this file
# The debconf questions output is additional documentation that is not
# easily accessible, but super long, along with the initial default comment in this
# file, so I've saved that into ./mail-notes.conf.
+ #
+ # # TODO: remove mx.iankelling.org once systems get updated mail-setup from jan 2022
cat >>/etc/exim4/update-exim4.conf.conf <<EOF
# man page: is used to build the local_domains list, together with "localhost"
# this is duplicated in a later router.
-dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
+dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;mx.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
EOF
[Service]
Restart=always
# time to sleep before restarting a service
-RestartSec=1
+RestartSec=20
EOF
i /etc/default/exim4in <<'EOF'
echo | /a/exe/cedit nn /etc/hosts || [[ $? == 1 ]]
echo | /a/exe/cedit mail /etc/dnsmasq-servers.conf || [[ $? == 1 ]]
+
if $bhost_t; then
+ install -d /bu
+ install -d -g $u -o $u -m 771 /bu/md
i /etc/exim4/conf.d/transport/30_backup_maildir <<EOF
# modified debian maildir transport
backup_maildir:
transport = backup_maildir
EOF
-
+ # Bind to wghole to receive mailbackup.
wgholeip=$(sed -rn 's/^ *Address *= *([^/]+).*/\1/p' /etc/wireguard/wghole.conf)
cat >>/etc/exim4/update-exim4.conf.conf <<EOF
dc_other_hostnames='eximbackup.b8.nz'
dc_local_interfaces='127.0.0.1;::1;$wgholeip'
EOF
+
+ # wghole & thus exim will fail to start without internet connectivity.
+ i /etc/systemd/system/exim4.service.d/backup.conf <<'EOF'
+[Unit]
+StartLimitIntervalSec=0
+
+[Service]
+Restart=always
+RestartSec=20
+EOF
+
else
cat >>/etc/exim4/update-exim4.conf.conf <<EOF
# Note: If theres like a temporary problem where mail gets sent to
# instead of a permanent 5xx.
dc_local_interfaces='127.0.0.1;::1'
EOF
+ rm -fv /etc/systemd/system/exim4.service.d/backup.conf
fi
cat >>/etc/exim4/update-exim4.conf.conf <<EOF
dc_eximconfig_configtype='smarthost'
$MAIL_HOST|bk)
# config for the non-nn exim
m rsync -ra --delete /etc/exim4/ /etc/myexim4
+ # If we ever wanted to have a separate spool,
+ # we could do it like this.
+ # cat >>/etc/exim4/conf.d/main/000_local-nn <<'EOF'
+ # spool_directory = /var/spool/myexim4
+ # EOF
cat >>/etc/myexim4/update-exim4.conf.conf <<'EOF'
dc_eximconfig_configtype='smarthost'
dc_smarthost='nn.b8.nz'
m systemctl daemon-reload
fi
+m systemctl --now enable epanicclean.timer
+
case $HOSTNAME in
je)
/a/exe/web-conf apache2 je.b8.nz
ln -sf 127.0.0.1-resolv/stub-resolv.conf /etc/resolv.conf
;;&
$MAIL_HOST|bk)
- sstart mailnn mailnnroute
+ m systemctl --now enable mailnn mailnnroute
;;&
$MAIL_HOST)
# we use dns to start wg
if $reload; then
sre unbound
else
- sstart unbound
+ m systemctl --now enable unbound
fi
;;&
$MAIL_HOST|bk)
if $reload; then
sre $vpnser
else
- sstart $vpnser
+ m systemctl --now enable $vpnser
fi
if ! systemctl is-active clamav-daemon >/dev/null; then
- sstart clamav-daemon
+ m systemctl --now enable clamav-daemon
+ out=$(rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/filesystem/etc/systemd/system/epanicclean.{timer,service} /etc/systemd/system)
+ if [[ $out ]]; then
+ reload=true
+ fi
+
# note, this will cause paniclog entries because it takes like 45
# seconds for clamav to start, i use ./epanic-clean to remove
# them.
# need to wait a bit before restarting exim, else I
# get a paniclog entry like: spam acl condition: all spamd servers failed
sleep 3
- sstart mailclean.timer
+ m systemctl --now enable mailclean.timer
;;&
$MAIL_HOST)
# < 2.1 (eg: in t9), uses a different data format which required manual
# migration. dont start if we are running an old version.
if dpkg --compare-versions $(dpkg -s radicale | awk '$1 == "Version:" { print $2 }') ge 2.1; then
- sstart radicale
+ m systemctl --now enable radicale
fi
;;&
esac
sre exim4
+case $HOSTNAME in
+ $MAIL_HOST)
+ m systemctl --now enable mailbindwatchdog
+ ;;
+ *)
+ soff mailbindwatchdog
+ ;;
+esac
+
+
case $HOSTNAME in
bk) sre exim4in ;;
esac
test_to="testignore@expertpathologyreview.com, testignore@je.b8.nz, testignore@amnimal.ninja, jtuttle@gnu.org"
cat >>/etc/cron.d/mailtest <<EOF
-2 * * * * $u check-remote-mailqs |& log-once check-remote-mailqs
+2 * * * * root check-remote-mailqs |& log-once check-remote-mailqs
EOF
;;&
bk)
$MAIL_HOST|bk|je)
cat >/usr/local/bin/send-test-forward <<'EOF'
#!/bin/bash
-exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$' | xargs /sbin/exim -Mrm >/dev/null
+olds=(
+$(/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$')
+)
+if (( ${#olds[@]} )); then
+ /sbin/exim -Mrm "${olds[@]}" >/dev/null
+fi
EOF
for test_from in ${test_froms[@]}; do
cat >>/usr/local/bin/send-test-forward <<EOFOUTER