improvements
authorIan Kelling <ian@iankelling.org>
Thu, 13 Jan 2022 19:30:04 +0000 (14:30 -0500)
committerIan Kelling <ian@iankelling.org>
Thu, 13 Jan 2022 19:30:04 +0000 (14:30 -0500)
brc
brc2
distro-end
install-my-scripts
mail-setup
mailbindwatchdog [new file with mode: 0755]
mailclean
rootsshsync
switch-mail-host
system-status
unsaved-buffers.el [new file with mode: 0644]

diff --git a/brc b/brc
index 7c89382ca6906cf5712fd360bd08b9511cd619c0..1f3aeeaab6660836781125fad776d9a74e947f9a 100644 (file)
--- a/brc
+++ b/brc
@@ -303,7 +303,7 @@ fpst() { # file paste
 
 _khfix_common() {
   local host ip port
-  read -r host ip port < <(timeout -s 9 2 ssh -oBatchMode=yes -oControlMaster=no -oControlPath=/ -v $1 |& sed -rn "s/debug1: Connecting to ([^ ]+) \[([^\]*)] port ([0-9]+).*/\1 \2 \3/p" || [[ $? == 124 ]])
+  read -r host ip port < <(timeout -s 9 2 ssh -oBatchMode=yes -oControlMaster=no -oControlPath=/ -v $1 |& sed -rn "s/debug1: Connecting to ([^ ]+) \[([^\]*)] port ([0-9]+).*/\1 \2 \3/p" ||)
   if [[ ! $ip ]]; then
     echo "khfix: ssh failed"
     return 1
@@ -316,10 +316,11 @@ _khfix_common() {
     host_entry=$host
   fi
   if [[ $host != $ip ]]; then
-    ssh-keygen -R "$host_entry" -f $(readlink -f ~/.ssh/known_hosts)
+    m ssh-keygen -R "$host_entry" -f $(readlink -f ~/.ssh/known_hosts)
+    ll ~/.ssh/known_hosts
   fi
-  echo "khfix: removing key for $ip_entry"
-  ssh-keygen -R "$ip_entry" -f $(readlink -f ~/.ssh/known_hosts)
+  m ssh-keygen -R "$ip_entry" -f $(readlink -f ~/.ssh/known_hosts)
+  ll ~/.ssh/known_hosts
   rootsshsync
 }
 khfix() { # known hosts fix
@@ -403,7 +404,7 @@ cam() {
 }
 
 ccat () { # config cat. see a config without extra lines.
-  grep '^\s*[^;[:space:]#]' "$@" || [[ $? == 1 ]]
+  sed -r '/^[[:space:]]*([;#]|--|\/\/|$)/d' "$@"
 }
 ccomp grep ccat
 
@@ -1133,7 +1134,7 @@ grep ps and output in a nice format"
     echo "$help"
     return
   fi
-  x=$(ps -eF)
+  x=$(ps -eF)
   # final grep is because some commands tend to have a lot of trailing spaces
   y=$(echo "$x" | grep -iP "$@" | grep -o '.*[^ ]') ||:
   if [[ $y ]]; then
@@ -1174,7 +1175,7 @@ randport() {
 import secrets
 print(secrets.SystemRandom().randrange(10002,65500))
 EOF
-  }
+}
 
 # reapply bashrc
 reb() {
@@ -1318,8 +1319,12 @@ sd() {
 
 ser() {
   if type -p systemctl &>/dev/null; then
-    s systemctl $1 $2
+    s systemctl "$@"
   else
+    if (( $# >= 3 )); then
+      echo iank: ser expected 2 or less arguments
+      return 1
+    fi
     s service $2 $1
   fi
 }
diff --git a/brc2 b/brc2
index 9af6424dd2256faecb4d5ce1911994c4e554d7be..af437b337aadb2cbbd1da504d237f4427fea8f87 100644 (file)
--- a/brc2
+++ b/brc2
@@ -1527,6 +1527,7 @@ sdnbash() { # systemd namespace bash
 mailnnbash() {
   m sudo nsenter -t $(systemctl status mailnn| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
 }
+
 mailvpnbash() {
   m sudo nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf") -n -m sudo -u $USER -i bash
 }
@@ -1538,6 +1539,9 @@ spamnn() {
   spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
   m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
 }
+unboundbash() {
+  m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
+  }
 
 mailnncheck() {
   local pid ns mailnn
index a36266f6365d2a43a0b97bd8c520d02ded65acde..51d01443d56475718bf508206e126657b78fac74 100755 (executable)
@@ -838,7 +838,11 @@ case $HOSTNAME in
 deb http://ppa.launchpad.net/system76-dev/stable/ubuntu $codename_compat main
 deb-src http://ppa.launchpad.net/system76-dev/stable/ubuntu $codename_compat main
 EOF
-      s apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5D1F3A80254F6AFBA254FED5ACD442D1C8B7748B
+      # ubuntu keyserver is prone to intermittent failures
+      for (( i=0; i <= 4 ; i++ )); do
+        s apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5D1F3A80254F6AFBA254FED5ACD442D1C8B7748B && break
+        sleep 10
+      done
       p update
       # https://support.system76.com/articles/install-ubuntu/
       # but i'm hoping this is not needed
index 303bdbbb3d5dfb610224d815ccd4c81ab2a4a923..6274111e0c830c2f4006939254b34ed396222c5a 100755 (executable)
@@ -37,7 +37,7 @@ x="$(readlink -f -- "${BASH_SOURCE[0]}")"; cd ${x%/*} # directory of this file
 /a/bin/log-quiet/setup
 rsync -t --chmod=755 --chown=root:root switch-mail-host btrbk-run mount-latest-subvol \
       check-subvol-stale system-status myi3status mailtest-check \
-      epanic-clean \
+      epanic-clean mailbindwatchdog \
       /a/bin/log-quiet/sysd-mail-once hssh \
       btrfsmaint \
       dynamic-ip-update \
index 4ce604b0eed1011908505728dcfd71f1911ce84a..f8cb3ee83e05dec206fb5d9c7fe0103e0b1b1392 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.
@@ -310,11 +326,6 @@ sre() {
     m systemctl enable $service;
   done
 }
-sstart() {
-  for service; do
-    m systemctl enable --now $service;
-  done
-}
 mailhost() {
   [[ $HOSTNAME == "$MAIL_HOST" ]]
 }
@@ -584,6 +595,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
@@ -2747,7 +2776,7 @@ if $reload; then
   m systemctl daemon-reload
 fi
 
-sstart epanicclean.timer
+m systemctl --now enable epanicclean.timer
 
 case $HOSTNAME in
   je)
@@ -2768,14 +2797,14 @@ case $HOSTNAME in
     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)
@@ -2784,10 +2813,10 @@ case $HOSTNAME in
     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
@@ -2804,13 +2833,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
@@ -2828,6 +2857,16 @@ esac
 
 sre exim4
 
+case $HOSTNAME in
+  $MAIL_HOST)
+    m systemctl --now enable mailbindwatchdog
+  ;;
+  *)
+    soff mailbindwatchdog
+    ;;
+esac
+
+
 case $HOSTNAME in
   bk) sre exim4in ;;
 esac
@@ -2877,7 +2916,8 @@ EOF
     cat >/usr/local/bin/send-test-forward <<'EOF'
 #!/bin/bash
 olds=(
-/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$')
+$(/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
diff --git a/mailbindwatchdog b/mailbindwatchdog
new file mode 100755 (executable)
index 0000000..380256c
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# When the system boots, systemd-resolved seems to recreate /run/systemd/resolve,
+# or something, because the bindmounts to that directory do not always exist
+# for units starting up at the same time. Anyways, removing and creating that
+# directory definitely has the effect of deleting the bindmount, so
+# here I solve for that ever happening.
+
+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
+
+if (( $# == 0 )); then
+  echo error: expected service argument >&2
+  exit 1
+fi
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+sleep 5
+while true; do
+  sleep 20
+  for unit; do
+    pid=$(systemctl show --property MainPID --value $unit 2>/dev/null ||:)
+    case $pid in
+      [1-9]*)
+        if ! nsenter -t $pid -m timeout 20 mountpoint /run/systemd/resolve &>/dev/null; then
+          echo mail bind restart of $unit
+          timeout 60 systemctl restart $unit ||:
+        fi
+        ;;
+    esac
+  done
+done
index 072e4046e4637279451b7ab4ffdb102c947dd3f8..4f0c55a028048e6fff195a4e52dc0cbcc5bcce5f 100755 (executable)
--- a/mailclean
+++ b/mailclean
@@ -38,6 +38,9 @@ myfind /m/md/log -type f -mtime +300 -execdir rm -- '{}' +
 myfind /m/md/dmarc -type f -mtime +60 -execdir rm -- '{}' +
 myfind /m/md/fsfalerts -type f -mtime +10 -execdir rm -- '{}' +
 
+# not strictly a mail directory, but it fits well in this script
+myfind /p/c/.editor-backups -type f -mtime +300 -execdir rm -- '{}' +
+
 
 
 shopt -s nullglob
index dc871336f9910d6b97b3116e022723f872680b8b..b4335dbcbbccfdb9164e44b4762dffcbba089268 100755 (executable)
@@ -52,7 +52,7 @@ if [[ -e $user_ssh_dir/config ]]; then
   # to root, and it allows us to have a working ssh when X isnt available,
   # eg, in an ssh shell. confirm for regular user provides some protection
   # that a rouge user program cant use my ssh key.
-  sed 's,^AddKeysToAgent confirm,AddKeysToAgent yes,' $user_ssh_dir/config >/root/.ssh/confighome
+  sed 's,^AddKeysToAgent confirm,AddKeysToAgent yes,;/^UserKnownHostsFile /d' $user_ssh_dir/config >/root/.ssh/confighome
   sed 's,^IdentityFile ~/\.ssh/home$,IdentityFile ~/\.ssh/h,' /root/.ssh/confighome >/root/.ssh/config
 fi
 chown -R root:root /root/.ssh
index 0a80d2c2c2eb048e082cf3b701bdd9352506bf0e..12bf126e1f2512179915933ebacf0ebeb6ec0513 100644 (file)
@@ -150,11 +150,32 @@ done
 
 # ensure these are unused before doing anything
 
-e "umounting /m and /o via $new_shell"
-$new_shell bash -xs <<'EOF'
+e "On $new_host: umounting /m and /o, checking emacs"
+$new_shell bash -s <<'EOF'
 set -eE
-if mountpoint -q /m; then umount /m; fi
-if mountpoint -q /o; then umount /o; fi
+if pgrep -f 'emacs --daemon' &>/dev/null; then
+  bufs="$(emacsclient --eval "$(cat /a/bin/ds/unsaved-buffers.el)"| sed '/^"nil"$/d;s/^"(/E: /;s/)"$//')"
+  if [[ $bufs ]]; then
+    echo "error: on $HOSTNAME, unsaved emacs files: $bufs" >&2
+    exit 1
+  fi
+fi
+for dir in m o; do
+  if mountpoint -q /$dir; then
+    echo On $new_host: umount /$dir
+    umount /$dir
+  fi
+done
+EOF
+
+$old_shell bash -s <<'EOF'
+if pgrep -f 'emacs --daemon' &>/dev/null; then
+  bufs="$(emacsclient --eval "$(cat /a/bin/ds/unsaved-buffers.el)"| sed '/^"nil"$/d;s/^"(/E: /;s/)"$//')"
+  if [[ $bufs ]]; then
+    echo "error: on $HOSTNAME, unsaved emacs files: $bufs" >&2
+    exit 1
+  fi
+fi
 EOF
 
 # previously, I was checking to see if the new mail host
@@ -185,6 +206,10 @@ if ! m $old_shell /a/exe/primary-setup $new_hostname; then
   exit $ret
 fi
 
+# Try to prevent emacs from saving stale data it has in memory to disk. eg: files, recentf list, etc.
+# But if emacs ignores the signal, let it live.
+m $new_shell killall -q emacs ||:
+
 e Running main btrbk
 m btrbk-run -v $bbk_args $incremental_arg -m /o || ret=$?
 if (( ret )); then
index 477eade3a72ebeca68bd77dbd367b565b6417de4..2dd39ca7d99a90c88ccc9bddf7e51a49f37535cf 100644 (file)
@@ -53,6 +53,13 @@ write-status() {
     fi
   fi
 
+  if pgrep -f 'emacs --daemon' &>/dev/null; then
+    emacsfiles="$(emacsclient --eval "$(cat /a/bin/ds/unsaved-buffers.el)"| sed '/^"nil"$/d;s/^"(/E: /;s/)"$//')"
+    if [[ $emacsfiles ]]; then
+      chars+=("$emacsfiles")
+    fi
+  fi
+
   glob=(/nocow/btrfs-stale/*)
   if [[ -e ${glob[0]} ]]; then
     chars+=("STALE")
diff --git a/unsaved-buffers.el b/unsaved-buffers.el
new file mode 100644 (file)
index 0000000..15f0f53
--- /dev/null
@@ -0,0 +1,20 @@
+;; print buffers unsaved, unless within "seconds" below
+
+;; run with
+;; emacsclient --eval "$(cat /a/bin/ds/unsaved-buffers.el)" | sed 's/^..//;s/..$//'
+
+
+(format "%s"
+        (-reduce-from
+         (lambda (acc buf)
+           (let ((seconds 60)
+                 (bpath (buffer-file-name buf)))
+             (if (and bpath
+                      (buffer-modified-p buf)
+                      (time-less-p
+                       (file-attribute-modification-time (file-attributes bpath))
+                       (time-add (current-time) (- seconds))))
+                 (cons bpath acc )
+               acc)))
+         nil (buffer-list))
+        )