_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
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
}
ccat () { # config cat. see a config without extra lines.
- grep '^\s*[^;[:space:]#]' "$@" || [[ $? == 1 ]]
+ sed -r '/^[[:space:]]*([;#]|--|\/\/|$)/d' "$@"
}
ccomp grep ccat
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
import secrets
print(secrets.SystemRandom().randrange(10002,65500))
EOF
- }
+}
# reapply bashrc
reb() {
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
}
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
}
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
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
/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 \
# 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.
m systemctl enable $service;
done
}
-sstart() {
- for service; do
- m systemctl enable --now $service;
- done
-}
mailhost() {
[[ $HOSTNAME == "$MAIL_HOST" ]]
}
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
m systemctl daemon-reload
fi
-sstart epanicclean.timer
+m systemctl --now enable epanicclean.timer
case $HOSTNAME in
je)
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
# 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
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
--- /dev/null
+#!/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
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
# 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
# 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
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
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")
--- /dev/null
+;; 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))
+ )