tmux
?On va utiliser deux super capacités de tmux
:
capture-pane
;Une commande pour récupérer le contenu du terminal:
$ tmux capture-pane -p -t "$TMUX_PANE"
la variable $TMUX_PANE
contient l’identifiant du panneau courant depuis lequel on exécute la commande.
Une commande pour envoyer des caractères vers un panneau de tmux
:
$ tmux send-keys -t "$PANE" "echo hello" ENTER
Ici, le mot ENTER
désigne le retour à la ligne.
Pour permettre à l’utilisateur de choisir le mot de passe qu’il veut entrer, on va utiliser fzf, l’outil incontournable de menu avec sélection fuzzy.
Enfin, on va définir un format de fichier texte pour stocker notre liste de mot de passe:
système1 mot_de_passe1
système2 mot_de_passe2
On considérera l’espace comme notre séparateur de champs.
Une commande pour utiliser fzf
avec la sélection offerte sur le premier champs (celui associé au système) et renvoyant le second champ (celui associé au mot de passe) lors de la sélection par l’utilisateur:
$ cat ma_liste | fzf --with-nth=1 --bind 'enter:execute(echo {2})+abort'
Tout d’abord, on peut en restreindre l’accès par les autorisations d’accès fichier:
$ chmod 600 ma_liste
Ensuite, on peut en chiffrer le contenu:
$ openssl enc -d -pbkdf2 -aes-128-cbc -in ma_liste -out ma_liste_chiffree
Oui mais comment faire en sorte d’en autoriser l’accès une fois en début de session et de permettre l’accès sans restriction ensuite à la manière du ssh-agent
?
fifo
avec des droits d’accès restreint sur lequel notre script va écrire de manière automatique et continuelle;tmux
, on va lire à la demande de l’utilisateur le contenu pour sélectionner et obtenir le mot de passe à entrer;Les avantages d’un tel système sont de:
tmux
par l’intermédiaire d’un fichier fifo
avec la protection des droits d’accès fichier.Le script réalisant l’accès à la liste des mots de passe:
#!/bin/bash
# command to cipher the password file
# openssl enc -pbkdf2 -aes-128-cbc -pass pass:$MDP -in ~/.ssh/logins -out ~/.ssh/loginz
# chmod 600 ~/.ssh/loginz
# rm ~/.ssh/logins
umask 077
FIFODIR="/tmp/$USER/secure"
FIFOPATH="$FIFODIR/fifo"
DATA="$(openssl enc -d -pbkdf2 -aes-128-cbc -in ~/.ssh/loginz)"
rm -rf "$FIFODIR"
mkdir -p "$FIFODIR"
mkfifo "$FIFOPATH" || { rmdir "$FIFODIR"; exit 1; }
while true
do
echo "Access request at $(date)"
echo "$DATA" > $FIFOPATH
done
Le fichier ~/.ssh/loginz
contient la liste des mots de passe chiffrée.
tmux_password
#!/bin/bash
umask 077
PANE=$TMUX_PANE
# Verify if the last line of the panel in tmux contains the string `password` to avoid leaking the password on the terminal
OK=$(tmux capture-pane -p -t "$PANE" | sed '/^[[:blank:]]*$/ d'| tail -n 1 | grep password)
if [ -n "$OK" ]
then
tmux popup -T "Select password" -E bash -c "cat /tmp/$USER/secure/fifo | fzf --with-nth=1 --bind 'enter:execute(echo {2})+abort' > /tmp/$USER/secure/.xxx"
tmux send-keys -t "$PANE" $(cat ~/.xxx) ENTER
rm /tmp/$USER/secure/.xxx
fi
Ici, je vérifie que la dernière ligne du terminal contient bien la chaîne password
avant d’envoyer les caractères du mot de passe.
Une meilleure méthode serait de vérifier l’état du terminal et savoir si l’écho est actif ou non, c-à-d si le terminal affiche ou non les caractères entrés au clavier:
tty
du panneau:$ tmux list-panes -aF "#{pane_tty}:#{pane_id}" | grep '%23' | grep -oE "^[^:]*"
/dev/pts/12
$ PTY=$(tmux list-panes -aF "#{pane_tty}:#{pane_id}" | grep '%23' | grep -oE "^[^:]*")
$ stty -a -F $PTY
Où %23
est l’identifiant du panneau donné par la variable d’environnement $TMUX_PANE
$ stty -a -F /dev/pts/12
speed 38400 baud; rows 35; columns 135; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = <undef>; discard = <undef>; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig -icanon iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
Le mode echo
qui régit ou non l’affichage des caractères est inactif avec le préfixe -
: il vaut -echo
Malheureusement, sous zsh
le seul mode qui diffère est le mode icanon
entre le mode sans saisie de mot de passe de ssh
(où tout caractère entré est affiché sur le terminal) et le mode avec saisie de mot de passe (où les caractères entrés ne sont pas affichés sur le terminal):
$ stty -a -F /dev/pts/12
speed 38400 baud; rows 35; columns 135; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
On peut néanmoins vérifier avec strace
le travail de ssh
lors de la saisie de mot de passe:
openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4
ioctl(4, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon -echo ...}) = 0
ioctl(4, TCGETS, {B38400 opost isig icanon -echo ...}) = 0
ssh
demande bien le changement du mode de terminal -echo
Cette vérification supplémentaire peut être ajoutée dans le script mais peut ne fonctionner qu’avec le shell zsh
.
tmux
est un outil formidable avec beaucoup d’applications possibles !