Pourquoi «sudo su» dans un script shell n'exécute-t-il pas le reste du script en tant que root?

36

Un exemple de script peut être comme ci-dessous:

#!/bin/bash
sudo su
ls /root

Lorsqu’il est utilisé en ./test.shtant qu’utilisateur normal, exécutez-le en lstant que super utilisateur et quittez-le; et lorsque je me déconnecte, il s'exécute en ls /roottant qu'utilisateur normal.

Quelqu'un peut-il me parler du mécanisme à ce sujet?

Hongxu Chen
la source
13
sudo sume fait mal aux yeux.
gelé le
Il est utilisé parce que les gens ne connaissent pas suffisamment sudo et qu'ils ont donc besoin d'un moyen d'exécuter su sur des systèmes où la racine est sécurisée par un mot de passe délibérément corrompu. Mais oui, sudo "redonde" l'utilisation de su.
Johan
1
Ne pouvez-vous pas simplement utiliser sudo -s, cependant?
Joe Z.
@Johan, j'utilise souvent sudo suparce que je suis plus habitué aux options de suque je ne suis de celles de sudo. Je connais assez bien les options de sudo, mais je peux taper plus rapidement les options su. Mais oui, cela veut dire que je ne connais pas assez le sudo.
user606723
1
Je viens de vérifier la page de manuel sudo. Il apparaît sudo -iest proche de su -tout sudo -sfonctionne comme su(sans le tiret)
Johan

Réponses:

49

Les commandes d'un script s'exécutent une par une, indépendamment. Le script lui-même, en tant que parent de toutes les commandes du script, est un autre processus indépendant et la commande su ne peut pas et ne peut pas le changer en root: la commande su crée un nouveau processus avec les privilèges root.

Une fois la commande su terminée, le processus parent, toujours en cours d'exécution sous le même utilisateur, exécutera le reste du script.

Ce que vous voulez faire, c'est écrire un script wrapper. Les commandes privilégiées vont dans le script principal, par exemple~/main.sh

#!/bin/sh
ls /root

Le script wrapper appelle le script principal avec les autorisations root, comme ceci

#!/bin/sh
su -c ~/main.sh root

Pour lancer ce processus, vous exécutez l'encapsuleur qui, à son tour, lance le script principal après avoir basculé utilisateur sur l'utilisateur root.

Cette technique de wrapper peut être utilisée pour transformer le script en un wrapper autour de lui-même. En gros, vérifiez s’il est exécuté en tant que root. Sinon, utilisez "su" pour se relancer.

$ 0 est un moyen pratique de faire en sorte qu'un script se réfère à lui-même, et la commande whoami peut nous dire qui nous sommes (sommes-nous root?)

Ainsi, le script principal avec wrapper intégré devient

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Notez l'utilisation de exec. Cela signifie "remplacer ce programme par", ce qui met effectivement fin à son exécution et lance le nouveau programme, lancé par su, avec root, pour s'exécuter depuis le haut. L'instance de remplacement est "root", elle n'exécute donc pas le côté droit de la commande ||

Johan
la source
1
fwiw, un addendum à ce point. Si j’écrivais un script comme celui-ci, je ferais juste une instruction if au début qui vérifie $ EUID et si ce n’est pas zéro sudo et se ferme, sinon continue avec l’exécution du script.
Bratchley le
D'accord, et je vais mettre à jour la réponse pour expliquer cela.
Johan
2
C’est peut-être un peu archaïque, mais j’aime les chemins absolus menant à tous les exécutables afin que l’on ne puisse pas changer le script ~ / main.sh en quelque chose de néfaste. Attaquer la partie USER du script
artifex
2
Vous voudrez peut-être aussi comprendre les arguments qui lui ont été transmis en incluant une référence à $ *
Bratchley le
@JoelDavis J'ai toujours couru dans le mur de "Que faire s'il y a des espaces espaces dans les arguments". Je n'ai jamais trouvé de solution satisfaisante. Une fois, j’ai écrit un script qui exposait ses arguments dans un fichier temporaire, un argument par ligne, puis j’appelais ce dont il avait besoin et transmettais à ce script final l’argument de ce fichier à lire pour trouver les arguments originaux.
Johan
20

Utilisez ce qui suit dans le script.

sudo su <<HERE
ls /root
HERE

Le code entre le bloc HERE sera exécuté en tant que root.

Ankit
la source
6
sudo suappelle deux programmes. Utilisez sudo -s <<HEREDOCou su user <<HEREDOC... Limite stupide de 5 minutes.
Johan
6

Sans autres arguments su, le shell de connexion sera exécuté pour root. C'est ce que la première ligne de votre script fait réellement. Lorsque vous quittez, le shell connexion se ferme, les retours et su votre script poursuit son exécution, qui est la deuxième ligne: ls /root. Je pense que vous pouvez simplement sudo ls /rootfaire ce que vous voulez.

Bananguin
la source
Oui, je sais que je peux le faire ls, mais ce n’est qu’un échantillon. En fait, j'ai besoin de faire beaucoup plus de choses avec le privilège root :-) Je préfère donc la réponse de @ Ankit.
Hongxu Chen
1

Une fois que vous lancez sudo suun nouveau processus avec le userid (euid=EUID)super utilisateur réel, nous avons donc un nouveau bash qui s'exécute sous différents identificateurs de processus (pid=PID)associés au même terminal (tname=TTY).

Explication

Supposons qu'après le tir, ps -A | grep bashvous ayez 21460 pts/2 00:00:00 bashcomme sortie. Maintenant, lorsque vous exécuterez les ./test.shdeux commandes sudo suet ls /rootque vous serez spoulé PID 21460. Après exécution lorsque l' rootutilisateur actif est à ps -A | grep bashnouveau touché , vous remarquerez un nouveau bash en cours d'exécution PID say, 21570. Sortir de root bashva tuer la bash récemment retournée user's bashet, par conséquent, exécuter la commande spooled ls /rootavant de relâcher l’invite.

sundeep
la source
Si utiliser su ou sudo était "persistant" dans bash (ou ailleurs), cela créerait beaucoup plus de problèmes qu'il n'aurait pas résolu. Vous devez faire le minimum possible en tant que root pour la sécurité. Le principal avantage d’avoir su et sudo (autre que la sécurité!) Est de vous faire réfléchir à ce qui a besoin des privilèges root.
Joe