diff --git a/ussh b/ussh new file mode 100755 index 0000000..3db1f70 --- /dev/null +++ b/ussh @@ -0,0 +1,221 @@ +#!/bin/bash +# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +source "$(dirname "$0")/ulib/ulib" || exit 1 +urequire DEFAULTS + +function display_help() { + uecho "$scriptname: se connecter par ssh à un ou plusieurs hôtes + +USAGE + $scriptname [options] hosts + $scriptname [options] @hostsfile + $scriptname -r hosts + +OPTIONS + hosts + @hostsfile + Spécifier un ou plusieurs hôtes distants sur lequels faire la connexion. + Pour spécifier plusieurs hôtes, il faut les séparer par un espace ou le + caractère ':', e.g. 'host1 host2' ou 'host1:host2'. Si la spécification + contient les caractères { et }, l'expansion est effectuée, e.g + 'root@{host1,host2}.univ.run' + La forme @hostsfile permet de lire la liste des hôtes depuis le fichier + hostsfile, à raison d'un hôte par ligne. + +Toutes les options de ssh sont reconnues. Les options longues suivantes sont +reconnues comme alias de certaines options courtes de ssh: + --quiet + alias de -q, activer le mode non verbeux + --tty + alias de -t, forcer l'allocation d'un TTY + --login USER + alias de -l, spécifier le user avec lequel se connecter + --port PORT + alias de -p, spécifier le port sur lequel se connecter + +Les options suivantes sont exclusives à ce script: + -d, --domain DOMAIN + Spécifier un domaine par défaut pour les hôtes qui sont spécifiés sans + domaine. + -z, --ssh SSH + Spécifier l'exécutable à utiliser pour lancer ssh. + -r, --remove + Lancer 'ssh-keygen -R' pour chacun des hôtes spécifiés avant de s'y + connecter. Par exemple: + $scriptname -r host.tld + est équivalent à: + ssh-keygen -R host.tld + ssh-keygen -R host + ssh-keygen -R 10.10.1.5 + ssh host.tld + si l'adresse ip de host.tld est 10.10.1.5 + Quand cette option est spécifié, l'option -j est reconnue et permet de + NE PAS se reconnecter à l'hôte juste après avoir nettoyé les clés. Avec + l'option -j, TOUS les arguments sont des noms d'hôte puisqu'aucune + connexion n'est effectuée." +} + +__PARSED_HOSTS=() +__PARSED_FILES=() +function parse_hostsfile() { + # Lire chacun des fichiers $* et initialiser __PARSED_HOSTS avec la liste + # des hôtes mentionnés dans les fichiers. + local inputfile basedir inputs input + for inputfile in "$@"; do + inputfile="$(abspath "$inputfile")" + array_contains __PARSED_FILES "$inputfile" && { + ewarn "$(ppath "$inputfile"): inclusion récursive" + continue + } + array_add __PARSED_FILES "$inputfile" + basedir="$(dirname "$inputfile")" + + array_from_lines inputs "$(<"$inputfile" filter_conf)" || { + ewarn "$inputfile: fichier ingnoré" + continue + } + for input in "${inputs[@]}"; do + if [ "${input#@}" != "$input" ]; then + # fichier inclus + parse_hostsfile "$(abspath "${input#@}" "$basedir")" + else + array_addu __PARSED_HOSTS "$input" + fi + done + done +} +function __expand_braces() { + if [[ "$1" == *{* ]] && [[ "$1" == *}* ]]; then + eval "echo $1" + else + echo "$1" + fi +} +function __dot_is_localhost() { [ "$1" == "." ] && echo "localhost." || echo "$1"; } +function fix_hosts() { + # Si hosts contient des éléments multiple, comme a:b, séparer ces + # éléments. i.e (a b:c "d e") --> (a b c d e) + # Supporter la syntaxe @hostsfile qui permet de charger la liste des hôtes + # depuis un fichier. + # Remplacer aussi les '.' par 'localhost' + array_map hosts __expand_braces + array_fix_paths hosts ":" + array_fix_paths hosts " " + + local -a _hosts _tmphosts host + for host in "${hosts[@]}"; do + host="${host%/}" + if [ "${host#@}" != "$host" ]; then + __PARSED_HOSTS=() + parse_hostsfile "${host#@}" + array_fix_paths __PARSED_HOSTS + array_extendu _hosts __PARSED_HOSTS + else + array_addu _hosts "$host" + fi + done + array_copy hosts _hosts + array_map hosts __dot_is_localhost +} + +function remove_key() { + estep "$1" + ssh-keygen -R "$1" >&/dev/null +} +function remove_keys() { + urequire ipcalc + + local -a __hosts; array_copy __hosts hosts + local -a allhosts hosts ips; local host user ip + array_copy allhosts __hosts + + etitle "Suppression des entrées dans ~/.ssh/known_hosts" + for host in "${allhosts[@]}"; do + splituserhost "$host" user host + if [ "${host%.}" != "$host" ]; then + host="${host%.}" + elif ! [[ "$host" == *.* ]]; then + host="$host${DOMAIN:+.$DOMAIN}" + fi + + if ipcalc_checkip "$host" >/dev/null; then + ip="$host" + remove_key "$ip" + + resolv_hosts hosts "$ip" + for host in "${hosts[@]}"; do + remove_key "$host" + hostname="${host%%.*}" + [ "$hostname" != "$host" ] && remove_key "$hostname" + done + else + remove_key "$host" + hostname="${host%%.*}" + [ "$hostname" != "$host" ] && remove_key "$hostname" + + resolv_ips ips "$host" + for ip in "${ips[@]}"; do + remove_key "$ip" + done + fi + done + eend +} + +function do_ssh() { + [ -n "$SSH" ] || SSH=ssh + [ "${#hosts[*]}" -gt 1 ] && showtitle=1 || showtitle= + for host in "${hosts[@]}"; do + splituserhost "$host" user host + if [ "${host%.}" != "$host" ]; then + host="${host%.}" + elif ! [[ "$host" == *.* ]]; then + host="$host${DOMAIN:+.$DOMAIN}" + fi + + [ -n "$showtitle" ] && etitle "${user:+$user@}$host" + "$SSH" "${SSHOPTS[@]}" "${user:+$user@}$host" "$@" + [ -n "$showtitle" ] && eend + done +} + +set_defaults nutools +SSHOPTS=(${USSH_USER:+-l "$USSH_USER"}) # options de ssh +function sshopt() { SSHOPTS=("${SSHOPTS[@]}" "$@"); } + +DOMAIN="$USSH_DOMAIN" +SSH= +remove= +remove_only= +parse_opts "${PRETTYOPTS[@]}" \ + --help '$exit_with display_help' \ + -1,-2,-4,-6,-A,-a,-C,-f,-g,-K,-k,-M,-N,-n,-q,-s,-T,-t,-V,-v,-X,-x,-Y,-y '$sshopt "$option_"' \ + -b:,-c:,-D:,-e:,-F:,-I:,-i:,-L:,-l:,-m:,-O:,-o:,-p:,-R:,-S:,-W:,-w: '$sshopt "$option_" "$value_"' \ + --quiet '$sshopt -q' \ + --tty '$sshopt -t' \ + --login: '$sshopt -l "$value_"' \ + --port: '$sshopt -p "$value_"' \ + -d:,--domain: DOMAIN= \ + -z:,--ssh: SSH= \ + -r,--remove remove=1 \ + -j remove_only=1 \ + @ args -- "$@" && set -- "${args[@]}" || die "$args" + +if [ -n "$remove" ]; then + [ -n "$*" ] || die "Vous devez spécifier les hôtes à supprimer de ~/.ssh/known_hosts" + if [ -n "$remove_only" ]; then + hosts=("$@") + fix_hosts + remove_keys + exit 0 + fi + + hosts=("$1"); shift + fix_hosts + remove_keys +else + hosts=("$1"); shift + fix_hosts +fi + +do_ssh "$@"