Comment puis-je détecter si le shell est contrôlé à partir de SSH?

69

Je veux détecter à partir d'un script shell (plus précisément .zshrc) s'il est contrôlé via SSH. J'ai essayé la variable HOST mais c'est toujours le nom de l'ordinateur qui exécute le shell. Puis-je accéder au nom d'hôte d'où provient la session SSH? Comparer les deux résoudrait mon problème.

Chaque fois que je me connecte, il y a un message indiquant la dernière heure de connexion et l'hôte:

Last login: Fri Mar 18 23:07:28 CET 2011 from max on pts/1
Last login: Fri Mar 18 23:11:56 2011 from max

Cela signifie que le serveur a cette information.

Stribika
la source

Réponses:

90

Voici les critères que j'utilise dans mes ~/.profile:

  • Si l'une des variables SSH_CLIENTou SSH_TTYest définie, c'est une session ssh.
  • Si le nom de processus parent du shell de connexion est sshd, il s'agit d'une session ssh.
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
  SESSION_TYPE=remote/ssh
# many other tests omitted
else
  case $(ps -o comm= -p $PPID) in
    sshd|*/sshd) SESSION_TYPE=remote/ssh;;
  esac
fi

(Pourquoi voudriez-vous tester cela dans votre configuration shell plutôt que dans le démarrage de votre session?)

Gilles, arrête de faire le mal
la source
3
Très bien, merci! github.com/balupton/dotfiles/commit/…
balupton
1
vous voudrez peut-être faire cela dans la configuration de votre shell si vous voulez activer le transfert d'agent ssh depuis votre shell distant (car les vars d'environnement doivent être définis dans chaque shell à partir duquel vous souhaitez transférer) à moins que quelque chose ne me manque?
Underrun
@underrun Je ne comprends pas votre point. Si vous exécutez un autre shell dans la même session, il hérite des variables d'environnement définies par .profile. Et qu'est-ce que cela a à voir avec le transfert d'agent?
Gilles 'SO- arrête d'être méchant'
1
@underrun Si vous souhaitez tester la présence du transfert d'agent SSH, testez la SSH_AUTH_SOCKvariable. Mais pourquoi voudriez-vous exécuter un agent SSH dans ce cas? Voulez-vous dire démarrer un agent si vous êtes connecté sans retransmission d'agent? Pourquoi ne pas démarrer un agent s'il n'y en a pas déjà un ( [ -n "$SSH_AUTH_SOCK" ] || eval $(ssh-agent))?
Gilles 'SO- arrête d'être méchant'
1
@Praxeolitic Les SSH_*variables sont également définies dans les sous-processus d'un shell se trouvant en tête d'une session SSH, par exemple si vous démarrez une session écran sur SSH (vous devez désélectionner les variables avant de démarrer la session si vous en tenez à vous). Je pense que la raison pour tester le processus parent est que j'ai commencé à le faire avant que sshd ne définisse une variable d'environnement.
Gilles 'SO- arrête d'être méchant'
21

Vous devriez être en mesure de vérifier par les SSH_TTY, SSH_CONNECTIONou les SSH_CLIENTvariables.

Cakemox
la source
1
Ajouter également à env_keepen sudoersfaire fonctionner à travers les sucommandes :)
Thomas G.
10

Je viens d'avoir le même problème sous Linux, en utilisant Bash. J'ai d'abord utilisé la variable d'environnement SSH_CONNECTION, mais je me suis ensuite rendu compte qu'elle n'était pas définie si vous su -.

La solution lastlog ci-dessus ne fonctionnait ni après suni su -.

Enfin, je l’utilise who am i, ce qui indique l’adresse IP distante (ou le nom d’hôte) à la fin s’il s’agit d’une connexion SSH. Cela fonctionne également après le su.

En utilisant des expressions régulières Bash, cela fonctionne:

if [[ $(who am i) =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then echo SSH; else echo no; fi

Si zsh ne prend pas en charge les expressions rationnelles, la même chose peut être réalisée de différentes manières avec grep, cut, sed, etc.

Pour les curieux, voici ce que j’utilise pour cela, dans le fichier .bashrc de root:

    # We don't allow root login over ssh.
    # To enable root X forwarding if we are logged in over SSH, 
    # use the .Xauthority file of the user who did su

    w=$(who am i)
    if [[ $w =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then
        olduser=${w/ .*/}
        oldhome=$(getent passwd $olduser | cut -d: -f 6)
        [ -f "$oldhome/.Xauthority" ] \
          && export XAUTHORITY=$oldhome/.Xauthority
    fi

Une alternative qui fonctionne également avec suserait de rechercher récursivement à sshdtravers les processus parents:

#!/bin/bash

function is_ssh() {
  p=${1:-$PPID}
  read pid name x ppid y < <( cat /proc/$p/stat )
  # or: read pid name ppid < <(ps -o pid= -o comm= -o ppid= -p $p) 
  [[ "$name" =~ sshd ]] && { echo "Is SSH : $pid $name"; return 0; }
  [ "$ppid" -le 1 ]     && { echo "Adam is $pid $name";  return 1; }
  is_ssh $ppid
}

is_ssh $PPID
exit $?

Si la fonction est ajoutée à .bashrc, elle peut être utilisée comme if is_ssh; then ...

mivk
la source
1
ne fonctionne pas dans les tmuxsessions à distance et présente également des problèmes si vous êtes connecté via IPv6 et qu’il n’existe pas de nom DNS inversé.
bene
@ bene: qu'est-ce qui ne marche pas? L'expression régulière, ou ne who am imontre pas votre adresse IPv6?
mardi
1) who am ine renvoie rien dans une tmuxsession à distance . 2) L’adresse IPv6 peut contenir des deux-points que votre regex n’autorise pas. Cela peut être délicat puisque who am icontient (:0.0)dans X sessions pour moi (xterm).
bene
@bene: La solution alternative que je viens d'ajouter devrait également fonctionner avec IPv6. Je ne sais pas pour tmux, mais ça marche aussi en screen.
mardi
7

Je pense que les réponses de Gilles et Cakemox sont bonnes, mais juste pour être complet ...

Last login: Fri Mar 18 23:07:28 CET 2011 from max on pts/1

vient de pam_lastlog1 .

Vous pouvez imprimer des pam_lastloginformations en utilisant la commande lastlog2 , par exemple

$ lastlog -u mikel  
Username         Port     From             Latest
mikel            tty1                      Fri Jan 28 10:58:10 +1100 2011

pour un login local, comparé à

Username         Port     From             Latest
mikel            pts/9    mikel-laptop     Sat Mar 19 11:11:58 +1100 2011

pour une connexion SSH.

Sur mon système, cela fonctionne pour l'extraire

$ lastlog -u mikel | sed -ne '2{p;q}' | cut -c 27-42
mikel-laptop 

lastet wpourrait être utile aussi, par exemple

$ TTY=$(tty)
$ last -n 1 ${TTY#/dev/} | sed -ne '1{p;q}'
mikel    pts/12       :0.0             Sat Mar 19 11:29   still logged in 


1 Documentation Linux / FreeBSD pour pam_lastlog.
2 pages de manuel Linux / FreeBSD lastlog(8) .

Mikel
la source
1

Commencez par examiner votre environnement et trouver la bonne option

printenv|grep SSH
SSH_CLIENT=192.168.1.xxx
SSH_CONNECTION=192.168.1.xxx
SSH_TTY=/dev/ttys021

Vous pouvez vous connecter à plusieurs de ces variables d'environnement pour déclencher des actions spécifiques en fonction de leur présence.

lfender6445
la source
-1

Ceci est pour vérifier toutes les connexions établies d'un autre utilisateur utilisant SSH

netstat | grep ssh
ARD
la source
Ce n'est pas du tout fiable.
DannyNiu