web-dev-qa-db-fra.com

Comment résoudre le problème "Le pseudo-terminal ne sera pas attribué car stdin n'est pas un terminal" dans Alpine Linux?

J'écris un programme PHP qui exécute une variété de commandes Shell. Parfois, il doit appeler su et, de par sa conception, je souhaite que l'invite demande un mot de passe à privilèges élevés. Utiliser passthru() dans PHP fonctionne très bien pour cela.

J'ai choisi d'écrire des tests fonctionnels uniquement pour mon programme, car il dépend de ssh, su et d'autres commandes Shell. Je veux donc lancer la vraie chose à l'intérieur de PHPUnit pour voir si cela fonctionne comme je l'espérais.

Comme cela nécessite un serveur SSH et des configurations de compte utilisateur, j'ai configuré les tests pour qu'ils s'exécutent dans Docker. Cette approche a l'air de bien fonctionner: l'image est construite, lorsqu'elle s'exécute, elle appelle PHPUnit, puis se ferme. Je pense qu’il sera possible de renvoyer un résultat via Docker à un système appelant, tel que Travis CI.

J'ai choisi Alpine Linux comme image de base pour Docker, mais je rencontre des problèmes d’allocation des terminaux. Je pensais à l'origine que PHPUnit se mettait en travers (voir la version originale de cette question), mais je l'ai maintenant réduit à SSH, que ce soit géré par PHP ou même simplement à la console.

Cela fonctionne bien:

su -c whoami

Cependant, cela ne veut pas:

ssh localhost -t 'su -c whoami'

Je reçois:

su: doit être suid pour fonctionner correctement
Connexion à localhost fermée.

Notez que ssh est configuré avec un accès sans mot de passe à localhost (à des fins de test), de sorte que le seul mot de passe que je compte entrer est le su.

Le manuel de ssh suggère que -f est utile pour indiquer où les mots de passe doivent être demandés (le commutateur "demande à ssh de passer en arrière-plan juste avant l'exécution de la commande"). J'essaie donc ceci:

ssh localhost -t -f 'su -c whoami'

Et je reçois:

Le pseudo-terminal ne sera pas attribué car stdin n'est pas un terminal.
4275760bde94: ~ $ su: doit être capable de fonctionner correctement

Ah, une autre erreur! OK, alors J'ai essayé ces idées , en particulier forçant un terminal:

ssh localhost -tt -f 'su -c whoami'

Le double-t émet toujours des plaintes à propos du SUID et ne fonctionne toujours pas.

Cependant, si je le fais sur ma machine de développement Ubuntu (également configuré avec un accès PPK à lui-même), cela fonctionne correctement:

$ ssh localhost -t 'su -c whoami'
Password: 
root
Connection to localhost closed.

Cela donne à penser que OpenSSH d’Alpine ou de BusyBox est en faute. Comment puis-je creuser plus loin?

Une solution consiste simplement à basculer sur une autre base de distribution, et Ubuntu fonctionnerait sûrement très bien, mais cela gonflerait massivement la taille de mon image Docker (actuellement sur un très beau total de 68 millions). Donc, je voudrais persister un peu avec Alpine si je peux.

Peu probable d'être Docker

Je me suis demandé si Docker pouvait empêcher la création ou la connexion d'un terminal, mais je l'ai rapidement écartée, car je peux obtenir un shell interactif avec docker exec -it container_name sh. De plus, je peux faire la ssh et ensuite la su dans deux commandes distinctes dans un Docker Shell.

Bash n'aide pas

Je remarque que Bash est disponible dans Alpine, mais cela ne m'a pas aidé non plus, ce qui me surprend:

/ $ apk add bash
bash-4.3$ bash
bash-4.3$ su nonpriv
bash-4.3$ ssh localhost whoami
nonpriv
bash-4.3$ ssh localhost 'su -c whoami'
su: must be suid to work properly
bash-4.3$ ssh localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
bash-4.3$ ssh -t localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tt localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tf localhost 'su -s /bin/bash -c whoami'
Pseudo-terminal will not be allocated because stdin is not a terminal.
bash-4.3$ su: must be suid to work properly

bash-4.3$ ssh -ttf localhost 'su -s /bin/bash -c whoami'
bash-4.3$ su: must be suid to work properly
Connection to localhost closed.

Essai d'interpolation de shell

J'ai trouvé cela fonctionne presque:

/ $ ssh -t localhost "$( su -c whoami )"
sh: Password:: not found
sh: root: not found
Connection to localhost closed.

Ceci utilise le standard alpin sh Shell, et utilise la construction "$()", qui se trouve sur le lien susmentionné, et que je ne comprends pas bien. Il génère Password:, qui correspond à l'invite dans su, puis attend le mot de passe. Lorsque le mot de passe est entré, la variable whoami est exécutée, laquelle affiche root.

On dirait qu’il exécute la commande, mais je ne sais pas s’il exécute la variable whoami immédiatement, puis la passe à ssh (pas ce que je veux) ou s’il envoie un shell distant à localhost puis le fait (cela c'est ce que j'ai l'intention).

Dans tous les cas, il essaie de run stdout comme si c’était une commande. Comment puis-je l'obtenir simplement pour imprimer le résultat via SSH?

5
halfer

J'ai deviné dans ma question que cela fonctionnerait dans un conteneur Ubuntu, et cela s'est avéré correct. Fait intéressant, j'obtiens toujours l'erreur «doit être exécuté à partir d'un terminal» avec cette commande:

su -c whoami

Mais pas ici, où un terminal est explicitement alloué à une commande SSH sans mot de passe:

ssh -t localhost 'su -c whoami'

Malheureusement, le nouvel OS a augmenté mon image de 68M à 430Mh, urgh! Je serais donc très heureux de recevoir de nouvelles réponses qui permettent à cela de fonctionner avec Alpine.

1
halfer