mostly fixes
[distro-setup] / mail-setup
index f85bb8732bf57f383a1139f5d99213e5927e2429..c40c56c0b6eab97923f57686a5c617eaed7040ca 100755 (executable)
@@ -3,6 +3,8 @@
 # Copyright (C) 2019 Ian Kelling
 # SPDX-License-Identifier: AGPL-3.0-or-later
 
+# todo: max line length macro changed in t11. look into it
+# todo: check that all macros we use are still valid in t11
 
 # todo: setup an alert for bouncing test emails.
 
@@ -347,7 +349,6 @@ stopifactive() {
 
 mxhost=mx.iankelling.org
 mxport=587
-forward=$u@$mxhost
 
 # old setup. left as comment for example
 # mxhost=mail.messagingengine.com
@@ -461,7 +462,7 @@ m usermod -a -G Debian-exim clamav
 
 i /etc/systemd/system/clamav-daemon.service.d/fix.conf <<EOF
 [Service]
-ExecStartPre=-/bin/mkdir /var/run/clamav
+ExecStartPre=-/bin/mkdir -p /var/run/clamav
 ExecStartPre=/bin/chown clamav /var/run/clamav
 EOF
 
@@ -469,8 +470,48 @@ EOF
 
 # old.
 #vpnser=mailvpn.service
-# todo: this hangs if it cant resolv the endpoint. we
-# want it to just retry in the background.
+# note: this hangs if it cant resolv the endpoint. we
+# want it to just retry in the background. i just use a static ip instead.
+#
+# Note: at least on t10, on reboot, the service fails to come up according to systemd, but
+# in reality it is up and working, then it tries to restart infinitely, and fails
+# because it detects that the interface exists.
+#
+# failing output:
+#
+# Aug 02 21:59:27 sy wg-quick[2092]: [#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
+# Aug 02 21:59:27 sy wg-quick[2248]: [#] iptables-restore -n
+# Aug 02 21:59:27 sy wg-quick[2249]: Another app is currently holding the xtables lock. Perhaps you want to use the -w option?
+# Aug 02 21:59:27 sy wg-quick[2259]: [#] iptables-restore -n
+# Aug 02 21:59:27 sy wg-quick[2260]: Another app is currently holding the xtables lock. Perhaps you want to use the -w option?
+# Aug 02 21:59:27 sy systemd[1]: wg-quick@wgmail.service: Main process exited, code=exited, status=4/NOPERMISSION
+
+
+# successful output.
+# Aug 03 14:12:47 sy wg-quick[711336]: [#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
+# Aug 03 14:12:47 sy wg-quick[711384]: [#] iptables-restore -n
+# Aug 03 14:12:47 sy wg-quick[711336]: [#] ping -w10 -c1 10.8.0.1 ||:
+# Aug 03 14:12:47 sy wg-quick[711389]: PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
+# Aug 03 14:12:47 sy wg-quick[711389]: 64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=73.0 ms
+# Aug 03 14:12:47 sy wg-quick[711389]: --- 10.8.0.1 ping statistics ---
+# Aug 03 14:12:47 sy wg-quick[711389]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
+# Aug 03 14:12:47 sy wg-quick[711389]: rtt min/avg/max/mdev = 72.993/72.993/72.993/0.000 ms
+# Aug 03 14:12:47 sy systemd[1]: Finished WireGuard via wg-quick(8) for wgmail.
+# Aug 02 21:59:27 sy systemd[1]: wg-quick@wgmail.service: Failed with result 'exit-code'.
+# Aug 02 21:59:27 sy systemd[1]: Failed to start WireGuard via wg-quick(8) for wgmail.
+# Aug 02 21:59:47 sy systemd[1]: wg-quick@wgmail.service: Scheduled restart job, restart counter is at 1.
+# Aug 02 21:59:47 sy systemd[1]: Stopped WireGuard via wg-quick(8) for wgmail.
+# Aug 02 21:59:47 sy systemd[1]: Starting WireGuard via wg-quick(8) for wgmail...
+# Aug 02 21:59:47 sy wg-quick[3424]: wg-quick: `wgmail' already exists
+# Aug 02 21:59:47 sy systemd[1]: wg-quick@wgmail.service: Main process exited, code=exited, status=1/FAILURE
+# Aug 02 21:59:47 sy systemd[1]: wg-quick@wgmail.service: Failed with result 'exit-code'.
+# Aug 02 21:59:47 sy systemd[1]: Failed to start WireGuard via wg-quick(8) for wgmail.
+
+
+# According to iptables -S and iptables -t nat -S,
+# there are no modifications to iptables rules on a succsfull run,
+# and
+
 vpnser=wg-quick@wgmail.service
 
 case $HOSTNAME in
@@ -755,6 +796,19 @@ EOF
     ;;
 esac
 
+# * wghole (another mail vpn)
+
+if $bhost_t; then
+  i /etc/systemd/system/wg-quick@wghole.service.d/override.conf <<'EOF'
+[Unit]
+StartLimitIntervalSec=0
+
+[Service]
+Restart=on-failure
+RestartSec=20
+EOF
+fi
+
 # * spamassassin config
 i /etc/sysctl.d/80-iank-mail.conf <<'EOF'
 # see exim spec
@@ -795,13 +849,16 @@ EOF
 
 
 # * Update mail cert
-if [[ -e /p/c/filesystem ]]; then
-  # note, man openvpn implies we could just call mail-route on vpn startup/shutdown with
-  # systemd, buuut it can remake the tun device unexpectedly, i got this in the log
-  # after my internet was down for a bit:
-  # NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.
-  m /a/exe/vpn-mk-client-cert -b mailclient -n mail li.iankelling.org
-fi
+
+
+## needed only for openvpn mail vpn.
+# if [[ -e /p/c/filesystem ]]; then
+#   # note, man openvpn implies we could just call mail-route on vpn startup/shutdown with
+#   # systemd, buuut it can remake the tun device unexpectedly, i got this in the log
+#   # after my internet was down for a bit:
+#   # NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.
+#   m /a/exe/vpn-mk-client-cert -b mailclient -n mail li.iankelling.org
+# fi
 
 # With openvpn, I didn't get around to persisting the openvpn
 # cert/configs into /p/c/machine_specific/bk, so I had this case to
@@ -1110,6 +1167,27 @@ cat >/etc/exim4/conf.d/main/000_local2 <<EOF
 MAIN_TRUSTED_GROUPS = $u
 EOF
 
+cd /etc/exim4
+{
+  for f in *-private.pem; do
+    echo ${f%-private.pem}
+  done
+} | i /etc/exim4/conf.d/my-dkim-domains
+
+if grep -Fq REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS \
+        /etc/exim4/conf.d/transport/10_exim4-config_transport-macros; then
+  cat >/etc/exim4/conf.d/transport/11_iank <<'EOF'
+# This unsets the default macro defined in on t11 in
+# /etc/exim4/conf.d/transport/10_exim4-config_transport-macros
+# It seems like a very odd choice that this has become
+# the default in t11. Normal smarthost clients use username/password
+# auth. Oh well.
+REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS ==
+EOF
+else
+  rm -f /etc/exim4/conf.d/transport/11_iank
+fi
+
 cat >/etc/exim4/conf.d/main/000_local <<'EOF'
 MAIN_TLS_ENABLE = true
 
@@ -1144,13 +1222,7 @@ smtp_accept_queue_per_connection = 500
 DKIM_CANON = relaxed
 DKIM_SELECTOR = li
 
-# from comments in
-# https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4
-# and its best for this to align https://tools.ietf.org/html/rfc7489#page-8
-# There could be some circumstance when the
-# from: isnt our domain, but the envelope sender is
-# and so still want to sign, but I cant think of any case.
-DKIM_DOMAIN = ${lc:${domain:$rh_from:}}
+
 # The file is based on the outgoing domain-name in the from-header.
 # sign if key exists
 DKIM_PRIVATE_KEY = ${if exists{/etc/exim4/${dkim_domain}-private.pem} {/etc/exim4/${dkim_domain}-private.pem}}
@@ -1188,7 +1260,38 @@ delay_warning_condition = ${if or {\
   { match{$h_auto-submitted:}{(?i)auto-generated|auto-replied} }\
   { match_domain{$domain}{+local_domains} }\
   } {no}{yes}}
+
+
+# enable 587 in addition to the default 25, so that
+# i can send mail where port 25 is firewalled by isp
+daemon_smtp_ports = 25 : 587
+# default of 25, can get stuck when catching up on mail
+smtp_accept_max = 400
+smtp_accept_reserve = 100
+smtp_reserve_hosts = +iank_trusted
+
+# Rules that make receiving more liberal should be on backup hosts
+# so that we dont reject mail accepted by MAIL_HOST
+LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE = /etc/exim4/conf.d/local_deny_exceptions_acl
+EOF
+
+if dpkg --compare-versions "$(dpkg-query -f='${Version}\n' --show exim4)" ge 4.94; then
+  cat >>/etc/exim4/conf.d/main/000_local <<'EOF'
+# In t11, we cant do the old anymore because this is tainted data used in a file lookup.
+# /usr/share/doc/exim4/NEWS.Debian.gz suggests to use lookups to untaint data.
+DKIM_DOMAIN = ${lookup {${domain:$rh_from:}}lsearch,ret=key{/etc/exim4/conf.d/my-dkim-domains}}
+EOF
+else
+  cat >>/etc/exim4/conf.d/main/000_local <<'EOF'
+# From comments in
+# https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4
+# and its best for this to align https://tools.ietf.org/html/rfc7489#page-8
+# There could be some circumstance when the
+# from: isnt our domain, but the envelope sender is
+# and so still want to sign, but I cant think of any case.
+DKIM_DOMAIN = ${lc:${domain:$rh_from:}}
 EOF
+fi
 
 rm -fv /etc/exim4/rcpt_local_acl # old path
 
@@ -1237,13 +1340,6 @@ warn
   add_header = X-Spam_report: $spam_report
   add_header = X-Spam_action: $spam_action
 
-warn
-  !hosts = +iank_trusted
-  !authenticated = plain_server:login_server
-  condition = ${if def:malware_name}
-  remove_header = Subject:
-  add_header = Subject: [Clamav warning: $malware_name] $h_subject
-  log_message = heuristic malware warning: $malware_name
 
 #accept
 #  spf = pass:fail:softfail:none:neutral:permerror:temperror
@@ -1252,6 +1348,202 @@ warn
 
 EOF
 
+# It is important for this to exist universally, instead of
+# just on the mail host because if we change mail host and
+# still have something in the queue which was destined for
+# this router, but hosts were unreachable, the routers will
+# be reevaluated on the next retry.
+i /etc/exim4/conf.d/router/890_backup_copy <<EOF
+### router/900_exim4-config_local_user
+#################################
+
+# todo, it would be nice backup sent email too,
+# but its not so important, they still exist in my head
+
+backup_copy:
+driver = manualroute
+domains = eximbackup.b8.nz
+transport = backup_remote
+ignore_target_hosts = ${HOSTNAME}wg.b8.nz
+# 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
+
+# exim4-config transports are the same as default except for
+# message_linelength_limit = 2097152
+#
+# TODO: copy the defaults into their own file, and setup a cronjob so
+# that if file.dpkg-dist shows up, and it is different, we get an alert.
+
+i /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost <<'EOF'
+### transport/30_exim4-config_remote_smtp_smarthost
+#################################
+
+# This transport is used for delivering messages over SMTP connections
+# to a smarthost. The local host tries to authenticate.
+# This transport is used for smarthost and satellite configurations.
+
+remote_smtp_smarthost:
+  debug_print = "T: remote_smtp_smarthost for $local_part@$domain"
+  driver = smtp
+  message_linelength_limit = 2097152
+  multi_domain
+  hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \
+        {\
+        ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\
+        }\
+        {} \
+      }
+.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
+  hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
+  hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
+  tls_verify_certificates = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
+  tls_verify_hosts = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
+.endif
+.ifdef REMOTE_SMTP_HEADERS_REWRITE
+  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
+.endif
+.ifdef REMOTE_SMTP_RETURN_PATH
+  return_path = REMOTE_SMTP_RETURN_PATH
+.endif
+.ifdef REMOTE_SMTP_HELO_DATA
+  helo_data=REMOTE_SMTP_HELO_DATA
+.endif
+.ifdef TLS_DH_MIN_BITS
+tls_dh_min_bits = TLS_DH_MIN_BITS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
+tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY
+tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
+.endif
+.ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+  headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_PROTOCOL
+  protocol = REMOTE_SMTP_SMARTHOST_PROTOCOL
+.endif
+EOF
+
+i /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp <<'EOF'
+### transport/30_exim4-config_remote_smtp
+#################################
+# This transport is used for delivering messages over SMTP connections.
+
+remote_smtp:
+  debug_print = "T: remote_smtp for $local_part@$domain"
+  driver = smtp
+  message_linelength_limit = 2097152
+.ifdef REMOTE_SMTP_HOSTS_AVOID_TLS
+  hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS
+.endif
+.ifdef REMOTE_SMTP_HEADERS_REWRITE
+  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
+.endif
+.ifdef REMOTE_SMTP_RETURN_PATH
+  return_path = REMOTE_SMTP_RETURN_PATH
+.endif
+.ifdef REMOTE_SMTP_HELO_DATA
+  helo_data=REMOTE_SMTP_HELO_DATA
+.endif
+.ifdef REMOTE_SMTP_INTERFACE
+  interface = REMOTE_SMTP_INTERFACE
+.endif
+.ifdef DKIM_DOMAIN
+dkim_domain = DKIM_DOMAIN
+.endif
+.ifdef DKIM_IDENTITY
+dkim_identity = DKIM_IDENTITY
+.endif
+.ifdef DKIM_SELECTOR
+dkim_selector = DKIM_SELECTOR
+.endif
+.ifdef DKIM_PRIVATE_KEY
+dkim_private_key = DKIM_PRIVATE_KEY
+.endif
+.ifdef DKIM_CANON
+dkim_canon = DKIM_CANON
+.endif
+.ifdef DKIM_STRICT
+dkim_strict = DKIM_STRICT
+.endif
+.ifdef DKIM_SIGN_HEADERS
+dkim_sign_headers = DKIM_SIGN_HEADERS
+.endif
+.ifdef DKIM_TIMESTAMPS
+dkim_timestamps = DKIM_TIMESTAMPS
+.endif
+.ifdef TLS_DH_MIN_BITS
+tls_dh_min_bits = TLS_DH_MIN_BITS
+.endif
+.ifdef REMOTE_SMTP_TLS_CERTIFICATE
+tls_certificate = REMOTE_SMTP_TLS_CERTIFICATE
+.endif
+.ifdef REMOTE_SMTP_PRIVATEKEY
+tls_privatekey = REMOTE_SMTP_PRIVATEKEY
+.endif
+.ifdef REMOTE_SMTP_HOSTS_REQUIRE_TLS
+  hosts_require_tls = REMOTE_SMTP_HOSTS_REQUIRE_TLS
+.endif
+.ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+  headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+.endif
+
+EOF
+
+i /etc/exim4/conf.d/transport/30_backup_remote <<'EOF'
+backup_remote:
+  driver = smtp
+  multi_domain
+  message_linelength_limit = 2097152
+  hosts_require_auth = *
+  hosts_try_auth = *
+  envelope_to_add
+  # 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
+  hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
+  hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
+  tls_verify_certificates = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
+  tls_verify_hosts = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOST
+.endif
+.ifdef REMOTE_SMTP_HEADERS_REWRITE
+  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
+.endif
+.ifdef REMOTE_SMTP_HELO_DATA
+  helo_data=REMOTE_SMTP_HELO_DATA
+.endif
+.ifdef TLS_DH_MIN_BITS
+tls_dh_min_bits = TLS_DH_MIN_BITS
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
+tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
+.endif
+.ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY
+tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
+.endif
+.ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+  headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
+.endif
+EOF
+
 i /etc/exim4/conf.d/router/900_exim4-config_local_user <<'EOF'
 ### router/900_exim4-config_local_user
 #################################
@@ -1289,9 +1581,7 @@ i /etc/exim4/conf.d/transport/30_remote_smtp_vpn <<'EOF'
 remote_smtp_vpn:
   debug_print = "T: remote_smtp_vpn for $local_part@$domain"
   driver = smtp
-.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
-  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
-.endif
+  message_linelength_limit = 2097152
 .ifdef REMOTE_SMTP_HOSTS_AVOID_TLS
   hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS
 .endif
@@ -1346,10 +1636,8 @@ i /etc/exim4/conf.d/transport/30_smarthost_dkim <<'EOF'
 smarthost_dkim:
   debug_print = "T: remote_smtp_smarthost for $local_part@$domain"
   driver = smtp
+  message_linelength_limit = 2097152
   multi_domain
-.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
-  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
-.endif
   hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \
         {\
         ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\
@@ -1502,7 +1790,7 @@ EOF
   # disable power management feature, set to 240 min sync interval,
   # so it shouldn't be bad.
 
-  # davdroid from f-druid.
+  # davx^5 from f-droid
   # login with url and user name
   # url https://cal.iankelling.org/ian
   # username ian
@@ -1609,7 +1897,7 @@ EOF
       cat <<'EOF'
 # https://ssl-config.mozilla.org
 ssl = required
-# this is the same as the certbot list, in my cert cronjob, I check if that has changed upstream.
+# this is the same as the certbot list, i check changes in /a/bin/ds/filesystem/usr/local/bin/check-lets-encrypt-ssl-settings
 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
@@ -1620,7 +1908,7 @@ protocol lmtp {
   mail_plugins = $mail_plugins sieve
 }
 EOF
-      if dpkg --compare-versions $(dpkg-query -f='${Version}\n' --show dovecot-core) ge 1:2.3; then
+      if dpkg --compare-versions "$(dpkg-query -f='${Version}\n' --show dovecot-core)" ge 1:2.3; then
         cat <<EOF
 ssl_dh = </etc/dovecot/dhparam
 EOF
@@ -1951,6 +2239,8 @@ if [[ $HOSTNAME == bk ]]; then
     rcdir=${rcdirs[i]}
     rcbase=${rcdir##*/}
     ncdir=${ncdirs[i]}
+    myncdir=/root/${ncdir##*/}
+    mkdir -p $myncdir
 
     # copied from debians cronjob
     i /etc/cron.d/$rcbase <<EOF
@@ -2164,7 +2454,8 @@ EOF
   ### begin php setup for rc ###
   # Enable PHP modules.
   m phpenmod -v php mcrypt imap
-  # dpkg says this is required
+  # dpkg says this is required.
+  # nextcloud needs these too
   m a2enmod proxy_fcgi setenvif
   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')
@@ -2228,16 +2519,21 @@ EOF
       m rm -f $file
       m chown -R www-data.www-data nextcloud
       m mv nextcloud $ncdir
+    fi
+
+    if [[ ! -e $myncdir/done-install ]]; then
       m cd $ncdir
       m sudo -u www-data php occ  maintenance:install --database sqlite --admin-user iank --admin-pass $nextcloud_admin_pass
+      m touch $myncdir/done-install
     fi
+
     # note, strange this happend where updater did not increment the version var,
     # mine was stuck on 20. I manually updated it.
     m cd $ncdir/config
-    if [[ ! -e config.php-orig ]]; then
-      m cp -a config.php config.php-orig
+    if [[ ! -e $myncdir/config.php-orig ]]; then
+      m cp -a config.php $myncdir/config.php-orig
     fi
-    cat config.php-orig - >tmp.php <<EOF
+    cat $myncdir/config.php-orig - >$myncdir/tmp.php <<EOF
 # https://docs.nextcloud.com/server/19/admin_manual/configuration_server/email_configuration.html
 \$CONFIG["mail_smtpmode"] = "sendmail";
 \$CONFIG["mail_smtphost"] = "127.0.0.1";
@@ -2269,14 +2565,17 @@ fwrite(STDOUT, "<?php\n\\\$CONFIG = ");
 var_export(\$CONFIG);
 fwrite(STDOUT, ";\n");
 EOF
-    m php tmp.php >config.php
-    m rm -f tmp.php
-    m sudo -u www-data php $ncdir/occ maintenance:update:htaccess
+    e running php $myncdir/tmp.php
+    # note: we leave it around place for debugging
+    php $myncdir/tmp.php >config.php
+    cd $ncdir
+    m sudo -u www-data php occ maintenance:update:htaccess
     list=$(sudo -u www-data php $ncdir/occ --output=json_pretty app:list)
     # user_external not compaible with nc 23
     for app in contacts calendar; do
       if [[ $(printf "%s\n" "$list"| jq ".enabled.$app") == null ]]; then
-        m sudo -u www-data php $ncdir/occ app:install $app
+        cd $ncdir
+        m sudo -u www-data php occ app:install $app
       fi
     done
     i /etc/systemd/system/$ncbase.service <<EOF
@@ -2304,22 +2603,37 @@ EOF
     systemctl enable --now $ncbase.timer
     i /usr/local/bin/ncup <<'EOFOUTER'
 #!/bin/bash
-if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
-shopt -s inherit_errexit 2>/dev/null ||: # ignore fail in bash < 4.4
-set -eE -o pipefail
-trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" exit status: $?, PIPESTATUS: ${PIPESTATUS[*]}" >&2' ERR
 
-ncbase=$1
-if ! php /var/www/$ncbase/updater/updater.phar -n; then
+source /usr/local/lib/err
+
+m() { printf "%s\n" "$*";  "$@"; }
+err-cleanup() {
   echo failed nextcloud update for $ncbase >&2
-  /sbin/exim -t <<EOF
+  # -odf or else systemd will kill the background delivery process
+  # and the message will sit in the queue until the next queue run.
+  exim -odf -t <<EOF
 To: alerts@iankelling.org
-From: root@$(hostname -f)
+From: www-data@$(hostname -f)
 Subject: failed nextcloud update for $ncbase
 
 For logs, run: jr -u $ncbase
 EOF
+}
+
+if [[ $(id -u -n) != www-data ]]; then
+  echo error: running as wrong user: $(id -u -n), expected www-data
+  exit 1
+fi
+
+if [[ ! $1 ]]; then
+  echo error: expected an arg, nextcloud relative base dir
+  exit 1
 fi
+
+ncbase=$1
+cd /var/www/$ncbase
+# https://docs.nextcloud.com/server/22/admin_manual/maintenance/update.html?highlight=updater+phar
+m php /var/www/$ncbase/updater/updater.phar -n
 EOFOUTER
     chmod +x /usr/local/bin/ncup
 
@@ -2411,9 +2725,17 @@ UPEX4OPTS='-o /etc/exim4/my.conf'
 # i use epanic-clean for alerting if there are bad paniclog entries
 E4BCD_WATCH_PANICLOG='no'
 EOF
+    # make exim be a nonroot setuid program.
     chown Debian-exim:Debian-exim /usr/sbin/exim4
     # needs guid set in order to become Debian-exim
     chmod g+s,u+s /usr/sbin/exim4
+    # need this to avoid error on service reload:
+    # 2022-08-07 18:44:34.005 [892491] pid 892491: SIGHUP received: re-exec daemon
+    # 2022-08-07 18:44:34.036 [892491] cwd=/var/spool/exim4 5 args: /usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf
+    # 2022-08-07 18:44:34.043 [892491] socket bind() to port 25 for address (any IPv6) failed: Permission denied: waiting 30s before trying again (9 more tries)
+    # note: the daemon gives up and dies after retrying those 9 times.
+    # I came upon this by guessing and trial and error.
+    setcap CAP_NET_BIND_SERVICE+ei /usr/sbin/exim4
     i /etc/exim4/trusted_configs <<'EOF'
 /etc/exim4/my.conf
 EOF
@@ -2453,7 +2775,10 @@ ProtectHome=yes
 # this whole setting doesnt work. tried it with a newer systemd 250 though
 # an nspawn, and it worked there.
 InaccessiblePaths=${dirs[@]}
-NoNewPrivileges=yes
+# this gives us the permission denied error:
+# socket bind() to port 25 for address (any IPv6) failed: Permission denied
+# but we also have to set the file capabilities to avoid the error.
+#NoNewPrivileges=yes
 ProtectSystem=yes
 
 # when we get newer systemd
@@ -2498,26 +2823,31 @@ CHECK_RCPT_SPF = true
 CHECK_RCPT_REVERSE_DNS = true
 CHECK_MAIL_HELO_ISSUED = true
 
-# enable 587 in addition to the default 25, so that
-# i can send mail where port 25 is firewalled by isp
-daemon_smtp_ports = 25 : 587
-# default of 25, can get stuck when catching up on mail
-smtp_accept_max = 400
-smtp_accept_reserve = 100
-smtp_reserve_hosts = +iank_trusted
 
-# options exim has to avoid having to alter the default config files
-CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/conf.d/rcpt_local_acl
 CHECK_DATA_LOCAL_ACL_FILE = /etc/exim4/conf.d/data_local_acl
-LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE = /etc/exim4/conf.d/local_deny_exceptions_acl
+CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/conf.d/rcpt_local_acl
+
 # testing dmarc
 #dmarc_tld_file = /etc/public_suffix_list.dat
+
 EOF
     ;;&
 
   # ** $MAIL_HOST|bk)
   $MAIL_HOST|bk)
 
+
+    # no clamav on je, it has 1.5g memory and clamav uses most of it
+    i /etc/exim4/conf.d/clamav_data_acl <<'EOF'
+warn
+!hosts = +iank_trusted
+!authenticated = plain_server:login_server
+condition = ${if def:malware_name}
+remove_header = Subject:
+add_header = Subject: [Clamav warning: $malware_name] $h_subject
+log_message = heuristic malware warning: $malware_name
+EOF
+
     cat >>/etc/exim4/conf.d/main/000_local <<EOF
 # je.b8.nz will run out of memory with freshclam
 av_scanner = clamd:/var/run/clamav/clamd.ctl
@@ -2596,14 +2926,7 @@ EOF
     # which required using a dedicated user, but realized smtp will be
     # more reliable and less fuss. If I ever need that again, see the
     # history of this file, and bum in brc2.
-
     i /etc/exim4/conf.d/router/890_backup_copy <<EOF
-### router/900_exim4-config_local_user
-#################################
-
-# todo, it would be nice to save sent email too,
-# but its not so important, they still exist in my head
-
 backup_redir:
 driver = redirect
 domains = +local_domains
@@ -2614,72 +2937,17 @@ data = b@eximbackup.b8.nz
 # redirected earlier, so that is just being overly cautious.
 local_parts = ! root : ! testignore : ! alerts
 unseen = true
-
-backup_copy:
-driver = manualroute
-domains = eximbackup.b8.nz
-transport = backup_remote
-ignore_target_hosts = ${HOSTNAME}wg.b8.nz
-# 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
 
 
-    i /etc/exim4/conf.d/transport/30_backup_remote <<'EOF'
-backup_remote:
-  driver = smtp
-  multi_domain
-.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
-  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
-.endif
-  hosts_require_auth = *
-  hosts_try_auth = *
-  envelope_to_add
-  # 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
-  hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
-.endif
-.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
-  hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS
-.endif
-.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
-  tls_verify_certificates = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_CERTIFICATES
-.endif
-.ifdef REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS
-  tls_verify_hosts = REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOST
-.endif
-.ifdef REMOTE_SMTP_HEADERS_REWRITE
-  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
-.endif
-.ifdef REMOTE_SMTP_HELO_DATA
-  helo_data=REMOTE_SMTP_HELO_DATA
-.endif
-.ifdef TLS_DH_MIN_BITS
-tls_dh_min_bits = TLS_DH_MIN_BITS
-.endif
-.ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
-tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE
-.endif
-.ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY
-tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
-.endif
-.ifdef REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
-  headers_remove = REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE
-.endif
-EOF
-
 
-    # 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
+    # This allows for forwarded mail to not get most rcpt checks, especially SPF,
+    # which would incorrectly get denied.
+    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
@@ -2862,6 +3130,7 @@ EOF
     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
+    echo|i /etc/exim4/conf.d/clamav_data_acl
 
 
     if $bhost_t; then
@@ -2896,7 +3165,7 @@ EOF
     echo | /a/exe/cedit nn /etc/hosts || [[ $? == 1 ]]
     echo | /a/exe/cedit mail /etc/dnsmasq-servers.conf || [[ $? == 1 ]]
 
-
+    # note: condition duplicated at else
     if $bhost_t; then
       install -d /bu
       install -d -g Debian-exim -o Debian-exim -m 771 /bu/md
@@ -2944,7 +3213,7 @@ Restart=always
 RestartSec=20
 EOF
 
-    else
+    else  # if $bhost_t; then
       cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # Note: If theres like a temporary problem where mail gets sent to
 # one of these hosts, if exim isnt listening, it will be a temporary error
@@ -2976,12 +3245,14 @@ esac
 case $HOSTNAME in
   $MAIL_HOST|bk)
     # config for the non-nn exim
-    m rsync -ra --delete /etc/exim4/ /etc/myexim4
-    cat >>/etc/myexim4/conf.d/main/000_local-nn <<'EOF'
+    m rsync -ra --delete --delete-excluded --exclude=/conf.d/main/000_local-nn /etc/exim4/ /etc/myexim4
+    cat >>/etc/myexim4/conf.d/main/000_local <<'EOF'
 # this makes it easier to see which exim is doing what
 log_file_path = /var/log/exim4/my%s
 EOF
 
+
+
     cat >/etc/logrotate.d/myexim <<'EOF'
 /var/log/exim4/mymain /var/log/exim4/myreject {
        daily
@@ -3097,6 +3368,12 @@ if $reload; then
   m systemctl daemon-reload
 fi
 
+# checking bhost_t is redundant, but could help us catch errors.
+if $bhost_t || [[ -e /etc/wireguard/wghole.conf ]]; then
+  # todo: in mail-setup, we have a static list of backup hosts, not *y
+  m systemctl --now enable wg-quick@wghole
+fi
+
 sysd-prom-fail-install epanicclean
 m systemctl --now enable epanicclean
 
@@ -3155,12 +3432,19 @@ case $HOSTNAME in
   $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
+    if dpkg --compare-versions "$(dpkg -s radicale | awk '$1 == "Version:" { print $2 }')" ge 2.1; then
       m systemctl --now enable radicale
     fi
     ;;&
 esac
 
+# for debugging dns issues
+case $HOSTNAME in
+  je|bk)
+    systemctl enable --now logrotate-fast.timer
+    ;;
+esac
+
 # last use of $reload happens in previous block
 rm -f /var/local/mail-setup-reload
 
@@ -3237,7 +3521,8 @@ EOF
     test_tos=(testignore@expertpathologyreview.com testignore@je.b8.nz testignore@amnimal.ninja jtuttle@gnu.org)
 
     cat >>/etc/cron.d/mailtest <<EOF
-0   13 * * *  root echo "1pm alert. You are not in the matrix."
+# 10 am friday
+0   10 * * 5  root echo "weekly alert. You are not in the matrix."
 2   * * * *   root check-remote-mailqs |& log-once check-remote-mailqs
 EOF
     ;;&
@@ -3289,7 +3574,7 @@ EOF
       esac
 
       cat >>/usr/local/bin/send-test-forward <<EOFOUTER
-/usr/sbin/exim -f $test_from -t <<EOF
+/usr/sbin/exim -odf -f $test_from -t <<EOF
 From: $test_from
 To: $test_to
 Subject: test \$(date +%Y-%m-%dT%H:%M:%S%z) \$EPOCHSECONDS