====== Envoyer des commandes shell par php comme avec une console SSH ====== (testé sur une opensuse 10.2) ===== Objectif ===== Grâce à un script php sur un site web, on veut pouvoir envoyer des commandes shell à n'importe quelle autre machine linux, comme si on les envoyait dans une console SSH. ===== Principe ===== On utilise un module "php-ssh2" ===== Références ===== * Un manuel php (en français): [[http://fr.php.net/manual/fr/ref.ssh2.php]] * Autre manuel php (en français) voir chapitre 8.125: [[http://www.nexen.net/index.php?option=com_nexen_v2&Itemid=232&lang=FR&nexen_url_type=nexen&nexen_path=docs%2Fphp%2Fannotee%2Fmanuel_tocd.php]] ===== Installation de php-ssh2 ===== Il faut installer les packages "libssh2" et "php-ssh2" que j'ai trouvé pour l'opensuse 10.2 ici: * [[http://software.opensuse.org/download/server:/php:/extensions/openSUSE_10.2/i586/]] Vous pouvez les installer avec la commande rpm en console sous root, mais sur l'opensuse 10.2, il est plus facile et plus sûr de faire ceci: * vous placez les 2 packages dans un répertoire de votre choix (par exemple: /ressources/progsup/php) * vous ajoutez ce répertoire comme source de packages dans "yast -> logiciels -> changez le support d'installation" en utilisant l'ajout "package directory" * vous installez ensuite le module php-ssh2 par "yast -> logiciels -> installer et supprimer des logiciels": yast se débrouillera pour intégrer les dépendances (ce que la commande "rpm" ne fait pas tout seul). Une fois fait, vous vérifiez avec une page php comportant la commande "infophp()" que le module "php-ssh2" a bien été intégré, ce qui s'est fait chez moi sans autre manip. ===== Configuration ===== ==== Mode d'identification ==== Pour que l'identification de l'utilisateur soit acceptée sur la machine à piloter par ssh, il faut activer une option dans /etc/ssh/sshd.config comme ça: PasswordAuthentication yes ce que j'ai mis un certain temps à trouver... Mais il y a d'autres modes d'identification, que je n'ai pas essayés, qui ne nécessitent pas une telle modification (comme quand on établit une liaison par une console ssh). ==== Reconnaissance du "fingerprint" ==== A l'établissement de la connexion SSH2, il faut être certain d'être en relation avec la machine voulue, ceci pour éviter d'être piégé par une usurpation d'adresse. On peut automatiser cette reconnaissance en comparant le "fingerprint" de la machine contactée avec celui qu'elle devrait avoir (et qu'il faut donc connaitre avant). Pour connaitre ce "fingerprint" de la machine cible, il faut pouvoir y accéder par un shell quelconque. Lancez (le paramètre est un "L" minuscule): # ssh-keygen -l le programme demande de quelle clé vous voulez le fingerprint. Répondez: # ssh_host_rsa_key.pub Le programme vous donne alors le fingerprint de la clé en question. Quelque chose comme: # 1024 d7:57:d2:5a:94:2c:49:6b:45:d0:1c:0d:fd:ac:08:95 Prenez note de ce fingerprint et rentrez-le (sans les "1024") comme paramètre dans le script php ci-dessous. Vous n'êtes cependant pas obligé de faire cette vérification! ===== Script php modèle ===== Le script que je vous propose est un script de type "debug". Par exemple, il ne dira pas seulement quand ça ne marche pas, mais aussi quand ça marche. Vous pourrez supprimer facilement cette dernière partie quand votre code sera au point (supprimer les parties "else" des 'if"). Une fois uploadé sur le site, il suffit d'appeler la page dans un navigateur quelconque pour que le script php soit exécuté. NB: ce script n'a pas la prétention d'être du très bon code php, mais... il marche! '; exit(); // sortie si erreur } else { echo 'connexion établie
'; } // Vérification du fingerprint $fingerprint = ssh2_fingerprint($connection, SSH2_FINGERPRINT_MD5 | SSH2_FINGERPRINT_HEX); if ($fingerprint != $known_host) { echo "La clé hôte ne correspond pas !
"; echo "clé renvoyée: ".$fingerprint.'
'; exit(); // sortie si erreur } else { echo "fingerprint conforme
"; } //authentification utilisateur if (false === ssh2_auth_password($connection, $username, $password)) { echo 'Echec identification
'; exit(); // sortie si erreur } else { echo 'Identification réussie !
'; } //exécution command shell sur la machine destinataire if (false === $stream = ssh2_exec($connection, $commande)) { echo "erreur d'exécution commande shell
"; } // sortie du résultat quand il y en a un stream_set_blocking($stream, true); $output = ''; while($ligne = fgets($stream)) { $output = $output . $ligne . '
'; } echo $output; // Sortie de l'erreur quand il y en a une $stderr = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR); stream_set_blocking($stderr, true); $output = ''; while($ligne = fgets($stderr)) { $output = $output . $ligne . '
'; } echo $output; fclose($stderr); fclose($stream); ?>
Ce script renvoie la sortie des commandes (stdio) quand il y a une sortie, ou la sortie de l'erreur (stderr) quand il en a une. Je suis parti du principe que l'on voulait voir le résultat des commandes comme c'est affiché en console. Mais si on veut voir le résultat comme un flux quelconque, il faut utiliser "fread" en remplacement de "fgets" et, bien sûr, retirer les "
" de fin de ligne. Comme cela: stream_set_blocking($stream, true); $output = ''; while ($bloc = fread($stream, 8192)) { $output = $output . $bloc; } Bien entendu, les commandes acceptables sont limitées par le niveau de privilèges de l'utilisateur logué! Si on en veut plus, il faut se loguer en root, dans la mesure où sshd.config ne l'interdit pas. On pourrait aussi modifier le niveau de privilège de l'utilisateur en modifiant le fichier /etc/sudoers et en utilisant sudo (voir la page dédiée sur ce site), ce qui permettrait, par exemple, d'attribuer à un utilisateur le droit de rebooter le linux ("shutdown -r now"), alors que cette commande nécessite en principe des droits "root". ===== Conclusion ===== Voilà. Avec ça, on peut faire à peu près tout ce qu'on pourrait faire avec une console SSH, y compris, par exemple, de rebooter un linux à distance, ou même de l'éteindre! L'utilisation la plus intéressante est, à mon avis, dans la création de morceaux d'outil d'administration de serveurs. Amusez-vous bien!