diff --git a/profile.d/ssh.sh b/profile.d/ssh.sh index a4e174f..89eb710 100644 --- a/profile.d/ssh.sh +++ b/profile.d/ssh.sh @@ -35,24 +35,32 @@ # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ -# Remove host from know_host (name and IP) for the active user +# Remove host entries (name and IP) from ~/.ssh/known_hosts for the active user # Usage: rmhost [hostname2|ip2 [...]] rmhost() { local PARSED - PARSED=$(getopt -o h --long help -n 'rmhost' -- "$@") + local all_users=0 + local -a known_hosts_files=() + + PARSED=$(getopt -o ha --long help,all-users -n 'rmhost' -- "$@") if [[ $? -ne 0 ]]; then return 1; fi eval set -- "$PARSED" while true; do case "$1" in -h|--help) - printf "rmhost: Remove host/IP from ~/.ssh/known_hosts.\n\n" - printf "Usage: rmhost [hostname2|ip2 ...]\n\n" + printf "rmhost: Remove host/IP from known_hosts files.\n\n" + printf "Usage: rmhost [--all-users] [hostname2|ip2 ...]\n\n" printf "Options:\n" + printf " -a, --all-users Remove entries from all local users when run as root\n" printf " -h, --help Display this help screen\n" return 0 ;; + -a|--all-users) + all_users=1 + shift + ;; --) shift break @@ -74,6 +82,28 @@ rmhost() return 127 } + if (( all_users )); then + [[ ${EUID:-$(id -u)} -eq 0 ]] || { + disp E "Option --all-users is only available when run as root." + return 1 + } + + while IFS=: read -r _ _ _ _ _ home _; do + [[ -n $home && -f $home/.ssh/known_hosts ]] || continue + known_hosts_files+=("$home/.ssh/known_hosts") + done < /etc/passwd + + [[ -f /etc/ssh/ssh_known_hosts ]] && \ + known_hosts_files+=("/etc/ssh/ssh_known_hosts") + + [[ ${#known_hosts_files[@]} -gt 0 ]] || { + disp W "No known_hosts files found for local users." + return 0 + } + else + known_hosts_files=("${HOME}/.ssh/known_hosts") + fi + for target in "$@"; do local hst="$target" local ip="" @@ -90,22 +120,33 @@ rmhost() if [[ -z ${ip:-} && -n ${hst:-} ]]; then if command -v host >/dev/null 2>&1; then - ip=$(host "$hst" 2>/dev/null | awk '/has address/ {print $NF; exit}') - [[ -z ${ip:-} ]] && \ - disp W "Could not resolve IP for '$hst'; removing hostname only." + ip=$(host "$hst" 2>/dev/null | + awk '/has address|has IPv6 address/ {print $NF; exit}') + elif command -v getent >/dev/null 2>&1; then + ip=$(getent ahosts "$hst" 2>/dev/null | awk 'NR == 1 {print $1; exit}') else - disp W "'host' is not installed; removing hostname only for '$hst'." + disp W "No resolver tool found; removing hostname only for '$hst'." fi + + [[ -z ${ip:-} ]] && \ + disp W "Could not resolve IP for '$hst'; removing hostname only." fi - if [[ -n ${hst:-} ]]; then - disp I "Removing host $hst from ssh known_hosts..." - ssh-keygen -R "$hst" >/dev/null - fi - if [[ -n ${ip:-} ]]; then - disp I "Removing IP $ip from ssh known_hosts..." - ssh-keygen -R "$ip" >/dev/null - fi + local known_hosts_file="" + for known_hosts_file in "${known_hosts_files[@]}"; do + if [[ -n ${hst:-} ]]; then + disp I "Removing host $hst from $known_hosts_file..." + if ! ssh-keygen -R "$hst" -f "$known_hosts_file" >/dev/null 2>&1; then + disp W "No known_hosts entry found for '$hst' in '$known_hosts_file'." + fi + fi + if [[ -n ${ip:-} ]]; then + disp I "Removing IP $ip from $known_hosts_file..." + if ! ssh-keygen -R "$ip" -f "$known_hosts_file" >/dev/null 2>&1; then + disp W "No known_hosts entry found for '$ip' in '$known_hosts_file'." + fi + fi + done done } export -f rmhost