fixes
[distro-setup] / mail-setup
index 47f5990258ca184d2c5388f6411ce25507f26701..f7f1fc56a853dc6c8ddc2a8b8e4e6e51f41cc859 100755 (executable)
@@ -3,6 +3,22 @@
 # 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.
@@ -300,22 +316,16 @@ soff () {
   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
 }
-sre () {
+sre() {
   for service; do
     m systemctl restart $service
     m systemctl enable $service;
   done
 }
-sstart() {
-  for service; do
-    m systemctl enable --now $service;
-  done
-}
 mailhost() {
   [[ $HOSTNAME == "$MAIL_HOST" ]]
 }
@@ -367,6 +377,10 @@ 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
@@ -404,21 +418,6 @@ fi
 # 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'
@@ -462,16 +461,26 @@ EOF
 
 # * mail vpn config
 
-vpnser=mailvpn.service
+# 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
   $MAIL_HOST)
+    rsync -aiSAX --chown=root:root --chmod=g-s /p/c/filesystem/etc/wireguard/ /etc/wireguard
     bindpaths="/etc/127.0.0.1-resolv:/run/systemd/resolve /etc/basic-nsswitch:/etc/resolved-nsswitch:norbind"
     ;;&
   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
@@ -571,6 +580,24 @@ ExecStart=/bin/sleep infinity
 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=1
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
 
 
 # old service name
@@ -799,9 +826,13 @@ fi
 # * 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
@@ -810,6 +841,20 @@ awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ { print $1 }' /etc/passwd| while read
   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
@@ -2010,7 +2055,7 @@ EOF
 
 # 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
@@ -2448,13 +2493,13 @@ EOF
 
     /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
@@ -2466,10 +2511,12 @@ EOF
     # 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
 
 
@@ -2548,6 +2595,7 @@ EOF
     echo|i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
     echo|i /etc/exim4/conf.d/rcpt_local_acl
     echo|i /etc/exim4/conf.d/router/890_backup_copy
+    echo|i /etc/exim4/conf.d/main/000_local-nn
 
 
     if $bhost_t; then
@@ -2608,11 +2656,11 @@ backup_local:
   transport = backup_maildir
 EOF
 
-
       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
     else
       cat >>/etc/exim4/update-exim4.conf.conf <<EOF
@@ -2733,6 +2781,8 @@ if $reload; then
   m systemctl daemon-reload
 fi
 
+m systemctl --now enable epanicclean.timer
+
 case $HOSTNAME in
   je)
     /a/exe/web-conf apache2 je.b8.nz
@@ -2752,25 +2802,31 @@ case $HOSTNAME in
     ln -sf 127.0.0.1-resolv/stub-resolv.conf /etc/resolv.conf
     ;;&
   $MAIL_HOST|bk)
-    sstart mailnn mailnnroute
-    # If these have changes, id rather manually restart it, id rather
-    # not restart and cause temporary errors
-    if $reload; then
-      sre $vpnser
-    else
-      sstart $vpnser
-    fi
+    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 these have changes, id rather manually restart it, id rather
+    # not restart and cause temporary errors
+    if $reload; then
+      sre $vpnser
+    else
+      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.
@@ -2782,13 +2838,13 @@ case $HOSTNAME in
     # 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
@@ -2806,6 +2862,16 @@ esac
 
 sre exim4
 
+case $HOSTNAME in
+  $MAIL_HOST)
+    m systemctl --now enable mailbindwatchdog
+  ;;
+  *)
+    soff mailbindwatchdog
+    ;;
+esac
+
+
 case $HOSTNAME in
   bk) sre exim4in ;;
 esac
@@ -2854,7 +2920,12 @@ EOF
   $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
@@ -2911,44 +2982,6 @@ done
 # Multiple user names need to be separated by spaces.
 # Root and postmaster mail recipient:
 
-# duplicated in brc2
-bum() {
-  local cur host
-  host=$1
-  (( $# == 1 )) || return 1
-  cur="$(awk '$2 == "/bu/mnt" {print $1}' /proc/mounts)"
-  if [[ $cur ]]; then
-    if [[ $cur == "$host:/bu/md" ]]; then
-      return 0
-    else
-      fusermount -u /bu/mnt
-    fi
-  fi
-  m sshfs bu@$host:/bu/home/md /bu/mnt -o reconnect,ServerAliveInterval=20,ServerAliveCountMax=30 -o allow_other
-}
-bu() {
-  if mountpoint -q /bu/mnt; then
-    if ! timeout -s 9 10 fusermount -u /bu/mnt; then
-      fusermount -zu /bu/mnt
-    fi
-  fi
-}
-
-case $HOSTNAME in
-  $MAIL_HOST)
-    case $HOSTNAME in
-      kw) bum x3 ;;
-      x3) bum kw ;;
-      kd|sy) bum x2 ;;
-      x2) bum kd ;;
-    esac
-    ;;
-  *)
-    bu
-    ;;
-esac
-
-
 m exit 0
 :