200 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| 
 | |
| function display_help() {
 | |
|     uecho "$scriptname: se connecter par ssh à un ou plusieurs hôtes
 | |
| 
 | |
| USAGE
 | |
|     $scriptname host [options]
 | |
|     $scriptname @hostsfile [options]
 | |
|     $scriptname -R hosts...
 | |
| 
 | |
| OPTIONS
 | |
|     host
 | |
|     @hostsfile
 | |
|         Spécifier un hôte distant sur lequel faire la connexion. Plusieurs
 | |
|         hôtes peuvent être spécifiées, en les séparant par ':', e.g. host1:host2
 | |
|         La forme @hostsfile permet de lire la liste des hôtes depuis le fichier
 | |
|         hostsfile, à raison d'un hôte par ligne.
 | |
|     [options]
 | |
|         Les arguments et options de ssh doivent se trouver *APRES* host, pour
 | |
|         simplifier leur analyse.
 | |
| Les options suivantes sont reconnues même quand elle sont spécifiées avant le
 | |
| premier argument (les options longues ne sont reconnues qu'avant le premier
 | |
| argument):
 | |
|     -q, --quiet
 | |
|         Mode non verbeux
 | |
|     -t, --tty
 | |
|         Forcer l'allocation d'un TTY
 | |
|     -l, --login USER
 | |
|         Spécifier le user avec lequel se connecter
 | |
|     -o OPTION
 | |
|         Ajouter une option de SSH
 | |
| Les options suivantes *doivent* se trouver *AVANT* le premier argument:
 | |
|     -d, --domain DOMAIN
 | |
|         Spécifier un domaine par défaut pour les hôtes qui sont spécifiés sans
 | |
|         domaine.
 | |
|     -S, --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. Par exemple:
 | |
|             $scriptname -R host.tld
 | |
|         est équivalent à:
 | |
|             ssh-keygen -R host.tld
 | |
|             ssh-keygen -R host
 | |
|             ssh-keygen -R 10.10.1.5
 | |
|         si l'adresse ip de host.tld est 10.10.1.5
 | |
|         Quand cette option est spécifié, l'option -c est reconnue et permet de
 | |
|         se reconnecter à l'hôte juste après avoir nettoyé les clés."
 | |
| }
 | |
| 
 | |
| source "$(dirname "$0")/ulib/ulib" || exit 1
 | |
| urequire DEFAULTS
 | |
| 
 | |
| set_defaults nutools
 | |
| 
 | |
| __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 __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) --> (a b c)
 | |
|     # Supporter la syntaxe @hostsfile qui permet de charger la liste des hôtes
 | |
|     # depuis un fichier.
 | |
|     # Remplacer aussi les '.' par 'localhost'
 | |
|     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 ussh() {
 | |
|     args=(${quiet:+-q} ${tty:+-t} ${login:+-l "$login"})
 | |
|     for option in "${options[@]}"; do
 | |
|         args=("${args[@]}" -o "$option")
 | |
|     done
 | |
|     args=("${args[@]}" "$@")
 | |
| 
 | |
|     [ -n "$ssh" ] || ssh=ssh
 | |
|     [ "${#hosts[*]}" -gt 1 ] && showtitle=1 || showtitle=
 | |
|     for host in "${hosts[@]}"; do
 | |
|         splituserhost "$host" user host
 | |
|         [[ "$host" == *.* ]] || host="$host${domain:+.$domain}"
 | |
|         [ -n "$showtitle" ] && etitle "${user:+$user@}$host"
 | |
|         "$ssh" "${user:+$user@}$host" "${args[@]}"
 | |
|         [ -n "$showtitle" ] && eend
 | |
|     done
 | |
| }
 | |
| 
 | |
| function remove_key() {
 | |
|     estep "$1"
 | |
|     ssh-keygen -R "$1" >&/dev/null
 | |
| }
 | |
| function remove_keys() {
 | |
|     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
 | |
|         [[ "$host" == *.* ]] || host="$host${domain:+.$domain}"
 | |
| 
 | |
|         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
 | |
| }
 | |
| 
 | |
| action=ssh
 | |
| quiet=
 | |
| tty=
 | |
| login="$USSH_USER"
 | |
| options=()
 | |
| domain="$USSH_DOMAIN"
 | |
| ssh=
 | |
| connect_after_remove=
 | |
| parse_opts + "${PRETTYOPTS[@]}" \
 | |
|     --help '$exit_with display_help' \
 | |
|     -q,--quiet quiet=1 \
 | |
|     -t,--tty tty=1 \
 | |
|     -l:,--login: login= \
 | |
|     -o options \
 | |
|     -d:,--domain: domain= \
 | |
|     -S:,--ssh ssh= \
 | |
|     -R,--remove action=remove \
 | |
|     -c,--connect connect_after_remove=1 \
 | |
|     @ args -- "$@" && set -- "${args[@]}" || die "$args"
 | |
| 
 | |
| if [ "$action" == "ssh" ]; then
 | |
|     [ -n "$1" ] || die "Vous devez spécifier l'hôte sur lequel faire la connexion"
 | |
|     hosts=("$1"); shift
 | |
|     fix_hosts
 | |
|     ussh "$@"
 | |
| 
 | |
| elif [ "$action" == "remove" ]; then
 | |
|     urequire ipcalc
 | |
| 
 | |
|     [ -n "$1" ] || die "Vous devez spécifier les hôtes à supprimer de ~/.ssh/known_hosts"
 | |
|     hosts=("$@")
 | |
|     fix_hosts
 | |
|     remove_keys
 | |
|     [ -n "$connect_after_remove" ] && ussh
 | |
| fi
 |