From 7d9ec600a5ed9f88b85e02a27ee017b85721a6ac Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Thu, 13 Jan 2022 14:30:04 -0500 Subject: [PATCH] improvements --- brc | 21 +++++++++------ brc2 | 4 +++ distro-end | 6 ++++- install-my-scripts | 2 +- mail-setup | 66 +++++++++++++++++++++++++++++++++++++--------- mailbindwatchdog | 35 ++++++++++++++++++++++++ mailclean | 3 +++ rootsshsync | 2 +- switch-mail-host | 33 ++++++++++++++++++++--- system-status | 7 +++++ unsaved-buffers.el | 20 ++++++++++++++ 11 files changed, 171 insertions(+), 28 deletions(-) create mode 100755 mailbindwatchdog create mode 100644 unsaved-buffers.el diff --git a/brc b/brc index 7c89382..1f3aeea 100644 --- 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=$(s 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 9af6424..af437b3 100644 --- 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 diff --git a/distro-end b/distro-end index a36266f..51d0144 100755 --- a/distro-end +++ b/distro-end @@ -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 diff --git a/install-my-scripts b/install-my-scripts index 303bdbb..6274111 100755 --- a/install-my-scripts +++ b/install-my-scripts @@ -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 \ diff --git a/mail-setup b/mail-setup index 4ce604b..f8cb3ee 100755 --- a/mail-setup +++ b/mail-setup @@ -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 </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 index 0000000..380256c --- /dev/null +++ b/mailbindwatchdog @@ -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 diff --git a/mailclean b/mailclean index 072e404..4f0c55a 100755 --- 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 diff --git a/rootsshsync b/rootsshsync index dc87133..b4335db 100755 --- a/rootsshsync +++ b/rootsshsync @@ -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 diff --git a/switch-mail-host b/switch-mail-host index 0a80d2c..12bf126 100644 --- a/switch-mail-host +++ b/switch-mail-host @@ -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 diff --git a/system-status b/system-status index 477eade..2dd39ca 100644 --- a/system-status +++ b/system-status @@ -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 index 0000000..15f0f53 --- /dev/null +++ b/unsaved-buffers.el @@ -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)) + ) -- 2.30.2