#!/usr/bin/env bash # ===================================================================== # fail2ban-webui agent – uninstaller # # Removes the key entry, the sudo rule, f2b-webctl and its config. # The user and the manual jail are only removed on request, because # removing the jail also lifts all manual bans. # Every removed file is backed up to --backup-dir first. # ===================================================================== set -euo pipefail AGENT_BIN=/usr/local/sbin/f2b-webctl CONF_FILE=/etc/f2b-webctl.conf SUDOERS_FILE=/etc/sudoers.d/f2b-webctl USER_NAME=f2bweb AK_FILE="" MANUAL_JAIL="" REMOVE_USER=0 REMOVE_JAIL=0 BACKUP_DIR=/var/backups/fail2ban-webui-agent DRY_RUN=0 YES=0 usage() { cat <<'EOF' Usage: uninstall.sh [options] --user NAME SSH user of the agent (default: f2bweb) --authorized-keys-file PATH file with the key entry (default: ~USER/.ssh/authorized_keys) --remove-user also delete the user (not possible for root) --remove-jail also delete the manual jail – lifts all its bans! --manual-jail NAME name of the manual jail (default: from /etc/f2b-webctl.conf) --backup-dir DIR backups (default: /var/backups/fail2ban-webui-agent) --dry-run only show what would be done -y, --yes do not ask for confirmation EOF } die() { echo "ERROR: $*" >&2; exit 1; } info() { echo "==> $*"; } need() { [ $# -ge 2 ] && [ -n "$2" ] || die "option $1 needs a value"; } while [ $# -gt 0 ]; do case "$1" in --user) need "$@"; USER_NAME="$2"; shift 2 ;; --authorized-keys-file) need "$@"; AK_FILE="$2"; shift 2 ;; --remove-user) REMOVE_USER=1; shift ;; --remove-jail) REMOVE_JAIL=1; shift ;; --manual-jail) need "$@"; MANUAL_JAIL="$2"; shift 2 ;; --backup-dir) need "$@"; BACKUP_DIR="$2"; shift 2 ;; --dry-run) DRY_RUN=1; shift ;; -y|--yes) YES=1; shift ;; -h|--help) usage; exit 0 ;; *) usage >&2; die "unknown option: $1" ;; esac done [ "$(id -u)" -eq 0 ] || die "please run as root" [[ "$USER_NAME" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || die "invalid user name: $USER_NAME" [ "$USER_NAME" != root ] || [ $REMOVE_USER -eq 0 ] || die "root cannot be removed" if [ -z "$MANUAL_JAIL" ]; then MANUAL_JAIL=$(sed -n 's/^MANUAL_JAIL=//p' "$CONF_FILE" 2>/dev/null | tail -n1) MANUAL_JAIL=${MANUAL_JAIL:-manual-block} fi [[ "$MANUAL_JAIL" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,40}$ ]] || die "invalid jail name: $MANUAL_JAIL" HOME_DIR=$(getent passwd "$USER_NAME" | cut -d: -f6 || true) AK_FILE=${AK_FILE:-${HOME_DIR:-/nonexistent}/.ssh/authorized_keys} JAIL_FILES=("/etc/fail2ban/jail.d/$MANUAL_JAIL.local" "/etc/fail2ban/filter.d/$MANUAL_JAIL.conf") KEY_LINES=0 [ -f "$AK_FILE" ] && KEY_LINES=$(grep -c 'command="[^"]*f2b-webctl"' "$AK_FILE" || true) echo echo "fail2ban-webui agent – removing from $(hostname -f 2>/dev/null || hostname):" echo " key entries $KEY_LINES in $AK_FILE" for f in "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE"; do [ -e "$f" ] && echo " file $f" done [ $REMOVE_JAIL -eq 1 ] && for f in "${JAIL_FILES[@]}"; do [ -e "$f" ] && echo " jail file $f"; done [ $REMOVE_USER -eq 1 ] && id "$USER_NAME" >/dev/null 2>&1 && echo " user $USER_NAME (with home directory)" echo " backups $BACKUP_DIR" echo if [ $REMOVE_JAIL -eq 1 ]; then echo "WARNING: removing jail $MANUAL_JAIL lifts all manual bans!" >&2 if fail2ban-client get "$MANUAL_JAIL" banip >/dev/null 2>&1; then echo " currently banned: $(fail2ban-client get "$MANUAL_JAIL" banip | tr '\n' ' ')" >&2 fi fi [ $DRY_RUN -eq 0 ] || { info "dry run – nothing changed"; exit 0; } if [ $YES -eq 0 ]; then [ -t 0 ] || die "no terminal for the confirmation – use --yes" read -r -p "Remove? [y/N] " answer [[ "$answer" =~ ^[yYjJ] ]] || die "aborted, nothing changed" fi STAMP=$(date +%Y-%m-%d_%H-%M-%S) BK="$BACKUP_DIR/uninstall_$STAMP" mkdir -p "$BK"; chmod 700 "$BACKUP_DIR" "$BK" for f in "$AK_FILE" "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE" "${JAIL_FILES[@]}"; do [ -e "$f" ] && cp -a --parents "$f" "$BK/" done info "backup: $BK" if [ "$KEY_LINES" -gt 0 ]; then info "removing key entries from $AK_FILE" tmp=$(mktemp) grep -v 'command="[^"]*f2b-webctl"' "$AK_FILE" > "$tmp" || true cat "$tmp" > "$AK_FILE" rm -f "$tmp" fi for f in "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE"; do [ -e "$f" ] && { info "removing $f"; rm -f "$f"; } done if [ $REMOVE_JAIL -eq 1 ]; then for f in "${JAIL_FILES[@]}"; do [ -e "$f" ] && { info "removing $f"; rm -f "$f"; } done fail2ban-client reload >/dev/null || echo "WARNING: fail2ban reload failed – check: fail2ban-client -t" >&2 fi if [ $REMOVE_USER -eq 1 ] && id "$USER_NAME" >/dev/null 2>&1; then info "removing user $USER_NAME" userdel -r "$USER_NAME" 2>/dev/null || userdel "$USER_NAME" fi info "done"